docs: fix site issue (#38552)

* docs: put an example loading component

* fix: site issue

* fix: site issue

* feat: add loading

* feat: alert

* docs: rm ReactDOM.render in md

* docs: use style tag

* chore: update snapshot

* Revert "docs: use style tag"

This reverts commit 1f75a99f8c.

* docs: update demo

* chore: update demo

Co-authored-by: PeachScript <scdzwyxst@gmail.com>
This commit is contained in:
MadCcc 2022-11-15 22:55:01 +08:00 committed by GitHub
parent 31a401ba1a
commit fab90b09f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 1510 additions and 510 deletions

View File

@ -0,0 +1,8 @@
import { Alert, AlertProps } from 'antd';
import React, { FC } from 'react';
const MdAlert: FC<AlertProps> = ({ style, ...props }) => {
return <Alert {...props} style={{ margin: '24px 0', ...style }} />;
};
export default MdAlert;

View File

@ -0,0 +1,4 @@
// @ts-ignore
import ColorPaletteTool from '../../common/Color/ColorPaletteTool';
export default ColorPaletteTool;

View File

@ -0,0 +1,4 @@
// @ts-ignore
import ColorPaletteToolDark from '../../common/Color/ColorPaletteToolDark';
export default ColorPaletteToolDark;

View File

@ -0,0 +1,4 @@
// @ts-ignore
import ColorPalettes from '../../common/Color/ColorPalettes';
export default ColorPalettes;

View File

@ -0,0 +1,4 @@
// @ts-ignore
import Palette from '../../common/Color/Palette';
export default Palette;

View File

@ -0,0 +1,36 @@
import React, { Component } from 'react';
import CopyToClipboard from 'react-copy-to-clipboard';
import { message } from 'antd';
export default class ColorBlock extends Component {
getTextStyle() {
const { color, index, dark } = this.props;
const colorMap = {
default: ['#fff', 'unset'],
dark: ['#314659', '#fff'],
};
const [lastColor, firstColor] = dark ? colorMap.dark : colorMap.default;
return {
background: color,
color: index > 5 ? lastColor : firstColor,
fontWeight: index === 6 ? 'bold' : 'normal',
};
}
onCopied = () => {
const { color } = this.props;
message.success(`Copied: ${color}`);
};
render() {
const { color, index } = this.props;
return (
<CopyToClipboard text={color} onCopy={this.onCopied} title="click to copy color">
<div className="main-color-item" style={this.getTextStyle()}>
color-{index}
<span className="main-color-value">{color.toLowerCase()}</span>
</div>
</CopyToClipboard>
);
}
}

View File

@ -0,0 +1,61 @@
import React, { Component } from 'react';
import { FormattedMessage } from 'dumi';
import ColorPicker from './ColorPicker';
import ColorPatterns from './ColorPatterns';
const primaryMinSaturation = 70; //
const primaryMinBrightness = 70; //
export default class ColorPaletteTool extends Component {
state = {
primaryColor: '#1890ff',
primaryColorInstance: null,
};
handleChangeColor = (e, color) => {
const value = e.target ? e.target.value : e;
this.setState({
primaryColor: value,
primaryColorInstance: color,
});
};
renderColorValidation() {
const { primaryColorInstance } = this.state;
let text = '';
if (primaryColorInstance) {
if (primaryColorInstance.hsv.s * 100 < primaryMinSaturation) {
text += ` 饱和度建议不低于${primaryMinSaturation}(现在 ${(
primaryColorInstance.hsv.s * 100
).toFixed(2)}`;
}
if (primaryColorInstance.hsv.v * 100 < primaryMinBrightness) {
text += ` 亮度建议不低于${primaryMinBrightness}(现在 ${(
primaryColorInstance.hsv.v * 100
).toFixed(2)}`;
}
}
return <span className="color-palette-picker-validation">{text.trim()}</span>;
}
render() {
const { primaryColor } = this.state;
return (
<div className="color-palette-horizontal">
<div className="color-palette-pick">
<FormattedMessage id="app.docs.color.pick-primary" />
</div>
<div className="main-color">
<ColorPatterns color={primaryColor} />
</div>
<div className="color-palette-picker">
<span style={{ display: 'inline-block', verticalAlign: 'middle' }}>
<ColorPicker type="chrome" color={primaryColor} onChange={this.handleChangeColor} />
</span>
<span className="color-palette-picker-value">{primaryColor}</span>
{this.renderColorValidation()}
</div>
</div>
);
}
}

View File

@ -0,0 +1,107 @@
import React, { Component } from 'react';
import { FormattedMessage } from 'dumi';
import { Row, Col } from 'antd';
import ColorPicker from './ColorPicker';
import ColorPatterns from './ColorPatterns';
const primaryMinSaturation = 70; //
const primaryMinBrightness = 70; //
export default class ColorPaletteTool extends Component {
state = {
primaryColor: '#1890ff',
backgroundColor: '#141414',
primaryColorInstance: null,
};
handleChangeColor = (e, color) => {
const value = e.target ? e.target.value : e;
this.setState({
primaryColor: value,
primaryColorInstance: color,
});
};
handleChangeBackgroundColor = e => {
const value = e.target ? e.target.value : e;
this.setState({
backgroundColor: value,
});
};
renderColorValidation() {
const { primaryColorInstance } = this.state;
let text = '';
if (primaryColorInstance) {
if (primaryColorInstance.hsv.s * 100 < primaryMinSaturation) {
text += ` 饱和度建议不低于${primaryMinSaturation}(现在 ${(
primaryColorInstance.hsv.s * 100
).toFixed(2)}`;
}
if (primaryColorInstance.hsv.v * 100 < primaryMinBrightness) {
text += ` 亮度建议不低于${primaryMinBrightness}(现在 ${(
primaryColorInstance.hsv.v * 100
).toFixed(2)}`;
}
}
return (
<span className="color-palette-picker-validation color-palette-picker-validation-dark">
{text.trim()}
</span>
);
}
render() {
const { primaryColor, backgroundColor } = this.state;
return (
<div className="color-palette-horizontal color-palette-horizontal-dark">
<div className="main-color">
<ColorPatterns color={primaryColor} dark backgroundColor={backgroundColor} />
</div>
<div className="color-palette-picker">
<Row>
<Col span={12}>
<div className="color-palette-pick">
<FormattedMessage id="app.docs.color.pick-primary" />
</div>
<span style={{ display: 'inline-block', verticalAlign: 'middle' }}>
<Row>
<Col span={18}>
<ColorPicker
type="chrome"
color={primaryColor}
onChange={this.handleChangeColor}
/>
</Col>
<Col span={6}>
<span className="color-palette-pick-hex">{primaryColor}</span>
</Col>
</Row>
</span>
</Col>
<Col span={12}>
<div className="color-palette-pick">
<FormattedMessage id="app.docs.color.pick-background" />
</div>
<span style={{ display: 'inline-block', verticalAlign: 'middle' }}>
<Row>
<Col span={18}>
<ColorPicker
type="chrome"
color={backgroundColor}
onChange={this.handleChangeBackgroundColor}
/>
</Col>
<Col span={6}>
<span className="color-palette-pick-hex">{backgroundColor}</span>
</Col>
</Row>
</span>
</Col>
</Row>
{this.renderColorValidation()}
</div>
</div>
);
}
}

View File

@ -0,0 +1,94 @@
import React from 'react';
import cls from 'classnames';
import Palette from './Palette';
const ColorPalettes = props => {
const { dark } = props;
const colors = [
{
name: 'red',
english: 'Dust Red',
chinese: '薄暮',
description: '斗志、奔放',
},
{
name: 'volcano',
english: 'Volcano',
chinese: '火山',
description: '醒目、澎湃',
},
{
name: 'orange',
english: 'Sunset Orange',
chinese: '日暮',
description: '温暖、欢快',
},
{
name: 'gold',
english: 'Calendula Gold',
chinese: '金盏花',
description: '活力、积极',
},
{
name: 'yellow',
english: 'Sunrise Yellow',
chinese: '日出',
description: '出生、阳光',
},
{
name: 'lime',
english: 'Lime',
chinese: '青柠',
description: '自然、生机',
},
{
name: 'green',
english: 'Polar Green',
chinese: '极光绿',
description: '健康、创新',
},
{
name: 'cyan',
english: 'Cyan',
chinese: '明青',
description: '希望、坚强',
},
{
name: 'blue',
english: 'Daybreak Blue',
chinese: '拂晓蓝',
description: '包容、科技、普惠',
},
{
name: 'geekblue',
english: 'Geek Blue',
chinese: '极客蓝',
description: '探索、钻研',
},
{
name: 'purple',
english: 'Golden Purple',
chinese: '酱紫',
description: '优雅、浪漫',
},
{
name: 'magenta',
english: 'Magenta',
chinese: '法式洋红',
description: '明快、感性',
},
];
const colorCls = cls('color-palettes', {
'color-palettes-dark': !!dark,
});
return (
<div className={colorCls}>
{colors.map(color => (
<Palette key={color.name} color={color} dark={dark} showTitle />
))}
</div>
);
};
export default ColorPalettes;

View File

@ -0,0 +1,11 @@
import React from 'react';
import { generate } from '@ant-design/colors';
import uniq from 'lodash/uniq';
import ColorBlock from './ColorBlock';
export default function ColorPatterns({ color, dark, backgroundColor }) {
const colors = generate(color, dark ? { theme: 'dark', backgroundColor } : {});
return uniq(colors).map((colorString, i) => (
<ColorBlock color={colorString} index={i + 1} dark={dark} key={colorString} />
));
}

View File

@ -0,0 +1,126 @@
import React, { Component } from 'react';
import { SketchPicker } from 'react-color';
const noop = () => {};
interface ColorPickerProps {
color?: string;
small: boolean;
position: string;
presetColors?: string[];
onChange: (hex: string, color: { hex: string }) => void;
onChangeComplete: (hex: string) => void;
}
export default class ColorPicker extends Component<ColorPickerProps> {
static getDerivedStateFromProps(props: ColorPickerProps) {
if ('color' in props) {
return {
color: props.color,
};
}
return null;
}
state = {
displayColorPicker: false,
color: undefined,
};
handleClick = () => {
const { displayColorPicker } = this.state;
this.setState({ displayColorPicker: !displayColorPicker });
};
handleClose = () => {
this.setState({ displayColorPicker: false });
};
handleChange = (color: { hex: string }) => {
const { onChange = noop } = this.props;
this.setState({ color: color.hex });
onChange(color.hex, color);
};
handleChangeComplete = (color: { hex: string }) => {
const { onChangeComplete = noop } = this.props;
this.setState({ color: color.hex });
onChangeComplete(color.hex);
};
render() {
const { small, position = 'bottom', presetColors } = this.props;
const { color, displayColorPicker } = this.state;
const width = small ? 80 : 120;
const styles: Record<PropertyKey, React.CSSProperties> = {
color: {
width: `${width}px`,
height: small ? '16px' : '24px',
borderRadius: '2px',
background: color,
},
swatch: {
padding: '4px',
background: '#fff',
borderRadius: '2px',
boxShadow: '0 0 0 1px rgba(0,0,0,.1)',
display: 'inline-block',
cursor: 'pointer',
},
popover: {
position: 'absolute',
zIndex: 10,
},
cover: {
position: 'fixed',
top: '0px',
right: '0px',
bottom: '0px',
left: '0px',
},
wrapper: {
position: 'inherit',
zIndex: 100,
},
};
if (position === 'top') {
styles.wrapper.transform = `translate(calc(-100% + ${width + 8}px), -100%)`;
styles.wrapper.paddingBottom = 8;
}
const swatch = (
<div style={styles.swatch} onClick={this.handleClick}>
<div style={styles.color} />
</div>
);
const picker = displayColorPicker ? (
<div style={styles.popover}>
<div style={styles.cover} onClick={this.handleClose} />
<div style={styles.wrapper}>
<SketchPicker
presetColors={presetColors}
color={color}
onChange={this.handleChange}
onChangeComplete={this.handleChangeComplete}
/>
</div>
</div>
) : null;
if (position === 'top') {
return (
<div>
{picker}
{swatch}
</div>
);
}
return (
<div>
{swatch}
{picker}
</div>
);
}
}

View File

@ -0,0 +1,290 @@
import { Global, css } from '@emotion/react';
import useSiteToken from '../../../hooks/useSiteToken';
const gray = {
1: '#fff',
2: '#fafafa',
3: '#f5f5f5',
4: '#f0f0f0',
5: '#d9d9d9',
6: '#bfbfbf',
7: '#8c8c8c',
8: '#595959',
9: '#434343',
10: '#262626',
11: '#1f1f1f',
12: '#141414',
13: '#000',
};
const ColorStyle = () => {
const { token } = useSiteToken();
const makePalette = (color: string, index: number = 1): string => {
if (index <= 10) {
return `
.palette-${color}-${index} {
background: ${(token as any)[`${color}-${index}`]};
}
${makePalette(color, index + 1)}
`;
}
return '';
};
const makeGrayPalette = (index: number = 1): string => {
if (index <= 13) {
return `
.palette-gray-${index} {
background: ${(gray as any)[index]};
}
${makeGrayPalette(index + 1)}
`;
}
return '';
};
return (
<Global
styles={css`
.color-palettes {
margin: 0 1%;
&-dark {
margin: 0;
padding: 0 28px;
background-color: #141414;
.color-title {
color: rgba(255, 255, 255, 0.85);
}
.color-description {
color: rgba(255, 255, 255, 0.45);
}
.color-palette {
margin: 45px 3.5% 45px 0;
&:nth-of-type(3n) {
margin-right: 0;
}
.main-color-item {
margin-right: 0;
&:hover {
margin-right: -8px;
}
}
}
}
}
.color-palette {
display: inline-block;
width: 31%;
margin: 45px 1%;
&-pick {
margin: 0 0 20px;
font-size: 20px;
text-align: center;
}
&-picker {
margin: 24px 0;
&-value {
position: relative;
top: -3px;
margin-left: 16px;
font-size: 14px;
font-family: Consolas, sans-serif;
.ant-row-rtl & {
margin-right: 16px;
margin-left: 0;
}
}
&-validation {
position: relative;
top: -3px;
margin-left: 16px;
color: ${token.colorError};
font-size: 13px;
.ant-row-rtl & {
margin-right: 16px;
margin-left: 0;
}
&-dark {
margin-left: 0;
}
}
}
}
.main-color {
${makePalette('blue')}
${makePalette('purple')}
${makePalette('cyan')}
${makePalette('green')}
${makePalette('magenta')}
${makePalette('red')}
${makePalette('volcano')}
${makePalette('orange')}
${makePalette('gold')}
${makePalette('yellow')}
${makePalette('lime')}
${makePalette('geekblue')}
${makeGrayPalette()}
text-align: left;
&-item {
position: relative;
height: 44px;
margin-right: 4px;
padding: 0 12px;
font-size: 14px;
font-family: Consolas, sans-serif;
line-height: 44px;
cursor: pointer;
transition: all 0.2s;
&:first-child {
border-radius: 4px 4px 0 0;
}
&:last-child {
border-radius: 0 0 4px 4px;
}
&:hover {
margin-right: -8px;
border-radius: 0 4px 4px 0;
}
}
&-item &-text {
float: left;
transition: all 0.3s;
}
&-item &-value {
position: relative;
left: 3px;
float: right;
transform: scale(0.85);
transform-origin: 100% 50%;
opacity: 0;
transition: all 0.3s;
}
}
.color-title {
margin: 0 0 24px;
color: #5c6b77;
font-weight: 500;
font-size: 22px;
text-align: center;
text-transform: capitalize;
}
.color-description {
display: block;
color: #777;
font-weight: lighter;
font-size: 14px;
}
.main-color:hover {
.main-color-value {
left: 0;
opacity: 0.7;
}
}
.color-palette-horizontal {
width: 100%;
box-sizing: border-box;
&-dark {
height: 303px;
padding: 32px 28px;
background-color: #141414;
.color-palette-picker {
margin-bottom: 0;
}
.color-palette-pick {
color: rgba(255, 255, 255, 0.65);
text-align: left;
&-hex {
color: rgba(255, 255, 255, 0.65);
}
.ant-row-rtl & {
direction: rtl;
text-align: right;
}
}
}
.main-color {
display: flex;
&-item {
box-sizing: border-box;
position: relative;
flex: 1;
height: 86px;
margin-right: 0;
padding: 37px 0 0;
line-height: normal;
text-align: center;
border-radius: 0;
.main-color-text {
float: none;
}
&:hover {
height: 96px;
margin-top: -10px;
border-radius: 4px 4px 0 0;
}
}
&-value {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
text-align: center;
transform-origin: unset;
}
&:hover {
.main-color-item {
padding-top: 8px;
}
.main-color-value {
bottom: 8px;
opacity: 0.7;
}
}
}
}
`}
/>
);
};
export default ColorStyle;

View File

@ -0,0 +1,93 @@
import React from 'react';
import { message } from 'antd';
import CopyToClipboard from 'react-copy-to-clipboard';
import { presetDarkPalettes } from '@ant-design/colors';
const rgbToHex = rgbString => {
const rgb = rgbString.match(/\d+/g);
let r = parseInt(rgb[0], 10).toString(16);
let g = parseInt(rgb[1], 10).toString(16);
let b = parseInt(rgb[2], 10).toString(16);
r = r.length === 1 ? `0${r}` : r;
g = g.length === 1 ? `0${g}` : g;
b = b.length === 1 ? `0${b}` : b;
return `#${r}${g}${b}`;
};
export default class Palette extends React.Component {
componentDidMount() {
this.hexColors = {};
Object.keys(this.colorNodes).forEach(key => {
const computedColor = getComputedStyle(this.colorNodes[key])['background-color'];
if (computedColor.includes('rgba')) {
this.hexColors[key] = computedColor;
} else {
this.hexColors[key] = rgbToHex(computedColor);
}
});
this.forceUpdate();
}
render() {
this.colorNodes = this.colorNodes || {};
const {
showTitle,
direction,
dark,
color: { name, description, english, chinese, count = 10 },
} = this.props;
const className = direction === 'horizontal' ? 'color-palette-horizontal' : 'color-palette';
const colors = [];
const colorName = `${english} / ${chinese}`;
const colorPaletteMap = {
dark: ['#fff', 'unset'],
default: ['rgba(0,0,0,0.85)', '#fff'],
};
const [lastColor, firstColor] = dark ? colorPaletteMap.dark : colorPaletteMap.default;
for (let i = 1; i <= count; i += 1) {
const colorText = `${name}-${i}`;
const defaultBgStyle = dark ? presetDarkPalettes[name][i - 1] : '';
colors.push(
<CopyToClipboard
text={this.hexColors ? this.hexColors[colorText] : ''}
onCopy={() => message.success(`@${colorText} copied: ${this.hexColors[colorText]}`)}
key={colorText}
>
<div
key={i}
ref={node => {
this.colorNodes[`${name}-${i}`] = node;
}}
className={`main-color-item palette-${name}-${i}`}
style={{
color: (name === 'yellow' ? i > 6 : i > 5) ? firstColor : lastColor,
fontWeight: i === 6 ? 'bold' : 'normal',
backgroundColor: defaultBgStyle,
}}
title="click to copy color"
>
<span className="main-color-text">{colorText}</span>
{this.hexColors ? (
<span className="main-color-value">{this.hexColors[colorText]}</span>
) : null}
</div>
</CopyToClipboard>,
);
}
return (
<div className={className}>
{showTitle && (
<div className="color-title">
{colorName}
<span className="color-description">{description}</span>
</div>
)}
<div className="main-color">{colors}</div>
</div>
);
}
}
Palette.defaultProps = {
color: { name: 'gray', count: 13 },
}

View File

@ -4,7 +4,7 @@ import { EditOutlined } from '@ant-design/icons';
import { css } from '@emotion/react';
import useSiteToken from '../../hooks/useSiteToken';
const branchUrl = 'https://github.com/ant-design/ant-design/edit/master/';
const branchUrl = 'https://github.com/ant-design/ant-design/edit/next/';
export interface EditButtonProps {
title: React.ReactNode;

View File

@ -2,6 +2,7 @@ import React from 'react';
import { Global, css } from '@emotion/react';
import useSiteToken from '../../hooks/useSiteToken';
import { TinyColor } from '@ctrl/tinycolor';
import ColorStyle from '../common/Color/ColorStyle';
const GlobalStyles = () => {
const { token } = useSiteToken();
@ -61,7 +62,7 @@ const GlobalStyles = () => {
ol {
list-style: none;
}
img {
vertical-align: middle;
border-style: none;
@ -1167,11 +1168,7 @@ const GlobalStyles = () => {
.all-code-box-controls {
position: absolute;
top: -32px;
right: 0;
${antCls}-row-rtl & {
float: left;
}
inset-inline-end: 0;
}
${antCls}-row-rtl {
@ -1783,6 +1780,234 @@ const GlobalStyles = () => {
}
`}
/>
{/* Preview Image */}
<Global
styles={css`
.preview-image-boxes {
display: flex;
float: right;
clear: both;
width: 496px;
margin: 0 0 70px 64px;
&-with-carousel {
width: 420px;
.preview-image-box img {
padding: 0;
}
}
.ant-row-rtl & {
float: left;
margin: 0 64px 70px 0;
}
}
.preview-image-boxes + .preview-image-boxes {
margin-top: -35px;
}
.preview-image-box {
float: left;
width: 100%;
}
.preview-image-box + .preview-image-box {
margin-left: 24px;
.ant-row-rtl & {
margin-right: 24px;
margin-left: 0;
}
}
.preview-image-wrapper {
position: relative;
display: inline-block;
width: 100%;
padding: 16px;
text-align: center;
background: #f2f4f5;
}
.preview-image-wrapper.video {
display: block;
padding: 0;
background: 0;
}
.preview-image-wrapper video {
display: block;
width: 100%;
+ svg {
position: absolute;
top: 0;
left: 0;
}
}
.preview-image-wrapper.good::after {
position: absolute;
bottom: 0;
left: 0;
display: block;
width: 100%;
height: 3px;
background: @primary-color;
content: '';
}
.preview-image-wrapper.bad::after {
position: absolute;
bottom: 0;
left: 0;
display: block;
width: 100%;
height: 3px;
background: @error-color;
content: '';
}
.preview-image-title {
margin-top: 20px;
color: @site-text-color;
font-size: 12px;
}
.preview-image-description {
margin-top: 2px;
color: @site-text-color-secondary;
font-size: 12px;
line-height: 1.5;
}
.preview-image-description hr {
margin: 2px 0;
background: none;
border: 0;
}
.preview-image-box img {
max-width: 100%;
padding: 12px;
background: @body-background;
border-radius: @border-radius-base;
cursor: pointer;
transition: all 0.3s;
&.no-padding {
padding: 0;
background: none;
}
}
.preview-image-boxes.preview-image-boxes-with-carousel img {
padding: 0;
box-shadow: 0 1px 0 0 #ddd, 0 3px 0 0 @body-background, 0 4px 0 0 #ddd, 0 6px 0 0 @body-background,
0 7px 0 0 #ddd;
}
.preview-image-box img:hover {
box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.3);
}
.image-modal {
text-align: center;
&-container {
position: relative;
text-align: center;
}
.ant-carousel {
.slick-slider {
padding-bottom: 24px;
img {
display: inline;
max-width: 100%;
}
}
.slick-dots {
bottom: 4px;
li button {
background: #888;
}
}
}
.image-modal-single.slick-slider {
padding-bottom: 0;
}
.image-modal-single .slick-dots {
display: none !important;
}
}
.transition-video-player,
.motion-video-min {
float: right;
width: 600px;
padding: 0 0 70px 20px;
.preview-image-wrapper {
padding: 0;
}
.ant-row-rtl & {
float: left;
}
}
.motion-video-min {
width: 390px;
}
.motion-principle-wrapper {
width: 100%;
max-width: 900px;
margin: 48px 0 24px;
}
.principle-wrapper {
width: 100%;
.principle {
display: inline-block;
width: 100%;
min-height: 180px;
margin-right: 12.5%;
margin-bottom: 24px;
padding: 24px;
font-size: 24px;
text-align: center;
border: 1px solid #e8e8e8;
border-radius: 4px;
box-sizing: border-box;
&:last-child {
margin-right: 0;
}
h4 {
margin: 16px 0 8px;
}
p {
font-size: 12px;
line-height: 24px;
}
}
}`}
/>
<ColorStyle />
</>
);
};

View File

@ -0,0 +1,28 @@
import React, { type FC } from 'react';
import { Skeleton, Space, Spin } from 'antd';
import { useLocation } from 'dumi';
const Loading: FC = () => {
const { pathname } = useLocation();
if (
pathname.startsWith('/components') ||
pathname.startsWith('/docs') ||
pathname.startsWith('/changelog')
) {
return (
<Space direction="vertical" style={{ width: '100%' }} size={40}>
<Skeleton title={false} active paragraph={{ rows: 3 }} />
<Skeleton active paragraph={{ rows: 3 }} />
</Space>
);
}
return (
<Space style={{ width: '100%', margin: '120px 0', justifyContent: 'center' }} align="center">
<Spin size="large" />
</Space>
);
};
export default Loading;

View File

@ -22,6 +22,8 @@ const useStyle = () => {
letter-spacing: -0.18px;
white-space: nowrap;
text-decoration: none;
display: inline-flex;
align-items: center;
&:hover {
color: ${colorTextHeading};
@ -65,7 +67,7 @@ const Logo = ({ isZhCN }: LogoProps) => {
<h1>
<Link to={utils.getLocalizedPathname('/', isZhCN, search)} css={logo}>
<img alt="logo" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg" />
Ant Design
<span style={{ lineHeight: '32px' }}>Ant Design</span>
</Link>
</h1>
);

View File

@ -106,7 +106,7 @@ export default ({
const module = pathname
.split('/')
.filter(path => path)
.filter((path) => path)
.slice(0, -1)
.join('/');
let activeMenuItem = module || 'home';
@ -187,7 +187,7 @@ export default ({
<FormattedMessage id="app.header.menu.resource" />
</Link>
),
key: '/docs/resources',
key: 'docs/resources',
},
showTechUIButton
? {

View File

@ -17,10 +17,7 @@ A breadcrumb displays the current location within a hierarchy. It allows going b
### Usage upgrade after 4.24.0
```__react
import Alert from '../alert';
ReactDOM.render(<Alert message="After version 4.24.0, we provide a simpler usage <Breadcrumb.Item menu={{ items: [...] }}> with better performance and potential of writing simpler code style in your applications. Meanwhile, we deprecated the old usage in browser console, we will remove it in antd 5.0." />, mountNode);
```
<Alert message="After version 4.24.0, we provide a simpler usage &lt;Breadcrumb.Item menu={{ items: [...] }}&gt; with better performance and potential of writing simpler code style in your applications. Meanwhile, we deprecated the old usage in browser console, we will remove it in antd 5.0."></Alert>
```jsx
// works when >=4.24.0, recommended ✅

View File

@ -18,10 +18,7 @@ demo:
### 4.24.0 用法升级
```__react
import Alert from '../alert';
ReactDOM.render(<Alert message="在 4.24.0 版本后,我们提供了 <Breadcrumb.Item menu={{ items: [...] }}> 的简写方式,有更好的性能和更方便的数据组织方式,开发者不再需要自行拼接 JSX。同时我们废弃了原先的写法你还是可以在 4.x 继续使用,但会在控制台看到警告,并会在 5.0 后移除。" />, mountNode);
```
<Alert message="在 4.24.0 版本后,我们提供了 &lt;Breadcrumb.Item menu={{ items: [...] }}&gt; 的简写方式,有更好的性能和更方便的数据组织方式,开发者不再需要自行拼接 JSX。同时我们废弃了原先的写法你还是可以在 4.x 继续使用,但会在控制台看到警告,并会在 5.0 后移除。"></Alert>
```jsx
// >=4.24.0 可用,推荐的写法 ✅

View File

@ -15,10 +15,7 @@ When there are more than a few options to choose from, you can wrap them in a `D
### Usage upgrade after 4.24.0
```__react
import Alert from '../alert';
ReactDOM.render(<Alert message="After version 4.24.0, we provide a simpler usage <Dropdown menu={{ items: [...] }} /> with better performance and potential of writing simpler code style in your applications. Meanwhile, we deprecated the old usage in browser console, we will remove it in antd 5.0." />, mountNode);
```
<Alert message="After version 4.24.0, we provide a simpler usage &lt;Dropdown menu={{ items: [...] }} /&gt; with better performance and potential of writing simpler code style in your applications. Meanwhile, we deprecated the old usage in browser console, we will remove it in antd 5.0."></Alert>
```jsx
// works when >=4.24.0, recommended ✅

View File

@ -19,10 +19,7 @@ demo:
### 4.24.0 用法升级
```__react
import Alert from '../alert';
ReactDOM.render(<Alert message="在 4.24.0 版本后,我们提供了 <Dropdown menu={{ items: [...] }} /> 的简写方式,有更好的性能和更方便的数据组织方式,开发者不再需要自行拼接 JSX。同时我们废弃了原先的写法你还是可以在 4.x 继续使用,但会在控制台看到警告,并会在 5.0 后移除。" />, mountNode);
```
<Alert message="在 4.24.0 版本后,我们提供了 &lt;Dropdown menu={{ items: [...] }} /&gt; 的简写方式,有更好的性能和更方便的数据组织方式,开发者不再需要自行拼接 JSX。同时我们废弃了原先的写法你还是可以在 4.x 继续使用,但会在控制台看到警告,并会在 5.0 后移除。"></Alert>
```jsx
// >=4.24.0 可用,推荐的写法 ✅

View File

@ -20,10 +20,7 @@ More layouts with navigation: [Layout](/components/layout).
### Usage upgrade after 4.20.0
```__react
import Alert from '../alert';
ReactDOM.render(<Alert message="After version 4.20.0, we provide a simpler usage <Menu items={[...]} /> with better performance and potential of writing simpler code style in your applications. Meanwhile, we deprecated the old usage in browser console, we will remove it in antd 5.0." />, mountNode);
```
<Alert message="After version 4.20.0, we provide a simpler usage &lt;Menu items={[...]} /&gt; with better performance and potential of writing simpler code style in your applications. Meanwhile, we deprecated the old usage in browser console, we will remove it in antd 5.0."></Alert>
```jsx
// works when >=4.20.0, recommended ✅

View File

@ -21,10 +21,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/3XZcjGpvK/Menu.svg
### 4.20.0 用法升级
```__react
import Alert from '../alert';
ReactDOM.render(<Alert message="在 4.20.0 版本后,我们提供了 <Menu items={[...]} /> 的简写方式,有更好的性能和更方便的数据组织方式,开发者不再需要自行拼接 JSX。同时我们废弃了原先的写法你还是可以在 4.x 继续使用,但会在控制台看到警告,并会在 5.0 后移除。" />, mountNode);
```
<Alert message="在 4.20.0 版本后,我们提供了 &lt;Menu items={[...]} /&gt; 的简写方式,有更好的性能和更方便的数据组织方式,开发者不再需要自行拼接 JSX。同时我们废弃了原先的写法你还是可以在 4.x 继续使用,但会在控制台看到警告,并会在 5.0 后移除。"></Alert>
```jsx
// >=4.20.0 可用,推荐的写法 ✅

View File

@ -3,8 +3,6 @@ category: Components
group: Navigation
title: Steps
cover: https://gw.alipayobjects.com/zos/antfincdn/UZYqMizXHaj/Steps.svg
demo:
cols: 2
---
`Steps` is a navigation bar that guides users through the steps of a task.
@ -15,9 +13,19 @@ When a given task is complicated or has a certain sequence in the series of subt
### Usage upgrade after 4.24.0
```__react
import Alert from '../alert';
ReactDOM.render(<Alert message="After version 4.24.0, we provide a simpler usage <Steps items={[...]} /> with better performance and potential of writing simpler code style in your applications. Meanwhile, we deprecated the old usage in browser console, we will remove it in antd 5.0." />, mountNode);
<Alert message="After version 4.24.0, we provide a simpler usage &lt;Steps items={[...]} /&gt; with better performance and potential of writing simpler code style in your applications. Meanwhile, we deprecated the old usage in browser console, we will remove it in antd 5.0."></Alert>
```jsx
// works when >=4.24.0, recommended ✅
const items = [{ title: 'first step' }, { title: 'second step' }, { title: 'third step' }];
return <Steps items={items} />;
// works when <4.24.0, deprecated when >=4.24.0 🙅🏻‍♀️
<Steps>
<Step title="first step" />
<Step title="second step" />
<Step title="third step" />
</Steps>;
```
## Examples
@ -43,21 +51,6 @@ ReactDOM.render(<Alert message="After version 4.24.0, we provide a simpler usage
## API
```jsx
// works when >=4.24.0, recommended ✅
const items = [{ title: 'first step' }, { title: 'second step' }, { title: 'third step' }];
return <Steps items={items} />;
// works when <4.24.0, deprecated when >=4.24.0 🙅🏻‍♀️
<Steps>
<Step title="first step" />
<Step title="second step" />
<Step title="third step" />
</Steps>;
```
## API
### Steps
The whole of the step bar.

View File

@ -4,8 +4,6 @@ subtitle: 步骤条
group: 导航
title: Steps
cover: https://gw.alipayobjects.com/zos/antfincdn/UZYqMizXHaj/Steps.svg
demo:
cols: 2
---
引导用户按照流程完成任务的导航条。
@ -16,9 +14,19 @@ demo:
### 4.24.0 用法升级
```__react
import Alert from '../alert';
ReactDOM.render(<Alert message="在 4.24.0 版本后,我们提供了 <Steps items={[...]} /> 的简写方式,有更好的性能和更方便的数据组织方式,开发者不再需要自行拼接 JSX。同时我们废弃了原先的写法你还是可以在 4.x 继续使用,但会在控制台看到警告,并会在 5.0 后移除。" />, mountNode);
<Alert message="在 4.24.0 版本后,我们提供了 &lt;Steps items={[...]} /&gt; 的简写方式,有更好的性能和更方便的数据组织方式,开发者不再需要自行拼接 JSX。同时我们废弃了原先的写法你还是可以在 4.x 继续使用,但会在控制台看到警告,并会在 5.0 后移除。"></Alert>
```jsx
// >=4.24.0 可用,推荐的写法 ✅
const items = [{ title: '第一步' }, { title: '第二步' }, { title: '第三步' }];
return <Steps items={items} />;
// <4.24.0 可用>=4.24.0 时不推荐 🙅🏻‍♀️
<Steps>
<Step title="第一步" />
<Step title="第二步" />
<Step title="第三步" />
</Steps>;
```
## 代码演示
@ -42,19 +50,6 @@ ReactDOM.render(<Alert message="在 4.24.0 版本后,我们提供了 <Steps it
<code src="./demo/steps-in-steps.tsx" debug>Steps 嵌套 Steps</code>
<code src="./demo/inline.tsx">内联步骤</code>
```jsx
// >=4.24.0 可用,推荐的写法 ✅
const items = [{ title: '第一步' }, { title: '第二步' }, { title: '第三步' }];
return <Steps items={items} />;
// <4.24.0 可用>=4.24.0 时不推荐 🙅🏻‍♀️
<Steps>
<Step title="第一步" />
<Step title="第二步" />
<Step title="第三步" />
</Steps>;
```
## API
### Steps

View File

@ -193,116 +193,130 @@ Array [
`;
exports[`renders ./components/switch/demo/text.tsx extend context correctly 1`] = `
Array [
<button
aria-checked="true"
class="ant-switch ant-switch-checked"
role="switch"
type="button"
<div
class="ant-space ant-space-vertical"
>
<div
class="ant-space-item"
style="margin-bottom:8px"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
<button
aria-checked="true"
class="ant-switch ant-switch-checked"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner-checked"
>
开启
</span>
<span
class="ant-switch-inner-unchecked"
>
关闭
</span>
</span>
</button>,
<br />,
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
>
<span
class="ant-switch-inner-checked"
>
1
</span>
<span
class="ant-switch-inner-unchecked"
>
0
</span>
</span>
</button>,
<br />,
<button
aria-checked="true"
class="ant-switch ant-switch-checked"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
>
<span
class="ant-switch-inner-checked"
class="ant-switch-inner"
>
<span
aria-label="check"
class="anticon anticon-check"
role="img"
class="ant-switch-inner-checked"
>
<svg
aria-hidden="true"
data-icon="check"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"
/>
</svg>
开启
</span>
<span
class="ant-switch-inner-unchecked"
>
关闭
</span>
</span>
</button>
</div>
<div
class="ant-space-item"
style="margin-bottom:8px"
>
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner-unchecked"
class="ant-switch-inner"
>
<span
aria-label="close"
class="anticon anticon-close"
role="img"
class="ant-switch-inner-checked"
>
<svg
aria-hidden="true"
data-icon="close"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
/>
</svg>
1
</span>
<span
class="ant-switch-inner-unchecked"
>
0
</span>
</span>
</span>
</button>,
]
</button>
</div>
<div
class="ant-space-item"
>
<button
aria-checked="true"
class="ant-switch ant-switch-checked"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
>
<span
class="ant-switch-inner-checked"
>
<span
aria-label="check"
class="anticon anticon-check"
role="img"
>
<svg
aria-hidden="true"
data-icon="check"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"
/>
</svg>
</span>
</span>
<span
class="ant-switch-inner-unchecked"
>
<span
aria-label="close"
class="anticon anticon-close"
role="img"
>
<svg
aria-hidden="true"
data-icon="close"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
/>
</svg>
</span>
</span>
</span>
</button>
</div>
</div>
`;

View File

@ -193,116 +193,130 @@ Array [
`;
exports[`renders ./components/switch/demo/text.tsx correctly 1`] = `
Array [
<button
aria-checked="true"
class="ant-switch ant-switch-checked"
role="switch"
type="button"
<div
class="ant-space ant-space-vertical"
>
<div
class="ant-space-item"
style="margin-bottom:8px"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
<button
aria-checked="true"
class="ant-switch ant-switch-checked"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner-checked"
>
开启
</span>
<span
class="ant-switch-inner-unchecked"
>
关闭
</span>
</span>
</button>,
<br />,
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
>
<span
class="ant-switch-inner-checked"
>
1
</span>
<span
class="ant-switch-inner-unchecked"
>
0
</span>
</span>
</button>,
<br />,
<button
aria-checked="true"
class="ant-switch ant-switch-checked"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
>
<span
class="ant-switch-inner-checked"
class="ant-switch-inner"
>
<span
aria-label="check"
class="anticon anticon-check"
role="img"
class="ant-switch-inner-checked"
>
<svg
aria-hidden="true"
data-icon="check"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"
/>
</svg>
开启
</span>
<span
class="ant-switch-inner-unchecked"
>
关闭
</span>
</span>
</button>
</div>
<div
class="ant-space-item"
style="margin-bottom:8px"
>
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner-unchecked"
class="ant-switch-inner"
>
<span
aria-label="close"
class="anticon anticon-close"
role="img"
class="ant-switch-inner-checked"
>
<svg
aria-hidden="true"
data-icon="close"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
/>
</svg>
1
</span>
<span
class="ant-switch-inner-unchecked"
>
0
</span>
</span>
</span>
</button>,
]
</button>
</div>
<div
class="ant-space-item"
>
<button
aria-checked="true"
class="ant-switch ant-switch-checked"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
>
<span
class="ant-switch-inner-checked"
>
<span
aria-label="check"
class="anticon anticon-check"
role="img"
>
<svg
aria-hidden="true"
data-icon="check"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"
/>
</svg>
</span>
</span>
<span
class="ant-switch-inner-unchecked"
>
<span
aria-label="close"
class="anticon anticon-close"
role="img"
>
<svg
aria-hidden="true"
data-icon="close"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
/>
</svg>
</span>
</span>
</span>
</button>
</div>
</div>
`;

View File

@ -1,19 +1,17 @@
import React from 'react';
import { CheckOutlined, CloseOutlined } from '@ant-design/icons';
import { Switch } from 'antd';
import { Switch, Space } from 'antd';
const App: React.FC = () => (
<>
<Space direction="vertical">
<Switch checkedChildren="开启" unCheckedChildren="关闭" defaultChecked />
<br />
<Switch checkedChildren="1" unCheckedChildren="0" />
<br />
<Switch
checkedChildren={<CheckOutlined />}
unCheckedChildren={<CloseOutlined />}
defaultChecked
/>
</>
</Space>
);
export default App;

View File

@ -19,10 +19,7 @@ Ant Design has 3 types of Tabs for different situations.
### Usage upgrade after 4.23.0
```__react
import Alert from '../alert';
ReactDOM.render(<Alert message="After version 4.23.0, we provide a simpler usage <Tabs items={[...]} /> with better performance and potential of writing simpler code style in your applications. Meanwhile, we deprecated the old usage in browser console, we will remove it in antd 5.0." />, mountNode);
```
<Alert message="After version 4.23.0, we provide a simpler usage &lt;Tabs items={[...]} /&gt; with better performance and potential of writing simpler code style in your applications. Meanwhile, we deprecated the old usage in browser console, we will remove it in antd 5.0."></Alert>
```jsx
// works when >=4.23.0, recommended ✅
@ -67,40 +64,40 @@ return <Tabs items={items} />;
### Tabs
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- | --- |
| activeKey | Current TabPane's key | string | - | |
| addIcon | Customize add icon | ReactNode | - | 4.4.0 |
| animated | Whether to change tabs with animation. Only works while `tabPosition="top"` | boolean \| { inkBar: boolean, tabPane: boolean } | { inkBar: true, tabPane: false } | |
| centered | Centers tabs | boolean | false | 4.4.0 |
| defaultActiveKey | Initial active TabPane's key, if `activeKey` is not set | string | - | |
| hideAdd | Hide plus icon or not. Only works while `type="editable-card"` | boolean | false | |
| items | Configure tab content | [TabItem](#TabItem) | [] | 4.23.0 |
| moreIcon | The custom icon of ellipsis | ReactNode | &lt;EllipsisOutlined /> | 4.14.0 |
| popupClassName | `className` for more dropdown. | string | - | 4.21.0 |
| renderTabBar | Replace the TabBar | (props: DefaultTabBarProps, DefaultTabBar: React.ComponentClass) => React.ReactElement | - | |
| size | Preset tab bar size | `large` \| `middle` \| `small` | `middle` | |
| tabBarExtraContent | Extra content in tab bar | ReactNode \| {left?: ReactNode, right?: ReactNode} | - | object: 4.6.0 |
| tabBarGutter | The gap between tabs | number | - | |
| tabBarStyle | Tab bar style object | CSSProperties | - | |
| tabPosition | Position of tabs | `top` \| `right` \| `bottom` \ | `left` | `top` | |
| destroyInactiveTabPane | Whether destroy inactive TabPane when change tab | boolean | false | |
| type | Basic style of tabs | `line` \| `card` \| `editable-card` | `line` | |
| onChange | Callback executed when active tab is changed | function(activeKey) {} | - | |
| onEdit | Callback executed when tab is added or removed. Only works while `type="editable-card"` | (action === 'add' ? event : targetKey, action): void | - | |
| onTabClick | Callback executed when tab is clicked | function(key: string, event: MouseEvent) | - | |
| onTabScroll | Trigger when tab scroll | function({ direction: `left` \| `right` \| `top` \| `bottom` }) | - | 4.3.0 |
| items | TabItem content | [TabItemType](#TabItemType) | [] | 4.23.0 |
| Property | Description | Type | Default | Version |
| ---------------------- | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | -------------------------------- | ------------- | --- |
| activeKey | Current TabPane's key | string | - | |
| addIcon | Customize add icon | ReactNode | - | 4.4.0 |
| animated | Whether to change tabs with animation. Only works while `tabPosition="top"` | boolean \| { inkBar: boolean, tabPane: boolean } | { inkBar: true, tabPane: false } | |
| centered | Centers tabs | boolean | false | 4.4.0 |
| defaultActiveKey | Initial active TabPane's key, if `activeKey` is not set | string | - | |
| hideAdd | Hide plus icon or not. Only works while `type="editable-card"` | boolean | false | |
| items | Configure tab content | [TabItem](#TabItem) | [] | 4.23.0 |
| moreIcon | The custom icon of ellipsis | ReactNode | &lt;EllipsisOutlined /> | 4.14.0 |
| popupClassName | `className` for more dropdown. | string | - | 4.21.0 |
| renderTabBar | Replace the TabBar | (props: DefaultTabBarProps, DefaultTabBar: React.ComponentClass) => React.ReactElement | - | |
| size | Preset tab bar size | `large` \| `middle` \| `small` | `middle` | |
| tabBarExtraContent | Extra content in tab bar | ReactNode \| {left?: ReactNode, right?: ReactNode} | - | object: 4.6.0 |
| tabBarGutter | The gap between tabs | number | - | |
| tabBarStyle | Tab bar style object | CSSProperties | - | |
| tabPosition | Position of tabs | `top` \| `right` \| `bottom` \ | `left` | `top` | |
| destroyInactiveTabPane | Whether destroy inactive TabPane when change tab | boolean | false | |
| type | Basic style of tabs | `line` \| `card` \| `editable-card` | `line` | |
| onChange | Callback executed when active tab is changed | function(activeKey) {} | - | |
| onEdit | Callback executed when tab is added or removed. Only works while `type="editable-card"` | (action === 'add' ? event : targetKey, action): void | - | |
| onTabClick | Callback executed when tab is clicked | function(key: string, event: MouseEvent) | - | |
| onTabScroll | Trigger when tab scroll | function({ direction: `left` \| `right` \| `top` \| `bottom` }) | - | 4.3.0 |
| items | TabItem content | [TabItemType](#TabItemType) | [] | 4.23.0 |
More option at [rc-tabs tabs](https://github.com/react-component/tabs#tabs)
### TabItemType
| Property | Description | Type | Default |
| --- | --- | --- | --- |
| closeIcon | Customize close icon in TabPane's head. Only works while `type="editable-card"` | ReactNode | - |
| disabled | Set TabPane disabled | boolean | false |
| forceRender | Forced render of content in tabs, not lazy render after clicking on tabs | boolean | false |
| key | TabPane's key | string | - |
| label | TabPane's head display text | ReactNode | - |
| children | TabPane's head display content | ReactNode | - |
| Property | Description | Type | Default |
| ----------- | ------------------------------------------------------------------------------- | --------- | ------- |
| closeIcon | Customize close icon in TabPane's head. Only works while `type="editable-card"` | ReactNode | - |
| disabled | Set TabPane disabled | boolean | false |
| forceRender | Forced render of content in tabs, not lazy render after clicking on tabs | boolean | false |
| key | TabPane's key | string | - |
| label | TabPane's head display text | ReactNode | - |
| children | TabPane's head display content | ReactNode | - |

View File

@ -22,10 +22,7 @@ Ant Design 依次提供了三级选项卡,分别用于不同的场景。
### 4.23.0 用法升级
```__react
import Alert from '../alert';
ReactDOM.render(<Alert message="在 4.23.0 版本后,我们提供了 <Tabs items={[...]} /> 的简写方式,有更好的性能和更方便的数据组织方式,开发者不再需要自行拼接 JSX。同时我们废弃了原先的写法你还是可以在 4.x 继续使用,但会在控制台看到警告,并会在 5.0 后移除。" />, mountNode);
```
<Alert message="在 4.23.0 版本后,我们提供了 &lt;Tabs items={[...]} /&gt; 的简写方式,有更好的性能和更方便的数据组织方式,开发者不再需要自行拼接 JSX。同时我们废弃了原先的写法你还是可以在 4.x 继续使用,但会在控制台看到警告,并会在 5.0 后移除。"></Alert>
```jsx
// >=4.23.0 可用,推荐的写法 ✅
@ -70,29 +67,29 @@ return <Tabs items={items} />;
### Tabs
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| activeKey | 当前激活 tab 面板的 key | string | - | |
| addIcon | 自定义添加按钮 | ReactNode | - | 4.4.0 |
| animated | 是否使用动画切换 Tabs, 仅生效于 `tabPosition="top"` | boolean\| { inkBar: boolean, tabPane: boolean } | { inkBar: true, tabPane: false } | |
| centered | 标签居中展示 | boolean | false | 4.4.0 |
| defaultActiveKey | 初始化选中面板的 key如果没有设置 activeKey | string | `第一个面板` | |
| hideAdd | 是否隐藏加号图标,在 `type="editable-card"` 时有效 | boolean | false | |
| items | 配置选项卡内容 | [TabItemType](#TabItemType) | [] | 4.23.0 |
| moreIcon | 自定义折叠 icon | ReactNode | &lt;EllipsisOutlined /> | 4.14.0 |
| popupClassName | 更多菜单的 `className` | string | - | 4.21.0 |
| renderTabBar | 替换 TabBar用于二次封装标签头 | (props: DefaultTabBarProps, DefaultTabBar: React.ComponentClass) => React.ReactElement | - | |
| size | 大小,提供 `large` `middle``small` 三种大小 | string | `middle` | |
| tabBarExtraContent | tab bar 上额外的元素 | ReactNode \| {left?: ReactNode, right?: ReactNode} | - | object: 4.6.0 |
| tabBarGutter | tabs 之间的间隙 | number | - | |
| tabBarStyle | tab bar 的样式对象 | CSSProperties | - | |
| tabPosition | 页签位置,可选值有 `top` `right` `bottom` `left` | string | `top` | |
| destroyInactiveTabPane | 被隐藏时是否销毁 DOM 结构 | boolean | false | |
| type | 页签的基本样式,可选 `line`、`card` `editable-card` 类型 | string | `line` | |
| onChange | 切换面板的回调 | function(activeKey) {} | - | |
| onEdit | 新增和删除页签的回调,在 `type="editable-card"` 时有效 | (action === 'add' ? event : targetKey, action): void | - | |
| onTabClick | tab 被点击的回调 | function(key: string, event: MouseEvent) | - | |
| onTabScroll | tab 滚动时触发 | function({ direction: `left` \| `right` \| `top` \| `bottom` }) | - | 4.3.0 |
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| ---------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------------- | -------------------------------- | ------------- |
| activeKey | 当前激活 tab 面板的 key | string | - | |
| addIcon | 自定义添加按钮 | ReactNode | - | 4.4.0 |
| animated | 是否使用动画切换 Tabs, 仅生效于 `tabPosition="top"` | boolean\| { inkBar: boolean, tabPane: boolean } | { inkBar: true, tabPane: false } | |
| centered | 标签居中展示 | boolean | false | 4.4.0 |
| defaultActiveKey | 初始化选中面板的 key如果没有设置 activeKey | string | `第一个面板` | |
| hideAdd | 是否隐藏加号图标,在 `type="editable-card"` 时有效 | boolean | false | |
| items | 配置选项卡内容 | [TabItemType](#TabItemType) | [] | 4.23.0 |
| moreIcon | 自定义折叠 icon | ReactNode | &lt;EllipsisOutlined /> | 4.14.0 |
| popupClassName | 更多菜单的 `className` | string | - | 4.21.0 |
| renderTabBar | 替换 TabBar用于二次封装标签头 | (props: DefaultTabBarProps, DefaultTabBar: React.ComponentClass) => React.ReactElement | - | |
| size | 大小,提供 `large` `middle``small` 三种大小 | string | `middle` | |
| tabBarExtraContent | tab bar 上额外的元素 | ReactNode \| {left?: ReactNode, right?: ReactNode} | - | object: 4.6.0 |
| tabBarGutter | tabs 之间的间隙 | number | - | |
| tabBarStyle | tab bar 的样式对象 | CSSProperties | - | |
| tabPosition | 页签位置,可选值有 `top` `right` `bottom` `left` | string | `top` | |
| destroyInactiveTabPane | 被隐藏时是否销毁 DOM 结构 | boolean | false | |
| type | 页签的基本样式,可选 `line`、`card` `editable-card` 类型 | string | `line` | |
| onChange | 切换面板的回调 | function(activeKey) {} | - | |
| onEdit | 新增和删除页签的回调,在 `type="editable-card"` 时有效 | (action === 'add' ? event : targetKey, action): void | - | |
| onTabClick | tab 被点击的回调 | function(key: string, event: MouseEvent) | - | |
| onTabScroll | tab 滚动时触发 | function({ direction: `left` \| `right` \| `top` \| `bottom` }) | - | 4.3.0 |
> 更多属性查看 [rc-tabs tabs](https://github.com/react-component/tabs#tabs)

View File

@ -3,8 +3,6 @@ category: Components
group: General
title: Typography
cover: https://gw.alipayobjects.com/zos/alicdn/GOM1KQ24O/Typography.svg
demo:
cols: 2
---
Basic text writing, including headings, body text, lists, and more.

View File

@ -4,8 +4,6 @@ subtitle: 排版
group: 通用
title: Typography
cover: https://gw.alipayobjects.com/zos/alicdn/GOM1KQ24O/Typography.svg
demo:
cols: 2
---
文本的基本格式。

View File

@ -24,21 +24,13 @@ Ant Design system-level color system also comes from the "natural" design langua
Ant Design's base color palette totals 120 colors, including 12 primary colors and their derivative colors. These colors can basically include the need for color in background applications design.
```__react
import ColorPalettes from '../../site/theme/template/Color/ColorPalettes';
ReactDOM.render(<ColorPalettes />, mountNode);
```
<ColorPalettes></ColorPalettes>
Ant Design's color palette also has the ability to further extend. After careful elaboration by designers and programmers, we have come up with a set of color generation tools that combine the natural variation of colors. When there is a need for further color design, designers simply define the primary colors according to certain rules and will get a complete range of derived colors automatically .
### Neutral Color Palette
```__react
import Palette from '../../site/theme/template/Color/Palette';
ReactDOM.render(<Palette color={{ name: 'gray', count: 13 }} direction="horizontal" />, mountNode);
```
<Palette direction="horizontal"></Palette>
### Data Visualization Color Palette
@ -48,11 +40,7 @@ Data visualization color palette is based on the basic color palette and neutral
If the above palettes do not meet your needs, you can choose a main color below, and Ant Design's color generation algorithm will generate a palette for you.
```__react
import ColorPaletteTool from '../../site/theme/template/Color/ColorPaletteTool';
ReactDOM.render(<ColorPaletteTool />, mountNode);
```
<ColorPaletteTool></ColorPaletteTool>
### Programmatic Usage
@ -93,8 +81,7 @@ We provide Less and JavaScript usage for developers.
### Brand Color
<img class="preview-img no-padding" align="right" src="
https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*1c74TKxuEW4AAAAAAAAAAABkARQnAQ">
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*1c74TKxuEW4AAAAAAAAAAABkARQnAQ">
The brand color is one of the most intuitive visual elements used that is used to embody product characteristics and communicate ideas. When selecting colors, it is important to understand how the brand color is used in the user interface. In the basic color palette to choose the main color, we recommend choosing the color plate from the shallow depth of the sixth color as the main color. Ant Design's brand color comes from blue of the base color palette, it's Hex value is 1890FF, application scenarios include: key action point, the operation status, important information highlighting, graphics and other scenes.

View File

@ -28,11 +28,7 @@ Ant Design 系统级色彩体系同样源于「自然」的设计价值观。设
Ant Design 的基础色板共计 120 个颜色,包含 12 个主色以及衍生色。这些颜色基本可以满足中后台设计中对于颜色的需求。
```__react
import ColorPalettes from '../../site/theme/template/Color/ColorPalettes';
ReactDOM.render(<ColorPalettes />, mountNode);
```
<ColorPalettes></ColorPalettes>
Ant Design 的色板还具备进一步拓展的能力。经过设计师和程序员的精心调制,结合了色彩自然变化的规律,我们得出了一套色彩生成工具,当有进一步色彩设计需求时,设计者只需按照一定规则定义完毕主色,便可以自动获得一系列完整的衍生色。
@ -42,11 +38,7 @@ Ant Design 的色板还具备进一步拓展的能力。经过设计师和程序
中性色包含了黑、白、灰。在蚂蚁中后台的网页设计中被大量使用到合理地选择中性色能够令页面信息具备良好的主次关系助力阅读体验。Ant Design 的中性色板一共包含了从白到黑的 13 个颜色。
```__react
import Palette from '../../site/theme/template/Color/Palette';
ReactDOM.render(<Palette color={{ name: 'gray', count: 13 }} direction="horizontal" />, mountNode);
```
<Palette direction="horizontal"></Palette>
### 数据可视化色板
@ -56,11 +48,7 @@ ReactDOM.render(<Palette color={{ name: 'gray', count: 13 }} direction="horizont
如果上面的色板不能满足你的需求你可以选择一个主色Ant Design 的色彩生成算法会为你生成完整的色板。
```__react
import ColorPaletteTool from '../../site/theme/template/Color/ColorPaletteTool';
ReactDOM.render(<ColorPaletteTool />, mountNode);
```
<ColorPaletteTool></ColorPaletteTool>
### 在代码中使用色板

View File

@ -28,18 +28,10 @@ In the application of colors, we are based on 12 sets of basic swatches and comb
### Color Palette
```__react
import ColorPalettes from '../../site/theme/template/Color/ColorPalettes';
ReactDOM.render(<ColorPalettes dark />, mountNode);
```
<ColorPalettes dark={true}></ColorPalettes>
### Color Palette Generator
Additionally, we also provide a set of tools for generating color palettes in dark colors. You need to select your primary color and the background color of the page. We will generate a dark mode color palette for you.
```__react
import ColorPaletteToolDark from '../../site/theme/template/Color/ColorPaletteToolDark';
ReactDOM.render(<ColorPaletteToolDark />, mountNode);
```
<ColorPaletteToolDark></ColorPaletteToolDark>

View File

@ -28,18 +28,10 @@ title: 暗黑模式
### 基础色板
```__react
import ColorPalettes from '../../site/theme/template/Color/ColorPalettes';
ReactDOM.render(<ColorPalettes dark />, mountNode);
```
<ColorPalettes dark={true}></ColorPalettes>
### 色板生成工具
同样,我们也提供了一套暗色下的色板生成工具,需要选择你的主色以及页面的背景色,我们会为你生成一套暗色下的色板
```__react
import ColorPaletteToolDark from '../../site/theme/template/Color/ColorPaletteToolDark';
ReactDOM.render(<ColorPaletteToolDark />, mountNode);
```
<ColorPaletteToolDark></ColorPaletteToolDark>

View File

@ -32,54 +32,13 @@ We provide comprehensive design guidelines, best practices, resources, and tools
[React](http://facebook.github.io/react/) is used to encapsulate a library of components which embody our design language. We welcome the community to implement [our design system](/docs/spec/introduce) in other front-end frameworks of their choice.
```__react
import {
ExportOutlined,
} from '@ant-design/icons';
const LinkIcon = () => (
<ExportOutlined className="outside-link-icon" />
);
const LinksList = () => (
<ul>
<li>
<a href="/docs/react/introduce" target="_blank">Ant Design of React </a>
(official implementation)
</li>
<li>
<a href="http://ng.ant.design" target="_blank">
NG-ZORRO - Ant Design of Angular
</a>
</li>
<li>
<a href="http://ng.mobile.ant.design" target="_blank">
NG-ZORRO-MOBILE - Ant Design Mobile of Angular
</a>
</li>
<li>
<a href="http://antdv.com" target="_blank">Ant Design of Vue</a>
</li>
<li>
<a href="https://ant-design-blazor.github.io/" target="_blank">
Ant Design Blazor
</a>
</li>
<li>
<a href="https://ecomfe.github.io/santd" target="_blank">
San UI Toolkit for Ant Design
</a>
</li>
<li>
<a href="https://github.com/priornix/antizer" target="_blank">
antizer (ClojureScript)
</a>
</li>
</ul>
);
ReactDOM.render(<LinksList />, mountNode);
```
- [Ant Design of React](/docs/react/introduce)official implementation
- [NG-ZORRO - Ant Design of Angular](http://ng.ant.design)
- [NG-ZORRO-MOBILE - Ant Design Mobile of Angular](http://ng.mobile.ant.design)
- [Ant Design of Vue](http://antdv.com)
- [Ant Design Blazor](https://ant-design-blazor.github.io/)
- [San UI Toolkit for Ant Design](https://ecomfe.github.io/santd)
- [antizer (ClojureScript)](https://github.com/priornix/antizer)
## Who's using Ant Design

View File

@ -32,54 +32,13 @@ title: 介绍
我们采用 [React](http://facebook.github.io/react/) 封装了一套 Ant Design 的组件库,也欢迎社区其他框架的实现版本。
```__react
import {
ExportOutlined,
} from '@ant-design/icons';
const LinkIcon = () => (
<ExportOutlined className="outside-link-icon" />
);
const LinksList = () => (
<ul>
<li>
<a href="/docs/react/introduce" target="_blank">Ant Design of React</a>
(官方实现)
</li>
<li>
<a href="http://ng.ant.design" target="_blank">
NG-ZORRO - Ant Design of Angular
</a>
</li>
<li>
<a href="http://ng.mobile.ant.design" target="_blank">
NG-ZORRO-MOBILE - Ant Design Mobile of Angular
</a>
</li>
<li>
<a href="http://antdv.com" target="_blank">Ant Design of Vue</a>
</li>
<li>
<a href="https://ant-design-blazor.github.io/" target="_blank">
Ant Design Blazor
</a>
</li>
<li>
<a href="https://ecomfe.github.io/santd" target="_blank">
San UI Toolkit for Ant Design
</a>
</li>
<li>
<a href="https://github.com/priornix/antizer" target="_blank">
antizer (ClojureScript)
</a>
</li>
</ul>
);
ReactDOM.render(<LinksList />, mountNode);
```
- [Ant Design of React](/docs/react/introduce)(官方实现)
- [NG-ZORRO - Ant Design of Angular](http://ng.ant.design)
- [NG-ZORRO-MOBILE - Ant Design Mobile of Angular](http://ng.mobile.ant.design)
- [Ant Design of Vue](http://antdv.com)
- [Ant Design Blazor](https://ant-design-blazor.github.io/)
- [San UI Toolkit for Ant Design](https://ecomfe.github.io/santd)
- [antizer (ClojureScript)](https://github.com/priornix/antizer)
## 谁在使用

View File

@ -25,21 +25,41 @@ We can determine if an animation is effective or not from the following two aspe
Different from animations usage in typical front-office applications, animations in enterprise level applications spend a great amount of efforts on reinforcing user interactions and the effectiveness of those interactions. Therefore, we derived three animation design principles from Ant Design's core design language:
```__react
```jsx | demo
/**
* inline: true
*/
import { Col, Row } from 'antd';
const text = [
{ title: 'Natural', img: 'https://gw.alipayobjects.com/zos/rmsportal/LyTPSGknLUlxiVdwMWyu.gif', content: 'The animation should based on law of nature. This assures the animation is smooth by its nature and intuitive to its users.' },
{ title: 'Performant', img: 'https://gw.alipayobjects.com/zos/rmsportal/SQOZVQVIossbXpzDmihu.gif', content: 'The animation should have a transition time as minimal as possible so that it serves its purpose in the most effective way.' },
{ title: 'Concise', img: 'https://gw.alipayobjects.com/zos/rmsportal/OkIXkscKxywYLSrilPIf.gif', content: 'The animation should be meaningful and justified. An over fancy animation will frustrate its users, and therefore should always be avoided.' },
{
title: 'Natural',
img: 'https://gw.alipayobjects.com/zos/rmsportal/LyTPSGknLUlxiVdwMWyu.gif',
content:
'The animation should based on law of nature. This assures the animation is smooth by its nature and intuitive to its users.',
},
{
title: 'Performant',
img: 'https://gw.alipayobjects.com/zos/rmsportal/SQOZVQVIossbXpzDmihu.gif',
content:
'The animation should have a transition time as minimal as possible so that it serves its purpose in the most effective way.',
},
{
title: 'Concise',
img: 'https://gw.alipayobjects.com/zos/rmsportal/OkIXkscKxywYLSrilPIf.gif',
content:
'The animation should be meaningful and justified. An over fancy animation will frustrate its users, and therefore should always be avoided.',
},
];
function Principle() {
const childrenToRender = text.map(item => (
<Col key={item.title} sm={24} md={8} >
<Col key={item.title} sm={24} md={8}>
<div className="principle">
<div><img src={item.img} width="80%" /></div>
<div>
<img src={item.img} width="80%" />
</div>
<h4>{item.title}</h4>
<p>{item.content}</p>
</div>
@ -54,14 +74,14 @@ function Principle() {
);
}
ReactDOM.render(<Principle />, mountNode);
export default Principle;
```
### Natural
Intuitive animations usually are backed by law of nature. This requires the animations to be smooth so that their users can feel the animations' motion being justified. A natural animation triggers its users with positive user experiences.
<video class="motion-video-min" src="https://gw.alipayobjects.com/os/rmsportal/NTMlQdLIkPjOACXsdRrq.mp4" loop="true" />
<video class="motion-video-min" src="https://gw.alipayobjects.com/os/rmsportal/NTMlQdLIkPjOACXsdRrq.mp4" loop="true"></video>
Take button animation as an example, designers image the button as foliage on water - when you press it and release, the leave will slightly go into the water, and then pop back up, creating ripples around itself.
@ -69,7 +89,7 @@ Take button animation as an example, designers image the button as foliage on wa
Enterprise level applications require highly effective user interactions. So is their animation design - with a transition time as minimal as possible.
<video class="motion-video-min" src="https://gw.alipayobjects.com/os/rmsportal/wMKeLGnpDxhwfCsBqKNN.mp4" loop="true" />
<video class="motion-video-min" src="https://gw.alipayobjects.com/os/rmsportal/wMKeLGnpDxhwfCsBqKNN.mp4" loop="true"></video>
For example, compared to appearing animations, disappearing animations should not attract too much attention from their users. They just need to be concise and clear. Therefore, disappearing animations are configured to swing out with faster velocity and no disappearing delay between each list items - they disappear all at the same time as one unit.
@ -77,7 +97,7 @@ For example, compared to appearing animations, disappearing animations should no
Avoid dramatic and complicated animations. A good animation will get the job done instead of frustrating its users.
<video src="https://gw.alipayobjects.com/os/rmsportal/FeUCANmoDRwCSmIcnPNF.mp4" loop="true" class="motion-video-min" />
<video src="https://gw.alipayobjects.com/os/rmsportal/FeUCANmoDRwCSmIcnPNF.mp4" loop="true" class="motion-video-min"></video>
For example, when a user expands a menu, his main focus is on the menu content, not the direction change of the arrow icon on the right. Therefore, the animation doesn't need to be very complicated and distracting; it changes just enough to indicate the transition.

View File

@ -18,28 +18,45 @@ title: 动效
衡量一个动效是否有意义,我们可以通过以下几个标准来考核:
- **一个动效的存在是否合理:**是否带有明确的目的性,助力交互体验,没有多余的动效。
- **动效与性能:**不能出现大幅度波动丢帧或者卡顿现象, 动效的体验须是流畅的,并且不影响产品的性能。
- **一个动效的存在是否合理:** 是否带有明确的目的性,助力交互体验,没有多余的动效。
- **动效与性能:** 不能出现大幅度波动丢帧或者卡顿现象, 动效的体验须是流畅的,并且不影响产品的性能。
## 原则
在企业级应用的产品设计中,使用动效和前台类产品有很大的不同,助力交互行为和信息认知的有效性会显得尤为重要,在 Ant Design 设计价值观的基础之上,我们衍生出动效设计的三原则:
```__react
```jsx | demo
/**
* inline: true
*/
import { Col, Row } from 'antd';
const text = [
{ title: '自然', img: 'https://gw.alipayobjects.com/zos/rmsportal/LyTPSGknLUlxiVdwMWyu.gif', content: '自然运动规律,保证视觉连惯,让用户感知到动作是成立的' },
{ title: '高效', img: 'https://gw.alipayobjects.com/zos/rmsportal/SQOZVQVIossbXpzDmihu.gif', content: '尽量节省过渡的时间,快速完成过渡的动画效果' },
{ title: '克制', img: 'https://gw.alipayobjects.com/zos/rmsportal/OkIXkscKxywYLSrilPIf.gif', content: '做有意义的动效,不去做太多的修饰和干扰用户' },
{
title: '自然',
img: 'https://gw.alipayobjects.com/zos/rmsportal/LyTPSGknLUlxiVdwMWyu.gif',
content: '自然运动规律,保证视觉连惯,让用户感知到动作是成立的',
},
{
title: '高效',
img: 'https://gw.alipayobjects.com/zos/rmsportal/SQOZVQVIossbXpzDmihu.gif',
content: '尽量节省过渡的时间,快速完成过渡的动画效果',
},
{
title: '克制',
img: 'https://gw.alipayobjects.com/zos/rmsportal/OkIXkscKxywYLSrilPIf.gif',
content: '做有意义的动效,不去做太多的修饰和干扰用户',
},
];
function Principle() {
const childrenToRender = text.map(item => (
<Col key={item.title} sm={24} md={8} >
<Col key={item.title} sm={24} md={8}>
<div className="principle">
<div><img src={item.img} width="80%" /></div>
<div>
<img src={item.img} width="80%" />
</div>
<h4>{item.title}</h4>
<p>{item.content}</p>
</div>
@ -54,14 +71,14 @@ function Principle() {
);
}
ReactDOM.render(<Principle />, mountNode);
export default Principle;
```
### 自然
自然的动效背后体现的是自然运动规律。这就要求动效在转换时保证视觉上的连惯性,让用户感知到这个动作是成立的,是能够引起共鸣的。
<video class="motion-video-min" src="https://gw.alipayobjects.com/os/rmsportal/NTMlQdLIkPjOACXsdRrq.mp4" loop="true" />
<video class="motion-video-min" src="https://gw.alipayobjects.com/os/rmsportal/NTMlQdLIkPjOACXsdRrq.mp4" loop="true"></video>
以 button 的动效设计为例,设计师将其想像成一片树叶飘浮在水面之上,当你去触碰它时,叶子会下浮再反弹,然后出现涟漪效果。
@ -69,7 +86,7 @@ ReactDOM.render(<Principle />, mountNode);
企业级应用追求的是高效的用户体验,与之对应的动效设计也应如此,尽量节省过渡的时间,快速完成过渡的动画效果。
<video class="motion-video-min" src="https://gw.alipayobjects.com/os/rmsportal/wMKeLGnpDxhwfCsBqKNN.mp4" loop="true" />
<video class="motion-video-min" src="https://gw.alipayobjects.com/os/rmsportal/wMKeLGnpDxhwfCsBqKNN.mp4" loop="true"></video>
举个例子,在出场与进场的动效里,出场不用大张旗鼓的去吸引用户的注意力,而是做到简单清晰即可。所以我们的出场时间采用了更快的速度,同时也不设置队列依次出场的形式,只需要整块直接消失即可。
@ -77,7 +94,7 @@ ReactDOM.render(<Principle />, mountNode);
尽量避免夸张的动效,做有意义的事,不去做太多的修饰而干扰用户。
<video src="https://gw.alipayobjects.com/os/rmsportal/FeUCANmoDRwCSmIcnPNF.mp4" loop="true" class="motion-video-min" />
<video src="https://gw.alipayobjects.com/os/rmsportal/FeUCANmoDRwCSmIcnPNF.mp4" loop="true" class="motion-video-min"></video>
如我们的 Menu在展开时更注重的是菜单的内容而右侧的图标切换并不是主要的元素不需要过度强调去分散用户的注意。只需在不经意间切换明确指示变化即可。

3
loading.js Normal file
View File

@ -0,0 +1,3 @@
// put it into `.dumi` folder when dumi ready
// eslint-disable-next-line no-restricted-exports
export { default } from './.dumi/theme/common/Loading';