@hrnec06/react_utils 1.2.0 → 1.2.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hrnec06/react_utils",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "A debugger component for react.",
5
5
  "exports": {
6
6
  ".": "./src/index.tsx"
@@ -3,11 +3,11 @@ import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
3
3
  import {DebuggerContext} from "./DebuggerContext";
4
4
  import clsx from "clsx";
5
5
  import ResizeBorder from "./DebuggerWindowResize";
6
- import ParseValue from "./DebugParser";
7
6
  import ScrollBar from "./DebuggerScrollBar";
8
7
  import useKeyListener from "../hooks/useKeyListener";
9
8
  import useUpdateEffect from "../hooks/useUpdateEffect";
10
9
  import useUpdatedRef from "../hooks/useUpdatedRef";
10
+ import ParseValue from "./parser/DebugParser";
11
11
 
12
12
  interface DebugProps {
13
13
  value: unknown,
@@ -182,7 +182,7 @@ export default function Debug({
182
182
 
183
183
  const calculateScrollHeight = () => {
184
184
  if (!containerRef.current) return 0;
185
-
185
+
186
186
  return containerRef.current.scrollHeight - calculateContainerHeight();
187
187
  }
188
188
 
@@ -206,7 +206,11 @@ export default function Debug({
206
206
  const handleExpandChange = (path: string[], state: boolean) => {
207
207
  if (!containerRef.current) return;
208
208
 
209
- setScrollProgress(minmax((scrollProgress * scrollHeight) / calculateScrollHeight(), 0, 1));
209
+ let newScrollProgress = minmax((scrollProgress * scrollHeight) / calculateScrollHeight(), 0, 1);
210
+ if (isNaN(newScrollProgress))
211
+ newScrollProgress = 0;
212
+
213
+ setScrollProgress(newScrollProgress);
210
214
 
211
215
  updateScrollHeight();
212
216
  }
@@ -271,7 +275,7 @@ export default function Debug({
271
275
 
272
276
  <div
273
277
  onWheel={handleWheel}
274
- className="bg-[#1f1f1f] shadow-lg rounded-md border border-primary-400 w-full h-full overflow-hidden flex"
278
+ className="bg-[#1f1f1f] shadow-lg rounded-md border border-[#4b4b4b] w-full h-full overflow-hidden flex"
275
279
  >
276
280
  <div
277
281
  ref={containerRef}
@@ -85,17 +85,17 @@ export default function ScrollBar({
85
85
  }
86
86
 
87
87
  return (
88
- <div className="p-1 border-l border-l-primary-600">
88
+ <div className="p-1 border-l border-l-[#2b2b2b]">
89
89
  <div
90
90
  onMouseDown={handleWraperMouseDown}
91
91
  ref={wrapperRef}
92
- className="h-full flex-shrink-0"
92
+ className="h-full shrink-0"
93
93
  >
94
94
  {debug.scroll.isScrollable && wrapperHeight > 0 && (
95
95
  <div
96
96
  onMouseDown={handleMouseDown}
97
97
 
98
- className="bg-primary-500 hover:bg-primary-400 w-2 rounded-lg"
98
+ className="bg-[#3b3b3b] hover:bg-[#4b4b4b] w-2 rounded-lg"
99
99
  style={{
100
100
  transform: `translateY(${barTop}px)`,
101
101
  height: `${barHeight}px`
@@ -53,7 +53,7 @@ export function Chevron_Toggle({
53
53
  {
54
54
  <ChevronDown
55
55
  className={clsx(
56
- "size-4 text-primary-400 hover:text-zinc-500",
56
+ "size-4 text-[#4b4b4b] hover:text-zinc-500",
57
57
  !expanded && '-rotate-90'
58
58
  )}
59
59
  />
@@ -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 (<span className="text-white">{className}</span>);
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,10 @@
1
+ import ValueKeyword from "./ValueKeyword"
2
+
3
+ interface ValueBooleanProps {
4
+ value: boolean
5
+ }
6
+ export default function ValueBoolean({
7
+ value
8
+ }: ValueBooleanProps) {
9
+ return <ValueKeyword value={value ? 'true' : 'false'} />
10
+ }
@@ -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,12 @@
1
+ interface ValueKeywordProps {
2
+ value: string
3
+ }
4
+ export default function ValueKeyword({
5
+ value
6
+ }: ValueKeywordProps) {
7
+ return (
8
+ <span className="text-[#439ccb]">
9
+ {value}
10
+ </span>
11
+ )
12
+ }
@@ -0,0 +1,12 @@
1
+ interface ValueNumberProps {
2
+ value: number | bigint
3
+ }
4
+ export default function ValueNumber({
5
+ value
6
+ }: ValueNumberProps) {
7
+ return (
8
+ <span className="text-[#a7ce9b]">
9
+ {value}
10
+ </span>
11
+ )
12
+ }
@@ -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 className="text-white">({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
+ }
@@ -1,401 +0,0 @@
1
- import { useLayoutEffect, useMemo, useState } from "react";
2
- import useDebugger from "./DebuggerContext";
3
- import { matchPath } from "./DebuggerLogic";
4
- import { entries, keys, padString } from "@hrnec06/util";
5
- import React from "react";
6
- import { Char_Bracket, Char_Colon, Char_Comma, Chevron_Toggle } from "./DebuggerSymbols";
7
-
8
- interface ParseValueProps {
9
- value: unknown,
10
- path?: string[]
11
- }
12
- export default function ParseValue({
13
- value,
14
- path = []
15
- }: ParseValueProps) {
16
- const debug = useDebugger();
17
-
18
- switch (typeof value) {
19
- case 'string': return (<Value_String value={value} />);
20
- case 'bigint':
21
- case 'number': return (<Value_Number value={value} />);
22
- case 'boolean': return (<Value_Boolean value={value} />);
23
- case 'undefined': return (<Value_Keyword value={"undefined"} />);
24
- case 'function': return (<Value_Function value={value} />);
25
- case 'symbol': return (<Value_Symbol value={value} />)
26
- case 'object': {
27
- if (value === null)
28
- return (<Value_Keyword value={"null"} />)
29
-
30
- const isRootObject = path.length === 0;
31
-
32
- const shouldBeExpanded = (isRootObject && debug.options.openRoot) || (matchPath(path, debug.paths.open) && !matchPath(path, debug.paths.exclude));
33
-
34
- if (Array.isArray(value)) {
35
- return <Value_Array value={value} path={path} defaultExpanded={shouldBeExpanded} />
36
- }
37
-
38
- return <Value_Object value={value} path={path} defaultExpanded={shouldBeExpanded} />
39
- }
40
- }
41
- }
42
-
43
- interface Value_String_Props {
44
- value: string,
45
- noEncase?: boolean
46
- }
47
- function Value_String({
48
- value,
49
- noEncase = false
50
- }: Value_String_Props) {
51
- return (
52
- <span className="text-[#ce9178]">
53
- {padString(value, noEncase ? 0 : 1, '"')}
54
- </span>
55
- )
56
- }
57
-
58
- interface Value_Number_Props {
59
- value: number | bigint
60
- }
61
- function Value_Number({
62
- value
63
- }: Value_Number_Props) {
64
- return (
65
- <span className="text-[#a7ce9b]">
66
- {value}
67
- </span>
68
- )
69
- }
70
-
71
- interface Value_Boolean_Props {
72
- value: boolean
73
- }
74
- function Value_Boolean({
75
- value
76
- }: Value_Boolean_Props) {
77
- return <Value_Keyword value={value ? 'true' : 'false'} />
78
- }
79
-
80
- interface Value_Function_Props {
81
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
82
- value: Function
83
- }
84
- function Value_Function({
85
- value
86
- }: Value_Function_Props) {
87
- const argsMatch = value.toString().match(/^[^(]*\(\s*([^)]*)\)/);
88
- let args: string = '';
89
-
90
- if (argsMatch && argsMatch.length > 1) {
91
- args = argsMatch[1]!;
92
- }
93
-
94
- return (
95
- <>
96
- <span className="text-[#f2824a]">
97
- {'ƒ '}
98
- </span>
99
- <span>
100
- {`${value.name}(${args})`}
101
- </span>
102
- </>
103
- )
104
- }
105
-
106
- interface Value_Keyword_Props {
107
- value: string
108
- }
109
- function Value_Keyword({
110
- value
111
- }: Value_Keyword_Props) {
112
- return (
113
- <span className="text-[#439ccb]">
114
- {value}
115
- </span>
116
- )
117
- }
118
-
119
- interface Value_Object_Props {
120
- value: object,
121
- path: string[],
122
- defaultExpanded?: boolean
123
- }
124
- function Value_Object({
125
- value,
126
- path,
127
- defaultExpanded = false
128
- }: Value_Object_Props) {
129
- const debug = useDebugger();
130
-
131
- const [expanded, setExpanded] = useState(defaultExpanded);
132
-
133
- const objectEntries = entries(value);
134
-
135
- const collapsedPreview = useMemo(() => {
136
- const children: React.ReactNode[] = [];
137
- const keyList = keys(value);
138
-
139
- for (let i = 0; i < Math.min(keyList.length, 6); i++) {
140
- children.push(
141
- <React.Fragment key={i}>
142
- <Value_Object_Key text={keyList[i]!} />
143
- {i < keyList.length - 1 && <Char_Comma />}
144
- </React.Fragment>
145
- );
146
- }
147
-
148
- if (keyList.length > 6)
149
- children.push(<span key={'rest'} className="text-zinc-500">...</span>);
150
-
151
- return children;
152
- }, [value]);
153
-
154
- useLayoutEffect(() => {
155
- debug.event.expand(path, expanded);
156
- }, [expanded]);
157
-
158
-
159
- const handleExpand = (state: boolean) => {
160
- setExpanded(state);
161
- }
162
-
163
- return (
164
- <>
165
- <Chevron_Toggle expanded={expanded} onToggle={handleExpand} />
166
-
167
- {
168
- Object.getPrototypeOf(value) !== Object.prototype && <span>({value.constructor.name}) </span>
169
- }
170
-
171
- {
172
- expanded ? (
173
- <>
174
- <Char_Bracket text="{" />
175
-
176
- <ul className="pl-4 ml-1 border-l border-l-primary-400">
177
- {
178
- objectEntries.map(([key, value], ix) => {
179
- return (
180
- <li key={ix}>
181
- <Value_Object_Key text={key} />
182
- <Char_Colon />
183
-
184
- <ParseValue value={value} path={[...path, `${key}`]} />
185
-
186
- {ix < objectEntries.length - 1 && (
187
- <Char_Comma />
188
- )}
189
- </li>
190
- );
191
- })
192
- }
193
- </ul>
194
-
195
- <Char_Bracket text="}" />
196
- </>
197
- ) : (
198
- <div
199
- className="inline-block cursor-pointer"
200
- onClick={() => setExpanded(true)}
201
- >
202
- <Char_Bracket text="{" />
203
- {' '}
204
- {collapsedPreview}
205
- {' '}
206
- <Char_Bracket text="}" />
207
- </div>
208
- )
209
- }
210
- </>
211
- );
212
- }
213
-
214
- interface Value_Array_Props {
215
- value: unknown[],
216
- path: string[],
217
- defaultExpanded?: boolean
218
- }
219
- function Value_Array({
220
- value,
221
- path,
222
- defaultExpanded = false
223
- }: Value_Array_Props) {
224
- const debug = useDebugger();
225
-
226
- const [expanded, setExpanded] = useState(defaultExpanded);
227
-
228
- const children = useMemo(() => {
229
- const children: React.ReactNode[] = [];
230
-
231
- let ix = 0;
232
-
233
- while (ix < value.length) {
234
- const nextTarget = Math.min(ix + debug.options.compactArrays, value.length);
235
-
236
- children.push(
237
- <li key={ix}>
238
- {
239
- (() => {
240
- const children: React.ReactNode[] = [];
241
-
242
- for (;ix < nextTarget; ix++) {
243
- children.push(
244
- <React.Fragment key={ix}>
245
- <ParseValue value={value[ix]} path={[...path, `${ix}`]} />
246
- {ix < value.length - 1 && (
247
- <Char_Comma />
248
- )}
249
- </React.Fragment>
250
- )
251
- }
252
-
253
- return children;
254
- })()
255
- }
256
- </li>
257
- );
258
-
259
- ix = nextTarget;
260
- }
261
-
262
- return children;
263
- }, [debug.options.compactArrays, value]);
264
-
265
- const collapsedPreview = useMemo(() => {
266
- const children: React.ReactNode[] = [];
267
-
268
- for (let i = 0; i < Math.min(value.length, 6); i++) {
269
- children.push(
270
- <React.Fragment key={i}>
271
- <ParseValue_ToSimple value={value[i]} />
272
-
273
- {i < value.length - 1 && <Char_Comma />}
274
- </React.Fragment>
275
- );
276
- }
277
-
278
- if (value.length > 6)
279
- children.push(<span key={'rest'} className="text-zinc-500">...</span>);
280
-
281
- return children;
282
- }, [value]);
283
-
284
- useLayoutEffect(() => {
285
- debug.event.expand(path, expanded);
286
- }, [expanded]);
287
-
288
- const handleExpand = (state: boolean) => {
289
- setExpanded(state);
290
- }
291
-
292
- return (
293
- <>
294
- <Chevron_Toggle expanded={expanded} onToggle={handleExpand} />
295
-
296
- <span>{`(${value.length}) `}</span>
297
- {
298
- expanded ? (
299
- <>
300
- <Char_Bracket text="[" />
301
-
302
- <ul className="pl-4 ml-1 border-l border-l-primary-400">
303
- {children}
304
- </ul>
305
-
306
- <Char_Bracket text="]" />
307
- </>
308
- ) : (
309
- <div
310
- className="inline-block cursor-pointer"
311
- onClick={() => setExpanded(true)}
312
- >
313
- <Char_Bracket text="[" />
314
- {/* <span className="text-zinc-500">...</span> */}
315
- {collapsedPreview}
316
- <Char_Bracket text="]" />
317
- </div>
318
- )
319
- }
320
- </>
321
- );
322
- }
323
-
324
-
325
- interface Value_Object_Key_Props {
326
- text: string,
327
- }
328
- function Value_Object_Key({
329
- text
330
- }: Value_Object_Key_Props) {
331
- return (
332
- <span className="text-[#9CDCF0]">
333
- {text}
334
- </span>
335
- )
336
- }
337
-
338
- interface Value_SymbolProps {
339
- value: symbol
340
- }
341
- function Value_Symbol({
342
- value
343
- }: Value_SymbolProps) {
344
- return (
345
- <>
346
- <Value_Keyword value="Symbol" />
347
- <Char_Bracket text="(" />
348
- <span>
349
- {value.description}
350
- </span>
351
- <Char_Bracket text=")" />
352
- </>
353
- )
354
- }
355
-
356
- interface ParseValue_ToSimpleProps {
357
- value: unknown
358
- }
359
- function ParseValue_ToSimple({
360
- value
361
- }: ParseValue_ToSimpleProps): React.ReactNode {
362
- const MAX_LENGTH = 16;
363
-
364
- switch (typeof value) {
365
- case 'bigint':
366
- case 'number': {
367
- const numStr = value.toString();
368
-
369
- if (numStr.length > MAX_LENGTH)
370
- return <Value_Keyword value={typeof value} />;
371
-
372
- return <Value_Number value={value} />
373
- }
374
- case 'boolean': return <Value_Boolean value={value} />
375
- case 'function': return <Value_Function value={value} />
376
- case 'object': {
377
- if (value === null)
378
- return <Value_Keyword value="null" />
379
-
380
- const className = Object.getPrototypeOf(value) !== Object.prototype ? value.constructor.name : null;
381
-
382
- if (className === null || className.length > MAX_LENGTH)
383
- return <Value_Keyword value="object" />
384
-
385
- return className;
386
- }
387
- case 'string': {
388
- if (value.length > MAX_LENGTH)
389
- return <Value_String value="string" noEncase />
390
-
391
- return <Value_String value={value} />;
392
- }
393
- case 'symbol': {
394
- if (!value.description || value.description.length > MAX_LENGTH)
395
- return <Value_Keyword value="Symbol" />
396
-
397
- return <Value_Symbol value={value} />
398
- }
399
- case 'undefined': return <Value_Keyword value="undefined" />
400
- }
401
- }