mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-07-22 22:19:48 +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": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.21.0",
|
"@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",
|
"@types/lodash": "^4.14.194",
|
||||||
"react-base16-styling": "^0.9.1"
|
"react-base16-styling": "^0.9.1"
|
||||||
},
|
},
|
||||||
|
|
|
@ -119,13 +119,16 @@ export default function JSONNestedNode(props: Props) {
|
||||||
isCircular ? false : shouldExpandNodeInitially(keyPath, data, level)
|
isCircular ? false : shouldExpandNodeInitially(keyPath, data, level)
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
const defaultExpanded = shouldExpandNodeInitially(keyPath, data, level);
|
||||||
if (shouldExpandNode === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setExpanded(shouldExpandNode);
|
useEffect(() => {
|
||||||
}, [shouldExpandNode]);
|
switch(shouldExpandNode){
|
||||||
|
case 'expand': setExpanded(true); break;
|
||||||
|
case'collapse': setExpanded(false); break;
|
||||||
|
case'default': setExpanded(defaultExpanded); break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}, [defaultExpanded, shouldExpandNode]);
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
if (expandable) setExpanded(!expanded);
|
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/
|
// Dave Vedder <veddermatic@gmail.com> http://www.eskimospy.com/
|
||||||
// port by Daniele Zannotti http://www.github.com/dzannotti <dzannotti@me.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 JSONNode from './JSONNode';
|
||||||
import createStylingFromTheme from './createStylingFromTheme';
|
import createStylingFromTheme from './createStylingFromTheme';
|
||||||
import { invertTheme } from 'react-base16-styling';
|
import { invertTheme } from 'react-base16-styling';
|
||||||
import type { StylingValue, Theme } from 'react-base16-styling';
|
import type { StylingValue, Theme } from 'react-base16-styling';
|
||||||
|
import ExpandableButtons from './expandableButtons'
|
||||||
import type {
|
import type {
|
||||||
CommonExternalProps,
|
CommonExternalProps,
|
||||||
GetItemString,
|
GetItemString,
|
||||||
|
@ -20,6 +21,14 @@ interface Props extends Partial<CommonExternalProps> {
|
||||||
data: unknown;
|
data: unknown;
|
||||||
theme?: Theme;
|
theme?: Theme;
|
||||||
invertTheme?: boolean;
|
invertTheme?: boolean;
|
||||||
|
expandable?: Expandable;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Expandable {
|
||||||
|
defaultValue?: 'expand' | 'collapse';
|
||||||
|
expandIcon?: ReactNode;
|
||||||
|
collapseIcon?: ReactNode;
|
||||||
|
defaultIcon?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const identity = (value: any) => value;
|
const identity = (value: any) => value;
|
||||||
|
@ -41,7 +50,7 @@ export function JSONTree({
|
||||||
labelRenderer = defaultLabelRenderer,
|
labelRenderer = defaultLabelRenderer,
|
||||||
valueRenderer = identity,
|
valueRenderer = identity,
|
||||||
shouldExpandNodeInitially = expandRootNode,
|
shouldExpandNodeInitially = expandRootNode,
|
||||||
shouldExpandNode,
|
expandable,
|
||||||
hideRoot = false,
|
hideRoot = false,
|
||||||
getItemString = defaultItemString,
|
getItemString = defaultItemString,
|
||||||
postprocessValue = identity,
|
postprocessValue = identity,
|
||||||
|
@ -49,6 +58,9 @@ export function JSONTree({
|
||||||
collectionLimit = 50,
|
collectionLimit = 50,
|
||||||
sortObjectKeys = false,
|
sortObjectKeys = false,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const expandableDefaultValue = expandable?.defaultValue || 'expand'
|
||||||
|
const [shouldExpandNode, setShouldExpandNode] = useState(expandableDefaultValue);
|
||||||
|
|
||||||
const styling = useMemo(
|
const styling = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createStylingFromTheme(shouldInvertTheme ? invertTheme(theme) : theme),
|
createStylingFromTheme(shouldInvertTheme ? invertTheme(theme) : theme),
|
||||||
|
@ -72,6 +84,13 @@ export function JSONTree({
|
||||||
collectionLimit={collectionLimit}
|
collectionLimit={collectionLimit}
|
||||||
sortObjectKeys={sortObjectKeys}
|
sortObjectKeys={sortObjectKeys}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ExpandableButtons
|
||||||
|
expandable={expandable}
|
||||||
|
expandableDefaultValue={expandableDefaultValue}
|
||||||
|
shouldExpandNode={shouldExpandNode}
|
||||||
|
setShouldExpandNode={setShouldExpandNode}
|
||||||
|
/>
|
||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -89,4 +108,4 @@ export type {
|
||||||
Styling,
|
Styling,
|
||||||
CommonExternalProps,
|
CommonExternalProps,
|
||||||
} from './types';
|
} from './types';
|
||||||
export type { StylingValue };
|
export type { Expandable, StylingValue };
|
||||||
|
|
|
@ -47,7 +47,6 @@ export interface CommonExternalProps {
|
||||||
labelRenderer: LabelRenderer;
|
labelRenderer: LabelRenderer;
|
||||||
valueRenderer: ValueRenderer;
|
valueRenderer: ValueRenderer;
|
||||||
shouldExpandNodeInitially: ShouldExpandNodeInitially;
|
shouldExpandNodeInitially: ShouldExpandNodeInitially;
|
||||||
shouldExpandNode: boolean | undefined;
|
|
||||||
hideRoot: boolean;
|
hideRoot: boolean;
|
||||||
getItemString: GetItemString;
|
getItemString: GetItemString;
|
||||||
postprocessValue: PostprocessValue;
|
postprocessValue: PostprocessValue;
|
||||||
|
@ -61,4 +60,5 @@ export interface CommonInternalProps extends CommonExternalProps {
|
||||||
circularCache?: CircularCache;
|
circularCache?: CircularCache;
|
||||||
level?: number;
|
level?: number;
|
||||||
isCircular?: boolean;
|
isCircular?: boolean;
|
||||||
|
shouldExpandNode?: 'expand' | 'collapse' | 'default';
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,6 @@ describe('JSONTree', () => {
|
||||||
const result = render(<JSONTree data={BASIC_DATA} />);
|
const result = render(<JSONTree data={BASIC_DATA} />);
|
||||||
|
|
||||||
expect(result.type).toBe('ul');
|
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