wenay-react2 1.0.19 → 1.0.21

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 (77) hide show
  1. package/README.md +383 -382
  2. package/lib/common/api.d.ts +28 -0
  3. package/lib/common/api.js +41 -16
  4. package/lib/common/src/components/Buttons/MiniButton.d.ts +1 -0
  5. package/lib/common/src/components/Buttons/MiniButton.js +2 -2
  6. package/lib/common/src/components/Dnd/DraggableOutlineDiv.d.ts +1 -0
  7. package/lib/common/src/components/Dnd/DraggableOutlineDiv.js +10 -7
  8. package/lib/common/src/components/Dnd/RNDFunc.js +28 -17
  9. package/lib/common/src/components/Dnd/RNDFunc3.d.ts +27 -17
  10. package/lib/common/src/components/Dnd/RNDFunc3.js +107 -107
  11. package/lib/common/src/components/Dnd/Resizable.js +3 -3
  12. package/lib/common/src/components/Input.js +3 -3
  13. package/lib/common/src/components/Menu/RightMenu.js +17 -18
  14. package/lib/common/src/components/Menu/StickerMenu.d.ts +1 -3
  15. package/lib/common/src/components/Menu/StickerMenu.js +42 -28
  16. package/lib/common/src/components/Menu/index.d.ts +1 -1
  17. package/lib/common/src/components/Menu/index.js +1 -1
  18. package/lib/common/src/components/Modal/LeftModal.d.ts +14 -12
  19. package/lib/common/src/components/Modal/LeftModal.js +34 -52
  20. package/lib/common/src/components/Modal/Modal.d.ts +26 -12
  21. package/lib/common/src/components/Modal/Modal.js +66 -89
  22. package/lib/common/src/components/Modal/ModalContextProvider.d.ts +20 -3
  23. package/lib/common/src/components/Modal/ModalContextProvider.js +35 -8
  24. package/lib/common/src/components/MyResizeObserver.js +15 -18
  25. package/lib/common/src/components/Other.js +6 -5
  26. package/lib/common/src/components/Parameters.js +8 -7
  27. package/lib/common/src/components/ParametersEngine.js +36 -59
  28. package/lib/common/src/grid/agGrid4/agGrid4.d.ts +53 -0
  29. package/lib/common/src/grid/agGrid4/agGrid4.js +132 -0
  30. package/lib/common/src/grid/agGrid4/core.d.ts +56 -0
  31. package/lib/common/src/grid/agGrid4/core.js +127 -0
  32. package/lib/common/src/grid/agGrid4/index.d.ts +6 -0
  33. package/lib/common/src/grid/agGrid4/index.js +3 -0
  34. package/lib/common/src/grid/agGrid4/theme.d.ts +7 -0
  35. package/lib/common/src/grid/agGrid4/theme.js +18 -0
  36. package/lib/common/src/hooks/useAddDownAnyKey.d.ts +21 -2
  37. package/lib/common/src/hooks/useAddDownAnyKey.js +46 -9
  38. package/lib/common/src/hooks/useDraggable.d.ts +20 -2
  39. package/lib/common/src/hooks/useDraggable.js +146 -115
  40. package/lib/common/src/hooks/useOutside.d.ts +24 -4
  41. package/lib/common/src/hooks/useOutside.js +77 -26
  42. package/lib/common/src/logs/logs.d.ts +5 -2
  43. package/lib/common/src/logs/logs.js +18 -34
  44. package/lib/common/src/logs/logs3.d.ts +9 -9
  45. package/lib/common/src/logs/logs3.js +48 -39
  46. package/lib/common/src/logs/miniLogs.d.ts +3 -3
  47. package/lib/common/src/logs/miniLogs.js +28 -36
  48. package/lib/common/src/menu/menu.d.ts +18 -18
  49. package/lib/common/src/menu/menu.js +49 -25
  50. package/lib/common/src/menu/menuMouse.d.ts +2 -1
  51. package/lib/common/src/menu/menuMouse.js +5 -4
  52. package/lib/common/src/menu/menuR.d.ts +4 -3
  53. package/lib/common/src/menu/menuR.js +42 -38
  54. package/lib/common/src/myChart/1/myChart.d.ts +5 -5
  55. package/lib/common/src/myChart/1/myChart.js +58 -47
  56. package/lib/common/src/myChart/1/myChartTest.js +8 -4
  57. package/lib/common/src/myChart/chartEngine/chartEngineReact.d.ts +24 -27
  58. package/lib/common/src/myChart/chartEngine/chartEngineReact.js +189 -118
  59. package/lib/common/src/styles/styleGrid.d.ts +2 -1
  60. package/lib/common/src/styles/styleGrid.js +10 -12
  61. package/lib/common/src/styles/tokens.d.ts +39 -0
  62. package/lib/common/src/styles/tokens.js +40 -0
  63. package/lib/common/src/utils/applyTransactionAsyncUpdate.d.ts +7 -0
  64. package/lib/common/src/utils/applyTransactionAsyncUpdate.js +25 -19
  65. package/lib/common/src/utils/arrayPromise.d.ts +6 -0
  66. package/lib/common/src/utils/arrayPromise.js +7 -1
  67. package/lib/common/src/utils/cache.js +32 -24
  68. package/lib/common/src/utils/inputAutoStep.d.ts +1 -1
  69. package/lib/common/src/utils/inputAutoStep.js +30 -19
  70. package/lib/common/src/utils/mapMemory.js +15 -15
  71. package/lib/common/updateBy.d.ts +21 -2
  72. package/lib/common/updateBy.js +66 -131
  73. package/lib/index.js +0 -2
  74. package/lib/style/menuRight.css +13 -26
  75. package/lib/style/style.css +51 -39
  76. package/lib/style/tokens.css +34 -0
  77. package/package.json +2 -2
@@ -1,42 +1,35 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { timeLocalToStr_hhmmss } from "wenay-common2";
3
3
  import { AgGridReact } from "ag-grid-react";
4
- import { useRef } from "react";
4
+ const columns = [
5
+ {
6
+ field: "time",
7
+ sort: "desc",
8
+ width: 50,
9
+ valueFormatter: (e) => e.value ? timeLocalToStr_hhmmss(e.value) : e.value
10
+ },
11
+ {
12
+ field: "id",
13
+ width: 20,
14
+ },
15
+ {
16
+ field: "var",
17
+ width: 50,
18
+ },
19
+ {
20
+ field: "txt",
21
+ wrapText: true,
22
+ autoHeight: true,
23
+ width: 350
24
+ },
25
+ {
26
+ field: "address",
27
+ width: 150,
28
+ },
29
+ ];
5
30
  export function MiniLogs({ data, onClick }) {
6
- const apiGrid = useRef(null);
7
- const columns = [
8
- {
9
- field: "time",
10
- sort: "desc",
11
- width: 50,
12
- valueFormatter: (e) => e.value.time ? timeLocalToStr_hhmmss(e.value.time) : e.value.time
13
- },
14
- {
15
- field: "id",
16
- width: 20,
17
- },
18
- {
19
- field: "var",
20
- width: 50,
21
- },
22
- {
23
- field: "txt",
24
- wrapText: true,
25
- autoHeight: true,
26
- width: 350
27
- },
28
- {
29
- field: "address",
30
- width: 150,
31
- },
32
- ];
33
- return _jsx("div", { className: "maxSize", children: _jsx(AgGridReact
34
- // className = "ag-theme-alpine-dark ag-theme-alpine2" // ag-theme-alpine-dark3
35
- , {
36
- // className = "ag-theme-alpine-dark ag-theme-alpine2" // ag-theme-alpine-dark3
37
- suppressCellFocus: true, onGridReady: (a) => {
38
- apiGrid.current = a; //as GridReadyEvent<tColum>
39
- apiGrid.current.api.sizeColumnsToFit();
31
+ return _jsx("div", { className: "maxSize", children: _jsx(AgGridReact, { suppressCellFocus: true, onGridReady: (a) => {
32
+ a.api.sizeColumnsToFit();
40
33
  }, defaultColDef: {
41
34
  headerClass: () => ("gridTable-header"),
42
35
  resizable: true,
@@ -45,7 +38,6 @@ export function MiniLogs({ data, onClick }) {
45
38
  filter: true,
46
39
  wrapText: true,
47
40
  }, headerHeight: 30, rowHeight: 26, autoSizePadding: 1, rowData: data, columnDefs: columns, onCellMouseDown: (e) => {
48
- // @ts-ignore
49
41
  onClick?.(e);
50
42
  } }) });
51
43
  }
@@ -1,6 +1,6 @@
1
1
  import React, { ReactElement } from 'react';
2
2
  /*******************************************************
3
- * Типы данных для меню
3
+ * Menu data types
4
4
  *******************************************************/
5
5
  export type tMenuReactStrictly<T = any> = {
6
6
  name: string | ((status?: T) => string);
@@ -15,7 +15,7 @@ export type tMenuReactStrictly<T = any> = {
15
15
  };
16
16
  export type tMenuReact<T = any> = tMenuReactStrictly<T> | false | null | undefined;
17
17
  /*******************************************************
18
- * Вспомогательный тип
18
+ * Helper type
19
19
  *******************************************************/
20
20
  type tCounters = {
21
21
  ok?: number;
@@ -23,13 +23,13 @@ type tCounters = {
23
23
  count?: number;
24
24
  };
25
25
  /*******************************************************
26
- * Отображает счётчик/прогресс (анимация, кол-во ok/error)
26
+ * Displays counter/progress with animation and ok/error counts
27
27
  *******************************************************/
28
28
  declare function TimeNum({ data }: {
29
29
  data: tCounters;
30
30
  }): ReactElement;
31
31
  /*******************************************************
32
- * Основной элемент меню (пункт с onClick, счётчиками и т.д.)
32
+ * Main menu element with onClick and counters
33
33
  *******************************************************/
34
34
  declare function MenuElement({ data: item, toLeft, className, update, }: {
35
35
  data: Pick<tMenuReactStrictly, "onClick" | "active" | "name" | "getStatus">;
@@ -38,22 +38,22 @@ declare function MenuElement({ data: item, toLeft, className, update, }: {
38
38
  update: () => void;
39
39
  }): ReactElement;
40
40
  /*******************************************************
41
- * Компонент MenuBase отвечает за отрисовку всплывающего меню с поддержкой
42
- * вложенных подменю и управления их состоянием.
41
+ * MenuBase renders the popup menu with support for
42
+ * nested submenus and their state management.
43
43
  *
44
- * @param {Object} props - Пропсы компонента.
45
- * @param {Object} [props.coordinate] - Координаты и параметры отображения меню.
46
- * @param {number} props.coordinate.x - Координата X для размещения меню.
47
- * @param {number} props.coordinate.y - Координата Y для размещения меню.
48
- * @param {boolean} [props.coordinate.toLeft=false] - Указывает, должно ли меню быть смещено влево.
49
- * @param {number} [props.coordinate.left=0] - Дополнительное смещение влево, если меню отображается с вложенными элементами.
50
- * @param {tMenuReactStrictly[]} props.data - Массив объектов, описывающих элементы меню.
51
- * @param {number} [props.zIndex] - Z-index меню для управления видимостью при перекрытии.
52
- * @param {Function} [props.menu] - Функция, которая генерирует кастомный React элемент для отображения всего меню.
53
- * @param {Function} [props.menuElement] - Функция для генерации кастомного React элемента для отображения отдельного элемента меню.
54
- * @param {Function} [props.className] - Функция для задания CSS-классов для элементов меню.
44
+ * @param {Object} props - Component props.
45
+ * @param {Object} [props.coordinate] - Menu coordinates and display parameters.
46
+ * @param {number} props.coordinate.x - X coordinate for menu placement.
47
+ * @param {number} props.coordinate.y - Y coordinate for menu placement.
48
+ * @param {boolean} [props.coordinate.toLeft=false] - Whether the menu should be shifted left.
49
+ * @param {number} [props.coordinate.left=0] - Additional left offset when the menu has nested items.
50
+ * @param {tMenuReactStrictly[]} props.data - Array of objects describing menu items.
51
+ * @param {number} [props.zIndex] - Menu z-index for overlap visibility.
52
+ * @param {Function} [props.menu] - Function that generates a custom React element for the whole menu.
53
+ * @param {Function} [props.menuElement] - Function that generates a custom React element for one menu item.
54
+ * @param {Function} [props.className] - Function for assigning CSS classes to menu items.
55
55
  *
56
- * @returns {ReactElement} Визуальный элемент меню.
56
+ * @returns {ReactElement} Visual menu element.
57
57
  */
58
58
  type MenuBaseProps = {
59
59
  menu?: (arr: tMenuReact[]) => ReactElement;
@@ -2,12 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
3
3
  import { PromiseArrayListen, sleepAsync } from "wenay-common2";
4
4
  /*******************************************************
5
- * Отображает счётчик/прогресс (анимация, кол-во ok/error)
5
+ * Displays counter/progress with animation and ok/error counts
6
6
  *******************************************************/
7
7
  function TimeNum({ data }) {
8
- const refCounter = useRef(0);
9
- const [count, setCount] = useState(refCounter.current);
10
- refCounter.current = count;
8
+ const [count, setCount] = useState(0);
11
9
  const formatLabel = () => {
12
10
  if (!data.ok && !data.error)
13
11
  return count;
@@ -29,13 +27,13 @@ function TimeNum({ data }) {
29
27
  }, children: formatLabel() }));
30
28
  }
31
29
  /*******************************************************
32
- * Основной элемент меню (пункт с onClick, счётчиками и т.д.)
30
+ * Main menu element with onClick and counters
33
31
  *******************************************************/
34
32
  function MenuElement({ data: item, toLeft, className, update, }) {
35
33
  const unsubOk = useRef(null);
36
34
  const unsubErr = useRef(null);
37
35
  useEffect(() => {
38
- // При размонтировании отписываемся
36
+ // Unsubscribe on unmount
39
37
  return () => {
40
38
  unsubOk.current?.();
41
39
  unsubErr.current?.();
@@ -53,24 +51,37 @@ function MenuElement({ data: item, toLeft, className, update, }) {
53
51
  update();
54
52
  return;
55
53
  }
56
- // Если это массив "задач" (промисов или функций)
54
+ // If this is an array of tasks, promises, or functions
57
55
  if (Array.isArray(result)) {
58
56
  const tasks = result.filter(Boolean);
59
- const pa = PromiseArrayListen(tasks); // Допустим, внешняя функция
57
+ const pa = PromiseArrayListen(tasks); // External helper function
60
58
  setProgress({});
61
59
  unsubOk.current?.();
62
60
  unsubErr.current?.();
63
- unsubOk.current = pa.listenOk((data, i, countOk, countError, count) => setProgress({ ok: countOk, error: countError, count }));
64
- unsubErr.current = pa.listenError((error, i, countOk, countError, count) => setProgress({ ok: countOk, error: countError, count }));
61
+ // clear progress when all tasks settle, same as the single-promise path;
62
+ // previously the counter (and its 30ms interval) lived until unmount
63
+ const onTick = async (countOk, countError, count) => {
64
+ setProgress({ ok: countOk, error: countError, count });
65
+ if (countOk + countError >= count) {
66
+ unsubOk.current?.();
67
+ unsubErr.current?.();
68
+ unsubOk.current = null;
69
+ unsubErr.current = null;
70
+ await sleepAsync(500);
71
+ setProgress(null);
72
+ }
73
+ };
74
+ unsubOk.current = pa.listenOk((data, i, countOk, countError, count) => onTick(countOk, countError, count));
75
+ unsubErr.current = pa.listenError((error, i, countOk, countError, count) => onTick(countOk, countError, count));
65
76
  }
66
- // Если это один промис
77
+ // If this is a single promise
67
78
  else if (result instanceof Promise) {
68
79
  setProgress({});
69
80
  result
70
81
  .then(async (val) => {
71
82
  if (Array.isArray(val) && val.length) {
72
- // Если вернулся массив из Promise.allSettled
73
- // Считаем кол-во ok/error
83
+ // If an array from Promise.allSettled was returned
84
+ // Count ok/error results
74
85
  if (val[0]?.status === "fulfilled" || val[0]?.status === "rejected") {
75
86
  const t = { ok: 0, error: 0 };
76
87
  val.forEach((res) => {
@@ -105,15 +116,18 @@ const MenuItemWrapper = ({ item, index, update, className, isLeftAligned, leftPo
105
116
  const [onFocusMenu, setOnFocusMenu] = useState([]);
106
117
  useEffect(() => {
107
118
  if (item.status && item.next) {
119
+ let alive = true; // guard: do not set state after unmount or item change
108
120
  const result = item.next();
109
121
  if (result instanceof Promise) {
110
122
  result.then((val) => {
111
- setChildMenu(val.filter(Boolean));
123
+ if (alive)
124
+ setChildMenu(val.filter(Boolean));
112
125
  });
113
126
  }
114
127
  else {
115
128
  setChildMenu(result.filter(Boolean));
116
129
  }
130
+ return () => { alive = false; };
117
131
  }
118
132
  else {
119
133
  setChildMenu([]);
@@ -121,15 +135,18 @@ const MenuItemWrapper = ({ item, index, update, className, isLeftAligned, leftPo
121
135
  }, [item.status, item.next]);
122
136
  useEffect(() => {
123
137
  if (item.status && item.func) {
138
+ let alive = true;
124
139
  const result = item.func();
125
140
  if (result instanceof Promise) {
126
141
  result.then((val) => {
127
- setAsyncFuncElement(val);
142
+ if (alive)
143
+ setAsyncFuncElement(val);
128
144
  });
129
145
  }
130
146
  else {
131
147
  setAsyncFuncElement(result);
132
148
  }
149
+ return () => { alive = false; };
133
150
  }
134
151
  else {
135
152
  setAsyncFuncElement(null);
@@ -137,15 +154,18 @@ const MenuItemWrapper = ({ item, index, update, className, isLeftAligned, leftPo
137
154
  }, [item.status, item.func]);
138
155
  useEffect(() => {
139
156
  if (item.status && item.onFocus) {
157
+ let alive = true;
140
158
  const result = item.onFocus();
141
159
  if (result instanceof Promise) {
142
160
  result.then((val) => {
143
- setOnFocusMenu(val.filter(Boolean));
161
+ if (alive)
162
+ setOnFocusMenu(val.filter(Boolean));
144
163
  });
145
164
  }
146
165
  else {
147
166
  setOnFocusMenu(result.filter(Boolean));
148
167
  }
168
+ return () => { alive = false; };
149
169
  }
150
170
  else {
151
171
  setOnFocusMenu([]);
@@ -184,24 +204,31 @@ const MenuItemWrapper = ({ item, index, update, className, isLeftAligned, leftPo
184
204
  } }) }))] })] }));
185
205
  };
186
206
  export function MenuBase({ coordinate = { x: 0, y: 0, toLeft: false, left: 0 }, data, zIndex, menu, className, menuElement, }) {
187
- const [_, forceUpdate] = useState(false);
207
+ const [, forceUpdate] = useState(false);
188
208
  const update = () => forceUpdate((p) => !p);
189
209
  const refMenu = useRef(null);
190
- const dataMemo = useMemo(() => data.filter((e) => e), [data, data.length]);
210
+ const dataMemo = useMemo(() => data.filter(Boolean), [data, data.length]);
191
211
  const [top, setTop] = useState(coordinate.y);
192
212
  const [leftPos, setLeftPos] = useState(coordinate.x);
193
213
  const [menuWidth, setMenuWidth] = useState(0);
194
214
  const [isLeftAligned, setIsLeftAligned] = useState(!!coordinate.toLeft);
195
215
  const [xOffset, setXOffset] = useState(0);
216
+ // Mirror of applied top: vertical snap is recalculated from the base coordinate.y,
217
+ // not from prev; the setTop(prev + ...) delta formula accumulated between runs and drifted.
218
+ const appliedTop = useRef(top);
219
+ appliedTop.current = top;
196
220
  useLayoutEffect(() => {
197
221
  if (!refMenu.current)
198
222
  return;
199
223
  const rect = refMenu.current.getBoundingClientRect();
200
224
  const w = window.innerWidth, h = window.innerHeight;
201
- if (h - rect.bottom < 8)
202
- setTop((prev) => prev + (h - rect.bottom));
225
+ // Vertical: same bottom snap to viewport edge, but idempotently from the base.
226
+ const baseBottom = rect.bottom - (appliedTop.current - coordinate.y);
227
+ setTop(h - baseBottom < 8 ? coordinate.y + (h - baseBottom) : coordinate.y);
203
228
  setLeftPos(rect.x);
204
229
  setMenuWidth(rect.width);
230
+ // Horizontal: original sticky logic; reflect once without rollback,
231
+ // it is self-stabilizing and does not accumulate.
205
232
  if (!coordinate.toLeft && w - rect.right < 8 && rect.width < (coordinate.left ?? 0)) {
206
233
  setXOffset(rect.x - (coordinate.left ?? 0));
207
234
  setIsLeftAligned(true);
@@ -213,10 +240,7 @@ export function MenuBase({ coordinate = { x: 0, y: 0, toLeft: false, left: 0 },
213
240
  const alignStyle = isLeftAligned
214
241
  ? { display: "flex", flexDirection: "column-reverse", alignItems: "flex-end" }
215
242
  : {};
216
- return (_jsx("div", { ref: (el) => {
217
- if (el)
218
- refMenu.current = el;
219
- }, style: {
243
+ return (_jsx("div", { ref: refMenu, style: {
220
244
  position: "absolute",
221
245
  zIndex,
222
246
  paddingLeft: 3,
@@ -225,6 +249,6 @@ export function MenuBase({ coordinate = { x: 0, y: 0, toLeft: false, left: 0 },
225
249
  ...alignStyle,
226
250
  }, children: menu
227
251
  ? menu(dataMemo)
228
- : dataMemo.map((item, i, arr) => (_jsx(MenuItemWrapper, { item: item, index: i, update: update, className: className, isLeftAligned: isLeftAligned, leftPos: leftPos, menuElement: menuElement, fullArray: dataMemo }, i))) }));
252
+ : dataMemo.map((item, i, arr) => (_jsx(MenuItemWrapper, { item: item, index: i, update: update, className: className, isLeftAligned: isLeftAligned, leftPos: leftPos, menuElement: menuElement, fullArray: dataMemo }, typeof item.name === "string" ? item.name : i))) }));
229
253
  }
230
254
  export { TimeNum, MenuElement };
@@ -9,12 +9,13 @@ export declare const mouseMenuApi: {
9
9
  clicks: number;
10
10
  };
11
11
  };
12
- ReactMouse: (agr: Parameters<({ children, other, statusOn, onUnClick, zIndex, className }: {
12
+ ReactMouse: (agr: Parameters<({ children, other, statusOn, onUnClick, onConsume, zIndex, className }: {
13
13
  children: React.ReactElement;
14
14
  zIndex?: number;
15
15
  other?: () => (tMenuReact)[];
16
16
  statusOn?: boolean;
17
17
  onUnClick?: (e: boolean) => void;
18
+ onConsume?: () => void;
18
19
  className?: (active?: boolean) => string;
19
20
  }) => import("react/jsx-runtime").JSX.Element>[0]) => import("react/jsx-runtime").JSX.Element;
20
21
  ReactMenu: typeof MenuBase;
@@ -1,3 +1,4 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
1
2
  import { GetMenuR } from "./menuR";
2
3
  import { MenuBase } from "./menu";
3
4
  function GetMouseMenuApi(data) {
@@ -11,7 +12,7 @@ function GetMouseMenuApi(data) {
11
12
  name,
12
13
  get value() { return value; }
13
14
  };
14
- const map = new Map;
15
+ const map = new Map();
15
16
  function other() {
16
17
  if (map.has("only"))
17
18
  return map.get("only");
@@ -21,9 +22,9 @@ function GetMouseMenuApi(data) {
21
22
  }
22
23
  function ReactMouse(agr) {
23
24
  const datum = menuMouse.value; //staticGetAdd(menuMouse.name, menuMouse.value
24
- return MenuR({ ...(agr ?? {}), other: agr.other ? agr.other : other, statusOn: datum.status, onUnClick: () => {
25
- map.clear();
26
- } });
25
+ // JSX instead of a direct call: MenuR's hooks must live in its own fiber,
26
+ // a direct call ties them to whichever component renders ReactMouse
27
+ return _jsx(MenuR, { ...agr, other: agr.other ?? other, statusOn: datum.status, onConsume: () => { map.clear(); } });
27
28
  }
28
29
  return {
29
30
  bb, get map() { return map; }, get menuMouse() { return menuMouse; }, ReactMouse, ReactMenu: MenuBase
@@ -2,16 +2,17 @@ import React from "react";
2
2
  import { tMenuReact } from "./menu";
3
3
  export declare function GetMenuR(): {
4
4
  /**
5
- * Управление глобальной переменной `bb`, предотвращающей множественное
6
- * открытие меню.
5
+ * Manage the global `bb` variable that prevents opening multiple
6
+ * menus.
7
7
  */
8
8
  bb(b?: boolean): boolean | undefined;
9
- MenuR: ({ children, other, statusOn, onUnClick, zIndex, className }: {
9
+ MenuR: ({ children, other, statusOn, onUnClick, onConsume, zIndex, className }: {
10
10
  children: React.ReactElement;
11
11
  zIndex?: number;
12
12
  other?: () => (tMenuReact)[];
13
13
  statusOn?: boolean;
14
14
  onUnClick?: (e: boolean) => void;
15
+ onConsume?: () => void;
15
16
  className?: (active?: boolean) => string;
16
17
  }) => import("react/jsx-runtime").JSX.Element;
17
18
  };
@@ -2,30 +2,30 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React, { useEffect, useRef } from "react";
3
3
  import { MenuBase } from "./menu";
4
4
  import { DivOutsideClick } from "../hooks/useOutside";
5
- // Функция-обёртка для создания компонента MenuR и управления глобальной переменной `bb`
5
+ // Wrapper function for creating MenuR and managing the global `bb` variable.
6
6
  export function GetMenuR() {
7
- let bb = false; // Глобальная переменная, предотвращающая множественное открытие меню (флаг активности)
8
- // Основной компонент MenuR
9
- function MenuR({ children, other = () => [], statusOn = true, onUnClick, zIndex, className }) {
10
- const data = { x: 0, y: 0 }; // Текущая позиция элемента, где происходит взаимодействие
7
+ let bb = false; // Global activity flag that prevents opening multiple menus.
8
+ // Main MenuR component
9
+ function MenuR({ children, other = () => [], statusOn = true, onUnClick, onConsume, zIndex, className }) {
10
+ const data = { x: 0, y: 0 }; // Current position of the interaction element
11
11
  const [show, setShow] = React.useState({ status: false });
12
12
  useEffect(() => {
13
13
  return () => {
14
- bb = false; // Сбрасываем флаг активности при размонтировании компонента
14
+ bb = false; // Reset activity flag when the component unmounts
15
15
  };
16
16
  }, []);
17
- const timeEvent = useRef(Date.now()); // Временная метка для отслеживания двойных кликов
18
- let x = 0, y = 0; // Текущие координаты касания
19
- const touchTime = useRef(null); // Время начала касания
17
+ const timeEvent = useRef(Date.now()); // Timestamp for tracking double clicks
18
+ const touchXY = useRef({ x: 0, y: 0 }); // Current touch coordinates (ref: survives rerenders mid-gesture)
19
+ const touchTime = useRef(null); // Touch start time
20
20
  return (_jsxs("div", { className: "maxSize", style: { position: "relative" },
21
- // Для отключения стандартного контекстного меню
21
+ // Disable the native context menu
22
22
  onContextMenu: e => {
23
23
  if (statusOn) {
24
24
  e.preventDefault();
25
25
  e.stopPropagation();
26
26
  }
27
27
  },
28
- // Определение позиции взаимодействия для текущего элемента (например, контейнера)
28
+ // Determine the interaction position for the current element
29
29
  ref: (e) => {
30
30
  if (e) {
31
31
  const r = e.getBoundingClientRect();
@@ -33,37 +33,39 @@ export function GetMenuR() {
33
33
  data.y = r.y;
34
34
  }
35
35
  },
36
- // Запоминаем начальные координаты касания
36
+ // Store initial touch coordinates
37
37
  onTouchStart: (e) => {
38
- if (x == 0)
39
- x = e.touches[0].screenX;
40
- if (y == 0)
41
- y = e.touches[0].screenY;
38
+ if (touchXY.current.x == 0)
39
+ touchXY.current.x = e.touches[0].screenX;
40
+ if (touchXY.current.y == 0)
41
+ touchXY.current.y = e.touches[0].screenY;
42
42
  touchTime.current = Date.now();
43
43
  },
44
- // Проверка на значительное смещение (чтобы не показывать меню при скролле)
44
+ // Check for significant movement to avoid showing the menu while scrolling
45
45
  onTouchMove: (e) => {
46
46
  let x2 = e.touches[0].screenX;
47
47
  let y2 = e.touches[0].screenY;
48
48
  let pX = e.touches[0].pageX;
49
49
  let pY = e.touches[0].pageY;
50
- if ((Math.abs(x2 - x) / pX > 0.05) || (Math.abs(y2 - y) / pY > 0.05)) {
51
- touchTime.current = null; // Если смещение слишком большое, отключаем показ меню
50
+ if ((Math.abs(x2 - touchXY.current.x) / pX > 0.05) || (Math.abs(y2 - touchXY.current.y) / pY > 0.05)) {
51
+ touchTime.current = null; // If movement is too large, disable menu display
52
52
  }
53
53
  },
54
- // Определяем долгое касание для вызова контекстного меню
54
+ // Detect long touch for opening the context menu
55
55
  onTouchEnd: (e) => {
56
56
  if (statusOn) {
57
57
  if (touchTime.current && Date.now() - touchTime.current > 300) {
58
- // Если прошло больше 300 мс считываем как долгое нажатие
58
+ // More than 300 ms counts as a long press
59
59
  touchTime.current = null;
60
- x = y = 0;
60
+ touchXY.current.x = touchXY.current.y = 0;
61
61
  if (bb)
62
- return; // Если меню уже активно, выходим
62
+ return; // Menu is already active
63
63
  bb = true;
64
+ const menu = other().filter(el => el);
65
+ onConsume?.();
64
66
  setShow({
65
67
  status: true,
66
- // Устанавливаем координаты меню относительно элемента
68
+ menu,
67
69
  coordinate: {
68
70
  x: e.changedTouches[0].clientX - data.x,
69
71
  y: e.changedTouches[0].clientY - data.y
@@ -72,37 +74,39 @@ export function GetMenuR() {
72
74
  }
73
75
  }
74
76
  },
75
- // Отслеживаем двойной клик
77
+ // Track double click
76
78
  onDoubleClick: (event) => {
77
79
  timeEvent.current = Date.now();
78
80
  },
79
- // Обрабатываем клик правой кнопкой мыши или двойной клик
81
+ // Handle right mouse click or double click
80
82
  onMouseUp: (event) => {
81
83
  if (statusOn) {
82
84
  if (event.button == 2 || Date.now() - timeEvent.current < 300) {
83
85
  if (bb)
84
- return; // Если меню уже активно, ничего не делаем
86
+ return; // Menu is already active
85
87
  bb = true;
86
- setShow({ status: true, coordinate: { x: event.clientX - data.x, y: event.clientY - data.y } });
88
+ const menu = other().filter(el => el);
89
+ onConsume?.();
90
+ setShow({ status: true, menu, coordinate: { x: event.clientX - data.x, y: event.clientY - data.y } });
87
91
  }
88
92
  }
89
- }, children: [children /* Дочерний элемент, внутри которого отслеживаются события */, show.status && statusOn && (
90
- // Показываем контекстное меню
93
+ }, children: [children /* Child element whose events are tracked */, show.status && statusOn && (
94
+ // Show the context menu
91
95
  _jsx(DivOutsideClick, { outsideClick: () => {
92
- onUnClick?.(false); // Вызов обработчика при закрытии меню
93
96
  if (!bb)
94
- return;
95
- bb = false; // Меню больше не активно
96
- setShow({ status: false }); // Скрываем меню
97
+ return; // Menu is already inactive; do not call close handler
98
+ bb = false; // Menu is no longer active
99
+ onUnClick?.(false); // Call close handler
100
+ setShow({ status: false }); // Hide the menu
97
101
  }, children: _jsx(MenuBase, { className: className, data: [
98
102
  ...(show.plusMenu ?? []),
99
- ...other().filter(e => e)
103
+ ...(show.menu ?? [])
100
104
  ], coordinate: { ...show.coordinate }, zIndex: zIndex }) }))] }));
101
105
  }
102
106
  return {
103
107
  /**
104
- * Управление глобальной переменной `bb`, предотвращающей множественное
105
- * открытие меню.
108
+ * Manage the global `bb` variable that prevents opening multiple
109
+ * menus.
106
110
  */
107
111
  bb(b) {
108
112
  if (b != undefined) {
@@ -111,6 +115,6 @@ export function GetMenuR() {
111
115
  else
112
116
  return bb;
113
117
  },
114
- MenuR // Возвращаем созданный компонент
118
+ MenuR // Return the created component
115
119
  };
116
120
  }
@@ -1,12 +1,12 @@
1
1
  /**
2
- * Точка на графике: время (time) и цена (price).
2
+ * Chart point: time and price.
3
3
  */
4
4
  export interface IChartPoint {
5
5
  time: number;
6
6
  price: number;
7
7
  }
8
8
  /**
9
- * Настройки канваса.
9
+ * Canvas settings.
10
10
  */
11
11
  export interface IChartConfig {
12
12
  container: HTMLElement;
@@ -17,8 +17,8 @@ export interface IChartConfig {
17
17
  showPriceAxis?: boolean;
18
18
  }
19
19
  /**
20
- * Интерфейс объекта, который возвращает createChartCanvas:
21
- * методы управления зумом, прокруткой и т.д.
20
+ * Interface returned by createChartCanvas:
21
+ * methods for zoom, scrolling, etc.
22
22
  */
23
23
  export interface IChartCanvas {
24
24
  appendData(points: IChartPoint | IChartPoint[]): void;
@@ -35,6 +35,6 @@ export interface IChartCanvas {
35
35
  destroy(): void;
36
36
  }
37
37
  /**
38
- * Создаём функциональный канвас с возможностью зума колёсиком.
38
+ * Creates a functional canvas with wheel zoom support.
39
39
  */
40
40
  export declare function createChartCanvas(config: IChartConfig): IChartCanvas;