mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-07-27 00:19:55 +03:00
feat: add copyToClipboard button
This commit is contained in:
parent
8e07c1d1d3
commit
25d7b5e8d4
|
@ -190,7 +190,7 @@ const App = () => (
|
||||||
Sort object keys with <code>sortObjectKeys</code> prop.
|
Sort object keys with <code>sortObjectKeys</code> prop.
|
||||||
</p>
|
</p>
|
||||||
<div>
|
<div>
|
||||||
<JSONTree data={data} theme={theme} sortObjectKeys />
|
<JSONTree data={data} theme={theme} sortObjectKeys expandCollapseAll={{}}/>
|
||||||
</div>
|
</div>
|
||||||
<p>Collapsed root node</p>
|
<p>Collapsed root node</p>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -2,9 +2,11 @@ import {
|
||||||
faArrowDown,
|
faArrowDown,
|
||||||
faArrowRight,
|
faArrowRight,
|
||||||
faUndo,
|
faUndo,
|
||||||
|
faCopy,
|
||||||
|
faCheck,
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import React, { ReactNode } from 'react';
|
import React, { ReactNode, useState } from 'react';
|
||||||
import { ExpandCollapseAll } from '.';
|
import { ExpandCollapseAll } from '.';
|
||||||
import { useExpandCollapseAllContext } from './expandCollapseContext';
|
import { useExpandCollapseAllContext } from './expandCollapseContext';
|
||||||
import { StylingFunction } from 'react-base16-styling';
|
import { StylingFunction } from 'react-base16-styling';
|
||||||
|
@ -12,6 +14,7 @@ import { StylingFunction } from 'react-base16-styling';
|
||||||
interface Props {
|
interface Props {
|
||||||
expandCollapseAll: ExpandCollapseAll;
|
expandCollapseAll: ExpandCollapseAll;
|
||||||
styling: StylingFunction;
|
styling: StylingFunction;
|
||||||
|
value: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExpandButtonProps {
|
interface ExpandButtonProps {
|
||||||
|
@ -24,11 +27,17 @@ interface CollapseButtonProps {
|
||||||
collapseIcon?: ReactNode;
|
collapseIcon?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface CopyToClipboardButtonProps {
|
||||||
|
copyToClipboardIcon?: ReactNode;
|
||||||
|
copiedToClipboardIcon?: ReactNode;
|
||||||
|
value: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
interface DefaultButtonProps {
|
interface DefaultButtonProps {
|
||||||
defaultIcon?: ReactNode;
|
defaultIcon?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ExpandCollapseButtons({ expandCollapseAll, styling }: Props) {
|
function ExpandCollapseButtons({ expandCollapseAll, styling, value }: Props) {
|
||||||
const { enableDefaultButton } = useExpandCollapseAllContext();
|
const { enableDefaultButton } = useExpandCollapseAllContext();
|
||||||
|
|
||||||
const expandableDefaultValue = expandCollapseAll?.defaultValue || 'expand';
|
const expandableDefaultValue = expandCollapseAll?.defaultValue || 'expand';
|
||||||
|
@ -39,6 +48,12 @@ function ExpandCollapseButtons({ expandCollapseAll, styling }: Props) {
|
||||||
<DefaultButton defaultIcon={expandCollapseAll?.defaultIcon} />
|
<DefaultButton defaultIcon={expandCollapseAll?.defaultIcon} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<CopyToClipboardButton
|
||||||
|
copyToClipboardIcon={expandCollapseAll?.copyToClipboardIcon}
|
||||||
|
copiedToClipboardIcon={expandCollapseAll?.copiedToClipboardIcon}
|
||||||
|
value={value}
|
||||||
|
/>
|
||||||
|
|
||||||
<ExpandButton
|
<ExpandButton
|
||||||
expandableDefaultValue={expandableDefaultValue}
|
expandableDefaultValue={expandableDefaultValue}
|
||||||
expandIcon={expandCollapseAll?.expandIcon}
|
expandIcon={expandCollapseAll?.expandIcon}
|
||||||
|
@ -108,6 +123,26 @@ function CollapseButton({
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function CopyToClipboardButton({copyToClipboardIcon, copiedToClipboardIcon, value}:CopyToClipboardButtonProps) {
|
||||||
|
const [isCopied, setIsCopied] = useState(false);
|
||||||
|
|
||||||
|
const handleOnCopyToClipboard = async () => {
|
||||||
|
await navigator.clipboard.writeText(JSON.stringify(value, null, 2));
|
||||||
|
setIsCopied(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isCopied){
|
||||||
|
return (<div role="presentation" onClick={handleOnCopyToClipboard}>
|
||||||
|
{copiedToClipboardIcon || <FontAwesomeIcon icon={faCheck} />}
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div role="presentation" onClick={handleOnCopyToClipboard}>
|
||||||
|
{copyToClipboardIcon || <FontAwesomeIcon icon={faCopy} />}
|
||||||
|
</div>)
|
||||||
|
}
|
||||||
|
|
||||||
function DefaultButton({ defaultIcon }: DefaultButtonProps) {
|
function DefaultButton({ defaultIcon }: DefaultButtonProps) {
|
||||||
const { setExpandAllState, setEnableDefaultButton } =
|
const { setExpandAllState, setEnableDefaultButton } =
|
||||||
useExpandCollapseAllContext();
|
useExpandCollapseAllContext();
|
||||||
|
@ -122,8 +157,6 @@ function DefaultButton({ defaultIcon }: DefaultButtonProps) {
|
||||||
{defaultIcon || <FontAwesomeIcon icon={faUndo} />}
|
{defaultIcon || <FontAwesomeIcon icon={faUndo} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
return <></>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ExpandCollapseButtons;
|
export default ExpandCollapseButtons;
|
||||||
|
|
|
@ -20,6 +20,7 @@ interface Props {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
expandCollapseAll?: ExpandCollapseAll;
|
expandCollapseAll?: ExpandCollapseAll;
|
||||||
styling: StylingFunction;
|
styling: StylingFunction;
|
||||||
|
value: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExpandCollapseAllContext = createContext<Context>({} as Context);
|
const ExpandCollapseAllContext = createContext<Context>({} as Context);
|
||||||
|
@ -28,11 +29,12 @@ function ExpandCollapseAllContextProvider({
|
||||||
expandCollapseAll,
|
expandCollapseAll,
|
||||||
children,
|
children,
|
||||||
styling,
|
styling,
|
||||||
|
value,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [enableDefaultButton, setEnableDefaultButton] = useState(false);
|
const [enableDefaultButton, setEnableDefaultButton] = useState(false);
|
||||||
const [expandAllState, setExpandAllState] = useState();
|
const [expandAllState, setExpandAllState] = useState();
|
||||||
|
|
||||||
const value = useMemo(
|
const contextValue = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
enableDefaultButton,
|
enableDefaultButton,
|
||||||
setEnableDefaultButton,
|
setEnableDefaultButton,
|
||||||
|
@ -43,12 +45,13 @@ function ExpandCollapseAllContextProvider({
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ExpandCollapseAllContext.Provider value={value}>
|
<ExpandCollapseAllContext.Provider value={contextValue}>
|
||||||
{children}
|
{children}
|
||||||
{expandCollapseAll && (
|
{expandCollapseAll && (
|
||||||
<ExpandCollapseButtons
|
<ExpandCollapseButtons
|
||||||
expandCollapseAll={expandCollapseAll}
|
expandCollapseAll={expandCollapseAll}
|
||||||
styling={styling}
|
styling={styling}
|
||||||
|
value={value}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</ExpandCollapseAllContext.Provider>
|
</ExpandCollapseAllContext.Provider>
|
||||||
|
|
|
@ -29,6 +29,8 @@ interface ExpandCollapseAll {
|
||||||
defaultValue?: 'expand' | 'collapse';
|
defaultValue?: 'expand' | 'collapse';
|
||||||
expandIcon?: ReactNode;
|
expandIcon?: ReactNode;
|
||||||
collapseIcon?: ReactNode;
|
collapseIcon?: ReactNode;
|
||||||
|
copyToClipboardIcon?: ReactNode;
|
||||||
|
copiedToClipboardIcon?: ReactNode;
|
||||||
defaultIcon?: ReactNode;
|
defaultIcon?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +72,7 @@ export function JSONTree({
|
||||||
<ExpandCollapseAllButtonsContext
|
<ExpandCollapseAllButtonsContext
|
||||||
expandCollapseAll={expandCollapseAll}
|
expandCollapseAll={expandCollapseAll}
|
||||||
styling={styling}
|
styling={styling}
|
||||||
|
value={value}
|
||||||
>
|
>
|
||||||
<JSONNode
|
<JSONNode
|
||||||
keyPath={hideRoot ? [] : keyPath}
|
keyPath={hideRoot ? [] : keyPath}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user