Skip to content

Commit 36466f9

Browse files
committed
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

Lines changed: 204 additions & 94 deletions
Large diffs are not rendered by default.

core/src/Code.tsx

Lines changed: 21 additions & 0 deletions
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

Lines changed: 64 additions & 0 deletions
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

Lines changed: 16 additions & 0 deletions
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

Lines changed: 68 additions & 0 deletions
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

Lines changed: 3 additions & 101 deletions
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

Lines changed: 20 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 12 additions & 2 deletions
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
}

0 commit comments

Comments
 (0)