wenay-react2 1.0.19 → 1.0.20

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.
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useRef, useState } from "react";
2
+ import { useEffect, useRef, useState } from "react";
3
3
  const ANIMATION_DURATION = 500; // длительность анимации в мс
4
4
  export function DraggableOutlineDiv() {
5
5
  const [isDragging, setIsDragging] = useState(false);
@@ -26,6 +26,8 @@ export function DraggableOutlineDiv() {
26
26
  timerRef.current = null;
27
27
  }
28
28
  };
29
+ useEffect(() => () => { if (timerRef.current)
30
+ window.clearTimeout(timerRef.current); }, []);
29
31
  return (_jsx("div", { className: `draggable-div ${isDragging ? 'outline-animation' : ''} ${animationFinished ? 'outline-complete' : ''}`, onMouseDown: handleMouseDown, onMouseUp: handleMouseUp, onMouseLeave: handleMouseUp, children: "\u0421\u043E\u0434\u0435\u0440\u0436\u0438\u043C\u043E\u0435 \u0434\u0438\u0432\u0430" }));
30
32
  }
31
33
  ;
@@ -356,8 +356,6 @@ export function Drag22({ children, onX, onY, x = 0, y = 0, right = false, last,
356
356
  x: posRef.current.x - e.clientX,
357
357
  y: posRef.current.y - e.clientY
358
358
  };
359
- console.log("xxx");
360
- console.log(offsetMouse.current.x, posRef.current.x, e.clientX);
361
359
  setDraggingMouse(true);
362
360
  };
363
361
  const handleTouchStart = (e) => {
@@ -20,10 +20,10 @@ export function InputFileModal({ callback, name, outClick, keyForSave = "InputFi
20
20
  return _jsx(ModalWrapper, { outClick: outClick, keyForSave: keyForSave, size: { height: 150, width: 300 }, position: { y: -150, x: -250 }, children: _jsx(InputFile, { callback: callback, name: name }) });
21
21
  }
22
22
  export function InputFile({ callback, name = "" }) {
23
- let file = null;
23
+ const file = useRef(null);
24
24
  return _jsxs("div", { className: "maxSize", style: { padding: 20, }, children: [_jsx("label", { children: name }), _jsx("input", { type: "file", style: { width: "100%" }, onChange: (e) => {
25
- file = e.target.files?.[0] ?? null;
26
- } }), _jsx("div", { style: { marginTop: 20 }, className: "msTradeAlt msTradeActive", onClick: () => { callback(file); }, children: "send" })] });
25
+ file.current = e.target.files?.[0] ?? null;
26
+ } }), _jsx("div", { style: { marginTop: 20 }, className: "msTradeAlt msTradeActive", onClick: () => { callback(file.current); }, children: "send" })] });
27
27
  }
28
28
  export function PageModalFree({ outClick, children, zIndex, size = { height: 150, width: 300 }, keyForSave = "PageModalFree2" }) {
29
29
  return _jsx(ModalWrapper, { outClick: outClick, keyForSave: keyForSave, size: size, zIndex: zIndex, children: children });
@@ -143,7 +143,12 @@ export function MenuRightApi() {
143
143
  render?.(elements);
144
144
  },
145
145
  delete(array) {
146
- array.forEach((e) => elements.splice(elements.indexOf(e), 1));
146
+ array.forEach((e) => {
147
+ const i = elements.indexOf(e);
148
+ if (i !== -1)
149
+ elements.splice(i, 1);
150
+ });
151
+ render?.([...elements]);
147
152
  },
148
153
  get() {
149
154
  return elements;
@@ -1,5 +1,3 @@
1
1
  import React from 'react';
2
- interface StickerMenuProps {
3
- }
4
- declare const StickerMenu: React.FC<StickerMenuProps>;
2
+ declare const StickerMenu: React.FC;
5
3
  export default StickerMenu;
@@ -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 }) {
@@ -275,10 +243,10 @@ export function getApiLeftMenu() {
275
243
  };
276
244
  }
277
245
  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
246
  export function TestLeft333() {
283
- return _jsx(ApiLeftMenu.Modal2, { zIndex: 20 });
247
+ // тест-меню перенесено сюда из уровня модуля — раньше ApiLeftMenu.setMenu(...) выполнялся при импорте и протекал всем потребителям
248
+ return _jsx(ApiLeftMenu.Modal2, { zIndex: 20, menu: [
249
+ { 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
+ { button: _jsx("div", { style: { width: 200, height: 50, background: "rgb(98,149,58)" }, children: "2" }), el: () => _jsx("div", { children: "2" }) },
251
+ ] });
284
252
  }
@@ -6,7 +6,7 @@ export function EditParams2({ onSave, params: paramsDef }) {
6
6
  paramsDef().then(e => {
7
7
  setParamsD(e);
8
8
  });
9
- }, [true]);
9
+ }, []);
10
10
  const [paramsD, setParamsD] = useState(null);
11
11
  const params = useRef(null);
12
12
  return _jsxs("div", { className: "maxSize", children: [paramsD && _jsx(ParametersReact, { params: paramsD, onChange: e => params.current = e }), onSave && _jsx("div", { className: "msTradeActive msTradeAlt", onClick: async () => {
@@ -20,10 +20,10 @@ export function EditParams3({ onSave, params: paramsDef }) {
20
20
  paramsDef().then(e => {
21
21
  setParams(e);
22
22
  });
23
- }, [true]);
23
+ }, []);
24
24
  const [params, setParams] = useState(null);
25
25
  return _jsxs("div", { className: "maxSize", children: [params && params.map((z, i) => _jsx(ParametersReact, { params: z, onChange: e => {
26
- params[i] = z;
26
+ params[i] = e;
27
27
  setParams(params);
28
28
  } }, i)), onSave && _jsx("div", { className: "msTradeActive msTradeAlt", onClick: async () => {
29
29
  params && onSave?.(params);
@@ -8,7 +8,7 @@ export function FButton(name) {
8
8
  export function FNameButton(type, name) { return FButton(_jsx("p", { className: "toPTextIndicator", children: (type ? "▼ " : "▶ ") + name })); }
9
9
  export function CParameter(props) {
10
10
  const [hovered, setHovered] = React.useState(false); // Состояние для отслеживания наведения мышки
11
- return (_jsxs("div", { className: "toLine LeftMenuParameters toIndicatorMenuButton", style: { position: "relative" }, children: [_jsx("div", { className: "toLine", style: { width: "auto", ...props.style }, onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), children: props.name }), _jsx("div", { className: "toLine toRight", style: props.enabled === false ? { opacity: 0.5 } : {}, children: props.children }), hovered && props.commentary?.length && (_jsx("div", { className: "commentary", style: {
11
+ return (_jsxs("div", { className: "toLine LeftMenuParameters toIndicatorMenuButton", style: { position: "relative" }, children: [_jsx("div", { className: "toLine", style: { width: "auto", ...props.style }, onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), children: props.name }), _jsx("div", { className: "toLine toRight", style: props.enabled === false ? { opacity: 0.5 } : {}, children: props.children }), hovered && props.commentary && props.commentary.length > 0 && (_jsx("div", { className: "commentary", style: {
12
12
  marginTop: "5px",
13
13
  fontSize: "12px",
14
14
  color: "gray",
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useRef, useState } from "react";
3
3
  import { deepCloneMutable, isDate, TF, timeLocalToStr_yyyymmdd, timeLocalToStr_yyyymmdd_hhmm, timeLocalToStr_yyyymmdd_hhmmss, timeLocalToStr_yyyymmdd_hhmmss_ms } from "wenay-common2";
4
- import { setResizeableElement } from "./MyResizeObserver";
4
+ import { setResizeableElement, removeResizeableElement } from "./MyResizeObserver";
5
5
  import { CParameter, FNameButton } from "./Parameters";
6
6
  import { SetAutoStepForElement } from "../utils";
7
7
  function timeToStr(time, step) {
@@ -72,6 +72,7 @@ function InputTime(set, value, range) {
72
72
  }, ref: (ref) => {
73
73
  if (ref) {
74
74
  setResizeableElement(ref);
75
+ return () => removeResizeableElement(ref);
75
76
  }
76
77
  } }), _jsx("div", { children: _jsx("input", { type: step % TF.D1.msec == 0 ? "date" : "datetime-local", style: { width: "calc(100% - 13px)", marginTop: 5 }, onInput: (e) => {
77
78
  set(e.currentTarget.value);
@@ -108,6 +109,7 @@ function InputList(set, value, range, rangeLabels) {
108
109
  }, ref: (ref) => {
109
110
  if (ref) {
110
111
  setResizeableElement(ref);
112
+ return () => removeResizeableElement(ref);
111
113
  }
112
114
  }, children: range.map((a, i) => {
113
115
  return _jsx("option", { value: toString(a), label: rangeLabels?.at(i) ?? toString(a), children: toString(a) }, toString(a));
@@ -131,6 +133,7 @@ function InputNumber(set, value, range) {
131
133
  }, ref: (ref) => {
132
134
  if (ref) {
133
135
  setResizeableElement(ref);
136
+ return () => removeResizeableElement(ref);
134
137
  }
135
138
  } }), _jsx("input", { required: true, className: "toNumberInput inputCan", type: "number", min: min, max: max, step: step, value: val, onInput: (e) => {
136
139
  const target = e.currentTarget;
@@ -175,6 +178,7 @@ function InputListArray(set, values, range, rangeLabels) {
175
178
  }, multiple: true, ref: (ref) => {
176
179
  if (ref) {
177
180
  setResizeableElement(ref);
181
+ return () => removeResizeableElement(ref);
178
182
  }
179
183
  }, children: range.map((a, i) => {
180
184
  return _jsx("option", { value: String(a), label: rangeLabels?.at(i) ?? String(a), children: a }, String(a));
@@ -198,14 +202,16 @@ function ParametersBaseReact(data) {
198
202
  myParams.current = p;
199
203
  Refresh();
200
204
  }, [p]);
201
- let timeoutId = null;
205
+ const timeoutId = useRef(null);
206
+ useEffect(() => () => { if (timeoutId.current != null)
207
+ clearTimeout(timeoutId.current); }, []);
202
208
  function refreshIndicator() {
203
209
  data.onChange(myParams.current);
204
210
  }
205
211
  function refreshIndicatorDelayed() {
206
- if (timeoutId != null)
207
- clearTimeout(timeoutId);
208
- timeoutId = setTimeout(() => {
212
+ if (timeoutId.current != null)
213
+ clearTimeout(timeoutId.current);
214
+ timeoutId.current = setTimeout(() => {
209
215
  refreshIndicator();
210
216
  }, 200);
211
217
  }
@@ -6,7 +6,6 @@ export const KeyDown = {
6
6
  export function useAddDownAnyKey() {
7
7
  useEffect(() => {
8
8
  const func = (ev) => {
9
- console.log(ev);
10
9
  KeyDown.key = ev.key;
11
10
  renderBy(KeyDown);
12
11
  };
@@ -14,7 +13,7 @@ export function useAddDownAnyKey() {
14
13
  return () => {
15
14
  document.removeEventListener("keydown", func);
16
15
  };
17
- }, [true]);
16
+ }, []);
18
17
  }
19
18
  // Backward-compatible name.
20
19
  export function addDownAnyKey() {
@@ -2,18 +2,20 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React, { useEffect, useRef, useState } from "react";
3
3
  export const StyleOtherRow = { display: "flex", flexDirection: "row", flex: "auto 1 1" };
4
4
  export const StyleOtherColum = { display: "flex", flexDirection: "column", flex: "auto 0 1" };
5
- export function useOutside({ outsideClick, ref = useRef(null), status = true }) {
5
+ export function useOutside({ outsideClick, ref, status = true }) {
6
+ const internalRef = useRef(null); // useRef всегда в теле, не в дефолте параметра — иначе нарушаются Rules of Hooks
7
+ const r = ref ?? internalRef;
6
8
  useEffect(() => {
7
9
  if (status) {
8
10
  function handleClickOutside(event) {
9
- if (ref.current && event.target instanceof Node && !ref.current.contains(event.target))
11
+ if (r.current && event.target instanceof Node && !r.current.contains(event.target))
10
12
  outsideClick();
11
13
  }
12
14
  document.addEventListener("mousedown", handleClickOutside);
13
15
  return () => document.removeEventListener("mousedown", handleClickOutside);
14
16
  }
15
- }, [ref, status, outsideClick]);
16
- return ref;
17
+ }, [r, status, outsideClick]);
18
+ return r;
17
19
  }
18
20
  export const DivOutsideClick = React.forwardRef(({ children, outsideClick, zIndex, style = {}, status = true, ...other }, forwardedRef) => {
19
21
  const style2 = zIndex ? { ...style, zIndex } : style;
@@ -39,8 +39,9 @@ export function getLogsApi(setting) {
39
39
  } });
40
40
  return {
41
41
  addLogs(a) {
42
- addToArr(datumMiniConst.last, { ...a, num: num++ }, 50);
43
- addToArr(datumConst.map.get(a.id) ?? datumConst.map.set(a.id, []).get(a.id), { ...a, num: num++ }, setting.limitPer);
42
+ const item = { ...a, num: num++ };
43
+ addToArr(datumMiniConst.last, item, 50);
44
+ addToArr(datumConst.map.get(a.id) ?? datumConst.map.set(a.id, []).get(a.id), item, setting.limitPer);
44
45
  renderBy(datumConst);
45
46
  renderBy(datumMiniConst);
46
47
  },
@@ -100,7 +101,6 @@ export function PageLogs({ update }) {
100
101
  });
101
102
  updateBy(datum, () => {
102
103
  const data = datum.last[0];
103
- console.log({ data });
104
104
  if (data) { // data.time timeLocalToStr_yyyymmdd_hhmmss_ms
105
105
  apiGrid.current?.api.applyTransactionAsync({
106
106
  add: [
@@ -118,7 +118,7 @@ export function PageLogs({ update }) {
118
118
  field: "time",
119
119
  sort: "desc",
120
120
  width: 50,
121
- valueFormatter: (e) => e.value.time ? timeLocalToStr_hhmmss(e.value.time) : e.value.time
121
+ valueFormatter: (e) => e.value ? timeLocalToStr_hhmmss(e.value) : e.value
122
122
  },
123
123
  {
124
124
  field: "id",
@@ -204,7 +204,7 @@ export function LogsNotifications() {
204
204
  border: 0,
205
205
  height: 1,
206
206
  margin: 0
207
- } }), _jsx("div", { style: { textAlign: 'right', marginRight: 10 }, children: typeof log.txt === 'object' ? JSON.stringify(log.txt) : log.txt }), _jsx("p", { style: { textAlign: 'right', marginRight: 10 }, children: log.time.toLocaleDateString() })] }, id));
207
+ } }), _jsx("div", { style: { textAlign: 'right', marginRight: 10 }, children: typeof log.txt === 'object' ? JSON.stringify(log.txt) : log.txt }), _jsx("p", { style: { textAlign: 'right', marginRight: 10 }, children: new Date(log.time).toLocaleDateString() })] }, id));
208
208
  }) })] }));
209
209
  }
210
210
  /** -----------------------------
@@ -9,7 +9,7 @@ export function MiniLogs({ data, onClick }) {
9
9
  field: "time",
10
10
  sort: "desc",
11
11
  width: 50,
12
- valueFormatter: (e) => e.value.time ? timeLocalToStr_hhmmss(e.value.time) : e.value.time
12
+ valueFormatter: (e) => e.value ? timeLocalToStr_hhmmss(e.value) : e.value
13
13
  },
14
14
  {
15
15
  field: "id",
@@ -184,7 +184,7 @@ const MenuItemWrapper = ({ item, index, update, className, isLeftAligned, leftPo
184
184
  } }) }))] })] }));
185
185
  };
186
186
  export function MenuBase({ coordinate = { x: 0, y: 0, toLeft: false, left: 0 }, data, zIndex, menu, className, menuElement, }) {
187
- const [_, forceUpdate] = useState(false);
187
+ const [, forceUpdate] = useState(false);
188
188
  const update = () => forceUpdate((p) => !p);
189
189
  const refMenu = useRef(null);
190
190
  const dataMemo = useMemo(() => data.filter((e) => e), [data, data.length]);
@@ -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;
@@ -11,7 +11,7 @@ function GetMouseMenuApi(data) {
11
11
  name,
12
12
  get value() { return value; }
13
13
  };
14
- const map = new Map;
14
+ const map = new Map();
15
15
  function other() {
16
16
  if (map.has("only"))
17
17
  return map.get("only");
@@ -21,9 +21,7 @@ function GetMouseMenuApi(data) {
21
21
  }
22
22
  function ReactMouse(agr) {
23
23
  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
- } });
24
+ return MenuR({ ...(agr ?? {}), other: agr.other ? agr.other : other, statusOn: datum.status, onConsume: () => { map.clear(); } });
27
25
  }
28
26
  return {
29
27
  bb, get map() { return map; }, get menuMouse() { return menuMouse; }, ReactMouse, ReactMenu: MenuBase
@@ -6,12 +6,13 @@ export declare function GetMenuR(): {
6
6
  * открытие меню.
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
  };
@@ -6,7 +6,7 @@ import { DivOutsideClick } from "../hooks/useOutside";
6
6
  export function GetMenuR() {
7
7
  let bb = false; // Глобальная переменная, предотвращающая множественное открытие меню (флаг активности)
8
8
  // Основной компонент MenuR
9
- function MenuR({ children, other = () => [], statusOn = true, onUnClick, zIndex, className }) {
9
+ function MenuR({ children, other = () => [], statusOn = true, onUnClick, onConsume, zIndex, className }) {
10
10
  const data = { x: 0, y: 0 }; // Текущая позиция элемента, где происходит взаимодействие
11
11
  const [show, setShow] = React.useState({ status: false });
12
12
  useEffect(() => {
@@ -61,9 +61,11 @@ export function GetMenuR() {
61
61
  if (bb)
62
62
  return; // Если меню уже активно, выходим
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
@@ -83,7 +85,9 @@ export function GetMenuR() {
83
85
  if (bb)
84
86
  return; // Если меню уже активно, ничего не делаем
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
93
  }, children: [children /* Дочерний элемент, внутри которого отслеживаются события */, show.status && statusOn && (
@@ -96,7 +100,7 @@ export function GetMenuR() {
96
100
  setShow({ status: false }); // Скрываем меню
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 {
@@ -314,13 +314,33 @@ export function createRenderer() {
314
314
  return;
315
315
  const result = [];
316
316
  let lastPixX = -1;
317
+ let minPt = null;
318
+ let maxPt = null;
319
+ const flush = () => {
320
+ if (!minPt || !maxPt)
321
+ return;
322
+ const a = minPt.x <= maxPt.x ? minPt : maxPt;
323
+ const b = a === minPt ? maxPt : minPt;
324
+ result.push(a);
325
+ if (b !== a)
326
+ result.push(b);
327
+ };
317
328
  for (const pt of visible) {
318
329
  const px = Math.round(xToPixX(pt.x, transform, panel));
319
330
  if (px !== lastPixX) {
320
- result.push(pt);
331
+ flush();
332
+ minPt = pt;
333
+ maxPt = pt;
321
334
  lastPixX = px;
322
335
  }
336
+ else {
337
+ if (pt.y < minPt.y)
338
+ minPt = pt;
339
+ if (pt.y > maxPt.y)
340
+ maxPt = pt;
341
+ }
323
342
  }
343
+ flush();
324
344
  if (result.length < 2)
325
345
  return;
326
346
  ctx.save();
@@ -700,6 +720,8 @@ export function createChartEngine(canvas) {
700
720
  resizeObserver = null;
701
721
  }
702
722
  function attachToContainer(container) {
723
+ if (resizeObserver)
724
+ resizeObserver.disconnect();
703
725
  containerEl = container;
704
726
  resizeObserver = new ResizeObserver((entries) => {
705
727
  for (const entry of entries) {
@@ -27,19 +27,20 @@ function applyTransactionAsyncUpdate3({ getId, bufTable, option, newData, grid,
27
27
  grid.api.applyTransaction({
28
28
  add: op.add ? arrNew : [],
29
29
  update: op.update ? arr : [],
30
+ remove: remove,
30
31
  });
31
32
  return;
32
33
  }
33
- if (arrNew.length && op.add)
34
- grid.api.applyTransaction({ add: arrNew, remove: remove }); // для удаления важно только получить ид
34
+ // remove применяем один раз и независимо: иначе при пустых add/update удаление терялось, а при обоих — дублировалось
35
+ if ((arrNew.length && op.add) || remove?.length)
36
+ grid.api.applyTransaction({ add: (arrNew.length && op.add) ? arrNew : [], remove: remove });
35
37
  if (arr.length && op.update)
36
- grid.api.applyTransactionAsync({ update: arr, remove: remove });
38
+ grid.api.applyTransactionAsync({ update: arr });
37
39
  }
38
40
  // тут нет удаления но эта версия может использовать где то
39
41
  export function applyTransactionAsyncUpdate(grid, newData, getId, bufTable, option) {
40
42
  return applyTransactionAsyncUpdate3({ getId, option, newData, grid, bufTable });
41
43
  }
42
- const map = new WeakMap();
43
44
  export function getUpdateTable(grid, newData, getId, bufTable, option) {
44
45
  return {};
45
46
  }
@@ -91,13 +92,11 @@ export function applyTransactionAsyncUpdate2(params) {
91
92
  if (existing)
92
93
  toRemove.push(existing);
93
94
  });
94
- if (newData?.length)
95
- applyTransactionAsyncUpdate3({ grid: g, newData, getId, bufTable, option: op, remove: toRemove });
95
+ if (newData?.length || toRemove.length)
96
+ applyTransactionAsyncUpdate3({ grid: g, newData: newData ?? [], getId, bufTable, option: op, remove: toRemove });
96
97
  }
97
98
  }
98
99
  else {
99
- if (!map.has(bufTable))
100
- map.set(bufTable, new Set());
101
100
  newData?.forEach(e => {
102
101
  const id = getId(e);
103
102
  bufTable[id] = { ...(bufTable[id] ?? {}), ...e };
@@ -29,7 +29,6 @@ export class CSaveToCache {
29
29
  }
30
30
  export class CSaveToLocalStorage {
31
31
  async set(key, value) {
32
- const t = new Response(JSON.stringify(value));
33
32
  if (window.localStorage) {
34
33
  await localStorage.setItem(key, JSON.stringify(value));
35
34
  return true;
@@ -39,8 +38,14 @@ export class CSaveToLocalStorage {
39
38
  async get(key) {
40
39
  if (window.localStorage) {
41
40
  const st = await localStorage.getItem(key);
42
- if (st)
43
- return JSON.parse(st);
41
+ if (st) {
42
+ try {
43
+ return JSON.parse(st);
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ }
44
49
  }
45
50
  return null;
46
51
  }
@@ -36,7 +36,7 @@ export function deepMergeWithMap(target, source, visited = new Map()) {
36
36
  }
37
37
  return target;
38
38
  }
39
- const map = new Map;
39
+ const map = new Map();
40
40
  export function staticGetAdd(key, def, options = { reversDeep: false }) {
41
41
  if (options.deepAutoMerge && !map.get(def)) {
42
42
  map.set(def, true);
@@ -53,12 +53,13 @@ export function staticGetAdd(key, def, options = { reversDeep: false }) {
53
53
  return t; // Object.assign(def, t) // t //
54
54
  }
55
55
  export function staticGetById(key, def, id) {
56
- const t = map.get(key);
57
- const el = { __id: id, data: def };
58
- if ((el && el.__id != id) || !el) {
59
- return staticGetAdd(key, el, { abs: true }).data;
56
+ const stored = staticProps.get(key);
57
+ if (!stored || stored.__id !== id) {
58
+ const fresh = { __id: id, data: def };
59
+ staticProps.set(key, fresh);
60
+ return fresh.data;
60
61
  }
61
- return el.data;
62
+ return stored.data;
62
63
  }
63
64
  export const Cash = CacheFuncMap([
64
65
  ["mapResiReact", mapResiReact],
@@ -87,103 +87,3 @@ export function useUpdateBy(a, f) {
87
87
  export function updateBy(a, f) {
88
88
  useUpdateBy(a, f);
89
89
  }
90
- // import {useLayoutEffect, useState} from "react";
91
- // import {waitRun} from "wenay-common2";
92
- //
93
- // type tFunc2 = Map<object, (a?: any) => void>
94
- // export const map3 = new WeakMap<object, tFunc2>();
95
- // export const mapWait = new Map<object, ReturnType<typeof waitRun>>();
96
- //
97
- //
98
- // export function renderBy(a: object, ms?: number) {
99
- // const t = () => map3.get(a)?.forEach(e=>e(a))
100
- // if (ms) {
101
- // (mapWait.get(a) || mapWait.set(a, waitRun()).get(a)!)
102
- // .refreshAsync(ms, ()=> {
103
- // mapWait.delete(a)
104
- // t()})
105
- // }
106
- // else t()
107
- // }
108
- //
109
- // export function renderByRevers(a: object, ms?: number, reverse = true) {
110
- // const ar: ((a?: any) => void)[] = []
111
- // map3.get(a)?.forEach(e=>ar.push(e))
112
- // const t = reverse ? () => ar.reverse().forEach(e=>e(a))
113
- // : () => ar.forEach(e=>e(a))
114
- // if (ms) {
115
- // (mapWait.get(a) || mapWait.set(a, waitRun()).get(a)!)
116
- // .refreshAsync(ms, ()=> {
117
- // mapWait.delete(a)
118
- // t()})
119
- // }
120
- // else t()
121
- // }
122
- //
123
- // export function renderByLast(a: object, ms?: number) {
124
- // const ar: ((a?: any) => void)[] = []
125
- // map3.get(a)?.forEach(e=>ar.push(e))
126
- // const t = () => ar.at(-1)?.()
127
- // if (ms) {
128
- // (mapWait.get(a) || mapWait.set(a, waitRun()).get(a)!)
129
- // .refreshAsync(ms, ()=> {
130
- // mapWait.delete(a)
131
- // t()})
132
- // }
133
- // else t()
134
- // }
135
- //
136
- // // Главная функция
137
- // export function useUpdateBy<T extends object>(
138
- // a: T,
139
- // f?: React.Dispatch<React.SetStateAction<T>> | ((a: T) => void)
140
- // ) {
141
- // const [_, setCounter] = useState(0); // Состояние счётчика для обновлений
142
- //
143
- // // Эффект для работы с объектом и картой
144
- // useLayoutEffect(() => {
145
- // // Если передан второй аргумент `f`, используем его, иначе создаём default-функцию
146
- // const func = f ?? (() => {
147
- // setCounter(prev => prev + 1);
148
- // });
149
- //
150
- // // Получаем карту из глобальной переменной map3 или создаём новую для объекта `a`
151
- // const funcMap = map3.get(a) || map3.set(a, new Map()).get(a)!;
152
- // funcMap.set(func, func); // Привязываем функцию обновления к объекту `a`
153
- //
154
- // // Возвращаем функцию очистки (cleanup), чтобы удалить привязки
155
- // return () => {
156
- // funcMap.delete(func); // Удаляем функцию из карты
157
- // if (funcMap.size === 0) {
158
- // map3.delete(a); // Удаляем объект из `map3`, если он больше не нужен
159
- // }
160
- // };
161
- // }, [a, f]); // Указываем зависимости: объект `a` и функция `f`
162
- // }
163
- //
164
- // // Backward-compatible name (hook rules are the same).
165
- // export function updateBy<T extends object>(
166
- // a: T,
167
- // f?: React.Dispatch<React.SetStateAction<T>> | ((a: T) => void)
168
- // ) {
169
- // return useUpdateBy(a, f);
170
- // }
171
- //
172
- // // export function updateBy<T extends object>(a: T, f?: React.Dispatch<React.SetStateAction<T>> | ((a: T) => void)) {
173
- // // const t = useState(0)
174
- // // useLayoutEffect(() => {
175
- // // const func = f ?? ((a: T) =>{
176
- // // // без особых причин только для первого рендера - необходима два вызова, иначе - вызов не проходит
177
- // // if (t[0] == 0) {
178
- // // t[1](t[0]++)
179
- // // // t[1](t[0]++)
180
- // // }
181
- // // else t[1](t[0]++)
182
- // // })
183
- // // const r = (map3.get(a) || map3.set(a, new Map()).get(a)!)
184
- // // r.set(func, func)
185
- // // return ()=> {
186
- // // r?.delete(func)
187
- // // }
188
- // // },[true])
189
- // // }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wenay-react2",
3
- "version": "1.0.19",
3
+ "version": "1.0.20",
4
4
  "description": "Common react",
5
5
  "strict": true,
6
6
  "main": "dist/index.js",