Skip to content

Commit

Permalink
feat: support props.onCopy (#113)
Browse files Browse the repository at this point in the history
  • Loading branch information
himself65 authored Nov 7, 2022
1 parent de53af1 commit da757e1
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 25 deletions.
7 changes: 2 additions & 5 deletions src/components/DataKeyPair.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,8 @@ export const DataKeyPair: React.FC<DataKeyPairProps> = (props) => {
event.preventDefault()
try {
copy(
JSON.stringify(
typeof value === 'function' ? value.toString() : value,
null,
' '
)
path,
value
)
} catch (e) {
// in some case, this will throw error
Expand Down
55 changes: 45 additions & 10 deletions src/hooks/useCopyToClipboard.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import copyToClipboard from 'copy-to-clipboard'
import { useCallback, useRef, useState } from 'react'

import { useJsonViewerStore } from '../stores/JsonViewerStore'
import type { JsonViewerOnCopy } from '../type'

/**
* 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
Expand All @@ -19,19 +22,51 @@ export function useClipboard ({ timeout = 2000 } = {}) {
copyTimeout.current = window.setTimeout(() => setCopied(false), timeout)
setCopied(value)
}, [timeout])
const onCopy = useJsonViewerStore(store => store.onCopy)

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))
const copy = useCallback<JsonViewerOnCopy>((path, value: unknown) => {
if (typeof onCopy === 'function') {
try {
const result = onCopy(path, value)
if (result instanceof Promise) {
result.then(() => {
handleCopyResult(true)
}).catch((error) => {
console.error(
`error when copy ${path.length === 0
? 'src'
: `src[${path.join(
'.')}`
}]`, error)
})
} else {
handleCopyResult(true)
}
} catch (error) {
console.error(
`error when copy ${path.length === 0
? 'src'
: `src[${path.join(
'.')}`
}]`, error)
}
} else {
// fallback to copy-to-clipboard when navigator.clipboard is not available
copyToClipboard(valueToCopy)
const valueToCopy = JSON.stringify(
typeof value === 'function' ? value.toString() : value,
null,
' '
)
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])
}, [handleCopyResult, onCopy])

const reset = useCallback(() => {
setCopied(false)
Expand Down
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const JsonViewerInner: React.FC<JsonViewerProps> = (props) => {
useSetIfNotUndefinedEffect('rootName', props.rootName)
useSetIfNotUndefinedEffect('displayDataTypes', props.displayDataTypes)
useSetIfNotUndefinedEffect('displayObjectSize', props.displayObjectSize)
useSetIfNotUndefinedEffect('onCopy', props.onCopy)
useEffect(() => {
if (props.theme === 'light') {
api.setState({
Expand Down
9 changes: 8 additions & 1 deletion src/stores/JsonViewerStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import create from 'zustand'
import createContext from 'zustand/context'
import { combine } from 'zustand/middleware'

import type { JsonViewerOnChange, JsonViewerProps, Path } from '..'
import type {
JsonViewerOnChange,
JsonViewerOnCopy,
JsonViewerProps,
Path
} from '..'
import type { Colorspace } from '../theme/base16'
import { lightColorspace } from '../theme/base16'
import type { JsonViewerKeyRenderer } from '../type'
Expand All @@ -28,6 +33,7 @@ export type JsonViewerState<T = unknown> = {
rootName: false | string
value: T
onChange: JsonViewerOnChange
onCopy: JsonViewerOnCopy | undefined
keyRenderer: JsonViewerKeyRenderer
displayObjectSize: boolean
}
Expand All @@ -54,6 +60,7 @@ export const createJsonViewerStore = <T = unknown> (props: JsonViewerProps<T>) =
maxDisplayLength: props.maxDisplayLength ?? 30,
rootName: props.rootName ?? 'root',
onChange: props.onChange ?? (() => {}),
onCopy: props.onCopy ?? undefined,
keyRenderer: props.keyRenderer ?? DefaultKeyRenderer,
editable: props.editable ?? false,
defaultInspectDepth: props.defaultInspectDepth ?? 5,
Expand Down
27 changes: 18 additions & 9 deletions src/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,24 @@ import type { Colorspace } from './theme/base16'

export type Path = (string | number)[]

/**
* @param path path to the target value
* @param oldValue
* @param newValue
*/
export type JsonViewerOnChange = <U = unknown>(
path: (string | number)[], oldValue: U,
path: Path, oldValue: U,
newValue: U /*, type: ChangeType */) => void

/**
* @param path path to the target value
* @param value
*/
export type JsonViewerOnCopy = <U = unknown>(
path: Path,
value: U
) => unknown | Promise<unknown>

export interface DataItemProps<ValueType = unknown> {
inspect: boolean
setInspect: Dispatch<SetStateAction<boolean>>
Expand All @@ -33,7 +47,7 @@ export type DataType<ValueType = unknown> = {
}

export interface JsonViewerKeyRenderer extends React.FC<DataItemProps> {
when(props: DataItemProps): boolean
when (props: DataItemProps): boolean
}

export type JsonViewerTheme = 'light' | 'dark' | 'auto' | Colorspace
Expand All @@ -59,13 +73,8 @@ export type JsonViewerProps<T = unknown> = {
*/
keyRenderer?: JsonViewerKeyRenderer
valueTypes?: DataType<any>[]
/**
*
* @param path path to the target value
* @param oldValue
* @param newValue
*/
onChange?: <U>(path: Path, oldValue: U, newValue: U) => void
onChange?: JsonViewerOnChange
onCopy?: JsonViewerOnCopy
/**
* Whether enable clipboard feature.
*
Expand Down

0 comments on commit da757e1

Please sign in to comment.