Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: uiwjs/react-code-preview-layout
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v2.1.1
Choose a base ref
...
head repository: uiwjs/react-code-preview-layout
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v3.0.0
Choose a head ref
  • 4 commits
  • 14 files changed
  • 1 contributor

Commits on Mar 7, 2023

  1. feat: refactor code.

    jaywcjlove committed Mar 7, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    36466f9 View commit details
  2. Copy the full SHA
    f1c293b View commit details
  3. Copy the full SHA
    ad0179b View commit details
  4. released v3.0.0

    jaywcjlove committed Mar 7, 2023
    Copy the full SHA
    022058a View commit details
298 changes: 204 additions & 94 deletions core/README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-code-preview-layout",
"version": "2.1.1",
"version": "3.0.0",
"description": "A react component showing the layout of `code` and `code preview example`.",
"author": "SunLxy <1011771396@qq.com>",
"contributors": [
21 changes: 21 additions & 0 deletions core/src/Code.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React, { useContext } from 'react';
import { Context } from './store';
import { CODE_PREVIEW_PREFIX } from './CodePreview';

export interface CodeProps extends React.HTMLAttributes<HTMLDivElement> {}

export const Code = React.forwardRef<HTMLDivElement, CodeProps>((props, ref) => {
const { className, children, ...htmlProps } = props;
const cls = [`${CODE_PREVIEW_PREFIX}-code`, className].filter(Boolean).join(' ').trim();
const store = useContext(Context);
if (store.collapse) {
return null;
}
return (
<div {...htmlProps} className={cls} ref={ref}>
{children}
</div>
);
});

Code.displayName = 'uiw.CodeLayoutCode';
64 changes: 64 additions & 0 deletions core/src/CodePreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from 'react';
import { Code } from './Code';
import { Preview } from './Preview';
import { Toolbar } from './Toolbar';
import { Provider } from './store';
import './styles.css';

export const CODE_PREVIEW_PREFIX = 'w-rcpl';

export interface CodePreviewProps extends React.HTMLAttributes<HTMLDivElement> {
prefixCls?: string;
/**
* Whether border is required
* @default true
*/
bordered?: boolean;
/** disable checkered */
disableCheckered?: boolean;
}

const Internal = React.forwardRef<HTMLDivElement, CodePreviewProps>((props, ref) => {
const {
children,
prefixCls = CODE_PREVIEW_PREFIX,
className,
bordered = true,
disableCheckered,
...divProps
} = props;
const cls = [prefixCls, className, bordered ? `w-bordered` : null, disableCheckered ? `w-disable-checkered` : null]
.filter(Boolean)
.join(' ')
.trim();
return (
<div ref={ref} {...divProps} className={cls}>
{React.Children.map(children, (child: React.ReactNode, key) => {
if (!React.isValidElement(child)) return child;
return React.cloneElement(child, { ...child.props, key });
})}
</div>
);
});

const InternalCodePreview = (props: CodePreviewProps, ref?: React.ForwardedRef<HTMLDivElement>) => {
return (
<Provider value={{ collapse: false }}>
<Internal {...props} ref={ref} />
</Provider>
);
};

type CodePreviewComponent = React.FC<React.PropsWithRef<CodePreviewProps>> & {
Preview: typeof Preview;
Code: typeof Code;
Toolbar: typeof Toolbar;
};

export const CodePreview: CodePreviewComponent = React.forwardRef<HTMLDivElement>(
InternalCodePreview,
) as unknown as CodePreviewComponent;

CodePreview.Preview = Preview;
CodePreview.Toolbar = Toolbar;
CodePreview.Code = Code;
16 changes: 16 additions & 0 deletions core/src/Preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { CODE_PREVIEW_PREFIX } from './CodePreview';

export interface PreviewProps extends React.HTMLAttributes<HTMLDivElement> {}

export const Preview = React.forwardRef<HTMLDivElement, PreviewProps>((props, ref) => {
const { className, children, ...htmlProps } = props;
const cls = [`${CODE_PREVIEW_PREFIX}-preview`, className].filter(Boolean).join(' ').trim();
return (
<div {...htmlProps} className={cls} ref={ref}>
{children}
</div>
);
});

Preview.displayName = 'uiw.Preview';
68 changes: 68 additions & 0 deletions core/src/Toolbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React, { useContext, useEffect } from 'react';
import { CODE_PREVIEW_PREFIX } from './CodePreview';
import { Copied } from './Copied';
import { ExpandIcon } from './icons';
import { Context } from './store';

export interface ToolbarProps extends React.HTMLAttributes<HTMLDivElement> {
extra?: React.ReactNode;
/**
* Display cope button
* @default true
*/
copied?: boolean;
/**
* Collapse code display?
* @default true
*/
collapse?: boolean;
/**
* Display Toolbar?
* @default true
*/
visible?: boolean;
/**
* Show button or not
* @default true
*/
visibleButton?: boolean;
/** Code to be copied */
text?: string;
}

export const Toolbar = React.forwardRef<HTMLDivElement, ToolbarProps>((props, ref) => {
const {
className,
children,
extra,
text = '',
copied = true,
collapse = true,
visibleButton = true,
visible = true,
...htmlProps
} = props;
const store = useContext(Context);
const cls = [`${CODE_PREVIEW_PREFIX}-toolbar`, className].filter(Boolean).join(' ').trim();
useEffect(() => store.dispatch!({ collapse }), [collapse]);
if (!visible) {
return null;
}
const handleClick = () => store.dispatch!({ collapse: !store.collapse });
return (
<div className={cls} {...htmlProps} ref={ref}>
<div className={`${CODE_PREVIEW_PREFIX}-title`}>{children}</div>
<div className={`${CODE_PREVIEW_PREFIX}-extra`}>
{extra}
{copied && <Copied text={text} />}
{visibleButton && (
<button onClick={handleClick}>
<ExpandIcon />
</button>
)}
</div>
</div>
);
});

Toolbar.displayName = 'uiw.Toolbar';
104 changes: 3 additions & 101 deletions core/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,102 +1,4 @@
import { forwardRef, useState } from 'react';
import { Copied } from './Copied';
import { ExpandIcon } from './icons';
import './styles.css';
import { CodePreview } from './CodePreview';
export * from './CodePreview';

export interface CodeLayoutProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
prefixCls?: string;
/** 原始 代码块 渲染 **/
code?: React.ReactNode;
text?: string;
/** Title section, you can also place buttons **/
toolbar?: React.ReactNode;
/** 额外内容,展示 toolbar 右侧内容 */
toolbarExtra?: React.ReactNode;
disableToolbar?: boolean;
disableCode?: boolean;
disablePreview?: boolean;
/** 禁用方格背景 */
disableCheckered?: boolean;
/** Configure the preview background color. */
background?: string;
codeProps?: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
/**
* 是否需要边框
* @default true
*/
bordered?: boolean;
/**
* 是否显示复制按钮
* @default true
*/
copied?: boolean;
}

/** react-code-preview-layout 缩写 */
const PRE_FIX = 'w-rcpl';

const CodeLayout = forwardRef<HTMLDivElement, CodeLayoutProps>((props, ref) => {
const [showCode, setShowCode] = useState(false);
const {
children,
toolbar,
bordered = true,
disableCheckered = false,
disablePreview = false,
disableCode = false,
disableToolbar = false,
text = '',
background = '',
copied = true,
toolbarExtra,
code,
prefixCls = PRE_FIX,
className,
codeProps,
...other
} = props;
const cls = [prefixCls, className, bordered ? `w-bordered` : null, disableCheckered ? `w-disable-checkered` : null]
.filter(Boolean)
.join(' ')
.trim();

const style: React.CSSProperties = !background
? {}
: {
backgroundColor: background,
backgroundImage: 'none',
};
return (
<div ref={ref} {...other} className={cls}>
{!disablePreview && (
<div className={`${prefixCls}-preview`} style={style}>
{children}
</div>
)}
{!disableToolbar && (
<div className={`${prefixCls}-toolbar`}>
<div className={`${prefixCls}-title`}>{toolbar}</div>
<div className={`${prefixCls}-extra`}>
{toolbarExtra}
{copied && <Copied text={text} />}
{!disableCode && (
<button onClick={() => setShowCode(!showCode)}>
<ExpandIcon />
</button>
)}
</div>
</div>
)}
{!disableCode && !disableToolbar && (
<div
{...codeProps}
className={`${prefixCls}-code ${codeProps?.className || ''} ${showCode ? 'w-display' : 'w-hidden'}`}
>
{code}
</div>
)}
</div>
);
});

export default CodeLayout;
export default CodePreview;
20 changes: 20 additions & 0 deletions core/src/store.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useReducer, createContext } from 'react';

export interface InitialState {
collapse?: boolean;
}

interface ContextValue extends InitialState {
dispatch?: React.Dispatch<InitialState>;
}
export const initialState: InitialState = {};
export const Context = createContext<ContextValue>({});

export const reducer = (state: InitialState, action: InitialState): InitialState => {
return { ...state, ...action };
};

export const Provider: React.FC<React.PropsWithChildren<{ value?: InitialState }>> = ({ children, value }) => {
const [state, dispatch] = useReducer(reducer, { ...initialState, ...value });
return <Context.Provider value={{ ...state, dispatch }}>{children}</Context.Provider>;
};
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"packages": ["core", "website"],
"version": "2.1.1",
"version": "3.0.0",
"useWorkspaces": true
}
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -22,11 +22,10 @@
"@types/react": "~18.0.21",
"@types/react-dom": "~18.0.6",
"tsbb": "~3.7.7",
"kkt": "~7.2.1",
"husky": "~8.0.0",
"lint-staged": "~13.0.0",
"prettier": "~2.6.0",
"lerna": "^5.1.0",
"lint-staged": "^13.1.2",
"prettier": "^2.8.4",
"lerna": "^6.5.1",
"pretty-quick": "~3.1.3",
"react-test-renderer": "~18.2.0"
},
8 changes: 4 additions & 4 deletions website/package.json
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
"name": "website",
"description": "Simple React package development project example template.",
"private": true,
"version": "2.1.1",
"version": "3.0.0",
"scripts": {
"start": "kkt start",
"build": "kkt build"
@@ -13,10 +13,10 @@
"react-dom": ">=18.0.0"
},
"devDependencies": {
"@kkt/less-modules": "~7.2.1",
"@kkt/raw-modules": "~7.2.1",
"@kkt/less-modules": "^7.4.8",
"@types/react": "~18.0.21",
"@types/react-dom": "~18.0.6",
"kkt": "^7.4.8",
"markdown-react-code-preview-loader": "^2.0.0"
},
"dependencies": {
@@ -25,7 +25,7 @@
"@uiw/react-github-corners": "^1.5.14",
"@uiw/react-markdown-preview": "^4.1.0",
"@wcj/dark-mode": "^1.0.14",
"react-code-preview-layout": "2.0.2",
"react-code-preview-layout": "3.0.0",
"react-router-dom": "^6.3.0",
"uiw": "^4.21.6"
},
14 changes: 12 additions & 2 deletions website/src/pages/doc/index.tsx
Original file line number Diff line number Diff line change
@@ -3,6 +3,10 @@ import CodeLayout from 'react-code-preview-layout';
import MarkdownPreview from '@uiw/react-markdown-preview';
import { getMetaId, isMeta, getURLParameters } from 'markdown-react-code-preview-loader';

const Preview = CodeLayout.Preview;
const Code = CodeLayout.Code;
const Toolbar = CodeLayout.Toolbar;

const Doc = () => (
<MarkdownPreview
disableCopy={true}
@@ -20,8 +24,14 @@ const Doc = () => (
const code = data.data[metaId].value || '';
const param = getURLParameters(meta);
return (
<CodeLayout toolbar={param.title || '示例展示'} code={<code {...rest} />} text={code}>
<Child />
<CodeLayout>
<Preview>
<Child />
</Preview>
<Toolbar text={code}>{param.title || 'Code Example'}</Toolbar>
<Code>
<code {...rest} />
</Code>
</CodeLayout>
);
}
117 changes: 77 additions & 40 deletions website/src/pages/example/index.tsx
Original file line number Diff line number Diff line change
@@ -4,11 +4,14 @@ import CodeSandbox from '@uiw/react-codesandbox';
import Codepen from '@uiw/react-codepen';
import { Button } from 'uiw';

const Preview = CodeLayout.Preview;
const Code = CodeLayout.Code;
const Toolbar = CodeLayout.Toolbar;

const code = `import React from "react";\nimport { Button } from "uiw";\nconst Demo = ()=>{\n return<div><Button>按钮</Button></div>\n};\nexport default Demo;`;

const codePenOptions = {
title: `demo`,
includeModule: ['uiw'],
js: `${code.replace(
'export default',
'const APP_render =',
@@ -47,70 +50,104 @@ const App = () => {
<React.Fragment>
<fieldset>
<legend>基础</legend>
<CodeLayout title="示例" code={<pre>{code}</pre>} text={code}>
<Button>按钮</Button>
<CodeLayout>
<Preview>
<Button>按钮</Button>
</Preview>
<Toolbar text={code}>示例</Toolbar>
<Code>
<pre>{code}</pre>
</Code>
</CodeLayout>
</fieldset>

<fieldset>
<legend>禁用方格背景</legend>
<CodeLayout code={<pre>{code}</pre>} text={code} disableCheckered>
<Button>禁用方格背景</Button>
<CodeLayout disableCheckered>
<Preview>
<Button>禁用方格背景</Button>
</Preview>
<Toolbar text={code}>示例</Toolbar>
<Code>
<pre>{code}</pre>
</Code>
</CodeLayout>
</fieldset>

<fieldset>
<legend>无边框</legend>
<CodeLayout code={<pre>{code}</pre>} text={code} bordered={false}>
<Button>按钮</Button>
<CodeLayout bordered={false}>
<Preview>
<Button>无边框</Button>
</Preview>
<Toolbar text={code}>示例</Toolbar>
<Code>
<pre>{code}</pre>
</Code>
</CodeLayout>
</fieldset>

<fieldset>
<legend>第三方预览按钮</legend>
<CodeLayout
code={<pre>{code}</pre>}
text={code}
toolbarExtra={
<Fragment>
<CodeSandbox {...codeSandboxOptions}>
<svg viewBox="0 0 1024 1024" width="18" height="18">
<path
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"
p-id="4089"
></path>
</svg>
</CodeSandbox>
<Codepen {...codePenOptions}>
<svg viewBox="0 0 1024 1024" width="18" height="18">
<path
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"
p-id="4089"
></path>
</svg>
</Codepen>
</Fragment>
}
>
<Button>按钮</Button>
<CodeLayout bordered={false}>
<Preview>
<Button>第三方预览按钮</Button>
</Preview>
<Toolbar
text={code}
extra={
<Fragment>
<CodeSandbox {...codeSandboxOptions}>
<svg viewBox="0 0 1024 1024" width="18" height="18">
<path
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"
p-id="4089"
></path>
</svg>
</CodeSandbox>
<Codepen {...codePenOptions}>
<svg viewBox="0 0 1024 1024" width="18" height="18">
<path
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"
p-id="4089"
></path>
</svg>
</Codepen>
</Fragment>
}
>
示例
</Toolbar>
<Code>
<pre>{code}</pre>
</Code>
</CodeLayout>
</fieldset>

<fieldset>
<legend>自定义操作按钮</legend>
<CodeLayout
code={<pre>{code}</pre>}
text={code}
toolbarExtra={<button style={{ marginRight: 30 }}>操作按钮</button>}
>
<Button>按钮</Button>
<CodeLayout bordered={false}>
<Preview>
<Button>无边框</Button>
</Preview>
<Toolbar text={code} extra={<button style={{ marginRight: 30 }}>操作按钮</button>}>
示例
</Toolbar>
<Code>
<pre>{code}</pre>
</Code>
</CodeLayout>
</fieldset>

<fieldset>
<legend>禁用工具栏</legend>
<CodeLayout code={<pre>{code}</pre>} text={code} disableToolbar>
<Button>按钮</Button>
<CodeLayout bordered={false}>
<Preview>
<Button>无边框</Button>
</Preview>
<Code>
<pre>{code}</pre>
</Code>
</CodeLayout>
</fieldset>
</React.Fragment>
14 changes: 12 additions & 2 deletions website/src/pages/markdown-example/index.tsx
Original file line number Diff line number Diff line change
@@ -4,6 +4,10 @@ import { getCodeString } from 'rehype-rewrite';
import { getMetaId, isMeta, getURLParameters } from 'markdown-react-code-preview-loader';
import data from './README.md';

const Preview = CodeLayout.Preview;
const Code = CodeLayout.Code;
const Toolbar = CodeLayout.Toolbar;

export default function MarkdownExample() {
return (
<MarkdownPreview
@@ -22,8 +26,14 @@ export default function MarkdownExample() {
const code = getCodeString(node.children);
const param = getURLParameters(meta);
return (
<CodeLayout toolbar={param.title || '示例展示'} code={<code {...rest} />} text={code}>
<Child />
<CodeLayout>
<Preview>
<Child />
</Preview>
<Toolbar text={code}>{param.title || 'Code Example'}</Toolbar>
<Code>
<code {...rest} />
</Code>
</CodeLayout>
);
}