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,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
  };
@@ -13,38 +13,6 @@ function useViewport() {
13
13
  }, []);
14
14
  return { width };
15
15
  }
16
- // Custom hook for smooth snap scrolling animation
17
- function useSmoothSnapScroll() {
18
- const animationState = useRef({ isAnimating: false });
19
- const currentPosition = useRef({ x: 0, y: 0 });
20
- const animateTo = async (target, onUpdate, onComplete) => {
21
- animationState.current.isAnimating = true;
22
- const step = 40;
23
- const animate = async () => {
24
- if (!animationState.current.isAnimating || currentPosition.current.x === target) {
25
- return;
26
- }
27
- const direction = target > currentPosition.current.x ? 1 : -1;
28
- await sleepAsync(10);
29
- const nextPosition = currentPosition.current.x + direction * step;
30
- if (Math.abs(target - nextPosition) < step) {
31
- animationState.current.isAnimating = false;
32
- currentPosition.current.x = target;
33
- onUpdate(target);
34
- onComplete?.();
35
- return;
36
- }
37
- currentPosition.current.x = nextPosition;
38
- onUpdate(nextPosition);
39
- animate();
40
- };
41
- await animate();
42
- };
43
- const stopAnimation = () => {
44
- animationState.current.isAnimating = false;
45
- };
46
- return { animateTo, stopAnimation, currentPosition };
47
- }
48
16
  const MENU_WIDTH_RATIO = 0.8;
49
17
  // Main sidebar menu component with snap scrolling behavior
50
18
  function SidebarMenuComponent({ y_, x_, api, arr, zIndex }) {
@@ -74,17 +42,21 @@ function SidebarMenuComponent({ y_, x_, api, arr, zIndex }) {
74
42
  textDecoration: "inherit",
75
43
  cursor: "default",
76
44
  }, children: e[0] }) }, i)));
77
- // 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)
78
52
  const animateToPosition = async (target) => {
79
53
  lastPosition.current.auto = true;
80
54
  const step = 40;
81
- if (!lastPosition.current.auto)
82
- return;
83
- const animate = async () => {
84
- if (!lastPosition.current.auto || currentPosition.current.x === target)
85
- return;
55
+ while (lastPosition.current.auto && currentPosition.current.x !== target) {
86
56
  const direction = target > currentPosition.current.x ? 1 : -1;
87
57
  await sleepAsync(10);
58
+ if (!mountedRef.current || !lastPosition.current.auto)
59
+ return;
88
60
  const nextPos = currentPosition.current.x + direction * step;
89
61
  if (Math.abs(target - nextPos) < step) {
90
62
  lastPosition.current.auto = false;
@@ -96,9 +68,7 @@ function SidebarMenuComponent({ y_, x_, api, arr, zIndex }) {
96
68
  }
97
69
  currentPosition.current.x = nextPos;
98
70
  setX(nextPos);
99
- animate();
100
- };
101
- await animate();
71
+ }
102
72
  };
103
73
  useEffect(() => {
104
74
  const menuApi = {
@@ -235,11 +205,11 @@ export function getApiLeftMenu() {
235
205
  color: "rgba(255,255,255,0.1)"
236
206
  }, children: textB })), children()] }));
237
207
  };
238
- let menuApi = null;
239
208
  const menuStore = new Map();
240
209
  const setMenu = (items, key = "base") => {
241
210
  const colorGen = colorGenerator2({ min: 0, max: 90 });
242
- 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);
243
213
  const baseColors = [];
244
214
  for (let i = 0; i < currentMenuLength + items.length; i++) {
245
215
  const colorResult = colorGen.next();
@@ -259,11 +229,23 @@ export function getApiLeftMenu() {
259
229
  function getAllMenuItems() {
260
230
  return [...menuStore.values()].flat();
261
231
  }
262
- function Modal2({ menu, zIndex, zIndex0, key }) {
263
- if (menu)
264
- 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]);
265
247
  updateBy(menuStore);
266
- 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() })] }));
267
249
  }
268
250
  const modal = GetModalJSX();
269
251
  return {
@@ -275,10 +257,10 @@ export function getApiLeftMenu() {
275
257
  };
276
258
  }
277
259
  export const ApiLeftMenu = getApiLeftMenu();
278
- ApiLeftMenu.setMenu([
279
- { 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)" },
280
- { button: _jsx("div", { style: { width: 200, height: 50, background: "rgb(98,149,58)" }, children: "2" }), el: () => _jsx("div", { children: "2" }) },
281
- ], "test");
282
260
  export function TestLeft333() {
283
- return _jsx(ApiLeftMenu.Modal2, { zIndex: 20 });
261
+ // Test menu moved here from module scope; previously ApiLeftMenu.setMenu(...) ran on import and leaked to all consumers.
262
+ return _jsx(ApiLeftMenu.Modal2, { zIndex: 20, menu: [
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)" },
264
+ { button: _jsx("div", { style: { width: 200, height: 50, background: "rgb(98,149,58)" }, children: "2" }), el: () => _jsx("div", { children: "2" }) },
265
+ ] });
284
266
  }
@@ -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
+ }