@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.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
+ };