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.
Files changed (292) hide show
  1. package/CHANGELOG.md +597 -0
  2. package/README.md +43 -644
  3. package/framework/appLayout/default/chui_app_layout.js +602 -496
  4. package/framework/appLayout/default/global_style.css +288 -97
  5. package/framework/appLayout/default/main_theme_style.css +188 -101
  6. package/framework/components/chui_accordion/accordion.js +38 -35
  7. package/framework/components/chui_accordion/styles.css +13 -12
  8. package/framework/components/chui_action_sheet/action_sheet.js +93 -64
  9. package/framework/components/chui_action_sheet/styles.css +12 -5
  10. package/framework/components/chui_actions_bar/actions_bar.js +338 -0
  11. package/framework/components/chui_actions_bar/styles.css +139 -0
  12. package/framework/components/chui_affix/affix.js +16 -11
  13. package/framework/components/chui_affix/styles.css +5 -0
  14. package/framework/components/chui_alert/alert.js +34 -19
  15. package/framework/components/chui_alert/styles.css +7 -0
  16. package/framework/components/chui_avatar/avatar.js +36 -35
  17. package/framework/components/chui_avatar/styles.css +1 -1
  18. package/framework/components/chui_avatar_group/avatar_group.js +25 -23
  19. package/framework/components/chui_avatar_group/styles.css +1 -1
  20. package/framework/components/chui_backtop/backtop.js +60 -21
  21. package/framework/components/chui_backtop/styles.css +21 -0
  22. package/framework/components/chui_badge/badge.js +30 -28
  23. package/framework/components/chui_badge/styles.css +6 -6
  24. package/framework/components/chui_banner/banner.js +222 -0
  25. package/framework/components/chui_banner/styles.css +170 -0
  26. package/framework/components/chui_breadcrumb/breadcrumb.js +15 -13
  27. package/framework/components/chui_breadcrumb/styles.css +1 -1
  28. package/framework/components/chui_button/button.js +52 -36
  29. package/framework/components/chui_button/styles.css +7 -7
  30. package/framework/components/chui_calendar/calendar.js +18 -16
  31. package/framework/components/chui_card/card.js +52 -32
  32. package/framework/components/chui_card_scroll/card_scroll.js +169 -0
  33. package/framework/components/chui_card_scroll/styles.css +86 -0
  34. package/framework/components/chui_chat/chat.js +140 -79
  35. package/framework/components/chui_chat/styles.css +18 -7
  36. package/framework/components/chui_clipboard_history/clipboard_history.js +53 -39
  37. package/framework/components/chui_clipboard_history/styles.css +13 -9
  38. package/framework/components/chui_code/code.js +10 -10
  39. package/framework/components/chui_code/styles.css +4 -4
  40. package/framework/components/chui_code_editor/code_editor.js +73 -57
  41. package/framework/components/chui_code_editor/styles.css +6 -5
  42. package/framework/components/chui_command_palette/command_palette.js +87 -64
  43. package/framework/components/chui_command_palette/styles.css +5 -5
  44. package/framework/components/chui_console/console.js +13 -13
  45. package/framework/components/chui_console/styles.css +6 -3
  46. package/framework/components/chui_content_block/content_block.js +35 -21
  47. package/framework/components/chui_content_block/styles.css +2 -2
  48. package/framework/components/chui_context_menu/context_menu.js +171 -58
  49. package/framework/components/chui_context_menu/styles.css +82 -8
  50. package/framework/components/chui_custom_element/custom_element.js +25 -18
  51. package/framework/components/chui_data_grid/data_grid.js +633 -471
  52. package/framework/components/chui_data_grid/styles.css +24 -22
  53. package/framework/components/chui_descriptions/descriptions.js +34 -17
  54. package/framework/components/chui_descriptions/styles.css +1 -1
  55. package/framework/components/chui_details/details.js +42 -36
  56. package/framework/components/chui_details/styles.css +12 -11
  57. package/framework/components/chui_diff_viewer/diff_viewer.js +172 -147
  58. package/framework/components/chui_diff_viewer/styles.css +10 -10
  59. package/framework/components/chui_divider/divider.js +19 -17
  60. package/framework/components/chui_divider/styles.css +2 -2
  61. package/framework/components/chui_drawer/drawer.js +63 -38
  62. package/framework/components/chui_drawer/styles.css +18 -4
  63. package/framework/components/chui_drop_zone/drop_zone.js +37 -27
  64. package/framework/components/chui_drop_zone/styles.css +10 -6
  65. package/framework/components/chui_empty_state/empty_state.js +20 -15
  66. package/framework/components/chui_fieldset/fieldset.js +40 -23
  67. package/framework/components/chui_fieldset/styles.css +6 -6
  68. package/framework/components/chui_file_explorer/file_explorer.js +260 -189
  69. package/framework/components/chui_file_explorer/styles.css +8 -7
  70. package/framework/components/chui_form/form.js +40 -28
  71. package/framework/components/chui_form/styles.css +1 -1
  72. package/framework/components/chui_gantt/gantt.js +102 -78
  73. package/framework/components/chui_gantt/styles.css +5 -5
  74. package/framework/components/chui_graphs/graphs.js +376 -239
  75. package/framework/components/chui_graphs/styles.css +27 -6
  76. package/framework/components/chui_hero/hero.js +98 -37
  77. package/framework/components/chui_hero/styles.css +176 -7
  78. package/framework/components/chui_html_block/html_block.js +8 -8
  79. package/framework/components/chui_html_block/styles.css +3 -3
  80. package/framework/components/chui_hx/hx.js +3 -3
  81. package/framework/components/chui_hx/styles.css +13 -6
  82. package/framework/components/chui_icons/icons.js +2115 -2115
  83. package/framework/components/chui_icons/styles.css +4 -3
  84. package/framework/components/chui_inputs/chui_check_box/check_box.js +31 -19
  85. package/framework/components/chui_inputs/chui_check_box/styles.css +30 -21
  86. package/framework/components/chui_inputs/chui_chips/chips.js +141 -70
  87. package/framework/components/chui_inputs/chui_chips/styles.css +32 -7
  88. package/framework/components/chui_inputs/chui_color_picker/color_picker.js +55 -38
  89. package/framework/components/chui_inputs/chui_color_picker/styles.css +7 -7
  90. package/framework/components/chui_inputs/chui_combo_box/combo_box.js +127 -109
  91. package/framework/components/chui_inputs/chui_combo_box/styles.css +23 -21
  92. package/framework/components/chui_inputs/chui_date/date.js +161 -127
  93. package/framework/components/chui_inputs/chui_date/styles.css +20 -19
  94. package/framework/components/chui_inputs/chui_date_range/date_range.js +61 -50
  95. package/framework/components/chui_inputs/chui_date_range/styles.css +3 -3
  96. package/framework/components/chui_inputs/chui_datetime/datetime.js +47 -39
  97. package/framework/components/chui_inputs/chui_datetime/styles.css +3 -3
  98. package/framework/components/chui_inputs/chui_email/email.js +48 -36
  99. package/framework/components/chui_inputs/chui_email/styles.css +11 -11
  100. package/framework/components/chui_inputs/chui_file/file.js +71 -44
  101. package/framework/components/chui_inputs/chui_file/styles.css +23 -19
  102. package/framework/components/chui_inputs/chui_hotkey/hotkey.js +101 -76
  103. package/framework/components/chui_inputs/chui_hotkey/styles.css +6 -6
  104. package/framework/components/chui_inputs/chui_masked/masked.js +83 -72
  105. package/framework/components/chui_inputs/chui_masked/styles.css +5 -5
  106. package/framework/components/chui_inputs/chui_mention/mention.js +87 -40
  107. package/framework/components/chui_inputs/chui_mention/styles.css +14 -8
  108. package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +242 -212
  109. package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +23 -15
  110. package/framework/components/chui_inputs/chui_number/number.js +84 -70
  111. package/framework/components/chui_inputs/chui_number/styles.css +13 -13
  112. package/framework/components/chui_inputs/chui_otp/otp.js +71 -62
  113. package/framework/components/chui_inputs/chui_otp/styles.css +5 -5
  114. package/framework/components/chui_inputs/chui_password/password.js +72 -56
  115. package/framework/components/chui_inputs/chui_password/styles.css +15 -15
  116. package/framework/components/chui_inputs/chui_radio_button/radio_button.js +37 -25
  117. package/framework/components/chui_inputs/chui_radio_button/styles.css +22 -22
  118. package/framework/components/chui_inputs/chui_rating/rating.js +54 -50
  119. package/framework/components/chui_inputs/chui_rating/styles.css +3 -3
  120. package/framework/components/chui_inputs/chui_select_box/select_box.js +132 -108
  121. package/framework/components/chui_inputs/chui_select_box/styles.css +21 -21
  122. package/framework/components/chui_inputs/chui_slider/slider.js +41 -38
  123. package/framework/components/chui_inputs/chui_slider/styles.css +7 -5
  124. package/framework/components/chui_inputs/chui_text/styles.css +14 -14
  125. package/framework/components/chui_inputs/chui_text/text.js +69 -52
  126. package/framework/components/chui_inputs/chui_text_area/styles.css +14 -14
  127. package/framework/components/chui_inputs/chui_text_area/text_area.js +59 -36
  128. package/framework/components/chui_inputs/chui_time/styles.css +18 -20
  129. package/framework/components/chui_inputs/chui_time/time.js +71 -49
  130. package/framework/components/chui_inputs/chui_toggle/styles.css +13 -6
  131. package/framework/components/chui_inputs/chui_toggle/toggle.js +27 -27
  132. package/framework/components/chui_json_editor/json_editor.js +137 -127
  133. package/framework/components/chui_json_editor/styles.css +5 -5
  134. package/framework/components/chui_json_viewer/json_viewer.js +133 -114
  135. package/framework/components/chui_json_viewer/styles.css +9 -8
  136. package/framework/components/chui_kanban/kanban.js +78 -60
  137. package/framework/components/chui_kanban/styles.css +8 -4
  138. package/framework/components/chui_kbd/kbd.js +12 -10
  139. package/framework/components/chui_kbd/styles.css +1 -1
  140. package/framework/components/chui_label/label.js +31 -29
  141. package/framework/components/chui_label/styles.css +3 -3
  142. package/framework/components/chui_link/link.js +36 -29
  143. package/framework/components/chui_link/styles.css +11 -4
  144. package/framework/components/chui_list/list.js +42 -38
  145. package/framework/components/chui_list/styles.css +4 -3
  146. package/framework/components/chui_markdown_editor/markdown_editor.js +125 -109
  147. package/framework/components/chui_markdown_editor/styles.css +5 -5
  148. package/framework/components/chui_media/audio.js +457 -364
  149. package/framework/components/chui_media/audio_styles.css +74 -37
  150. package/framework/components/chui_media/image.js +99 -64
  151. package/framework/components/chui_media/image_compare.js +86 -55
  152. package/framework/components/chui_media/image_compare_styles.css +5 -5
  153. package/framework/components/chui_media/image_styles.css +4 -4
  154. package/framework/components/chui_media/video.js +264 -171
  155. package/framework/components/chui_media/video_styles.css +57 -24
  156. package/framework/components/chui_menu_bar/menu_bar.js +67 -65
  157. package/framework/components/chui_menu_bar/styles.css +14 -12
  158. package/framework/components/chui_message_bar/message_bar.js +551 -0
  159. package/framework/components/chui_message_bar/styles.css +248 -0
  160. package/framework/components/chui_modal/modal.js +81 -56
  161. package/framework/components/chui_modal/styles.css +3 -2
  162. package/framework/components/chui_notification/notification.js +107 -69
  163. package/framework/components/chui_notification/notification_download.js +28 -77
  164. package/framework/components/chui_notification/notification_download_card.js +115 -0
  165. package/framework/components/chui_notification/notification_download_progress.css +5 -4
  166. package/framework/components/chui_notification/notification_download_progress.js +73 -105
  167. package/framework/components/chui_notification/notification_update.js +44 -37
  168. package/framework/components/chui_notification/status_plate.css +3 -3
  169. package/framework/components/chui_notification/status_plate.js +2 -2
  170. package/framework/components/chui_notification/styles.css +6 -1
  171. package/framework/components/chui_notification/styles_download.css +2 -2
  172. package/framework/components/chui_notification/styles_update.css +3 -3
  173. package/framework/components/chui_org_chart/org_chart.js +101 -62
  174. package/framework/components/chui_org_chart/styles.css +2 -2
  175. package/framework/components/chui_pagination/pagination.js +65 -30
  176. package/framework/components/chui_pagination/styles.css +1 -1
  177. package/framework/components/chui_paragraph/paragraph.js +2 -2
  178. package/framework/components/chui_paragraph/styles.css +3 -3
  179. package/framework/components/chui_popover/popover.js +77 -50
  180. package/framework/components/chui_popover/styles.css +1 -1
  181. package/framework/components/chui_popups/popups.js +210 -181
  182. package/framework/components/chui_popups/styles.css +7 -7
  183. package/framework/components/chui_print_button/print_button.js +48 -33
  184. package/framework/components/chui_progress_bar/progress_bar.js +49 -19
  185. package/framework/components/chui_progress_bar/styles.css +6 -6
  186. package/framework/components/chui_progress_ring/progress_ring.js +32 -30
  187. package/framework/components/chui_progress_ring/styles.css +1 -1
  188. package/framework/components/chui_qrcode/qrcode.js +85 -41
  189. package/framework/components/chui_query_builder/query_builder.js +263 -170
  190. package/framework/components/chui_query_builder/styles.css +4 -4
  191. package/framework/components/chui_radio_group/radio_group.js +36 -26
  192. package/framework/components/chui_radio_group/styles.css +2 -2
  193. package/framework/components/chui_result/result.js +41 -31
  194. package/framework/components/chui_result/styles.css +3 -3
  195. package/framework/components/chui_scheduler/scheduler.js +126 -104
  196. package/framework/components/chui_scheduler/styles.css +11 -7
  197. package/framework/components/chui_screen_spinner/screen_spinner.js +167 -0
  198. package/framework/components/chui_screen_spinner/styles.css +49 -0
  199. package/framework/components/chui_segmented_control/segmented_control.js +90 -27
  200. package/framework/components/chui_segmented_control/styles.css +32 -6
  201. package/framework/components/chui_settings/settings.js +160 -87
  202. package/framework/components/chui_settings/styles.css +4 -4
  203. package/framework/components/chui_shortcut_help/shortcut_help.js +82 -61
  204. package/framework/components/chui_sidebar_nav/sidebar_nav.js +132 -53
  205. package/framework/components/chui_sidebar_nav/styles.css +9 -3
  206. package/framework/components/chui_skeleton/skeleton.js +29 -24
  207. package/framework/components/chui_slideshow/slideshow.js +122 -103
  208. package/framework/components/chui_slideshow/styles.css +22 -16
  209. package/framework/components/chui_spinner/spinner.js +17 -17
  210. package/framework/components/chui_spinner/styles.css +0 -1
  211. package/framework/components/chui_split_button/split_button.js +53 -30
  212. package/framework/components/chui_split_button/styles.css +22 -6
  213. package/framework/components/chui_splitter/splitter.js +46 -39
  214. package/framework/components/chui_splitter/styles.css +2 -2
  215. package/framework/components/chui_statistic/statistic.js +111 -84
  216. package/framework/components/chui_status_bar/status_bar.js +11 -9
  217. package/framework/components/chui_status_bar/styles.css +2 -2
  218. package/framework/components/chui_stepper/stepper.js +230 -54
  219. package/framework/components/chui_stepper/styles.css +79 -14
  220. package/framework/components/chui_sticky_bar/sticky_bar.js +53 -17
  221. package/framework/components/chui_sticky_bar/styles.css +11 -7
  222. package/framework/components/chui_tabs/chui_tabs.js +100 -46
  223. package/framework/components/chui_tabs/styles.css +43 -15
  224. package/framework/components/chui_text_editor/styles.css +24 -23
  225. package/framework/components/chui_text_editor/text_editor.js +103 -79
  226. package/framework/components/chui_text_editor/text_editor_panel.js +428 -367
  227. package/framework/components/chui_theme_toggle/theme_toggle.js +46 -25
  228. package/framework/components/chui_timeline/styles.css +3 -1
  229. package/framework/components/chui_timeline/timeline.js +14 -12
  230. package/framework/components/chui_toast_queue/styles.css +11 -11
  231. package/framework/components/chui_toast_queue/toast_queue.js +82 -73
  232. package/framework/components/chui_toolbar/styles.css +2 -2
  233. package/framework/components/chui_toolbar/toolbar.js +20 -13
  234. package/framework/components/chui_tooltip/styles.css +2 -2
  235. package/framework/components/chui_tooltip/tooltip.js +40 -27
  236. package/framework/components/chui_tour/styles.css +12 -7
  237. package/framework/components/chui_tour/tour.js +132 -98
  238. package/framework/components/chui_transfer/styles.css +8 -7
  239. package/framework/components/chui_transfer/transfer.js +143 -123
  240. package/framework/components/chui_tree_table/styles.css +4 -4
  241. package/framework/components/chui_tree_table/tree_table.js +88 -74
  242. package/framework/components/chui_tree_view/styles.css +14 -10
  243. package/framework/components/chui_tree_view/tree_view.js +298 -253
  244. package/framework/components/chui_user_bar/styles.css +145 -0
  245. package/framework/components/chui_user_bar/user_bar.js +402 -0
  246. package/framework/components/chui_user_list_bar/styles.css +173 -0
  247. package/framework/components/chui_user_list_bar/user_list_bar.js +485 -0
  248. package/framework/components/chui_watermark/watermark.js +41 -33
  249. package/framework/components/chui_webview/styles.css +2 -2
  250. package/framework/components/chui_webview/webview.js +64 -52
  251. package/framework/components/chui_write_bar/styles.css +172 -0
  252. package/framework/components/chui_write_bar/write_bar.js +320 -0
  253. package/framework/main_window.js +1234 -0
  254. package/framework/modules/chui_a11y/chui_a11y.js +153 -123
  255. package/framework/modules/chui_animations/animations.js +105 -43
  256. package/framework/modules/chui_animations/motion.js +120 -0
  257. package/framework/modules/chui_animations/styles.css +37 -4
  258. package/framework/modules/chui_bridge/preload.js +36 -25
  259. package/framework/modules/chui_functions.js +69 -63
  260. package/framework/modules/chui_highlight/chui_highlight.js +25 -22
  261. package/framework/modules/chui_highlight/styles.css +13 -10
  262. package/framework/modules/chui_i18n/chui_i18n.js +12 -10
  263. package/framework/modules/chui_i18n/locales/a11y.js +5 -5
  264. package/framework/modules/chui_i18n/locales/app_layout.js +5 -5
  265. package/framework/modules/chui_i18n/locales/calendar.js +3 -3
  266. package/framework/modules/chui_i18n/locales/common.js +3 -3
  267. package/framework/modules/chui_i18n/locales/data.js +36 -26
  268. package/framework/modules/chui_i18n/locales/editors.js +40 -13
  269. package/framework/modules/chui_i18n/locales/feedback.js +65 -3
  270. package/framework/modules/chui_i18n/locales/forms.js +8 -8
  271. package/framework/modules/chui_i18n/locales/graphics.js +8 -8
  272. package/framework/modules/chui_i18n/locales/media.js +4 -4
  273. package/framework/modules/chui_i18n/locales/navigation.js +12 -8
  274. package/framework/modules/chui_i18n/locales/validate.js +3 -3
  275. package/framework/modules/chui_json/chui_json.js +11 -11
  276. package/framework/modules/chui_layout/chui_layout.js +12 -10
  277. package/framework/modules/chui_logger/chui_logger.js +47 -28
  278. package/framework/modules/chui_page/page.js +39 -33
  279. package/framework/modules/chui_palette/palette.js +61 -0
  280. package/framework/modules/chui_qr/chui_qr.js +179 -88
  281. package/framework/modules/chui_scrollbar/chui_scrollbar.js +79 -68
  282. package/framework/modules/chui_scrollbar/styles.css +4 -2
  283. package/framework/modules/chui_services/chui_channels.js +27 -13
  284. package/framework/modules/chui_services/chui_services.js +47 -39
  285. package/framework/modules/chui_services/desktop.js +108 -101
  286. package/framework/modules/chui_sortable/chui_sortable.js +33 -28
  287. package/framework/modules/chui_validate/chui_validate.js +10 -7
  288. package/framework/tray_bar/chui_menu_items.js +136 -46
  289. package/index.d.ts +5046 -0
  290. package/index.js +199 -1254
  291. package/package.json +81 -68
  292. 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
- Опции конструктора: `name`, `sizes {width, height, minWidth, minHeight}`, `render`, `devTools`,
141
- `webSecurity`, `resizable`, `security {contextIsolation, csp, channels}`, `paths {downloadPath}`, `icon`.
142
- Если `icon` не передан, `Main` сам подставляет иконку приложения по умолчанию.
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
- #### `TelegramBot`
275
- Обёртка над Telegram Bot HTTP API (26 методов).
7
+ ## Установка
276
8
 
277
- ```javascript
278
- const bot = new TelegramBot('token');
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
- Сервисы системы живут в main-процессе (`globalShortcut`, `clipboard`, `app.addRecentDocument`
286
- доступны только там), а страница работает с ними через `Desktop`: он сам выбирает транспорт —
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
- Глобальная клавиша регистрируется в main один раз на комбинацию: сколько бы окон ни подписалось,
325
- `globalShortcut.register` вызывается один раз, событие уходит только окнам-подписчикам, а закрытие
326
- окна освобождает комбинации, которые больше никто не слушает.
17
+ ## Быстрый старт
327
18
 
328
- Main-сторона (для кода в `main.js`, без страницы):
19
+ `main.js` — окно и трей:
329
20
 
330
21
  ```javascript
331
- const { Shortcuts, Shell, Clipboard, RecentDocuments, TaskbarProgress, Theme, Print } = require('chuijs');
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: 'exampleApp',
25
+ name: "exampleApp",
26
+ sizes: { width: 1366, height: 768, minWidth: 960, minHeight: 540 },
395
27
  render: `${__dirname}/app/app.js`,
396
- // Строгий режим: contextIsolation + preload-мост + CSP вместо Node в рендерере
397
- security: { contextIsolation: true, csp: true, channels: ['preview:save'] }
28
+ paths: { downloadPath: path.join(Desktop.app.path("userData"), "downloads") },
398
29
  });
399
30
 
400
- // Или только для одного окна: main.start() остаётся в привычном режиме
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
- Готовый переключатель в интерфейсе — компонент `ThemeToggle` (см. дальше), а строка для страницы
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 {LAYOUT_ROLE, getLayout, findLayoutNode, requireLayoutNode} = require('chuijs/framework/modules/chui_layout/chui_layout');
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
- **Направление текста.** `I18n.setDirection('rtl')` (или локаль с `direction: 'rtl'`) ставит `dir`
603
- и `lang` на `<html>`; арабский (`ar`) объявляет RTL сам. Стили компонентов написаны на логических
604
- свойствах (`margin-inline-start`, `padding-inline`, `inset-inline-start`, `border-start-start-radius`,
605
- `text-align: start`), поэтому вёрстка зеркалится без отдельных RTL-правил. Физическое центрирование
606
- (`left: 50%` + `translate`) оставлено физическим намеренно: со сдвигом оно разъехалось бы. У элементов
607
- с зеркальным сдвигом (`Toggle`) есть явное правило для `[dir="rtl"]`.
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
- выбор в главном процессе — `Desktop.locale.get()/set(locale)/onChange(listener)` (как `Desktop.theme`),
616
- значение переживает перезапуск (`electron-store`, ключ `locale`). Тот же выбор применяется и в
617
- main-процессе: `Locale.restore()` при старте и канал `LOCALE_SET` вызывают `I18n.setLocale()`, поэтому
618
- меню «Открыть последние» и уведомления об обновлении переводятся вместе с окнами.
47
+ class App extends AppLayout {
48
+ constructor() {
49
+ super();
50
+ this.setRoute(new MainPage());
51
+ }
52
+ }
619
53
 
620
- ```javascript
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
- Скрипт окна подключается как preload и выполняется до документа, поэтому `dir`/`lang` ставятся ещё
626
- и из `AppLayout` — на настоящем документе.
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
- Общие правила компонентов — там же: [Опции и умолчания](docs/topics/options.html),
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
- Модули и десктоп-сервисы (`Main`, `I18n`, `Theme`, `Desktop`, `Log`) описаны выше, в разделе «Модули».
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
- - Нет CI: тесты (`npm test`, `node --test`) и линт есть, автоматического прогона на push нет.
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).