@hrnec06/react_utils 1.1.0 → 1.2.1
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/package.json +3 -11
- package/src/debugger/Debugger.tsx +297 -0
- package/src/debugger/DebuggerContext.ts +41 -0
- package/src/debugger/DebuggerLogic.ts +30 -0
- package/src/debugger/DebuggerScrollBar.tsx +108 -0
- package/src/debugger/DebuggerSymbols.tsx +63 -0
- package/src/debugger/DebuggerWindowResize.tsx +136 -0
- package/src/debugger/parser/DebugParser.tsx +45 -0
- package/src/debugger/parser/DebugParserSimple.tsx +53 -0
- package/src/debugger/parser/ValueArray.tsx +143 -0
- package/src/debugger/parser/ValueBoolean.tsx +10 -0
- package/src/debugger/parser/ValueFunction.tsx +25 -0
- package/src/debugger/parser/ValueKeyword.tsx +12 -0
- package/src/debugger/parser/ValueNumber.tsx +12 -0
- package/src/debugger/parser/ValueObject.tsx +113 -0
- package/src/debugger/parser/ValueString.tsx +16 -0
- package/src/debugger/parser/ValueSymbol.tsx +20 -0
- package/src/hooks/useKeyListener.ts +47 -0
- package/src/hooks/useListener.ts +11 -0
- package/src/hooks/useSignal.ts +31 -0
- package/src/hooks/useUpdateEffect.ts +14 -0
- package/src/hooks/useUpdatedRef.ts +12 -0
- package/src/hooks/useWindowSize.ts +22 -0
- package/src/index.tsx +17 -0
- package/dist/index.d.mts +0 -40
- package/dist/index.d.ts +0 -40
- package/dist/index.js +0 -934
- package/dist/index.mjs +0 -891
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import useDebugger from "../DebuggerContext";
|
|
2
|
+
import { matchPath } from "../DebuggerLogic";
|
|
3
|
+
import ValueArray from "./ValueArray";
|
|
4
|
+
import ValueBoolean from "./ValueBoolean";
|
|
5
|
+
import ValueFunction from "./ValueFunction";
|
|
6
|
+
import ValueKeyword from "./ValueKeyword";
|
|
7
|
+
import ValueNumber from "./ValueNumber";
|
|
8
|
+
import ValueObject from "./ValueObject";
|
|
9
|
+
import ValueString from "./ValueString";
|
|
10
|
+
import ValueSymbol from "./ValueSymbol";
|
|
11
|
+
|
|
12
|
+
interface ParseValueProps {
|
|
13
|
+
value: unknown,
|
|
14
|
+
path?: string[]
|
|
15
|
+
}
|
|
16
|
+
export default function ParseValue({
|
|
17
|
+
value,
|
|
18
|
+
path = []
|
|
19
|
+
}: ParseValueProps) {
|
|
20
|
+
const debug = useDebugger();
|
|
21
|
+
|
|
22
|
+
switch (typeof value) {
|
|
23
|
+
case 'string': return (<ValueString value={value} />);
|
|
24
|
+
case 'bigint':
|
|
25
|
+
case 'number': return (<ValueNumber value={value} />);
|
|
26
|
+
case 'boolean': return (<ValueBoolean value={value} />);
|
|
27
|
+
case 'undefined': return (<ValueKeyword value={"undefined"} />);
|
|
28
|
+
case 'function': return (<ValueFunction value={value} />);
|
|
29
|
+
case 'symbol': return (<ValueSymbol value={value} />)
|
|
30
|
+
case 'object': {
|
|
31
|
+
if (value === null)
|
|
32
|
+
return (<ValueKeyword value={"null"} />)
|
|
33
|
+
|
|
34
|
+
const isRootObject = path.length === 0;
|
|
35
|
+
|
|
36
|
+
const shouldBeExpanded = (isRootObject && debug.options.openRoot) || (matchPath(path, debug.paths.open) && !matchPath(path, debug.paths.exclude));
|
|
37
|
+
|
|
38
|
+
if (Array.isArray(value)) {
|
|
39
|
+
return <ValueArray value={value} path={path} defaultExpanded={shouldBeExpanded} />
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return <ValueObject value={value} path={path} defaultExpanded={shouldBeExpanded} />
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import ValueBoolean from "./ValueBoolean";
|
|
2
|
+
import ValueFunction from "./ValueFunction";
|
|
3
|
+
import ValueKeyword from "./ValueKeyword";
|
|
4
|
+
import ValueNumber from "./ValueNumber";
|
|
5
|
+
import ValueString from "./ValueString";
|
|
6
|
+
import ValueSymbol from "./ValueSymbol";
|
|
7
|
+
|
|
8
|
+
interface ParseValueSimpleProps {
|
|
9
|
+
value: unknown
|
|
10
|
+
}
|
|
11
|
+
export default function ParseValueSimple({
|
|
12
|
+
value
|
|
13
|
+
}: ParseValueSimpleProps): React.ReactNode {
|
|
14
|
+
const MAX_LENGTH = 16;
|
|
15
|
+
|
|
16
|
+
switch (typeof value) {
|
|
17
|
+
case 'bigint':
|
|
18
|
+
case 'number': {
|
|
19
|
+
const numStr = value.toString();
|
|
20
|
+
|
|
21
|
+
if (numStr.length > MAX_LENGTH)
|
|
22
|
+
return <ValueKeyword value={typeof value} />;
|
|
23
|
+
|
|
24
|
+
return <ValueNumber value={value} />
|
|
25
|
+
}
|
|
26
|
+
case 'boolean': return <ValueBoolean value={value} />
|
|
27
|
+
case 'function': return <ValueFunction value={value} />
|
|
28
|
+
case 'object': {
|
|
29
|
+
if (value === null)
|
|
30
|
+
return <ValueKeyword value="null" />
|
|
31
|
+
|
|
32
|
+
const className = Object.getPrototypeOf(value) !== Object.prototype ? value.constructor.name : null;
|
|
33
|
+
|
|
34
|
+
if (className === null || className.length > MAX_LENGTH)
|
|
35
|
+
return <ValueKeyword value="object" />
|
|
36
|
+
|
|
37
|
+
return className;
|
|
38
|
+
}
|
|
39
|
+
case 'string': {
|
|
40
|
+
if (value.length > MAX_LENGTH)
|
|
41
|
+
return <ValueString value="string" noEncase />
|
|
42
|
+
|
|
43
|
+
return <ValueString value={value} />;
|
|
44
|
+
}
|
|
45
|
+
case 'symbol': {
|
|
46
|
+
if (!value.description || value.description.length > MAX_LENGTH)
|
|
47
|
+
return <ValueKeyword value="Symbol" />
|
|
48
|
+
|
|
49
|
+
return <ValueSymbol value={value} />
|
|
50
|
+
}
|
|
51
|
+
case 'undefined': return <ValueKeyword value="undefined" />
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import React, { useLayoutEffect, useMemo, useState } from "react";
|
|
2
|
+
import useDebugger from "../DebuggerContext";
|
|
3
|
+
import { Char_Bracket, Char_Comma, Chevron_Toggle } from "../DebuggerSymbols";
|
|
4
|
+
import ParseValueSimple from "./DebugParserSimple";
|
|
5
|
+
import ParseValue from "./DebugParser";
|
|
6
|
+
|
|
7
|
+
interface ValueArrayProps {
|
|
8
|
+
value: unknown[],
|
|
9
|
+
path: string[],
|
|
10
|
+
defaultExpanded?: boolean
|
|
11
|
+
}
|
|
12
|
+
export default function ValueArray({
|
|
13
|
+
value,
|
|
14
|
+
path,
|
|
15
|
+
defaultExpanded = false
|
|
16
|
+
}: ValueArrayProps) {
|
|
17
|
+
const debug = useDebugger();
|
|
18
|
+
|
|
19
|
+
const [expanded, setExpanded] = useState(defaultExpanded);
|
|
20
|
+
|
|
21
|
+
const children = useMemo(() => {
|
|
22
|
+
const children: React.ReactNode[] = [];
|
|
23
|
+
|
|
24
|
+
let ix = 0;
|
|
25
|
+
|
|
26
|
+
while (ix < value.length) {
|
|
27
|
+
const nextTarget = Math.min(ix + debug.options.compactArrays, value.length);
|
|
28
|
+
|
|
29
|
+
children.push(
|
|
30
|
+
<li key={ix}>
|
|
31
|
+
{
|
|
32
|
+
(() => {
|
|
33
|
+
const children: React.ReactNode[] = [];
|
|
34
|
+
|
|
35
|
+
for (;ix < nextTarget; ix++) {
|
|
36
|
+
children.push(
|
|
37
|
+
<CompactArrayItem
|
|
38
|
+
key={ix}
|
|
39
|
+
value={value[ix]}
|
|
40
|
+
path={[...path, `${ix}`]}
|
|
41
|
+
isLast={ix < value.length - 1}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return children;
|
|
47
|
+
})()
|
|
48
|
+
}
|
|
49
|
+
</li>
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
ix = nextTarget;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return children;
|
|
56
|
+
}, [debug.options.compactArrays, value]);
|
|
57
|
+
|
|
58
|
+
const collapsedPreview = useMemo(() => {
|
|
59
|
+
const children: React.ReactNode[] = [];
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < Math.min(value.length, 6); i++) {
|
|
62
|
+
children.push(
|
|
63
|
+
<CompactArrayItem
|
|
64
|
+
key={i}
|
|
65
|
+
value={value[i]}
|
|
66
|
+
path={path}
|
|
67
|
+
isLast={i < value.length - 1}
|
|
68
|
+
simple
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (value.length > 6)
|
|
74
|
+
children.push(<span key={'rest'} className="text-zinc-500">...</span>);
|
|
75
|
+
|
|
76
|
+
return children;
|
|
77
|
+
}, [value]);
|
|
78
|
+
|
|
79
|
+
useLayoutEffect(() => {
|
|
80
|
+
debug.event.expand(path, expanded);
|
|
81
|
+
}, [expanded]);
|
|
82
|
+
|
|
83
|
+
const handleExpand = (state: boolean) => {
|
|
84
|
+
setExpanded(state);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<>
|
|
89
|
+
<Chevron_Toggle expanded={expanded} onToggle={handleExpand} />
|
|
90
|
+
|
|
91
|
+
<span className="text-white" >{`(${value.length}) `}</span>
|
|
92
|
+
{
|
|
93
|
+
expanded ? (
|
|
94
|
+
<>
|
|
95
|
+
<Char_Bracket text="[" />
|
|
96
|
+
|
|
97
|
+
<ul className="pl-4 ml-1 border-l border-l-[#4b4b4b]">
|
|
98
|
+
{children}
|
|
99
|
+
</ul>
|
|
100
|
+
|
|
101
|
+
<Char_Bracket text="]" />
|
|
102
|
+
</>
|
|
103
|
+
) : (
|
|
104
|
+
<div
|
|
105
|
+
className="inline-block cursor-pointer"
|
|
106
|
+
onClick={() => setExpanded(true)}
|
|
107
|
+
>
|
|
108
|
+
<Char_Bracket text="[" />
|
|
109
|
+
{/* <span className="text-zinc-500">...</span> */}
|
|
110
|
+
{collapsedPreview}
|
|
111
|
+
<Char_Bracket text="]" />
|
|
112
|
+
</div>
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
</>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
interface CompactArrayItemProps {
|
|
120
|
+
value: unknown,
|
|
121
|
+
isLast: boolean,
|
|
122
|
+
path: string[],
|
|
123
|
+
simple?: boolean
|
|
124
|
+
}
|
|
125
|
+
function CompactArrayItem({
|
|
126
|
+
value,
|
|
127
|
+
isLast,
|
|
128
|
+
path,
|
|
129
|
+
simple
|
|
130
|
+
}: CompactArrayItemProps)
|
|
131
|
+
{
|
|
132
|
+
return (
|
|
133
|
+
<>
|
|
134
|
+
{
|
|
135
|
+
!simple
|
|
136
|
+
? <ParseValue value={value} path={path} />
|
|
137
|
+
: <ParseValueSimple value={value} />
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
{isLast && (<Char_Comma />)}
|
|
141
|
+
</>
|
|
142
|
+
)
|
|
143
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface ValueFunctionProps {
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
3
|
+
value: Function
|
|
4
|
+
}
|
|
5
|
+
export default function ValueFunction({
|
|
6
|
+
value
|
|
7
|
+
}: ValueFunctionProps) {
|
|
8
|
+
const argsMatch = value.toString().match(/^[^(]*\(\s*([^)]*)\)/);
|
|
9
|
+
let args: string = '';
|
|
10
|
+
|
|
11
|
+
if (argsMatch && argsMatch.length > 1) {
|
|
12
|
+
args = argsMatch[1]!;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<>
|
|
17
|
+
<span className="text-[#f2824a]">
|
|
18
|
+
{'ƒ '}
|
|
19
|
+
</span>
|
|
20
|
+
<span>
|
|
21
|
+
{`${value.name}(${args})`}
|
|
22
|
+
</span>
|
|
23
|
+
</>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import React, { useLayoutEffect, useMemo, useState } from "react";
|
|
2
|
+
import useDebugger from "../DebuggerContext";
|
|
3
|
+
import { entries, keys } from "@hrnec06/util";
|
|
4
|
+
import { Char_Bracket, Char_Colon, Char_Comma, Chevron_Toggle } from "../DebuggerSymbols";
|
|
5
|
+
import ParseValue from "./DebugParser";
|
|
6
|
+
|
|
7
|
+
interface ValueObjectProps {
|
|
8
|
+
value: object,
|
|
9
|
+
path: string[],
|
|
10
|
+
defaultExpanded?: boolean
|
|
11
|
+
}
|
|
12
|
+
export default function ValueObject({
|
|
13
|
+
value,
|
|
14
|
+
path,
|
|
15
|
+
defaultExpanded = false
|
|
16
|
+
}: ValueObjectProps) {
|
|
17
|
+
const debug = useDebugger();
|
|
18
|
+
|
|
19
|
+
const [expanded, setExpanded] = useState(defaultExpanded);
|
|
20
|
+
|
|
21
|
+
const objectEntries = entries(value);
|
|
22
|
+
|
|
23
|
+
const collapsedPreview = useMemo(() => {
|
|
24
|
+
const children: React.ReactNode[] = [];
|
|
25
|
+
const keyList = keys(value);
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < Math.min(keyList.length, 6); i++) {
|
|
28
|
+
children.push(
|
|
29
|
+
<React.Fragment key={i}>
|
|
30
|
+
<ValueObjectKey text={keyList[i]!} />
|
|
31
|
+
{i < keyList.length - 1 && <Char_Comma />}
|
|
32
|
+
</React.Fragment>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (keyList.length > 6)
|
|
37
|
+
children.push(<span key={'rest'} className="text-zinc-500">...</span>);
|
|
38
|
+
|
|
39
|
+
return children;
|
|
40
|
+
}, [value]);
|
|
41
|
+
|
|
42
|
+
useLayoutEffect(() => {
|
|
43
|
+
debug.event.expand(path, expanded);
|
|
44
|
+
}, [expanded]);
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
const handleExpand = (state: boolean) => {
|
|
48
|
+
setExpanded(state);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<>
|
|
53
|
+
<Chevron_Toggle expanded={expanded} onToggle={handleExpand} />
|
|
54
|
+
|
|
55
|
+
{
|
|
56
|
+
Object.getPrototypeOf(value) !== Object.prototype && <span>({value.constructor.name}) </span>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
{
|
|
60
|
+
expanded ? (
|
|
61
|
+
<>
|
|
62
|
+
<Char_Bracket text="{" />
|
|
63
|
+
|
|
64
|
+
<ul className="pl-4 ml-1 border-l border-l-[#4b4b4b]">
|
|
65
|
+
{
|
|
66
|
+
objectEntries.map(([key, value], ix) => {
|
|
67
|
+
return (
|
|
68
|
+
<li key={ix}>
|
|
69
|
+
<ValueObjectKey text={key} />
|
|
70
|
+
<Char_Colon />
|
|
71
|
+
|
|
72
|
+
<ParseValue value={value} path={[...path, `${key}`]} />
|
|
73
|
+
|
|
74
|
+
{ix < objectEntries.length - 1 && (
|
|
75
|
+
<Char_Comma />
|
|
76
|
+
)}
|
|
77
|
+
</li>
|
|
78
|
+
);
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
</ul>
|
|
82
|
+
|
|
83
|
+
<Char_Bracket text="}" />
|
|
84
|
+
</>
|
|
85
|
+
) : (
|
|
86
|
+
<div
|
|
87
|
+
className="inline-block cursor-pointer"
|
|
88
|
+
onClick={() => setExpanded(true)}
|
|
89
|
+
>
|
|
90
|
+
<Char_Bracket text="{" />
|
|
91
|
+
{' '}
|
|
92
|
+
{collapsedPreview}
|
|
93
|
+
{' '}
|
|
94
|
+
<Char_Bracket text="}" />
|
|
95
|
+
</div>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
</>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
interface ValueObjectKeyProps {
|
|
103
|
+
text: string,
|
|
104
|
+
}
|
|
105
|
+
function ValueObjectKey({
|
|
106
|
+
text
|
|
107
|
+
}: ValueObjectKeyProps) {
|
|
108
|
+
return (
|
|
109
|
+
<span className="text-[#9CDCF0]">
|
|
110
|
+
{text}
|
|
111
|
+
</span>
|
|
112
|
+
)
|
|
113
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { padString } from "@hrnec06/util"
|
|
2
|
+
|
|
3
|
+
interface ValueStringProps {
|
|
4
|
+
value: string,
|
|
5
|
+
noEncase?: boolean
|
|
6
|
+
}
|
|
7
|
+
export default function ValueString({
|
|
8
|
+
value,
|
|
9
|
+
noEncase = false
|
|
10
|
+
}: ValueStringProps) {
|
|
11
|
+
return (
|
|
12
|
+
<span className="text-[#ce9178]">
|
|
13
|
+
{padString(value, noEncase ? 0 : 1, '"')}
|
|
14
|
+
</span>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Char_Bracket } from "../DebuggerSymbols"
|
|
2
|
+
import ValueKeyword from "./ValueKeyword"
|
|
3
|
+
|
|
4
|
+
interface ValueSymbolProps {
|
|
5
|
+
value: symbol
|
|
6
|
+
}
|
|
7
|
+
export default function ValueSymbol({
|
|
8
|
+
value
|
|
9
|
+
}: ValueSymbolProps) {
|
|
10
|
+
return (
|
|
11
|
+
<>
|
|
12
|
+
<ValueKeyword value="Symbol" />
|
|
13
|
+
<Char_Bracket text="(" />
|
|
14
|
+
<span>
|
|
15
|
+
{value.description}
|
|
16
|
+
</span>
|
|
17
|
+
<Char_Bracket text=")" />
|
|
18
|
+
</>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
interface KeyListenerOptions {
|
|
4
|
+
ctrl?: boolean,
|
|
5
|
+
shift?: boolean,
|
|
6
|
+
alt?: boolean
|
|
7
|
+
}
|
|
8
|
+
export default function useKeyListener(key: string, options?: KeyListenerOptions) {
|
|
9
|
+
const [pressing, setPressing] = useState(false);
|
|
10
|
+
|
|
11
|
+
const keyMatching = (e: KeyboardEvent, strict: boolean): boolean => {
|
|
12
|
+
if (strict && options?.ctrl && !e.ctrlKey)
|
|
13
|
+
return false;
|
|
14
|
+
|
|
15
|
+
if (strict && options?.shift && !e.shiftKey)
|
|
16
|
+
return false;
|
|
17
|
+
|
|
18
|
+
if (strict && options?.alt && !e.altKey)
|
|
19
|
+
return false;
|
|
20
|
+
|
|
21
|
+
return e.code == key;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const downListener = (e: KeyboardEvent) => {
|
|
26
|
+
if (!keyMatching(e, true)) return;
|
|
27
|
+
|
|
28
|
+
setPressing(true);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const upListener = (e: KeyboardEvent) => {
|
|
32
|
+
if (!keyMatching(e, false)) return;
|
|
33
|
+
|
|
34
|
+
setPressing(false);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
window.addEventListener('keydown', downListener);
|
|
38
|
+
window.addEventListener('keyup', upListener);
|
|
39
|
+
|
|
40
|
+
return () => {
|
|
41
|
+
window.removeEventListener('keydown', downListener);
|
|
42
|
+
window.removeEventListener('keyup', upListener);
|
|
43
|
+
}
|
|
44
|
+
}, []);
|
|
45
|
+
|
|
46
|
+
return pressing;
|
|
47
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DependencyList, useEffect } from "react"
|
|
2
|
+
|
|
3
|
+
export default function useListener<E extends keyof GlobalEventHandlersEventMap>(element: Node, event: E, listener: (event: GlobalEventHandlersEventMap[E]) => void, deps?: DependencyList) {
|
|
4
|
+
useEffect(() => {
|
|
5
|
+
element.addEventListener(event, listener as EventListenerOrEventListenerObject);
|
|
6
|
+
|
|
7
|
+
return () => {
|
|
8
|
+
element.removeEventListener(event, listener as EventListenerOrEventListenerObject);
|
|
9
|
+
}
|
|
10
|
+
}, deps);
|
|
11
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ReactUtils } from "@hrnec06/util";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
|
|
4
|
+
export default function useSignal<T>(value: T): Signal<T>
|
|
5
|
+
{
|
|
6
|
+
const [_value, _setValue] = useState(value);
|
|
7
|
+
|
|
8
|
+
const signal = new Signal(_value, _setValue);
|
|
9
|
+
|
|
10
|
+
return signal;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class Signal<T>
|
|
14
|
+
{
|
|
15
|
+
constructor(
|
|
16
|
+
private _value: T,
|
|
17
|
+
private setState: ReactUtils.SetState<T>
|
|
18
|
+
)
|
|
19
|
+
{
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public set value(value: T)
|
|
23
|
+
{
|
|
24
|
+
this.setState(value);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public get value(): T
|
|
28
|
+
{
|
|
29
|
+
return this._value;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
|
|
3
|
+
export default function useUpdateEffect(callback: React.EffectCallback, value: unknown[]) {
|
|
4
|
+
const isFirstRun = useRef(true);
|
|
5
|
+
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
if (isFirstRun.current) {
|
|
8
|
+
isFirstRun.current = false;
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return callback();
|
|
13
|
+
}, value);
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useRef } from "react";
|
|
2
|
+
import useUpdateEffect from "./useUpdateEffect";
|
|
3
|
+
|
|
4
|
+
export default function useUpdatedRef<V>(value: V): React.RefObject<V> {
|
|
5
|
+
const ref = useRef(value);
|
|
6
|
+
|
|
7
|
+
useUpdateEffect(() => {
|
|
8
|
+
ref.current = value;
|
|
9
|
+
}, [value]);
|
|
10
|
+
|
|
11
|
+
return ref;
|
|
12
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Vector2 } from "@hrnec06/util";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
|
|
4
|
+
export default function useWindowSize(): Vector2 {
|
|
5
|
+
const [dimensions, setDimensions] = useState<Vector2>([1920, 1080]);
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
setDimensions([window.innerWidth, window.innerHeight]);
|
|
9
|
+
|
|
10
|
+
const listener = () => {
|
|
11
|
+
setDimensions([window.innerWidth, window.innerHeight]);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
window.addEventListener('resize', listener);
|
|
15
|
+
|
|
16
|
+
return () => {
|
|
17
|
+
window.removeEventListener('resize', listener);
|
|
18
|
+
}
|
|
19
|
+
}, []);
|
|
20
|
+
|
|
21
|
+
return dimensions;
|
|
22
|
+
}
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import useKeyListener from "./hooks/useKeyListener";
|
|
2
|
+
import useListener from "./hooks/useListener";
|
|
3
|
+
import useUpdatedRef from "./hooks/useUpdatedRef";
|
|
4
|
+
import useUpdateEffect from "./hooks/useUpdateEffect";
|
|
5
|
+
import useWindowSize from "./hooks/useWindowSize";
|
|
6
|
+
import useSignal from "./hooks/useSignal";
|
|
7
|
+
import Debugger from './debugger/Debugger';
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
useKeyListener,
|
|
11
|
+
useListener,
|
|
12
|
+
useUpdatedRef,
|
|
13
|
+
useUpdateEffect,
|
|
14
|
+
useWindowSize,
|
|
15
|
+
useSignal,
|
|
16
|
+
Debugger
|
|
17
|
+
};
|
package/dist/index.d.mts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { DependencyList } from 'react';
|
|
2
|
-
import { Vector2, ReactUtils } from '@hrnec06/util';
|
|
3
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
|
-
|
|
5
|
-
interface KeyListenerOptions {
|
|
6
|
-
ctrl?: boolean;
|
|
7
|
-
shift?: boolean;
|
|
8
|
-
alt?: boolean;
|
|
9
|
-
}
|
|
10
|
-
declare function useKeyListener(key: string, options?: KeyListenerOptions): boolean;
|
|
11
|
-
|
|
12
|
-
declare function useListener<E extends keyof GlobalEventHandlersEventMap>(element: Node, event: E, listener: (event: GlobalEventHandlersEventMap[E]) => void, deps?: DependencyList): void;
|
|
13
|
-
|
|
14
|
-
declare function useUpdatedRef<V>(value: V): React.RefObject<V>;
|
|
15
|
-
|
|
16
|
-
declare function useUpdateEffect(callback: React.EffectCallback, value: unknown[]): void;
|
|
17
|
-
|
|
18
|
-
declare function useWindowSize(): Vector2;
|
|
19
|
-
|
|
20
|
-
declare function useSignal<T>(value: T): Signal<T>;
|
|
21
|
-
declare class Signal<T> {
|
|
22
|
-
private _value;
|
|
23
|
-
private setState;
|
|
24
|
-
constructor(_value: T, setState: ReactUtils.SetState<T>);
|
|
25
|
-
set value(value: T);
|
|
26
|
-
get value(): T;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface DebugProps {
|
|
30
|
-
value: unknown;
|
|
31
|
-
openPaths?: string[];
|
|
32
|
-
excludePaths?: string[];
|
|
33
|
-
size?: 'normal' | 'big' | 'tiny';
|
|
34
|
-
compactArrays?: number;
|
|
35
|
-
autoHeight?: boolean;
|
|
36
|
-
openRoot?: boolean;
|
|
37
|
-
}
|
|
38
|
-
declare function Debug({ value, openPaths, excludePaths, size, compactArrays, autoHeight, openRoot }: DebugProps): react_jsx_runtime.JSX.Element;
|
|
39
|
-
|
|
40
|
-
export { Debug as Debugger, useKeyListener, useListener, useSignal, useUpdateEffect, useUpdatedRef, useWindowSize };
|