@hrnec06/react_utils 1.1.0
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.
- package/dist/index.d.mts +40 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +934 -0
- package/dist/index.mjs +891 -0
- package/package.json +44 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,891 @@
|
|
|
1
|
+
// src/hooks/useKeyListener.ts
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
function useKeyListener(key, options) {
|
|
4
|
+
const [pressing, setPressing] = useState(false);
|
|
5
|
+
const keyMatching = (e, strict) => {
|
|
6
|
+
if (strict && options?.ctrl && !e.ctrlKey)
|
|
7
|
+
return false;
|
|
8
|
+
if (strict && options?.shift && !e.shiftKey)
|
|
9
|
+
return false;
|
|
10
|
+
if (strict && options?.alt && !e.altKey)
|
|
11
|
+
return false;
|
|
12
|
+
return e.code == key;
|
|
13
|
+
};
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
const downListener = (e) => {
|
|
16
|
+
if (!keyMatching(e, true)) return;
|
|
17
|
+
setPressing(true);
|
|
18
|
+
};
|
|
19
|
+
const upListener = (e) => {
|
|
20
|
+
if (!keyMatching(e, false)) return;
|
|
21
|
+
setPressing(false);
|
|
22
|
+
};
|
|
23
|
+
window.addEventListener("keydown", downListener);
|
|
24
|
+
window.addEventListener("keyup", upListener);
|
|
25
|
+
return () => {
|
|
26
|
+
window.removeEventListener("keydown", downListener);
|
|
27
|
+
window.removeEventListener("keyup", upListener);
|
|
28
|
+
};
|
|
29
|
+
}, []);
|
|
30
|
+
return pressing;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/hooks/useListener.ts
|
|
34
|
+
import { useEffect as useEffect2 } from "react";
|
|
35
|
+
function useListener(element, event, listener, deps) {
|
|
36
|
+
useEffect2(() => {
|
|
37
|
+
element.addEventListener(event, listener);
|
|
38
|
+
return () => {
|
|
39
|
+
element.removeEventListener(event, listener);
|
|
40
|
+
};
|
|
41
|
+
}, deps);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/hooks/useUpdatedRef.ts
|
|
45
|
+
import { useRef as useRef2 } from "react";
|
|
46
|
+
|
|
47
|
+
// src/hooks/useUpdateEffect.ts
|
|
48
|
+
import { useEffect as useEffect3, useRef } from "react";
|
|
49
|
+
function useUpdateEffect(callback, value) {
|
|
50
|
+
const isFirstRun = useRef(true);
|
|
51
|
+
useEffect3(() => {
|
|
52
|
+
if (isFirstRun.current) {
|
|
53
|
+
isFirstRun.current = false;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
return callback();
|
|
57
|
+
}, value);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/hooks/useUpdatedRef.ts
|
|
61
|
+
function useUpdatedRef(value) {
|
|
62
|
+
const ref = useRef2(value);
|
|
63
|
+
useUpdateEffect(() => {
|
|
64
|
+
ref.current = value;
|
|
65
|
+
}, [value]);
|
|
66
|
+
return ref;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/hooks/useWindowSize.ts
|
|
70
|
+
import { useEffect as useEffect4, useState as useState3 } from "react";
|
|
71
|
+
function useWindowSize() {
|
|
72
|
+
const [dimensions, setDimensions] = useState3([1920, 1080]);
|
|
73
|
+
useEffect4(() => {
|
|
74
|
+
setDimensions([window.innerWidth, window.innerHeight]);
|
|
75
|
+
const listener = () => {
|
|
76
|
+
setDimensions([window.innerWidth, window.innerHeight]);
|
|
77
|
+
};
|
|
78
|
+
window.addEventListener("resize", listener);
|
|
79
|
+
return () => {
|
|
80
|
+
window.removeEventListener("resize", listener);
|
|
81
|
+
};
|
|
82
|
+
}, []);
|
|
83
|
+
return dimensions;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/hooks/useSignal.ts
|
|
87
|
+
import { useState as useState4 } from "react";
|
|
88
|
+
function useSignal(value) {
|
|
89
|
+
const [_value, _setValue] = useState4(value);
|
|
90
|
+
const signal = new Signal(_value, _setValue);
|
|
91
|
+
return signal;
|
|
92
|
+
}
|
|
93
|
+
var Signal = class {
|
|
94
|
+
constructor(_value, setState) {
|
|
95
|
+
this._value = _value;
|
|
96
|
+
this.setState = setState;
|
|
97
|
+
}
|
|
98
|
+
set value(value) {
|
|
99
|
+
this.setState(value);
|
|
100
|
+
}
|
|
101
|
+
get value() {
|
|
102
|
+
return this._value;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// src/debugger/Debugger.tsx
|
|
107
|
+
import { minmax as minmax2 } from "@hrnec06/util";
|
|
108
|
+
import { useEffect as useEffect7, useLayoutEffect as useLayoutEffect2, useMemo as useMemo3, useRef as useRef4, useState as useState8 } from "react";
|
|
109
|
+
|
|
110
|
+
// src/debugger/DebuggerContext.ts
|
|
111
|
+
import { createContext, useContext } from "react";
|
|
112
|
+
var DebuggerContext = createContext(void 0);
|
|
113
|
+
function useDebugger() {
|
|
114
|
+
const ctx = useContext(DebuggerContext);
|
|
115
|
+
if (!ctx)
|
|
116
|
+
throw new Error(`useDebugger may be used only within DebuggerContext.Provider!`);
|
|
117
|
+
return ctx;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// src/debugger/Debugger.tsx
|
|
121
|
+
import clsx3 from "clsx";
|
|
122
|
+
|
|
123
|
+
// src/debugger/DebuggerWindowResize.tsx
|
|
124
|
+
import { cloneVector2, removeVector2 } from "@hrnec06/util";
|
|
125
|
+
import { useEffect as useEffect5, useState as useState5 } from "react";
|
|
126
|
+
import clsx from "clsx";
|
|
127
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
128
|
+
function ResizeBorder() {
|
|
129
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
130
|
+
/* @__PURE__ */ jsx(
|
|
131
|
+
ResizeBar,
|
|
132
|
+
{
|
|
133
|
+
className: "-top-1.5 h-3 w-full cursor-ns-resize",
|
|
134
|
+
applyReposition: true,
|
|
135
|
+
onMove: ([, y]) => [0, y]
|
|
136
|
+
}
|
|
137
|
+
),
|
|
138
|
+
/* @__PURE__ */ jsx(
|
|
139
|
+
ResizeBar,
|
|
140
|
+
{
|
|
141
|
+
className: "-right-1.5 h-full w-3 cursor-ew-resize",
|
|
142
|
+
onMove: ([x]) => [-x, 0]
|
|
143
|
+
}
|
|
144
|
+
),
|
|
145
|
+
/* @__PURE__ */ jsx(
|
|
146
|
+
ResizeBar,
|
|
147
|
+
{
|
|
148
|
+
className: "-bottom-1.5 h-3 w-full cursor-ns-resize",
|
|
149
|
+
onMove: ([, y]) => [0, -y]
|
|
150
|
+
}
|
|
151
|
+
),
|
|
152
|
+
/* @__PURE__ */ jsx(
|
|
153
|
+
ResizeBar,
|
|
154
|
+
{
|
|
155
|
+
className: "-left-1.5 h-full w-3 cursor-ew-resize",
|
|
156
|
+
applyReposition: true,
|
|
157
|
+
onMove: ([x]) => [x, 0]
|
|
158
|
+
}
|
|
159
|
+
),
|
|
160
|
+
/* @__PURE__ */ jsx(
|
|
161
|
+
ResizeBar,
|
|
162
|
+
{
|
|
163
|
+
className: "-top-1.5 -left-1.5 size-3 cursor-nwse-resize",
|
|
164
|
+
applyReposition: true,
|
|
165
|
+
onMove: ([x, y]) => [x, y]
|
|
166
|
+
}
|
|
167
|
+
),
|
|
168
|
+
/* @__PURE__ */ jsx(
|
|
169
|
+
ResizeBar,
|
|
170
|
+
{
|
|
171
|
+
className: "-top-1.5 -right-1.5 size-3 cursor-nesw-resize",
|
|
172
|
+
applyReposition: "y",
|
|
173
|
+
onMove: ([x, y]) => [-x, y]
|
|
174
|
+
}
|
|
175
|
+
),
|
|
176
|
+
/* @__PURE__ */ jsx(
|
|
177
|
+
ResizeBar,
|
|
178
|
+
{
|
|
179
|
+
className: "-bottom-1.5 -right-1.5 size-3 cursor-nwse-resize",
|
|
180
|
+
onMove: ([x, y]) => [-x, -y]
|
|
181
|
+
}
|
|
182
|
+
),
|
|
183
|
+
/* @__PURE__ */ jsx(
|
|
184
|
+
ResizeBar,
|
|
185
|
+
{
|
|
186
|
+
className: "-bottom-1.5 -left-1.5 size-3 cursor-nesw-resize",
|
|
187
|
+
applyReposition: "x",
|
|
188
|
+
onMove: ([x, y]) => [x, -y]
|
|
189
|
+
}
|
|
190
|
+
)
|
|
191
|
+
] });
|
|
192
|
+
}
|
|
193
|
+
function ResizeBar({
|
|
194
|
+
className,
|
|
195
|
+
applyReposition = false,
|
|
196
|
+
onMove
|
|
197
|
+
}) {
|
|
198
|
+
const debug = useDebugger();
|
|
199
|
+
const [drag, setDrag] = useState5(null);
|
|
200
|
+
useEffect5(() => {
|
|
201
|
+
const mouseUp = () => {
|
|
202
|
+
if (!drag) return;
|
|
203
|
+
setDrag(null);
|
|
204
|
+
};
|
|
205
|
+
const mouseMove = (e) => {
|
|
206
|
+
if (!drag) return;
|
|
207
|
+
const offset = [
|
|
208
|
+
e.clientX - drag.dragOrigin[0],
|
|
209
|
+
e.clientY - drag.dragOrigin[1]
|
|
210
|
+
];
|
|
211
|
+
const newSize = onMove(
|
|
212
|
+
offset,
|
|
213
|
+
drag.originalSize,
|
|
214
|
+
drag.originalPosition
|
|
215
|
+
);
|
|
216
|
+
newSize[0] = drag.originalSize[0] - newSize[0];
|
|
217
|
+
newSize[1] = drag.originalSize[1] - newSize[1];
|
|
218
|
+
if (applyReposition !== false) {
|
|
219
|
+
const repositionOffset = cloneVector2(newSize);
|
|
220
|
+
removeVector2(repositionOffset, drag.originalSize);
|
|
221
|
+
debug.placement.reposition([
|
|
222
|
+
drag.originalPosition[0] - (applyReposition === true || applyReposition === "x" ? repositionOffset[0] : 0),
|
|
223
|
+
drag.originalPosition[1] - (applyReposition === true || applyReposition === "y" ? repositionOffset[1] : 0)
|
|
224
|
+
]);
|
|
225
|
+
}
|
|
226
|
+
debug.window.resize(newSize);
|
|
227
|
+
};
|
|
228
|
+
document.addEventListener("mouseup", mouseUp);
|
|
229
|
+
document.addEventListener("mousemove", mouseMove);
|
|
230
|
+
return () => {
|
|
231
|
+
document.removeEventListener("mouseup", mouseUp);
|
|
232
|
+
document.removeEventListener("mousemove", mouseMove);
|
|
233
|
+
};
|
|
234
|
+
}, [drag]);
|
|
235
|
+
const handleMouseDown = (e) => {
|
|
236
|
+
e.preventDefault();
|
|
237
|
+
setDrag({
|
|
238
|
+
dragOrigin: [e.clientX, e.clientY],
|
|
239
|
+
originalSize: debug.window.size,
|
|
240
|
+
originalPosition: debug.placement.position
|
|
241
|
+
});
|
|
242
|
+
};
|
|
243
|
+
return /* @__PURE__ */ jsx(
|
|
244
|
+
"div",
|
|
245
|
+
{
|
|
246
|
+
onMouseDown: handleMouseDown,
|
|
247
|
+
className: clsx(
|
|
248
|
+
"absolute",
|
|
249
|
+
className
|
|
250
|
+
)
|
|
251
|
+
}
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// src/debugger/DebugParser.tsx
|
|
256
|
+
import { useLayoutEffect, useMemo, useState as useState6 } from "react";
|
|
257
|
+
|
|
258
|
+
// src/debugger/DebuggerLogic.ts
|
|
259
|
+
function matchPath(_path, openPaths) {
|
|
260
|
+
for (const openPath of openPaths) {
|
|
261
|
+
const matchers = openPath.split(".");
|
|
262
|
+
const path = [..._path];
|
|
263
|
+
let passed = true;
|
|
264
|
+
while (path.length && passed) {
|
|
265
|
+
const pathItem = path.shift();
|
|
266
|
+
const matcher = matchers.shift();
|
|
267
|
+
if (matcher === "**")
|
|
268
|
+
return true;
|
|
269
|
+
if (matcher === "*") {
|
|
270
|
+
if (path.length > 1)
|
|
271
|
+
passed = false;
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
if (pathItem !== matcher)
|
|
275
|
+
passed = false;
|
|
276
|
+
}
|
|
277
|
+
if (path.length === 0 && passed)
|
|
278
|
+
return true;
|
|
279
|
+
}
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// src/debugger/DebugParser.tsx
|
|
284
|
+
import { entries, keys, padString } from "@hrnec06/util";
|
|
285
|
+
import React from "react";
|
|
286
|
+
|
|
287
|
+
// src/debugger/DebuggerSymbols.tsx
|
|
288
|
+
import clsx2 from "clsx";
|
|
289
|
+
import { ChevronDown } from "lucide-react";
|
|
290
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
291
|
+
function Char_Colon() {
|
|
292
|
+
return /* @__PURE__ */ jsx2("span", { className: "text-[#ccccab]", children: ": " });
|
|
293
|
+
}
|
|
294
|
+
function Char_Comma() {
|
|
295
|
+
return /* @__PURE__ */ jsx2("span", { className: "text-[#ccccab]", children: ", " });
|
|
296
|
+
}
|
|
297
|
+
function Char_Bracket({
|
|
298
|
+
text
|
|
299
|
+
}) {
|
|
300
|
+
return /* @__PURE__ */ jsx2("span", { className: "text-[#da70d6]", children: text });
|
|
301
|
+
}
|
|
302
|
+
function Chevron_Toggle({
|
|
303
|
+
expanded,
|
|
304
|
+
onToggle
|
|
305
|
+
}) {
|
|
306
|
+
const handleClick = () => {
|
|
307
|
+
onToggle?.(!expanded);
|
|
308
|
+
};
|
|
309
|
+
return /* @__PURE__ */ jsx2(
|
|
310
|
+
"button",
|
|
311
|
+
{
|
|
312
|
+
onClick: handleClick,
|
|
313
|
+
className: clsx2(
|
|
314
|
+
"absolute",
|
|
315
|
+
"left-1 translate-y-0.5"
|
|
316
|
+
),
|
|
317
|
+
children: /* @__PURE__ */ jsx2(
|
|
318
|
+
ChevronDown,
|
|
319
|
+
{
|
|
320
|
+
className: clsx2(
|
|
321
|
+
"size-4 text-primary-400 hover:text-zinc-500",
|
|
322
|
+
!expanded && "-rotate-90"
|
|
323
|
+
)
|
|
324
|
+
}
|
|
325
|
+
)
|
|
326
|
+
}
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// src/debugger/DebugParser.tsx
|
|
331
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
332
|
+
function ParseValue({
|
|
333
|
+
value,
|
|
334
|
+
path = []
|
|
335
|
+
}) {
|
|
336
|
+
const debug = useDebugger();
|
|
337
|
+
switch (typeof value) {
|
|
338
|
+
case "string":
|
|
339
|
+
return /* @__PURE__ */ jsx3(Value_String, { value });
|
|
340
|
+
case "bigint":
|
|
341
|
+
case "number":
|
|
342
|
+
return /* @__PURE__ */ jsx3(Value_Number, { value });
|
|
343
|
+
case "boolean":
|
|
344
|
+
return /* @__PURE__ */ jsx3(Value_Boolean, { value });
|
|
345
|
+
case "undefined":
|
|
346
|
+
return /* @__PURE__ */ jsx3(Value_Keyword, { value: "undefined" });
|
|
347
|
+
case "function":
|
|
348
|
+
return /* @__PURE__ */ jsx3(Value_Function, { value });
|
|
349
|
+
case "symbol":
|
|
350
|
+
return /* @__PURE__ */ jsx3(Value_Symbol, { value });
|
|
351
|
+
case "object": {
|
|
352
|
+
if (value === null)
|
|
353
|
+
return /* @__PURE__ */ jsx3(Value_Keyword, { value: "null" });
|
|
354
|
+
const isRootObject = path.length === 0;
|
|
355
|
+
const shouldBeExpanded = isRootObject && debug.options.openRoot || matchPath(path, debug.paths.open) && !matchPath(path, debug.paths.exclude);
|
|
356
|
+
if (Array.isArray(value)) {
|
|
357
|
+
return /* @__PURE__ */ jsx3(Value_Array, { value, path, defaultExpanded: shouldBeExpanded });
|
|
358
|
+
}
|
|
359
|
+
return /* @__PURE__ */ jsx3(Value_Object, { value, path, defaultExpanded: shouldBeExpanded });
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
function Value_String({
|
|
364
|
+
value,
|
|
365
|
+
noEncase = false
|
|
366
|
+
}) {
|
|
367
|
+
return /* @__PURE__ */ jsx3("span", { className: "text-[#ce9178]", children: padString(value, noEncase ? 0 : 1, '"') });
|
|
368
|
+
}
|
|
369
|
+
function Value_Number({
|
|
370
|
+
value
|
|
371
|
+
}) {
|
|
372
|
+
return /* @__PURE__ */ jsx3("span", { className: "text-[#a7ce9b]", children: value });
|
|
373
|
+
}
|
|
374
|
+
function Value_Boolean({
|
|
375
|
+
value
|
|
376
|
+
}) {
|
|
377
|
+
return /* @__PURE__ */ jsx3(Value_Keyword, { value: value ? "true" : "false" });
|
|
378
|
+
}
|
|
379
|
+
function Value_Function({
|
|
380
|
+
value
|
|
381
|
+
}) {
|
|
382
|
+
const argsMatch = value.toString().match(/^[^(]*\(\s*([^)]*)\)/);
|
|
383
|
+
let args = "";
|
|
384
|
+
if (argsMatch && argsMatch.length > 1) {
|
|
385
|
+
args = argsMatch[1];
|
|
386
|
+
}
|
|
387
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
388
|
+
/* @__PURE__ */ jsx3("span", { className: "text-[#f2824a]", children: "\u0192 " }),
|
|
389
|
+
/* @__PURE__ */ jsx3("span", { children: `${value.name}(${args})` })
|
|
390
|
+
] });
|
|
391
|
+
}
|
|
392
|
+
function Value_Keyword({
|
|
393
|
+
value
|
|
394
|
+
}) {
|
|
395
|
+
return /* @__PURE__ */ jsx3("span", { className: "text-[#439ccb]", children: value });
|
|
396
|
+
}
|
|
397
|
+
function Value_Object({
|
|
398
|
+
value,
|
|
399
|
+
path,
|
|
400
|
+
defaultExpanded = false
|
|
401
|
+
}) {
|
|
402
|
+
const debug = useDebugger();
|
|
403
|
+
const [expanded, setExpanded] = useState6(defaultExpanded);
|
|
404
|
+
const objectEntries = entries(value);
|
|
405
|
+
const collapsedPreview = useMemo(() => {
|
|
406
|
+
const children = [];
|
|
407
|
+
const keyList = keys(value);
|
|
408
|
+
for (let i = 0; i < Math.min(keyList.length, 6); i++) {
|
|
409
|
+
children.push(
|
|
410
|
+
/* @__PURE__ */ jsxs2(React.Fragment, { children: [
|
|
411
|
+
/* @__PURE__ */ jsx3(Value_Object_Key, { text: keyList[i] }),
|
|
412
|
+
i < keyList.length - 1 && /* @__PURE__ */ jsx3(Char_Comma, {})
|
|
413
|
+
] }, i)
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
if (keyList.length > 6)
|
|
417
|
+
children.push(/* @__PURE__ */ jsx3("span", { className: "text-zinc-500", children: "..." }, "rest"));
|
|
418
|
+
return children;
|
|
419
|
+
}, [value]);
|
|
420
|
+
useLayoutEffect(() => {
|
|
421
|
+
debug.event.expand(path, expanded);
|
|
422
|
+
}, [expanded]);
|
|
423
|
+
const handleExpand = (state) => {
|
|
424
|
+
setExpanded(state);
|
|
425
|
+
};
|
|
426
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
427
|
+
/* @__PURE__ */ jsx3(Chevron_Toggle, { expanded, onToggle: handleExpand }),
|
|
428
|
+
Object.getPrototypeOf(value) !== Object.prototype && /* @__PURE__ */ jsxs2("span", { children: [
|
|
429
|
+
"(",
|
|
430
|
+
value.constructor.name,
|
|
431
|
+
") "
|
|
432
|
+
] }),
|
|
433
|
+
expanded ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
434
|
+
/* @__PURE__ */ jsx3(Char_Bracket, { text: "{" }),
|
|
435
|
+
/* @__PURE__ */ jsx3("ul", { className: "pl-4 ml-1 border-l border-l-primary-400", children: objectEntries.map(([key, value2], ix) => {
|
|
436
|
+
return /* @__PURE__ */ jsxs2("li", { children: [
|
|
437
|
+
/* @__PURE__ */ jsx3(Value_Object_Key, { text: key }),
|
|
438
|
+
/* @__PURE__ */ jsx3(Char_Colon, {}),
|
|
439
|
+
/* @__PURE__ */ jsx3(ParseValue, { value: value2, path: [...path, `${key}`] }),
|
|
440
|
+
ix < objectEntries.length - 1 && /* @__PURE__ */ jsx3(Char_Comma, {})
|
|
441
|
+
] }, ix);
|
|
442
|
+
}) }),
|
|
443
|
+
/* @__PURE__ */ jsx3(Char_Bracket, { text: "}" })
|
|
444
|
+
] }) : /* @__PURE__ */ jsxs2(
|
|
445
|
+
"div",
|
|
446
|
+
{
|
|
447
|
+
className: "inline-block cursor-pointer",
|
|
448
|
+
onClick: () => setExpanded(true),
|
|
449
|
+
children: [
|
|
450
|
+
/* @__PURE__ */ jsx3(Char_Bracket, { text: "{" }),
|
|
451
|
+
" ",
|
|
452
|
+
collapsedPreview,
|
|
453
|
+
" ",
|
|
454
|
+
/* @__PURE__ */ jsx3(Char_Bracket, { text: "}" })
|
|
455
|
+
]
|
|
456
|
+
}
|
|
457
|
+
)
|
|
458
|
+
] });
|
|
459
|
+
}
|
|
460
|
+
function Value_Array({
|
|
461
|
+
value,
|
|
462
|
+
path,
|
|
463
|
+
defaultExpanded = false
|
|
464
|
+
}) {
|
|
465
|
+
const debug = useDebugger();
|
|
466
|
+
const [expanded, setExpanded] = useState6(defaultExpanded);
|
|
467
|
+
const children = useMemo(() => {
|
|
468
|
+
const children2 = [];
|
|
469
|
+
let ix = 0;
|
|
470
|
+
while (ix < value.length) {
|
|
471
|
+
const nextTarget = Math.min(ix + debug.options.compactArrays, value.length);
|
|
472
|
+
children2.push(
|
|
473
|
+
/* @__PURE__ */ jsx3("li", { children: (() => {
|
|
474
|
+
const children3 = [];
|
|
475
|
+
for (; ix < nextTarget; ix++) {
|
|
476
|
+
children3.push(
|
|
477
|
+
/* @__PURE__ */ jsxs2(React.Fragment, { children: [
|
|
478
|
+
/* @__PURE__ */ jsx3(ParseValue, { value: value[ix], path: [...path, `${ix}`] }),
|
|
479
|
+
ix < value.length - 1 && /* @__PURE__ */ jsx3(Char_Comma, {})
|
|
480
|
+
] }, ix)
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
return children3;
|
|
484
|
+
})() }, ix)
|
|
485
|
+
);
|
|
486
|
+
ix = nextTarget;
|
|
487
|
+
}
|
|
488
|
+
return children2;
|
|
489
|
+
}, [debug.options.compactArrays, value]);
|
|
490
|
+
const collapsedPreview = useMemo(() => {
|
|
491
|
+
const children2 = [];
|
|
492
|
+
for (let i = 0; i < Math.min(value.length, 6); i++) {
|
|
493
|
+
children2.push(
|
|
494
|
+
/* @__PURE__ */ jsxs2(React.Fragment, { children: [
|
|
495
|
+
/* @__PURE__ */ jsx3(ParseValue_ToSimple, { value: value[i] }),
|
|
496
|
+
i < value.length - 1 && /* @__PURE__ */ jsx3(Char_Comma, {})
|
|
497
|
+
] }, i)
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
if (value.length > 6)
|
|
501
|
+
children2.push(/* @__PURE__ */ jsx3("span", { className: "text-zinc-500", children: "..." }, "rest"));
|
|
502
|
+
return children2;
|
|
503
|
+
}, [value]);
|
|
504
|
+
useLayoutEffect(() => {
|
|
505
|
+
debug.event.expand(path, expanded);
|
|
506
|
+
}, [expanded]);
|
|
507
|
+
const handleExpand = (state) => {
|
|
508
|
+
setExpanded(state);
|
|
509
|
+
};
|
|
510
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
511
|
+
/* @__PURE__ */ jsx3(Chevron_Toggle, { expanded, onToggle: handleExpand }),
|
|
512
|
+
/* @__PURE__ */ jsx3("span", { children: `(${value.length}) ` }),
|
|
513
|
+
expanded ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
514
|
+
/* @__PURE__ */ jsx3(Char_Bracket, { text: "[" }),
|
|
515
|
+
/* @__PURE__ */ jsx3("ul", { className: "pl-4 ml-1 border-l border-l-primary-400", children }),
|
|
516
|
+
/* @__PURE__ */ jsx3(Char_Bracket, { text: "]" })
|
|
517
|
+
] }) : /* @__PURE__ */ jsxs2(
|
|
518
|
+
"div",
|
|
519
|
+
{
|
|
520
|
+
className: "inline-block cursor-pointer",
|
|
521
|
+
onClick: () => setExpanded(true),
|
|
522
|
+
children: [
|
|
523
|
+
/* @__PURE__ */ jsx3(Char_Bracket, { text: "[" }),
|
|
524
|
+
collapsedPreview,
|
|
525
|
+
/* @__PURE__ */ jsx3(Char_Bracket, { text: "]" })
|
|
526
|
+
]
|
|
527
|
+
}
|
|
528
|
+
)
|
|
529
|
+
] });
|
|
530
|
+
}
|
|
531
|
+
function Value_Object_Key({
|
|
532
|
+
text
|
|
533
|
+
}) {
|
|
534
|
+
return /* @__PURE__ */ jsx3("span", { className: "text-[#9CDCF0]", children: text });
|
|
535
|
+
}
|
|
536
|
+
function Value_Symbol({
|
|
537
|
+
value
|
|
538
|
+
}) {
|
|
539
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
540
|
+
/* @__PURE__ */ jsx3(Value_Keyword, { value: "Symbol" }),
|
|
541
|
+
/* @__PURE__ */ jsx3(Char_Bracket, { text: "(" }),
|
|
542
|
+
/* @__PURE__ */ jsx3("span", { children: value.description }),
|
|
543
|
+
/* @__PURE__ */ jsx3(Char_Bracket, { text: ")" })
|
|
544
|
+
] });
|
|
545
|
+
}
|
|
546
|
+
function ParseValue_ToSimple({
|
|
547
|
+
value
|
|
548
|
+
}) {
|
|
549
|
+
const MAX_LENGTH = 16;
|
|
550
|
+
switch (typeof value) {
|
|
551
|
+
case "bigint":
|
|
552
|
+
case "number": {
|
|
553
|
+
const numStr = value.toString();
|
|
554
|
+
if (numStr.length > MAX_LENGTH)
|
|
555
|
+
return /* @__PURE__ */ jsx3(Value_Keyword, { value: typeof value });
|
|
556
|
+
return /* @__PURE__ */ jsx3(Value_Number, { value });
|
|
557
|
+
}
|
|
558
|
+
case "boolean":
|
|
559
|
+
return /* @__PURE__ */ jsx3(Value_Boolean, { value });
|
|
560
|
+
case "function":
|
|
561
|
+
return /* @__PURE__ */ jsx3(Value_Function, { value });
|
|
562
|
+
case "object": {
|
|
563
|
+
if (value === null)
|
|
564
|
+
return /* @__PURE__ */ jsx3(Value_Keyword, { value: "null" });
|
|
565
|
+
const className = Object.getPrototypeOf(value) !== Object.prototype ? value.constructor.name : null;
|
|
566
|
+
if (className === null || className.length > MAX_LENGTH)
|
|
567
|
+
return /* @__PURE__ */ jsx3(Value_Keyword, { value: "object" });
|
|
568
|
+
return className;
|
|
569
|
+
}
|
|
570
|
+
case "string": {
|
|
571
|
+
if (value.length > MAX_LENGTH)
|
|
572
|
+
return /* @__PURE__ */ jsx3(Value_String, { value: "string", noEncase: true });
|
|
573
|
+
return /* @__PURE__ */ jsx3(Value_String, { value });
|
|
574
|
+
}
|
|
575
|
+
case "symbol": {
|
|
576
|
+
if (!value.description || value.description.length > MAX_LENGTH)
|
|
577
|
+
return /* @__PURE__ */ jsx3(Value_Keyword, { value: "Symbol" });
|
|
578
|
+
return /* @__PURE__ */ jsx3(Value_Symbol, { value });
|
|
579
|
+
}
|
|
580
|
+
case "undefined":
|
|
581
|
+
return /* @__PURE__ */ jsx3(Value_Keyword, { value: "undefined" });
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// src/debugger/DebuggerScrollBar.tsx
|
|
586
|
+
import { minmax } from "@hrnec06/util";
|
|
587
|
+
import { useEffect as useEffect6, useRef as useRef3, useState as useState7 } from "react";
|
|
588
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
589
|
+
function ScrollBar({
|
|
590
|
+
containerHeight,
|
|
591
|
+
scrollHeight
|
|
592
|
+
}) {
|
|
593
|
+
const debug = useDebugger();
|
|
594
|
+
const [wrapperHeight, setWrapperHeight] = useState7(0);
|
|
595
|
+
const barHeight = containerHeight / (scrollHeight + containerHeight) * wrapperHeight;
|
|
596
|
+
const barTop = (wrapperHeight - barHeight) * debug.scroll.progress;
|
|
597
|
+
const [grab, setGrab] = useState7(null);
|
|
598
|
+
const [grabOffset, setGrabOffset] = useState7(null);
|
|
599
|
+
const wrapperRef = useRef3(null);
|
|
600
|
+
useEffect6(() => {
|
|
601
|
+
if (!wrapperRef.current) return;
|
|
602
|
+
const observer = new ResizeObserver(() => updateWrapperHeight());
|
|
603
|
+
observer.observe(wrapperRef.current);
|
|
604
|
+
updateWrapperHeight();
|
|
605
|
+
return () => {
|
|
606
|
+
observer.disconnect();
|
|
607
|
+
};
|
|
608
|
+
}, [wrapperRef]);
|
|
609
|
+
useListener(document, "mouseup", (event) => {
|
|
610
|
+
if (!grab) return;
|
|
611
|
+
setGrab(null);
|
|
612
|
+
setGrabOffset(null);
|
|
613
|
+
}, [grab]);
|
|
614
|
+
useListener(document, "mousemove", (event) => {
|
|
615
|
+
if (!grab) return;
|
|
616
|
+
setGrabOffset(event.clientY - (grab.windowOrigin - grab.positionOrigin * (wrapperHeight - barHeight)));
|
|
617
|
+
}, [grab]);
|
|
618
|
+
useEffect6(() => {
|
|
619
|
+
if (grabOffset === null) return;
|
|
620
|
+
const fixedOffset = minmax(grabOffset, 0, wrapperHeight - barHeight) / (wrapperHeight - barHeight);
|
|
621
|
+
debug.scroll.setProgress(fixedOffset);
|
|
622
|
+
}, [grabOffset]);
|
|
623
|
+
const updateWrapperHeight = () => {
|
|
624
|
+
if (!wrapperRef.current) return;
|
|
625
|
+
setWrapperHeight(wrapperRef.current.clientHeight);
|
|
626
|
+
};
|
|
627
|
+
const handleWraperMouseDown = (e) => {
|
|
628
|
+
e.preventDefault();
|
|
629
|
+
if (grab) return;
|
|
630
|
+
};
|
|
631
|
+
const handleMouseDown = (e) => {
|
|
632
|
+
e.preventDefault();
|
|
633
|
+
if (grab) return;
|
|
634
|
+
setGrab({
|
|
635
|
+
positionOrigin: debug.scroll.progress,
|
|
636
|
+
windowOrigin: e.clientY
|
|
637
|
+
});
|
|
638
|
+
};
|
|
639
|
+
return /* @__PURE__ */ jsx4("div", { className: "p-1 border-l border-l-primary-600", children: /* @__PURE__ */ jsx4(
|
|
640
|
+
"div",
|
|
641
|
+
{
|
|
642
|
+
onMouseDown: handleWraperMouseDown,
|
|
643
|
+
ref: wrapperRef,
|
|
644
|
+
className: "h-full flex-shrink-0",
|
|
645
|
+
children: debug.scroll.isScrollable && wrapperHeight > 0 && /* @__PURE__ */ jsx4(
|
|
646
|
+
"div",
|
|
647
|
+
{
|
|
648
|
+
onMouseDown: handleMouseDown,
|
|
649
|
+
className: "bg-primary-500 hover:bg-primary-400 w-2 rounded-lg",
|
|
650
|
+
style: {
|
|
651
|
+
transform: `translateY(${barTop}px)`,
|
|
652
|
+
height: `${barHeight}px`
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
)
|
|
656
|
+
}
|
|
657
|
+
) });
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// src/debugger/Debugger.tsx
|
|
661
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
662
|
+
function Debug({
|
|
663
|
+
value,
|
|
664
|
+
openPaths,
|
|
665
|
+
excludePaths,
|
|
666
|
+
size = "normal",
|
|
667
|
+
compactArrays = 1,
|
|
668
|
+
autoHeight = false,
|
|
669
|
+
openRoot = true
|
|
670
|
+
}) {
|
|
671
|
+
const LS_POS_KEY = "debugger_position";
|
|
672
|
+
const LS_SIZE_KEY = "debugger_size";
|
|
673
|
+
const LS_EXPAND_KEY = "debugger_expanded";
|
|
674
|
+
const f9_pressed = useKeyListener("F9");
|
|
675
|
+
const [position, setPosition] = useState8([0, 0]);
|
|
676
|
+
const [grab, setGrab] = useState8(null);
|
|
677
|
+
const [grabOffset, setGrabOffset] = useState8(null);
|
|
678
|
+
const [windowSize, setWindowSize] = useState8([500, 500]);
|
|
679
|
+
const [scrollHeight, setScrollHeight] = useState8(0);
|
|
680
|
+
const [containerHeight, setContainerHeight] = useState8(0);
|
|
681
|
+
const [scrollProgress, setScrollProgress] = useState8(0);
|
|
682
|
+
const font = useMemo3(() => {
|
|
683
|
+
switch (size) {
|
|
684
|
+
case "tiny":
|
|
685
|
+
return { fontSize: 12, lineHeight: 16 };
|
|
686
|
+
case "normal":
|
|
687
|
+
return { fontSize: 14, lineHeight: 20 };
|
|
688
|
+
case "big":
|
|
689
|
+
return { fontSize: 16, lineHeight: 24 };
|
|
690
|
+
}
|
|
691
|
+
}, [size]);
|
|
692
|
+
const containerRef = useRef4(null);
|
|
693
|
+
useEffect7(() => {
|
|
694
|
+
const mouseUp = (e) => {
|
|
695
|
+
if (!grab) return;
|
|
696
|
+
setPosition(finalPositionRef.current);
|
|
697
|
+
setGrab(null);
|
|
698
|
+
setGrabOffset(null);
|
|
699
|
+
};
|
|
700
|
+
const mouseMove = (e) => {
|
|
701
|
+
if (!grab) return;
|
|
702
|
+
setGrabOffset([
|
|
703
|
+
e.clientX - grab.windowOrigin[0],
|
|
704
|
+
e.clientY - grab.windowOrigin[1]
|
|
705
|
+
]);
|
|
706
|
+
};
|
|
707
|
+
document.addEventListener("mouseup", mouseUp);
|
|
708
|
+
document.addEventListener("mousemove", mouseMove);
|
|
709
|
+
return () => {
|
|
710
|
+
document.removeEventListener("mouseup", mouseUp);
|
|
711
|
+
document.removeEventListener("mousemove", mouseMove);
|
|
712
|
+
};
|
|
713
|
+
}, [grab]);
|
|
714
|
+
useLayoutEffect2(() => {
|
|
715
|
+
updateScrollHeight();
|
|
716
|
+
}, [windowSize, value, size, containerRef]);
|
|
717
|
+
const isScrollable = useMemo3(() => scrollHeight > 0, [scrollHeight]);
|
|
718
|
+
useEffect7(() => {
|
|
719
|
+
try {
|
|
720
|
+
const saved_position = localStorage.getItem(LS_POS_KEY);
|
|
721
|
+
if (saved_position) {
|
|
722
|
+
const [v1, v2] = saved_position.split(",");
|
|
723
|
+
if (v1 === void 0 || v2 === void 0)
|
|
724
|
+
throw new Error("Invalid vector: " + saved_position);
|
|
725
|
+
const [v1_p, v2_p] = [parseInt(v1), parseInt(v2)];
|
|
726
|
+
if (isNaN(v1_p) || isNaN(v2_p))
|
|
727
|
+
throw new Error("Invalid vector values: " + saved_position);
|
|
728
|
+
setPosition([v1_p, v2_p]);
|
|
729
|
+
}
|
|
730
|
+
} catch (error) {
|
|
731
|
+
console.error(`Error loading saved position: `, error);
|
|
732
|
+
localStorage.removeItem(LS_POS_KEY);
|
|
733
|
+
}
|
|
734
|
+
}, []);
|
|
735
|
+
useEffect7(() => {
|
|
736
|
+
try {
|
|
737
|
+
const saved_size = localStorage.getItem(LS_SIZE_KEY);
|
|
738
|
+
if (saved_size) {
|
|
739
|
+
const [v1, v2] = saved_size.split(",");
|
|
740
|
+
if (v1 === void 0 || v2 === void 0)
|
|
741
|
+
throw new Error("Invalid vector: " + saved_size);
|
|
742
|
+
const [v1_p, v2_p] = [parseInt(v1), parseInt(v2)];
|
|
743
|
+
if (isNaN(v1_p) || isNaN(v2_p))
|
|
744
|
+
throw new Error("Invalid vector values: " + saved_size);
|
|
745
|
+
setWindowSize([v1_p, v2_p]);
|
|
746
|
+
}
|
|
747
|
+
} catch (error) {
|
|
748
|
+
console.error(`Error loading saved size: `, error);
|
|
749
|
+
localStorage.removeItem(LS_POS_KEY);
|
|
750
|
+
}
|
|
751
|
+
}, []);
|
|
752
|
+
useUpdateEffect(() => {
|
|
753
|
+
localStorage.setItem(LS_POS_KEY, `${position[0]},${position[1]}`);
|
|
754
|
+
}, [position]);
|
|
755
|
+
useUpdateEffect(() => {
|
|
756
|
+
localStorage.setItem(LS_SIZE_KEY, `${windowSize[0]},${windowSize[1]}`);
|
|
757
|
+
}, [windowSize]);
|
|
758
|
+
useEffect7(() => {
|
|
759
|
+
if (!f9_pressed)
|
|
760
|
+
return;
|
|
761
|
+
setPosition([0, 0]);
|
|
762
|
+
}, [f9_pressed]);
|
|
763
|
+
const finalPosition = useMemo3(() => {
|
|
764
|
+
return [
|
|
765
|
+
position[0] + (grabOffset?.[0] ?? 0),
|
|
766
|
+
position[1] + (grabOffset?.[1] ?? 0)
|
|
767
|
+
];
|
|
768
|
+
}, [position, grabOffset]);
|
|
769
|
+
const finalPositionRef = useUpdatedRef(finalPosition);
|
|
770
|
+
const calculateContainerHeight = () => {
|
|
771
|
+
if (!containerRef.current) return 0;
|
|
772
|
+
return containerRef.current.clientHeight;
|
|
773
|
+
};
|
|
774
|
+
const calculateScrollHeight = () => {
|
|
775
|
+
if (!containerRef.current) return 0;
|
|
776
|
+
return containerRef.current.scrollHeight - calculateContainerHeight();
|
|
777
|
+
};
|
|
778
|
+
const updateScrollHeight = () => {
|
|
779
|
+
if (!containerRef.current) return;
|
|
780
|
+
setScrollHeight(calculateScrollHeight());
|
|
781
|
+
setContainerHeight(calculateContainerHeight());
|
|
782
|
+
};
|
|
783
|
+
const handleMouseDown = (e) => {
|
|
784
|
+
e.preventDefault();
|
|
785
|
+
setGrab({
|
|
786
|
+
positionOrigin: position,
|
|
787
|
+
windowOrigin: [e.clientX, e.clientY]
|
|
788
|
+
});
|
|
789
|
+
};
|
|
790
|
+
const handleExpandChange = (path, state) => {
|
|
791
|
+
if (!containerRef.current) return;
|
|
792
|
+
setScrollProgress(minmax2(scrollProgress * scrollHeight / calculateScrollHeight(), 0, 1));
|
|
793
|
+
updateScrollHeight();
|
|
794
|
+
};
|
|
795
|
+
const handleWheel = (e) => {
|
|
796
|
+
const moveByPX = font.lineHeight * 3;
|
|
797
|
+
let addProgress = moveByPX / scrollHeight;
|
|
798
|
+
if (e.deltaY < 0)
|
|
799
|
+
addProgress *= -1;
|
|
800
|
+
setScrollProgress((p) => minmax2(p + addProgress, 0, 1));
|
|
801
|
+
};
|
|
802
|
+
return /* @__PURE__ */ jsx5(
|
|
803
|
+
DebuggerContext.Provider,
|
|
804
|
+
{
|
|
805
|
+
value: {
|
|
806
|
+
paths: {
|
|
807
|
+
exclude: excludePaths ?? [],
|
|
808
|
+
open: openPaths ?? []
|
|
809
|
+
},
|
|
810
|
+
options: {
|
|
811
|
+
compactArrays,
|
|
812
|
+
autoHeight,
|
|
813
|
+
openRoot
|
|
814
|
+
},
|
|
815
|
+
window: {
|
|
816
|
+
resize: setWindowSize,
|
|
817
|
+
size: windowSize
|
|
818
|
+
},
|
|
819
|
+
placement: {
|
|
820
|
+
reposition: setPosition,
|
|
821
|
+
position
|
|
822
|
+
},
|
|
823
|
+
event: {
|
|
824
|
+
expand: handleExpandChange
|
|
825
|
+
},
|
|
826
|
+
scroll: {
|
|
827
|
+
setProgress: setScrollProgress,
|
|
828
|
+
progress: scrollProgress,
|
|
829
|
+
isScrollable
|
|
830
|
+
}
|
|
831
|
+
},
|
|
832
|
+
children: /* @__PURE__ */ jsx5("div", { className: "fixed pointer-events-none w-full h-full left-0 top-0 overflow-hidden", children: /* @__PURE__ */ jsxs3(
|
|
833
|
+
"div",
|
|
834
|
+
{
|
|
835
|
+
className: clsx3(
|
|
836
|
+
"absolute font-jetbrains pointer-events-auto",
|
|
837
|
+
size === "tiny" && "text-xs",
|
|
838
|
+
size === "normal" && "text-sm",
|
|
839
|
+
size === "big" && "text-base"
|
|
840
|
+
),
|
|
841
|
+
style: {
|
|
842
|
+
left: finalPosition[0],
|
|
843
|
+
top: finalPosition[1],
|
|
844
|
+
width: windowSize[0],
|
|
845
|
+
height: windowSize[1]
|
|
846
|
+
},
|
|
847
|
+
children: [
|
|
848
|
+
/* @__PURE__ */ jsx5(ResizeBorder, {}),
|
|
849
|
+
/* @__PURE__ */ jsxs3(
|
|
850
|
+
"div",
|
|
851
|
+
{
|
|
852
|
+
onWheel: handleWheel,
|
|
853
|
+
className: "bg-[#1f1f1f] shadow-lg rounded-md border border-primary-400 w-full h-full overflow-hidden flex",
|
|
854
|
+
children: [
|
|
855
|
+
/* @__PURE__ */ jsx5(
|
|
856
|
+
"div",
|
|
857
|
+
{
|
|
858
|
+
ref: containerRef,
|
|
859
|
+
onMouseDown: handleMouseDown,
|
|
860
|
+
className: " cursor-grab w-full",
|
|
861
|
+
style: {
|
|
862
|
+
transform: `translateY(${-(scrollProgress * scrollHeight)}px)`
|
|
863
|
+
},
|
|
864
|
+
children: /* @__PURE__ */ jsx5("div", { className: "p-3 pl-5", children: /* @__PURE__ */ jsx5(ParseValue, { value }) })
|
|
865
|
+
}
|
|
866
|
+
),
|
|
867
|
+
/* @__PURE__ */ jsx5(
|
|
868
|
+
ScrollBar,
|
|
869
|
+
{
|
|
870
|
+
containerHeight,
|
|
871
|
+
scrollHeight
|
|
872
|
+
}
|
|
873
|
+
)
|
|
874
|
+
]
|
|
875
|
+
}
|
|
876
|
+
)
|
|
877
|
+
]
|
|
878
|
+
}
|
|
879
|
+
) })
|
|
880
|
+
}
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
export {
|
|
884
|
+
Debug as Debugger,
|
|
885
|
+
useKeyListener,
|
|
886
|
+
useListener,
|
|
887
|
+
useSignal,
|
|
888
|
+
useUpdateEffect,
|
|
889
|
+
useUpdatedRef,
|
|
890
|
+
useWindowSize
|
|
891
|
+
};
|