Skip to content

Commit 36466f9

Browse files
committedMar 7, 2023
feat: refactor code.
1 parent 3d7e0a1 commit 36466f9

File tree

11 files changed

+498
-240
lines changed

11 files changed

+498
-240
lines changed
 

‎core/README.md

+204-94
Large diffs are not rendered by default.

‎core/src/Code.tsx

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React, { useContext } from 'react';
2+
import { Context } from './store';
3+
import { CODE_PREVIEW_PREFIX } from './CodePreview';
4+
5+
export interface CodeProps extends React.HTMLAttributes<HTMLDivElement> {}
6+
7+
export const Code = React.forwardRef<HTMLDivElement, CodeProps>((props, ref) => {
8+
const { className, children, ...htmlProps } = props;
9+
const cls = [`${CODE_PREVIEW_PREFIX}-code`, className].filter(Boolean).join(' ').trim();
10+
const store = useContext(Context);
11+
if (store.collapse) {
12+
return null;
13+
}
14+
return (
15+
<div {...htmlProps} className={cls} ref={ref}>
16+
{children}
17+
</div>
18+
);
19+
});
20+
21+
Code.displayName = 'uiw.CodeLayoutCode';

‎core/src/CodePreview.tsx

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import React from 'react';
2+
import { Code } from './Code';
3+
import { Preview } from './Preview';
4+
import { Toolbar } from './Toolbar';
5+
import { Provider } from './store';
6+
import './styles.css';
7+
8+
export const CODE_PREVIEW_PREFIX = 'w-rcpl';
9+
10+
export interface CodePreviewProps extends React.HTMLAttributes<HTMLDivElement> {
11+
prefixCls?: string;
12+
/**
13+
* Whether border is required
14+
* @default true
15+
*/
16+
bordered?: boolean;
17+
/** disable checkered */
18+
disableCheckered?: boolean;
19+
}
20+
21+
const Internal = React.forwardRef<HTMLDivElement, CodePreviewProps>((props, ref) => {
22+
const {
23+
children,
24+
prefixCls = CODE_PREVIEW_PREFIX,
25+
className,
26+
bordered = true,
27+
disableCheckered,
28+
...divProps
29+
} = props;
30+
const cls = [prefixCls, className, bordered ? `w-bordered` : null, disableCheckered ? `w-disable-checkered` : null]
31+
.filter(Boolean)
32+
.join(' ')
33+
.trim();
34+
return (
35+
<div ref={ref} {...divProps} className={cls}>
36+
{React.Children.map(children, (child: React.ReactNode, key) => {
37+
if (!React.isValidElement(child)) return child;
38+
return React.cloneElement(child, { ...child.props, key });
39+
})}
40+
</div>
41+
);
42+
});
43+
44+
const InternalCodePreview = (props: CodePreviewProps, ref?: React.ForwardedRef<HTMLDivElement>) => {
45+
return (
46+
<Provider value={{ collapse: false }}>
47+
<Internal {...props} ref={ref} />
48+
</Provider>
49+
);
50+
};
51+
52+
type CodePreviewComponent = React.FC<React.PropsWithRef<CodePreviewProps>> & {
53+
Preview: typeof Preview;
54+
Code: typeof Code;
55+
Toolbar: typeof Toolbar;
56+
};
57+
58+
export const CodePreview: CodePreviewComponent = React.forwardRef<HTMLDivElement>(
59+
InternalCodePreview,
60+
) as unknown as CodePreviewComponent;
61+
62+
CodePreview.Preview = Preview;
63+
CodePreview.Toolbar = Toolbar;
64+
CodePreview.Code = Code;

‎core/src/Preview.tsx

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from 'react';
2+
import { CODE_PREVIEW_PREFIX } from './CodePreview';
3+
4+
export interface PreviewProps extends React.HTMLAttributes<HTMLDivElement> {}
5+
6+
export const Preview = React.forwardRef<HTMLDivElement, PreviewProps>((props, ref) => {
7+
const { className, children, ...htmlProps } = props;
8+
const cls = [`${CODE_PREVIEW_PREFIX}-preview`, className].filter(Boolean).join(' ').trim();
9+
return (
10+
<div {...htmlProps} className={cls} ref={ref}>
11+
{children}
12+
</div>
13+
);
14+
});
15+
16+
Preview.displayName = 'uiw.Preview';

‎core/src/Toolbar.tsx

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import React, { useContext, useEffect } from 'react';
2+
import { CODE_PREVIEW_PREFIX } from './CodePreview';
3+
import { Copied } from './Copied';
4+
import { ExpandIcon } from './icons';
5+
import { Context } from './store';
6+
7+
export interface ToolbarProps extends React.HTMLAttributes<HTMLDivElement> {
8+
extra?: React.ReactNode;
9+
/**
10+
* Display cope button
11+
* @default true
12+
*/
13+
copied?: boolean;
14+
/**
15+
* Collapse code display?
16+
* @default true
17+
*/
18+
collapse?: boolean;
19+
/**
20+
* Display Toolbar?
21+
* @default true
22+
*/
23+
visible?: boolean;
24+
/**
25+
* Show button or not
26+
* @default true
27+
*/
28+
visibleButton?: boolean;
29+
/** Code to be copied */
30+
text?: string;
31+
}
32+
33+
export const Toolbar = React.forwardRef<HTMLDivElement, ToolbarProps>((props, ref) => {
34+
const {
35+
className,
36+
children,
37+
extra,
38+
text = '',
39+
copied = true,
40+
collapse = true,
41+
visibleButton = true,
42+
visible = true,
43+
...htmlProps
44+
} = props;
45+
const store = useContext(Context);
46+
const cls = [`${CODE_PREVIEW_PREFIX}-toolbar`, className].filter(Boolean).join(' ').trim();
47+
useEffect(() => store.dispatch!({ collapse }), [collapse]);
48+
if (!visible) {
49+
return null;
50+
}
51+
const handleClick = () => store.dispatch!({ collapse: !store.collapse });
52+
return (
53+
<div className={cls} {...htmlProps} ref={ref}>
54+
<div className={`${CODE_PREVIEW_PREFIX}-title`}>{children}</div>
55+
<div className={`${CODE_PREVIEW_PREFIX}-extra`}>
56+
{extra}
57+
{copied && <Copied text={text} />}
58+
{visibleButton && (
59+
<button onClick={handleClick}>
60+
<ExpandIcon />
61+
</button>
62+
)}
63+
</div>
64+
</div>
65+
);
66+
});
67+
68+
Toolbar.displayName = 'uiw.Toolbar';

‎core/src/index.tsx

+3-101
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,4 @@
1-
import { forwardRef, useState } from 'react';
2-
import { Copied } from './Copied';
3-
import { ExpandIcon } from './icons';
4-
import './styles.css';
1+
import { CodePreview } from './CodePreview';
2+
export * from './CodePreview';
53

6-
export interface CodeLayoutProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
7-
prefixCls?: string;
8-
/** 原始 代码块 渲染 **/
9-
code?: React.ReactNode;
10-
text?: string;
11-
/** Title section, you can also place buttons **/
12-
toolbar?: React.ReactNode;
13-
/** 额外内容,展示 toolbar 右侧内容 */
14-
toolbarExtra?: React.ReactNode;
15-
disableToolbar?: boolean;
16-
disableCode?: boolean;
17-
disablePreview?: boolean;
18-
/** 禁用方格背景 */
19-
disableCheckered?: boolean;
20-
/** Configure the preview background color. */
21-
background?: string;
22-
codeProps?: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
23-
/**
24-
* 是否需要边框
25-
* @default true
26-
*/
27-
bordered?: boolean;
28-
/**
29-
* 是否显示复制按钮
30-
* @default true
31-
*/
32-
copied?: boolean;
33-
}
34-
35-
/** react-code-preview-layout 缩写 */
36-
const PRE_FIX = 'w-rcpl';
37-
38-
const CodeLayout = forwardRef<HTMLDivElement, CodeLayoutProps>((props, ref) => {
39-
const [showCode, setShowCode] = useState(false);
40-
const {
41-
children,
42-
toolbar,
43-
bordered = true,
44-
disableCheckered = false,
45-
disablePreview = false,
46-
disableCode = false,
47-
disableToolbar = false,
48-
text = '',
49-
background = '',
50-
copied = true,
51-
toolbarExtra,
52-
code,
53-
prefixCls = PRE_FIX,
54-
className,
55-
codeProps,
56-
...other
57-
} = props;
58-
const cls = [prefixCls, className, bordered ? `w-bordered` : null, disableCheckered ? `w-disable-checkered` : null]
59-
.filter(Boolean)
60-
.join(' ')
61-
.trim();
62-
63-
const style: React.CSSProperties = !background
64-
? {}
65-
: {
66-
backgroundColor: background,
67-
backgroundImage: 'none',
68-
};
69-
return (
70-
<div ref={ref} {...other} className={cls}>
71-
{!disablePreview && (
72-
<div className={`${prefixCls}-preview`} style={style}>
73-
{children}
74-
</div>
75-
)}
76-
{!disableToolbar && (
77-
<div className={`${prefixCls}-toolbar`}>
78-
<div className={`${prefixCls}-title`}>{toolbar}</div>
79-
<div className={`${prefixCls}-extra`}>
80-
{toolbarExtra}
81-
{copied && <Copied text={text} />}
82-
{!disableCode && (
83-
<button onClick={() => setShowCode(!showCode)}>
84-
<ExpandIcon />
85-
</button>
86-
)}
87-
</div>
88-
</div>
89-
)}
90-
{!disableCode && !disableToolbar && (
91-
<div
92-
{...codeProps}
93-
className={`${prefixCls}-code ${codeProps?.className || ''} ${showCode ? 'w-display' : 'w-hidden'}`}
94-
>
95-
{code}
96-
</div>
97-
)}
98-
</div>
99-
);
100-
});
101-
102-
export default CodeLayout;
4+
export default CodePreview;

‎core/src/store.tsx

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { useReducer, createContext } from 'react';
2+
3+
export interface InitialState {
4+
collapse?: boolean;
5+
}
6+
7+
interface ContextValue extends InitialState {
8+
dispatch?: React.Dispatch<InitialState>;
9+
}
10+
export const initialState: InitialState = {};
11+
export const Context = createContext<ContextValue>({});
12+
13+
export const reducer = (state: InitialState, action: InitialState): InitialState => {
14+
return { ...state, ...action };
15+
};
16+
17+
export const Provider: React.FC<React.PropsWithChildren<{ value?: InitialState }>> = ({ children, value }) => {
18+
const [state, dispatch] = useReducer(reducer, { ...initialState, ...value });
19+
return <Context.Provider value={{ ...state, dispatch }}>{children}</Context.Provider>;
20+
};

‎website/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"@uiw/react-github-corners": "^1.5.14",
2626
"@uiw/react-markdown-preview": "^4.1.0",
2727
"@wcj/dark-mode": "^1.0.14",
28-
"react-code-preview-layout": "2.0.2",
28+
"react-code-preview-layout": "2.1.1",
2929
"react-router-dom": "^6.3.0",
3030
"uiw": "^4.21.6"
3131
},

‎website/src/pages/doc/index.tsx

+12-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import CodeLayout from 'react-code-preview-layout';
33
import MarkdownPreview from '@uiw/react-markdown-preview';
44
import { getMetaId, isMeta, getURLParameters } from 'markdown-react-code-preview-loader';
55

6+
const Preview = CodeLayout.Preview;
7+
const Code = CodeLayout.Code;
8+
const Toolbar = CodeLayout.Toolbar;
9+
610
const Doc = () => (
711
<MarkdownPreview
812
disableCopy={true}
@@ -20,8 +24,14 @@ const Doc = () => (
2024
const code = data.data[metaId].value || '';
2125
const param = getURLParameters(meta);
2226
return (
23-
<CodeLayout toolbar={param.title || '示例展示'} code={<code {...rest} />} text={code}>
24-
<Child />
27+
<CodeLayout>
28+
<Preview>
29+
<Child />
30+
</Preview>
31+
<Toolbar text={code}>{param.title || 'Code Example'}</Toolbar>
32+
<Code>
33+
<code {...rest} />
34+
</Code>
2535
</CodeLayout>
2636
);
2737
}

‎website/src/pages/example/index.tsx

+77-40
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ import CodeSandbox from '@uiw/react-codesandbox';
44
import Codepen from '@uiw/react-codepen';
55
import { Button } from 'uiw';
66

7+
const Preview = CodeLayout.Preview;
8+
const Code = CodeLayout.Code;
9+
const Toolbar = CodeLayout.Toolbar;
10+
711
const code = `import React from "react";\nimport { Button } from "uiw";\nconst Demo = ()=>{\n return<div><Button>按钮</Button></div>\n};\nexport default Demo;`;
812

913
const codePenOptions = {
1014
title: `demo`,
11-
includeModule: ['uiw'],
1215
js: `${code.replace(
1316
'export default',
1417
'const APP_render =',
@@ -47,70 +50,104 @@ const App = () => {
4750
<React.Fragment>
4851
<fieldset>
4952
<legend>基础</legend>
50-
<CodeLayout title="示例" code={<pre>{code}</pre>} text={code}>
51-
<Button>按钮</Button>
53+
<CodeLayout>
54+
<Preview>
55+
<Button>按钮</Button>
56+
</Preview>
57+
<Toolbar text={code}>示例</Toolbar>
58+
<Code>
59+
<pre>{code}</pre>
60+
</Code>
5261
</CodeLayout>
5362
</fieldset>
5463

5564
<fieldset>
5665
<legend>禁用方格背景</legend>
57-
<CodeLayout code={<pre>{code}</pre>} text={code} disableCheckered>
58-
<Button>禁用方格背景</Button>
66+
<CodeLayout disableCheckered>
67+
<Preview>
68+
<Button>禁用方格背景</Button>
69+
</Preview>
70+
<Toolbar text={code}>示例</Toolbar>
71+
<Code>
72+
<pre>{code}</pre>
73+
</Code>
5974
</CodeLayout>
6075
</fieldset>
6176

6277
<fieldset>
6378
<legend>无边框</legend>
64-
<CodeLayout code={<pre>{code}</pre>} text={code} bordered={false}>
65-
<Button>按钮</Button>
79+
<CodeLayout bordered={false}>
80+
<Preview>
81+
<Button>无边框</Button>
82+
</Preview>
83+
<Toolbar text={code}>示例</Toolbar>
84+
<Code>
85+
<pre>{code}</pre>
86+
</Code>
6687
</CodeLayout>
6788
</fieldset>
6889

6990
<fieldset>
7091
<legend>第三方预览按钮</legend>
71-
<CodeLayout
72-
code={<pre>{code}</pre>}
73-
text={code}
74-
toolbarExtra={
75-
<Fragment>
76-
<CodeSandbox {...codeSandboxOptions}>
77-
<svg viewBox="0 0 1024 1024" width="18" height="18">
78-
<path
79-
d="M85.333333 256l446.08-256L977.493333 256 981.333333 765.866667 531.413333 1024 85.333333 768V256z m89.088 105.856v202.965333l142.72 79.36v150.016l169.472 97.962667v-352.938667L174.421333 361.856z m714.197334 0l-312.192 177.365333v352.938667l169.472-97.962667V644.266667l142.72-79.402667V361.813333zM219.050667 281.642667l311.594666 176.810666 312.32-178.346666-165.162666-93.738667-145.493334 82.986667-146.346666-83.968L219.008 281.6z"
80-
p-id="4089"
81-
></path>
82-
</svg>
83-
</CodeSandbox>
84-
<Codepen {...codePenOptions}>
85-
<svg viewBox="0 0 1024 1024" width="18" height="18">
86-
<path
87-
d="M85.333333 256l446.08-256L977.493333 256 981.333333 765.866667 531.413333 1024 85.333333 768V256z m89.088 105.856v202.965333l142.72 79.36v150.016l169.472 97.962667v-352.938667L174.421333 361.856z m714.197334 0l-312.192 177.365333v352.938667l169.472-97.962667V644.266667l142.72-79.402667V361.813333zM219.050667 281.642667l311.594666 176.810666 312.32-178.346666-165.162666-93.738667-145.493334 82.986667-146.346666-83.968L219.008 281.6z"
88-
p-id="4089"
89-
></path>
90-
</svg>
91-
</Codepen>
92-
</Fragment>
93-
}
94-
>
95-
<Button>按钮</Button>
92+
<CodeLayout bordered={false}>
93+
<Preview>
94+
<Button>第三方预览按钮</Button>
95+
</Preview>
96+
<Toolbar
97+
text={code}
98+
extra={
99+
<Fragment>
100+
<CodeSandbox {...codeSandboxOptions}>
101+
<svg viewBox="0 0 1024 1024" width="18" height="18">
102+
<path
103+
d="M85.333333 256l446.08-256L977.493333 256 981.333333 765.866667 531.413333 1024 85.333333 768V256z m89.088 105.856v202.965333l142.72 79.36v150.016l169.472 97.962667v-352.938667L174.421333 361.856z m714.197334 0l-312.192 177.365333v352.938667l169.472-97.962667V644.266667l142.72-79.402667V361.813333zM219.050667 281.642667l311.594666 176.810666 312.32-178.346666-165.162666-93.738667-145.493334 82.986667-146.346666-83.968L219.008 281.6z"
104+
p-id="4089"
105+
></path>
106+
</svg>
107+
</CodeSandbox>
108+
<Codepen {...codePenOptions}>
109+
<svg viewBox="0 0 1024 1024" width="18" height="18">
110+
<path
111+
d="M85.333333 256l446.08-256L977.493333 256 981.333333 765.866667 531.413333 1024 85.333333 768V256z m89.088 105.856v202.965333l142.72 79.36v150.016l169.472 97.962667v-352.938667L174.421333 361.856z m714.197334 0l-312.192 177.365333v352.938667l169.472-97.962667V644.266667l142.72-79.402667V361.813333zM219.050667 281.642667l311.594666 176.810666 312.32-178.346666-165.162666-93.738667-145.493334 82.986667-146.346666-83.968L219.008 281.6z"
112+
p-id="4089"
113+
></path>
114+
</svg>
115+
</Codepen>
116+
</Fragment>
117+
}
118+
>
119+
示例
120+
</Toolbar>
121+
<Code>
122+
<pre>{code}</pre>
123+
</Code>
96124
</CodeLayout>
97125
</fieldset>
98126

99127
<fieldset>
100128
<legend>自定义操作按钮</legend>
101-
<CodeLayout
102-
code={<pre>{code}</pre>}
103-
text={code}
104-
toolbarExtra={<button style={{ marginRight: 30 }}>操作按钮</button>}
105-
>
106-
<Button>按钮</Button>
129+
<CodeLayout bordered={false}>
130+
<Preview>
131+
<Button>无边框</Button>
132+
</Preview>
133+
<Toolbar text={code} extra={<button style={{ marginRight: 30 }}>操作按钮</button>}>
134+
示例
135+
</Toolbar>
136+
<Code>
137+
<pre>{code}</pre>
138+
</Code>
107139
</CodeLayout>
108140
</fieldset>
109141

110142
<fieldset>
111143
<legend>禁用工具栏</legend>
112-
<CodeLayout code={<pre>{code}</pre>} text={code} disableToolbar>
113-
<Button>按钮</Button>
144+
<CodeLayout bordered={false}>
145+
<Preview>
146+
<Button>无边框</Button>
147+
</Preview>
148+
<Code>
149+
<pre>{code}</pre>
150+
</Code>
114151
</CodeLayout>
115152
</fieldset>
116153
</React.Fragment>

‎website/src/pages/markdown-example/index.tsx

+12-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import { getCodeString } from 'rehype-rewrite';
44
import { getMetaId, isMeta, getURLParameters } from 'markdown-react-code-preview-loader';
55
import data from './README.md';
66

7+
const Preview = CodeLayout.Preview;
8+
const Code = CodeLayout.Code;
9+
const Toolbar = CodeLayout.Toolbar;
10+
711
export default function MarkdownExample() {
812
return (
913
<MarkdownPreview
@@ -22,8 +26,14 @@ export default function MarkdownExample() {
2226
const code = getCodeString(node.children);
2327
const param = getURLParameters(meta);
2428
return (
25-
<CodeLayout toolbar={param.title || '示例展示'} code={<code {...rest} />} text={code}>
26-
<Child />
29+
<CodeLayout>
30+
<Preview>
31+
<Child />
32+
</Preview>
33+
<Toolbar text={code}>{param.title || 'Code Example'}</Toolbar>
34+
<Code>
35+
<code {...rest} />
36+
</Code>
2737
</CodeLayout>
2838
);
2939
}

0 commit comments

Comments
 (0)
Please sign in to comment.