Skip to content

Commit ad3dbad

Browse files
committed
refactor: refactor the code to completa all features view JSON.
1 parent ac19f59 commit ad3dbad

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+2536
-2834
lines changed

core/README.md

Lines changed: 230 additions & 267 deletions
Large diffs are not rendered by default.

core/src/Container.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React, { forwardRef, useId, useImperativeHandle, useRef } from 'react';
2+
import { NestedClose } from './comps/NestedClose';
3+
import { NestedOpen } from './comps/NestedOpen';
4+
import { KeyValues } from './comps/KeyValues';
5+
import { useShowToolsDispatch } from './store/ShowTools';
6+
7+
export interface ContainerProps<T extends object> extends React.HTMLAttributes<HTMLDivElement> {
8+
keyName?: string | number;
9+
keyid?: string;
10+
parentValue?: T;
11+
level?: number;
12+
value?: T;
13+
initialValue?: T;
14+
}
15+
export const Container = forwardRef(<T extends object>(props: ContainerProps<T>, ref: React.Ref<HTMLDivElement>) => {
16+
const { className = '', children, parentValue, keyid, level = 1, value, initialValue, keyName, ...elmProps } = props;
17+
const $ref = useRef<HTMLDivElement>(null);
18+
const dispatch = useShowToolsDispatch();
19+
useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(ref, () => $ref.current, [$ref]);
20+
const subkeyid = useId();
21+
const defaultClassNames = `w-rjv-inner ${className}`;
22+
const reset: React.HTMLAttributes<HTMLDivElement> = {
23+
onMouseEnter: () => dispatch({ [subkeyid]: true }),
24+
onMouseLeave: () => dispatch({ [subkeyid]: false }),
25+
};
26+
return (
27+
<div className={defaultClassNames} {...elmProps} {...reset}>
28+
<NestedOpen expandKey={subkeyid} value={value} level={level} keyName={keyName} initialValue={initialValue} />
29+
<KeyValues expandKey={subkeyid} value={value} level={level} />
30+
<NestedClose expandKey={subkeyid} value={value} level={level} />
31+
</div>
32+
);
33+
});
34+
35+
Container.displayName = 'JVR.Container';

core/src/arrow/TriangleArrow.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ export function TriangleArrow(props: TriangleArrowProps) {
77
cursor: 'pointer',
88
height: '1em',
99
width: '1em',
10+
userSelect: 'none',
11+
display: 'flex',
1012
...style,
1113
};
1214
return (

core/src/arrow/TriangleSolidArrow.test.tsx

Lines changed: 0 additions & 19 deletions
This file was deleted.

core/src/arrow/TriangleSolidArrow.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,20 @@ export function TriangleSolidArrow(props: TriangleSolidArrowProps) {
77
cursor: 'pointer',
88
height: '1em',
99
width: '1em',
10+
userSelect: 'none',
11+
display: 'flex',
1012
...style,
1113
};
1214
return (
13-
<svg viewBox="0 0 15 15" fill="var(--w-rjv-arrow-color, currentColor)" style={defaultStyle} {...reset}>
14-
<path d="M0 5l6 6 6-6z"></path>
15+
<svg
16+
viewBox="0 0 30 30"
17+
fill="var(--w-rjv-arrow-color, currentColor)"
18+
height="1em"
19+
width="1em"
20+
style={defaultStyle}
21+
{...reset}
22+
>
23+
<path d="M14.1758636,22.5690012 C14.3620957,22.8394807 14.6694712,23.001033 14.9978636,23.001033 C15.326256,23.001033 15.6336315,22.8394807 15.8198636,22.5690012 L24.8198636,9.56900125 C25.0322035,9.2633716 25.0570548,8.86504616 24.8843497,8.5353938 C24.7116447,8.20574144 24.3700159,7.99941506 23.9978636,8 L5.9978636,8 C5.62665,8.00153457 5.28670307,8.20817107 5.11443241,8.53699428 C4.94216175,8.86581748 4.96580065,9.26293681 5.1758636,9.56900125 L14.1758636,22.5690012 Z" />
1524
</svg>
1625
);
1726
}
Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,35 @@
11
import { useState } from 'react';
2+
import { useStore } from '../store';
3+
import { useShowToolsStore } from '../store/ShowTools';
4+
import { useSectionStore } from '../store/Section';
5+
import { type TagType } from '../store/Types';
26

3-
export interface CopiedProps<T = object> extends React.SVGProps<SVGSVGElement> {
4-
show?: boolean;
5-
text?: T;
6-
onCopied?: (text: string, obj: T | '') => void;
7-
render?: (props: Omit<CopiedProps<T>, 'render'>) => JSX.Element;
7+
export type CopiedOption<T extends object> = {
8+
value?: T;
9+
copied: boolean;
10+
setCopied: React.Dispatch<React.SetStateAction<boolean>>;
11+
};
12+
13+
export interface CopiedProps<T extends object> extends React.SVGProps<SVGSVGElement> {
14+
value?: T;
15+
keyName: string | number;
16+
expandKey: string;
817
}
918

10-
export function Copied<T>(props: CopiedProps<T>) {
11-
const { children, style, text = '', onCopied, render, show, ...reset } = props;
12-
if (!show) return null;
19+
export const Copied = <T extends object, K extends TagType>(props: CopiedProps<T>) => {
20+
const { keyName, value, expandKey, ...other } = props;
21+
const { onCopied, enableClipboard } = useStore();
22+
const showTools = useShowToolsStore();
23+
const isShowTools = showTools[expandKey];
1324
const [copied, setCopied] = useState(false);
25+
const { Copied: Comp = {} } = useSectionStore();
26+
27+
if (enableClipboard === false || !isShowTools) return null;
28+
1429
const click = (event: React.MouseEvent<SVGSVGElement, MouseEvent>) => {
1530
event.stopPropagation();
1631
let copyText = JSON.stringify(
17-
text || '',
32+
value,
1833
(key, value) => {
1934
if (typeof value === 'bigint') {
2035
return value.toString();
@@ -23,13 +38,13 @@ export function Copied<T>(props: CopiedProps<T>) {
2338
},
2439
2,
2540
);
26-
27-
if (text === Infinity) copyText = Infinity;
28-
41+
if (typeof value === 'number' && value === Infinity) copyText = 'Infinity';
42+
if (typeof value === 'number' && isNaN(value)) copyText = 'NaN';
43+
if (typeof value === 'bigint') copyText = value + 'n';
2944
navigator.clipboard
3045
.writeText(copyText)
3146
.then(() => {
32-
onCopied && onCopied(copyText, text);
47+
onCopied && onCopied(copyText, value);
3348
setCopied(true);
3449
const timer = setTimeout(() => {
3550
setCopied(false);
@@ -38,29 +53,29 @@ export function Copied<T>(props: CopiedProps<T>) {
3853
})
3954
.catch((error) => {});
4055
};
41-
const defalutStyle = { ...style, cursor: 'pointer', verticalAlign: 'middle', marginLeft: 5 } as React.CSSProperties;
4256
const svgProps: React.SVGProps<SVGSVGElement> = {
43-
height: '1em',
44-
width: '1em',
45-
fill: 'var(--w-rjv-copied-color, currentColor)',
57+
fill: copied ? 'var(--w-rjv-copied-success-color, #28a745)' : 'var(--w-rjv-copied-color, currentColor)',
4658
onClick: click,
47-
style: defalutStyle,
48-
className: 'w-rjv-copied',
49-
...reset,
5059
};
51-
if (render) return render({ ...props, ...svgProps });
60+
const { as, render, ...reset } = Comp;
61+
62+
const elmProps: React.SVGProps<SVGSVGElement> = { ...reset, ...other, ...svgProps } as React.SVGProps<SVGSVGElement>;
63+
const isRender = render && typeof render === 'function';
64+
const child =
65+
isRender && render({ ...elmProps, 'data-copied': copied } as React.HTMLAttributes<K>, { value, keyName });
66+
if (child) return child;
5267
if (copied) {
5368
return (
54-
<svg viewBox="0 0 32 36" {...svgProps} fill="var(--w-rjv-copied-success-color, #28a745)">
55-
<path d="M27.5,33 L2.5,33 L2.5,12.5 L27.5,12.5 L27.5,15.2249049 C29.1403264,13.8627542 29.9736597,13.1778155 30,13.1700887 C30,11.9705278 30,10.0804982 30,7.5 C30,6.1 28.9,5 27.5,5 L20,5 C20,2.2 17.8,0 15,0 C12.2,0 10,2.2 10,5 L2.5,5 C1.1,5 0,6.1 0,7.5 L0,33 C0,34.4 1.1,36 2.5,36 L27.5,36 C28.9,36 30,34.4 30,33 L30,26.1114493 L27.5,28.4926435 L27.5,33 Z M7.5,7.5 L10,7.5 C10,7.5 12.5,6.4 12.5,5 C12.5,3.6 13.6,2.5 15,2.5 C16.4,2.5 17.5,3.6 17.5,5 C17.5,6.4 18.8,7.5 20,7.5 L22.5,7.5 C22.5,7.5 25,8.6 25,10 L5,10 C5,8.5 6.1,7.5 7.5,7.5 Z M5,27.5 L10,27.5 L10,25 L5,25 L5,27.5 Z M28.5589286,16 L32,19.6 L21.0160714,30.5382252 L13.5303571,24.2571429 L17.1303571,20.6571429 L21.0160714,24.5428571 L28.5589286,16 Z M17.5,15 L5,15 L5,17.5 L17.5,17.5 L17.5,15 Z M10,20 L5,20 L5,22.5 L10,22.5 L10,20 Z"></path>
69+
<svg viewBox="0 0 32 36" {...elmProps}>
70+
<path d="M27.5,33 L2.5,33 L2.5,12.5 L27.5,12.5 L27.5,15.2249049 C29.1403264,13.8627542 29.9736597,13.1778155 30,13.1700887 C30,11.9705278 30,10.0804982 30,7.5 C30,6.1 28.9,5 27.5,5 L20,5 C20,2.2 17.8,0 15,0 C12.2,0 10,2.2 10,5 L2.5,5 C1.1,5 0,6.1 0,7.5 L0,33 C0,34.4 1.1,36 2.5,36 L27.5,36 C28.9,36 30,34.4 30,33 L30,26.1114493 L27.5,28.4926435 L27.5,33 Z M7.5,7.5 L10,7.5 C10,7.5 12.5,6.4 12.5,5 C12.5,3.6 13.6,2.5 15,2.5 C16.4,2.5 17.5,3.6 17.5,5 C17.5,6.4 18.8,7.5 20,7.5 L22.5,7.5 C22.5,7.5 25,8.6 25,10 L5,10 C5,8.5 6.1,7.5 7.5,7.5 Z M5,27.5 L10,27.5 L10,25 L5,25 L5,27.5 Z M28.5589286,16 L32,19.6 L21.0160714,30.5382252 L13.5303571,24.2571429 L17.1303571,20.6571429 L21.0160714,24.5428571 L28.5589286,16 Z M17.5,15 L5,15 L5,17.5 L17.5,17.5 L17.5,15 Z M10,20 L5,20 L5,22.5 L10,22.5 L10,20 Z" />
5671
</svg>
5772
);
5873
}
5974
return (
60-
<svg viewBox="0 0 32 36" {...svgProps}>
61-
<path d="M27.5,33 L2.5,33 L2.5,12.5 L27.5,12.5 L27.5,20 L30,20 L30,7.5 C30,6.1 28.9,5 27.5,5 L20,5 C20,2.2 17.8,0 15,0 C12.2,0 10,2.2 10,5 L2.5,5 C1.1,5 0,6.1 0,7.5 L0,33 C0,34.4 1.1,36 2.5,36 L27.5,36 C28.9,36 30,34.4 30,33 L30,29 L27.5,29 L27.5,33 Z M7.5,7.5 L10,7.5 C10,7.5 12.5,6.4 12.5,5 C12.5,3.6 13.6,2.5 15,2.5 C16.4,2.5 17.5,3.6 17.5,5 C17.5,6.4 18.8,7.5 20,7.5 L22.5,7.5 C22.5,7.5 25,8.6 25,10 L5,10 C5,8.5 6.1,7.5 7.5,7.5 Z M5,27.5 L10,27.5 L10,25 L5,25 L5,27.5 Z M22.5,21.5 L22.5,16.5 L12.5,24 L22.5,31.5 L22.5,26.5 L32,26.5 L32,21.5 L22.5,21.5 Z M17.5,15 L5,15 L5,17.5 L17.5,17.5 L17.5,15 Z M10,20 L5,20 L5,22.5 L10,22.5 L10,20 Z"></path>
75+
<svg viewBox="0 0 32 36" {...elmProps}>
76+
<path d="M27.5,33 L2.5,33 L2.5,12.5 L27.5,12.5 L27.5,20 L30,20 L30,7.5 C30,6.1 28.9,5 27.5,5 L20,5 C20,2.2 17.8,0 15,0 C12.2,0 10,2.2 10,5 L2.5,5 C1.1,5 0,6.1 0,7.5 L0,33 C0,34.4 1.1,36 2.5,36 L27.5,36 C28.9,36 30,34.4 30,33 L30,29 L27.5,29 L27.5,33 Z M7.5,7.5 L10,7.5 C10,7.5 12.5,6.4 12.5,5 C12.5,3.6 13.6,2.5 15,2.5 C16.4,2.5 17.5,3.6 17.5,5 C17.5,6.4 18.8,7.5 20,7.5 L22.5,7.5 C22.5,7.5 25,8.6 25,10 L5,10 C5,8.5 6.1,7.5 7.5,7.5 Z M5,27.5 L10,27.5 L10,25 L5,25 L5,27.5 Z M22.5,21.5 L22.5,16.5 L12.5,24 L22.5,31.5 L22.5,26.5 L32,26.5 L32,21.5 L22.5,21.5 Z M17.5,15 L5,15 L5,17.5 L17.5,17.5 L17.5,15 Z M10,20 L5,20 L5,22.5 L10,22.5 L10,20 Z" />
6277
</svg>
6378
);
64-
}
79+
};
6580

6681
Copied.displayName = 'JVR.Copied';

core/src/comps/CountInfo.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { useStore } from '../store';
2+
import { useSectionStore, type SectionElementProps } from '../store/Section';
3+
import { type TagType } from '../store/Types';
4+
5+
export interface CountInfoProps<T extends object> {
6+
value?: T;
7+
keyName: string | number;
8+
}
9+
10+
export const CountInfo = <T extends object>(
11+
props: SectionElementProps<TagType> & CountInfoProps<T> & React.HTMLAttributes<HTMLElement>,
12+
) => {
13+
const { value = {}, keyName, ...other } = props;
14+
const { displayObjectSize } = useStore();
15+
16+
const { CountInfo: Comp = {} } = useSectionStore();
17+
18+
if (!displayObjectSize) return null;
19+
20+
const { as, render, ...reset } = Comp;
21+
const Elm = as || 'span';
22+
23+
reset.style = { ...reset.style, ...props.style };
24+
25+
const len = Object.keys(value).length;
26+
if (!reset.children) {
27+
reset.children = `${len} items`;
28+
}
29+
30+
const elmProps = { ...reset, ...other };
31+
const isRender = render && typeof render === 'function';
32+
const child = isRender && render({ ...elmProps, 'data-length': len }, { value, keyName });
33+
if (child) return child;
34+
return <Elm {...elmProps} />;
35+
};
36+
37+
CountInfo.displayName = 'JVR.CountInfo';
38+
39+
export interface CountInfoExtraProps<T extends object> {
40+
value?: T;
41+
keyName: string | number;
42+
}
43+
44+
export const CountInfoExtra = <T extends object>(props: SectionElementProps<TagType> & CountInfoExtraProps<T>) => {
45+
const { value = {}, keyName, ...other } = props;
46+
const { CountInfoExtra: Comp = {} } = useSectionStore();
47+
const { as, render, ...reset } = Comp;
48+
const Elm = as || 'span';
49+
const isRender = render && typeof render === 'function';
50+
const elmProps = { ...reset, ...other };
51+
const child = isRender && render(elmProps, { value, keyName });
52+
if (child) return child;
53+
return <Elm {...elmProps} />;
54+
};
55+
56+
CountInfoExtra.displayName = 'JVR.CountInfoExtra';

core/src/comps/Key.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { FC, PropsWithChildren } from 'react';
2+
import { useSectionStore } from '../store/Section';
3+
4+
type KeyProps = {
5+
keyName: string | number;
6+
value?: unknown;
7+
};
8+
export const Key: FC<PropsWithChildren<KeyProps>> = (props) => {
9+
const { children, value, keyName } = props;
10+
const isNumber = typeof children === 'number';
11+
const style: React.CSSProperties = {
12+
color: isNumber ? 'var(--w-rjv-key-number, #268bd2)' : 'var(--w-rjv-key-string, #002b36)',
13+
};
14+
const { KeyName: Comp = {} } = useSectionStore();
15+
const { as, render, ...reset } = Comp;
16+
reset.style = { ...reset.style, ...style };
17+
const Elm = as || 'span';
18+
const child = render && typeof render === 'function' && render(reset, { value, keyName });
19+
if (child) return child;
20+
return <Elm {...reset}>{children}</Elm>;
21+
};
22+
23+
Key.displayName = 'JVR.Key';

core/src/comps/KeyValues.tsx

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { Fragment, useId, useRef } from 'react';
2+
import { useStore } from '../store';
3+
import { useExpandsStore } from '../store/Expands';
4+
import { useShowToolsDispatch } from '../store/ShowTools';
5+
import { Value } from './Value';
6+
import { Key } from './Key';
7+
import { Container } from '../Container';
8+
import { Quote, Colon } from './ReRender/Symbols';
9+
import { useHighlight } from '../utils/useHighlight';
10+
11+
interface KeyValuesProps<T extends object> {
12+
keyName?: string | number;
13+
value?: T;
14+
parentValue?: T;
15+
expandKey?: string;
16+
level: number;
17+
}
18+
19+
export const KeyValues = <T extends object>(props: KeyValuesProps<T>) => {
20+
const { value, expandKey = '', level } = props;
21+
const expands = useExpandsStore();
22+
const { objectSortKeys, indentWidth, collapsed } = useStore();
23+
const isMyArray = Array.isArray(value);
24+
const isExpanded =
25+
expands[expandKey] ??
26+
(typeof collapsed === 'boolean' ? collapsed : typeof collapsed === 'number' ? level > collapsed : false);
27+
if (isExpanded) {
28+
return null;
29+
}
30+
// object
31+
let entries: [key: string | number, value: T][] = isMyArray
32+
? Object.entries(value).map((m) => [Number(m[0]), m[1]])
33+
: Object.entries(value as T);
34+
if (objectSortKeys) {
35+
entries =
36+
objectSortKeys === true
37+
? entries.sort(([a], [b]) => (typeof a === 'string' && typeof b === 'string' ? a.localeCompare(b) : 0))
38+
: entries.sort(([a], [b]) => (typeof a === 'string' && typeof b === 'string' ? objectSortKeys(a, b) : 0));
39+
}
40+
41+
const style = {
42+
borderLeft: 'var(--w-rjv-border-left-width, 1px) var(--w-rjv-line-style, solid) var(--w-rjv-line-color, #ebebeb)',
43+
paddingLeft: indentWidth,
44+
marginLeft: 6,
45+
};
46+
return (
47+
<div className="w-rjv-wrap" style={style}>
48+
{entries.map(([key, val], idx) => {
49+
return <KeyValuesItem parentValue={value} keyName={key} value={val} key={idx} level={level} />;
50+
})}
51+
</div>
52+
);
53+
};
54+
55+
KeyValues.displayName = 'JVR.KeyValues';
56+
57+
interface KayNameProps<T extends object> extends Omit<KeyValuesProps<T>, 'level'> {}
58+
export const KayName = <T extends object>(props: KayNameProps<T>) => {
59+
const { keyName, value } = props;
60+
const { highlightUpdates } = useStore();
61+
const isNumber = typeof keyName === 'number';
62+
const highlightContainer = useRef<HTMLSpanElement>(null);
63+
useHighlight({ value, highlightUpdates, highlightContainer });
64+
return (
65+
<Fragment>
66+
<span ref={highlightContainer}>
67+
<Quote isNumber={isNumber} />
68+
<Key keyName={keyName!} value={value}>
69+
{keyName}
70+
</Key>
71+
<Quote isNumber={isNumber} />
72+
</span>
73+
<Colon />
74+
</Fragment>
75+
);
76+
};
77+
78+
KayName.displayName = 'JVR.KayName';
79+
80+
export const KeyValuesItem = <T extends object>(props: KeyValuesProps<T>) => {
81+
const { keyName, value, parentValue, level = 0 } = props;
82+
const dispatch = useShowToolsDispatch();
83+
const subkeyid = useId();
84+
const isMyArray = Array.isArray(value);
85+
const isMySet = value instanceof Set;
86+
const isMyMap = value instanceof Map;
87+
const isDate = value instanceof Date;
88+
const isUrl = value instanceof URL;
89+
const isMyObject = value && typeof value === 'object' && !isMyArray && !isMySet && !isMyMap && !isDate && !isUrl;
90+
const isNested = isMyObject || isMyArray || isMySet || isMyMap;
91+
if (isNested) {
92+
const myValue = isMySet ? Array.from(value as Set<any>) : isMyMap ? Object.fromEntries(value) : value;
93+
return (
94+
<Container keyName={keyName} value={myValue} parentValue={parentValue} initialValue={value} level={level + 1} />
95+
);
96+
}
97+
const reset: React.HTMLAttributes<HTMLDivElement> = {
98+
onMouseEnter: () => dispatch({ [subkeyid]: true }),
99+
onMouseLeave: () => dispatch({ [subkeyid]: false }),
100+
};
101+
return (
102+
<div className="w-rjv-line" {...reset}>
103+
<KayName keyName={keyName} value={value} />
104+
<Value keyName={keyName!} value={value} expandKey={subkeyid} />
105+
</div>
106+
);
107+
};
108+
109+
KeyValuesItem.displayName = 'JVR.KeyValuesItem';

0 commit comments

Comments
 (0)