Skip to content

Commit f2c5b4f

Browse files
committed
feat: add beforeCopy callback to Copied component #78
- Add beforeCopy prop to JsonViewProps with rich context parameters (copyText, keyName, value, parentValue, expandKey, keys) - Implement beforeCopy support in Copied component only (not affecting other section components) - Support three-level priority: component prop > section prop > global prop - Add CopiedSectionElement type for section-level beforeCopy customization - Include comprehensive example showing different usage patterns - Allow users to transform copied text based on context information Breaking changes: None New features: - JsonView beforeCopy prop for global copy transformation - JsonView.Copied beforeCopy prop for component-level customization - Rich context parameters for advanced copy transformations
1 parent bd1b1f2 commit f2c5b4f

File tree

6 files changed

+101
-4
lines changed

6 files changed

+101
-4
lines changed

core/src/comps/Copied.tsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,24 @@ export type CopiedOption<T extends object> = {
1313

1414
export interface CopiedProps<T extends object> extends React.SVGProps<SVGSVGElement>, SectionElementResult<T> {
1515
expandKey: string;
16+
beforeCopy?: (
17+
copyText: string,
18+
keyName?: string | number,
19+
value?: T,
20+
parentValue?: T,
21+
expandKey?: string,
22+
keys?: (number | string)[],
23+
) => string;
1624
}
1725

1826
export const Copied = <T extends object, K extends TagType>(props: CopiedProps<T>) => {
19-
const { keyName, value, parentValue, expandKey, keys, ...other } = props;
20-
const { onCopied, enableClipboard } = useStore();
27+
const { keyName, value, parentValue, expandKey, keys, beforeCopy, ...other } = props;
28+
const { onCopied, enableClipboard, beforeCopy: globalBeforeCopy } = useStore();
2129
const showTools = useShowToolsStore();
2230
const isShowTools = showTools[expandKey];
2331
const [copied, setCopied] = useState(false);
2432
const { Copied: Comp = {} } = useSectionStore();
33+
const sectionBeforeCopy = Comp?.beforeCopy;
2534

2635
if (enableClipboard === false || !isShowTools) return null;
2736

@@ -39,6 +48,14 @@ export const Copied = <T extends object, K extends TagType>(props: CopiedProps<T
3948
} else {
4049
copyText = JSON.stringify(value, (_, v) => (typeof v === 'bigint' ? bigIntToString(v) : v), 2);
4150
}
51+
52+
// Apply beforeCopy transformation if provided
53+
// Priority: component prop > section prop > global prop
54+
const finalBeforeCopy = beforeCopy || sectionBeforeCopy || globalBeforeCopy;
55+
if (finalBeforeCopy && typeof finalBeforeCopy === 'function') {
56+
copyText = finalBeforeCopy(copyText, keyName, value, parentValue, expandKey, keys);
57+
}
58+
4259
onCopied && onCopied(copyText, value);
4360
setCopied(true);
4461

core/src/index.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ export interface JsonViewProps<T extends object>
7575
onExpand?: (props: { expand: boolean; value?: T; keyid: string; keyName?: string | number }) => void;
7676
/** Fires event when you copy */
7777
onCopied?: (text: string, value?: T) => void;
78+
/** Transform the text before copying to clipboard */
79+
beforeCopy?: (
80+
copyText: string,
81+
keyName?: string | number,
82+
value?: T,
83+
parentValue?: T,
84+
expandKey?: string,
85+
keys?: (number | string)[],
86+
) => string;
7887
}
7988

8089
type JsonViewComponent = React.FC<React.PropsWithRef<JsonViewProps<object>>> & {
@@ -128,6 +137,7 @@ const JsonView: JsonViewComponent = forwardRef<HTMLDivElement, JsonViewProps<obj
128137
objectSortKeys = false,
129138
onExpand,
130139
onCopied,
140+
beforeCopy,
131141
...elmProps
132142
} = props;
133143
const defaultStyle: CSS.Properties<string | number> = {
@@ -154,6 +164,7 @@ const JsonView: JsonViewComponent = forwardRef<HTMLDivElement, JsonViewProps<obj
154164
highlightUpdates,
155165
onCopied,
156166
onExpand,
167+
beforeCopy,
157168
}}
158169
initialTypes={{ displayDataTypes }}
159170
>

core/src/section/Copied.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,18 @@ import { type TagType } from '../store/Types';
22
import { type SectionElement, useSectionStore } from '../store/Section';
33
import { useSectionRender } from '../utils/useRender';
44

5-
export const Copied = <K extends TagType = 'svg'>(props: SectionElement<K>) => {
5+
export type CopiedSectionElement<T extends TagType = 'svg'> = SectionElement<T> & {
6+
beforeCopy?: (
7+
copyText: string,
8+
keyName?: string | number,
9+
value?: object,
10+
parentValue?: object,
11+
expandKey?: string,
12+
keys?: (number | string)[],
13+
) => string;
14+
};
15+
16+
export const Copied = <K extends TagType = 'svg'>(props: CopiedSectionElement<K>) => {
617
const { Copied: Comp = {} } = useSectionStore();
718
useSectionRender(Comp, props, 'Copied');
819
return null;

core/src/store.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export interface InitialState<T extends object> {
1212
value?: object;
1313
onExpand?: JsonViewProps<object>['onExpand'];
1414
onCopied?: JsonViewProps<object>['onCopied'];
15+
beforeCopy?: JsonViewProps<T>['beforeCopy'];
1516
objectSortKeys?: JsonViewProps<T>['objectSortKeys'];
1617
displayObjectSize?: JsonViewProps<T>['displayObjectSize'];
1718
shortenTextAfterLength?: JsonViewProps<T>['shortenTextAfterLength'];

example/src/BeforeCopyExample.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import React from 'react';
2+
import JsonView from '@uiw/react-json-view';
3+
4+
const example = {
5+
string: 'Hello World',
6+
number: 42,
7+
boolean: true,
8+
nested: {
9+
array: [1, 2, 3],
10+
quote: 'This has "quotes" inside',
11+
},
12+
};
13+
14+
export default function BeforeCopyExample() {
15+
const handleBeforeCopy = (
16+
text: string,
17+
keyName?: string | number,
18+
value?: any,
19+
parentValue?: any,
20+
expandKey?: string,
21+
keys?: (number | string)[],
22+
) => {
23+
console.log('Global beforeCopy context:', { keyName, value, parentValue, expandKey, keys });
24+
25+
// Example: Add key name as comment when copying objects
26+
if (keyName && typeof value === 'object' && value !== null) {
27+
return `// Key: ${keyName}\n${text}`;
28+
}
29+
30+
// Remove all quotes from the copied text
31+
return text.replace(/"/g, '');
32+
};
33+
34+
const handleCopied = (text: string, value?: any) => {
35+
console.log('Copied text:', text);
36+
console.log('Original value:', value);
37+
};
38+
39+
return (
40+
<div>
41+
<h2>beforeCopy Example</h2>
42+
<p>This example shows three ways to use beforeCopy with additional context parameters.</p>
43+
44+
<h3>1. Global beforeCopy (removes quotes and adds comments for objects)</h3>
45+
<JsonView value={example} beforeCopy={handleBeforeCopy} onCopied={handleCopied} displayObjectSize={false} />
46+
47+
<h3>2. Section-level beforeCopy (converts to uppercase)</h3>
48+
<JsonView value={example} onCopied={handleCopied} displayObjectSize={false}>
49+
<JsonView.Copied
50+
beforeCopy={(text, keyName, value) => {
51+
console.log('Section-level beforeCopy:', { text, keyName, value });
52+
return text.toUpperCase();
53+
}}
54+
/>
55+
</JsonView>
56+
</div>
57+
);
58+
}

example/src/demo.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ const example = {
3232

3333
const shouldExpandNodeInitially: ShouldExpandNodeInitially<object> = (isExpanded, props) => {
3434
const { value, level, keyName, parentValue, keys } = props;
35-
console.log('~~~~:', keyName, level, parentValue, keys);
3635
const isArray = Array.isArray(value);
3736
const isObject = typeof value === 'object' && !isArray;
3837
if (isArray) {

0 commit comments

Comments
 (0)