Skip to content

Commit da757e1

Browse files
authored
feat: support props.onCopy (#113)
1 parent de53af1 commit da757e1

File tree

5 files changed

+74
-25
lines changed

5 files changed

+74
-25
lines changed

src/components/DataKeyPair.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,8 @@ export const DataKeyPair: React.FC<DataKeyPairProps> = (props) => {
113113
event.preventDefault()
114114
try {
115115
copy(
116-
JSON.stringify(
117-
typeof value === 'function' ? value.toString() : value,
118-
null,
119-
' '
120-
)
116+
path,
117+
value
121118
)
122119
} catch (e) {
123120
// in some case, this will throw error

src/hooks/useCopyToClipboard.ts

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import copyToClipboard from 'copy-to-clipboard'
22
import { useCallback, useRef, useState } from 'react'
33

4+
import { useJsonViewerStore } from '../stores/JsonViewerStore'
5+
import type { JsonViewerOnCopy } from '../type'
6+
47
/**
58
* useClipboard hook accepts one argument options in which copied status timeout duration is defined (defaults to 2000). Hook returns object with properties:
69
* - copy – function to copy value to clipboard
@@ -19,19 +22,51 @@ export function useClipboard ({ timeout = 2000 } = {}) {
1922
copyTimeout.current = window.setTimeout(() => setCopied(false), timeout)
2023
setCopied(value)
2124
}, [timeout])
25+
const onCopy = useJsonViewerStore(store => store.onCopy)
2226

23-
const copy = useCallback((valueToCopy: string) => {
24-
if ('clipboard' in navigator) {
25-
navigator.clipboard
26-
.writeText(valueToCopy)
27-
.then(() => handleCopyResult(true))
28-
// When navigator.clipboard throws an error, fallback to copy-to-clipboard package
29-
.catch(() => copyToClipboard(valueToCopy))
27+
const copy = useCallback<JsonViewerOnCopy>((path, value: unknown) => {
28+
if (typeof onCopy === 'function') {
29+
try {
30+
const result = onCopy(path, value)
31+
if (result instanceof Promise) {
32+
result.then(() => {
33+
handleCopyResult(true)
34+
}).catch((error) => {
35+
console.error(
36+
`error when copy ${path.length === 0
37+
? 'src'
38+
: `src[${path.join(
39+
'.')}`
40+
}]`, error)
41+
})
42+
} else {
43+
handleCopyResult(true)
44+
}
45+
} catch (error) {
46+
console.error(
47+
`error when copy ${path.length === 0
48+
? 'src'
49+
: `src[${path.join(
50+
'.')}`
51+
}]`, error)
52+
}
3053
} else {
31-
// fallback to copy-to-clipboard when navigator.clipboard is not available
32-
copyToClipboard(valueToCopy)
54+
const valueToCopy = JSON.stringify(
55+
typeof value === 'function' ? value.toString() : value,
56+
null,
57+
' '
58+
)
59+
if ('clipboard' in navigator) {
60+
navigator.clipboard.writeText(valueToCopy)
61+
.then(() => handleCopyResult(true))
62+
// When navigator.clipboard throws an error, fallback to copy-to-clipboard package
63+
.catch(() => copyToClipboard(valueToCopy))
64+
} else {
65+
// fallback to copy-to-clipboard when navigator.clipboard is not available
66+
copyToClipboard(valueToCopy)
67+
}
3368
}
34-
}, [handleCopyResult])
69+
}, [handleCopyResult, onCopy])
3570

3671
const reset = useCallback(() => {
3772
setCopied(false)

src/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ const JsonViewerInner: React.FC<JsonViewerProps> = (props) => {
5656
useSetIfNotUndefinedEffect('rootName', props.rootName)
5757
useSetIfNotUndefinedEffect('displayDataTypes', props.displayDataTypes)
5858
useSetIfNotUndefinedEffect('displayObjectSize', props.displayObjectSize)
59+
useSetIfNotUndefinedEffect('onCopy', props.onCopy)
5960
useEffect(() => {
6061
if (props.theme === 'light') {
6162
api.setState({

src/stores/JsonViewerStore.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import create from 'zustand'
33
import createContext from 'zustand/context'
44
import { combine } from 'zustand/middleware'
55

6-
import type { JsonViewerOnChange, JsonViewerProps, Path } from '..'
6+
import type {
7+
JsonViewerOnChange,
8+
JsonViewerOnCopy,
9+
JsonViewerProps,
10+
Path
11+
} from '..'
712
import type { Colorspace } from '../theme/base16'
813
import { lightColorspace } from '../theme/base16'
914
import type { JsonViewerKeyRenderer } from '../type'
@@ -28,6 +33,7 @@ export type JsonViewerState<T = unknown> = {
2833
rootName: false | string
2934
value: T
3035
onChange: JsonViewerOnChange
36+
onCopy: JsonViewerOnCopy | undefined
3137
keyRenderer: JsonViewerKeyRenderer
3238
displayObjectSize: boolean
3339
}
@@ -54,6 +60,7 @@ export const createJsonViewerStore = <T = unknown> (props: JsonViewerProps<T>) =
5460
maxDisplayLength: props.maxDisplayLength ?? 30,
5561
rootName: props.rootName ?? 'root',
5662
onChange: props.onChange ?? (() => {}),
63+
onCopy: props.onCopy ?? undefined,
5764
keyRenderer: props.keyRenderer ?? DefaultKeyRenderer,
5865
editable: props.editable ?? false,
5966
defaultInspectDepth: props.defaultInspectDepth ?? 5,

src/type.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,24 @@ import type { Colorspace } from './theme/base16'
55

66
export type Path = (string | number)[]
77

8+
/**
9+
* @param path path to the target value
10+
* @param oldValue
11+
* @param newValue
12+
*/
813
export type JsonViewerOnChange = <U = unknown>(
9-
path: (string | number)[], oldValue: U,
14+
path: Path, oldValue: U,
1015
newValue: U /*, type: ChangeType */) => void
1116

17+
/**
18+
* @param path path to the target value
19+
* @param value
20+
*/
21+
export type JsonViewerOnCopy = <U = unknown>(
22+
path: Path,
23+
value: U
24+
) => unknown | Promise<unknown>
25+
1226
export interface DataItemProps<ValueType = unknown> {
1327
inspect: boolean
1428
setInspect: Dispatch<SetStateAction<boolean>>
@@ -33,7 +47,7 @@ export type DataType<ValueType = unknown> = {
3347
}
3448

3549
export interface JsonViewerKeyRenderer extends React.FC<DataItemProps> {
36-
when(props: DataItemProps): boolean
50+
when (props: DataItemProps): boolean
3751
}
3852

3953
export type JsonViewerTheme = 'light' | 'dark' | 'auto' | Colorspace
@@ -59,13 +73,8 @@ export type JsonViewerProps<T = unknown> = {
5973
*/
6074
keyRenderer?: JsonViewerKeyRenderer
6175
valueTypes?: DataType<any>[]
62-
/**
63-
*
64-
* @param path path to the target value
65-
* @param oldValue
66-
* @param newValue
67-
*/
68-
onChange?: <U>(path: Path, oldValue: U, newValue: U) => void
76+
onChange?: JsonViewerOnChange
77+
onCopy?: JsonViewerOnCopy
6978
/**
7079
* Whether enable clipboard feature.
7180
*

0 commit comments

Comments
 (0)