chuijs 4.0.2 → 4.0.3

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 (221) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +43 -644
  3. package/framework/appLayout/default/chui_app_layout.js +308 -260
  4. package/framework/appLayout/default/global_style.css +85 -48
  5. package/framework/components/chui_accordion/accordion.js +29 -26
  6. package/framework/components/chui_accordion/styles.css +6 -5
  7. package/framework/components/chui_action_sheet/action_sheet.js +59 -33
  8. package/framework/components/chui_action_sheet/styles.css +2 -1
  9. package/framework/components/chui_affix/affix.js +11 -6
  10. package/framework/components/chui_alert/alert.js +23 -14
  11. package/framework/components/chui_avatar/avatar.js +23 -22
  12. package/framework/components/chui_avatar_group/avatar_group.js +21 -19
  13. package/framework/components/chui_backtop/backtop.js +35 -19
  14. package/framework/components/chui_badge/badge.js +15 -13
  15. package/framework/components/chui_breadcrumb/breadcrumb.js +15 -13
  16. package/framework/components/chui_button/button.js +42 -22
  17. package/framework/components/chui_button/styles.css +2 -2
  18. package/framework/components/chui_calendar/calendar.js +12 -10
  19. package/framework/components/chui_card/card.js +43 -23
  20. package/framework/components/chui_chat/chat.js +72 -33
  21. package/framework/components/chui_clipboard_history/clipboard_history.js +30 -21
  22. package/framework/components/chui_clipboard_history/styles.css +4 -2
  23. package/framework/components/chui_code/code.js +2 -2
  24. package/framework/components/chui_code/styles.css +2 -2
  25. package/framework/components/chui_code_editor/code_editor.js +47 -31
  26. package/framework/components/chui_code_editor/styles.css +3 -2
  27. package/framework/components/chui_command_palette/command_palette.js +60 -37
  28. package/framework/components/chui_console/console.js +5 -5
  29. package/framework/components/chui_console/styles.css +1 -1
  30. package/framework/components/chui_content_block/content_block.js +33 -19
  31. package/framework/components/chui_content_block/styles.css +2 -2
  32. package/framework/components/chui_context_menu/context_menu.js +9 -4
  33. package/framework/components/chui_custom_element/custom_element.js +22 -15
  34. package/framework/components/chui_data_grid/data_grid.js +396 -234
  35. package/framework/components/chui_data_grid/styles.css +10 -8
  36. package/framework/components/chui_descriptions/descriptions.js +34 -17
  37. package/framework/components/chui_details/details.js +32 -26
  38. package/framework/components/chui_details/styles.css +5 -4
  39. package/framework/components/chui_diff_viewer/diff_viewer.js +91 -66
  40. package/framework/components/chui_diff_viewer/styles.css +1 -1
  41. package/framework/components/chui_divider/divider.js +13 -11
  42. package/framework/components/chui_drawer/drawer.js +27 -25
  43. package/framework/components/chui_drop_zone/drop_zone.js +31 -21
  44. package/framework/components/chui_empty_state/empty_state.js +20 -15
  45. package/framework/components/chui_fieldset/fieldset.js +37 -20
  46. package/framework/components/chui_fieldset/styles.css +1 -1
  47. package/framework/components/chui_file_explorer/file_explorer.js +157 -86
  48. package/framework/components/chui_file_explorer/styles.css +2 -1
  49. package/framework/components/chui_form/form.js +31 -19
  50. package/framework/components/chui_form/styles.css +1 -1
  51. package/framework/components/chui_gantt/gantt.js +64 -40
  52. package/framework/components/chui_graphs/graphs.js +301 -200
  53. package/framework/components/chui_graphs/styles.css +1 -1
  54. package/framework/components/chui_hero/hero.js +40 -22
  55. package/framework/components/chui_html_block/html_block.js +6 -6
  56. package/framework/components/chui_html_block/styles.css +2 -2
  57. package/framework/components/chui_hx/hx.js +3 -3
  58. package/framework/components/chui_hx/styles.css +11 -4
  59. package/framework/components/chui_icons/icons.js +2109 -2109
  60. package/framework/components/chui_icons/styles.css +2 -2
  61. package/framework/components/chui_inputs/chui_check_box/check_box.js +31 -19
  62. package/framework/components/chui_inputs/chui_check_box/styles.css +18 -18
  63. package/framework/components/chui_inputs/chui_chips/chips.js +50 -40
  64. package/framework/components/chui_inputs/chui_chips/styles.css +4 -2
  65. package/framework/components/chui_inputs/chui_color_picker/color_picker.js +36 -24
  66. package/framework/components/chui_inputs/chui_combo_box/combo_box.js +100 -82
  67. package/framework/components/chui_inputs/chui_combo_box/styles.css +14 -12
  68. package/framework/components/chui_inputs/chui_date/date.js +102 -66
  69. package/framework/components/chui_inputs/chui_date/styles.css +12 -11
  70. package/framework/components/chui_inputs/chui_date_range/date_range.js +40 -29
  71. package/framework/components/chui_inputs/chui_datetime/datetime.js +35 -27
  72. package/framework/components/chui_inputs/chui_email/email.js +43 -31
  73. package/framework/components/chui_inputs/chui_email/styles.css +5 -5
  74. package/framework/components/chui_inputs/chui_file/file.js +68 -41
  75. package/framework/components/chui_inputs/chui_file/styles.css +13 -12
  76. package/framework/components/chui_inputs/chui_hotkey/hotkey.js +61 -36
  77. package/framework/components/chui_inputs/chui_masked/masked.js +39 -28
  78. package/framework/components/chui_inputs/chui_mention/mention.js +77 -30
  79. package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +173 -153
  80. package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +9 -7
  81. package/framework/components/chui_inputs/chui_number/number.js +58 -41
  82. package/framework/components/chui_inputs/chui_number/styles.css +7 -7
  83. package/framework/components/chui_inputs/chui_otp/otp.js +38 -29
  84. package/framework/components/chui_inputs/chui_password/password.js +58 -36
  85. package/framework/components/chui_inputs/chui_password/styles.css +8 -8
  86. package/framework/components/chui_inputs/chui_radio_button/radio_button.js +37 -25
  87. package/framework/components/chui_inputs/chui_radio_button/styles.css +20 -20
  88. package/framework/components/chui_inputs/chui_rating/rating.js +26 -22
  89. package/framework/components/chui_inputs/chui_select_box/select_box.js +102 -78
  90. package/framework/components/chui_inputs/chui_select_box/styles.css +11 -11
  91. package/framework/components/chui_inputs/chui_slider/slider.js +29 -26
  92. package/framework/components/chui_inputs/chui_slider/styles.css +2 -1
  93. package/framework/components/chui_inputs/chui_text/styles.css +8 -8
  94. package/framework/components/chui_inputs/chui_text/text.js +65 -44
  95. package/framework/components/chui_inputs/chui_text_area/styles.css +6 -6
  96. package/framework/components/chui_inputs/chui_text_area/text_area.js +51 -28
  97. package/framework/components/chui_inputs/chui_time/styles.css +5 -3
  98. package/framework/components/chui_inputs/chui_time/time.js +38 -27
  99. package/framework/components/chui_inputs/chui_toggle/styles.css +3 -3
  100. package/framework/components/chui_inputs/chui_toggle/toggle.js +16 -16
  101. package/framework/components/chui_json_editor/json_editor.js +53 -43
  102. package/framework/components/chui_json_viewer/json_viewer.js +52 -33
  103. package/framework/components/chui_json_viewer/styles.css +3 -2
  104. package/framework/components/chui_kanban/kanban.js +52 -34
  105. package/framework/components/chui_kbd/kbd.js +12 -10
  106. package/framework/components/chui_label/label.js +14 -12
  107. package/framework/components/chui_label/styles.css +2 -2
  108. package/framework/components/chui_link/link.js +27 -20
  109. package/framework/components/chui_list/list.js +31 -27
  110. package/framework/components/chui_list/styles.css +2 -1
  111. package/framework/components/chui_markdown_editor/markdown_editor.js +60 -44
  112. package/framework/components/chui_media/audio.js +326 -227
  113. package/framework/components/chui_media/audio_styles.css +40 -21
  114. package/framework/components/chui_media/image.js +70 -38
  115. package/framework/components/chui_media/image_compare.js +52 -21
  116. package/framework/components/chui_media/image_styles.css +3 -3
  117. package/framework/components/chui_media/video.js +155 -62
  118. package/framework/components/chui_media/video_styles.css +33 -16
  119. package/framework/components/chui_menu_bar/menu_bar.js +26 -24
  120. package/framework/components/chui_menu_bar/styles.css +4 -2
  121. package/framework/components/chui_modal/modal.js +44 -43
  122. package/framework/components/chui_modal/styles.css +3 -2
  123. package/framework/components/chui_notification/notification.js +50 -34
  124. package/framework/components/chui_notification/notification_download.js +31 -25
  125. package/framework/components/chui_notification/notification_download_progress.css +3 -2
  126. package/framework/components/chui_notification/notification_download_progress.js +47 -41
  127. package/framework/components/chui_notification/notification_update.js +23 -16
  128. package/framework/components/chui_notification/status_plate.js +2 -2
  129. package/framework/components/chui_notification/styles_download.css +1 -1
  130. package/framework/components/chui_notification/styles_update.css +1 -1
  131. package/framework/components/chui_org_chart/org_chart.js +74 -35
  132. package/framework/components/chui_pagination/pagination.js +62 -27
  133. package/framework/components/chui_paragraph/paragraph.js +2 -2
  134. package/framework/components/chui_paragraph/styles.css +1 -1
  135. package/framework/components/chui_popover/popover.js +49 -28
  136. package/framework/components/chui_popups/popups.js +137 -108
  137. package/framework/components/chui_popups/styles.css +2 -2
  138. package/framework/components/chui_print_button/print_button.js +33 -23
  139. package/framework/components/chui_progress_bar/progress_bar.js +23 -15
  140. package/framework/components/chui_progress_bar/styles.css +2 -2
  141. package/framework/components/chui_progress_ring/progress_ring.js +17 -15
  142. package/framework/components/chui_qrcode/qrcode.js +75 -31
  143. package/framework/components/chui_query_builder/query_builder.js +216 -123
  144. package/framework/components/chui_radio_group/radio_group.js +36 -26
  145. package/framework/components/chui_radio_group/styles.css +1 -1
  146. package/framework/components/chui_result/result.js +26 -16
  147. package/framework/components/chui_scheduler/scheduler.js +57 -35
  148. package/framework/components/chui_scheduler/styles.css +6 -2
  149. package/framework/components/chui_segmented_control/segmented_control.js +27 -21
  150. package/framework/components/chui_settings/settings.js +122 -48
  151. package/framework/components/chui_shortcut_help/shortcut_help.js +55 -32
  152. package/framework/components/chui_sidebar_nav/sidebar_nav.js +33 -23
  153. package/framework/components/chui_skeleton/skeleton.js +29 -24
  154. package/framework/components/chui_slideshow/slideshow.js +60 -41
  155. package/framework/components/chui_slideshow/styles.css +18 -12
  156. package/framework/components/chui_spinner/spinner.js +8 -8
  157. package/framework/components/chui_spinner/styles.css +0 -1
  158. package/framework/components/chui_split_button/split_button.js +23 -18
  159. package/framework/components/chui_split_button/styles.css +1 -1
  160. package/framework/components/chui_splitter/splitter.js +35 -28
  161. package/framework/components/chui_statistic/statistic.js +65 -38
  162. package/framework/components/chui_status_bar/status_bar.js +11 -9
  163. package/framework/components/chui_stepper/stepper.js +27 -22
  164. package/framework/components/chui_sticky_bar/sticky_bar.js +9 -4
  165. package/framework/components/chui_sticky_bar/styles.css +3 -1
  166. package/framework/components/chui_tabs/chui_tabs.js +28 -22
  167. package/framework/components/chui_tabs/styles.css +3 -3
  168. package/framework/components/chui_text_editor/styles.css +20 -19
  169. package/framework/components/chui_text_editor/text_editor.js +85 -61
  170. package/framework/components/chui_text_editor/text_editor_panel.js +346 -284
  171. package/framework/components/chui_theme_toggle/theme_toggle.js +27 -22
  172. package/framework/components/chui_timeline/timeline.js +14 -12
  173. package/framework/components/chui_toast_queue/toast_queue.js +52 -46
  174. package/framework/components/chui_toolbar/toolbar.js +20 -13
  175. package/framework/components/chui_tooltip/tooltip.js +37 -24
  176. package/framework/components/chui_tour/styles.css +8 -3
  177. package/framework/components/chui_tour/tour.js +61 -27
  178. package/framework/components/chui_transfer/styles.css +2 -1
  179. package/framework/components/chui_transfer/transfer.js +75 -42
  180. package/framework/components/chui_tree_table/tree_table.js +43 -29
  181. package/framework/components/chui_tree_view/styles.css +4 -2
  182. package/framework/components/chui_tree_view/tree_view.js +142 -99
  183. package/framework/components/chui_watermark/watermark.js +24 -16
  184. package/framework/components/chui_webview/styles.css +2 -2
  185. package/framework/components/chui_webview/webview.js +62 -50
  186. package/framework/components/telegram_bot/chui_telegram_bot.js +71 -64
  187. package/framework/modules/chui_a11y/chui_a11y.js +77 -46
  188. package/framework/modules/chui_animations/animations.js +42 -42
  189. package/framework/modules/chui_animations/styles.css +1 -1
  190. package/framework/modules/chui_bridge/preload.js +36 -25
  191. package/framework/modules/chui_functions.js +52 -50
  192. package/framework/modules/chui_highlight/chui_highlight.js +25 -22
  193. package/framework/modules/chui_i18n/chui_i18n.js +9 -7
  194. package/framework/modules/chui_i18n/locales/a11y.js +5 -5
  195. package/framework/modules/chui_i18n/locales/app_layout.js +5 -5
  196. package/framework/modules/chui_i18n/locales/calendar.js +3 -3
  197. package/framework/modules/chui_i18n/locales/common.js +3 -3
  198. package/framework/modules/chui_i18n/locales/data.js +36 -26
  199. package/framework/modules/chui_i18n/locales/editors.js +40 -13
  200. package/framework/modules/chui_i18n/locales/feedback.js +3 -3
  201. package/framework/modules/chui_i18n/locales/forms.js +8 -8
  202. package/framework/modules/chui_i18n/locales/graphics.js +8 -8
  203. package/framework/modules/chui_i18n/locales/media.js +4 -4
  204. package/framework/modules/chui_i18n/locales/navigation.js +8 -8
  205. package/framework/modules/chui_i18n/locales/validate.js +3 -3
  206. package/framework/modules/chui_json/chui_json.js +9 -9
  207. package/framework/modules/chui_layout/chui_layout.js +12 -10
  208. package/framework/modules/chui_logger/chui_logger.js +29 -25
  209. package/framework/modules/chui_page/page.js +33 -27
  210. package/framework/modules/chui_qr/chui_qr.js +158 -67
  211. package/framework/modules/chui_scrollbar/chui_scrollbar.js +35 -24
  212. package/framework/modules/chui_scrollbar/styles.css +3 -1
  213. package/framework/modules/chui_services/chui_channels.js +27 -13
  214. package/framework/modules/chui_services/chui_services.js +39 -31
  215. package/framework/modules/chui_services/desktop.js +32 -31
  216. package/framework/modules/chui_sortable/chui_sortable.js +17 -12
  217. package/framework/modules/chui_validate/chui_validate.js +7 -4
  218. package/framework/tray_bar/chui_menu_items.js +136 -46
  219. package/index.d.ts +4814 -0
  220. package/index.js +385 -292
  221. package/package.json +79 -68
@@ -1,6 +1,6 @@
1
- const {Icon, Icons} = require("../chui_icons/icons");
2
- const {makeKeyboardButton} = require("../../modules/chui_a11y/chui_a11y");
3
- const {I18n} = require("../../modules/chui_i18n/chui_i18n");
1
+ const { Icon, Icons } = require("../chui_icons/icons");
2
+ const { makeKeyboardButton } = require("../../modules/chui_a11y/chui_a11y");
3
+ const { I18n } = require("../../modules/chui_i18n/chui_i18n");
4
4
 
5
5
  /** Идентификаторы панелей дерева для aria-controls */
6
6
  let tree_panel_counter = 0;
@@ -11,7 +11,7 @@ const DRAGGING_CLASS = "tree_view_button_dragging";
11
11
  const DROP_CLASSES = {
12
12
  before: "tree_view_button_drop_before",
13
13
  after: "tree_view_button_drop_after",
14
- inside: "tree_view_button_drop_inside"
14
+ inside: "tree_view_button_drop_inside",
15
15
  };
16
16
 
17
17
  /**
@@ -58,12 +58,12 @@ class TreeView {
58
58
  static SELECTION = {
59
59
  NONE: "none",
60
60
  SINGLE: "single",
61
- MULTIPLE: "multiple"
61
+ MULTIPLE: "multiple",
62
62
  };
63
63
  static DROP = {
64
64
  BEFORE: "before",
65
65
  AFTER: "after",
66
- INSIDE: "inside"
66
+ INSIDE: "inside",
67
67
  };
68
68
  // Узел → описание из фабрики: коллбэки и getSelected() отдают то же, что вернул TreeView.Button
69
69
  static #registry = new WeakMap();
@@ -112,36 +112,42 @@ class TreeView {
112
112
  #raf = null;
113
113
  #destroyed = false;
114
114
 
115
- constructor(options = {
116
- width: String(),
117
- components: [],
118
- selection: String(),
119
- draggable: Boolean(),
120
- moveOnDrop: Boolean(),
121
- label: String(),
122
- onSelect: undefined,
123
- onDrop: undefined,
124
- deferRender: Boolean(),
125
- virtual: undefined,
126
- variableHeight: Boolean(),
127
- estimatedRowHeight: undefined,
128
- height: String()
129
- }) {
130
- require('../../modules/chui_functions').setStyles(__dirname + "/styles.css", 'chUiJS_TreeView');
115
+ constructor(
116
+ options = {
117
+ width: String(),
118
+ components: [],
119
+ selection: String(),
120
+ draggable: Boolean(),
121
+ moveOnDrop: Boolean(),
122
+ label: String(),
123
+ onSelect: undefined,
124
+ onDrop: undefined,
125
+ deferRender: Boolean(),
126
+ virtual: undefined,
127
+ variableHeight: Boolean(),
128
+ estimatedRowHeight: undefined,
129
+ height: String(),
130
+ }
131
+ ) {
132
+ require("../../modules/chui_functions").setStyles(__dirname + "/styles.css", "chUiJS_TreeView");
131
133
  let main_test = document.createElement(`chui_tree_view_main_test`);
132
134
  main_test.setAttribute("role", "tree");
133
135
  this.#main_test = main_test;
134
136
  // Виртуализация включается явно: `virtual: true` или `{rowHeight, buffer}`
135
- this.#virtual = options.virtual === undefined || options.virtual === false
136
- ? undefined
137
- : (options.virtual === true ? {} : {...options.virtual});
137
+ this.#virtual =
138
+ options.virtual === undefined || options.virtual === false
139
+ ? undefined
140
+ : options.virtual === true
141
+ ? {}
142
+ : { ...options.virtual };
138
143
  // Переменная высота: функция `rowHeight(record, index)` — высоты из данных,
139
144
  // `variableHeight: true` — высоты измеряются по отрисованным строкам
140
145
  if (this.#virtual !== undefined) {
141
146
  if (options.variableHeight === true) this.#virtual.variableHeight = true;
142
147
  this.#variable_height = typeof this.#virtual.rowHeight === "function";
143
148
  this.#measure_dom = this.#virtual.variableHeight === true;
144
- if (this.#measure_dom && this.#virtual.estimatedRowHeight === undefined) this.#virtual.estimatedRowHeight = 32;
149
+ if (this.#measure_dom && this.#virtual.estimatedRowHeight === undefined)
150
+ this.#virtual.estimatedRowHeight = 32;
145
151
  }
146
152
  this.#selection_mode = options.selection === undefined ? TreeView.SELECTION.NONE : options.selection;
147
153
  this.#draggable = options.draggable === true;
@@ -152,7 +158,10 @@ class TreeView {
152
158
  // Отложенная отрисовка строк: узлы в DOM, но далёкие от окна не раскладываются
153
159
  if (options.deferRender === true) main_test.classList.add("tree_view_defer");
154
160
  if (this.#selection_mode !== TreeView.SELECTION.NONE) {
155
- main_test.setAttribute("aria-multiselectable", this.#selection_mode === TreeView.SELECTION.MULTIPLE ? "true" : "false");
161
+ main_test.setAttribute(
162
+ "aria-multiselectable",
163
+ this.#selection_mode === TreeView.SELECTION.MULTIPLE ? "true" : "false"
164
+ );
156
165
  main_test.addEventListener("click", this.#onClick);
157
166
  // Space приходит и от makeKeyboardButton (кликом), поэтому перехватываем его
158
167
  // с модификатором раньше — в фазе перехвата
@@ -170,23 +179,24 @@ class TreeView {
170
179
  if (options.width !== undefined) {
171
180
  this.#chui_tree_view.style.width = options.width;
172
181
  } else {
173
- this.#chui_tree_view.style.width = 'max-content'
182
+ this.#chui_tree_view.style.width = "max-content";
174
183
  }
175
184
  // Панели действий приходят опцией: частичный объект опций без них — дерево без панелей
176
185
  const toolbar_buttons = Array.isArray(options.components) ? options.components : [];
177
- toolbar_buttons.forEach(buttons => {
178
- main_test.appendChild(buttons.button)
186
+ toolbar_buttons.forEach((buttons) => {
187
+ main_test.appendChild(buttons.button);
179
188
  if (buttons.panel !== undefined) {
180
- main_test.appendChild(buttons.panel)
189
+ main_test.appendChild(buttons.panel);
181
190
  }
182
- })
191
+ });
183
192
  // Структурная модель строится один раз по полному DOM: дальше окно собирается из неё,
184
193
  // поэтому отрисовка перестаёт зависеть от того, что сейчас лежит в документе
185
194
  this.#buildStructure();
186
195
  if (this.#virtual !== undefined) {
187
196
  this.#chui_tree_view.style.height = options.height === undefined ? "400px" : options.height;
188
197
  // Высота строки одна для вёрстки и для арифметики распорок (в переменном режиме её нет)
189
- if (!this.#isVariable()) this.#chui_tree_view.style.setProperty("--tree_view_row_height", `${this.#rowHeight()}px`);
198
+ if (!this.#isVariable())
199
+ this.#chui_tree_view.style.setProperty("--tree_view_row_height", `${this.#rowHeight()}px`);
190
200
  this.#chui_tree_view.dataset.virtual = "true";
191
201
  main_test.classList.add("tree_view_virtual");
192
202
  this.#bindScroll();
@@ -195,7 +205,7 @@ class TreeView {
195
205
  }
196
206
  this.#applySelection(false);
197
207
  this.#syncDraggable();
198
- this.#chui_tree_view.appendChild(main_test)
208
+ this.#chui_tree_view.appendChild(main_test);
199
209
  if (this.#virtual !== undefined) this.#renderVirtual();
200
210
  }
201
211
 
@@ -285,7 +295,9 @@ class TreeView {
285
295
  // строки могут быть вне документа, но остаются видимыми по смыслу
286
296
  #items() {
287
297
  if (this.#virtual === undefined) {
288
- return [...this.#main_test.querySelectorAll('tree_view_button')].filter(button => this.#isVisibleRow(button));
298
+ return [...this.#main_test.querySelectorAll("tree_view_button")].filter((button) =>
299
+ this.#isVisibleRow(button)
300
+ );
289
301
  }
290
302
  return this.#project().map((row) => this.#nodes[row.index].button);
291
303
  }
@@ -308,7 +320,7 @@ class TreeView {
308
320
 
309
321
  /** Все кнопки, к которым применим выбор: в виртуальном режиме — по модели, а не по документу */
310
322
  #selectionTargets() {
311
- if (this.#virtual === undefined) return [...this.#main_test.querySelectorAll('tree_view_button')];
323
+ if (this.#virtual === undefined) return [...this.#main_test.querySelectorAll("tree_view_button")];
312
324
  return this.#project().map((row) => this.#nodes[row.index].button);
313
325
  }
314
326
 
@@ -337,7 +349,8 @@ class TreeView {
337
349
  for (const node of this.#selectionTargets()) {
338
350
  const selected = this.#selected.has(node);
339
351
  node.classList.toggle(SELECTED_CLASS, selected);
340
- if (this.#selection_mode !== TreeView.SELECTION.NONE) node.setAttribute("aria-selected", selected ? "true" : "false");
352
+ if (this.#selection_mode !== TreeView.SELECTION.NONE)
353
+ node.setAttribute("aria-selected", selected ? "true" : "false");
341
354
  }
342
355
  if (!announce || this.#on_select === undefined) return;
343
356
  const items = this.getSelected();
@@ -345,7 +358,9 @@ class TreeView {
345
358
  }
346
359
 
347
360
  #toggleNode(node) {
348
- const nodes = this.#selected.has(node) ? [...this.#selected].filter((entry) => entry !== node) : [...this.#selected, node];
361
+ const nodes = this.#selected.has(node)
362
+ ? [...this.#selected].filter((entry) => entry !== node)
363
+ : [...this.#selected, node];
349
364
  this.#anchor = node;
350
365
  this.#commitSelection(nodes);
351
366
  }
@@ -416,7 +431,7 @@ class TreeView {
416
431
  }
417
432
  if (target !== undefined && position !== undefined) {
418
433
  target.classList.add(DROP_CLASSES[position]);
419
- this.#drop_target = {node: target, position: position};
434
+ this.#drop_target = { node: target, position: position };
420
435
  }
421
436
  }
422
437
 
@@ -428,7 +443,10 @@ class TreeView {
428
443
  let reference;
429
444
  if (position === TreeView.DROP.INSIDE) {
430
445
  const panel = target.nextElementSibling;
431
- const html = panel !== null && panel.tagName.toLowerCase() === "tree_view_panel" ? panel.querySelector("tree_view_html") : null;
446
+ const html =
447
+ panel !== null && panel.tagName.toLowerCase() === "tree_view_panel"
448
+ ? panel.querySelector("tree_view_html")
449
+ : null;
432
450
  if (html === null) return false;
433
451
  container = html;
434
452
  reference = null;
@@ -451,7 +469,7 @@ class TreeView {
451
469
  #descriptor(node) {
452
470
  const item = TreeView.#registry.get(node);
453
471
  if (item !== undefined) return item;
454
- return {title: this.#title(node), button: node};
472
+ return { title: this.#title(node), button: node };
455
473
  }
456
474
 
457
475
  #title(node) {
@@ -495,7 +513,7 @@ class TreeView {
495
513
  parent: parent,
496
514
  children: [],
497
515
  title: this.#title(button),
498
- hidden: false
516
+ hidden: false,
499
517
  };
500
518
  this.#nodes.push(record);
501
519
  this.#node_index.set(button, index);
@@ -529,7 +547,7 @@ class TreeView {
529
547
  const record = this.#nodes[index];
530
548
  if (record === undefined || record.hidden) return 0;
531
549
  positions.set(index, rows.length);
532
- rows.push({index: index, depth: depth});
550
+ rows.push({ index: index, depth: depth });
533
551
  const own = variable ? this.#heightOf(index) : this.#rowHeight();
534
552
  heights.push(own);
535
553
  let size = 1;
@@ -632,7 +650,7 @@ class TreeView {
632
650
  #bindScroll() {
633
651
  if (this.#scroll_bound) return;
634
652
  this.#scroll_bound = true;
635
- this.#chui_tree_view.addEventListener("scroll", this.#onScroll, {passive: true});
653
+ this.#chui_tree_view.addEventListener("scroll", this.#onScroll, { passive: true });
636
654
  }
637
655
 
638
656
  #onScroll = () => {
@@ -699,9 +717,10 @@ class TreeView {
699
717
  let scrollTop = Math.min(Math.max(0, this.#chui_tree_view.scrollTop), Math.max(modelBottom, realBottom));
700
718
  // Низ окна для переменной высоты — позиция строки под нижней кромкой плюс одна строка,
701
719
  // иначе последняя видимая строка выпадала бы из окна
702
- const windowTo = (top) => variable
703
- ? Math.min(rows.length, positionFor(top + viewport) + 1 + buffer)
704
- : Math.min(rows.length, Math.ceil((top + viewport) / height) + buffer);
720
+ const windowTo = (top) =>
721
+ variable
722
+ ? Math.min(rows.length, positionFor(top + viewport) + 1 + buffer)
723
+ : Math.min(rows.length, Math.ceil((top + viewport) / height) + buffer);
705
724
  let from = Math.max(0, positionFor(scrollTop) - buffer);
706
725
  let to = windowTo(scrollTop);
707
726
  // Список сжался (поиск, сворачивание) — позиция ещё старая и указывает за конец: прижимаем
@@ -714,8 +733,15 @@ class TreeView {
714
733
  if (scrollTop !== this.#chui_tree_view.scrollTop) this.#chui_tree_view.scrollTop = scrollTop;
715
734
  // Ни окно, ни структура не изменились (прокрутка в пределах строки) — пересобирать
716
735
  // нечего: пересборка на каждом кадре только дёргала бы DOM и фокус
717
- if (!force && this.#win !== undefined && from === this.#win.from && to === this.#win.to
718
- && this.#win_rows === rows.length && this.#win_stamp === this.#stamp) return;
736
+ if (
737
+ !force &&
738
+ this.#win !== undefined &&
739
+ from === this.#win.from &&
740
+ to === this.#win.to &&
741
+ this.#win_rows === rows.length &&
742
+ this.#win_stamp === this.#stamp
743
+ )
744
+ return;
719
745
  // Кто держит фокус: снимок до мутации — после неё `document.activeElement` уже `body`
720
746
  const active = document.activeElement;
721
747
  const activeIndex = active instanceof Element ? this.#node_index.get(active) : undefined;
@@ -745,10 +771,10 @@ class TreeView {
745
771
  return node;
746
772
  };
747
773
  // Сколько занимает пропущенная ветка: в переменном режиме — суммарная высота её поддерева
748
- const subtreePx = (index) => variable ? (this.#subtree_heights.get(index) || 0) : sizeOf(index) * height;
774
+ const subtreePx = (index) => (variable ? this.#subtree_heights.get(index) || 0 : sizeOf(index) * height);
749
775
  const fill = (container, parentIndex) => {
750
776
  // Дети берутся из проекции: скрытое поиском и свёрнутое в неё уже не попадает
751
- const children = parentIndex === -1 ? this.#root_rows : (this.#child_rows.get(parentIndex) || []);
777
+ const children = parentIndex === -1 ? this.#root_rows : this.#child_rows.get(parentIndex) || [];
752
778
  const parts = [];
753
779
  let gap = 0;
754
780
  for (const index of children) {
@@ -788,7 +814,7 @@ class TreeView {
788
814
  this.#restoreFocus(keepIndex);
789
815
  this.#applySelection(false);
790
816
  this.#syncDraggable();
791
- this.#win = {from: from, to: to};
817
+ this.#win = { from: from, to: to };
792
818
  this.#win_stamp = this.#stamp;
793
819
  this.#win_rows = rows.length;
794
820
  }
@@ -818,14 +844,18 @@ class TreeView {
818
844
  if (index === undefined) return;
819
845
  const record = this.#nodes[index];
820
846
  if (record === undefined || document.activeElement === record.button) return;
821
- record.button.focus({preventScroll: true});
847
+ record.button.focus({ preventScroll: true });
822
848
  }
823
849
 
824
850
  /** Что сейчас в окне: {from, to} по плоскому списку (для стендов и приложений) */
825
- getVirtualWindow() { return this.#win; }
851
+ getVirtualWindow() {
852
+ return this.#win;
853
+ }
826
854
 
827
855
  /** Переменная высота строк включена (`rowHeight`-функция или `variableHeight`) */
828
- isVariableHeight() { return this.#isVariable(); }
856
+ isVariableHeight() {
857
+ return this.#isVariable();
858
+ }
829
859
 
830
860
  /** Высота строки с индексом модели: из данных, из замеров или заданная */
831
861
  getRowHeightAt(index = Number()) {
@@ -856,7 +886,7 @@ class TreeView {
856
886
  if (place === undefined) return;
857
887
  // В переменном режиме верх и высота строки берутся из смещений проекции
858
888
  const variable = this.#isVariable();
859
- const height = variable ? (this.#row_heights[place] || this.#rowHeight()) : this.#rowHeight();
889
+ const height = variable ? this.#row_heights[place] || this.#rowHeight() : this.#rowHeight();
860
890
  const viewport = Math.max(1, this.#chui_tree_view.clientHeight);
861
891
  const top = variable ? this.#offsets[place] : place * height;
862
892
  const scrollTop = this.#chui_tree_view.scrollTop;
@@ -921,17 +951,23 @@ class TreeView {
921
951
  }
922
952
 
923
953
  // === ПОИСК ===
924
- getSearchQuery() { return this.#query; }
925
- isSearching() { return this.#query !== ""; }
954
+ getSearchQuery() {
955
+ return this.#query;
956
+ }
957
+ isSearching() {
958
+ return this.#query !== "";
959
+ }
926
960
  /** Совпадения поиска (описания из фабрик), в порядке показа */
927
- getMatches() { return [...this.#matches].map((node) => this.#descriptor(node)); }
961
+ getMatches() {
962
+ return [...this.#matches].map((node) => this.#descriptor(node));
963
+ }
928
964
 
929
965
  /**
930
966
  * Показать только подходящие узлы и цепочку их предков; остальное убирается (`display: none`),
931
967
  * поэтому навигация и выбор дальше работают по видимому. `autoExpand` раскрывает предков
932
968
  * (без него совпадения внутри свёрнутых веток остаются скрытыми), `highlight` подсвечивает совпадения.
933
969
  */
934
- search(query = String(), options = {autoExpand: true, highlight: true}) {
970
+ search(query = String(), options = { autoExpand: true, highlight: true }) {
935
971
  this.clearSearch();
936
972
  const text = String(query).trim().toLocaleLowerCase();
937
973
  if (text === "") return this;
@@ -939,7 +975,7 @@ class TreeView {
939
975
  // В виртуальном режиме в документе только окно — ищем и скрываем по модели
940
976
  if (this.#virtual !== undefined) {
941
977
  this.#searchModel(text, options);
942
- this.#announce(I18n.t("treeView.found", {count: this.#matches.size}));
978
+ this.#announce(I18n.t("treeView.found", { count: this.#matches.size }));
943
979
  return this;
944
980
  }
945
981
  const buttons = [...this.#main_test.querySelectorAll("tree_view_button")];
@@ -972,7 +1008,7 @@ class TreeView {
972
1008
  if (options.highlight !== false) for (const node of this.#matches) node.classList.add("tree_view_button_match");
973
1009
  this.#touch();
974
1010
  if (this.#virtual !== undefined) this.#renderVirtual();
975
- this.#announce(I18n.t("treeView.found", {count: this.#matches.size}));
1011
+ this.#announce(I18n.t("treeView.found", { count: this.#matches.size }));
976
1012
  return this;
977
1013
  }
978
1014
 
@@ -1000,7 +1036,9 @@ class TreeView {
1000
1036
  return this;
1001
1037
  }
1002
1038
 
1003
- collapse(target) { return this.expand(target, false); }
1039
+ collapse(target) {
1040
+ return this.expand(target, false);
1041
+ }
1004
1042
 
1005
1043
  /** Раскрыть всё: в виртуальном режиме — единственный способ, строки вне окна не кликнуть */
1006
1044
  expandAll() {
@@ -1014,7 +1052,8 @@ class TreeView {
1014
1052
  }
1015
1053
 
1016
1054
  getExpanded() {
1017
- return this.#nodes.filter((record) => record.button.getAttribute("aria-expanded") === "true")
1055
+ return this.#nodes
1056
+ .filter((record) => record.button.getAttribute("aria-expanded") === "true")
1018
1057
  .map((record) => this.#descriptor(record.button));
1019
1058
  }
1020
1059
 
@@ -1045,14 +1084,16 @@ class TreeView {
1045
1084
  }
1046
1085
  }
1047
1086
  for (const record of this.#nodes) record.hidden = !visible.has(record.index);
1048
- if (options.highlight !== false) for (const button of this.#matches) button.classList.add("tree_view_button_match");
1087
+ if (options.highlight !== false)
1088
+ for (const button of this.#matches) button.classList.add("tree_view_button_match");
1049
1089
  this.#touch();
1050
1090
  this.#renderVirtual();
1051
1091
  }
1052
1092
 
1053
1093
  /** Снять фильтр поиска: возвращает все узлы и снимает подсветку */
1054
1094
  clearSearch() {
1055
- for (const node of this.#main_test.querySelectorAll("." + TreeView.#HIDDEN_CLASS)) node.classList.remove(TreeView.#HIDDEN_CLASS);
1095
+ for (const node of this.#main_test.querySelectorAll("." + TreeView.#HIDDEN_CLASS))
1096
+ node.classList.remove(TreeView.#HIDDEN_CLASS);
1056
1097
  for (const node of this.#matches) node.classList.remove("tree_view_button_match");
1057
1098
  for (const record of this.#nodes) record.hidden = false;
1058
1099
  const wasSearching = this.#query !== "";
@@ -1067,7 +1108,9 @@ class TreeView {
1067
1108
  // Статус поиска читает скринридер (узла нет, пока поиск не использовался)
1068
1109
  #announce(text = String()) {
1069
1110
  if (this.#status === undefined) {
1070
- this.#status = Object.assign(document.createElement("chui_visually_hidden"), {className: "chui_visually_hidden"});
1111
+ this.#status = Object.assign(document.createElement("chui_visually_hidden"), {
1112
+ className: "chui_visually_hidden",
1113
+ });
1071
1114
  this.#status.setAttribute("role", "status");
1072
1115
  this.#status.setAttribute("aria-live", "polite");
1073
1116
  this.#main_test.appendChild(this.#status);
@@ -1106,7 +1149,7 @@ class TreeView {
1106
1149
 
1107
1150
  #onNavigationKeyDown = (event) => {
1108
1151
  const items = this.#items();
1109
- const current = items.findIndex(item => item === document.activeElement);
1152
+ const current = items.findIndex((item) => item === document.activeElement);
1110
1153
  if (current === -1) return;
1111
1154
  if (event.key === "ArrowDown" || event.key === "ArrowUp") {
1112
1155
  if (event.altKey && this.#draggable) {
@@ -1126,7 +1169,7 @@ class TreeView {
1126
1169
  document.activeElement.click();
1127
1170
  }
1128
1171
  } else if (event.key === "ArrowLeft") {
1129
- const parent = document.activeElement.parentElement.closest('tree_view_button[aria-expanded]');
1172
+ const parent = document.activeElement.parentElement.closest("tree_view_button[aria-expanded]");
1130
1173
  if (document.activeElement.getAttribute("aria-expanded") === "true") {
1131
1174
  event.preventDefault();
1132
1175
  document.activeElement.click();
@@ -1200,20 +1243,20 @@ class TreeView {
1200
1243
  };
1201
1244
 
1202
1245
  static Button(options = { title: String(), listener: () => {} }) {
1203
- let button = document.createElement('tree_view_button');
1246
+ let button = document.createElement("tree_view_button");
1204
1247
  if (options.listener !== undefined) button.addEventListener("click", options.listener);
1205
1248
  makeKeyboardButton(button, "treeitem");
1206
- let button_text = document.createElement('tree_view_button_text');
1249
+ let button_text = document.createElement("tree_view_button_text");
1207
1250
  button_text.innerHTML = options.title;
1208
- button.appendChild(button_text)
1209
- const item = {title: options.title, button: button};
1251
+ button.appendChild(button_text);
1252
+ const item = { title: options.title, button: button };
1210
1253
  TreeView.#registry.set(button, item);
1211
1254
  return item;
1212
1255
  }
1213
1256
 
1214
1257
  static ExpandButton(options = { title: String(), subButtons: [], components: [], lazySubButtons: undefined }) {
1215
- let button = document.createElement('tree_view_button');
1216
- let panel = document.createElement('tree_view_panel')
1258
+ let button = document.createElement("tree_view_button");
1259
+ let panel = document.createElement("tree_view_panel");
1217
1260
  // Раскрытая панель переходит с фиксированной высоты на max-content: иначе высота
1218
1261
  // остаётся «замороженной» после первого раскрытия
1219
1262
  const transitionEndEvent = (event) => {
@@ -1224,29 +1267,29 @@ class TreeView {
1224
1267
  button.setAttribute("aria-controls", panel.id);
1225
1268
  button.setAttribute("aria-expanded", "false");
1226
1269
  makeKeyboardButton(button, "treeitem");
1227
- button.addEventListener('click', () => {
1270
+ button.addEventListener("click", () => {
1228
1271
  buildSubs();
1229
- const open = !button.classList.contains('tree_view_button_active');
1230
- button.classList.toggle('tree_view_button_active', open);
1272
+ const open = !button.classList.contains("tree_view_button_active");
1273
+ button.classList.toggle("tree_view_button_active", open);
1231
1274
  // Стрелка поворачивается по aria-expanded (styles.css) — состояние одно
1232
1275
  button.setAttribute("aria-expanded", open ? "true" : "false");
1233
1276
  if (open) {
1234
1277
  panel.style.maxHeight = panel.scrollHeight + "px";
1235
- panel.addEventListener('transitionend', transitionEndEvent);
1278
+ panel.addEventListener("transitionend", transitionEndEvent);
1236
1279
  } else {
1237
1280
  // Сначала фиксируем текущую высоту, иначе сжатие не анимируется
1238
1281
  panel.style.maxHeight = panel.scrollHeight + "px";
1239
1282
  void panel.offsetHeight;
1240
1283
  panel.style.maxHeight = "0px";
1241
1284
  }
1242
- })
1243
- let button_text = document.createElement('tree_view_button_text');
1285
+ });
1286
+ let button_text = document.createElement("tree_view_button_text");
1244
1287
  button_text.innerHTML = options.title;
1245
- button.appendChild(button_text)
1246
- let barrow = document.createElement('tree_view_button_arrow')
1288
+ button.appendChild(button_text);
1289
+ let barrow = document.createElement("tree_view_button_arrow");
1247
1290
  barrow.innerHTML = new Icon(Icons.HARDWARE.KEYBOARD_ARROW_DOWN).getHTML();
1248
- button.appendChild(barrow)
1249
- let html = document.createElement('tree_view_html')
1291
+ button.appendChild(barrow);
1292
+ let html = document.createElement("tree_view_html");
1250
1293
  // Ленивое поддерево: содержимое строится один раз — при первом раскрытии,
1251
1294
  // поэтому большое дерево не занимает DOM заранее (lazySubButtons: () => [...])
1252
1295
  let subs_built = false;
@@ -1254,34 +1297,34 @@ class TreeView {
1254
1297
  if (subs_built) return;
1255
1298
  subs_built = true;
1256
1299
  if (options.subButtons !== undefined) {
1257
- options.subButtons.forEach(sub => {
1258
- html.appendChild(sub.button)
1300
+ options.subButtons.forEach((sub) => {
1301
+ html.appendChild(sub.button);
1259
1302
  if (sub.panel !== undefined) {
1260
- html.appendChild(sub.panel)
1303
+ html.appendChild(sub.panel);
1261
1304
  }
1262
- })
1305
+ });
1263
1306
  }
1264
1307
  if (options.components !== undefined) {
1265
- options.components.forEach(sub => {
1266
- html.appendChild(sub.set())
1267
- })
1308
+ options.components.forEach((sub) => {
1309
+ html.appendChild(sub.set());
1310
+ });
1268
1311
  }
1269
1312
  if (options.lazySubButtons !== undefined) {
1270
- options.lazySubButtons().forEach(sub => {
1271
- html.appendChild(sub.button)
1313
+ options.lazySubButtons().forEach((sub) => {
1314
+ html.appendChild(sub.button);
1272
1315
  if (sub.panel !== undefined) {
1273
- html.appendChild(sub.panel)
1316
+ html.appendChild(sub.panel);
1274
1317
  }
1275
- })
1318
+ });
1276
1319
  }
1277
1320
  };
1278
1321
  // Без ленивой фабрики поведение прежнее — строим сразу
1279
1322
  if (options.lazySubButtons === undefined) buildSubs();
1280
- panel.appendChild(html)
1281
- const item = {title: options.title, button: button, panel: panel};
1323
+ panel.appendChild(html);
1324
+ const item = { title: options.title, button: button, panel: panel };
1282
1325
  TreeView.#registry.set(button, item);
1283
1326
  return item;
1284
1327
  }
1285
1328
  }
1286
1329
 
1287
- exports.TreeView = TreeView
1330
+ exports.TreeView = TreeView;
@@ -1,4 +1,4 @@
1
- const {setStyles, optionOr} = require('../../modules/chui_functions');
1
+ const { setStyles, optionOr } = require("../../modules/chui_functions");
2
2
 
3
3
  /** Схемы источника картинки: остальное считается локальным путём и читается как data URL */
4
4
  const URL_SCHEMES = ["data:", "http:", "https:", "file:", "blob:"];
@@ -32,7 +32,7 @@ const URL_SCHEMES = ["data:", "http:", "https:", "file:", "blob:"];
32
32
  */
33
33
  class Watermark {
34
34
  static #counter = 0;
35
- static #DEFAULT_GAP = {x: 100, y: 100};
35
+ static #DEFAULT_GAP = { x: 100, y: 100 };
36
36
  static #DEFAULT_ROTATE = -22;
37
37
  static #DEFAULT_OPACITY = 0.15;
38
38
  static #DEFAULT_FONT_SIZE = 16;
@@ -45,19 +45,27 @@ class Watermark {
45
45
  #text = undefined;
46
46
  #image = undefined;
47
47
  #image_node = undefined;
48
- #font = {size: Watermark.#DEFAULT_FONT_SIZE, weight: 400, family: undefined, color: undefined};
48
+ #font = { size: Watermark.#DEFAULT_FONT_SIZE, weight: 400, family: undefined, color: undefined };
49
49
  #rotate = Watermark.#DEFAULT_ROTATE;
50
- #gap = {...Watermark.#DEFAULT_GAP};
50
+ #gap = { ...Watermark.#DEFAULT_GAP };
51
51
  #opacity = Watermark.#DEFAULT_OPACITY;
52
52
  #z_index = Watermark.#DEFAULT_Z_INDEX;
53
53
  #scheme = undefined;
54
54
  #destroyed = false;
55
55
 
56
- constructor(options = {
57
- id: String(), text: String(), image: String(),
58
- font: Object(), rotate: Number(), gap: Object(), opacity: Number(),
59
- zIndex: Number(), components: []
60
- }) {
56
+ constructor(
57
+ options = {
58
+ id: String(),
59
+ text: String(),
60
+ image: String(),
61
+ font: Object(),
62
+ rotate: Number(),
63
+ gap: Object(),
64
+ opacity: Number(),
65
+ zIndex: Number(),
66
+ components: [],
67
+ }
68
+ ) {
61
69
  setStyles(__dirname + "/styles.css", "chUiJS_Watermark");
62
70
  Watermark.#counter += 1;
63
71
  this.#id = optionOr(options.id, `chui_watermark_${Watermark.#counter}`);
@@ -98,7 +106,7 @@ class Watermark {
98
106
 
99
107
  /** Настройки метки: `{size, weight, family, color}` */
100
108
  getFont() {
101
- return {...this.#font};
109
+ return { ...this.#font };
102
110
  }
103
111
 
104
112
  getRotate() {
@@ -107,7 +115,7 @@ class Watermark {
107
115
 
108
116
  /** Шаг между метками */
109
117
  getGap() {
110
- return {...this.#gap};
118
+ return { ...this.#gap };
111
119
  }
112
120
 
113
121
  getOpacity() {
@@ -245,12 +253,12 @@ class Watermark {
245
253
  }
246
254
 
247
255
  static #normalizeGap(gap = Object()) {
248
- const source = Array.isArray(gap) ? {x: gap[0], y: gap[1]} : gap;
256
+ const source = Array.isArray(gap) ? { x: gap[0], y: gap[1] } : gap;
249
257
  const x = Number(source === undefined ? undefined : source.x);
250
258
  const y = Number(source === undefined ? undefined : source.y);
251
259
  return {
252
260
  x: Number.isFinite(x) && x > 0 ? x : Watermark.#DEFAULT_GAP.x,
253
- y: Number.isFinite(y) && y > 0 ? y : Watermark.#DEFAULT_GAP.y
261
+ y: Number.isFinite(y) && y > 0 ? y : Watermark.#DEFAULT_GAP.y,
254
262
  };
255
263
  }
256
264
 
@@ -265,7 +273,7 @@ class Watermark {
265
273
  weight: this.#font.weight,
266
274
  // Шрифт и цвет палитры берём из вычисленного стиля: канва наследование не умеет
267
275
  family: optionOr(this.#font.family, style.fontFamily),
268
- color: optionOr(this.#font.color, style.color)
276
+ color: optionOr(this.#font.color, style.color),
269
277
  };
270
278
  }
271
279
 
@@ -283,7 +291,7 @@ class Watermark {
283
291
  return this;
284
292
  }
285
293
  const pixel_ratio = typeof window !== "undefined" && window.devicePixelRatio > 0 ? window.devicePixelRatio : 1;
286
- const tile = {x: this.#gap.x, y: this.#gap.y};
294
+ const tile = { x: this.#gap.x, y: this.#gap.y };
287
295
  // Плитка = две метки по каждой оси: на стыках соседних плиток рисунок сходится
288
296
  const canvas = document.createElement("canvas");
289
297
  canvas.width = Math.round(tile.x * 2 * pixel_ratio);
@@ -330,4 +338,4 @@ class Watermark {
330
338
  }
331
339
  }
332
340
 
333
- exports.Watermark = Watermark
341
+ exports.Watermark = Watermark;