diff --git a/src/components/DataKeyPair.tsx b/src/components/DataKeyPair.tsx
index 76bf006e..bad294d0 100644
--- a/src/components/DataKeyPair.tsx
+++ b/src/components/DataKeyPair.tsx
@@ -5,11 +5,11 @@ import {
Edit as EditIcon
} from '@mui/icons-material'
import { Box, styled } from '@mui/material'
-import copy from 'copy-to-clipboard'
import type React from 'react'
import { useCallback, useMemo, useState } from 'react'
import { useTextColor } from '../hooks/useColor'
+import { useClipboard } from '../hooks/useCopyToClipboard'
import { useInspect } from '../hooks/useInspect'
import { useJsonViewerStore } from '../stores/JsonViewerStore'
import { useTypeComponents } from '../stores/typeRegistry'
@@ -22,7 +22,7 @@ export type DataKeyPairProps = {
path: (string | number)[]
}
-const IconBox = styled(props => )`
+const IconBox = styled(props => )`
cursor: pointer;
padding-left: 0.7rem;
` as typeof Box
@@ -56,6 +56,8 @@ export const DataKeyPair: React.FC = (props) => {
setInspect,
value
}), [inspect, path, setInspect, value])
+ const { copy, copied } = useClipboard()
+
const actionIcons = useMemo(() => {
if (editing) {
return (
@@ -101,11 +103,23 @@ export const DataKeyPair: React.FC = (props) => {
event.preventDefault()
}}
>
-
+ {
+ copied
+ ? (
+
+ )
+ : (
+
+ )
+ }
{/* todo: support edit object */}
{Editor &&
@@ -126,15 +140,15 @@ export const DataKeyPair: React.FC = (props) => {
}
>
)
- }, [Editor, editing, onChange, path, tempValue, value])
+ }, [Editor, copied, copy, editing, onChange, path, tempValue, value])
const expandable = PreComponent && PostComponent
const KeyRenderer = useJsonViewerStore(store => store.keyRenderer)
return (
setHover(path), [setHover, path])
- }
+ onMouseEnter={
+ useCallback(() => setHover(path), [setHover, path])
+ }
>
= (props) => {
>
{
KeyRenderer.when(downstreamProps)
- ?
+ ?
: !props.nested && (
isNumberKey
? {displayKey}
+ style={{ color: numberKeyColor }}>{displayKey}
: <>"{displayKey}">
)
}
@@ -169,18 +183,18 @@ export const DataKeyPair: React.FC = (props) => {
:
)
}
- {PreComponent && }
+ {PreComponent && }
{(isHover && expandable && inspect) && actionIcons}
{
editing
- ? (Editor && )
+ ? (Editor && )
: (Component)
- ?
+ ?
: {`fallback: ${value}`}
+ className='data-value-fallback'>{`fallback: ${value}`}
}
- {PostComponent && }
+ {PostComponent && }
{(isHover && expandable && !inspect) && actionIcons}
{(isHover && !expandable) && actionIcons}
diff --git a/src/hooks/useCopyToClipboard.ts b/src/hooks/useCopyToClipboard.ts
new file mode 100644
index 00000000..5c72f66b
--- /dev/null
+++ b/src/hooks/useCopyToClipboard.ts
@@ -0,0 +1,43 @@
+import copyToClipboard from 'copy-to-clipboard'
+import { useCallback, useRef, useState } from 'react'
+
+/**
+ * useClipboard hook accepts one argument options in which copied status timeout duration is defined (defaults to 2000). Hook returns object with properties:
+ * - copy – function to copy value to clipboard
+ * - copied – value that indicates that copy handler was called less than options.timeout ms ago
+ * - reset – function to clear timeout and reset copied to false
+ */
+export function useClipboard ({ timeout = 2000 } = {}) {
+ const [copied, setCopied] = useState(false)
+ const copyTimeout = useRef(null)
+
+ const handleCopyResult = useCallback((value: boolean) => {
+ if (copyTimeout.current) {
+ clearTimeout(copyTimeout.current)
+ }
+ copyTimeout.current = setTimeout(() => setCopied(false), timeout)
+ setCopied(value)
+ }, [timeout])
+
+ const copy = useCallback((valueToCopy: string) => {
+ if ('clipboard' in navigator) {
+ navigator.clipboard
+ .writeText(valueToCopy)
+ .then(() => handleCopyResult(true))
+ // When navigator.clipboard throws an error, fallback to copy-to-clipboard package
+ .catch(() => copyToClipboard(valueToCopy))
+ } else {
+ // fallback to copy-to-clipboard when navigator.clipboard is not available
+ copyToClipboard(valueToCopy)
+ }
+ }, [handleCopyResult])
+
+ const reset = useCallback(() => {
+ setCopied(false)
+ if (copyTimeout.current) {
+ clearTimeout(copyTimeout.current)
+ }
+ }, [])
+
+ return { copy, reset, copied }
+}