mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-07-22 14:09:46 +03:00
Integrate expand/collapse buttons into the react-json-tree
This commit is contained in:
parent
f0b8a64713
commit
decde458b1
|
@ -46,6 +46,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@types/lodash": "^4.14.194",
|
||||
"react-base16-styling": "^0.9.1"
|
||||
},
|
||||
|
|
|
@ -119,13 +119,16 @@ export default function JSONNestedNode(props: Props) {
|
|||
isCircular ? false : shouldExpandNodeInitially(keyPath, data, level)
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldExpandNode === undefined) {
|
||||
return;
|
||||
}
|
||||
const defaultExpanded = shouldExpandNodeInitially(keyPath, data, level);
|
||||
|
||||
setExpanded(shouldExpandNode);
|
||||
}, [shouldExpandNode]);
|
||||
useEffect(() => {
|
||||
switch(shouldExpandNode){
|
||||
case 'expand': setExpanded(true); break;
|
||||
case'collapse': setExpanded(false); break;
|
||||
case'default': setExpanded(defaultExpanded); break;
|
||||
default:
|
||||
}
|
||||
}, [defaultExpanded, shouldExpandNode]);
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (expandable) setExpanded(!expanded);
|
||||
|
|
106
packages/react-json-tree/src/expandableButtons.tsx
Normal file
106
packages/react-json-tree/src/expandableButtons.tsx
Normal file
|
@ -0,0 +1,106 @@
|
|||
import React, { ReactNode } from 'react'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faArrowDown, faArrowRight, faUndo } from '@fortawesome/free-solid-svg-icons';
|
||||
import { Expandable } from '.';
|
||||
|
||||
interface Props {
|
||||
expandable?: Expandable;
|
||||
expandableDefaultValue?: 'expand' | 'collapse';
|
||||
shouldExpandNode?: 'expand' | 'collapse' | 'default';
|
||||
setShouldExpandNode: any;
|
||||
}
|
||||
|
||||
interface ExpandButtonProps {
|
||||
expandableDefaultValue?: 'expand' | 'collapse';
|
||||
expandIcon?: ReactNode;
|
||||
shouldExpandNode?: 'expand' | 'collapse' | 'default';
|
||||
setShouldExpandNode: any;
|
||||
}
|
||||
|
||||
interface CollapseButtonProps {
|
||||
expandableDefaultValue?: 'expand' | 'collapse';
|
||||
collapseIcon?: ReactNode;
|
||||
shouldExpandNode?: 'expand' | 'collapse' | 'default';
|
||||
setShouldExpandNode: any;
|
||||
}
|
||||
|
||||
interface DefaultButtonProps {
|
||||
defaultIcon?: ReactNode;
|
||||
setShouldExpandNode: any;
|
||||
}
|
||||
|
||||
function ExpandableButtons({
|
||||
expandable,
|
||||
expandableDefaultValue,
|
||||
setShouldExpandNode,
|
||||
shouldExpandNode
|
||||
}: Props){
|
||||
if(!expandable){
|
||||
return <></>
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{position: 'absolute', display: 'flex', justifyContent:'center', alignItems: 'center', gap:'1rem', top: '1rem', right: '1rem', cursor: 'pointer'}}>
|
||||
<DefaultButton
|
||||
defaultIcon={expandable?.defaultIcon}
|
||||
setShouldExpandNode={setShouldExpandNode}
|
||||
/>
|
||||
|
||||
<ExpandButton
|
||||
expandableDefaultValue={expandableDefaultValue}
|
||||
expandIcon={expandable?.expandIcon}
|
||||
setShouldExpandNode={setShouldExpandNode}
|
||||
shouldExpandNode={shouldExpandNode}
|
||||
/>
|
||||
|
||||
<CollapseButton
|
||||
expandableDefaultValue={expandable?.defaultValue}
|
||||
collapseIcon={expandable?.collapseIcon}
|
||||
setShouldExpandNode={setShouldExpandNode}
|
||||
shouldExpandNode={shouldExpandNode}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function ExpandButton({ expandableDefaultValue, expandIcon, shouldExpandNode, setShouldExpandNode }: ExpandButtonProps) {
|
||||
const onExpand = () => setShouldExpandNode('expand');
|
||||
|
||||
if (shouldExpandNode === 'collapse' || (shouldExpandNode === 'default' && expandableDefaultValue === 'collapse')) {
|
||||
return (
|
||||
<div role="presentation" onClick={onExpand}>
|
||||
{expandIcon || <FontAwesomeIcon icon={faArrowRight} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <></>;
|
||||
}
|
||||
|
||||
function CollapseButton({ expandableDefaultValue, collapseIcon, shouldExpandNode, setShouldExpandNode }: CollapseButtonProps) {
|
||||
const onCollapse = () => setShouldExpandNode('collapse');
|
||||
|
||||
if (shouldExpandNode === 'expand' ||(shouldExpandNode === 'default' && expandableDefaultValue === 'expand')) {
|
||||
return (
|
||||
<div role="presentation" onClick={onCollapse}>
|
||||
{collapseIcon || <FontAwesomeIcon icon={faArrowDown} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <></>;
|
||||
}
|
||||
|
||||
function DefaultButton({defaultIcon, setShouldExpandNode }:DefaultButtonProps) {
|
||||
const onDefaultCollapse = () => setShouldExpandNode('default');
|
||||
|
||||
return (
|
||||
<div role="presentation" onClick={onDefaultCollapse}>
|
||||
{defaultIcon || <FontAwesomeIcon icon={faUndo} />}
|
||||
</div>
|
||||
);
|
||||
|
||||
return <></>;
|
||||
}
|
||||
|
||||
export default ExpandableButtons
|
|
@ -3,11 +3,12 @@
|
|||
// Dave Vedder <veddermatic@gmail.com> http://www.eskimospy.com/
|
||||
// port by Daniele Zannotti http://www.github.com/dzannotti <dzannotti@me.com>
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { ReactNode, useMemo, useState } from 'react';
|
||||
import JSONNode from './JSONNode';
|
||||
import createStylingFromTheme from './createStylingFromTheme';
|
||||
import { invertTheme } from 'react-base16-styling';
|
||||
import type { StylingValue, Theme } from 'react-base16-styling';
|
||||
import ExpandableButtons from './expandableButtons'
|
||||
import type {
|
||||
CommonExternalProps,
|
||||
GetItemString,
|
||||
|
@ -20,6 +21,14 @@ interface Props extends Partial<CommonExternalProps> {
|
|||
data: unknown;
|
||||
theme?: Theme;
|
||||
invertTheme?: boolean;
|
||||
expandable?: Expandable;
|
||||
}
|
||||
|
||||
interface Expandable {
|
||||
defaultValue?: 'expand' | 'collapse';
|
||||
expandIcon?: ReactNode;
|
||||
collapseIcon?: ReactNode;
|
||||
defaultIcon?: ReactNode;
|
||||
}
|
||||
|
||||
const identity = (value: any) => value;
|
||||
|
@ -41,7 +50,7 @@ export function JSONTree({
|
|||
labelRenderer = defaultLabelRenderer,
|
||||
valueRenderer = identity,
|
||||
shouldExpandNodeInitially = expandRootNode,
|
||||
shouldExpandNode,
|
||||
expandable,
|
||||
hideRoot = false,
|
||||
getItemString = defaultItemString,
|
||||
postprocessValue = identity,
|
||||
|
@ -49,6 +58,9 @@ export function JSONTree({
|
|||
collectionLimit = 50,
|
||||
sortObjectKeys = false,
|
||||
}: Props) {
|
||||
const expandableDefaultValue = expandable?.defaultValue || 'expand'
|
||||
const [shouldExpandNode, setShouldExpandNode] = useState(expandableDefaultValue);
|
||||
|
||||
const styling = useMemo(
|
||||
() =>
|
||||
createStylingFromTheme(shouldInvertTheme ? invertTheme(theme) : theme),
|
||||
|
@ -72,6 +84,13 @@ export function JSONTree({
|
|||
collectionLimit={collectionLimit}
|
||||
sortObjectKeys={sortObjectKeys}
|
||||
/>
|
||||
|
||||
<ExpandableButtons
|
||||
expandable={expandable}
|
||||
expandableDefaultValue={expandableDefaultValue}
|
||||
shouldExpandNode={shouldExpandNode}
|
||||
setShouldExpandNode={setShouldExpandNode}
|
||||
/>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
@ -89,4 +108,4 @@ export type {
|
|||
Styling,
|
||||
CommonExternalProps,
|
||||
} from './types';
|
||||
export type { StylingValue };
|
||||
export type { Expandable, StylingValue };
|
||||
|
|
|
@ -47,7 +47,6 @@ export interface CommonExternalProps {
|
|||
labelRenderer: LabelRenderer;
|
||||
valueRenderer: ValueRenderer;
|
||||
shouldExpandNodeInitially: ShouldExpandNodeInitially;
|
||||
shouldExpandNode: boolean | undefined;
|
||||
hideRoot: boolean;
|
||||
getItemString: GetItemString;
|
||||
postprocessValue: PostprocessValue;
|
||||
|
@ -61,4 +60,5 @@ export interface CommonInternalProps extends CommonExternalProps {
|
|||
circularCache?: CircularCache;
|
||||
level?: number;
|
||||
isCircular?: boolean;
|
||||
shouldExpandNode?: 'expand' | 'collapse' | 'default';
|
||||
}
|
||||
|
|
|
@ -17,6 +17,6 @@ describe('JSONTree', () => {
|
|||
const result = render(<JSONTree data={BASIC_DATA} />);
|
||||
|
||||
expect(result.type).toBe('ul');
|
||||
expect(result.props.children.type.name).toBe(JSONNode.name);
|
||||
expect(result.props.children[0].type.name).toBe(JSONNode.name);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user