-
-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathKeyValues.tsx
More file actions
133 lines (124 loc) · 5.25 KB
/
KeyValues.tsx
File metadata and controls
133 lines (124 loc) · 5.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import { Fragment, useRef, useState } from 'react';
import { useStore } from '../store';
import { useExpandsStore } from '../store/Expands';
import { useShowToolsDispatch } from '../store/ShowTools';
import { Value } from './Value';
import { KeyNameComp } from '../section/KeyName';
import { RowComp } from '../section/Row';
import { Container } from '../Container';
import { Quote, Colon } from '../symbol/';
import { useHighlight } from '../utils/useHighlight';
import { type SectionElementResult } from '../store/Section';
import { Copied } from '../comps/Copied';
import { useIdCompat } from '../comps/useIdCompat';
import { ValueExtraComp } from '../section/ValueExtra';
import { KeyValueItemContext } from '../editor/store';
interface KeyValuesProps<T extends object> extends SectionElementResult<T> {
expandKey?: string;
level: number;
}
export const KeyValues = <T extends object>(props: KeyValuesProps<T>) => {
const { keyName, value, expandKey = '', level, keys = [], parentValue } = props;
const expands = useExpandsStore();
const { objectSortKeys, indentWidth, collapsed, shouldExpandNodeInitially } = useStore();
const defaultExpanded =
typeof collapsed === 'boolean' ? collapsed : typeof collapsed === 'number' ? level > collapsed : false;
const isExpanded = expands[expandKey] ?? defaultExpanded;
const shouldExpand =
shouldExpandNodeInitially && shouldExpandNodeInitially(isExpanded, { value, keys, level, keyName, parentValue });
if (expands[expandKey] === undefined && !!shouldExpand) {
return null;
}
if (isExpanded) {
return null;
}
const isMyArray = Array.isArray(value);
// object
let entries: [key: string | number, value: T][] = isMyArray
? Object.entries(value).map((m) => [Number(m[0]), m[1]])
: Object.entries(value as T);
if (objectSortKeys) {
entries =
objectSortKeys === true
? entries.sort(([a], [b]) => (typeof a === 'string' && typeof b === 'string' ? a.localeCompare(b) : 0))
: entries.sort(([a, valA], [b, valB]) =>
typeof a === 'string' && typeof b === 'string' ? objectSortKeys(a, b, valA, valB) : 0,
);
}
const style = {
borderLeft: 'var(--w-rjv-border-left-width, 1px) var(--w-rjv-line-style, solid) var(--w-rjv-line-color, #ebebeb)',
paddingLeft: indentWidth,
marginLeft: 6,
};
return (
<div className="w-rjv-wrap" style={style}>
{entries.map(([key, val], idx) => {
return (
<KeyValuesItem parentValue={value} keyName={key} keys={[...keys, key]} value={val} key={idx} level={level} />
);
})}
</div>
);
};
KeyValues.displayName = 'JVR.KeyValues';
interface KayNameProps<T extends object> extends Omit<KeyValuesProps<T>, 'level'> {}
export const KayName = <T extends object>(props: KayNameProps<T>) => {
const { keyName, parentValue, keys, value } = props;
const { highlightUpdates } = useStore();
const isNumber = typeof keyName === 'number';
const highlightContainer = useRef<HTMLSpanElement>(null);
useHighlight({ value, highlightUpdates, highlightContainer });
const compProps = { keyName, value, keys, parentValue };
return (
<Fragment>
<span ref={highlightContainer}>
<Quote isNumber={isNumber} data-placement="left" {...compProps} />
<KeyNameComp {...compProps}>{keyName}</KeyNameComp>
<Quote isNumber={isNumber} data-placement="right" {...compProps} />
</span>
<Colon {...compProps} />
</Fragment>
);
};
KayName.displayName = 'JVR.KayName';
export const KeyValuesItem = <T extends object>(props: KeyValuesProps<T>) => {
const { keyName, value, parentValue, level = 0, keys = [] } = props;
const dispatch = useShowToolsDispatch();
const subkeyid = useIdCompat();
const isMyArray = Array.isArray(value);
const isMySet = value instanceof Set;
const isMyMap = value instanceof Map;
const isDate = value instanceof Date;
const isUrl = value instanceof URL;
const isMyObject = value && typeof value === 'object' && !isMyArray && !isMySet && !isMyMap && !isDate && !isUrl;
const isNested = isMyObject || isMyArray || isMySet || isMyMap;
if (isNested) {
const myValue = isMySet ? Array.from(value as Set<any>) : isMyMap ? Object.fromEntries(value) : value;
return (
<Container
keyName={keyName}
value={myValue}
parentValue={parentValue}
initialValue={value}
keys={keys}
level={level + 1}
/>
);
}
const reset: React.HTMLAttributes<HTMLDivElement> = {
onMouseEnter: () => dispatch({ [subkeyid]: true }),
onMouseLeave: () => dispatch({ [subkeyid]: false }),
};
const [editable, setEditable] = useState(false)
return (
<KeyValueItemContext.Provider value={{ editable, setEditable }}>
<RowComp className="w-rjv-line" value={value} keyName={keyName} keys={keys} parentValue={parentValue} {...reset}>
<KayName keyName={keyName} value={value} keys={keys} parentValue={parentValue} />
<Value keyName={keyName!} value={value} keys={keys} />
<ValueExtraComp keyName={keyName!} value={value} keys={keys} expandKey={subkeyid} />
<Copied keyName={keyName} value={value as object} keys={keys} parentValue={parentValue} expandKey={subkeyid} />
</RowComp>
</KeyValueItemContext.Provider>
);
};
KeyValuesItem.displayName = 'JVR.KeyValuesItem';