Skip to content

Commit

Permalink
feat: support copy everything
Browse files Browse the repository at this point in the history
  • Loading branch information
blucas.wu committed Aug 31, 2023
1 parent 44ad4de commit cc07066
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 84 deletions.
18 changes: 15 additions & 3 deletions examples/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,26 @@ const App = () => {
<span
className="absolute inline-block inset-0 bg-pink-400"
style={{
transform: 'skewY(-2deg)',
transform: 'skewY(-2deg)'
}}
></span>
</span>{' '}
is a react component for displaying serializable data.
</p>
<p>
You can open the repo{' '}
You can open the Github repo
<svg
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 24 24"
style={{ transform: 'translateY(10px)', marginInline: 6 }}
>
<path
fill="currentColor"
d="M12 2A10 10 0 0 0 2 12c0 4.42 2.87 8.17 6.84 9.5c.5.08.66-.23.66-.5v-1.69c-2.77.6-3.36-1.34-3.36-1.34c-.46-1.16-1.11-1.47-1.11-1.47c-.91-.62.07-.6.07-.6c1 .07 1.53 1.03 1.53 1.03c.87 1.52 2.34 1.07 2.91.83c.09-.65.35-1.09.63-1.34c-2.22-.25-4.55-1.11-4.55-4.92c0-1.11.38-2 1.03-2.71c-.1-.25-.45-1.29.1-2.64c0 0 .84-.27 2.75 1.02c.79-.22 1.65-.33 2.5-.33c.85 0 1.71.11 2.5.33c1.91-1.29 2.75-1.02 2.75-1.02c.55 1.35.2 2.39.1 2.64c.65.71 1.03 1.6 1.03 2.71c0 3.82-2.34 4.66-4.57 4.91c.36.31.69.92.69 1.85V21c0 .27.16.59.67.5C19.14 20.16 22 16.42 22 12A10 10 0 0 0 12 2Z"
/>
</svg>
<a
href="https://github.com/HuolalaTech/react-json-view"
className="text-purple-500"
Expand Down Expand Up @@ -92,7 +104,7 @@ const App = () => {
darkMode: mode === 'dark',
originSource,
renderSource,
rjvProps: item.props,
rjvProps: item.props
}}
/>
</div>
Expand Down
12 changes: 3 additions & 9 deletions examples/components/SourceRender/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,8 @@ const ExchangeIcon = (props: React.SVGAttributes<Element>) => {
viewBox="0 0 24 24"
{...props}
>
<path
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M7 10h14l-4-4m0 8H3l4 4"
/>
<path fill="currentColor" d="M15.5 5H11l5 7l-5 7h4.5l5-7z" />
<path fill="currentColor" d="M8.5 5H4l5 7l-5 7h4.5l5-7z" />
</svg>
);
};
Expand Down Expand Up @@ -50,7 +44,7 @@ export const SourceRender = ({
darkMode,
originSource,
renderSource,
rjvProps,
rjvProps
}: Props) => {
return (
<div className="flex justify-evenly">
Expand Down
46 changes: 21 additions & 25 deletions src/ReactJsonView/components/CopyContent.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import { Fragment, useCallback, useMemo } from 'react';
import { useCallback, useMemo } from 'react';
import copy from 'copy-to-clipboard';
import React from 'react';
import { cutOffStringLiteral, useSwitchWithDelay } from '../../utils';
import React, { MouseEvent } from 'react';
import { useSwitchWithDelay } from '../../utils';
import { CheckMark, CrossMark, TextCopy } from './SvgIcon';

interface Props {
content: string;
data: string;
}

const CopyContent: React.FC<Props> = ({ content }) => {
const Copyable: React.FC<Props> = ({ data }) => {
const [state, switchState] = useSwitchWithDelay(0);
const computedContent = useMemo(() => {
if (typeof content !== 'string') return content;
return cutOffStringLiteral(content);
}, [content]);

const onCopy = useCallback(() => {
if (state !== 0) return;
const copyResult = copy(`${content}`);
if (copyResult) {
switchState(1);
} else {
switchState(-1);
}
}, [content, state, switchState]);
const onCopy = useCallback(
(e: MouseEvent<HTMLSpanElement>) => {
e.stopPropagation();
if (state !== 0) return;
const copyResult = copy(`${data}`);
if (copyResult) {
switchState(1);
} else {
switchState(-1);
}
},
[data, state, switchState]
);

const icon = useMemo(() => {
let Icon = TextCopy;
Expand All @@ -43,17 +43,13 @@ const CopyContent: React.FC<Props> = ({ content }) => {
return <Icon width={14} height={14} color={color} />;
}, [state]);

if (computedContent === content)
return React.createElement(Fragment, null, content);

return (
<span className="copyable">
<span className="copyable-content">{computedContent}</span>
<span className="copyable-icon" onClick={onCopy}>
<span className="rjv-copyable">
<span className="rjv-copyable-icon" onClick={onCopy}>
{icon}
</span>
</span>
);
};

export default CopyContent;
export default Copyable;
47 changes: 33 additions & 14 deletions src/ReactJsonView/components/JsonNode.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
import { useState, useMemo, ReactNode } from 'react';
import { useState, useMemo, ReactNode, Fragment } from 'react';
import {
clsx,
cutOffStringLiteral,
isBoolean,
isListOrMap,
isNumber,
shortTitle,
shortTitle
} from '../../utils';
import { ArrowRight } from './SvgIcon';
import { useConfigInfo } from './ConfigContext';
import CopyContent from './CopyContent';
import LazyLoadMore from './LazyLoadMore';
import { Options } from '../../../types';
import React from 'react';
import Copyable from './CopyContent';

const PrimitiveContent = ({ content }: { content: React.ReactNode }) => {
const computedContent = useMemo(() => {
if (typeof content !== 'string') return content;
return cutOffStringLiteral(content);
}, [content]);

return React.createElement(Fragment, null, computedContent);
};

const JsonNode = ({
source = null,
depth = 1,
label = '',
label = ''
}: {
source: Options['source'];
depth?: number;
Expand Down Expand Up @@ -49,15 +60,15 @@ const JsonNode = ({

let className = '';
const type = typeof data;
const primitiveType = ['string', 'number', 'symbol', 'boolean', 'undefined'];
const primitiveType = ['string', 'number', 'boolean'];
if (primitiveType.indexOf(type) > -1) {
className = type;
} else if (data === null) {
className = 'null';
}
if (className) {
return (
<code>
<code className="rjv-primitive">
{labelContent && (
<>
<span style={{ opacity: 0 }}>
Expand All @@ -66,9 +77,10 @@ const JsonNode = ({
{labelContent}
</>
)}
<span className={clsx('rjv-type-node', className)}>
<CopyContent content={`${data}`} />
<span className={clsx('rjv-primitive-type', className)}>
<PrimitiveContent content={`${data}`} />
</span>
<Copyable data={JSON.stringify(data, null, 2)} />
</code>
);
}
Expand All @@ -77,20 +89,27 @@ const JsonNode = ({
const title = shortTitle(data, maxTitleSize);

return (
<div className="rjv-node">
<div className="rjv-node__title" onClick={() => setExpanded(!expanded)}>
<div className="rjv-ref">
<div
className="rjv-ref-title"
onClick={() => setExpanded(!expanded)}
data-depth={depth - 1}
>
<ArrowRight
width={10}
height={10}
className={clsx('rjv-node__spread-controller', {
spread: expanded,
className={clsx('rjv-ref-arrow', {
spread: expanded
})}
/>
{labelContent}
{(!label || !expanded) && <code>{title}</code>}
{(!label || !expanded) && (
<code className="rjv-node__property-value">{title}</code>
)}
<Copyable data={JSON.stringify(data, null, 2)} />
</div>
{expanded && (
<div className="rjv-node__property" data-depth={depth}>
<div className="rjv-ref-property">
<LazyLoadMore
list={Object.keys(data)}
render={(key) => (
Expand Down
77 changes: 45 additions & 32 deletions src/ReactJsonView/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,30 @@
@fontFamily: SFMono-Regular, Consolas, Liberation Mono, Menlo, Courier,
monospace;

.rjv-node {
font-size: @fontSize;
line-height: 1.4;
.rjv-ref {
code {
font-family: @fontFamily;
}
&__title {
&-node {
font-size: @fontSize;
line-height: 1.4;
}
&-title {
cursor: default;
}
&__spread-controller {
&-arrow {
transform: rotateZ(0);
transform-origin: 35% center;
transition: transform linear 0.1s;
&.spread {
transform: rotateZ(90deg);
}
}
&__property {
&-property {
margin-left: 12px;
&-key {
font-size: @fontSize;
font-family: @fontFamily;
color: #7d237c;
}
}
.rjv-load-more {
color: #7d237c;
font-size: 13px;
> span {
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
}
}
.rjv-type-node {
.rjv-primitive-type {
font-size: @fontSize;
font-family: @fontFamily;
&.number,
Expand All @@ -54,15 +41,6 @@
&::after {
content: '"';
}
.copyable {
&-icon {
position: absolute;
right: 0;
bottom: 0;
transform: translate(17px, 4px);
cursor: pointer;
}
}
}
&.symbol {
color: #be3c31;
Expand All @@ -76,12 +54,47 @@
}
}

.rjv-node__property-key {
font-size: @fontSize;
font-family: @fontFamily;
color: #7d237c;
}

.rjv-load-more {
color: #7d237c;
font-size: 13px;
> span {
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
}

.rjv-copyable {
display: inline-block;
margin-left: 4px;
cursor: pointer;
visibility: hidden;
transform: translateY(2px);
}


.rjv-primitive,
.rjv-ref-title {
&:hover {
.rjv-copyable {
visibility: visible;
}
}
}

[data-dark-mode='true'] {
.rjv-node__property-key,
.rjv-load-more {
color: #70afd3;
}
.rjv-type-node {
.rjv-primitive-type {
&.number,
&.boolean {
color: #9384f7;
Expand Down
2 changes: 1 addition & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export function shortTitle(data: any, max = 100) {
if (typeof curVal === 'string') {
curVal = cutOffStringLiteral(curVal);
}
const curStr = `${key}: ${JSON.stringify(curVal)}`;
const curStr = `"${key}": ${JSON.stringify(curVal)}`;
const result = `${content}${curStr}, `;
if (result.length > max) {
hasEllipsis = true;
Expand Down

0 comments on commit cc07066

Please sign in to comment.