add context

This commit is contained in:
lucataglia 2023-05-20 22:41:59 +02:00
parent e664cba9fb
commit fc0611d750
5 changed files with 195 additions and 143 deletions

View File

@ -1,8 +1,9 @@
import React, { useCallback, useEffect, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import JSONArrow from './JSONArrow';
import getCollectionEntries from './getCollectionEntries';
import JSONNode from './JSONNode';
import ItemRange from './ItemRange'; import ItemRange from './ItemRange';
import JSONArrow from './JSONArrow';
import JSONNode from './JSONNode';
import { useExpandableButtonContext } from './expandableButtonsContext';
import getCollectionEntries from './getCollectionEntries';
import type { CircularCache, CommonInternalProps } from './types'; import type { CircularCache, CommonInternalProps } from './types';
/** /**
@ -110,12 +111,12 @@ export default function JSONNestedNode(props: Props) {
nodeType, nodeType,
nodeTypeIndicator, nodeTypeIndicator,
shouldExpandNodeInitially, shouldExpandNodeInitially,
shouldExpandNode,
setShouldExpandNode,
setEnableDefaultButton,
styling, styling,
} = props; } = props;
const { shouldExpandNode, setShouldExpandNode, setEnableDefaultButton } =
useExpandableButtonContext();
const [expanded, setExpanded] = useState<boolean>( const [expanded, setExpanded] = useState<boolean>(
// calculate individual node expansion if necessary // calculate individual node expansion if necessary
isCircular ? false : shouldExpandNodeInitially(keyPath, data, level) isCircular ? false : shouldExpandNodeInitially(keyPath, data, level)
@ -124,11 +125,17 @@ export default function JSONNestedNode(props: Props) {
const defaultExpanded = shouldExpandNodeInitially(keyPath, data, level); const defaultExpanded = shouldExpandNodeInitially(keyPath, data, level);
useEffect(() => { useEffect(() => {
switch(shouldExpandNode){ switch (shouldExpandNode) {
case 'expand': setExpanded(true); break; case 'expand':
case'collapse': setExpanded(false); break; setExpanded(true);
case'default': setExpanded(defaultExpanded); break; break;
default: case 'collapse':
setExpanded(false);
break;
case 'default':
setExpanded(defaultExpanded);
break;
default: // Do nothing
} }
}, [defaultExpanded, shouldExpandNode]); }, [defaultExpanded, shouldExpandNode]);
@ -136,7 +143,7 @@ export default function JSONNestedNode(props: Props) {
if (expandable) { if (expandable) {
setExpanded(!expanded); setExpanded(!expanded);
setEnableDefaultButton(true); setEnableDefaultButton(true);
setShouldExpandNode(undefined) setShouldExpandNode(undefined);
} }
}, [expandable, expanded, setEnableDefaultButton, setShouldExpandNode]); }, [expandable, expanded, setEnableDefaultButton, setShouldExpandNode]);

View File

@ -1,129 +1,138 @@
import React, { ReactNode } from 'react' import {
faArrowDown,
faArrowRight,
faUndo,
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faArrowDown, faArrowRight, faUndo } from '@fortawesome/free-solid-svg-icons'; import React, { ReactNode } from 'react';
import { Expandable } from '.'; import { Expandable } from '.';
import { useExpandableButtonContext } from './expandableButtonsContext';
interface Props { interface ExpandableButtonsProps {
expandable?: Expandable; expandable: Expandable;
enableDefaultButton: boolean;
setEnableDefaultButton: any;
shouldExpandNode?: 'expand' | 'collapse' | 'default';
setShouldExpandNode: any;
} }
interface ExpandButtonProps { interface ExpandButtonProps {
expandableDefaultValue?: 'expand' | 'collapse'; expandableDefaultValue?: 'expand' | 'collapse';
expandIcon?: ReactNode; expandIcon?: ReactNode;
shouldExpandNode?: 'expand' | 'collapse' | 'default';
setShouldExpandNode: any;
setEnableDefaultButton: any;
} }
interface CollapseButtonProps { interface CollapseButtonProps {
expandableDefaultValue?: 'expand' | 'collapse'; expandableDefaultValue?: 'expand' | 'collapse';
collapseIcon?: ReactNode; collapseIcon?: ReactNode;
shouldExpandNode?: 'expand' | 'collapse' | 'default';
setShouldExpandNode: any;
setEnableDefaultButton: any;
} }
interface DefaultButtonProps { interface DefaultButtonProps {
defaultIcon?: ReactNode; defaultIcon?: ReactNode;
setShouldExpandNode: any;
setEnableDefaultButton: any;
} }
function ExpandableButtons({ function ExpandableButtons({ expandable }: ExpandableButtonsProps) {
expandable, const { enableDefaultButton } = useExpandableButtonContext();
enableDefaultButton,
setEnableDefaultButton,
setShouldExpandNode,
shouldExpandNode
}: Props){
if(!expandable){
return <></>
}
const expandableDefaultValue = expandable?.defaultValue || 'expand' const expandableDefaultValue = expandable?.defaultValue || 'expand';
return ( return (
<div style={{position: 'absolute', display: 'flex', justifyContent:'center', alignItems: 'center', gap:'1rem', top: '1rem', right: '1rem', cursor: 'pointer'}}> <div
{enableDefaultButton && <DefaultButton style={{
defaultIcon={expandable?.defaultIcon} position: 'absolute',
setShouldExpandNode={setShouldExpandNode} display: 'flex',
setEnableDefaultButton={setEnableDefaultButton} justifyContent: 'center',
/>} alignItems: 'center',
gap: '1rem',
top: '1rem',
right: '1rem',
cursor: 'pointer',
}}
>
{enableDefaultButton && (
<DefaultButton defaultIcon={expandable?.defaultIcon} />
)}
<ExpandButton <ExpandButton
expandableDefaultValue={expandableDefaultValue} expandableDefaultValue={expandableDefaultValue}
expandIcon={expandable?.expandIcon} expandIcon={expandable?.expandIcon}
setShouldExpandNode={setShouldExpandNode} />
setEnableDefaultButton={setEnableDefaultButton}
shouldExpandNode={shouldExpandNode}
/>
<CollapseButton <CollapseButton
expandableDefaultValue={expandable?.defaultValue} expandableDefaultValue={expandable?.defaultValue}
collapseIcon={expandable?.collapseIcon} collapseIcon={expandable?.collapseIcon}
setShouldExpandNode={setShouldExpandNode} />
setEnableDefaultButton={setEnableDefaultButton} </div>
shouldExpandNode={shouldExpandNode} );
/>
</div>
)
} }
function ExpandButton({ expandableDefaultValue, expandIcon, shouldExpandNode, setEnableDefaultButton, setShouldExpandNode }: ExpandButtonProps) { function ExpandButton({
const onExpand = () => { expandableDefaultValue,
setShouldExpandNode('expand'); expandIcon,
setEnableDefaultButton(true); }: ExpandButtonProps) {
} const { shouldExpandNode, setShouldExpandNode, setEnableDefaultButton } =
useExpandableButtonContext();
const isDefault = !shouldExpandNode ||shouldExpandNode === 'default' const onExpand = () => {
setShouldExpandNode('expand');
setEnableDefaultButton(true);
};
if (shouldExpandNode === 'collapse' || (isDefault && expandableDefaultValue === 'collapse')) { const isDefault = !shouldExpandNode || shouldExpandNode === 'default';
return (
<div role="presentation" onClick={onExpand}>
{expandIcon || <FontAwesomeIcon icon={faArrowRight} />}
</div>
);
}
return <></>;
}
function CollapseButton({ expandableDefaultValue, collapseIcon, shouldExpandNode, setEnableDefaultButton, setShouldExpandNode }: CollapseButtonProps) {
const onCollapse = () => {
setShouldExpandNode('collapse');
setEnableDefaultButton(true);
}
const isDefault = !shouldExpandNode ||shouldExpandNode === 'default'
if (shouldExpandNode === 'expand' ||(isDefault && expandableDefaultValue === 'expand')) {
return (
<div role="presentation" onClick={onCollapse}>
{collapseIcon || <FontAwesomeIcon icon={faArrowDown} />}
</div>
);
}
return <></>;
}
function DefaultButton({defaultIcon, setEnableDefaultButton, setShouldExpandNode }:DefaultButtonProps) {
const onDefaultCollapse = () => {
setShouldExpandNode('default');
setEnableDefaultButton(false)
}
if (
shouldExpandNode === 'collapse' ||
(isDefault && expandableDefaultValue === 'collapse')
) {
return ( return (
<div role="presentation" onClick={onDefaultCollapse}> <div role="presentation" onClick={onExpand}>
{defaultIcon || <FontAwesomeIcon icon={faUndo} />} {expandIcon || <FontAwesomeIcon icon={faArrowRight} />}
</div> </div>
); );
return <></>;
} }
export default ExpandableButtons return <></>;
}
function CollapseButton({
expandableDefaultValue,
collapseIcon,
}: CollapseButtonProps) {
const { shouldExpandNode, setShouldExpandNode, setEnableDefaultButton } =
useExpandableButtonContext();
const onCollapse = () => {
setShouldExpandNode('collapse');
setEnableDefaultButton(true);
};
const isDefault = !shouldExpandNode || shouldExpandNode === 'default';
if (
shouldExpandNode === 'expand' ||
(isDefault && expandableDefaultValue === 'expand')
) {
return (
<div role="presentation" onClick={onCollapse}>
{collapseIcon || <FontAwesomeIcon icon={faArrowDown} />}
</div>
);
}
return <></>;
}
function DefaultButton({ defaultIcon }: DefaultButtonProps) {
const { setShouldExpandNode, setEnableDefaultButton } =
useExpandableButtonContext();
const onDefaultCollapse = () => {
setShouldExpandNode('default');
setEnableDefaultButton(false);
};
return (
<div role="presentation" onClick={onDefaultCollapse}>
{defaultIcon || <FontAwesomeIcon icon={faUndo} />}
</div>
);
return <></>;
}
export default ExpandableButtons;

View File

@ -0,0 +1,50 @@
import React, {
ReactNode,
createContext,
useContext,
useMemo,
useState,
} from 'react';
import { Expandable } from '.';
import ExpandableButtons from './expandableButtons';
interface Context {
enableDefaultButton: boolean;
setEnableDefaultButton: any;
shouldExpandNode?: 'expand' | 'collapse' | 'default';
setShouldExpandNode: any;
}
interface Props {
children: ReactNode;
expandable?: Expandable;
}
const ExpandableButtonsContext = createContext<Context>({} as Context);
function ExpandableButtonsContextProvider({ expandable, children }: Props) {
const [enableDefaultButton, setEnableDefaultButton] = useState(false);
const [shouldExpandNode, setShouldExpandNode] = useState();
const value = useMemo(
() => ({
enableDefaultButton,
setEnableDefaultButton,
shouldExpandNode,
setShouldExpandNode,
}),
[enableDefaultButton, shouldExpandNode]
);
return (
<ExpandableButtonsContext.Provider value={value}>
{children}
{expandable && <ExpandableButtons expandable={expandable} />}
</ExpandableButtonsContext.Provider>
);
}
export const useExpandableButtonContext = () =>
useContext(ExpandableButtonsContext);
export default ExpandableButtonsContextProvider;

View File

@ -3,12 +3,13 @@
// 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, { ReactNode, useMemo, useState } from 'react'; import React, { ReactNode, useMemo } 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 ExpandableButtonsContext from './expandableButtonsContext';
import type { import type {
CommonExternalProps, CommonExternalProps,
GetItemString, GetItemString,
@ -58,9 +59,6 @@ export function JSONTree({
collectionLimit = 50, collectionLimit = 50,
sortObjectKeys = false, sortObjectKeys = false,
}: Props) { }: Props) {
const [enableDefaultButton, setEnableDefaultButton] = useState(false);
const [shouldExpandNode, setShouldExpandNode] = useState();
const styling = useMemo( const styling = useMemo(
() => () =>
createStylingFromTheme(shouldInvertTheme ? invertTheme(theme) : theme), createStylingFromTheme(shouldInvertTheme ? invertTheme(theme) : theme),
@ -69,31 +67,22 @@ export function JSONTree({
return ( return (
<ul {...styling('tree')}> <ul {...styling('tree')}>
<JSONNode <ExpandableButtonsContext expandable={expandable}>
keyPath={hideRoot ? [] : keyPath} <JSONNode
value={postprocessValue(value)} keyPath={hideRoot ? [] : keyPath}
isCustomNode={isCustomNode} value={postprocessValue(value)}
styling={styling} isCustomNode={isCustomNode}
labelRenderer={labelRenderer} styling={styling}
valueRenderer={valueRenderer} labelRenderer={labelRenderer}
shouldExpandNodeInitially={shouldExpandNodeInitially} valueRenderer={valueRenderer}
shouldExpandNode={shouldExpandNode} shouldExpandNodeInitially={shouldExpandNodeInitially}
setEnableDefaultButton={setEnableDefaultButton} hideRoot={hideRoot}
setShouldExpandNode={setShouldExpandNode} getItemString={getItemString}
hideRoot={hideRoot} postprocessValue={postprocessValue}
getItemString={getItemString} collectionLimit={collectionLimit}
postprocessValue={postprocessValue} sortObjectKeys={sortObjectKeys}
collectionLimit={collectionLimit} />
sortObjectKeys={sortObjectKeys} </ExpandableButtonsContext>
/>
<ExpandableButtons
expandable={expandable}
enableDefaultButton={enableDefaultButton}
setEnableDefaultButton={setEnableDefaultButton}
shouldExpandNode={shouldExpandNode}
setShouldExpandNode={setShouldExpandNode}
/>
</ul> </ul>
); );
} }

View File

@ -53,8 +53,6 @@ export interface CommonExternalProps {
isCustomNode: IsCustomNode; isCustomNode: IsCustomNode;
collectionLimit: number; collectionLimit: number;
sortObjectKeys: SortObjectKeys; sortObjectKeys: SortObjectKeys;
setEnableDefaultButton: any;
setShouldExpandNode: any;
} }
export interface CommonInternalProps extends CommonExternalProps { export interface CommonInternalProps extends CommonExternalProps {
@ -62,5 +60,4 @@ export interface CommonInternalProps extends CommonExternalProps {
circularCache?: CircularCache; circularCache?: CircularCache;
level?: number; level?: number;
isCircular?: boolean; isCircular?: boolean;
shouldExpandNode?: 'expand' | 'collapse' | 'default';
} }