mirror of
https://github.com/ant-design/ant-design.git
synced 2024-12-18 11:18:14 +08:00
commit
da441ae35f
@ -7,7 +7,7 @@ version: 2.1
|
||||
jobs:
|
||||
test-argos-ci:
|
||||
docker:
|
||||
- image: cimg/node:16.19.0-browsers
|
||||
- image: cimg/node:16.19.1-browsers
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
|
556
.dumi/theme/builtins/Previewer/CodePreviewer.tsx
Normal file
556
.dumi/theme/builtins/Previewer/CodePreviewer.tsx
Normal file
@ -0,0 +1,556 @@
|
||||
import {
|
||||
CheckOutlined,
|
||||
LinkOutlined,
|
||||
SnippetsOutlined,
|
||||
ThunderboltOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import type { Project } from '@stackblitz/sdk';
|
||||
import stackblitzSdk from '@stackblitz/sdk';
|
||||
import { Alert, Badge, Space, Tooltip } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import LZString from 'lz-string';
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import type { IPreviewerProps } from 'dumi';
|
||||
import { FormattedMessage } from 'dumi';
|
||||
import Prism from 'prismjs';
|
||||
import JsonML from 'jsonml.js/lib/utils';
|
||||
import toReactElement from 'jsonml-to-react-element';
|
||||
import { ping } from '../../utils';
|
||||
import ClientOnly from '../../common/ClientOnly';
|
||||
import BrowserFrame from '../../common/BrowserFrame';
|
||||
import EditButton from '../../common/EditButton';
|
||||
import CodePenIcon from '../../common/CodePenIcon';
|
||||
import CodePreview from '../../common/CodePreview';
|
||||
import CodeSandboxIcon from '../../common/CodeSandboxIcon';
|
||||
import RiddleIcon from '../../common/RiddleIcon';
|
||||
import ExternalLinkIcon from '../../common/ExternalLinkIcon';
|
||||
import type { SiteContextProps } from '../../slots/SiteContext';
|
||||
import SiteContext from '../../slots/SiteContext';
|
||||
import useLocation from '../../../hooks/useLocation';
|
||||
|
||||
const { ErrorBoundary } = Alert;
|
||||
|
||||
function toReactComponent(jsonML: any) {
|
||||
return toReactElement(jsonML, [
|
||||
[
|
||||
(node: any) => JsonML.isElement(node) && JsonML.getTagName(node) === 'pre',
|
||||
(node: any, index: any) => {
|
||||
// ref: https://github.com/benjycui/bisheng/blob/master/packages/bisheng/src/bisheng-plugin-highlight/lib/browser.js#L7
|
||||
const attr = JsonML.getAttributes(node);
|
||||
return React.createElement(
|
||||
'pre',
|
||||
{
|
||||
key: index,
|
||||
className: `language-${attr.lang}`,
|
||||
},
|
||||
React.createElement('code', {
|
||||
dangerouslySetInnerHTML: { __html: attr.highlighted },
|
||||
}),
|
||||
);
|
||||
},
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
function compress(string: string): string {
|
||||
return LZString.compressToBase64(string)
|
||||
.replace(/\+/g, '-') // Convert '+' to '-'
|
||||
.replace(/\//g, '_') // Convert '/' to '_'
|
||||
.replace(/=+$/, ''); // Remove ending '='
|
||||
}
|
||||
|
||||
const track = ({ type, demo }: { type: string; demo: string }) => {
|
||||
if (!window.gtag) {
|
||||
return;
|
||||
}
|
||||
window.gtag('event', 'demo', { event_category: type, event_label: demo });
|
||||
};
|
||||
|
||||
let pingDeferrer: PromiseLike<boolean>;
|
||||
|
||||
function useShowRiddleButton() {
|
||||
const [showRiddleButton, setShowRiddleButton] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
pingDeferrer ??= new Promise<boolean>((resolve) => {
|
||||
ping((status) => {
|
||||
if (status !== 'timeout' && status !== 'error') {
|
||||
return resolve(true);
|
||||
}
|
||||
|
||||
return resolve(false);
|
||||
});
|
||||
});
|
||||
pingDeferrer.then(setShowRiddleButton);
|
||||
}, []);
|
||||
|
||||
return showRiddleButton;
|
||||
}
|
||||
|
||||
const CodePreviewer: React.FC<IPreviewerProps> = (props) => {
|
||||
const {
|
||||
asset,
|
||||
expand,
|
||||
iframe,
|
||||
demoUrl,
|
||||
children,
|
||||
title,
|
||||
description,
|
||||
debug,
|
||||
jsx,
|
||||
style,
|
||||
compact,
|
||||
background,
|
||||
filePath,
|
||||
version,
|
||||
} = props;
|
||||
|
||||
const location = useLocation();
|
||||
|
||||
const entryCode = asset.dependencies['index.tsx'].value;
|
||||
const showRiddleButton = useShowRiddleButton();
|
||||
|
||||
const liveDemo = useRef<React.ReactNode>(null);
|
||||
const anchorRef = useRef<HTMLAnchorElement>(null);
|
||||
const codeSandboxIconRef = useRef<HTMLFormElement>(null);
|
||||
const riddleIconRef = useRef<HTMLFormElement>(null);
|
||||
const codepenIconRef = useRef<HTMLFormElement>(null);
|
||||
const [codeExpand, setCodeExpand] = useState<boolean>(false);
|
||||
const [copyTooltipOpen, setCopyTooltipOpen] = useState<boolean>(false);
|
||||
const [copied, setCopied] = useState<boolean>(false);
|
||||
const [codeType, setCodeType] = useState<string>('tsx');
|
||||
const { theme } = useContext<SiteContextProps>(SiteContext);
|
||||
|
||||
const { hash, pathname, search } = location;
|
||||
const docsOnlineUrl = `https://ant.design${pathname}${search}#${asset.id}`;
|
||||
|
||||
const [showOnlineUrl, setShowOnlineUrl] = useState<boolean>(false);
|
||||
|
||||
const highlightedCodes = {
|
||||
jsx: Prism.highlight(jsx, Prism.languages.javascript, 'jsx'),
|
||||
tsx: Prism.highlight(entryCode, Prism.languages.javascript, 'jsx'),
|
||||
};
|
||||
|
||||
const highlightedStyle = style ? Prism.highlight(style, Prism.languages.css, 'css') : '';
|
||||
|
||||
useEffect(() => {
|
||||
const regexp = /preview-(\d+)-ant-design/; // matching PR preview addresses
|
||||
setShowOnlineUrl(
|
||||
process.env.NODE_ENV === 'development' || regexp.test(window.location.hostname),
|
||||
);
|
||||
}, []);
|
||||
|
||||
const handleCodeExpand = (demo: string) => {
|
||||
setCodeExpand((prev) => !prev);
|
||||
track({ type: 'expand', demo });
|
||||
};
|
||||
|
||||
const handleCodeCopied = (demo: string) => {
|
||||
setCopied(true);
|
||||
track({ type: 'copy', demo });
|
||||
};
|
||||
|
||||
const onCopyTooltipOpenChange = (open: boolean) => {
|
||||
setCopyTooltipOpen(open);
|
||||
if (open) {
|
||||
setCopied(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (asset.id === hash.slice(1)) {
|
||||
anchorRef.current?.click();
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setCodeExpand(expand);
|
||||
}, [expand]);
|
||||
|
||||
if (!liveDemo.current) {
|
||||
liveDemo.current = iframe ? (
|
||||
<BrowserFrame>
|
||||
<iframe
|
||||
src={demoUrl}
|
||||
height={iframe === true ? undefined : iframe}
|
||||
title="demo"
|
||||
className="iframe-demo"
|
||||
/>
|
||||
</BrowserFrame>
|
||||
) : (
|
||||
children
|
||||
);
|
||||
}
|
||||
|
||||
const codeBoxClass = classNames('code-box', {
|
||||
expand: codeExpand,
|
||||
'code-box-debug': debug,
|
||||
});
|
||||
|
||||
const localizedTitle = title;
|
||||
const introChildren = <div dangerouslySetInnerHTML={{ __html: description }} />;
|
||||
const highlightClass = classNames('highlight-wrapper', {
|
||||
'highlight-wrapper-expand': codeExpand,
|
||||
});
|
||||
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
</head>
|
||||
<body>
|
||||
<div id="container" style="padding: 24px" />
|
||||
<script>const mountNode = document.getElementById('container');</script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
const tsconfig = `
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"esModuleInterop": true,
|
||||
"moduleResolution": "node",
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const suffix = codeType === 'tsx' ? 'tsx' : 'js';
|
||||
|
||||
const dependencies: Record<PropertyKey, string> = jsx.split('\n').reduce(
|
||||
(acc, line) => {
|
||||
const matches = line.match(/import .+? from '(.+)';$/);
|
||||
if (matches && matches[1] && !line.includes('antd')) {
|
||||
const paths = matches[1].split('/');
|
||||
if (paths.length) {
|
||||
const dep = paths[0].startsWith('@') ? `${paths[0]}/${paths[1]}` : paths[0];
|
||||
acc[dep] = 'latest';
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ antd: version },
|
||||
);
|
||||
|
||||
dependencies['@ant-design/icons'] = 'latest';
|
||||
|
||||
if (suffix === 'tsx') {
|
||||
dependencies['@types/react'] = '^18.0.0';
|
||||
dependencies['@types/react-dom'] = '^18.0.0';
|
||||
}
|
||||
|
||||
dependencies.react = '^18.0.0';
|
||||
dependencies['react-dom'] = '^18.0.0';
|
||||
|
||||
const codepenPrefillConfig = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
html,
|
||||
js: `const { createRoot } = ReactDOM;\n${jsx
|
||||
.replace(/import\s+(?:React,\s+)?{(\s+[^}]*\s+)}\s+from\s+'react'/, `const { $1 } = React;`)
|
||||
.replace(/import\s+{(\s+[^}]*\s+)}\s+from\s+'antd';/, 'const { $1 } = antd;')
|
||||
.replace(/import\s+{(\s+[^}]*\s+)}\s+from\s+'@ant-design\/icons';/, 'const { $1 } = icons;')
|
||||
.replace("import moment from 'moment';", '')
|
||||
.replace("import React from 'react';", '')
|
||||
.replace(/import\s+{\s+(.*)\s+}\s+from\s+'react-router';/, 'const { $1 } = ReactRouter;')
|
||||
.replace(
|
||||
/import\s+{\s+(.*)\s+}\s+from\s+'react-router-dom';/,
|
||||
'const { $1 } = ReactRouterDOM;',
|
||||
)
|
||||
.replace(/([A-Za-z]*)\s+as\s+([A-Za-z]*)/, '$1:$2')
|
||||
.replace(
|
||||
/export default/,
|
||||
'const ComponentDemo =',
|
||||
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
|
||||
editors: '001',
|
||||
css: '',
|
||||
js_external: [
|
||||
'react@18/umd/react.development.js',
|
||||
'react-dom@18/umd/react-dom.development.js',
|
||||
'dayjs@1/dayjs.min.js',
|
||||
`antd@${version}/dist/antd-with-locales.js`,
|
||||
`@ant-design/icons/dist/index.umd.js`,
|
||||
'react-router-dom/dist/umd/react-router-dom.production.min.js',
|
||||
'react-router/dist/umd/react-router.production.min.js',
|
||||
]
|
||||
.map((url) => `https://unpkg.com/${url}`)
|
||||
.join(';'),
|
||||
js_pre_processor: 'typescript',
|
||||
};
|
||||
|
||||
const riddlePrefillConfig = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
js: `${
|
||||
/import React(\D*)from 'react';/.test(jsx) ? '' : `import React from 'react';\n`
|
||||
}import { createRoot } from 'react-dom/client';\n${jsx.replace(
|
||||
/export default/,
|
||||
'const ComponentDemo =',
|
||||
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
|
||||
css: '',
|
||||
json: JSON.stringify({ name: 'antd-demo', dependencies }, null, 2),
|
||||
};
|
||||
|
||||
// Reorder source code
|
||||
let parsedSourceCode = suffix === 'tsx' ? entryCode : jsx;
|
||||
let importReactContent = "import React from 'react';";
|
||||
const importReactReg = /import React(\D*)from 'react';/;
|
||||
const matchImportReact = parsedSourceCode.match(importReactReg);
|
||||
if (matchImportReact) {
|
||||
[importReactContent] = matchImportReact;
|
||||
parsedSourceCode = parsedSourceCode.replace(importReactReg, '').trim();
|
||||
}
|
||||
const demoJsContent = `
|
||||
${importReactContent}
|
||||
import './index.css';
|
||||
${parsedSourceCode}
|
||||
`.trim();
|
||||
const indexCssContent = (style || '')
|
||||
.trim()
|
||||
.replace(new RegExp(`#${asset.id}\\s*`, 'g'), '')
|
||||
.replace('</style>', '')
|
||||
.replace('<style>', '');
|
||||
|
||||
const indexJsContent = `
|
||||
import React from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import Demo from './demo';
|
||||
|
||||
createRoot(document.getElementById('container')).render(<Demo />);
|
||||
`;
|
||||
|
||||
const codesandboxPackage = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
main: 'index.js',
|
||||
dependencies: {
|
||||
...dependencies,
|
||||
react: '^18.0.0',
|
||||
'react-dom': '^18.0.0',
|
||||
'react-scripts': '^4.0.0',
|
||||
},
|
||||
devDependencies: {
|
||||
typescript: '^4.0.5',
|
||||
},
|
||||
scripts: {
|
||||
start: 'react-scripts start',
|
||||
build: 'react-scripts build',
|
||||
test: 'react-scripts test --env=jsdom',
|
||||
eject: 'react-scripts eject',
|
||||
},
|
||||
browserslist: ['>0.2%', 'not dead'],
|
||||
};
|
||||
|
||||
const codesanboxPrefillConfig = {
|
||||
files: {
|
||||
'package.json': { content: codesandboxPackage },
|
||||
'index.css': { content: indexCssContent },
|
||||
[`index.${suffix}`]: { content: indexJsContent },
|
||||
[`demo.${suffix}`]: { content: demoJsContent },
|
||||
'index.html': {
|
||||
content: html,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const stackblitzPrefillConfig: Project = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
template: 'create-react-app',
|
||||
dependencies,
|
||||
description: '',
|
||||
files: {
|
||||
'index.css': indexCssContent,
|
||||
[`index.${suffix}`]: indexJsContent,
|
||||
[`demo.${suffix}`]: demoJsContent,
|
||||
'index.html': html,
|
||||
},
|
||||
};
|
||||
if (suffix === 'tsx') {
|
||||
stackblitzPrefillConfig.files['tsconfig.json'] = tsconfig;
|
||||
}
|
||||
|
||||
const backgroundGrey = theme.includes('dark') ? '#303030' : '#f0f2f5';
|
||||
|
||||
const codeBoxDemoStyle: React.CSSProperties = {
|
||||
padding: iframe || compact ? 0 : undefined,
|
||||
overflow: iframe || compact ? 'hidden' : undefined,
|
||||
backgroundColor: background === 'grey' ? backgroundGrey : undefined,
|
||||
};
|
||||
|
||||
const codeBox: React.ReactNode = (
|
||||
<section className={codeBoxClass} id={asset.id}>
|
||||
<section className="code-box-demo" style={codeBoxDemoStyle}>
|
||||
<ErrorBoundary>
|
||||
<React.StrictMode>{liveDemo.current}</React.StrictMode>
|
||||
</ErrorBoundary>
|
||||
{style ? <style dangerouslySetInnerHTML={{ __html: style }} /> : null}
|
||||
</section>
|
||||
<section className="code-box-meta markdown">
|
||||
<div className="code-box-title">
|
||||
<Tooltip title={debug ? <FormattedMessage id="app.demo.debug" /> : ''}>
|
||||
<a href={`#${asset.id}`} ref={anchorRef}>
|
||||
{localizedTitle}
|
||||
</a>
|
||||
</Tooltip>
|
||||
<EditButton title={<FormattedMessage id="app.content.edit-demo" />} filename={filePath} />
|
||||
</div>
|
||||
<div className="code-box-description">{introChildren}</div>
|
||||
<Space wrap size="middle" className="code-box-actions">
|
||||
{showOnlineUrl && (
|
||||
<Tooltip title={<FormattedMessage id="app.demo.online" />}>
|
||||
<a
|
||||
className="code-box-code-action"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href={docsOnlineUrl}
|
||||
>
|
||||
<LinkOutlined className="code-box-online" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
{showRiddleButton ? (
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="//riddle.alibaba-inc.com/riddles/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={riddleIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'riddle', demo: asset.id });
|
||||
riddleIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<input type="hidden" name="data" value={JSON.stringify(riddlePrefillConfig)} />
|
||||
<Tooltip title={<FormattedMessage id="app.demo.riddle" />}>
|
||||
<RiddleIcon className="code-box-riddle" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
) : null}
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="https://codesandbox.io/api/v1/sandboxes/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={codeSandboxIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'codesandbox', demo: asset.id });
|
||||
codeSandboxIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="hidden"
|
||||
name="parameters"
|
||||
value={compress(JSON.stringify(codesanboxPrefillConfig))}
|
||||
/>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.codesandbox" />}>
|
||||
<CodeSandboxIcon className="code-box-codesandbox" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="https://codepen.io/pen/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={codepenIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'codepen', demo: asset.id });
|
||||
codepenIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<ClientOnly>
|
||||
<input type="hidden" name="data" value={JSON.stringify(codepenPrefillConfig)} />
|
||||
</ClientOnly>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.codepen" />}>
|
||||
<CodePenIcon className="code-box-codepen" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.stackblitz" />}>
|
||||
<span
|
||||
className="code-box-code-action"
|
||||
onClick={() => {
|
||||
track({ type: 'stackblitz', demo: asset.id });
|
||||
stackblitzSdk.openProject(stackblitzPrefillConfig, {
|
||||
openFile: [`demo.${suffix}`],
|
||||
});
|
||||
}}
|
||||
>
|
||||
<ThunderboltOutlined className="code-box-stackblitz" />
|
||||
</span>
|
||||
</Tooltip>
|
||||
<CopyToClipboard text={entryCode} onCopy={() => handleCodeCopied(asset.id)}>
|
||||
<Tooltip
|
||||
open={copyTooltipOpen as boolean}
|
||||
onOpenChange={onCopyTooltipOpenChange}
|
||||
title={<FormattedMessage id={`app.demo.${copied ? 'copied' : 'copy'}`} />}
|
||||
>
|
||||
{React.createElement(copied && copyTooltipOpen ? CheckOutlined : SnippetsOutlined, {
|
||||
className: 'code-box-code-copy code-box-code-action',
|
||||
})}
|
||||
</Tooltip>
|
||||
</CopyToClipboard>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.separate" />}>
|
||||
<a className="code-box-code-action" target="_blank" rel="noreferrer" href={demoUrl}>
|
||||
<ExternalLinkIcon className="code-box-separate" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip
|
||||
title={<FormattedMessage id={`app.demo.code.${codeExpand ? 'hide' : 'show'}`} />}
|
||||
>
|
||||
<div className="code-expand-icon code-box-code-action">
|
||||
<img
|
||||
alt="expand code"
|
||||
src={
|
||||
theme?.includes('dark')
|
||||
? 'https://gw.alipayobjects.com/zos/antfincdn/btT3qDZn1U/wSAkBuJFbdxsosKKpqyq.svg'
|
||||
: 'https://gw.alipayobjects.com/zos/antfincdn/Z5c7kzvi30/expand.svg'
|
||||
}
|
||||
className={codeExpand ? 'code-expand-icon-hide' : 'code-expand-icon-show'}
|
||||
onClick={() => handleCodeExpand(asset.id)}
|
||||
/>
|
||||
<img
|
||||
alt="expand code"
|
||||
src={
|
||||
theme?.includes('dark')
|
||||
? 'https://gw.alipayobjects.com/zos/antfincdn/CjZPwcKUG3/OpROPHYqWmrMDBFMZtKF.svg'
|
||||
: 'https://gw.alipayobjects.com/zos/antfincdn/4zAaozCvUH/unexpand.svg'
|
||||
}
|
||||
className={codeExpand ? 'code-expand-icon-show' : 'code-expand-icon-hide'}
|
||||
onClick={() => handleCodeExpand(asset.id)}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</section>
|
||||
<section className={highlightClass} key="code">
|
||||
<CodePreview
|
||||
codes={highlightedCodes}
|
||||
toReactComponent={toReactComponent}
|
||||
onCodeTypeChange={(type) => setCodeType(type)}
|
||||
/>
|
||||
{highlightedStyle ? (
|
||||
<div key="style" className="highlight">
|
||||
<pre>
|
||||
<code className="css" dangerouslySetInnerHTML={{ __html: highlightedStyle }} />
|
||||
</pre>
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
</section>
|
||||
);
|
||||
|
||||
if (version) {
|
||||
return (
|
||||
<Badge.Ribbon text={version} color={version.includes('<') ? 'red' : null}>
|
||||
{codeBox}
|
||||
</Badge.Ribbon>
|
||||
);
|
||||
}
|
||||
|
||||
return codeBox;
|
||||
};
|
||||
|
||||
export default CodePreviewer;
|
102
.dumi/theme/builtins/Previewer/DesignPreviewer.tsx
Normal file
102
.dumi/theme/builtins/Previewer/DesignPreviewer.tsx
Normal file
@ -0,0 +1,102 @@
|
||||
import type { FC } from 'react';
|
||||
import React, { useRef } from 'react';
|
||||
import type { IPreviewerProps } from 'dumi';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import { CheckOutlined, SketchOutlined } from '@ant-design/icons';
|
||||
import { nodeToGroup } from 'html2sketch';
|
||||
import copy from 'copy-to-clipboard';
|
||||
import { App } from 'antd';
|
||||
|
||||
const useStyle = createStyles(({ token }) => ({
|
||||
wrapper: css`
|
||||
border: 1px solid ${token.colorBorderSecondary};
|
||||
border-radius: ${token.borderRadius}px;
|
||||
padding: 20px 24px 40px;
|
||||
position: relative;
|
||||
margin-bottom: ${token.marginLG}px;
|
||||
`,
|
||||
title: css`
|
||||
font-size: ${token.fontSizeLG}px;
|
||||
font-weight: ${token.fontWeightStrong};
|
||||
color: ${token.colorTextHeading};
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorTextHeading};
|
||||
}
|
||||
`,
|
||||
description: css`
|
||||
margin-top: ${token.margin}px;
|
||||
`,
|
||||
demo: css`
|
||||
margin-top: ${token.marginLG}px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
`,
|
||||
copy: css`
|
||||
position: absolute;
|
||||
inset-inline-end: 20px;
|
||||
inset-block-start: 20px;
|
||||
cursor: pointer;
|
||||
`,
|
||||
copyTip: css`
|
||||
color: ${token.colorTextTertiary};
|
||||
`,
|
||||
copiedTip: css`
|
||||
.anticon {
|
||||
color: ${token.colorSuccess};
|
||||
}
|
||||
`,
|
||||
tip: css`
|
||||
color: ${token.colorTextTertiary};
|
||||
margin-top: 40px;
|
||||
`,
|
||||
}));
|
||||
|
||||
const DesignPreviewer: FC<IPreviewerProps> = ({ children, title, description, tip, asset }) => {
|
||||
const { styles } = useStyle();
|
||||
const demoRef = useRef<HTMLDivElement>(null);
|
||||
const [copied, setCopied] = React.useState<boolean>(false);
|
||||
const { message } = App.useApp();
|
||||
|
||||
const handleCopy = async () => {
|
||||
try {
|
||||
const group = await nodeToGroup(demoRef.current);
|
||||
copy(JSON.stringify(group.toSketchJSON()));
|
||||
setCopied(true);
|
||||
setTimeout(() => {
|
||||
setCopied(false);
|
||||
}, 5000);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
message.error('复制失败');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper} id={asset.id}>
|
||||
<a className={styles.title} href={`#${asset.id}`}>
|
||||
{title}
|
||||
</a>
|
||||
<div className={styles.description} dangerouslySetInnerHTML={{ __html: description }} />
|
||||
<div className={styles.copy}>
|
||||
{copied ? (
|
||||
<div className={styles.copiedTip}>
|
||||
<CheckOutlined />
|
||||
<span style={{ marginLeft: 8 }}>已复制,使用 Kitchen 插件即可粘贴</span>
|
||||
</div>
|
||||
) : (
|
||||
<div onClick={handleCopy} className={styles.copyTip}>
|
||||
<SketchOutlined />
|
||||
<span style={{ marginLeft: 8 }}>复制 Sketch JSON</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.demo} ref={demoRef}>
|
||||
{children}
|
||||
</div>
|
||||
<div className={styles.tip}>{tip}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DesignPreviewer;
|
@ -1,95 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import JsonML from 'jsonml.js/lib/utils';
|
||||
import toReactComponent from 'jsonml-to-react-element';
|
||||
import Prism from 'prismjs';
|
||||
import 'prismjs/components/prism-typescript';
|
||||
import { useLocation, useIntl, type IPreviewerProps } from 'dumi';
|
||||
import { ping } from '../../utils';
|
||||
|
||||
let pingDeferrer: PromiseLike<boolean>;
|
||||
|
||||
function useShowRiddleButton() {
|
||||
const [showRiddleButton, setShowRiddleButton] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
pingDeferrer ??= new Promise<boolean>((resolve) => {
|
||||
ping((status) => {
|
||||
if (status !== 'timeout' && status !== 'error') {
|
||||
return resolve(true);
|
||||
}
|
||||
|
||||
return resolve(false);
|
||||
});
|
||||
});
|
||||
pingDeferrer.then(setShowRiddleButton);
|
||||
}, []);
|
||||
|
||||
return showRiddleButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* HOC for convert dumi previewer props to bisheng previewer props
|
||||
*/
|
||||
export default function fromDumiProps<P extends object>(
|
||||
WrappedComponent: React.ComponentType<P>,
|
||||
): React.FC<IPreviewerProps> {
|
||||
const hoc = function DumiPropsAntdPreviewer(props: IPreviewerProps) {
|
||||
const showRiddleButton = useShowRiddleButton();
|
||||
const location = useLocation();
|
||||
const { asset, children, demoUrl, expand, description = '', ...meta } = props;
|
||||
const intl = useIntl();
|
||||
const entryCode = asset.dependencies['index.tsx'].value;
|
||||
const transformedProps = {
|
||||
meta: {
|
||||
id: asset.id,
|
||||
title: '',
|
||||
filename: meta.filePath,
|
||||
...meta,
|
||||
},
|
||||
content: description,
|
||||
preview: () => children,
|
||||
utils: {
|
||||
toReactComponent(jsonML: any) {
|
||||
return toReactComponent(jsonML, [
|
||||
[
|
||||
(node: any) => JsonML.isElement(node) && JsonML.getTagName(node) === 'pre',
|
||||
(node: any, index: any) => {
|
||||
// ref: https://github.com/benjycui/bisheng/blob/master/packages/bisheng/src/bisheng-plugin-highlight/lib/browser.js#L7
|
||||
const attr = JsonML.getAttributes(node);
|
||||
return React.createElement(
|
||||
'pre',
|
||||
{
|
||||
key: index,
|
||||
className: `language-${attr.lang}`,
|
||||
},
|
||||
React.createElement('code', {
|
||||
dangerouslySetInnerHTML: { __html: attr.highlighted },
|
||||
}),
|
||||
);
|
||||
},
|
||||
],
|
||||
]);
|
||||
},
|
||||
},
|
||||
intl: { locale: intl.locale },
|
||||
showRiddleButton,
|
||||
sourceCodes: {
|
||||
jsx: meta.jsx,
|
||||
tsx: entryCode,
|
||||
},
|
||||
highlightedCodes: {
|
||||
jsx: Prism.highlight(meta.jsx, Prism.languages.javascript, 'jsx'),
|
||||
tsx: Prism.highlight(entryCode, Prism.languages.typescript, 'tsx'),
|
||||
},
|
||||
style: meta.style,
|
||||
location,
|
||||
src: demoUrl,
|
||||
expand,
|
||||
highlightedStyle: meta.style ? Prism.highlight(meta.style, Prism.languages.css, 'css') : '',
|
||||
} as P;
|
||||
|
||||
return <WrappedComponent {...transformedProps} />;
|
||||
};
|
||||
|
||||
return hoc;
|
||||
}
|
@ -1,512 +1,18 @@
|
||||
import {
|
||||
CheckOutlined,
|
||||
SnippetsOutlined,
|
||||
ThunderboltOutlined,
|
||||
LinkOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import stackblitzSdk from '@stackblitz/sdk';
|
||||
import type { Project } from '@stackblitz/sdk';
|
||||
import { Alert, Badge, Tooltip, Space } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import LZString from 'lz-string';
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { FormattedMessage } from 'dumi';
|
||||
import ClientOnly from '../../common/ClientOnly';
|
||||
import BrowserFrame from '../../common/BrowserFrame';
|
||||
import EditButton from '../../common/EditButton';
|
||||
import CodePenIcon from '../../common/CodePenIcon';
|
||||
import CodePreview from '../../common/CodePreview';
|
||||
import CodeSandboxIcon from '../../common/CodeSandboxIcon';
|
||||
import RiddleIcon from '../../common/RiddleIcon';
|
||||
import ExternalLinkIcon from '../../common/ExternalLinkIcon';
|
||||
import fromDumiProps from './fromDumiProps';
|
||||
import type { SiteContextProps } from '../../slots/SiteContext';
|
||||
import SiteContext from '../../slots/SiteContext';
|
||||
import { version } from '../../../../package.json';
|
||||
|
||||
const { ErrorBoundary } = Alert;
|
||||
|
||||
function compress(string: string): string {
|
||||
return LZString.compressToBase64(string)
|
||||
.replace(/\+/g, '-') // Convert '+' to '-'
|
||||
.replace(/\//g, '_') // Convert '/' to '_'
|
||||
.replace(/=+$/, ''); // Remove ending '='
|
||||
}
|
||||
|
||||
const track = ({ type, demo }: { type: string; demo: string }) => {
|
||||
if (!window.gtag) {
|
||||
return;
|
||||
}
|
||||
window.gtag('event', 'demo', { event_category: type, event_label: demo });
|
||||
};
|
||||
|
||||
interface DemoProps {
|
||||
meta: any;
|
||||
intl: any;
|
||||
utils?: any;
|
||||
src: string;
|
||||
content: string;
|
||||
highlightedCodes: Record<PropertyKey, string>;
|
||||
style: string;
|
||||
highlightedStyle: string;
|
||||
expand: boolean;
|
||||
sourceCodes: Record<'jsx' | 'tsx', string>;
|
||||
location: Location;
|
||||
showRiddleButton: boolean;
|
||||
preview: (react: typeof React, reactDOM: typeof ReactDOM) => React.ReactNode;
|
||||
}
|
||||
|
||||
const Demo: React.FC<DemoProps> = (props) => {
|
||||
const {
|
||||
location,
|
||||
sourceCodes,
|
||||
meta,
|
||||
src,
|
||||
utils,
|
||||
content,
|
||||
highlightedCodes,
|
||||
style,
|
||||
highlightedStyle,
|
||||
expand,
|
||||
intl: { locale },
|
||||
showRiddleButton,
|
||||
preview,
|
||||
} = props;
|
||||
|
||||
const liveDemo = useRef<React.ReactNode>(null);
|
||||
const anchorRef = useRef<HTMLAnchorElement>(null);
|
||||
const codeSandboxIconRef = useRef<HTMLFormElement>(null);
|
||||
const riddleIconRef = useRef<HTMLFormElement>(null);
|
||||
const codepenIconRef = useRef<HTMLFormElement>(null);
|
||||
const [codeExpand, setCodeExpand] = useState<boolean>(false);
|
||||
const [copyTooltipOpen, setCopyTooltipOpen] = useState<boolean>(false);
|
||||
const [copied, setCopied] = useState<boolean>(false);
|
||||
const [codeType, setCodeType] = useState<string>('tsx');
|
||||
const { theme } = useContext<SiteContextProps>(SiteContext);
|
||||
|
||||
const { hash, pathname, search } = location;
|
||||
const docsOnlineUrl = `https://ant.design${pathname}${search}#${meta.id}`;
|
||||
|
||||
const [showOnlineUrl, setShowOnlineUrl] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
const regexp = /preview-(\d+)-ant-design/; // matching PR preview addresses
|
||||
setShowOnlineUrl(
|
||||
process.env.NODE_ENV === 'development' || regexp.test(window.location.hostname),
|
||||
);
|
||||
}, []);
|
||||
|
||||
const handleCodeExpand = (demo: string) => {
|
||||
setCodeExpand((prev) => !prev);
|
||||
track({ type: 'expand', demo });
|
||||
};
|
||||
|
||||
const handleCodeCopied = (demo: string) => {
|
||||
setCopied(true);
|
||||
track({ type: 'copy', demo });
|
||||
};
|
||||
|
||||
const onCopyTooltipOpenChange = (open: boolean) => {
|
||||
setCopyTooltipOpen(open);
|
||||
if (open) {
|
||||
setCopied(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (meta.id === hash.slice(1)) {
|
||||
anchorRef.current?.click();
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setCodeExpand(expand);
|
||||
}, [expand]);
|
||||
|
||||
if (!liveDemo.current) {
|
||||
liveDemo.current = meta.iframe ? (
|
||||
<BrowserFrame>
|
||||
<iframe src={src} height={meta.iframe} title="demo" className="iframe-demo" />
|
||||
</BrowserFrame>
|
||||
) : (
|
||||
preview(React, ReactDOM)
|
||||
);
|
||||
}
|
||||
|
||||
const codeBoxClass = classNames('code-box', {
|
||||
expand: codeExpand,
|
||||
'code-box-debug': meta.originDebug,
|
||||
});
|
||||
|
||||
const localizedTitle = meta?.title[locale] || meta?.title;
|
||||
const localizeIntro = content[locale] || content;
|
||||
const introChildren = <div dangerouslySetInnerHTML={{ __html: localizeIntro }} />;
|
||||
const highlightClass = classNames('highlight-wrapper', {
|
||||
'highlight-wrapper-expand': codeExpand,
|
||||
});
|
||||
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
</head>
|
||||
<body>
|
||||
<div id="container" style="padding: 24px" />
|
||||
<script>const mountNode = document.getElementById('container');</script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
const tsconfig = `
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"esModuleInterop": true,
|
||||
"moduleResolution": "node",
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const suffix = codeType === 'tsx' ? 'tsx' : 'js';
|
||||
|
||||
const dependencies: Record<PropertyKey, string> = sourceCodes?.jsx.split('\n').reduce(
|
||||
(acc, line) => {
|
||||
const matches = line.match(/import .+? from '(.+)';$/);
|
||||
if (matches && matches[1] && !line.includes('antd')) {
|
||||
const paths = matches[1].split('/');
|
||||
if (paths.length) {
|
||||
const dep = paths[0].startsWith('@') ? `${paths[0]}/${paths[1]}` : paths[0];
|
||||
acc[dep] = 'latest';
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ antd: version },
|
||||
);
|
||||
|
||||
dependencies['@ant-design/icons'] = 'latest';
|
||||
|
||||
if (suffix === 'tsx') {
|
||||
dependencies['@types/react'] = '^18.0.0';
|
||||
dependencies['@types/react-dom'] = '^18.0.0';
|
||||
}
|
||||
|
||||
dependencies.react = '^18.0.0';
|
||||
dependencies['react-dom'] = '^18.0.0';
|
||||
|
||||
const codepenPrefillConfig = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
html,
|
||||
js: `const { createRoot } = ReactDOM;\n${sourceCodes?.jsx
|
||||
.replace(/import\s+(?:React,\s+)?{(\s+[^}]*\s+)}\s+from\s+'react'/, `const { $1 } = React;`)
|
||||
.replace(/import\s+{(\s+[^}]*\s+)}\s+from\s+'antd';/, 'const { $1 } = antd;')
|
||||
.replace(/import\s+{(\s+[^}]*\s+)}\s+from\s+'@ant-design\/icons';/, 'const { $1 } = icons;')
|
||||
.replace("import moment from 'moment';", '')
|
||||
.replace("import React from 'react';", '')
|
||||
.replace(/import\s+{\s+(.*)\s+}\s+from\s+'react-router';/, 'const { $1 } = ReactRouter;')
|
||||
.replace(
|
||||
/import\s+{\s+(.*)\s+}\s+from\s+'react-router-dom';/,
|
||||
'const { $1 } = ReactRouterDOM;',
|
||||
)
|
||||
.replace(/([A-Za-z]*)\s+as\s+([A-Za-z]*)/, '$1:$2')
|
||||
.replace(
|
||||
/export default/,
|
||||
'const ComponentDemo =',
|
||||
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
|
||||
editors: '001',
|
||||
css: '',
|
||||
js_external: [
|
||||
'react@18/umd/react.development.js',
|
||||
'react-dom@18/umd/react-dom.development.js',
|
||||
'dayjs@1/dayjs.min.js',
|
||||
`antd@${version}/dist/antd-with-locales.js`,
|
||||
`@ant-design/icons/dist/index.umd.js`,
|
||||
'react-router-dom/dist/umd/react-router-dom.production.min.js',
|
||||
'react-router/dist/umd/react-router.production.min.js',
|
||||
]
|
||||
.map((url) => `https://unpkg.com/${url}`)
|
||||
.join(';'),
|
||||
js_pre_processor: 'typescript',
|
||||
};
|
||||
|
||||
const riddlePrefillConfig = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
js: `${
|
||||
/import React(\D*)from 'react';/.test(sourceCodes?.jsx) ? '' : `import React from 'react';\n`
|
||||
}import { createRoot } from 'react-dom/client';\n${sourceCodes?.jsx.replace(
|
||||
/export default/,
|
||||
'const ComponentDemo =',
|
||||
)}\n\ncreateRoot(mountNode).render(<ComponentDemo />);\n`,
|
||||
css: '',
|
||||
json: JSON.stringify({ name: 'antd-demo', dependencies }, null, 2),
|
||||
};
|
||||
|
||||
// Reorder source code
|
||||
let parsedSourceCode = suffix === 'tsx' ? sourceCodes?.tsx : sourceCodes?.jsx;
|
||||
let importReactContent = "import React from 'react';";
|
||||
const importReactReg = /import React(\D*)from 'react';/;
|
||||
const matchImportReact = parsedSourceCode.match(importReactReg);
|
||||
if (matchImportReact) {
|
||||
[importReactContent] = matchImportReact;
|
||||
parsedSourceCode = parsedSourceCode.replace(importReactReg, '').trim();
|
||||
}
|
||||
const demoJsContent = `
|
||||
${importReactContent}
|
||||
import './index.css';
|
||||
${parsedSourceCode}
|
||||
`.trim();
|
||||
const indexCssContent = (style || '')
|
||||
.trim()
|
||||
.replace(new RegExp(`#${meta.id}\\s*`, 'g'), '')
|
||||
.replace('</style>', '')
|
||||
.replace('<style>', '');
|
||||
|
||||
const indexJsContent = `
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import Demo from './demo';
|
||||
import type { IPreviewerProps } from 'dumi';
|
||||
import { useTabMeta } from 'dumi';
|
||||
import CodePreviewer from './CodePreviewer';
|
||||
import DesignPreviewer from './DesignPreviewer';
|
||||
|
||||
createRoot(document.getElementById('container')).render(<Demo />);
|
||||
`;
|
||||
const Previewer: FC<IPreviewerProps> = ({ ...props }) => {
|
||||
const tab = useTabMeta();
|
||||
|
||||
const codesandboxPackage = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
main: 'index.js',
|
||||
dependencies: {
|
||||
...dependencies,
|
||||
react: '^18.0.0',
|
||||
'react-dom': '^18.0.0',
|
||||
'react-scripts': '^4.0.0',
|
||||
},
|
||||
devDependencies: {
|
||||
typescript: '^4.0.5',
|
||||
},
|
||||
scripts: {
|
||||
start: 'react-scripts start',
|
||||
build: 'react-scripts build',
|
||||
test: 'react-scripts test --env=jsdom',
|
||||
eject: 'react-scripts eject',
|
||||
},
|
||||
browserslist: ['>0.2%', 'not dead'],
|
||||
};
|
||||
|
||||
const codesanboxPrefillConfig = {
|
||||
files: {
|
||||
'package.json': { content: codesandboxPackage },
|
||||
'index.css': { content: indexCssContent },
|
||||
[`index.${suffix}`]: { content: indexJsContent },
|
||||
[`demo.${suffix}`]: { content: demoJsContent },
|
||||
'index.html': {
|
||||
content: html,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const stackblitzPrefillConfig: Project = {
|
||||
title: `${localizedTitle} - antd@${dependencies.antd}`,
|
||||
template: 'create-react-app',
|
||||
dependencies,
|
||||
description: '',
|
||||
files: {
|
||||
'index.css': indexCssContent,
|
||||
[`index.${suffix}`]: indexJsContent,
|
||||
[`demo.${suffix}`]: demoJsContent,
|
||||
'index.html': html,
|
||||
},
|
||||
};
|
||||
if (suffix === 'tsx') {
|
||||
stackblitzPrefillConfig.files['tsconfig.json'] = tsconfig;
|
||||
if (tab?.frontmatter.title === 'Design') {
|
||||
return <DesignPreviewer {...props} />;
|
||||
}
|
||||
|
||||
const backgroundGrey = theme.includes('dark') ? '#303030' : '#f0f2f5';
|
||||
|
||||
const codeBoxDemoStyle: React.CSSProperties = {
|
||||
padding: meta.iframe || meta.compact ? 0 : undefined,
|
||||
overflow: meta.iframe || meta.compact ? 'hidden' : undefined,
|
||||
backgroundColor: meta.background === 'grey' ? backgroundGrey : undefined,
|
||||
return <CodePreviewer {...props} />;
|
||||
};
|
||||
|
||||
const codeBox: React.ReactNode = (
|
||||
<section className={codeBoxClass} id={meta.id}>
|
||||
<section className="code-box-demo" style={codeBoxDemoStyle}>
|
||||
<ErrorBoundary>
|
||||
<React.StrictMode>{liveDemo.current}</React.StrictMode>
|
||||
</ErrorBoundary>
|
||||
{style ? <style dangerouslySetInnerHTML={{ __html: style }} /> : null}
|
||||
</section>
|
||||
<section className="code-box-meta markdown">
|
||||
<div className="code-box-title">
|
||||
<Tooltip title={meta.originDebug ? <FormattedMessage id="app.demo.debug" /> : ''}>
|
||||
<a href={`#${meta.id}`} ref={anchorRef}>
|
||||
{localizedTitle}
|
||||
</a>
|
||||
</Tooltip>
|
||||
<EditButton
|
||||
title={<FormattedMessage id="app.content.edit-demo" />}
|
||||
filename={meta.filename}
|
||||
/>
|
||||
</div>
|
||||
<div className="code-box-description">{introChildren}</div>
|
||||
<Space wrap size="middle" className="code-box-actions">
|
||||
{showOnlineUrl && (
|
||||
<Tooltip title={<FormattedMessage id="app.demo.online" />}>
|
||||
<a
|
||||
className="code-box-code-action"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href={docsOnlineUrl}
|
||||
>
|
||||
<LinkOutlined className="code-box-online" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
{showRiddleButton ? (
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="//riddle.alibaba-inc.com/riddles/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={riddleIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'riddle', demo: meta.id });
|
||||
riddleIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<input type="hidden" name="data" value={JSON.stringify(riddlePrefillConfig)} />
|
||||
<Tooltip title={<FormattedMessage id="app.demo.riddle" />}>
|
||||
<RiddleIcon className="code-box-riddle" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
) : null}
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="https://codesandbox.io/api/v1/sandboxes/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={codeSandboxIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'codesandbox', demo: meta.id });
|
||||
codeSandboxIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="hidden"
|
||||
name="parameters"
|
||||
value={compress(JSON.stringify(codesanboxPrefillConfig))}
|
||||
/>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.codesandbox" />}>
|
||||
<CodeSandboxIcon className="code-box-codesandbox" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
action="https://codepen.io/pen/define"
|
||||
method="POST"
|
||||
target="_blank"
|
||||
ref={codepenIconRef}
|
||||
onClick={() => {
|
||||
track({ type: 'codepen', demo: meta.id });
|
||||
codepenIconRef.current?.submit();
|
||||
}}
|
||||
>
|
||||
<ClientOnly>
|
||||
<input type="hidden" name="data" value={JSON.stringify(codepenPrefillConfig)} />
|
||||
</ClientOnly>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.codepen" />}>
|
||||
<CodePenIcon className="code-box-codepen" />
|
||||
</Tooltip>
|
||||
</form>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.stackblitz" />}>
|
||||
<span
|
||||
className="code-box-code-action"
|
||||
onClick={() => {
|
||||
track({ type: 'stackblitz', demo: meta.id });
|
||||
stackblitzSdk.openProject(stackblitzPrefillConfig, {
|
||||
openFile: [`demo.${suffix}`],
|
||||
});
|
||||
}}
|
||||
>
|
||||
<ThunderboltOutlined className="code-box-stackblitz" />
|
||||
</span>
|
||||
</Tooltip>
|
||||
<CopyToClipboard text={sourceCodes?.tsx} onCopy={() => handleCodeCopied(meta.id)}>
|
||||
<Tooltip
|
||||
open={copyTooltipOpen as boolean}
|
||||
onOpenChange={onCopyTooltipOpenChange}
|
||||
title={<FormattedMessage id={`app.demo.${copied ? 'copied' : 'copy'}`} />}
|
||||
>
|
||||
{React.createElement(copied && copyTooltipOpen ? CheckOutlined : SnippetsOutlined, {
|
||||
className: 'code-box-code-copy code-box-code-action',
|
||||
})}
|
||||
</Tooltip>
|
||||
</CopyToClipboard>
|
||||
<Tooltip title={<FormattedMessage id="app.demo.separate" />}>
|
||||
<a className="code-box-code-action" target="_blank" rel="noreferrer" href={src}>
|
||||
<ExternalLinkIcon className="code-box-separate" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip
|
||||
title={<FormattedMessage id={`app.demo.code.${codeExpand ? 'hide' : 'show'}`} />}
|
||||
>
|
||||
<div className="code-expand-icon code-box-code-action">
|
||||
<img
|
||||
alt="expand code"
|
||||
src={
|
||||
theme?.includes('dark')
|
||||
? 'https://gw.alipayobjects.com/zos/antfincdn/btT3qDZn1U/wSAkBuJFbdxsosKKpqyq.svg'
|
||||
: 'https://gw.alipayobjects.com/zos/antfincdn/Z5c7kzvi30/expand.svg'
|
||||
}
|
||||
className={codeExpand ? 'code-expand-icon-hide' : 'code-expand-icon-show'}
|
||||
onClick={() => handleCodeExpand(meta.id)}
|
||||
/>
|
||||
<img
|
||||
alt="expand code"
|
||||
src={
|
||||
theme?.includes('dark')
|
||||
? 'https://gw.alipayobjects.com/zos/antfincdn/CjZPwcKUG3/OpROPHYqWmrMDBFMZtKF.svg'
|
||||
: 'https://gw.alipayobjects.com/zos/antfincdn/4zAaozCvUH/unexpand.svg'
|
||||
}
|
||||
className={codeExpand ? 'code-expand-icon-show' : 'code-expand-icon-hide'}
|
||||
onClick={() => handleCodeExpand(meta.id)}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</section>
|
||||
<section className={highlightClass} key="code">
|
||||
<CodePreview
|
||||
codes={highlightedCodes}
|
||||
toReactComponent={utils?.toReactComponent}
|
||||
onCodeTypeChange={(type) => setCodeType(type)}
|
||||
/>
|
||||
{highlightedStyle ? (
|
||||
<div key="style" className="highlight">
|
||||
<pre>
|
||||
<code className="css" dangerouslySetInnerHTML={{ __html: highlightedStyle }} />
|
||||
</pre>
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
</section>
|
||||
);
|
||||
|
||||
if (meta.version) {
|
||||
return (
|
||||
<Badge.Ribbon text={meta.version} color={meta.version.includes('<') ? 'red' : null}>
|
||||
{codeBox}
|
||||
</Badge.Ribbon>
|
||||
);
|
||||
}
|
||||
|
||||
return codeBox;
|
||||
};
|
||||
|
||||
export default fromDumiProps(Demo);
|
||||
export default Previewer;
|
||||
|
334
.dumi/theme/common/BehaviorMap/index.tsx
Normal file
334
.dumi/theme/common/BehaviorMap/index.tsx
Normal file
@ -0,0 +1,334 @@
|
||||
import type { FC } from 'react';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import G6 from '@antv/g6';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import { useRouteMeta } from 'dumi';
|
||||
|
||||
G6.registerNode('behavior-start-node', {
|
||||
draw: (cfg, group) => {
|
||||
const textWidth = G6.Util.getTextSize(cfg!.label, 16)[0];
|
||||
const size = [textWidth + 20 * 2, 48];
|
||||
const keyShape = group!.addShape('rect', {
|
||||
name: 'start-node',
|
||||
attrs: {
|
||||
width: size[0],
|
||||
height: size[1],
|
||||
y: -size[1] / 2,
|
||||
radius: 8,
|
||||
fill: '#fff',
|
||||
},
|
||||
});
|
||||
group!.addShape('text', {
|
||||
attrs: {
|
||||
text: `${cfg!.label}`,
|
||||
fill: 'rgba(0, 0, 0, 0.88)',
|
||||
fontSize: 16,
|
||||
fontWeight: 500,
|
||||
x: 20,
|
||||
textBaseline: 'middle',
|
||||
},
|
||||
name: 'start-node-text',
|
||||
});
|
||||
return keyShape;
|
||||
},
|
||||
getAnchorPoints() {
|
||||
return [
|
||||
[0, 0.5],
|
||||
[1, 0.5],
|
||||
];
|
||||
},
|
||||
});
|
||||
|
||||
G6.registerNode(
|
||||
'behavior-sub-node',
|
||||
{
|
||||
draw: (cfg, group) => {
|
||||
const textWidth = G6.Util.getTextSize(cfg!.label, 14)[0];
|
||||
const padding = 16;
|
||||
const size = [textWidth + 16 * 2 + (cfg!.targetType ? 12 : 0) + (cfg!.link ? 20 : 0), 40];
|
||||
const keyShape = group!.addShape('rect', {
|
||||
name: 'sub-node',
|
||||
attrs: {
|
||||
width: size[0],
|
||||
height: size[1],
|
||||
y: -size[1] / 2,
|
||||
radius: 8,
|
||||
fill: '#fff',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
});
|
||||
group!.addShape('text', {
|
||||
attrs: {
|
||||
text: `${cfg!.label}`,
|
||||
x: cfg!.targetType ? 12 + 16 : padding,
|
||||
fill: 'rgba(0, 0, 0, 0.88)',
|
||||
fontSize: 14,
|
||||
textBaseline: 'middle',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
name: 'sub-node-text',
|
||||
});
|
||||
if (cfg!.targetType) {
|
||||
group!.addShape('rect', {
|
||||
name: 'sub-node-type',
|
||||
attrs: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
radius: 4,
|
||||
y: -4,
|
||||
x: 12,
|
||||
fill: cfg!.targetType === 'mvp' ? '#1677ff' : '#A0A0A0',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
});
|
||||
}
|
||||
if (cfg!.children) {
|
||||
const { length } = cfg!.children as any;
|
||||
group!.addShape('rect', {
|
||||
name: 'sub-node-children-length',
|
||||
attrs: {
|
||||
width: 20,
|
||||
height: 20,
|
||||
radius: 10,
|
||||
y: -10,
|
||||
x: size[0] - 4,
|
||||
fill: '#404040',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
});
|
||||
group!.addShape('text', {
|
||||
name: 'sub-node-children-length-text',
|
||||
attrs: {
|
||||
text: `${length}`,
|
||||
x: size[0] + 6 - G6.Util.getTextSize(`${length}`, 12)[0] / 2,
|
||||
textBaseline: 'middle',
|
||||
fill: '#fff',
|
||||
fontSize: 12,
|
||||
cursor: 'pointer',
|
||||
},
|
||||
});
|
||||
}
|
||||
if (cfg!.link) {
|
||||
group!.addShape('dom', {
|
||||
attrs: {
|
||||
width: 16,
|
||||
height: 16,
|
||||
x: size[0] - 12 - 16,
|
||||
y: -8,
|
||||
cursor: 'pointer',
|
||||
// DOM's html
|
||||
html: `
|
||||
<div style="width: 16px; height: 16px;">
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="DatePicker" transform="translate(-890.000000, -441.000000)" fill-rule="nonzero">
|
||||
<g id="编组-30" transform="translate(288.000000, 354.000000)">
|
||||
<g id="编组-7备份-7" transform="translate(522.000000, 79.000000)">
|
||||
<g id="right-circle-outlinedd" transform="translate(80.000000, 8.000000)">
|
||||
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16"></rect>
|
||||
<path d="M10.4171875,7.8984375 L6.5734375,5.1171875 C6.490625,5.0578125 6.375,5.115625 6.375,5.21875 L6.375,5.9515625 C6.375,6.1109375 6.4515625,6.2625 6.58125,6.35625 L8.853125,8 L6.58125,9.64375 C6.4515625,9.7375 6.375,9.8875 6.375,10.0484375 L6.375,10.78125 C6.375,10.8828125 6.490625,10.9421875 6.5734375,10.8828125 L10.4171875,8.1015625 C10.4859375,8.0515625 10.4859375,7.9484375 10.4171875,7.8984375 Z" id="路径" fill="#BFBFBF"></path>
|
||||
<path d="M8,1 C4.134375,1 1,4.134375 1,8 C1,11.865625 4.134375,15 8,15 C11.865625,15 15,11.865625 15,8 C15,4.134375 11.865625,1 8,1 Z M8,13.8125 C4.790625,13.8125 2.1875,11.209375 2.1875,8 C2.1875,4.790625 4.790625,2.1875 8,2.1875 C11.209375,2.1875 13.8125,4.790625 13.8125,8 C13.8125,11.209375 11.209375,13.8125 8,13.8125 Z" id="形状" fill="#BFBFBF"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
`,
|
||||
},
|
||||
// 在 G6 3.3 及之后的版本中,必须指定 name,可以是任意字符串,但需要在同一个自定义元素类型中保持唯一性
|
||||
name: 'sub-node-link',
|
||||
});
|
||||
}
|
||||
return keyShape;
|
||||
},
|
||||
getAnchorPoints() {
|
||||
return [
|
||||
[0, 0.5],
|
||||
[1, 0.5],
|
||||
];
|
||||
},
|
||||
options: {
|
||||
stateStyles: {
|
||||
hover: {
|
||||
stroke: '#1677ff',
|
||||
'sub-node-link': {
|
||||
html: `
|
||||
<div style="width: 16px; height: 16px;">
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="DatePicker" transform="translate(-890.000000, -441.000000)" fill-rule="nonzero">
|
||||
<g id="编组-30" transform="translate(288.000000, 354.000000)">
|
||||
<g id="编组-7备份-7" transform="translate(522.000000, 79.000000)">
|
||||
<g id="right-circle-outlinedd" transform="translate(80.000000, 8.000000)">
|
||||
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16"></rect>
|
||||
<path d="M10.4171875,7.8984375 L6.5734375,5.1171875 C6.490625,5.0578125 6.375,5.115625 6.375,5.21875 L6.375,5.9515625 C6.375,6.1109375 6.4515625,6.2625 6.58125,6.35625 L8.853125,8 L6.58125,9.64375 C6.4515625,9.7375 6.375,9.8875 6.375,10.0484375 L6.375,10.78125 C6.375,10.8828125 6.490625,10.9421875 6.5734375,10.8828125 L10.4171875,8.1015625 C10.4859375,8.0515625 10.4859375,7.9484375 10.4171875,7.8984375 Z" id="路径" fill="#1677ff"></path>
|
||||
<path d="M8,1 C4.134375,1 1,4.134375 1,8 C1,11.865625 4.134375,15 8,15 C11.865625,15 15,11.865625 15,8 C15,4.134375 11.865625,1 8,1 Z M8,13.8125 C4.790625,13.8125 2.1875,11.209375 2.1875,8 C2.1875,4.790625 4.790625,2.1875 8,2.1875 C11.209375,2.1875 13.8125,4.790625 13.8125,8 C13.8125,11.209375 11.209375,13.8125 8,13.8125 Z" id="形状" fill="#1677ff"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'rect',
|
||||
);
|
||||
|
||||
const dataTransform = (data: BehaviorMapItem) => {
|
||||
const changeData = (d: any, level = 0) => {
|
||||
const clonedData: any = {
|
||||
...d,
|
||||
};
|
||||
switch (level) {
|
||||
case 0:
|
||||
clonedData.type = 'behavior-start-node';
|
||||
break;
|
||||
case 1:
|
||||
clonedData.type = 'behavior-sub-node';
|
||||
clonedData.collapsed = true;
|
||||
break;
|
||||
default:
|
||||
clonedData.type = 'behavior-sub-node';
|
||||
break;
|
||||
}
|
||||
|
||||
if (d.children) {
|
||||
clonedData.children = d.children.map((child: any) => changeData(child, level + 1));
|
||||
}
|
||||
return clonedData;
|
||||
};
|
||||
return changeData(data);
|
||||
};
|
||||
|
||||
type BehaviorMapItem = {
|
||||
id: string;
|
||||
label: string;
|
||||
targetType?: 'mvp' | 'extension';
|
||||
children?: BehaviorMapItem[];
|
||||
link?: string;
|
||||
};
|
||||
|
||||
const useStyle = createStyles(() => ({
|
||||
container: css`
|
||||
width: 100%;
|
||||
height: 600px;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
`,
|
||||
title: css`
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
font-size: 16px;
|
||||
`,
|
||||
tips: css`
|
||||
display: flex;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
`,
|
||||
mvp: css`
|
||||
margin-right: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&::before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: #1677ff;
|
||||
border-radius: 50%;
|
||||
margin-right: 8px;
|
||||
}
|
||||
`,
|
||||
extension: css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&::before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: #A0A0A0;
|
||||
border-radius: 50%;
|
||||
margin-right: 8px;
|
||||
}
|
||||
`,
|
||||
}));
|
||||
|
||||
export type BehaviorMapProps = {
|
||||
data: BehaviorMapItem;
|
||||
};
|
||||
|
||||
const BehaviorMap: FC<BehaviorMapProps> = ({ data }) => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const { styles } = useStyle();
|
||||
const meta = useRouteMeta();
|
||||
|
||||
useEffect(() => {
|
||||
const graph = new G6.TreeGraph({
|
||||
container: ref.current!,
|
||||
width: ref.current!.scrollWidth,
|
||||
height: ref.current!.scrollHeight,
|
||||
renderer: 'svg',
|
||||
modes: {
|
||||
default: ['collapse-expand', 'drag-canvas'],
|
||||
},
|
||||
defaultEdge: {
|
||||
type: 'cubic-horizontal',
|
||||
style: {
|
||||
lineWidth: 1,
|
||||
stroke: '#BFBFBF',
|
||||
},
|
||||
},
|
||||
layout: {
|
||||
type: 'mindmap',
|
||||
direction: 'LR',
|
||||
getHeight: () => 48,
|
||||
getWidth: (node: any) => G6.Util.getTextSize(node.label, 16)[0] + 20 * 2,
|
||||
getVGap: () => 10,
|
||||
getHGap: () => 60,
|
||||
getSide: (node: any) => node.data.direction,
|
||||
},
|
||||
});
|
||||
|
||||
graph.on('node:mouseenter', (e) => {
|
||||
graph.setItemState(e.item!, 'hover', true);
|
||||
});
|
||||
graph.on('node:mouseleave', (e) => {
|
||||
graph.setItemState(e.item!, 'hover', false);
|
||||
});
|
||||
graph.on('node:click', (e) => {
|
||||
const { link } = e.item!.getModel();
|
||||
if (link) {
|
||||
window.location.hash = link as string;
|
||||
}
|
||||
});
|
||||
|
||||
graph.data(dataTransform(data));
|
||||
graph.render();
|
||||
graph.fitCenter();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div ref={ref} className={styles.container}>
|
||||
<div className={styles.title}>{`${meta.frontmatter.title} 行为模式地图`}</div>
|
||||
<div className={styles.tips}>
|
||||
<div className={styles.mvp}>MVP 行为目的</div>
|
||||
<div className={styles.extension}>拓展行为目的</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BehaviorMap;
|
@ -5,7 +5,7 @@ import {
|
||||
parentSelectorLinter,
|
||||
StyleProvider,
|
||||
} from '@ant-design/cssinjs';
|
||||
import { ConfigProvider, theme as antdTheme } from 'antd';
|
||||
import { ConfigProvider, theme as antdTheme, App } from 'antd';
|
||||
import type { DirectionType } from 'antd/es/config-provider';
|
||||
import { createSearchParams, useOutlet, useSearchParams } from 'dumi';
|
||||
import React, { startTransition, useCallback, useEffect, useMemo } from 'react';
|
||||
@ -118,6 +118,7 @@ const GlobalLayout: React.FC = () => {
|
||||
algorithm: getAlgorithm(theme),
|
||||
}}
|
||||
>
|
||||
<App>
|
||||
{outlet}
|
||||
{!pathname.startsWith('/~demos') && (
|
||||
<ThemeSwitch
|
||||
@ -125,6 +126,7 @@ const GlobalLayout: React.FC = () => {
|
||||
onChange={(nextTheme) => updateSiteConfig({ theme: nextTheme })}
|
||||
/>
|
||||
)}
|
||||
</App>
|
||||
</ConfigProvider>
|
||||
</SiteContext.Provider>
|
||||
</StyleProvider>
|
||||
|
@ -4,7 +4,7 @@ import ContributorsList from '@qixian.cs/github-contributors-list';
|
||||
import { Affix, Anchor, Avatar, Col, Skeleton, Space, Tooltip, Typography } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import DayJS from 'dayjs';
|
||||
import { FormattedMessage, useIntl, useRouteMeta } from 'dumi';
|
||||
import { FormattedMessage, useIntl, useRouteMeta, useTabMeta } from 'dumi';
|
||||
import type { ReactNode } from 'react';
|
||||
import React, { useContext, useLayoutEffect, useMemo, useState } from 'react';
|
||||
import useLocation from '../../../hooks/useLocation';
|
||||
@ -107,6 +107,7 @@ type AnchorItem = {
|
||||
|
||||
const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const meta = useRouteMeta();
|
||||
const tab = useTabMeta();
|
||||
const { pathname, hash } = useLocation();
|
||||
const { formatMessage } = useIntl();
|
||||
const styles = useStyle();
|
||||
@ -132,7 +133,7 @@ const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
|
||||
const anchorItems = useMemo(
|
||||
() =>
|
||||
meta.toc.reduce<AnchorItem[]>((result, item) => {
|
||||
(tab?.toc || meta.toc).reduce<AnchorItem[]>((result, item) => {
|
||||
if (item.depth === 2) {
|
||||
result.push({ ...item });
|
||||
} else if (item.depth === 3) {
|
||||
@ -144,7 +145,7 @@ const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
}
|
||||
return result;
|
||||
}, []),
|
||||
[meta.toc],
|
||||
[tab?.toc, meta.toc],
|
||||
);
|
||||
|
||||
const isRTL = direction === 'rtl';
|
||||
@ -219,6 +220,7 @@ const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
</Space>
|
||||
</Typography.Paragraph>
|
||||
) : null}
|
||||
{meta.frontmatter.description !== meta.texts[0]?.value && meta.frontmatter.description}
|
||||
{children}
|
||||
{meta.frontmatter.filename && (
|
||||
<ContributorsList
|
||||
|
57
.dumi/theme/slots/ContentTabs/index.tsx
Normal file
57
.dumi/theme/slots/ContentTabs/index.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import type { FC, ReactNode } from 'react';
|
||||
import React from 'react';
|
||||
import { CodeOutlined, SkinOutlined } from '@ant-design/icons';
|
||||
import { Tabs } from 'antd';
|
||||
import { useRouteMeta } from 'dumi';
|
||||
import type { IContentTabsProps } from 'dumi/theme-default/slots/ContentTabs';
|
||||
import type { TabsProps } from 'rc-tabs';
|
||||
|
||||
const titleMap: Record<string, string> = {
|
||||
design: '设计',
|
||||
};
|
||||
|
||||
const iconMap: Record<string, ReactNode> = {
|
||||
design: <SkinOutlined />,
|
||||
};
|
||||
|
||||
const ContentTabs: FC<IContentTabsProps> = ({ tabs, tabKey, onChange }) => {
|
||||
const meta = useRouteMeta();
|
||||
|
||||
if (!meta.tabs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const items: TabsProps['items'] = [
|
||||
{
|
||||
label: (
|
||||
<span>
|
||||
<CodeOutlined />
|
||||
开发
|
||||
</span>
|
||||
),
|
||||
key: 'development',
|
||||
},
|
||||
];
|
||||
tabs?.forEach((tab) => {
|
||||
items.push({
|
||||
label: (
|
||||
<span>
|
||||
{iconMap[tab.key]}
|
||||
{titleMap[tab.key]}
|
||||
</span>
|
||||
),
|
||||
key: tab.key,
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
items={items}
|
||||
activeKey={tabKey || 'development'}
|
||||
onChange={(key) => onChange(tabs.find((tab) => tab.key === key))}
|
||||
style={{ margin: '32px 0 -16px' }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContentTabs;
|
@ -14,6 +14,7 @@ server
|
||||
.dumi/tmp-production
|
||||
!.dumi/
|
||||
node_modules
|
||||
.eslintcache
|
||||
_site
|
||||
dist
|
||||
coverage
|
||||
|
74
.github/workflows/codeql.yml
vendored
74
.github/workflows/codeql.yml
vendored
@ -1,74 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master", "feature" ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "master", "feature" ]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Use only 'java' to analyze code written in Java, Kotlin or both
|
||||
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
4
.github/workflows/size-limit.yml
vendored
4
.github/workflows/size-limit.yml
vendored
@ -25,6 +25,10 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: cache package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
|
33
.github/workflows/test.yml
vendored
33
.github/workflows/test.yml
vendored
@ -19,6 +19,10 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: cache package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@ -51,6 +55,10 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@ -73,6 +81,10 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@ -97,6 +109,10 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@ -136,6 +152,10 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@ -209,6 +229,11 @@ jobs:
|
||||
needs: [normal-test]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: coverage-artifacts
|
||||
@ -231,6 +256,10 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@ -278,6 +307,10 @@ jobs:
|
||||
if: ${{ github.event_name != 'pull_request' || matrix.module != 'lib' }}
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
# lib only run in master branch not in pull request
|
||||
if: ${{ github.event_name != 'pull_request' || matrix.module != 'lib' }}
|
||||
|
1
.jest.js
1
.jest.js
@ -52,6 +52,7 @@ module.exports = {
|
||||
'!components/*/__tests__/image.test.{ts,tsx}',
|
||||
'!components/__tests__/node.test.tsx',
|
||||
'!components/*/demo/*.tsx',
|
||||
'!components/*/design/**',
|
||||
],
|
||||
transformIgnorePatterns,
|
||||
globals: {
|
||||
|
@ -15,9 +15,29 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 5.2.2
|
||||
|
||||
`2023-02-19`
|
||||
|
||||
- DatePicker
|
||||
- 💄 Optimize DatePicker date panel style. [#40768](https://github.com/ant-design/ant-design/pull/40768)
|
||||
- 🐞 Fix RangePicker hover style on wrong date. [#40785](https://github.com/ant-design/ant-design/pull/40785) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- Form
|
||||
- 🐞 Fixed inconsistency between Checkbox and Radio in table when Form is `disabled`. [#40728](https://github.com/ant-design/ant-design/pull/40728) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 Fix Radio/Checkbox under Form `disabled` property don't works correctly. [#40741](https://github.com/ant-design/ant-design/pull/40741) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 Fix List extra padding when enable `grid` property. [#40806](https://github.com/ant-design/ant-design/pull/40806)
|
||||
- 🐞 Fix Upload actions icon alignment issue. [#40805](https://github.com/ant-design/ant-design/pull/40805)
|
||||
- 💄 Tweak Table filter dropdown radius style. [#40802](https://github.com/ant-design/ant-design/pull/40802)
|
||||
- 🐞 Fix Button `loading.delay` not delay at first time. [#40759](https://github.com/ant-design/ant-design/pull/40759) [@RedJue](https://github.com/RedJue)
|
||||
- 🐞 Fix Input status style when using `addonAfter` and `addonBefore`. [#40744](https://github.com/ant-design/ant-design/pull/40744) [@carla-cn](https://github.com/carla-cn)
|
||||
- 🐞 Fix Skeleton `active` flicky animation in Safari. [#40692](https://github.com/ant-design/ant-design/pull/40692) [@slotDumpling](https://github.com/slotDumpling)
|
||||
- Locales
|
||||
- 🇫🇷 Added french locale for Tour component. [#40750](https://github.com/ant-design/ant-design/pull/40750) [@RedJue](https://github.com/RedJue)
|
||||
- 🇰🇷 Update ko_KR locale. [#40716](https://github.com/ant-design/ant-design/pull/40716) [@owjs3901](https://github.com/owjs3901)
|
||||
|
||||
## 5.2.1
|
||||
|
||||
`2023-2-13`
|
||||
`2023-02-13`
|
||||
|
||||
- 🛠 Rewrite `panelRender` in Tour to function component。[#40670](https://github.com/ant-design/ant-design/pull/40670) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 Fix `className` property wrongly passed to child nodes in TimeLine。[#40700](https://github.com/ant-design/ant-design/pull/40700) [@any1024](https://github.com/any1024)
|
||||
@ -32,7 +52,7 @@ timeline: true
|
||||
|
||||
## 5.2.0
|
||||
|
||||
`2023-2-8`
|
||||
`2023-02-08`
|
||||
|
||||
- 🔥 Add `picture-circle` to Upload's `listType` prop. [#40134](https://github.com/ant-design/ant-design/pull/40134) [@ds1371dani](https://github.com/ds1371dani)
|
||||
- 🔥 Anchor component add `direction`, which supports vertical. [#39372](https://github.com/ant-design/ant-design/pull/39372) [@foryuki](https://github.com/foryuki)
|
||||
@ -94,7 +114,7 @@ timeline: true
|
||||
|
||||
## 5.1.7
|
||||
|
||||
`2023-1-31`
|
||||
`2023-01-31`
|
||||
|
||||
- Input
|
||||
- 🐞 Fix Input that unexpected cancel button is shown when `type="search"`. [#40457](https://github.com/ant-design/ant-design/pull/40457) [@MadCcc](https://github.com/MadCcc)
|
||||
@ -113,7 +133,7 @@ timeline: true
|
||||
|
||||
## 5.1.6
|
||||
|
||||
`2023-1-20`
|
||||
`2023-01-20`
|
||||
|
||||
- 🐞 Fix DatePicker animation timing function. [#40133](https://github.com/ant-design/ant-design/pull/40133) [@MadCcc](https://github.com/MadCcc)
|
||||
- Menu
|
||||
@ -131,7 +151,7 @@ timeline: true
|
||||
|
||||
## 5.1.5
|
||||
|
||||
`2023-1-15`
|
||||
`2023-01-15`
|
||||
|
||||
- 🐞 Fix Checkbox that label not aligned with checkbox. [#40208](https://github.com/ant-design/ant-design/pull/40208)
|
||||
- 🐞 Fix Button wave effect sometime makes layout shaking. [#40192](https://github.com/ant-design/ant-design/pull/40192)
|
||||
@ -148,7 +168,7 @@ timeline: true
|
||||
|
||||
## 5.1.4
|
||||
|
||||
`2023-1-9`
|
||||
`2023-01-09`
|
||||
|
||||
- 🐞 Fix missing locale file. [#40116](https://github.com/ant-design/ant-design/pull/40116)
|
||||
- 🐞 Fix Cascader dropdown `placement` in RTL mode. [#40109](https://github.com/ant-design/ant-design/pull/40109) [@3hson](https://github.com/3hson)
|
||||
@ -156,7 +176,7 @@ timeline: true
|
||||
|
||||
## 5.1.3
|
||||
|
||||
`2023-1-9`
|
||||
`2023-01-09`
|
||||
|
||||
- Table
|
||||
- 🛠 Optimize the Table `shouldCellUpdate` logic to increase the secondary rendering speed. [#40063](https://github.com/ant-design/ant-design/pull/40063)
|
||||
|
@ -15,9 +15,29 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 5.2.2
|
||||
|
||||
`2023-02-19`
|
||||
|
||||
- DatePicker
|
||||
- 💄 调整 DatePicker 组件日期面板的间距样式。[#40768](https://github.com/ant-design/ant-design/pull/40768)
|
||||
- 🐞 修复 RangePicker `hover` 日期错位的问题。[#40785](https://github.com/ant-design/ant-design/pull/40785) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- Form
|
||||
- 🐞 修复 Form 下 Radio/Checkbox 的 disabled 优先级问题。[#40741](https://github.com/ant-design/ant-design/pull/40741) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 修复 Form 为 `disabled` 时 Checkbox 和 Radio 表现不一致的问题。[#40728](https://github.com/ant-design/ant-design/pull/40728) [@Yuiai01](https://github.com/Yuiai01)
|
||||
- 🐞 修复 List 启用 `grid` 时下额外 `padding` 样式。[#40806](https://github.com/ant-design/ant-design/pull/40806)
|
||||
- 🐞 修复 Upload 操作图标不对齐的问题。[#40805](https://github.com/ant-design/ant-design/pull/40805)
|
||||
- 💄 调整 Table 筛选菜单的底部圆角样式。[#40802](https://github.com/ant-design/ant-design/pull/40802)
|
||||
- 🐞 修复 Button 组件 `loading.delay` 第一次不生效的问题。[#40759](https://github.com/ant-design/ant-design/pull/40759) [@RedJue](https://github.com/RedJue)
|
||||
- 🐞 修复 Input `addonAfter` 和 `addonBefore` 的各种状态样式。[#40744](https://github.com/ant-design/ant-design/pull/40744) [@carla-cn](https://github.com/carla-cn)
|
||||
- 🐞 修复 Skeleton 在 Safari 下 `active` 效果闪烁的问题。[#40692](https://github.com/ant-design/ant-design/pull/40692) [@slotDumpling](https://github.com/slotDumpling)
|
||||
- 国际化
|
||||
- 🇫🇷 补充 Tour 法语本地化文案。[#40750](https://github.com/ant-design/ant-design/pull/40750) [@RedJue](https://github.com/RedJue)
|
||||
- 🇰🇷 更新韩国本地化文案。[#40716](https://github.com/ant-design/ant-design/pull/40716) [@owjs3901](https://github.com/owjs3901)
|
||||
|
||||
## 5.2.1
|
||||
|
||||
`2023-2-13`
|
||||
`2023-02-13`
|
||||
|
||||
- 🛠 重构 Tour 中 `panelRender` 为函数式组件。[#40670](https://github.com/ant-design/ant-design/pull/40670) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 修复 TimeLine 中 `className` 传给子节点的问题。[#40700](https://github.com/ant-design/ant-design/pull/40700) [@any1024](https://github.com/any1024)
|
||||
@ -32,7 +52,7 @@ timeline: true
|
||||
|
||||
## 5.2.0
|
||||
|
||||
`2023-2-8`
|
||||
`2023-02-08`
|
||||
|
||||
- 🔥 Upload 的 `listType` 属性添加 `picture-circle` 支持。[#40134](https://github.com/ant-design/ant-design/pull/40134) [@ds1371dani](https://github.com/ds1371dani)
|
||||
- 🔥 Anchor 组件新增 `direction` 属性,支持 vertical。[#39372](https://github.com/ant-design/ant-design/pull/39372) [@foryuki](https://github.com/foryuki)
|
||||
@ -94,7 +114,7 @@ timeline: true
|
||||
|
||||
## 5.1.7
|
||||
|
||||
`2023-1-31`
|
||||
`2023-01-31`
|
||||
|
||||
- Input
|
||||
- 🐞 修复 Input 组件 `type="search"` 时未隐藏浏览器原生取消按钮的问题。[#40457](https://github.com/ant-design/ant-design/pull/40457) [@MadCcc](https://github.com/MadCcc)
|
||||
@ -113,7 +133,7 @@ timeline: true
|
||||
|
||||
## 5.1.6
|
||||
|
||||
`2023-1-20`
|
||||
`2023-01-20`
|
||||
|
||||
- 🐞 修复 DatePicker 等组件动画 timing function 错误的问题。[#40133](https://github.com/ant-design/ant-design/pull/40133) [@MadCcc](https://github.com/MadCcc)
|
||||
- Menu
|
||||
@ -131,7 +151,7 @@ timeline: true
|
||||
|
||||
## 5.1.5
|
||||
|
||||
`2023-1-15`
|
||||
`2023-01-15`
|
||||
|
||||
- 🐞 修复 Checkbox 组件 label 不对齐的问题。 [#40208](https://github.com/ant-design/ant-design/pull/40208)
|
||||
- 🐞 修复 Button 水波纹效果有时会使得布局抖动的问题。[#40192](https://github.com/ant-design/ant-design/pull/40192)
|
||||
@ -148,7 +168,7 @@ timeline: true
|
||||
|
||||
## 5.1.4
|
||||
|
||||
`2023-1-9`
|
||||
`2023-01-09`
|
||||
|
||||
- 🐞 修复 locale 文件丢失的问题。[#40116](https://github.com/ant-design/ant-design/pull/40116)
|
||||
- 🐞 修复 Cascader 组件 RTL 模式中下拉菜单位置问题。[#40109](https://github.com/ant-design/ant-design/pull/40109) [@3hson](https://github.com/3hson)
|
||||
@ -156,7 +176,7 @@ timeline: true
|
||||
|
||||
## 5.1.3
|
||||
|
||||
`2023-1-9`
|
||||
`2023-01-09`
|
||||
|
||||
- Table
|
||||
- 🛠 优化 Table `shouldCellUpdate` 逻辑,提升二次渲染速度。[#40063](https://github.com/ant-design/ant-design/pull/40063)
|
||||
|
@ -53,7 +53,7 @@ describe('Avatar Render', () => {
|
||||
|
||||
it('should handle onError correctly', () => {
|
||||
const LOAD_FAILURE_SRC = 'http://error.url/';
|
||||
const LOAD_SUCCESS_SRC = 'https://joeschmoe.io/api/v1/random';
|
||||
const LOAD_SUCCESS_SRC = 'https://joesch.moe/api/v1/random';
|
||||
const Foo: React.FC = () => {
|
||||
const [avatarSrc, setAvatarSrc] = useState<typeof LOAD_FAILURE_SRC | typeof LOAD_SUCCESS_SRC>(
|
||||
LOAD_FAILURE_SRC,
|
||||
@ -75,7 +75,7 @@ describe('Avatar Render', () => {
|
||||
|
||||
it('should show image on success after a failure state', () => {
|
||||
const LOAD_FAILURE_SRC = 'http://error.url';
|
||||
const LOAD_SUCCESS_SRC = 'https://joeschmoe.io/api/v1/random';
|
||||
const LOAD_SUCCESS_SRC = 'https://joesch.moe/api/v1/random';
|
||||
|
||||
const div = global.document.createElement('div');
|
||||
global.document.body.appendChild(div);
|
||||
@ -172,7 +172,7 @@ describe('Avatar Render', () => {
|
||||
});
|
||||
|
||||
it('should exist crossorigin attribute', () => {
|
||||
const LOAD_SUCCESS_SRC = 'https://joeschmoe.io/api/v1/random';
|
||||
const LOAD_SUCCESS_SRC = 'https://joesch.moe/api/v1/random';
|
||||
const crossOrigin = 'anonymous';
|
||||
const { container } = render(
|
||||
<Avatar src={LOAD_SUCCESS_SRC} crossOrigin={crossOrigin}>
|
||||
@ -184,7 +184,7 @@ describe('Avatar Render', () => {
|
||||
});
|
||||
|
||||
it('should not exist crossorigin attribute', () => {
|
||||
const LOAD_SUCCESS_SRC = 'https://joeschmoe.io/api/v1/random';
|
||||
const LOAD_SUCCESS_SRC = 'https://joesch.moe/api/v1/random';
|
||||
const { container } = render(<Avatar src={LOAD_SUCCESS_SRC}>crossorigin</Avatar>);
|
||||
expect(container.querySelector('img')?.crossOrigin).toBeFalsy();
|
||||
expect(container.querySelector('img')?.crossOrigin).toEqual('');
|
||||
|
@ -140,7 +140,7 @@ exports[`Avatar Render should handle onError correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
`;
|
||||
@ -163,7 +163,7 @@ exports[`Avatar Render should show image on success after a failure state 2`] =
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
`;
|
||||
|
@ -415,7 +415,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=1"
|
||||
/>
|
||||
</span>
|
||||
<a
|
||||
@ -512,7 +512,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=2"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
@ -638,7 +638,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=3"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
|
@ -415,7 +415,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=1"
|
||||
/>
|
||||
</span>
|
||||
<a
|
||||
@ -493,7 +493,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=2"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
@ -530,7 +530,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=3"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
import { AntDesignOutlined, UserOutlined } from '@ant-design/icons';
|
||||
import { Avatar, Divider, Tooltip } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<>
|
||||
<Avatar.Group>
|
||||
<Avatar src="https://joeschmoe.io/api/v1/random" />
|
||||
<Avatar src="https://joesch.moe/api/v1/random?key=1" />
|
||||
<a href="https://ant.design">
|
||||
<Avatar style={{ backgroundColor: '#f56a00' }}>K</Avatar>
|
||||
</a>
|
||||
@ -16,7 +16,7 @@ const App: React.FC = () => (
|
||||
</Avatar.Group>
|
||||
<Divider />
|
||||
<Avatar.Group maxCount={2} maxStyle={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>
|
||||
<Avatar src="https://joeschmoe.io/api/v1/random" />
|
||||
<Avatar src="https://joesch.moe/api/v1/random?key=2" />
|
||||
<Avatar style={{ backgroundColor: '#f56a00' }}>K</Avatar>
|
||||
<Tooltip title="Ant User" placement="top">
|
||||
<Avatar style={{ backgroundColor: '#87d068' }} icon={<UserOutlined />} />
|
||||
@ -29,7 +29,7 @@ const App: React.FC = () => (
|
||||
size="large"
|
||||
maxStyle={{ color: '#f56a00', backgroundColor: '#fde3cf' }}
|
||||
>
|
||||
<Avatar src="https://joeschmoe.io/api/v1/random" />
|
||||
<Avatar src="https://joesch.moe/api/v1/random?key=3" />
|
||||
<Avatar style={{ backgroundColor: '#f56a00' }}>K</Avatar>
|
||||
<Tooltip title="Ant User" placement="top">
|
||||
<Avatar style={{ backgroundColor: '#87d068' }} icon={<UserOutlined />} />
|
||||
|
@ -91,3 +91,8 @@ it('Delay loading timer in Button component', () => {
|
||||
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
it('Delay loading while use loading delay at first time', () => {
|
||||
const Demo = () => <Button loading={{ delay: specialDelay }} />;
|
||||
const wrapper = render(<Demo />);
|
||||
expect(wrapper.container.firstChild).not.toHaveClass('ant-btn-loading');
|
||||
});
|
||||
|
@ -2,19 +2,19 @@
|
||||
import classNames from 'classnames';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
import * as React from 'react';
|
||||
import warning from '../_util/warning';
|
||||
import Wave from '../_util/wave';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import DisabledContext from '../config-provider/DisabledContext';
|
||||
import SizeContext from '../config-provider/SizeContext';
|
||||
import { useCompactItemContext } from '../space/Compact';
|
||||
import warning from '../_util/warning';
|
||||
import Wave from '../_util/wave';
|
||||
import Group, { GroupSizeContext } from './button-group';
|
||||
import { isTwoCNChar, isUnBorderedButtonType, spaceChildren } from './buttonHelpers';
|
||||
import LoadingIcon from './LoadingIcon';
|
||||
import useStyle from './style';
|
||||
|
||||
import type { ButtonType, ButtonHTMLType, ButtonShape } from './buttonHelpers';
|
||||
import type { SizeType } from '../config-provider/SizeContext';
|
||||
import type { ButtonHTMLType, ButtonShape, ButtonType } from './buttonHelpers';
|
||||
|
||||
export type LegacyButtonType = ButtonType | 'danger';
|
||||
|
||||
@ -66,6 +66,27 @@ type CompoundedComponent = React.ForwardRefExoticComponent<
|
||||
|
||||
type Loading = number | boolean;
|
||||
|
||||
type LoadingConfigType = {
|
||||
loading: boolean;
|
||||
delay: number;
|
||||
};
|
||||
|
||||
function getLoadingConfig(loading: BaseButtonProps['loading']): LoadingConfigType {
|
||||
if (typeof loading === 'object' && loading) {
|
||||
const delay = loading?.delay;
|
||||
const isDelay = !Number.isNaN(delay) && typeof delay === 'number';
|
||||
return {
|
||||
loading: false,
|
||||
delay: isDelay ? delay : 0,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
loading: !!loading,
|
||||
delay: 0,
|
||||
};
|
||||
}
|
||||
|
||||
const InternalButton: React.ForwardRefRenderFunction<
|
||||
HTMLButtonElement | HTMLAnchorElement,
|
||||
ButtonProps
|
||||
@ -99,7 +120,11 @@ const InternalButton: React.ForwardRefRenderFunction<
|
||||
const mergedDisabled = customDisabled ?? disabled;
|
||||
|
||||
const groupSize = React.useContext(GroupSizeContext);
|
||||
const [innerLoading, setLoading] = React.useState<Loading>(!!loading);
|
||||
const loadingOrDelay: LoadingConfigType = React.useMemo(
|
||||
() => getLoadingConfig(loading),
|
||||
[loading],
|
||||
);
|
||||
const [innerLoading, setLoading] = React.useState<Loading>(loadingOrDelay.loading);
|
||||
const [hasTwoCNChar, setHasTwoCNChar] = React.useState(false);
|
||||
const buttonRef = (ref as any) || React.createRef<HTMLAnchorElement | HTMLButtonElement>();
|
||||
|
||||
@ -121,18 +146,16 @@ const InternalButton: React.ForwardRefRenderFunction<
|
||||
}
|
||||
};
|
||||
|
||||
const loadingOrDelay: Loading = typeof loading === 'boolean' ? loading : loading?.delay || true;
|
||||
|
||||
React.useEffect(() => {
|
||||
let delayTimer: number | null = null;
|
||||
|
||||
if (typeof loadingOrDelay === 'number') {
|
||||
if (loadingOrDelay.delay > 0) {
|
||||
delayTimer = window.setTimeout(() => {
|
||||
delayTimer = null;
|
||||
setLoading(loadingOrDelay);
|
||||
}, loadingOrDelay);
|
||||
setLoading(true);
|
||||
}, loadingOrDelay.delay);
|
||||
} else {
|
||||
setLoading(loadingOrDelay);
|
||||
setLoading(loadingOrDelay.loading);
|
||||
}
|
||||
|
||||
function cleanupTimer() {
|
||||
|
@ -601,7 +601,7 @@ exports[`renders ./components/card/demo/meta.tsx extend context correctly 1`] =
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -601,7 +601,7 @@ exports[`renders ./components/card/demo/meta.tsx correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { EditOutlined, EllipsisOutlined, SettingOutlined } from '@ant-design/icons';
|
||||
import { Avatar, Card, Skeleton, Switch } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const { Meta } = Card;
|
||||
|
||||
@ -14,15 +14,13 @@ const App: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<Switch checked={!loading} onChange={onChange} />
|
||||
|
||||
<Card style={{ width: 300, marginTop: 16 }} loading={loading}>
|
||||
<Meta
|
||||
avatar={<Avatar src="https://joeschmoe.io/api/v1/random" />}
|
||||
avatar={<Avatar src="https://joesch.moe/api/v1/random?key=1" />}
|
||||
title="Card title"
|
||||
description="This is the description"
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
style={{ width: 300, marginTop: 16 }}
|
||||
actions={[
|
||||
@ -33,7 +31,7 @@ const App: React.FC = () => {
|
||||
>
|
||||
<Skeleton loading={loading} avatar active>
|
||||
<Meta
|
||||
avatar={<Avatar src="https://joeschmoe.io/api/v1/random" />}
|
||||
avatar={<Avatar src="https://joesch.moe/api/v1/random?key=2" />}
|
||||
title="Card title"
|
||||
description="This is the description"
|
||||
/>
|
||||
|
@ -20,7 +20,7 @@ const App: React.FC = () => (
|
||||
]}
|
||||
>
|
||||
<Meta
|
||||
avatar={<Avatar src="https://joeschmoe.io/api/v1/random" />}
|
||||
avatar={<Avatar src="https://joesch.moe/api/v1/random" />}
|
||||
title="Card title"
|
||||
description="This is the description"
|
||||
/>
|
||||
|
@ -2,8 +2,8 @@ import React, { useState } from 'react';
|
||||
import { Cascader } from 'antd';
|
||||
|
||||
interface Option {
|
||||
value: string;
|
||||
label: string;
|
||||
value?: string | number | null;
|
||||
label: React.ReactNode;
|
||||
children?: Option[];
|
||||
isLeaf?: boolean;
|
||||
loading?: boolean;
|
||||
@ -25,7 +25,7 @@ const optionLists: Option[] = [
|
||||
const App: React.FC = () => {
|
||||
const [options, setOptions] = useState<Option[]>(optionLists);
|
||||
|
||||
const onChange = (value: string[], selectedOptions: Option[]) => {
|
||||
const onChange = (value: (string | number)[], selectedOptions: Option[]) => {
|
||||
console.log(value, selectedOptions);
|
||||
};
|
||||
|
||||
|
@ -16015,7 +16015,7 @@ exports[`ConfigProvider components Input configProvider componentDisabled 1`] =
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="config-input-group-wrapper config-input-search"
|
||||
class="config-input-group-wrapper config-input-search config-input-group-wrapper-disabled"
|
||||
>
|
||||
<span
|
||||
class="config-input-wrapper config-input-group"
|
||||
@ -17327,7 +17327,7 @@ exports[`ConfigProvider components List configProvider 1`] = `
|
||||
class="config-avatar config-avatar-circle config-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -17379,7 +17379,7 @@ exports[`ConfigProvider components List configProvider componentDisabled 1`] = `
|
||||
class="config-avatar config-avatar-circle config-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -17431,7 +17431,7 @@ exports[`ConfigProvider components List configProvider componentSize large 1`] =
|
||||
class="config-avatar config-avatar-circle config-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -17483,7 +17483,7 @@ exports[`ConfigProvider components List configProvider componentSize middle 1`]
|
||||
class="config-avatar config-avatar-circle config-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -17535,7 +17535,7 @@ exports[`ConfigProvider components List configProvider virtual and dropdownMatch
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -17587,7 +17587,7 @@ exports[`ConfigProvider components List normal 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -17639,7 +17639,7 @@ exports[`ConfigProvider components List prefixCls 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -40,6 +40,7 @@ import Skeleton from '../../skeleton';
|
||||
import type { SliderTooltipProps } from '../../slider';
|
||||
import Slider from '../../slider';
|
||||
// eslint-disable-next-line import/no-named-as-default
|
||||
import { render } from '../../../tests/utils';
|
||||
import Spin from '../../spin';
|
||||
import Statistic from '../../statistic';
|
||||
import Steps from '../../steps';
|
||||
@ -55,7 +56,6 @@ import Transfer from '../../transfer';
|
||||
import Tree from '../../tree';
|
||||
import TreeSelect from '../../tree-select';
|
||||
import Upload from '../../upload';
|
||||
import { render } from '../../../tests/utils';
|
||||
|
||||
dayjs.extend(customParseFormat);
|
||||
jest.mock('rc-util/lib/Portal');
|
||||
@ -351,7 +351,7 @@ describe('ConfigProvider', () => {
|
||||
<List.Item {...props}>
|
||||
<List.Item.Meta
|
||||
{...props}
|
||||
avatar={<Avatar src="https://joeschmoe.io/api/v1/random" />}
|
||||
avatar={<Avatar src="https://joesch.moe/api/v1/random" />}
|
||||
title="Ant Design"
|
||||
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
|
||||
/>
|
||||
|
112
components/date-picker/design/behavior-pattern.tsx
Normal file
112
components/date-picker/design/behavior-pattern.tsx
Normal file
@ -0,0 +1,112 @@
|
||||
import React from 'react';
|
||||
import BehaviorMap from '../../../.dumi/theme/common/BehaviorMap';
|
||||
|
||||
const BehaviorPattern = () => (
|
||||
<BehaviorMap
|
||||
data={{
|
||||
id: '200000004',
|
||||
label: '选择(输入)日期数据',
|
||||
children: [
|
||||
{
|
||||
id: '500000061',
|
||||
label: '选择时间点',
|
||||
targetType: 'mvp',
|
||||
children: [
|
||||
{
|
||||
id: '707000085',
|
||||
label: '选择某天',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-pick-date',
|
||||
},
|
||||
{
|
||||
id: '707000086',
|
||||
label: '选择某周',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-pick-week',
|
||||
},
|
||||
{
|
||||
id: '707000087',
|
||||
label: '选择某月',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-pick-month',
|
||||
},
|
||||
{
|
||||
id: '707000088',
|
||||
label: '选择某季度',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-pick-quarter',
|
||||
},
|
||||
{
|
||||
id: '707000089',
|
||||
label: '选择某年',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-pick-year',
|
||||
},
|
||||
{
|
||||
id: '707000090',
|
||||
label: '选择某时间',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-pick-time',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '200000005',
|
||||
label: '选择时间段',
|
||||
targetType: 'mvp',
|
||||
children: [
|
||||
{
|
||||
id: '7070000851',
|
||||
label: '选择某天至某天',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-pick-date-range',
|
||||
},
|
||||
{
|
||||
id: '7070000861',
|
||||
label: '选择某周至某周',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-pick-week-range',
|
||||
},
|
||||
{
|
||||
id: '7070000871',
|
||||
label: '选择某月至某月',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-pick-month-range',
|
||||
},
|
||||
{
|
||||
id: '7070000881',
|
||||
label: '选择某季度至某季度',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-pick-quarter-range',
|
||||
},
|
||||
{
|
||||
id: '7070000891',
|
||||
label: '选择某年至某年',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-pick-year-range',
|
||||
},
|
||||
{
|
||||
id: '7070000901',
|
||||
label: '选择某时间至某时间',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-pick-time-range',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '200000006',
|
||||
label: '快捷选择日期数据',
|
||||
targetType: 'extension',
|
||||
children: [
|
||||
{
|
||||
id: '70700008912',
|
||||
label: '快捷选择时间点',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-preset-time',
|
||||
},
|
||||
{
|
||||
id: '70700009012',
|
||||
label: '快捷选择时间段',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-preset-range',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '200000007',
|
||||
label: '查看日期附属信息',
|
||||
targetType: 'extension',
|
||||
link: 'components-date-picker-index-tab-design-zh-cn-demo-date-extra-info',
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export default BehaviorPattern;
|
120
components/date-picker/design/demo/date-extra-info.tsx
Normal file
120
components/date-picker/design/demo/date-extra-info.tsx
Normal file
@ -0,0 +1,120 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import classNames from 'classnames';
|
||||
|
||||
const { _InternalPanelDoNotUseOrYouWillBeFired: PureDatePicker } = DatePicker;
|
||||
|
||||
const useStyle = createStyles(({ token }) => ({
|
||||
weekendCell: css`
|
||||
color: #ff4d4f40;
|
||||
.ant-picker-cell-in-view & {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
`,
|
||||
detailedCell: css`
|
||||
width: 40px;
|
||||
height: 40px !important;
|
||||
`,
|
||||
detailedPicker: css`
|
||||
.ant-picker-date-panel {
|
||||
width: auto;
|
||||
.ant-picker-content {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
`,
|
||||
extraInfo: css`
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
transform: scale(${10 / 12});
|
||||
color: ${token.colorTextQuaternary};
|
||||
.ant-picker-cell-in-view & {
|
||||
color: ${token.colorTextSecondary};
|
||||
}
|
||||
.ant-picker-cell-selected & {
|
||||
color: #fff;
|
||||
}
|
||||
`,
|
||||
add: css`
|
||||
color: #ff4d4f80;
|
||||
.ant-picker-cell-in-view & {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
.ant-picker-cell-selected & {
|
||||
color: #fff;
|
||||
}
|
||||
`,
|
||||
minus: css`
|
||||
color: #52C41A80;
|
||||
.ant-picker-cell-in-view & {
|
||||
color: #52C41A;
|
||||
}
|
||||
.ant-picker-cell-selected & {
|
||||
color: #fff;
|
||||
}
|
||||
`,
|
||||
}));
|
||||
|
||||
const seeds = Array(30)
|
||||
.fill(1)
|
||||
.map(() => Math.random());
|
||||
|
||||
const getSales = (date: Dayjs) => Math.floor(seeds[date.date() % 30] * 10000);
|
||||
|
||||
const getData = (date: Dayjs) => (Math.floor(seeds[date.date() % 30] * 10000) - 5000) / 5000;
|
||||
|
||||
const Demo: FC = () => {
|
||||
const { styles } = useStyle();
|
||||
const dateRender = (current: Dayjs) => (
|
||||
<div
|
||||
className={classNames(
|
||||
'ant-picker-cell-inner',
|
||||
[6, 0].includes(current.day()) && styles.weekendCell,
|
||||
)}
|
||||
>
|
||||
{current.date()}
|
||||
</div>
|
||||
);
|
||||
|
||||
const saleDateRender = (current: Dayjs) => (
|
||||
<div className={classNames('ant-picker-cell-inner', styles.detailedCell)}>
|
||||
{current.date()}
|
||||
<div className={styles.extraInfo}>{getSales(current)}</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const dataDateRender = (current: Dayjs) => {
|
||||
const data = getData(current);
|
||||
|
||||
return (
|
||||
<div className={classNames('ant-picker-cell-inner', styles.detailedCell)}>
|
||||
{current.date()}
|
||||
<div className={classNames(styles.extraInfo, data > 0 ? styles.add : styles.minus)}>
|
||||
{data.toFixed(2)}%
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ width: '100%' }}>
|
||||
<div style={{ color: 'rgba(0,0,0,0.45)', marginBottom: 32 }}>办公场景:预览节假日信息</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'center', marginBottom: 40 }}>
|
||||
<PureDatePicker dateRender={dateRender} popupClassName={styles.detailedPicker} />
|
||||
</div>
|
||||
<div style={{ color: 'rgba(0,0,0,0.45)', marginBottom: 32 }}>电商场景:预览销售额信息</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'center', marginBottom: 40 }}>
|
||||
<PureDatePicker dateRender={saleDateRender} popupClassName={styles.detailedPicker} />
|
||||
</div>
|
||||
<div style={{ color: 'rgba(0,0,0,0.45)', marginBottom: 32 }}>大数据场景:预览数据波动</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'center', marginBottom: 40 }}>
|
||||
<PureDatePicker dateRender={dataDateRender} popupClassName={styles.detailedPicker} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Demo;
|
9
components/date-picker/design/demo/pick-date-range.tsx
Normal file
9
components/date-picker/design/demo/pick-date-range.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
|
||||
const { _InternalRangePanelDoNotUseOrYouWillBeFired: PureRangePicker } = DatePicker;
|
||||
|
||||
const Demo: FC = () => <PureRangePicker />;
|
||||
|
||||
export default Demo;
|
9
components/date-picker/design/demo/pick-date.tsx
Normal file
9
components/date-picker/design/demo/pick-date.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
|
||||
const { _InternalPanelDoNotUseOrYouWillBeFired: PureDatePicker } = DatePicker;
|
||||
|
||||
const Demo: FC = () => <PureDatePicker />;
|
||||
|
||||
export default Demo;
|
9
components/date-picker/design/demo/pick-month-range.tsx
Normal file
9
components/date-picker/design/demo/pick-month-range.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
|
||||
const { _InternalRangePanelDoNotUseOrYouWillBeFired: PureRangePicker } = DatePicker;
|
||||
|
||||
const Demo: FC = () => <PureRangePicker picker="month" />;
|
||||
|
||||
export default Demo;
|
9
components/date-picker/design/demo/pick-month.tsx
Normal file
9
components/date-picker/design/demo/pick-month.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
|
||||
const { _InternalPanelDoNotUseOrYouWillBeFired: PureDatePicker } = DatePicker;
|
||||
|
||||
const Demo: FC = () => <PureDatePicker picker="month" />;
|
||||
|
||||
export default Demo;
|
@ -0,0 +1,9 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
|
||||
const { _InternalRangePanelDoNotUseOrYouWillBeFired: PureRangePicker } = DatePicker;
|
||||
|
||||
const Demo: FC = () => <PureRangePicker picker="quarter" />;
|
||||
|
||||
export default Demo;
|
9
components/date-picker/design/demo/pick-quarter.tsx
Normal file
9
components/date-picker/design/demo/pick-quarter.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
|
||||
const { _InternalPanelDoNotUseOrYouWillBeFired: PureDatePicker } = DatePicker;
|
||||
|
||||
const Demo: FC = () => <PureDatePicker picker="quarter" />;
|
||||
|
||||
export default Demo;
|
9
components/date-picker/design/demo/pick-time-range.tsx
Normal file
9
components/date-picker/design/demo/pick-time-range.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
|
||||
const { _InternalRangePanelDoNotUseOrYouWillBeFired: PureRangePicker } = DatePicker;
|
||||
|
||||
const Demo: FC = () => <PureRangePicker showTime />;
|
||||
|
||||
export default Demo;
|
9
components/date-picker/design/demo/pick-time.tsx
Normal file
9
components/date-picker/design/demo/pick-time.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
|
||||
const { _InternalPanelDoNotUseOrYouWillBeFired: PureDatePicker } = DatePicker;
|
||||
|
||||
const Demo: FC = () => <PureDatePicker showTime />;
|
||||
|
||||
export default Demo;
|
9
components/date-picker/design/demo/pick-week-range.tsx
Normal file
9
components/date-picker/design/demo/pick-week-range.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
|
||||
const { _InternalRangePanelDoNotUseOrYouWillBeFired: PureRangePicker } = DatePicker;
|
||||
|
||||
const Demo: FC = () => <PureRangePicker picker="week" />;
|
||||
|
||||
export default Demo;
|
9
components/date-picker/design/demo/pick-week.tsx
Normal file
9
components/date-picker/design/demo/pick-week.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
|
||||
const { _InternalPanelDoNotUseOrYouWillBeFired: PureDatePicker } = DatePicker;
|
||||
|
||||
const Demo: FC = () => <PureDatePicker picker="week" />;
|
||||
|
||||
export default Demo;
|
9
components/date-picker/design/demo/pick-year-range.tsx
Normal file
9
components/date-picker/design/demo/pick-year-range.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
|
||||
const { _InternalRangePanelDoNotUseOrYouWillBeFired: PureRangePicker } = DatePicker;
|
||||
|
||||
const Demo: FC = () => <PureRangePicker picker="year" />;
|
||||
|
||||
export default Demo;
|
9
components/date-picker/design/demo/pick-year.tsx
Normal file
9
components/date-picker/design/demo/pick-year.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
|
||||
const { _InternalPanelDoNotUseOrYouWillBeFired: PureDatePicker } = DatePicker;
|
||||
|
||||
const Demo: FC = () => <PureDatePicker picker="year" />;
|
||||
|
||||
export default Demo;
|
18
components/date-picker/design/demo/preset-range.tsx
Normal file
18
components/date-picker/design/demo/preset-range.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const { _InternalRangePanelDoNotUseOrYouWillBeFired: PureRangePicker } = DatePicker;
|
||||
|
||||
const App: React.FC = () => (
|
||||
<PureRangePicker
|
||||
presets={[
|
||||
{ label: 'Last 7 Days', value: [dayjs().add(-7, 'd'), dayjs()] },
|
||||
{ label: 'Last 14 Days', value: [dayjs().add(-14, 'd'), dayjs()] },
|
||||
{ label: 'Last 30 Days', value: [dayjs().add(-30, 'd'), dayjs()] },
|
||||
{ label: 'Last 90 Days', value: [dayjs().add(-90, 'd'), dayjs()] },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
export default App;
|
17
components/date-picker/design/demo/preset-time.tsx
Normal file
17
components/date-picker/design/demo/preset-time.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import { DatePicker } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const { _InternalPanelDoNotUseOrYouWillBeFired: PureDatePicker } = DatePicker;
|
||||
|
||||
const App: React.FC = () => (
|
||||
<PureDatePicker
|
||||
presets={[
|
||||
{ label: 'Yesterday', value: dayjs().add(-1, 'd') },
|
||||
{ label: 'Last Week', value: dayjs().add(-7, 'd') },
|
||||
{ label: 'Last Month', value: dayjs().add(-1, 'month') },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
export default App;
|
39
components/date-picker/index.$tab-design.zh-CN.md
Normal file
39
components/date-picker/index.$tab-design.zh-CN.md
Normal file
@ -0,0 +1,39 @@
|
||||
## 组件定义
|
||||
|
||||
DatePicker 的本质是选择(输入)日期型数据。
|
||||
|
||||
<code src="./design/behavior-pattern.tsx" inline></code>
|
||||
|
||||
## 基础使用
|
||||
|
||||
<code src="./design/demo/pick-date.tsx" description="用于具体日期的选择。用户仅需要输入非常具体的日期信息时使用。">选择某天</code>
|
||||
|
||||
<code src="./design/demo/pick-week.tsx" description="用于周的选择。用户仅需输入年份 + 周信息时使用。">选择某周</code>
|
||||
|
||||
<code src="./design/demo/pick-month.tsx" description="用于月份的选择。用户仅需输入年份 + 月份信息时使用。">选择某月</code>
|
||||
|
||||
<code src="./design/demo/pick-quarter.tsx" description="用于季度的选择。用户仅需输入年份 + 季度信息时使用。">选择某季度</code>
|
||||
|
||||
<code src="./design/demo/pick-year.tsx" description="用于年的选择。用户仅需输入年份时使用。">选择某年</code>
|
||||
|
||||
<code src="./design/demo/pick-time.tsx" description="用于具体时刻的选择。用户需输入年份+月份+日期+时间信息时使用。">选择某时刻</code>
|
||||
|
||||
<code src="./design/demo/pick-date-range.tsx" description="用于具体日期范围的选择。">选择某天至某天</code>
|
||||
|
||||
<code src="./design/demo/pick-week-range.tsx" description="用于周范围的选择。">选择某周至某周</code>
|
||||
|
||||
<code src="./design/demo/pick-month-range.tsx" description="用于月范围的选择。">选择某月至某月</code>
|
||||
|
||||
<code src="./design/demo/pick-quarter-range.tsx" description="用于季度范围的选择。">选择某季度至某季度</code>
|
||||
|
||||
<code src="./design/demo/pick-year-range.tsx" description="用于年范围的选择。">选择某年至某年</code>
|
||||
|
||||
<code src="./design/demo/pick-time-range.tsx" description="用于具体时刻范围的选择。">选择某时刻至某时刻</code>
|
||||
|
||||
## 交互变体
|
||||
|
||||
<code src="./design/demo/preset-time.tsx" description="通过面板左侧区域提供的预置项,帮助用户快速完成时间点的选择。" tip="根据希克定律,建议快捷选项的个数不超过8个。">快捷选择时间点</code>
|
||||
|
||||
<code src="./design/demo/preset-range.tsx" description="通过面板左侧区域提供的预置项,帮助用户快速完成时间段的选择。" tip="根据希克定律,建议快捷选项的个数不超过8个。">快捷选择时间段</code>
|
||||
|
||||
<code src="./design/demo/date-extra-info.tsx" description="通过定义日期单元格内容及样式,为用户展示更多业务场景相关信息作为选择参考。">查看日期附属信息</code>
|
@ -2,14 +2,13 @@
|
||||
category: Components
|
||||
group: Data Entry
|
||||
title: DatePicker
|
||||
description: To select or input a date.
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*xXA9TJ8BTioAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*3OpRQKcygo8AAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
cols: 2
|
||||
---
|
||||
|
||||
To select or input a date.
|
||||
|
||||
## When To Use
|
||||
|
||||
By clicking the input box, you can select a date from a popup calendar.
|
||||
|
@ -19,7 +19,10 @@ const DatePicker = generatePicker<Dayjs>(dayjsGenerateConfig);
|
||||
/* istanbul ignore next */
|
||||
const PurePanel = genPurePanel(DatePicker, 'picker');
|
||||
(DatePicker as any)._InternalPanelDoNotUseOrYouWillBeFired = PurePanel;
|
||||
const PureRangePanel = genPurePanel(DatePicker.RangePicker, 'picker');
|
||||
(DatePicker as any)._InternalRangePanelDoNotUseOrYouWillBeFired = PureRangePanel;
|
||||
|
||||
export default DatePicker as typeof DatePicker & {
|
||||
_InternalPanelDoNotUseOrYouWillBeFired: typeof PurePanel;
|
||||
_InternalRangePanelDoNotUseOrYouWillBeFired: typeof PureRangePanel;
|
||||
};
|
||||
|
@ -3,14 +3,13 @@ category: Components
|
||||
group: 数据录入
|
||||
title: DatePicker
|
||||
subtitle: 日期选择框
|
||||
description: 输入或选择日期的控件。
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*xXA9TJ8BTioAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*3OpRQKcygo8AAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
cols: 2
|
||||
---
|
||||
|
||||
输入或选择日期的控件。
|
||||
|
||||
## 何时使用
|
||||
|
||||
当用户需要输入一个日期,可以点击标准输入框,弹出日期面板进行选择。
|
||||
|
@ -206,6 +206,8 @@ const genPickerCellInnerStyle = (token: SharedPickerToken): CSSObject => {
|
||||
|
||||
// Hover with in range
|
||||
[`&-in-view${pickerCellCls}-in-range${pickerCellCls}-range-hover::before,
|
||||
&-in-view${pickerCellCls}-in-range${pickerCellCls}-range-hover-start::before,
|
||||
&-in-view${pickerCellCls}-in-range${pickerCellCls}-range-hover-end::before,
|
||||
&-in-view${pickerCellCls}-range-start${pickerCellCls}-range-hover::before,
|
||||
&-in-view${pickerCellCls}-range-end${pickerCellCls}-range-hover::before,
|
||||
&-in-view${pickerCellCls}-range-start:not(${pickerCellCls}-range-start-single)${pickerCellCls}-range-hover-start::before,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { TinyColor } from '@ctrl/tinycolor';
|
||||
import * as React from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { TinyColor } from '@ctrl/tinycolor';
|
||||
import { useToken } from '../theme/internal';
|
||||
|
||||
const Simple = () => {
|
||||
@ -10,9 +10,13 @@ const Simple = () => {
|
||||
|
||||
const { borderColor, shadowColor, contentColor } = useMemo(
|
||||
() => ({
|
||||
borderColor: new TinyColor(colorFill).onBackground(colorBgContainer).toHexString(),
|
||||
shadowColor: new TinyColor(colorFillTertiary).onBackground(colorBgContainer).toHexString(),
|
||||
contentColor: new TinyColor(colorFillQuaternary).onBackground(colorBgContainer).toHexString(),
|
||||
borderColor: new TinyColor(colorFill).onBackground(colorBgContainer).toHexShortString(),
|
||||
shadowColor: new TinyColor(colorFillTertiary)
|
||||
.onBackground(colorBgContainer)
|
||||
.toHexShortString(),
|
||||
contentColor: new TinyColor(colorFillQuaternary)
|
||||
.onBackground(colorBgContainer)
|
||||
.toHexShortString(),
|
||||
}),
|
||||
[colorFill, colorFillTertiary, colorFillQuaternary, colorBgContainer],
|
||||
);
|
||||
|
@ -5526,7 +5526,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.tsx extend context
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-status-error"
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-disabled ant-input-group-wrapper-status-error"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
|
@ -2999,7 +2999,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.tsx correctly 1`] =
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-status-error"
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-disabled ant-input-group-wrapper-status-error"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
|
@ -20,9 +20,6 @@ const { TextArea } = Input;
|
||||
|
||||
const FormDisabledDemo: React.FC = () => {
|
||||
const [componentDisabled, setComponentDisabled] = useState<boolean>(true);
|
||||
const onFormLayoutChange = ({ disabled }: { disabled: boolean }) => {
|
||||
setComponentDisabled(disabled);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -36,7 +33,6 @@ const FormDisabledDemo: React.FC = () => {
|
||||
labelCol={{ span: 4 }}
|
||||
wrapperCol={{ span: 14 }}
|
||||
layout="horizontal"
|
||||
onValuesChange={onFormLayoutChange}
|
||||
disabled={componentDisabled}
|
||||
style={{ maxWidth: 600 }}
|
||||
>
|
||||
|
@ -2,6 +2,7 @@
|
||||
category: Components
|
||||
group: General
|
||||
title: Icon
|
||||
description: Semantic vector graphics.
|
||||
toc: false
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*PdAYS7anRpoAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*xEDOTJx2DEkAAAAAAAAAAAAADrJ8AQ/original
|
||||
@ -9,7 +10,9 @@ demo:
|
||||
cols: 2
|
||||
---
|
||||
|
||||
Semantic vector graphics. Before use icons, you need to install `@ant-design/icons` package:
|
||||
## How to use
|
||||
|
||||
Before use icons, you need to install `@ant-design/icons` package:
|
||||
|
||||
```bash
|
||||
npm install --save @ant-design/icons
|
||||
|
@ -1,6 +1,7 @@
|
||||
---
|
||||
category: Components
|
||||
subtitle: 图标
|
||||
description: 语义化的矢量图形。
|
||||
group: 通用
|
||||
title: Icon
|
||||
toc: false
|
||||
@ -10,7 +11,9 @@ demo:
|
||||
cols: 2
|
||||
---
|
||||
|
||||
语义化的矢量图形。使用图标组件,你需要安装 `@ant-design/icons` 图标组件包:
|
||||
## 使用方法
|
||||
|
||||
使用图标组件,你需要安装 `@ant-design/icons` 图标组件包:
|
||||
|
||||
```bash
|
||||
npm install --save @ant-design/icons
|
||||
|
@ -219,6 +219,7 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
|
||||
[`${prefixCls}-group-wrapper-sm`]: mergedSize === 'small',
|
||||
[`${prefixCls}-group-wrapper-lg`]: mergedSize === 'large',
|
||||
[`${prefixCls}-group-wrapper-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-group-wrapper-disabled`]: mergedDisabled,
|
||||
},
|
||||
getStatusClassNames(`${prefixCls}-group-wrapper`, mergedStatus, hasFeedback),
|
||||
hashId,
|
||||
|
@ -1,9 +1,9 @@
|
||||
import type { CSSObject } from '@ant-design/cssinjs';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import type { GlobalToken } from '../../theme/interface';
|
||||
import { clearFix, resetComponent } from '../../style';
|
||||
import { genCompactItemStyle } from '../../style/compact-item';
|
||||
import type { GlobalToken } from '../../theme/interface';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
|
||||
export type InputToken<T extends GlobalToken = FullToken<'Input'>> = T & {
|
||||
inputAffixPadding: number;
|
||||
@ -669,7 +669,7 @@ const genAffixStyle: GenerateStyle<InputToken> = (token: InputToken) => {
|
||||
};
|
||||
|
||||
const genGroupStyle: GenerateStyle<InputToken> = (token: InputToken) => {
|
||||
const { componentCls, colorError, colorSuccess, borderRadiusLG, borderRadiusSM } = token;
|
||||
const { componentCls, colorError, colorWarning, borderRadiusLG, borderRadiusSM } = token;
|
||||
|
||||
return {
|
||||
[`${componentCls}-group`]: {
|
||||
@ -711,9 +711,15 @@ const genGroupStyle: GenerateStyle<InputToken> = (token: InputToken) => {
|
||||
},
|
||||
},
|
||||
'&-status-warning': {
|
||||
[`${componentCls}-group-addon:last-child`]: {
|
||||
color: colorSuccess,
|
||||
borderColor: colorSuccess,
|
||||
[`${componentCls}-group-addon`]: {
|
||||
color: colorWarning,
|
||||
borderColor: colorWarning,
|
||||
},
|
||||
},
|
||||
|
||||
'&-disabled': {
|
||||
[`${componentCls}-group-addon`]: {
|
||||
...genDisabledStyle(token),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -8,8 +8,8 @@ describe('List Item Layout', () => {
|
||||
{
|
||||
key: 1,
|
||||
href: 'https://ant.design',
|
||||
title: `ant design`,
|
||||
avatar: 'https://joeschmoe.io/api/v1/random',
|
||||
title: 'ant design',
|
||||
avatar: 'https://joesch.moe/api/v1/random',
|
||||
description:
|
||||
'Ant Design, a design language for background applications, is refined by Ant UED Team.',
|
||||
content:
|
||||
|
@ -26,7 +26,7 @@ exports[`renders ./components/list/demo/basic.tsx extend context correctly 1`] =
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=0"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -63,7 +63,7 @@ exports[`renders ./components/list/demo/basic.tsx extend context correctly 1`] =
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=1"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -100,7 +100,7 @@ exports[`renders ./components/list/demo/basic.tsx extend context correctly 1`] =
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=2"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -137,7 +137,7 @@ exports[`renders ./components/list/demo/basic.tsx extend context correctly 1`] =
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=3"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -1360,7 +1360,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=0"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -1397,7 +1397,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=1"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -1434,7 +1434,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=2"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -1471,7 +1471,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=3"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -2072,7 +2072,7 @@ exports[`renders ./components/list/demo/vertical.tsx extend context correctly 1`
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=0"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -2238,7 +2238,7 @@ exports[`renders ./components/list/demo/vertical.tsx extend context correctly 1`
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=1"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -2404,7 +2404,7 @@ exports[`renders ./components/list/demo/vertical.tsx extend context correctly 1`
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=2"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -26,7 +26,7 @@ exports[`renders ./components/list/demo/basic.tsx correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=0"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -63,7 +63,7 @@ exports[`renders ./components/list/demo/basic.tsx correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=1"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -100,7 +100,7 @@ exports[`renders ./components/list/demo/basic.tsx correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=2"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -137,7 +137,7 @@ exports[`renders ./components/list/demo/basic.tsx correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=3"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -1360,7 +1360,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=0"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -1397,7 +1397,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=1"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -1434,7 +1434,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=2"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -1471,7 +1471,7 @@ Array [
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=3"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -2072,7 +2072,7 @@ exports[`renders ./components/list/demo/vertical.tsx correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=0"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -2238,7 +2238,7 @@ exports[`renders ./components/list/demo/vertical.tsx correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=1"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -2404,7 +2404,7 @@ exports[`renders ./components/list/demo/vertical.tsx correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=2"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Avatar, List } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const data = [
|
||||
{
|
||||
@ -20,10 +20,10 @@ const App: React.FC = () => (
|
||||
<List
|
||||
itemLayout="horizontal"
|
||||
dataSource={data}
|
||||
renderItem={(item) => (
|
||||
renderItem={(item, index) => (
|
||||
<List.Item>
|
||||
<List.Item.Meta
|
||||
avatar={<Avatar src="https://joeschmoe.io/api/v1/random" />}
|
||||
avatar={<Avatar src={`https://joesch.moe/api/v1/random?key=${index}`} />}
|
||||
title={<a href="https://ant.design">{item.title}</a>}
|
||||
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
|
||||
/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Avatar, List, Radio, Space } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
import { Avatar, List, Space, Radio } from 'antd';
|
||||
|
||||
type PaginationPosition = 'top' | 'bottom' | 'both';
|
||||
|
||||
@ -30,7 +30,7 @@ const App: React.FC = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Space direction='vertical' style={{ marginBottom: '20px' }} size="middle">
|
||||
<Space direction="vertical" style={{ marginBottom: '20px' }} size="middle">
|
||||
<Space>
|
||||
<span>Pagination Position:</span>
|
||||
<Radio.Group
|
||||
@ -67,10 +67,10 @@ const App: React.FC = () => {
|
||||
<List
|
||||
pagination={{ position, align }}
|
||||
dataSource={data}
|
||||
renderItem={(item) => (
|
||||
renderItem={(item, index) => (
|
||||
<List.Item>
|
||||
<List.Item.Meta
|
||||
avatar={<Avatar src="https://joeschmoe.io/api/v1/random" />}
|
||||
avatar={<Avatar src={`https://joesch.moe/api/v1/random?key=${index}`} />}
|
||||
title={<a href="https://ant.design">{item.title}</a>}
|
||||
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
|
||||
/>
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
import { LikeOutlined, MessageOutlined, StarOutlined } from '@ant-design/icons';
|
||||
import { Avatar, List, Space } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const data = Array.from({ length: 23 }).map((_, i) => ({
|
||||
href: 'https://ant.design',
|
||||
title: `ant design part ${i}`,
|
||||
avatar: 'https://joeschmoe.io/api/v1/random',
|
||||
avatar: `https://joesch.moe/api/v1/random?key=${i}`,
|
||||
description:
|
||||
'Ant Design, a design language for background applications, is refined by Ant UED Team.',
|
||||
content:
|
||||
|
@ -351,7 +351,7 @@ export default genComponentStyleHook(
|
||||
const listToken = mergeToken<ListToken>(token, {
|
||||
listBorderedCls: `${token.componentCls}-bordered`,
|
||||
minHeight: token.controlHeightLG,
|
||||
listItemPadding: `${token.paddingContentVertical}px ${token.paddingContentHorizontalLG}px`,
|
||||
listItemPadding: `${token.paddingContentVertical}px 0`,
|
||||
listItemPaddingSM: `${token.paddingContentVerticalSM}px ${token.paddingContentHorizontal}px`,
|
||||
listItemPaddingLG: `${token.paddingContentVerticalLG}px ${token.paddingContentHorizontalLG}px`,
|
||||
});
|
||||
|
@ -330,7 +330,7 @@ exports[`renders ./components/segmented/demo/custom.tsx extend context correctly
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
<div>
|
||||
|
@ -330,7 +330,7 @@ exports[`renders ./components/segmented/demo/custom.tsx correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random"
|
||||
/>
|
||||
</span>
|
||||
<div>
|
||||
|
@ -9,7 +9,7 @@ const App: React.FC = () => (
|
||||
{
|
||||
label: (
|
||||
<div style={{ padding: 4 }}>
|
||||
<Avatar src="https://joeschmoe.io/api/v1/random" />
|
||||
<Avatar src="https://joesch.moe/api/v1/random" />
|
||||
<div>User 1</div>
|
||||
</div>
|
||||
),
|
||||
|
@ -1,7 +1,7 @@
|
||||
// TODO: 4.0 - codemod should help to change `filterOption` to support node props.
|
||||
import classNames from 'classnames';
|
||||
import type { BaseSelectRef, SelectProps as RcSelectProps } from 'rc-select';
|
||||
import RcSelect, { OptGroup, Option } from 'rc-select';
|
||||
import type { SelectProps as RcSelectProps, BaseSelectRef } from 'rc-select';
|
||||
import type { OptionProps } from 'rc-select/lib/Option';
|
||||
import type { BaseOptionType, DefaultOptionType } from 'rc-select/lib/Select';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
@ -18,10 +18,10 @@ import type { InputStatus } from '../_util/statusUtils';
|
||||
import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils';
|
||||
import getIcons from './utils/iconUtil';
|
||||
|
||||
import useStyle from './style';
|
||||
import { useCompactItemContext } from '../space/Compact';
|
||||
import genPurePanel from '../_util/PurePanel';
|
||||
import warning from '../_util/warning';
|
||||
import { useCompactItemContext } from '../space/Compact';
|
||||
import useStyle from './style';
|
||||
|
||||
type RawValue = string | number;
|
||||
|
||||
@ -182,13 +182,11 @@ const InternalSelect = <OptionType extends BaseOptionType | DefaultOptionType =
|
||||
);
|
||||
|
||||
// ===================== Placement =====================
|
||||
const getPlacement = () => {
|
||||
const getPlacement = (): SelectCommonPlacement => {
|
||||
if (placement !== undefined) {
|
||||
return placement;
|
||||
}
|
||||
return direction === 'rtl'
|
||||
? ('bottomRight' as SelectCommonPlacement)
|
||||
: ('bottomLeft' as SelectCommonPlacement);
|
||||
return direction === 'rtl' ? 'bottomRight' : 'bottomLeft';
|
||||
};
|
||||
|
||||
// ====================== Warning ======================
|
||||
|
@ -11,7 +11,7 @@ interface IconTextProps {
|
||||
const listData = Array.from({ length: 3 }).map((_, i) => ({
|
||||
href: 'https://ant.design',
|
||||
title: `ant design part ${i + 1}`,
|
||||
avatar: 'https://joeschmoe.io/api/v1/random',
|
||||
avatar: `https://joesch.moe/api/v1/random?key=${i}`,
|
||||
description:
|
||||
'Ant Design, a design language for background applications, is refined by Ant UED Team.',
|
||||
content:
|
||||
|
@ -1,9 +1,9 @@
|
||||
import type { CSSObject } from '@ant-design/cssinjs';
|
||||
import type * as React from 'react';
|
||||
import { TinyColor } from '@ctrl/tinycolor';
|
||||
import type * as React from 'react';
|
||||
import { resetComponent } from '../../style';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import { resetComponent } from '../../style';
|
||||
|
||||
// Direction naming standard:
|
||||
// Horizontal base:
|
||||
@ -214,7 +214,7 @@ const genBaseStyle: GenerateStyle<SliderToken> = (token) => {
|
||||
height: token.handleSize,
|
||||
boxShadow: `0 0 0 ${token.handleLineWidth}px ${new TinyColor(token.colorTextDisabled)
|
||||
.onBackground(token.colorBgContainer)
|
||||
.toHexString()}`,
|
||||
.toHexShortString()}`,
|
||||
insetInlineStart: 0,
|
||||
insetBlockStart: 0,
|
||||
},
|
||||
|
@ -875,7 +875,7 @@ exports[`renders ./components/steps/demo/inline.tsx extend context correctly 1`]
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=0"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -1082,7 +1082,7 @@ exports[`renders ./components/steps/demo/inline.tsx extend context correctly 1`]
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=1"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -1289,7 +1289,7 @@ exports[`renders ./components/steps/demo/inline.tsx extend context correctly 1`]
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=2"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -1496,7 +1496,7 @@ exports[`renders ./components/steps/demo/inline.tsx extend context correctly 1`]
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=3"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -751,7 +751,7 @@ exports[`renders ./components/steps/demo/inline.tsx correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=0"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -901,7 +901,7 @@ exports[`renders ./components/steps/demo/inline.tsx correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=1"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -1051,7 +1051,7 @@ exports[`renders ./components/steps/demo/inline.tsx correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=2"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@ -1201,7 +1201,7 @@ exports[`renders ./components/steps/demo/inline.tsx correctly 1`] = `
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://joeschmoe.io/api/v1/random"
|
||||
src="https://joesch.moe/api/v1/random?key=3"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import type { StepsProps } from 'antd';
|
||||
import { Steps, List, Avatar } from 'antd';
|
||||
import { Avatar, List, Steps } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const data = [
|
||||
{
|
||||
@ -42,10 +42,10 @@ const App: React.FC = () => (
|
||||
<List
|
||||
itemLayout="horizontal"
|
||||
dataSource={data}
|
||||
renderItem={(item) => (
|
||||
renderItem={(item, index) => (
|
||||
<List.Item>
|
||||
<List.Item.Meta
|
||||
avatar={<Avatar src="https://joeschmoe.io/api/v1/random" />}
|
||||
avatar={<Avatar src={`https://joesch.moe/api/v1/random?key=${index}`} />}
|
||||
title={<a href="https://ant.design">{item.title}</a>}
|
||||
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
|
||||
/>
|
||||
|
@ -142,7 +142,6 @@ const genFilterStyle: GenerateStyle<TableToken> = (token) => {
|
||||
justifyContent: 'space-between',
|
||||
padding: `${paddingXS - lineWidth}px ${paddingXS}px`,
|
||||
overflow: 'hidden',
|
||||
backgroundColor: 'inherit',
|
||||
borderTop: tableBorder,
|
||||
},
|
||||
},
|
||||
|
@ -1,5 +1,6 @@
|
||||
import type { CSSObject } from '@ant-design/cssinjs';
|
||||
import { TinyColor } from '@ctrl/tinycolor';
|
||||
import { clearFix, resetComponent } from '../../style';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import genBorderedStyle from './bordered';
|
||||
@ -16,7 +17,6 @@ import genSizeStyle from './size';
|
||||
import genSorterStyle from './sorter';
|
||||
import genStickyStyle from './sticky';
|
||||
import genSummaryStyle from './summary';
|
||||
import { clearFix, resetComponent } from '../../style';
|
||||
|
||||
export interface ComponentToken {}
|
||||
|
||||
@ -257,14 +257,14 @@ export default genComponentStyleHook('Table', (token) => {
|
||||
|
||||
const colorFillSecondarySolid = new TinyColor(colorFillSecondary)
|
||||
.onBackground(colorBgContainer)
|
||||
.toHexString();
|
||||
.toHexShortString();
|
||||
const colorFillContentSolid = new TinyColor(colorFillContent)
|
||||
.onBackground(colorBgContainer)
|
||||
.toHexString();
|
||||
.toHexShortString();
|
||||
|
||||
const colorFillAlterSolid = new TinyColor(colorFillAlter)
|
||||
.onBackground(colorBgContainer)
|
||||
.toHexString();
|
||||
.toHexShortString();
|
||||
|
||||
const tableToken = mergeToken<TableToken>(token, {
|
||||
tableFontSize: fontSize,
|
||||
|
@ -50,7 +50,7 @@ export interface SeedToken extends PresetColorType {
|
||||
/**
|
||||
* @nameZH 基础文本色
|
||||
* @nameEN Seed Text Color
|
||||
* @desc 用于派生文本色梯度的基础变量,v5 中我们添加了一层文本色的派生算法可以产出梯度明确的文本色的梯度变量。但**请不要在代码中直接使用该 Seed Token**!
|
||||
* @desc 用于派生文本色梯度的基础变量,v5 中我们添加了一层文本色的派生算法可以产出梯度明确的文本色的梯度变量。但请不要在代码中直接使用该 Seed Token !
|
||||
* @descEN Used to derive the base variable of the text color gradient. In v5, we added a layer of text color derivation algorithm to produce gradient variables of text color gradient. But please do not use this Seed Token directly in the code!
|
||||
*/
|
||||
colorTextBase: string;
|
||||
@ -58,7 +58,7 @@ export interface SeedToken extends PresetColorType {
|
||||
/**
|
||||
* @nameZH 基础背景色
|
||||
* @nameEN Seed Background Color
|
||||
* @desc 用于派生背景色梯度的基础变量,v5 中我们添加了一层背景色的派生算法可以产出梯度明确的背景色的梯度变量。但 **请不要在代码中直接使用该 Seed Token** !
|
||||
* @desc 用于派生背景色梯度的基础变量,v5 中我们添加了一层背景色的派生算法可以产出梯度明确的背景色的梯度变量。但请不要在代码中直接使用该 Seed Token !
|
||||
* @descEN Used to derive the base variable of the background color gradient. In v5, we added a layer of background color derivation algorithm to produce map token of background color. But PLEASE DO NOT USE this Seed Token directly in the code!
|
||||
*/
|
||||
colorBgBase: string;
|
||||
|
@ -185,6 +185,10 @@ const genPictureCardStyle: GenerateStyle<UploadToken> = (token) => {
|
||||
fontSize: fontSizeLG,
|
||||
cursor: 'pointer',
|
||||
transition: `all ${token.motionDurationSlow}`,
|
||||
|
||||
svg: {
|
||||
verticalAlign: 'baseline',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
15
package.json
15
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "antd",
|
||||
"version": "5.2.1",
|
||||
"version": "5.2.2",
|
||||
"description": "An enterprise-class UI design language and React components implementation",
|
||||
"title": "Ant Design",
|
||||
"keywords": [
|
||||
@ -76,9 +76,9 @@
|
||||
"lint:deps": "antd-tools run deps-lint",
|
||||
"lint:md": "remark . -f -q",
|
||||
"lint:style": "ts-node --project tsconfig.node.json scripts/check-cssinjs.js",
|
||||
"lint:script": "eslint . --ext .js,.jsx,.ts,.tsx",
|
||||
"lint:script": "eslint . --ext .js,.jsx,.ts,.tsx --cache",
|
||||
"pre-publish": "npm run test-all -- --skip-build",
|
||||
"prettier": "prettier -c --write **/*",
|
||||
"prettier": "prettier -c --write **/* --cache",
|
||||
"pub": "npm run version && npm run collect-token-statistic && npm run token-meta && antd-tools run pub",
|
||||
"rome:format": "rome format --write .",
|
||||
"prepublishOnly": "antd-tools run guard",
|
||||
@ -112,7 +112,7 @@
|
||||
"@ant-design/icons": "^5.0.0",
|
||||
"@ant-design/react-slick": "~1.0.0",
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@ctrl/tinycolor": "^3.4.0",
|
||||
"@ctrl/tinycolor": "^3.6.0",
|
||||
"@rc-component/mutate-observer": "^1.0.0",
|
||||
"@rc-component/tour": "~1.6.0",
|
||||
"classnames": "^2.2.6",
|
||||
@ -158,6 +158,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ant-design/tools": "^17.0.0",
|
||||
"@antv/g6": "^4.8.5",
|
||||
"@babel/eslint-plugin": "^7.19.1",
|
||||
"@dnd-kit/core": "^6.0.7",
|
||||
"@dnd-kit/sortable": "^7.0.2",
|
||||
@ -169,9 +170,9 @@
|
||||
"@qixian.cs/github-contributors-list": "^1.0.3",
|
||||
"@size-limit/file": "^8.1.0",
|
||||
"@stackblitz/sdk": "^1.3.0",
|
||||
"@testing-library/dom": "^8.17.1",
|
||||
"@testing-library/dom": "^9.0.0",
|
||||
"@testing-library/jest-dom": "^5.16.3",
|
||||
"@testing-library/react": "^13.0.0",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@testing-library/user-event": "^14.4.2",
|
||||
"@types/gtag.js": "^0.0.12",
|
||||
"@types/jest": "^29.0.0",
|
||||
@ -196,6 +197,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "^5.40.0",
|
||||
"@typescript-eslint/parser": "^5.40.0",
|
||||
"antd-img-crop": "^4.2.8",
|
||||
"antd-style": "^2.0.2",
|
||||
"antd-token-previewer": "^1.1.0-21",
|
||||
"chalk": "^4.0.0",
|
||||
"cheerio": "1.0.0-rc.12",
|
||||
@ -221,6 +223,7 @@
|
||||
"fs-extra": "^11.0.0",
|
||||
"gh-pages": "^5.0.0",
|
||||
"glob": "^8.0.1",
|
||||
"html2sketch": "^1.0.0",
|
||||
"http-server": "^14.0.0",
|
||||
"husky": "^8.0.1",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
const React = require('react');
|
||||
const util = require('util');
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user