[WIP] docs: use sandpack for demo (#43854)

* docs: use sandpack for demo

* chore: update

* docs: adjust theme

* docs: sandpack ssr

* docs: sandpack fallback

* fix: ssr

* chore: fix css extract

* chore: fix lint

* fix: fix lint

* chore: rm theme

* fix: solve ssr sissue

* chore: fix lint

---------

Signed-off-by: lijianan <574980606@qq.com>
Co-authored-by: lijianan <574980606@qq.com>
This commit is contained in:
MadCcc 2023-08-01 10:53:55 +08:00 committed by GitHub
parent 23040aa25f
commit 76dd6dc1bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 153 additions and 24 deletions

View File

@ -8,7 +8,7 @@ function rehypeAntd(): UnifiedTransformer<HastRoot> {
return (tree, vFile) => {
const { filename } = vFile.data.frontmatter as any;
unistUtilVisit.visit(tree, 'element', (node) => {
unistUtilVisit.visit(tree, 'element', (node, i, parent) => {
if (node.tagName === 'DumiDemoGrid') {
// replace DumiDemoGrid to DemoWrapper, to implement demo toolbar
node.tagName = 'DemoWrapper';
@ -66,6 +66,20 @@ function rehypeAntd(): UnifiedTransformer<HastRoot> {
node.tagName = 'LocaleLink';
} else if (node.type === 'element' && node.tagName === 'video') {
node.tagName = 'VideoPlayer';
} else if (node.tagName === 'SourceCode') {
const { lang } = node.properties;
if (lang === 'sandpack') {
parent!.children.splice(i!, 1, {
type: 'element',
tagName: 'Sandpack',
children: [
{
type: 'text',
value: (node.children[0] as any).value,
},
],
});
}
}
});
};

View File

@ -0,0 +1,3 @@
import { Sandpack } from '@codesandbox/sandpack-react';
export default Sandpack;

View File

@ -0,0 +1,91 @@
import type { ReactNode } from 'react';
import React, { Suspense } from 'react';
import { useSearchParams, useServerInsertedHTML } from 'dumi';
import { createStyles } from 'antd-style';
import { getSandpackCssText } from '@codesandbox/sandpack-react';
import { Skeleton } from 'antd';
const OriginSandpack = React.lazy(() => import('./Sandpack'));
const setup = {
dependencies: {
react: '^18.0.0',
'react-dom': '^18.0.0',
antd: '^5.0.0',
},
devDependencies: {
'@types/react': '^18.0.0',
'@types/react-dom': '^18.0.0',
typescript: '^5',
},
entry: 'index.tsx',
};
const options = {
activeFile: 'app.tsx' as never,
visibleFiles: ['index.tsx', 'app.tsx', 'package.json'] as any,
showLineNumbers: true,
editorHeight: '500px',
};
const indexContent = `import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './app';
const root = createRoot(document.getElementById("root"));
root.render(<App />);
`;
const useStyle = createStyles(({ token, css }) => ({
fallback: css`
width: 100%;
> * {
width: 100% !important;
border-radius: 8px;
}
`,
placeholder: css`
color: ${token.colorTextDescription};
font-size: 16px;
`,
}));
const SandpackFallback = () => {
const { styles } = useStyle();
return (
<div className={styles.fallback}>
<Skeleton.Node active style={{ height: 500, width: '100%' }}>
<span className={styles.placeholder}>Loading Demo...</span>
</Skeleton.Node>
</div>
);
};
const Sandpack = ({ children }: { children: ReactNode }) => {
const [searchParams] = useSearchParams();
useServerInsertedHTML(() => (
<style
data-sandpack="true"
id="sandpack"
dangerouslySetInnerHTML={{ __html: getSandpackCssText() }}
/>
));
return (
<Suspense fallback={<SandpackFallback />}>
<OriginSandpack
theme={searchParams.getAll('theme').includes('dark') ? 'dark' : undefined}
customSetup={setup}
options={options}
files={{
'index.tsx': indexContent,
'app.tsx': children,
}}
/>
</Suspense>
);
};
export default Sandpack;

View File

@ -6,11 +6,10 @@ import {
StyleProvider,
extractStyle,
} from '@ant-design/cssinjs';
import { createSearchParams, useOutlet, useSearchParams } from 'dumi';
import { useServerInsertedHTML } from 'umi';
import React, { useCallback, useEffect, useMemo } from 'react';
import type { DirectionType } from 'antd/es/config-provider';
import { createSearchParams, useOutlet, useSearchParams, useServerInsertedHTML } from 'dumi';
import { App, theme as antdTheme } from 'antd';
import type { DirectionType } from 'antd/es/config-provider';
import useLayoutState from '../../hooks/useLayoutState';
import SiteThemeProvider from '../SiteThemeProvider';
import useLocation from '../../hooks/useLocation';

View File

@ -116,11 +116,14 @@ const RoutesPlugin = (api: IApi) => {
// fs.writeFileSync(tmpFilePath, file.content, 'utf8');
// extract all emotion style tags from body
file.content = file.content.replace(/<style data-emotion[\S\s]+?<\/style>/g, (s) => {
globalStyles += s;
file.content = file.content.replace(
/<style (data-emotion|data-sandpack)[\S\s]+?<\/style>/g,
(s) => {
globalStyles += s;
return '';
});
return '';
},
);
// insert emotion style tags to head
file.content = file.content.replace('</head>', `${globalStyles}</head>`);
@ -142,14 +145,14 @@ const RoutesPlugin = (api: IApi) => {
});
// Insert antd style to head
const matchRegex = /<style data-type="antd-cssinjs">(.*)<\/style>/;
const matchRegex = /<style data-type="antd-cssinjs">(.*?)<\/style>/;
const matchList = file.content.match(matchRegex) || [];
let antdStyle = '';
matchList.forEach((text) => {
file.content = file.content.replace(text, '');
antdStyle = text.replace(matchRegex, '$1');
antdStyle += text.replace(matchRegex, '$1');
});
const cssFile = writeCSSFile('antd', antdStyle, antdStyle);

View File

@ -15,13 +15,22 @@ Finally, if you are working in a local development environment, please refer to
Here is a simple online codesandbox demo of an Ant Design component to show the usage of Ant Design React.
<iframe
src="https://codesandbox.io/embed/antd-reproduction-template-forked-jyh2k9?autoresize=1&fontsize=14&hidenavigation=1&theme=light"
style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;"
title="antd reproduction template"
allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb"
sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"
/>
```sandpack
import React from 'react';
import { Button, Space, DatePicker, version } from 'antd';
const App = () => (
<div style={{ padding: '0 24px' }}>
<h1>antd version: {version}</h1>
<Space>
<DatePicker />
<Button type="primary">Primary Button</Button>
</Space>
</div>
);
export default App;
```
Follow the steps below to play around with Ant Design yourself:

View File

@ -13,13 +13,22 @@ Ant Design React 致力于提供给程序员**愉悦**的开发体验。
这是一个最简单的 Ant Design 组件的在线 codesandbox 演示。
<iframe
src="https://codesandbox.io/embed/antd-reproduction-template-forked-jyh2k9?autoresize=1&fontsize=14&hidenavigation=1&theme=light"
style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;"
title="antd reproduction template"
allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb"
sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"
/>
```sandpack
import React from 'react';
import { Button, Space, DatePicker, version } from 'antd';
const App = () => (
<div style={{ padding: '0 24px' }}>
<h1>antd version: {version}</h1>
<Space>
<DatePicker />
<Button type="primary">Primary Button</Button>
</Space>
</div>
);
export default App;
```
### 1. 创建一个 codesandbox

View File

@ -162,6 +162,7 @@
"@antv/g6": "^4.8.13",
"@argos-ci/core": "^0.9.0",
"@babel/eslint-plugin": "^7.19.1",
"@codesandbox/sandpack-react": "^2.6.9",
"@dnd-kit/core": "^6.0.7",
"@dnd-kit/modifiers": "^6.0.1",
"@dnd-kit/sortable": "^7.0.2",