mirror of
https://github.com/ant-design/ant-design.git
synced 2025-08-06 07:56:28 +08:00
[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:
parent
23040aa25f
commit
76dd6dc1bb
@ -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,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
3
.dumi/theme/builtins/Sandpack/Sandpack.ts
Normal file
3
.dumi/theme/builtins/Sandpack/Sandpack.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { Sandpack } from '@codesandbox/sandpack-react';
|
||||
|
||||
export default Sandpack;
|
91
.dumi/theme/builtins/Sandpack/index.tsx
Normal file
91
.dumi/theme/builtins/Sandpack/index.tsx
Normal 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;
|
@ -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';
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user