wenay-react2 1.0.20 → 1.0.22

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 (74) 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 +7 -6
  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 -105
  11. package/lib/common/src/components/Dnd/Resizable.js +3 -3
  12. package/lib/common/src/components/Menu/RightMenu.js +11 -17
  13. package/lib/common/src/components/Menu/StickerMenu.js +42 -28
  14. package/lib/common/src/components/Menu/index.d.ts +1 -1
  15. package/lib/common/src/components/Menu/index.js +1 -1
  16. package/lib/common/src/components/Modal/LeftModal.d.ts +14 -12
  17. package/lib/common/src/components/Modal/LeftModal.js +30 -16
  18. package/lib/common/src/components/Modal/Modal.d.ts +26 -12
  19. package/lib/common/src/components/Modal/Modal.js +66 -89
  20. package/lib/common/src/components/Modal/ModalContextProvider.d.ts +20 -3
  21. package/lib/common/src/components/Modal/ModalContextProvider.js +35 -8
  22. package/lib/common/src/components/MyResizeObserver.js +15 -18
  23. package/lib/common/src/components/Other.js +3 -2
  24. package/lib/common/src/components/Parameters.js +7 -6
  25. package/lib/common/src/components/ParametersEngine.js +25 -54
  26. package/lib/common/src/grid/agGrid4/agGrid4.d.ts +53 -0
  27. package/lib/common/src/grid/agGrid4/agGrid4.js +132 -0
  28. package/lib/common/src/grid/agGrid4/core.d.ts +56 -0
  29. package/lib/common/src/grid/agGrid4/core.js +127 -0
  30. package/lib/common/src/grid/agGrid4/index.d.ts +6 -0
  31. package/lib/common/src/grid/agGrid4/index.js +3 -0
  32. package/lib/common/src/grid/agGrid4/theme.d.ts +7 -0
  33. package/lib/common/src/grid/agGrid4/theme.js +18 -0
  34. package/lib/common/src/hooks/useAddDownAnyKey.d.ts +21 -2
  35. package/lib/common/src/hooks/useAddDownAnyKey.js +46 -8
  36. package/lib/common/src/hooks/useDraggable.d.ts +20 -2
  37. package/lib/common/src/hooks/useDraggable.js +146 -115
  38. package/lib/common/src/hooks/useOutside.d.ts +24 -4
  39. package/lib/common/src/hooks/useOutside.js +76 -27
  40. package/lib/common/src/logs/logs.d.ts +5 -2
  41. package/lib/common/src/logs/logs.js +15 -31
  42. package/lib/common/src/logs/logs3.d.ts +9 -9
  43. package/lib/common/src/logs/logs3.js +47 -38
  44. package/lib/common/src/logs/miniLogs.d.ts +3 -3
  45. package/lib/common/src/logs/miniLogs.js +28 -36
  46. package/lib/common/src/menu/menu.d.ts +18 -18
  47. package/lib/common/src/menu/menu.js +48 -24
  48. package/lib/common/src/menu/menuMouse.js +4 -1
  49. package/lib/common/src/menu/menuR.d.ts +2 -2
  50. package/lib/common/src/menu/menuR.js +34 -34
  51. package/lib/common/src/myChart/1/myChart.d.ts +5 -5
  52. package/lib/common/src/myChart/1/myChart.js +58 -47
  53. package/lib/common/src/myChart/1/myChartTest.js +8 -4
  54. package/lib/common/src/myChart/chartEngine/chartEngineReact.d.ts +24 -27
  55. package/lib/common/src/myChart/chartEngine/chartEngineReact.js +166 -117
  56. package/lib/common/src/styles/styleGrid.d.ts +2 -1
  57. package/lib/common/src/styles/styleGrid.js +10 -12
  58. package/lib/common/src/styles/tokens.d.ts +39 -0
  59. package/lib/common/src/styles/tokens.js +40 -0
  60. package/lib/common/src/utils/applyTransactionAsyncUpdate.d.ts +7 -0
  61. package/lib/common/src/utils/applyTransactionAsyncUpdate.js +19 -12
  62. package/lib/common/src/utils/arrayPromise.d.ts +6 -0
  63. package/lib/common/src/utils/arrayPromise.js +7 -1
  64. package/lib/common/src/utils/cache.js +24 -21
  65. package/lib/common/src/utils/inputAutoStep.d.ts +1 -1
  66. package/lib/common/src/utils/inputAutoStep.js +30 -19
  67. package/lib/common/src/utils/mapMemory.js +9 -10
  68. package/lib/common/updateBy.d.ts +21 -2
  69. package/lib/common/updateBy.js +66 -31
  70. package/lib/index.js +0 -2
  71. package/lib/style/menuRight.css +13 -26
  72. package/lib/style/style.css +51 -39
  73. package/lib/style/tokens.css +34 -0
  74. package/package.json +2 -2
@@ -1,65 +1,75 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState, useRef, useEffect } from 'react';
3
3
  const StickerMenu = () => {
4
- // Флаг состояния: открыто меню или закрыто
4
+ // State flag: menu is open or closed
5
5
  const [isOpen, setIsOpen] = useState(false);
6
- // Сдвиг по X в процессе перетаскивания
6
+ // X offset during dragging; duplicated in a ref so document listeners
7
+ // subscribe once instead of on every drag tick
7
8
  const [dragX, setDragX] = useState(0);
8
- // Рефы для отслеживания начала перетаскивания и самого процесса
9
+ const dragXRef = useRef(0);
10
+ const setDrag = (v) => {
11
+ dragXRef.current = v;
12
+ setDragX(v);
13
+ };
14
+ // Refs for tracking drag start and dragging itself
9
15
  const startXRef = useRef(null);
10
16
  const draggingRef = useRef(false);
11
- // Настройки размеров: общая ширина меню и ширина видимой части (стикер) при закрытом состоянии
12
- const menuWidth = 250; // общая ширина открытого меню
13
- const stickerWidth = 50; // ширина видимой части при закрытом меню
14
- // Начало перетаскивания (мышь)
17
+ const movedRef = useRef(false);
18
+ // Size settings: total menu width and visible sticker width when closed
19
+ const menuWidth = 250; // total width of the open menu
20
+ const stickerWidth = 50; // width of the visible part when the menu is closed
21
+ // Start dragging with mouse
15
22
  const handleMouseDown = (e) => {
16
23
  draggingRef.current = true;
17
24
  startXRef.current = e.clientX;
18
25
  };
19
- // Начало перетаскивания (касание)
26
+ // Start dragging with touch
20
27
  const handleTouchStart = (e) => {
21
28
  draggingRef.current = true;
22
29
  startXRef.current = e.touches[0].clientX;
23
30
  };
24
- // Обработка движения мыши
31
+ // Handle mouse movement
25
32
  const handleMouseMove = (e) => {
26
33
  if (!draggingRef.current || startXRef.current === null)
27
34
  return;
28
35
  const deltaX = e.clientX - startXRef.current;
29
- setDragX(deltaX);
36
+ setDrag(deltaX);
30
37
  };
31
- // Обработка движения при касании
38
+ // Handle touch movement
32
39
  const handleTouchMove = (e) => {
33
40
  if (!draggingRef.current || startXRef.current === null)
34
41
  return;
35
42
  const deltaX = e.touches[0].clientX - startXRef.current;
36
- setDragX(deltaX);
43
+ setDrag(deltaX);
37
44
  };
38
- // Завершение перетаскивания (мышь)
45
+ // Finish dragging with mouse
39
46
  const handleMouseUp = () => {
40
47
  if (!draggingRef.current)
41
48
  return;
42
49
  finishDrag();
43
50
  };
44
- // Завершение перетаскивания (касание)
51
+ // Finish dragging with touch
45
52
  const handleTouchEnd = () => {
46
53
  if (!draggingRef.current)
47
54
  return;
48
55
  finishDrag();
49
56
  };
50
- // Функция завершения перетаскивания: если сдвиг больше половины ширины меню переключаем состояние
57
+ // Finish dragging: switch state if offset is greater than half of the menu width
51
58
  const finishDrag = () => {
52
59
  draggingRef.current = false;
53
- if (dragX < -menuWidth / 2) {
60
+ const delta = dragXRef.current;
61
+ if (delta < -menuWidth / 2) {
54
62
  setIsOpen(true);
63
+ movedRef.current = true; // suppress the click that follows mouseup, it would toggle back
55
64
  }
56
- else if (dragX > menuWidth / 2) {
65
+ else if (delta > menuWidth / 2) {
57
66
  setIsOpen(false);
67
+ movedRef.current = true;
58
68
  }
59
- setDragX(0);
69
+ setDrag(0);
60
70
  startXRef.current = null;
61
71
  };
62
- // Подписываемся на глобальные события движения и завершения перетаскивания
72
+ // Subscribe to global movement and drag-finish events
63
73
  useEffect(() => {
64
74
  document.addEventListener('mousemove', handleMouseMove);
65
75
  document.addEventListener('touchmove', handleTouchMove);
@@ -71,25 +81,29 @@ const StickerMenu = () => {
71
81
  document.removeEventListener('mouseup', handleMouseUp);
72
82
  document.removeEventListener('touchend', handleTouchEnd);
73
83
  };
74
- }, [dragX]);
75
- // Переключение состояния меню по клику
84
+ }, []);
85
+ // Toggle menu state on click
76
86
  const handleClick = () => {
87
+ if (movedRef.current) {
88
+ movedRef.current = false;
89
+ return;
90
+ }
77
91
  setIsOpen(!isOpen);
78
92
  };
79
93
  /*
80
- Вычисляем итоговый сдвиг по X:
81
- - Когда меню закрыто, сдвигаем его влево так, чтобы виден был только стикер.
82
- - При перетаскивании корректируем позицию относительно текущего сдвига.
94
+ Calculate the final X offset:
95
+ - When the menu is closed, shift it left so only the sticker is visible.
96
+ - During dragging, adjust the position relative to the current offset.
83
97
  */
84
98
  let translateX = 0;
85
99
  if (dragX !== 0) {
86
- // Если меню открыто, перетаскиваем вправо (открытие) только в отрицательном направлении
87
- // Если закрыто перетаскиваем влево (открытие) только в положительном направлении
100
+ // If the menu is open, drag right only in the negative direction
101
+ // If closed, drag left only in the positive direction
88
102
  translateX = isOpen ? Math.min(0, dragX) : Math.max(0, dragX);
89
103
  }
90
104
  const baseTranslate = isOpen ? 0 : -(menuWidth - stickerWidth);
91
105
  const finalTranslate = baseTranslate + translateX;
92
- // Стили для контейнера меню
106
+ // Menu container styles
93
107
  const containerStyle = {
94
108
  position: 'fixed',
95
109
  top: '50%',
@@ -105,6 +119,6 @@ const StickerMenu = () => {
105
119
  userSelect: 'none',
106
120
  overflow: 'hidden'
107
121
  };
108
- return (_jsx("div", { style: containerStyle, onMouseDown: handleMouseDown, onTouchStart: handleTouchStart, onClick: handleClick, children: _jsxs("div", { style: { padding: '10px' }, children: [_jsx("h3", { children: "\u041C\u0435\u043D\u044E" }), isOpen && (_jsxs("ul", { style: { listStyle: 'none', padding: 0 }, children: [_jsx("li", { children: "\u041F\u0443\u043D\u043A\u0442 1" }), _jsx("li", { children: "\u041F\u0443\u043D\u043A\u0442 2" }), _jsx("li", { children: "\u041F\u0443\u043D\u043A\u0442 3" })] }))] }) }));
122
+ return (_jsx("div", { style: containerStyle, onMouseDown: handleMouseDown, onTouchStart: handleTouchStart, onClick: handleClick, children: _jsxs("div", { style: { padding: '10px' }, children: [_jsx("h3", { children: "Menu" }), isOpen && (_jsxs("ul", { style: { listStyle: 'none', padding: 0 }, children: [_jsx("li", { children: "Item 1" }), _jsx("li", { children: "Item 2" }), _jsx("li", { children: "Item 3" })] }))] }) }));
109
123
  };
110
124
  export default StickerMenu;
@@ -1,2 +1,2 @@
1
- export * from './StickerMenu';
1
+ export { default as StickerMenu } from './StickerMenu';
2
2
  export * from './RightMenu';
@@ -1,2 +1,2 @@
1
- export * from './StickerMenu';
1
+ export { default as StickerMenu } from './StickerMenu';
2
2
  export * from './RightMenu';
@@ -19,18 +19,19 @@ export declare function getApiLeftMenu(): {
19
19
  set(jsx: React.JSX.Element | null): void;
20
20
  JSX: React.JSX.Element | null;
21
21
  Render(): React.JSX.Element | null;
22
- addJSX(jsx: React.JSX.Element): React.JSX.Element;
23
- dellBy(jsx: React.JSX.Element): void;
24
- readonly arrJSX: import("react/jsx-runtime").JSX.Element[];
25
- RenderArr(): import("react/jsx-runtime").JSX.Element[];
22
+ addJSX<A extends React.JSX.Element | null>(jsx: A): A;
23
+ dellBy(jsx: React.JSX.Element | null): void;
24
+ readonly arrJSX: (import("react/jsx-runtime").JSX.Element | null)[];
25
+ RenderArr(): (import("react/jsx-runtime").JSX.Element | null)[];
26
26
  };
27
27
  renderBy(): void;
28
28
  getMenu: () => Map<string, MenuItem[]>;
29
29
  setMenu: (items: (MenuItemPartial | MenuItem)[], key?: string) => void;
30
- Modal2: ({ menu, zIndex, zIndex0, key }: {
30
+ Modal2: ({ menu, zIndex, zIndex0, menuKey }: {
31
31
  zIndex: number;
32
32
  zIndex0?: number;
33
- key?: string;
33
+ /** Store key for this menu; the former `key` prop never worked (React strips it from props). */
34
+ menuKey?: string;
34
35
  menu?: (MenuItemPartial | MenuItem)[];
35
36
  }) => import("react/jsx-runtime").JSX.Element;
36
37
  };
@@ -39,18 +40,19 @@ export declare const ApiLeftMenu: {
39
40
  set(jsx: React.JSX.Element | null): void;
40
41
  JSX: React.JSX.Element | null;
41
42
  Render(): React.JSX.Element | null;
42
- addJSX(jsx: React.JSX.Element): React.JSX.Element;
43
- dellBy(jsx: React.JSX.Element): void;
44
- readonly arrJSX: import("react/jsx-runtime").JSX.Element[];
45
- RenderArr(): import("react/jsx-runtime").JSX.Element[];
43
+ addJSX<A extends React.JSX.Element | null>(jsx: A): A;
44
+ dellBy(jsx: React.JSX.Element | null): void;
45
+ readonly arrJSX: (import("react/jsx-runtime").JSX.Element | null)[];
46
+ RenderArr(): (import("react/jsx-runtime").JSX.Element | null)[];
46
47
  };
47
48
  renderBy(): void;
48
49
  getMenu: () => Map<string, MenuItem[]>;
49
50
  setMenu: (items: (MenuItemPartial | MenuItem)[], key?: string) => void;
50
- Modal2: ({ menu, zIndex, zIndex0, key }: {
51
+ Modal2: ({ menu, zIndex, zIndex0, menuKey }: {
51
52
  zIndex: number;
52
53
  zIndex0?: number;
53
- key?: string;
54
+ /** Store key for this menu; the former `key` prop never worked (React strips it from props). */
55
+ menuKey?: string;
54
56
  menu?: (MenuItemPartial | MenuItem)[];
55
57
  }) => import("react/jsx-runtime").JSX.Element;
56
58
  };
@@ -42,17 +42,21 @@ function SidebarMenuComponent({ y_, x_, api, arr, zIndex }) {
42
42
  textDecoration: "inherit",
43
43
  cursor: "default",
44
44
  }, children: e[0] }) }, i)));
45
- // Smooth animation function to target position
45
+ const mountedRef = useRef(true);
46
+ useEffect(() => {
47
+ mountedRef.current = true;
48
+ return () => { mountedRef.current = false; };
49
+ }, []);
50
+ // Smooth animation function to target position; cancels on unmount,
51
+ // and the returned promise now resolves at the end (recursion was not awaited)
46
52
  const animateToPosition = async (target) => {
47
53
  lastPosition.current.auto = true;
48
54
  const step = 40;
49
- if (!lastPosition.current.auto)
50
- return;
51
- const animate = async () => {
52
- if (!lastPosition.current.auto || currentPosition.current.x === target)
53
- return;
55
+ while (lastPosition.current.auto && currentPosition.current.x !== target) {
54
56
  const direction = target > currentPosition.current.x ? 1 : -1;
55
57
  await sleepAsync(10);
58
+ if (!mountedRef.current || !lastPosition.current.auto)
59
+ return;
56
60
  const nextPos = currentPosition.current.x + direction * step;
57
61
  if (Math.abs(target - nextPos) < step) {
58
62
  lastPosition.current.auto = false;
@@ -64,9 +68,7 @@ function SidebarMenuComponent({ y_, x_, api, arr, zIndex }) {
64
68
  }
65
69
  currentPosition.current.x = nextPos;
66
70
  setX(nextPos);
67
- animate();
68
- };
69
- await animate();
71
+ }
70
72
  };
71
73
  useEffect(() => {
72
74
  const menuApi = {
@@ -203,11 +205,11 @@ export function getApiLeftMenu() {
203
205
  color: "rgba(255,255,255,0.1)"
204
206
  }, children: textB })), children()] }));
205
207
  };
206
- let menuApi = null;
207
208
  const menuStore = new Map();
208
209
  const setMenu = (items, key = "base") => {
209
210
  const colorGen = colorGenerator2({ min: 0, max: 90 });
210
- const currentMenuLength = getAllMenuItems().length;
211
+ // exclude this key's old items, otherwise a repeated setMenu shifts default colors
212
+ const currentMenuLength = getAllMenuItems().length - (menuStore.get(key)?.length ?? 0);
211
213
  const baseColors = [];
212
214
  for (let i = 0; i < currentMenuLength + items.length; i++) {
213
215
  const colorResult = colorGen.next();
@@ -227,11 +229,23 @@ export function getApiLeftMenu() {
227
229
  function getAllMenuItems() {
228
230
  return [...menuStore.values()].flat();
229
231
  }
230
- function Modal2({ menu, zIndex, zIndex0, key }) {
231
- if (menu)
232
- setMenu(menu, key);
232
+ function Modal2({ menu, zIndex, zIndex0, menuKey }) {
233
+ const lastSet = useRef(null);
234
+ // Set in an effect, not during render: otherwise StrictMode sets twice and every render has a side effect.
235
+ useEffect(() => {
236
+ if (!menu)
237
+ return;
238
+ const prev = lastSet.current;
239
+ // shallow compare: skip the store rewrite when an inline array has the same items
240
+ if (prev && prev.menuKey === menuKey && prev.menu.length === menu.length
241
+ && prev.menu.every((el, i) => el === menu[i]))
242
+ return;
243
+ lastSet.current = { menu, menuKey };
244
+ setMenu(menu, menuKey);
245
+ renderBy(menuStore);
246
+ }, [menu, menuKey]);
233
247
  updateBy(menuStore);
234
- return (_jsxs("div", { className: "maxSize", style: { position: "absolute", zIndex: zIndex0 }, children: [_jsx(modal.Render, {}), _jsx(LeftMenuComponent, { zIndex: zIndex, api: a => menuApi = a, menu: getAllMenuItems() })] }));
248
+ return (_jsxs("div", { className: "maxSize", style: { position: "absolute", zIndex: zIndex0 }, children: [_jsx(modal.Render, {}), _jsx(LeftMenuComponent, { zIndex: zIndex, api: () => { }, menu: getAllMenuItems() })] }));
235
249
  }
236
250
  const modal = GetModalJSX();
237
251
  return {
@@ -244,7 +258,7 @@ export function getApiLeftMenu() {
244
258
  }
245
259
  export const ApiLeftMenu = getApiLeftMenu();
246
260
  export function TestLeft333() {
247
- // тест-меню перенесено сюда из уровня модуля раньше ApiLeftMenu.setMenu(...) выполнялся при импорте и протекал всем потребителям
261
+ // Test menu moved here from module scope; previously ApiLeftMenu.setMenu(...) ran on import and leaked to all consumers.
248
262
  return _jsx(ApiLeftMenu.Modal2, { zIndex: 20, menu: [
249
263
  { button: _jsx("div", { style: { width: 200, height: 50, background: "rgb(92,50,213)" }, children: "1" }), el: () => _jsx("div", { children: "1" }), color: "rgb(92,50,213)" },
250
264
  { button: _jsx("div", { style: { width: 200, height: 50, background: "rgb(98,149,58)" }, children: "2" }), el: () => _jsx("div", { children: "2" }) },
@@ -1,30 +1,44 @@
1
1
  import React from "react";
2
+ import type { ModalApi } from "./ModalContextProvider";
3
+ type LegacyModalSetter = (jsx: React.ReactNode | null) => void;
4
+ type ModalTarget = LegacyModalSetter | ModalApi;
2
5
  export declare function inputModal({ setModalJSX, func, name, txt }: {
3
6
  txt?: string;
4
7
  name?: string;
5
- setModalJSX: React.Dispatch<React.SetStateAction<React.JSX.Element | null>>;
8
+ /** Any modal setter: setState/useModal or ModalApi from useModal */
9
+ setModalJSX: ModalTarget;
6
10
  func: (txt: string) => void;
7
11
  }): void;
8
- export declare function confirmModal({ setModalJSX, func }: {
9
- setModalJSX: React.Dispatch<React.SetStateAction<React.JSX.Element | null>>;
12
+ export declare function confirmModal({ setModalJSX, func, password }: {
13
+ /** Any modal setter: setState/useModal or ModalApi from useModal */
14
+ setModalJSX: ModalTarget;
10
15
  func: () => any;
16
+ /** Confirmation code word. Default "111" is kept for compatibility; pass your own. */
17
+ password?: string;
11
18
  }): void;
19
+ /**
20
+ * @deprecated Imperative JSX storage based on updateBy/renderBy.
21
+ * Use `ModalProvider`/`useModal` (ModalContextProvider): context plus portal.
22
+ */
12
23
  export declare function GetModalJSX(): {
13
24
  set(jsx: React.JSX.Element | null): void;
14
25
  JSX: React.JSX.Element | null;
15
26
  Render(): React.JSX.Element | null;
16
- addJSX(jsx: React.JSX.Element): React.JSX.Element;
17
- dellBy(jsx: React.JSX.Element): void;
18
- readonly arrJSX: import("react/jsx-runtime").JSX.Element[];
19
- RenderArr(): import("react/jsx-runtime").JSX.Element[];
27
+ addJSX<A extends React.JSX.Element | null>(jsx: A): A;
28
+ dellBy(jsx: React.JSX.Element | null): void;
29
+ readonly arrJSX: (import("react/jsx-runtime").JSX.Element | null)[];
30
+ RenderArr(): (import("react/jsx-runtime").JSX.Element | null)[];
20
31
  };
21
- type t1 = (() => React.JSX.Element | null) | null;
32
+ /**
33
+ * @deprecated Imperative JSX storage based on updateBy/renderBy.
34
+ * Use `ModalProvider`/`useModal` (ModalContextProvider): context plus portal.
35
+ */
22
36
  export declare function GetModalFuncJSX(): {
23
- set(jsx: t1): void;
24
- JSX: t1;
37
+ set(jsx: (() => React.JSX.Element | null) | null): void;
38
+ JSX: (() => React.JSX.Element | null) | null;
25
39
  Render(): React.JSX.Element | null;
26
- addJSX(jsx: t1): t1;
27
- dellBy(jsx: t1): void;
40
+ addJSX<A extends (() => React.JSX.Element | null) | null>(jsx: A): A;
41
+ dellBy(jsx: (() => React.JSX.Element | null) | null): void;
28
42
  readonly arrJSX: (import("react/jsx-runtime").JSX.Element | null)[];
29
43
  RenderArr(): (import("react/jsx-runtime").JSX.Element | null)[];
30
44
  };
@@ -1,104 +1,81 @@
1
1
  import { jsx as _jsx_1 } from "react/jsx-runtime";
2
2
  import { renderBy, updateBy } from "../../../updateBy";
3
3
  import { InputPageModal } from "../Input";
4
+ function setModalTarget(target, jsx) {
5
+ if (typeof target == "function")
6
+ target(jsx);
7
+ else
8
+ target.replace(jsx);
9
+ }
4
10
  export function inputModal({ setModalJSX, func, name, txt }) {
5
- setModalJSX(_jsx_1(InputPageModal, { callback: txt => {
11
+ setModalTarget(setModalJSX, _jsx_1(InputPageModal, { callback: txt => {
6
12
  func(txt);
7
- setModalJSX(null);
8
- }, outClick: () => setModalJSX(null), name: name ?? "name", txt: txt }));
13
+ setModalTarget(setModalJSX, null);
14
+ }, outClick: () => setModalTarget(setModalJSX, null), name: name ?? "name", txt: txt }));
9
15
  }
10
- export function confirmModal({ setModalJSX, func }) {
11
- setModalJSX(_jsx_1(InputPageModal, { callback: txt => {
12
- if (txt == "111")
16
+ export function confirmModal({ setModalJSX, func, password = "111" }) {
17
+ // Do not expose custom passwords in the hint; show the legacy default as before.
18
+ const hint = password == "111" ? "password 111" : "password";
19
+ setModalTarget(setModalJSX, _jsx_1(InputPageModal, { callback: txt => {
20
+ if (txt == password)
13
21
  func();
14
- setModalJSX(null);
15
- }, outClick: () => setModalJSX(null), name: "password 111" }));
22
+ setModalTarget(setModalJSX, null);
23
+ }, outClick: () => setModalTarget(setModalJSX, null), name: hint }));
16
24
  }
17
- export function GetModalJSX() {
18
- const data = (() => {
19
- let _jsx = null;
20
- let _jsxArr = [];
21
- let key = 0;
22
- const check = (jsx) => _jsxArr.findIndex(e => e.jsx == jsx);
23
- return {
24
- set(jsx) {
25
- _jsx = jsx;
25
+ // Shared store for GetModalJSX/GetModalFuncJSX: identical logic, the only
26
+ // difference is how a stored value turns into an element (renderItem)
27
+ function createJsxStore(renderItem) {
28
+ let _jsx = null;
29
+ let _jsxArr = [];
30
+ let key = 0;
31
+ const check = (jsx) => _jsxArr.findIndex(e => e.jsx == jsx);
32
+ const data = {
33
+ set(jsx) {
34
+ _jsx = jsx;
35
+ renderBy(data);
36
+ },
37
+ set JSX(jsx) {
38
+ _jsx = jsx;
39
+ renderBy(data);
40
+ },
41
+ get JSX() { return _jsx; },
42
+ Render() {
43
+ updateBy(data);
44
+ return _jsx && renderItem(_jsx);
45
+ },
46
+ addJSX(jsx) {
47
+ if (check(jsx) == -1) {
48
+ _jsxArr.push({ jsx, key: key++ });
26
49
  renderBy(data);
27
- },
28
- set JSX(jsx) {
29
- _jsx = jsx;
50
+ }
51
+ return jsx;
52
+ },
53
+ dellBy(jsx) {
54
+ const c = check(jsx);
55
+ if (c != -1) {
56
+ _jsxArr.splice(c, 1);
30
57
  renderBy(data);
31
- },
32
- get JSX() { return _jsx; },
33
- Render() {
34
- updateBy(data);
35
- return _jsx;
36
- },
37
- addJSX(jsx) {
38
- const c = check(jsx);
39
- if (c == -1) {
40
- _jsxArr.push({ jsx, key: key++ });
41
- renderBy(data);
42
- }
43
- return jsx;
44
- },
45
- dellBy(jsx) {
46
- const c = check(jsx);
47
- if (c != -1) {
48
- _jsxArr.splice(c, 1);
49
- renderBy(data);
50
- }
51
- },
52
- get arrJSX() { return _jsxArr.map(e => _jsx_1("div", { children: e.jsx }, e.key)); },
53
- RenderArr() {
54
- updateBy(data);
55
- return _jsxArr.map(e => _jsx_1("div", { children: e.jsx }, e.key));
56
58
  }
57
- };
58
- })();
59
+ },
60
+ get arrJSX() { return _jsxArr.map(e => e.jsx && _jsx_1("div", { children: renderItem(e.jsx) }, e.key)); },
61
+ RenderArr() {
62
+ updateBy(data);
63
+ return data.arrJSX;
64
+ }
65
+ };
59
66
  return data;
60
67
  }
68
+ /**
69
+ * @deprecated Imperative JSX storage based on updateBy/renderBy.
70
+ * Use `ModalProvider`/`useModal` (ModalContextProvider): context plus portal.
71
+ */
72
+ export function GetModalJSX() {
73
+ return createJsxStore(jsx => jsx);
74
+ }
75
+ /**
76
+ * @deprecated Imperative JSX storage based on updateBy/renderBy.
77
+ * Use `ModalProvider`/`useModal` (ModalContextProvider): context plus portal.
78
+ */
61
79
  export function GetModalFuncJSX() {
62
- const data = (() => {
63
- let _jsx = null;
64
- let _jsxArr = [];
65
- let key = 0;
66
- const check = (jsx) => _jsxArr.findIndex(e => e.jsx == jsx);
67
- return {
68
- set(jsx) {
69
- _jsx = jsx;
70
- renderBy(data);
71
- },
72
- set JSX(jsx) {
73
- _jsx = jsx;
74
- renderBy(data);
75
- },
76
- get JSX() { return _jsx; },
77
- Render() {
78
- updateBy(data);
79
- return _jsx ? _jsx() : null;
80
- },
81
- addJSX(jsx) {
82
- const c = check(jsx);
83
- if (c == -1) {
84
- _jsxArr.push({ jsx, key: key++ });
85
- renderBy(data);
86
- }
87
- return jsx;
88
- },
89
- dellBy(jsx) {
90
- const c = check(jsx);
91
- if (c != -1) {
92
- _jsxArr.splice(c, 1);
93
- renderBy(data);
94
- }
95
- },
96
- get arrJSX() { return _jsxArr.map(e => e.jsx && _jsx_1("div", { children: e.jsx() }, e.key)); },
97
- RenderArr() {
98
- updateBy(data);
99
- return _jsxArr.map(e => e.jsx && _jsx_1("div", { children: e.jsx() }, e.key));
100
- }
101
- };
102
- })();
103
- return data;
80
+ return createJsxStore(f => f());
104
81
  }
@@ -1,5 +1,22 @@
1
1
  import { ReactNode } from 'react';
2
- export declare const ModalProvider: ({ children }: {
2
+ export type ModalApi = {
3
+ show(node: ReactNode): void;
4
+ open(node: ReactNode): void;
5
+ close(): void;
6
+ replace(node: ReactNode | null): void;
7
+ set(node: ReactNode | null): void;
8
+ };
9
+ export type ModalController = ((jsx: ReactNode | null) => void) & ModalApi;
10
+ export type ModalProviderProps = {
3
11
  children: ReactNode;
4
- }) => import("react/jsx-runtime").JSX.Element;
5
- export declare const useModal: () => (jsx: ReactNode | null) => void;
12
+ /** Close on click outside the modal. Defaults to true for legacy behavior. */
13
+ closeOnOutsideClick?: boolean;
14
+ /** Close on Escape. Defaults to true. */
15
+ closeOnEscape?: boolean;
16
+ };
17
+ export declare const ModalProvider: ({ children, closeOnOutsideClick, closeOnEscape }: ModalProviderProps) => import("react/jsx-runtime").JSX.Element;
18
+ export declare const useModal: () => ModalController;
19
+ /** @deprecated Use `useModal()`; it is callable and also has show/open/close/set methods. */
20
+ export declare const useModalOld: () => ModalController;
21
+ /** @deprecated Use `useModal()` directly. */
22
+ export declare function useModalApi(): ModalApi;
@@ -1,16 +1,43 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { createContext, useContext, useState } from 'react';
2
+ import { createContext, useContext, useEffect, useMemo, useState } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
4
  import { DivOutsideClick } from "../../hooks/useOutside";
5
- // Контекст хранит только функцию setModal
6
- const ModalContext = createContext(() => { });
7
- export const ModalProvider = ({ children }) => {
5
+ import { tokens } from "../../styles/tokens";
6
+ const noopModal = Object.assign(() => { }, { show() { }, open() { }, close() { }, replace() { }, set() { } });
7
+ const ModalContext = createContext(noopModal);
8
+ export const ModalProvider = ({ children, closeOnOutsideClick = true, closeOnEscape = true }) => {
8
9
  const [modal, setModal] = useState(null);
9
- return (_jsxs(ModalContext.Provider, { value: setModal, children: [children, modal && createPortal(_jsx("div", { style: {
10
- position: 'fixed', inset: 0, zIndex: 9999,
10
+ const modalApi = useMemo(() => {
11
+ const api = ((node) => setModal(node));
12
+ api.show = (node) => setModal(node);
13
+ api.open = api.show;
14
+ api.close = () => setModal(null);
15
+ api.replace = (node) => setModal(node);
16
+ api.set = api.replace;
17
+ return api;
18
+ }, []);
19
+ useEffect(() => {
20
+ if (!modal || !closeOnEscape)
21
+ return;
22
+ const onKeyDown = (e) => {
23
+ if (e.key == 'Escape')
24
+ setModal(null);
25
+ };
26
+ document.addEventListener('keydown', onKeyDown);
27
+ return () => document.removeEventListener('keydown', onKeyDown);
28
+ }, [modal, closeOnEscape]);
29
+ return (_jsxs(ModalContext.Provider, { value: modalApi, children: [children, modal && createPortal(_jsx("div", { style: {
30
+ position: 'fixed', inset: 0, zIndex: tokens.zIndex.modal,
11
31
  display: 'flex', alignItems: 'center', justifyContent: 'center',
12
32
  backgroundColor: 'rgba(0,0,0,0.5)'
13
- }, children: _jsx(DivOutsideClick, { outsideClick: () => setModal(null), status: true, children: modal }) }), document.body)] }));
33
+ }, children: _jsx(DivOutsideClick, { outsideClick: () => { if (closeOnOutsideClick)
34
+ setModal(null); }, status: true, children: modal }) }), document.body)] }));
14
35
  };
15
- // Тот самый компактный хук
36
+ // Callable for legacy code, controller-style for new code.
16
37
  export const useModal = () => useContext(ModalContext);
38
+ /** @deprecated Use `useModal()`; it is callable and also has show/open/close/set methods. */
39
+ export const useModalOld = () => useContext(ModalContext);
40
+ /** @deprecated Use `useModal()` directly. */
41
+ export function useModalApi() {
42
+ return useContext(ModalContext);
43
+ }