@hrnec06/react_utils 1.5.1 → 1.7.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/package.json +1 -1
- package/src/components/ContextMenu/ContextMenu.tsx +235 -0
- package/src/components/ContextMenu/ContextMenu.types.ts +17 -0
- package/src/components/ContextMenu/ContextMenuCtx.tsx +33 -0
- package/src/components/ContextMenu/ContextMenuItem.tsx +147 -0
- package/src/components/ContextMenu/ContextMenuRoot.tsx +28 -0
- package/src/components/ContextMenu/ContextMenuSection.tsx +28 -0
- package/src/components/Debugger/Debugger.tsx +86 -84
- package/src/components/Debugger/DebuggerTerminal.tsx +18 -49
- package/src/components/Debugger/parser/DebugParser.tsx +121 -14
- package/src/components/Debugger/parser/DebugTerminal.tsx +24 -7
- package/src/components/Debugger/parser/ValueArray.tsx +22 -7
- package/src/components/Debugger/parser/ValueBoolean.tsx +15 -4
- package/src/components/Debugger/parser/ValueConstant.tsx +21 -0
- package/src/components/Debugger/parser/ValueFunction.tsx +17 -5
- package/src/components/Debugger/parser/ValueNumber.tsx +14 -4
- package/src/components/Debugger/parser/ValueObject.tsx +61 -17
- package/src/components/Debugger/parser/ValueString.tsx +13 -4
- package/src/components/ResizeableBox/ResizeableBox.tsx +1 -1
- package/src/hooks/useDebounce.ts +26 -0
- package/src/hooks/useDefaultValue.ts +8 -0
- package/src/hooks/useEfficientRef.ts +3 -2
- package/src/hooks/useEvent.ts +15 -0
- package/src/hooks/useLatestRef.ts +12 -0
- package/src/hooks/useLocalStorage.ts +134 -0
- package/src/hooks/useSyncRef.ts +17 -0
- package/src/hooks/useTransition.ts +2 -1
- package/src/index.ts +16 -5
- package/src/lib/errors/ContextError.ts +11 -0
- package/src/hooks/useEfficientState.ts +0 -9
- package/src/hooks/useUpdatedRef.ts +0 -12
|
@@ -1,10 +1,18 @@
|
|
|
1
|
+
import { forwardRef, useImperativeHandle } from "react";
|
|
2
|
+
import { ParseValueRef } from "./DebugParser";
|
|
3
|
+
|
|
1
4
|
interface ValueFunctionProps {
|
|
2
5
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
3
6
|
value: Function
|
|
4
7
|
}
|
|
5
|
-
|
|
8
|
+
const ValueFunction = forwardRef<ParseValueRef, ValueFunctionProps>(({
|
|
6
9
|
value
|
|
7
|
-
}
|
|
10
|
+
}, ref) => {
|
|
11
|
+
useImperativeHandle(ref, () => ({
|
|
12
|
+
name: "Function",
|
|
13
|
+
copyValue: value.toString()
|
|
14
|
+
}), [value]);
|
|
15
|
+
|
|
8
16
|
const argsMatch = value.toString().match(/^[^(]*\(\s*([^)]*)\)/);
|
|
9
17
|
let args: string = '';
|
|
10
18
|
|
|
@@ -12,14 +20,18 @@ export default function ValueFunction({
|
|
|
12
20
|
args = argsMatch[1]!;
|
|
13
21
|
}
|
|
14
22
|
|
|
23
|
+
const displayValue = `${value.name}(${args})`;
|
|
24
|
+
|
|
15
25
|
return (
|
|
16
26
|
<>
|
|
17
27
|
<span className="text-[#f2824a]">
|
|
18
28
|
{'ƒ '}
|
|
19
29
|
</span>
|
|
20
30
|
<span className="text-white">
|
|
21
|
-
{
|
|
31
|
+
{displayValue}
|
|
22
32
|
</span>
|
|
23
33
|
</>
|
|
24
|
-
)
|
|
25
|
-
}
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
export default ValueFunction;
|
|
@@ -1,12 +1,22 @@
|
|
|
1
|
+
import { forwardRef, useImperativeHandle } from "react"
|
|
2
|
+
import { ParseValueRef } from "./DebugParser";
|
|
3
|
+
|
|
1
4
|
interface ValueNumberProps {
|
|
2
5
|
value: number | bigint | string
|
|
3
6
|
}
|
|
4
|
-
|
|
7
|
+
const ValueNumber = forwardRef<ParseValueRef, ValueNumberProps>(({
|
|
5
8
|
value
|
|
6
|
-
}
|
|
9
|
+
}, ref) => {
|
|
10
|
+
useImperativeHandle(ref, () => ({
|
|
11
|
+
name: "Number",
|
|
12
|
+
copyValue: value.toString()
|
|
13
|
+
}), [value]);
|
|
14
|
+
|
|
7
15
|
return (
|
|
8
16
|
<span className="text-[#a7ce9b]">
|
|
9
17
|
{value}
|
|
10
18
|
</span>
|
|
11
|
-
)
|
|
12
|
-
}
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export default ValueNumber;
|
|
@@ -1,25 +1,41 @@
|
|
|
1
|
-
import React, { useLayoutEffect, useMemo, useState } from "react";
|
|
1
|
+
import React, { forwardRef, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import useDebugger from "../DebuggerContext";
|
|
3
|
-
import { entries, keys } from "@hrnec06/util";
|
|
3
|
+
import { entries, keys, Nullable } from "@hrnec06/util";
|
|
4
4
|
import { Char_Bracket, Char_Colon, Char_Comma, Chevron_Toggle } from "../DebuggerSymbols";
|
|
5
|
-
import ParseValue from "./DebugParser";
|
|
5
|
+
import ParseValue, { DebugCTXMProvider, ParseValueRef } from "./DebugParser";
|
|
6
|
+
import useSyncRef from "../../../hooks/useSyncRef";
|
|
7
|
+
import { useCTXMListener } from "../../ContextMenu/ContextMenuCtx";
|
|
6
8
|
|
|
7
9
|
interface ValueObjectProps {
|
|
8
10
|
value: object,
|
|
9
11
|
path: string[],
|
|
10
12
|
defaultExpanded?: boolean
|
|
11
13
|
}
|
|
12
|
-
|
|
14
|
+
const ValueObject = forwardRef<ParseValueRef, ValueObjectProps>(({
|
|
13
15
|
value,
|
|
14
16
|
path,
|
|
15
17
|
defaultExpanded = false
|
|
16
|
-
}
|
|
18
|
+
}, ref) => {
|
|
17
19
|
const debug = useDebugger();
|
|
18
20
|
|
|
19
21
|
const [expanded, setExpanded] = useState(defaultExpanded);
|
|
20
22
|
|
|
21
23
|
const objectEntries = entries(value);
|
|
22
24
|
|
|
25
|
+
useImperativeHandle(ref, () => ({
|
|
26
|
+
name: `Object {${objectEntries.length}}`,
|
|
27
|
+
copyValue: JSON.stringify(value),
|
|
28
|
+
menu: [
|
|
29
|
+
{
|
|
30
|
+
id: "open-toggle",
|
|
31
|
+
label: expanded ? "Collapse" : "Expand",
|
|
32
|
+
onClick: () => {
|
|
33
|
+
setExpanded(!expanded);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}), [value, expanded]);
|
|
38
|
+
|
|
23
39
|
const collapsedPreview = useMemo(() => {
|
|
24
40
|
const children: React.ReactNode[] = [];
|
|
25
41
|
const keyList = keys(value);
|
|
@@ -48,6 +64,8 @@ export default function ValueObject({
|
|
|
48
64
|
setExpanded(state);
|
|
49
65
|
}
|
|
50
66
|
|
|
67
|
+
const ctxmListener = useCTXMListener();
|
|
68
|
+
|
|
51
69
|
return (
|
|
52
70
|
<>
|
|
53
71
|
<Chevron_Toggle expanded={expanded} onToggle={handleExpand} />
|
|
@@ -65,16 +83,13 @@ export default function ValueObject({
|
|
|
65
83
|
{
|
|
66
84
|
objectEntries.map(([key, value], ix) => {
|
|
67
85
|
return (
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
<Char_Comma />
|
|
76
|
-
)}
|
|
77
|
-
</li>
|
|
86
|
+
<ValueObjectEntry
|
|
87
|
+
key={ix}
|
|
88
|
+
entryKey={key}
|
|
89
|
+
value={value}
|
|
90
|
+
path={path}
|
|
91
|
+
isLast={ix === objectEntries.length - 1}
|
|
92
|
+
/>
|
|
78
93
|
);
|
|
79
94
|
})
|
|
80
95
|
}
|
|
@@ -97,7 +112,7 @@ export default function ValueObject({
|
|
|
97
112
|
}
|
|
98
113
|
</>
|
|
99
114
|
);
|
|
100
|
-
}
|
|
115
|
+
});
|
|
101
116
|
|
|
102
117
|
interface ValueObjectKeyProps {
|
|
103
118
|
text: string,
|
|
@@ -110,4 +125,33 @@ function ValueObjectKey({
|
|
|
110
125
|
{text}
|
|
111
126
|
</span>
|
|
112
127
|
)
|
|
113
|
-
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
interface ValueObjectEntryProps {
|
|
131
|
+
entryKey: string,
|
|
132
|
+
value: unknown,
|
|
133
|
+
path: string[],
|
|
134
|
+
isLast: boolean
|
|
135
|
+
}
|
|
136
|
+
function ValueObjectEntry({
|
|
137
|
+
entryKey: key,
|
|
138
|
+
value,
|
|
139
|
+
path,
|
|
140
|
+
isLast
|
|
141
|
+
}: ValueObjectEntryProps)
|
|
142
|
+
{
|
|
143
|
+
return (
|
|
144
|
+
<li>
|
|
145
|
+
<ParseValue value={value} path={[...path, `${key}`]}>
|
|
146
|
+
<ValueObjectKey text={key} />
|
|
147
|
+
<Char_Colon />
|
|
148
|
+
</ParseValue>
|
|
149
|
+
|
|
150
|
+
{!isLast && (
|
|
151
|
+
<Char_Comma />
|
|
152
|
+
)}
|
|
153
|
+
</li>
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export default ValueObject;
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import { padString } from "@hrnec06/util"
|
|
2
|
+
import { forwardRef, useImperativeHandle } from "react"
|
|
3
|
+
import { ParseValueRef } from "./DebugParser";
|
|
2
4
|
|
|
3
5
|
interface ValueStringProps {
|
|
4
6
|
value: string,
|
|
5
7
|
noEncase?: boolean
|
|
6
8
|
}
|
|
7
|
-
|
|
9
|
+
const ValueString = forwardRef<ParseValueRef, ValueStringProps>(({
|
|
8
10
|
value,
|
|
9
11
|
noEncase = false
|
|
10
|
-
}
|
|
12
|
+
}, ref) => {
|
|
13
|
+
useImperativeHandle(ref, () => ({
|
|
14
|
+
name: "String",
|
|
15
|
+
copyValue: value
|
|
16
|
+
}), [value]);
|
|
17
|
+
|
|
11
18
|
return (
|
|
12
19
|
<span className="text-[#ce9178]">
|
|
13
20
|
{padString(value, noEncase ? 0 : 1, '"')}
|
|
14
21
|
</span>
|
|
15
|
-
)
|
|
16
|
-
}
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export default ValueString;
|
|
@@ -3,7 +3,7 @@ import clsx from "clsx";
|
|
|
3
3
|
import { useEffect } from "react";
|
|
4
4
|
import DragAreas from "./DragAreas";
|
|
5
5
|
import useSignal from "../../hooks/useSignal";
|
|
6
|
-
import useUpdatedRef from "../../hooks/
|
|
6
|
+
import useUpdatedRef from "../../hooks/useLatestRef";
|
|
7
7
|
import useListener from "../../hooks/useListener";
|
|
8
8
|
import { ResizeableBoxContext } from "./ResizeableBoxContext";
|
|
9
9
|
import RB from "./ResizeableBox.types";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useCallback, useLayoutEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
export default function useDebounce<T>(value: T, delay: number, updateOnUnmount: boolean = false): T
|
|
4
|
+
{
|
|
5
|
+
const [debounced, setValue] = useState(value);
|
|
6
|
+
|
|
7
|
+
const update = useCallback((value: T) => setValue(value), []);
|
|
8
|
+
|
|
9
|
+
useLayoutEffect(() => {
|
|
10
|
+
let updated = false;
|
|
11
|
+
|
|
12
|
+
const t = setTimeout(() => {
|
|
13
|
+
update(value);
|
|
14
|
+
updated = true;
|
|
15
|
+
}, delay);
|
|
16
|
+
|
|
17
|
+
return () => {
|
|
18
|
+
clearTimeout(t);
|
|
19
|
+
|
|
20
|
+
if (!updated && updateOnUnmount)
|
|
21
|
+
update(value);
|
|
22
|
+
}
|
|
23
|
+
}, [value]);
|
|
24
|
+
|
|
25
|
+
return debounced;
|
|
26
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { useMemo, useRef } from "react";
|
|
2
|
+
import useDefaultValue from "./useDefaultValue";
|
|
2
3
|
|
|
3
4
|
export default function useEfficientRef<T>(callback: () => T): React.RefObject<T>
|
|
4
5
|
{
|
|
5
|
-
const
|
|
6
|
+
const value = useDefaultValue(callback);
|
|
6
7
|
|
|
7
|
-
return useRef<T>(
|
|
8
|
+
return useRef<T>(value);
|
|
8
9
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
import useLatestRef from "./useLatestRef";
|
|
3
|
+
|
|
4
|
+
export default function useEvent<
|
|
5
|
+
F extends (...args: any[]) => any,
|
|
6
|
+
P extends any[] = Parameters<F>,
|
|
7
|
+
R = ReturnType<F>,
|
|
8
|
+
> (
|
|
9
|
+
cb: (...args: P) => R
|
|
10
|
+
)
|
|
11
|
+
{
|
|
12
|
+
const cache = useLatestRef(cb);
|
|
13
|
+
|
|
14
|
+
return useCallback((...args: P) => cache.current(...args), [cache]);
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef } from "react";
|
|
2
|
+
import useUpdateEffect from "./useUpdateEffect";
|
|
3
|
+
|
|
4
|
+
export default function useLatestRef<V>(value: V): React.RefObject<V> {
|
|
5
|
+
const ref = useRef(value);
|
|
6
|
+
|
|
7
|
+
useLayoutEffect(() => {
|
|
8
|
+
ref.current = value;
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
return ref;
|
|
12
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { disposables, Listenable, Nullable, Optional, ReactUtils } from "@hrnec06/util";
|
|
2
|
+
import useSignal, { Signal } from "./useSignal";
|
|
3
|
+
import useUpdateEffect from "./useUpdateEffect";
|
|
4
|
+
import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
5
|
+
import useDisposables from "./useDisposables";
|
|
6
|
+
import useDefaultValue from "./useDefaultValue";
|
|
7
|
+
import z from "zod";
|
|
8
|
+
|
|
9
|
+
type StateValue<T> = T | StateCallback<T>;
|
|
10
|
+
type StateCallback<T> = (value: T) => T;
|
|
11
|
+
|
|
12
|
+
function isStateCallback<T>(v: StateValue<T>): v is StateCallback<T> {
|
|
13
|
+
return typeof v === "function";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function encodeValue(value: unknown): Optional<string>
|
|
17
|
+
{
|
|
18
|
+
if (value === undefined)
|
|
19
|
+
return undefined;
|
|
20
|
+
|
|
21
|
+
try
|
|
22
|
+
{
|
|
23
|
+
const encoded = JSON.stringify(value);
|
|
24
|
+
|
|
25
|
+
return encoded;
|
|
26
|
+
}
|
|
27
|
+
catch (error)
|
|
28
|
+
{
|
|
29
|
+
console.error(error);
|
|
30
|
+
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function decodeValue(value: Nullable<string>): unknown
|
|
36
|
+
{
|
|
37
|
+
if (value === null)
|
|
38
|
+
return undefined;
|
|
39
|
+
|
|
40
|
+
try
|
|
41
|
+
{
|
|
42
|
+
const decoded = JSON.parse(value);
|
|
43
|
+
|
|
44
|
+
return decoded;
|
|
45
|
+
}
|
|
46
|
+
catch (error)
|
|
47
|
+
{
|
|
48
|
+
console.error(error);
|
|
49
|
+
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class StorageEventEmitter extends Listenable<{
|
|
55
|
+
storage: void
|
|
56
|
+
}> {
|
|
57
|
+
constructor
|
|
58
|
+
(
|
|
59
|
+
private readonly key: string
|
|
60
|
+
)
|
|
61
|
+
{
|
|
62
|
+
super();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public setLocalStorage = (value: string) => {
|
|
66
|
+
localStorage.setItem(this.key, value);
|
|
67
|
+
|
|
68
|
+
this.triggerListener("storage");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public removeLocalStorage = () => {
|
|
72
|
+
localStorage.removeItem(this.key);
|
|
73
|
+
|
|
74
|
+
this.triggerListener("storage");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public getLocalStorage = () => {
|
|
78
|
+
return localStorage.getItem(this.key);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public subscribe = (onStoreChange: () => void) => {
|
|
82
|
+
const id = this.on("storage", onStoreChange);
|
|
83
|
+
|
|
84
|
+
return () => {
|
|
85
|
+
this.off("storage", id);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export default function useLocalStorage<T>(key: string, defaultValue: T, schema?: z.ZodType): ReactUtils.State<T>
|
|
91
|
+
{
|
|
92
|
+
const storageManager = useMemo(() => new StorageEventEmitter(key), [key]);
|
|
93
|
+
const [currentValue, setCurrentValue] = useState(defaultValue);
|
|
94
|
+
|
|
95
|
+
const store = useSyncExternalStore(
|
|
96
|
+
storageManager.subscribe,
|
|
97
|
+
storageManager.getLocalStorage,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
const decoded = decodeValue(store);
|
|
102
|
+
|
|
103
|
+
if (decoded === undefined || ((schema && !schema.safeParse(decoded).success) || (typeof decoded !== typeof defaultValue)))
|
|
104
|
+
{
|
|
105
|
+
storageManager.removeLocalStorage();
|
|
106
|
+
|
|
107
|
+
setCurrentValue(defaultValue);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
setCurrentValue(decoded as T);
|
|
112
|
+
}, [store]);
|
|
113
|
+
|
|
114
|
+
const setState = useCallback((value: StateValue<T>) => {
|
|
115
|
+
setCurrentValue(prevCurrentValue => {
|
|
116
|
+
const newValue = isStateCallback(value) ? value(prevCurrentValue) : value;
|
|
117
|
+
|
|
118
|
+
const encoded = encodeValue(newValue);
|
|
119
|
+
|
|
120
|
+
if (encoded === undefined)
|
|
121
|
+
{
|
|
122
|
+
storageManager.removeLocalStorage();
|
|
123
|
+
}
|
|
124
|
+
else
|
|
125
|
+
{
|
|
126
|
+
storageManager.setLocalStorage(encoded);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return newValue;
|
|
130
|
+
});
|
|
131
|
+
}, [key, currentValue]);
|
|
132
|
+
|
|
133
|
+
return [currentValue, setState];
|
|
134
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Nullable } from '@hrnec06/util'
|
|
2
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'
|
|
3
|
+
import useEvent from './useEvent';
|
|
4
|
+
|
|
5
|
+
export default function useSyncRef<T>(
|
|
6
|
+
ref: React.RefObject<T>,
|
|
7
|
+
state: (value: T) => void
|
|
8
|
+
)
|
|
9
|
+
{
|
|
10
|
+
const syncRefs = useEvent((value: T) => {
|
|
11
|
+
ref.current = value;
|
|
12
|
+
|
|
13
|
+
state(value);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
return syncRefs;
|
|
17
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { disposables, mapRecord, Nullable } from "@hrnec06/util";
|
|
2
|
-
import { useLayoutEffect, useRef, useState } from "react";
|
|
2
|
+
import { useEffect, useEffectEvent, useLayoutEffect, useRef, useState } from "react";
|
|
3
3
|
import useFlags from "./useFlags";
|
|
4
4
|
import useDisposables from "./useDisposables";
|
|
5
5
|
|
|
@@ -235,6 +235,7 @@ function prepareTransition(
|
|
|
235
235
|
if (inFlight?.current)
|
|
236
236
|
{
|
|
237
237
|
prepare();
|
|
238
|
+
|
|
238
239
|
return;
|
|
239
240
|
}
|
|
240
241
|
|
package/src/index.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
+
import useDefaultValue from "./hooks/useDefaultValue";
|
|
2
|
+
import useDisposables from "./hooks/useDisposables";
|
|
1
3
|
import useKeyListener from "./hooks/useKeyListener";
|
|
2
4
|
import useListener from "./hooks/useListener";
|
|
3
|
-
import useUpdatedRef from "./hooks/useUpdatedRef";
|
|
4
5
|
import useUpdateEffect from "./hooks/useUpdateEffect";
|
|
5
6
|
import useWindowSize from "./hooks/useWindowSize";
|
|
6
7
|
import useEfficientRef from "./hooks/useEfficientRef";
|
|
7
|
-
import useEfficientState from "./hooks/useEfficientState";
|
|
8
8
|
import useUUID from "./hooks/useUUID";
|
|
9
9
|
import useFlags from "./hooks/useFlags";
|
|
10
|
-
import useDisposables from "./hooks/useDisposables";
|
|
11
10
|
import useNamespacedId from "./hooks/useNamespacedId";
|
|
12
11
|
import useTransition from "./hooks/useTransition";
|
|
12
|
+
import useLocalStorage from "./hooks/useLocalStorage";
|
|
13
13
|
|
|
14
14
|
import useSignal, { Signal } from "./hooks/useSignal";
|
|
15
15
|
import useLazySignal, { LazySignal } from "./hooks/useLazySignal";
|
|
@@ -19,20 +19,30 @@ import * as Debugger from './components/Debugger/Debugger';
|
|
|
19
19
|
import ResizeableBox from "./components/ResizeableBox/ResizeableBox";
|
|
20
20
|
import Dialog from "./components/Dialog/Dialog";
|
|
21
21
|
|
|
22
|
+
import ContextMenu from "./components/ContextMenu/ContextMenu";
|
|
23
|
+
|
|
22
24
|
import * as util from './lib/utils';
|
|
25
|
+
import useDebounce from "./hooks/useDebounce";
|
|
26
|
+
import useEvent from "./hooks/useEvent";
|
|
27
|
+
import useLatestRef from "./hooks/useLatestRef";
|
|
28
|
+
import useSyncRef from "./hooks/useSyncRef";
|
|
23
29
|
|
|
24
30
|
|
|
25
31
|
export {
|
|
26
32
|
// Hooks
|
|
33
|
+
useDebounce,
|
|
34
|
+
useDefaultValue,
|
|
27
35
|
useDisposables,
|
|
28
36
|
useEfficientRef,
|
|
29
|
-
|
|
37
|
+
useEvent,
|
|
30
38
|
useFlags,
|
|
31
39
|
useKeyListener,
|
|
40
|
+
useLatestRef,
|
|
32
41
|
useListener,
|
|
42
|
+
useLocalStorage,
|
|
33
43
|
useNamespacedId,
|
|
44
|
+
useSyncRef,
|
|
34
45
|
useTransition,
|
|
35
|
-
useUpdatedRef,
|
|
36
46
|
useUpdateEffect,
|
|
37
47
|
useUUID,
|
|
38
48
|
useWindowSize,
|
|
@@ -47,6 +57,7 @@ export {
|
|
|
47
57
|
Debugger,
|
|
48
58
|
ResizeableBox,
|
|
49
59
|
Dialog,
|
|
60
|
+
ContextMenu,
|
|
50
61
|
|
|
51
62
|
// Utilities
|
|
52
63
|
util,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { capitalizeString } from '@hrnec06/util';
|
|
2
|
+
|
|
3
|
+
export default class ContextError extends Error
|
|
4
|
+
{
|
|
5
|
+
constructor(context: string)
|
|
6
|
+
{
|
|
7
|
+
const name = capitalizeString(context.toLowerCase());
|
|
8
|
+
|
|
9
|
+
super(`use${name}() may be used only within ${name}Context.Provider!`)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { ReactUtils } from "@hrnec06/util";
|
|
2
|
-
import { useMemo, useState } from "react";
|
|
3
|
-
|
|
4
|
-
export default function useEfficientState<T>(callback: () => T): [T, ReactUtils.SetState<T>]
|
|
5
|
-
{
|
|
6
|
-
const defaultValue = useMemo(() => callback(), []);
|
|
7
|
-
|
|
8
|
-
return useState<T>(defaultValue);
|
|
9
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
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
|
-
}
|