mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-12-12 11:55:23 +08:00
Merge pull request #18802 from ant-design/master-to-merge
chore: merge master into feature
This commit is contained in:
commit
2128ee28ae
28
.github/workflows/publish-to-github-package.yml
vendored
Normal file
28
.github/workflows/publish-to-github-package.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
name: Publish to github-package
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@master
|
||||
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '12.x'
|
||||
registry-url: 'https://npm.pkg.github.com'
|
||||
|
||||
- name: install
|
||||
run: npm install
|
||||
|
||||
- name: compile
|
||||
run: npm run compile
|
||||
|
||||
- name: publish
|
||||
run: npm publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
@ -66,7 +66,7 @@ timeline: true
|
||||
- Descriptions
|
||||
- 🐞 修复 Descriptions.Item 最后一个宽度计算不正确的问题。[#18568](https://github.com/ant-design/ant-design/pull/18568)
|
||||
- 🐞 Description.Item 在渲染时会复用用户提供的 `key`。[#18578](https://github.com/ant-design/ant-design/pull/18578)
|
||||
- 🐞 修复 Tab 内容宽度在 Safari 下不正确的问题。[#18574](https://github.com/ant-design/ant-design/pull/18574)
|
||||
- 🐞 修复 Tabs 内容宽度在 Safari 下不正确的问题。[#18574](https://github.com/ant-design/ant-design/pull/18574)
|
||||
- 🐞 修复 Mentions 的 `prefix` 为空字符串时,弹窗位置不正确的问题。[#18576](https://github.com/ant-design/ant-design/pull/18576)
|
||||
- 🐞 修复 Upload.Dragger 在 `multiple` 为 false 时,仍然可以上传多份文件的问题。[#18580](https://github.com/ant-design/ant-design/pull/18580)
|
||||
- 🐞 修复 `Button[href]` 在 Card `actions` 中样式变形的问题。[#18588](https://github.com/ant-design/ant-design/pull/18588)
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
<div align="center">
|
||||
|
||||
一套企业级的 UI 设计语言和 React 实现。
|
||||
一套企业级 UI 设计语言和 React 组件库。
|
||||
|
||||
[![CircleCI branch](https://img.shields.io/circleci/project/github/ant-design/ant-design/master.svg?style=flat-square)](https://circleci.com/gh/ant-design/ant-design) [![Codecov](https://img.shields.io/codecov/c/github/ant-design/ant-design/master.svg?style=flat-square)](https://codecov.io/gh/ant-design/ant-design/branch/master) [![npm package](https://img.shields.io/npm/v/antd.svg?style=flat-square)](https://www.npmjs.org/package/antd) [![NPM downloads](http://img.shields.io/npm/dm/antd.svg?style=flat-square)](http://npmjs.com/antd)
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
<div align="center">
|
||||
|
||||
An enterprise-class UI design language and React implementation.
|
||||
An enterprise-class UI design language and React UI library.
|
||||
|
||||
[![CircleCI branch](https://img.shields.io/circleci/project/github/ant-design/ant-design/master.svg?style=flat-square)](https://circleci.com/gh/ant-design/ant-design) [![Codecov](https://img.shields.io/codecov/c/github/ant-design/ant-design/master.svg?style=flat-square)](https://codecov.io/gh/ant-design/ant-design/branch/master) [![](https://flat.badgen.net/npm/v/antd?icon=npm)](https://www.npmjs.com/package/antd) [![NPM downloads](http://img.shields.io/npm/dm/antd.svg?style=flat-square)](http://npmjs.com/antd)
|
||||
|
||||
|
@ -66,10 +66,10 @@ exports[`renders ./components/alert/demo/banner.md correctly 1`] = `
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
<span
|
||||
<button
|
||||
class="ant-alert-close-icon"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: close"
|
||||
@ -90,7 +90,7 @@ exports[`renders ./components/alert/demo/banner.md correctly 1`] = `
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<br />
|
||||
<div
|
||||
@ -172,10 +172,10 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
<span
|
||||
<button
|
||||
class="ant-alert-close-icon"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: close"
|
||||
@ -196,7 +196,7 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-alert ant-alert-error ant-alert-with-description ant-alert-no-icon ant-alert-closable"
|
||||
@ -212,10 +212,10 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
|
||||
>
|
||||
Error Description Error Description Error Description Error Description Error Description Error Description
|
||||
</span>
|
||||
<span
|
||||
<button
|
||||
class="ant-alert-close-icon"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: close"
|
||||
@ -236,7 +236,7 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@ -254,17 +254,17 @@ exports[`renders ./components/alert/demo/close-text.md correctly 1`] = `
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
<span
|
||||
<button
|
||||
class="ant-alert-close-icon"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-alert-close-text"
|
||||
>
|
||||
Close Now
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -910,10 +910,10 @@ exports[`renders ./components/alert/demo/smooth-closed.md correctly 1`] = `
|
||||
<span
|
||||
class="ant-alert-description"
|
||||
/>
|
||||
<span
|
||||
<button
|
||||
class="ant-alert-close-icon"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: close"
|
||||
@ -934,7 +934,7 @@ exports[`renders ./components/alert/demo/smooth-closed.md correctly 1`] = `
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<p>
|
||||
placeholder text here
|
||||
|
@ -23,7 +23,7 @@ export interface AlertProps {
|
||||
/** Additional content of Alert */
|
||||
description?: React.ReactNode;
|
||||
/** Callback when close Alert */
|
||||
onClose?: React.MouseEventHandler<HTMLAnchorElement>;
|
||||
onClose?: React.MouseEventHandler<HTMLButtonElement>;
|
||||
/** Trigger when animation ending of Alert */
|
||||
afterClose?: () => void;
|
||||
/** Whether to show icon */
|
||||
@ -57,7 +57,7 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
|
||||
};
|
||||
}
|
||||
|
||||
handleClose = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
handleClose = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.preventDefault();
|
||||
const dom = ReactDOM.findDOMNode(this) as HTMLElement;
|
||||
dom.style.height = `${dom.offsetHeight}px`;
|
||||
@ -143,8 +143,8 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
|
||||
);
|
||||
|
||||
const closeIcon = closable ? (
|
||||
<span
|
||||
role="button"
|
||||
<button
|
||||
type="button"
|
||||
onClick={this.handleClose}
|
||||
className={`${prefixCls}-close-icon`}
|
||||
tabIndex={0}
|
||||
@ -154,7 +154,7 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
|
||||
) : (
|
||||
<Icon type="close" />
|
||||
)}
|
||||
</span>
|
||||
</button>
|
||||
) : null;
|
||||
|
||||
const dataOrAriaProps = getDataOrAriaProps(this.props);
|
||||
|
@ -74,6 +74,8 @@
|
||||
overflow: hidden;
|
||||
font-size: @font-size-sm;
|
||||
line-height: 22px;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
cursor: pointer;
|
||||
|
||||
.@{iconfont-css-prefix}-close {
|
||||
|
@ -26,6 +26,7 @@ const dataSource = ['12345', '23456', '34567'];
|
||||
| children (for customize input element) | customize input element | HTMLInputElement <br /><br /> HTMLTextAreaElement <br /><br /> `React.ReactElement<InputProps>` | `<Input />` | |
|
||||
| children (for dataSource) | Data source to auto complete | `React.ReactElement<OptionProps>` <br /><br /> `Array<React.ReactElement<OptionProps>>` | - | |
|
||||
| dataSource | Data source for autocomplete | [DataSourceItemType](https://git.io/vMMKF)\[] | - | |
|
||||
| dropdownMenuStyle | additional style applied to dropdown menu | object | | |
|
||||
| defaultActiveFirstOption | Whether active first option by default | boolean | true | |
|
||||
| defaultValue | Initial selected option. | string\|string\[] | - | |
|
||||
| disabled | Whether disabled select | boolean | false | |
|
||||
|
@ -31,6 +31,7 @@ export interface AutoCompleteProps extends Omit<AbstractSelectProps, 'loading'>
|
||||
value?: SelectValue;
|
||||
defaultValue?: SelectValue;
|
||||
dataSource?: DataSourceItemType[];
|
||||
dropdownMenuStyle?: React.CSSProperties;
|
||||
autoFocus?: boolean;
|
||||
backfill?: boolean;
|
||||
optionLabelProp?: string;
|
||||
|
@ -27,6 +27,7 @@ const dataSource = ['12345', '23456', '34567'];
|
||||
| children (自定义输入框) | 自定义输入框 | HTMLInputElement <br /><br /> HTMLTextAreaElement <br /><br /> `React.ReactElement<InputProps>` | `<Input />` | |
|
||||
| children (自动完成的数据源) | 自动完成的数据源 | `React.ReactElement<OptionProps>` <br /><br /> `Array<React.ReactElement<OptionProps>>` | - | |
|
||||
| dataSource | 自动完成的数据源 | [DataSourceItemType](https://git.io/vMMKF)\[] | | |
|
||||
| dropdownMenuStyle | dropdown 菜单自定义样式 | object | | |
|
||||
| defaultActiveFirstOption | 是否默认高亮第一个选项。 | boolean | true | |
|
||||
| defaultValue | 指定默认选中的条目 | string\|string\[]\| 无 | |
|
||||
| disabled | 是否禁用 | boolean | false | |
|
||||
|
@ -37,6 +37,7 @@
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,6 +188,17 @@ exports[`Button renders Chinese characters correctly 6`] = `
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`Button renders Chinese characters correctly 7`] = `
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
按 钮
|
||||
</span>
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`Button renders correctly 1`] = `
|
||||
<button
|
||||
class="ant-btn"
|
||||
@ -222,6 +233,17 @@ exports[`Button should merge text if children using variable 1`] = `
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`Button should not insert space to link button 1`] = `
|
||||
<button
|
||||
class="ant-btn ant-btn-link"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
按钮
|
||||
</span>
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`Button should not render as link button when href is undefined 1`] = `
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
@ -233,6 +255,23 @@ exports[`Button should not render as link button when href is undefined 1`] = `
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`Button should render empty button without errors 1`] = `
|
||||
<Button
|
||||
block={false}
|
||||
ghost={false}
|
||||
htmlType="button"
|
||||
loading={false}
|
||||
>
|
||||
<Wave>
|
||||
<button
|
||||
className="ant-btn"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
/>
|
||||
</Wave>
|
||||
</Button>
|
||||
`;
|
||||
|
||||
exports[`Button should support link button 1`] = `
|
||||
<a
|
||||
class="ant-btn"
|
||||
|
@ -4,10 +4,15 @@ import renderer from 'react-test-renderer';
|
||||
import Button from '..';
|
||||
import Icon from '../../icon';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
|
||||
describe('Button', () => {
|
||||
mountTest(Button);
|
||||
mountTest(() => <Button size="large" />);
|
||||
mountTest(() => <Button size="small" />);
|
||||
mountTest(Button.Group);
|
||||
mountTest(() => <Button.Group size="large" />);
|
||||
mountTest(() => <Button.Group size="small" />);
|
||||
|
||||
it('renders correctly', () => {
|
||||
const wrapper = render(<Button>Follow</Button>);
|
||||
@ -48,6 +53,14 @@ describe('Button', () => {
|
||||
// should insert space while loading
|
||||
const wrapper5 = render(<Button loading>按钮</Button>);
|
||||
expect(wrapper5).toMatchSnapshot();
|
||||
|
||||
// should insert space while only one nested element
|
||||
const wrapper6 = render(
|
||||
<Button>
|
||||
<span>按钮</span>
|
||||
</Button>,
|
||||
);
|
||||
expect(wrapper6).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders Chinese characters correctly in HOC', () => {
|
||||
@ -70,6 +83,22 @@ describe('Button', () => {
|
||||
expect(wrapper.find('.ant-btn').hasClass('ant-btn-two-chinese-chars')).toBe(true);
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/18118
|
||||
it('should not insert space to link button', () => {
|
||||
const wrapper = render(<Button type="link">按钮</Button>);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render empty button without errors', () => {
|
||||
const wrapper = mount(
|
||||
<Button>
|
||||
{null}
|
||||
{undefined}
|
||||
</Button>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('have static property for type detecting', () => {
|
||||
const wrapper = mount(<Button>Button Text</Button>);
|
||||
// eslint-disable-next-line
|
||||
@ -125,6 +154,17 @@ describe('Button', () => {
|
||||
expect(wrapper.hasClass('ant-btn-loading')).toBe(false);
|
||||
});
|
||||
|
||||
it('should not clickable when button is loading', () => {
|
||||
const onClick = jest.fn();
|
||||
const wrapper = mount(
|
||||
<Button loading onClick={onClick}>
|
||||
button
|
||||
</Button>,
|
||||
);
|
||||
wrapper.simulate('click');
|
||||
expect(onClick).not.toHaveBeenCalledWith();
|
||||
});
|
||||
|
||||
it('should support link button', () => {
|
||||
const wrapper = mount(
|
||||
<Button target="_blank" href="http://ant.design">
|
||||
@ -172,4 +212,27 @@ describe('Button', () => {
|
||||
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should support to change loading', async () => {
|
||||
const wrapper = mount(<Button>Button</Button>);
|
||||
wrapper.setProps({ loading: true });
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.ant-btn-loading').length).toBe(1);
|
||||
wrapper.setProps({ loading: false });
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.ant-btn-loading').length).toBe(0);
|
||||
wrapper.setProps({ loading: { delay: 50 } });
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.ant-btn-loading').length).toBe(0);
|
||||
await sleep(50);
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.ant-btn-loading').length).toBe(1);
|
||||
wrapper.setProps({ loading: false });
|
||||
await sleep(50);
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.ant-btn-loading').length).toBe(0);
|
||||
expect(() => {
|
||||
wrapper.unmount();
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
@ -134,16 +134,6 @@ class Button extends React.Component<ButtonProps, ButtonState> {
|
||||
title: PropTypes.string,
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps(nextProps: ButtonProps, prevState: ButtonState) {
|
||||
if (nextProps.loading instanceof Boolean) {
|
||||
return {
|
||||
...prevState,
|
||||
loading: nextProps.loading,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private delayTimeout: number;
|
||||
|
||||
private buttonNode: HTMLElement | null;
|
||||
@ -169,8 +159,10 @@ class Button extends React.Component<ButtonProps, ButtonState> {
|
||||
|
||||
const { loading } = this.props;
|
||||
if (loading && typeof loading !== 'boolean' && loading.delay) {
|
||||
this.delayTimeout = window.setTimeout(() => this.setState({ loading }), loading.delay);
|
||||
} else if (prevProps.loading !== this.props.loading) {
|
||||
this.delayTimeout = window.setTimeout(() => {
|
||||
this.setState({ loading });
|
||||
}, loading.delay);
|
||||
} else if (prevProps.loading !== loading) {
|
||||
// eslint-disable-next-line react/no-did-update-set-state
|
||||
this.setState({ loading });
|
||||
}
|
||||
@ -217,8 +209,8 @@ class Button extends React.Component<ButtonProps, ButtonState> {
|
||||
}
|
||||
|
||||
isNeedInserted() {
|
||||
const { icon, children } = this.props;
|
||||
return React.Children.count(children) === 1 && !icon;
|
||||
const { icon, children, type } = this.props;
|
||||
return React.Children.count(children) === 1 && !icon && type !== 'link';
|
||||
}
|
||||
|
||||
renderButton = ({ getPrefixCls, autoInsertSpaceInButton }: ConfigConsumerProps) => {
|
||||
@ -260,7 +252,7 @@ class Button extends React.Component<ButtonProps, ButtonState> {
|
||||
[`${prefixCls}-${shape}`]: shape,
|
||||
[`${prefixCls}-${sizeCls}`]: sizeCls,
|
||||
[`${prefixCls}-icon-only`]: !children && children !== 0 && iconType,
|
||||
[`${prefixCls}-loading`]: loading,
|
||||
[`${prefixCls}-loading`]: !!loading,
|
||||
[`${prefixCls}-background-ghost`]: ghost,
|
||||
[`${prefixCls}-two-chinese-chars`]: hasTwoCNChar && autoInsertSpace,
|
||||
[`${prefixCls}-block`]: block,
|
||||
|
@ -2,10 +2,16 @@ import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import ConfigProvider from '..';
|
||||
import LocaleProvider from '../../locale-provider';
|
||||
import locale from '../../locale/zh_CN';
|
||||
import zhCN from '../../locale/zh_CN';
|
||||
import enUS from '../../locale/en_US';
|
||||
import TimePicker from '../../time-picker';
|
||||
import Modal from '../../modal';
|
||||
|
||||
describe('ConfigProvider.Locale', () => {
|
||||
function $$(className) {
|
||||
return document.body.querySelectorAll(className);
|
||||
}
|
||||
|
||||
it('not throw', () => {
|
||||
if (process.env.REACT === '15') {
|
||||
return;
|
||||
@ -19,14 +25,54 @@ describe('ConfigProvider.Locale', () => {
|
||||
);
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/18731
|
||||
it('should not reset locale for Modal', () => {
|
||||
class App extends React.Component {
|
||||
state = {
|
||||
showButton: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({
|
||||
showButton: true,
|
||||
});
|
||||
}
|
||||
|
||||
openConfirm = () => {
|
||||
Modal.confirm({
|
||||
title: 'title',
|
||||
content: 'Some descriptions',
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ConfigProvider locale={zhCN}>
|
||||
{this.state.showButton ? (
|
||||
<ConfigProvider locale={enUS}>
|
||||
<button type="button" onClick={this.openConfirm}>
|
||||
open
|
||||
</button>
|
||||
</ConfigProvider>
|
||||
) : null}
|
||||
</ConfigProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const wrapper = mount(<App />);
|
||||
wrapper.find('button').simulate('click');
|
||||
expect($$('.ant-btn-primary')[0].textContent).toBe('OK');
|
||||
});
|
||||
|
||||
describe('support legacy LocaleProvider', () => {
|
||||
function testLocale(wrapper) {
|
||||
expect(wrapper.find('input').props().placeholder).toBe(locale.TimePicker.placeholder);
|
||||
expect(wrapper.find('input').props().placeholder).toBe(zhCN.TimePicker.placeholder);
|
||||
}
|
||||
|
||||
it('LocaleProvider', () => {
|
||||
const wrapper = mount(
|
||||
<LocaleProvider locale={locale}>
|
||||
<LocaleProvider locale={zhCN}>
|
||||
<TimePicker />
|
||||
</LocaleProvider>,
|
||||
);
|
||||
@ -36,7 +82,7 @@ describe('ConfigProvider.Locale', () => {
|
||||
|
||||
it('LocaleProvider > ConfigProvider', () => {
|
||||
const wrapper = mount(
|
||||
<LocaleProvider locale={locale}>
|
||||
<LocaleProvider locale={zhCN}>
|
||||
<ConfigProvider>
|
||||
<TimePicker />
|
||||
</ConfigProvider>
|
||||
@ -48,7 +94,7 @@ describe('ConfigProvider.Locale', () => {
|
||||
|
||||
it('ConfigProvider > ConfigProvider', () => {
|
||||
const wrapper = mount(
|
||||
<ConfigProvider locale={locale}>
|
||||
<ConfigProvider locale={zhCN}>
|
||||
<ConfigProvider>
|
||||
<TimePicker />
|
||||
</ConfigProvider>
|
||||
|
@ -32,4 +32,4 @@ cols: 1
|
||||
| label | 内容的描述 | ReactNode | - | 3.19.0 |
|
||||
| span | 包含列的数量 | number | 1 | 3.19.0 |
|
||||
|
||||
> span Description.Item 的数量。 span={2} 会占用两个 DescriptionItem 的宽度。
|
||||
> span 是 Description.Item 的数量。 span={2} 会占用两个 DescriptionItem 的宽度。
|
||||
|
@ -4151,20 +4151,16 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
|
||||
<span
|
||||
class="ant-form-item-children"
|
||||
>
|
||||
<div
|
||||
class="dropbox"
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="ant-upload ant-upload-drag"
|
||||
/>
|
||||
<div
|
||||
class="ant-upload-list ant-upload-list-text"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-upload ant-upload-drag"
|
||||
/>
|
||||
<div
|
||||
class="ant-upload-list ant-upload-list-text"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -178,20 +178,18 @@ class Demo extends React.Component {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Dragger">
|
||||
<div className="dropbox">
|
||||
{getFieldDecorator('dragger', {
|
||||
valuePropName: 'fileList',
|
||||
getValueFromEvent: this.normFile,
|
||||
})(
|
||||
<Upload.Dragger name="files" action="/upload.do">
|
||||
<p className="ant-upload-drag-icon">
|
||||
<Icon type="inbox" />
|
||||
</p>
|
||||
<p className="ant-upload-text">Click or drag file to this area to upload</p>
|
||||
<p className="ant-upload-hint">Support for a single or bulk upload.</p>
|
||||
</Upload.Dragger>,
|
||||
)}
|
||||
</div>
|
||||
{getFieldDecorator('dragger', {
|
||||
valuePropName: 'fileList',
|
||||
getValueFromEvent: this.normFile,
|
||||
})(
|
||||
<Upload.Dragger name="files" action="/upload.do">
|
||||
<p className="ant-upload-drag-icon">
|
||||
<Icon type="inbox" />
|
||||
</p>
|
||||
<p className="ant-upload-text">Click or drag file to this area to upload</p>
|
||||
<p className="ant-upload-hint">Support for a single or bulk upload.</p>
|
||||
</Upload.Dragger>,
|
||||
)}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item wrapperCol={{ span: 12, offset: 6 }}>
|
||||
@ -208,10 +206,3 @@ const WrappedDemo = Form.create({ name: 'validate_other' })(Demo);
|
||||
|
||||
ReactDOM.render(<WrappedDemo />, mountNode);
|
||||
```
|
||||
|
||||
```css
|
||||
#components-form-demo-validate-other .dropbox {
|
||||
height: 180px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
```
|
||||
|
@ -43,7 +43,7 @@ A form consists of one or more form fields whose type includes input, textarea,
|
||||
| layout | Define form layout | 'horizontal'\|'vertical'\|'inline' | 'horizontal' | |
|
||||
| onSubmit | Defines a function will be called if form data validation is successful. | Function(e:Event) | | |
|
||||
| wrapperCol | (Added in 3.14.0. Previous version can only set on FormItem.) The layout for input controls, same as `labelCol` | [object](https://ant.design/components/grid/#Col) | | 3.14.0 |
|
||||
| colon | change default props colon value of Form.Item | boolean | true | 3.15.0 |
|
||||
| colon | change default props colon value of Form.Item (only effective when prop layout is horizontal) | boolean | true | 3.15.0 |
|
||||
|
||||
### Form.create(options)
|
||||
|
||||
|
@ -46,7 +46,7 @@ title: Form
|
||||
| layout | 表单布局 | 'horizontal'\|'vertical'\|'inline' | 'horizontal' | |
|
||||
| onSubmit | 数据验证成功后回调事件 | Function(e:Event) | | |
|
||||
| wrapperCol | (3.14.0 新增,之前的版本只能设置到 FormItem 上。)需要为输入控件设置布局样式时,使用该属性,用法同 labelCol | [object](https://ant.design/components/grid-cn/#Col) | | 3.14.0 |
|
||||
| colon | 配置 Form.Item 的 colon 的默认值 | boolean | true | 3.15.0 |
|
||||
| colon | 配置 Form.Item 的 colon 的默认值 (只有在属性 layout 为 horizontal 时有效) | boolean | true | 3.15.0 |
|
||||
|
||||
### Form.create(options)
|
||||
|
||||
|
@ -141,6 +141,7 @@
|
||||
|
||||
&-handler-up {
|
||||
cursor: pointer;
|
||||
border-top-right-radius: @border-radius-base;
|
||||
&-inner {
|
||||
top: 50%;
|
||||
margin-top: -5px;
|
||||
@ -154,6 +155,7 @@
|
||||
&-handler-down {
|
||||
top: 0;
|
||||
border-top: @border-width-base @border-style-base @border-color-base;
|
||||
border-bottom-right-radius: @border-radius-base;
|
||||
cursor: pointer;
|
||||
&-inner {
|
||||
top: 50%;
|
||||
|
@ -9,7 +9,10 @@ export interface SearchProps extends InputProps {
|
||||
inputPrefixCls?: string;
|
||||
onSearch?: (
|
||||
value: string,
|
||||
event?: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLInputElement>,
|
||||
event?:
|
||||
| React.ChangeEvent<HTMLInputElement>
|
||||
| React.MouseEvent<HTMLElement>
|
||||
| React.KeyboardEvent<HTMLInputElement>,
|
||||
) => void;
|
||||
enterButton?: React.ReactNode;
|
||||
loading?: boolean;
|
||||
@ -26,6 +29,16 @@ export default class Search extends React.Component<SearchProps, any> {
|
||||
this.input = node;
|
||||
};
|
||||
|
||||
onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { onChange, onSearch } = this.props;
|
||||
if (e && e.target && e.type === 'click' && onSearch) {
|
||||
onSearch((e as React.ChangeEvent<HTMLInputElement>).target.value, e);
|
||||
}
|
||||
if (onChange) {
|
||||
onChange(e);
|
||||
}
|
||||
};
|
||||
|
||||
onSearch = (e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLInputElement>) => {
|
||||
const { onSearch, loading } = this.props;
|
||||
|
||||
@ -168,6 +181,7 @@ export default class Search extends React.Component<SearchProps, any> {
|
||||
prefixCls={inputPrefixCls}
|
||||
addonAfter={this.renderAddonAfter(prefixCls)}
|
||||
suffix={this.renderSuffix(prefixCls)}
|
||||
onChange={this.onChange}
|
||||
ref={this.saveInput}
|
||||
className={inputClassName}
|
||||
/>
|
||||
|
@ -138,6 +138,21 @@ describe('Input.Search', () => {
|
||||
expect(wrapperWithEnterButton.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/18729
|
||||
it('should trigger onSearch when click clear icon', () => {
|
||||
const onSearch = jest.fn();
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mount(
|
||||
<Search allowClear defaultValue="value" onSearch={onSearch} onChange={onChange} />,
|
||||
);
|
||||
wrapper
|
||||
.find('.ant-input-clear-icon')
|
||||
.at(0)
|
||||
.simulate('click');
|
||||
expect(onSearch).toHaveBeenLastCalledWith('', expect.anything());
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should support loading', () => {
|
||||
const wrapper = mount(<Search loading />);
|
||||
const wrapperWithEnterButton = mount(<Search loading enterButton />);
|
||||
|
@ -253,6 +253,7 @@ exports[`Input.Search should support suffix 1`] = `
|
||||
>
|
||||
<Input
|
||||
className="ant-input-search"
|
||||
onChange={[Function]}
|
||||
onPressEnter={[Function]}
|
||||
prefixCls="ant-input"
|
||||
suffix={
|
||||
|
@ -73,8 +73,8 @@ export default class LocaleProvider extends React.Component<LocaleProviderProps,
|
||||
const { locale } = this.props;
|
||||
if (prevProps.locale !== locale) {
|
||||
setMomentLocale(locale);
|
||||
changeConfirmLocale(locale && locale.Modal);
|
||||
}
|
||||
changeConfirmLocale(locale && locale.Modal);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -65,7 +65,7 @@ The items listed above are all functions, expecting a settings object as paramet
|
||||
| className | className of container | string | - | 3.1.1 |
|
||||
| content | Content | string\|ReactNode | - | |
|
||||
| icon | custom icon (`Added in 3.12.0`) | string\|ReactNode | `<Icon type="question-circle">` | 3.12.0 |
|
||||
| iconType | Icon `type` of the Icon component (deperated after `3.12.0`) | string | `question-circle` | |
|
||||
| iconType | Icon `type` of the Icon component (deprecated after `3.12.0`) | string | `question-circle` | |
|
||||
| keyboard | Whether support press esc to close | Boolean | true | 3.4.2 |
|
||||
| mask | Whether show mask or not. | Boolean | true | 3.13.0 |
|
||||
| maskClosable | Whether to close the modal dialog when the mask (area outside the modal) is clicked | Boolean | `false` | |
|
||||
|
@ -25,5 +25,3 @@ It can also be used as inter-page navigation when it is needed to make the user
|
||||
| breadcrumb | breadcrumb config | [breadcrumb](https://ant.design/components/breadcrumb-cn/) | - | 3.14.0 |
|
||||
| footer | PageHeader's footer, generally used to render TabBar | ReactNode | - | 3.14.0 |
|
||||
| onBack | back icon click event | `()=>void` | `()=>history.back()` | 3.14.0 |
|
||||
|
||||
> breadcrumbs will automatically disappear when configuring back icon.
|
||||
|
@ -25,5 +25,3 @@ subtitle: 页头
|
||||
| breadcrumb | 面包屑的配置 | [breadcrumb](https://ant.design/components/breadcrumb-cn/) | - | 3.14.0 |
|
||||
| footer | PageHeader 的页脚,一般用于渲染 TabBar | ReactNode | - | 3.14.0 |
|
||||
| onBack | 返回按钮的点击事件 | `()=>void` | `()=>history.back()` | 3.14.0 |
|
||||
|
||||
> 配置返回按钮时,breadcrumb 会自动隐藏。
|
||||
|
@ -33,6 +33,7 @@ Select component to select value from options.
|
||||
| dropdownMatchSelectWidth | Whether dropdown's width is same with select. | boolean | true | |
|
||||
| dropdownRender | Customize dropdown content | (menuNode: ReactNode, props) => ReactNode | - | 3.11.0 |
|
||||
| dropdownStyle | style of dropdown menu | object | - | |
|
||||
| dropdownMenuStyle | additional style applied to dropdown menu | object | - | |
|
||||
| filterOption | If true, filter options by input, if function, filter options against it. The function will receive two arguments, `inputValue` and `option`, if the function returns `true`, the option will be included in the filtered set; Otherwise, it will be excluded. | boolean or function(inputValue, option) | true | |
|
||||
| firstActiveValue | Value of action option by default | string\|string\[] | - | |
|
||||
| getPopupContainer | Parent Node which the selector should be rendered to. Default to `body`. When position issues happen, try to modify it into scrollable content and position it relative. [Example](https://codesandbox.io/s/4j168r7jw0) | function(triggerNode) | () => document.body | |
|
||||
|
@ -34,6 +34,7 @@ title: Select
|
||||
| dropdownMatchSelectWidth | 下拉菜单和选择器同宽 | boolean | true | |
|
||||
| dropdownRender | 自定义下拉框内容 | (menuNode: ReactNode, props) => ReactNode | - | 3.11.0 |
|
||||
| dropdownStyle | 下拉菜单的 style 属性 | object | - | |
|
||||
| dropdownMenuStyle | dropdown 菜单自定义样式 | object | - | |
|
||||
| filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。 | boolean or function(inputValue, option) | true | |
|
||||
| firstActiveValue | 默认高亮的选项 | string\|string\[] | - | |
|
||||
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。[示例](https://codesandbox.io/s/4j168r7jw0) | Function(triggerNode) | () => document.body | |
|
||||
|
@ -143,7 +143,7 @@ const columns = [
|
||||
| sorter | 排序函数,本地排序使用一个函数(参考 [Array.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) 的 compareFunction),需要服务端排序可设为 true | Function\|boolean | - | |
|
||||
| sortOrder | 排序的受控属性,外界可用此控制列的排序,可设置为 `'ascend'` `'descend'` `false` | boolean\|string | - | |
|
||||
| sortDirections | 支持的排序方式,取值为 `'ascend'` `'descend'` | Array | `['ascend', 'descend']` | 3.15.2 |
|
||||
| title | 列头显示文字 | ReactNode\|({ sortOrder, filters }) => ReactNode | - | |
|
||||
| title | 列头显示文字(函数用法 `3.10.0` 后支持) | ReactNode\|({ sortOrder, filters }) => ReactNode | - | |
|
||||
| width | 列宽度([指定了也不生效?](https://github.com/ant-design/ant-design/issues/13825#issuecomment-449889241)) | string\|number | - | |
|
||||
| onCell | 设置单元格属性 | Function(record, rowIndex) | - | |
|
||||
| onFilter | 本地模式下,确定筛选的运行函数 | Function | - | |
|
||||
|
@ -24,19 +24,19 @@ One or more elements can be selected from either column, one click on the proper
|
||||
| dataSource | Used for setting the source data. The elements that are part of this array will be present the left column. Except the elements whose keys are included in `targetKeys` prop. | [TransferItem](https://git.io/vMM64)\[] | \[] | |
|
||||
| disabled | Whether disabled transfer | boolean | false | 3.10.0 |
|
||||
| filterOption | A function to determine whether an item should show in search result list | (inputValue, option): boolean | | |
|
||||
| footer | A function used for rendering the footer. | (props): ReactNode | | |
|
||||
| footer | A function used for rendering the footer. | (props) => ReactNode | | |
|
||||
| lazy | property of [react-lazy-load](https://github.com/loktar00/react-lazy-load) for lazy rendering items. Turn off it by set to `false`. | object\|boolean | `{ height: 32, offset: 32 }` | |
|
||||
| listStyle | A custom CSS style used for rendering the transfer columns. | object | | |
|
||||
| locale | i18n text including filter, empty text, item unit, etc | { itemUnit: string; itemsUnit: string; searchPlaceholder: string; notFoundContent: ReactNode; } | `{ itemUnit: 'item', itemsUnit: 'items', notFoundContent: 'The list is empty', searchPlaceholder: 'Search here' }` | 3.9.0 |
|
||||
| operations | A set of operations that are sorted from top to bottom. | string\[] | \['>', '<'] | |
|
||||
| operationStyle | A custom CSS style used for rendering the operations column. | object | | 3.6.0 |
|
||||
| render | The function to generate the item shown on a column. Based on an record (element of the dataSource array), this function should return a React element which is generated from that record. Also, it can return a plain object with `value` and `label`, `label` is a React element and `value` is for title | Function(record) | | |
|
||||
| render | The function to generate the item shown on a column. Based on an record (element of the dataSource array), this function should return a React element which is generated from that record. Also, it can return a plain object with `value` and `label`, `label` is a React element and `value` is for title | (record) => ReactNode | | |
|
||||
| selectedKeys | A set of keys of selected items. | string\[] | \[] | |
|
||||
| showSearch | If included, a search box is shown on each column. | boolean | false | |
|
||||
| showSelectAll | Show select all checkbox on the header | boolean | true | 3.18.0 |
|
||||
| style | A custom CSS style used for rendering wrapper element. | object | | 3.6.0 |
|
||||
| targetKeys | A set of keys of elements that are listed on the right column. | string\[] | \[] | |
|
||||
| titles | A set of titles that are sorted from left to right. | string\[] | - | |
|
||||
| titles | A set of titles that are sorted from left to right. | ReactNode\[] | - | |
|
||||
| onChange | A callback function that is executed when the transfer between columns is complete. | (targetKeys, direction, moveKeys): void | | |
|
||||
| onScroll | A callback function which is executed when scroll options list | (direction, event): void | | |
|
||||
| onSearch | A callback function which is executed when search field are changed | (direction: 'left'\|'right', value: string): void | - | 3.11.0 |
|
||||
|
@ -27,18 +27,18 @@ title: Transfer
|
||||
| dataSource | 数据源,其中的数据将会被渲染到左边一栏中,`targetKeys` 中指定的除外。 | [TransferItem](https://git.io/vMM64)\[] | \[] | |
|
||||
| disabled | 是否禁用 | boolean | false | 3.10.0 |
|
||||
| filterOption | 接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。 | | (inputValue, option): boolean | | |
|
||||
| footer | 底部渲染函数 | (props): ReactNode | | |
|
||||
| footer | 底部渲染函数 | (props) => ReactNode | | |
|
||||
| lazy | Transfer 使用了 [react-lazy-load](https://github.com/loktar00/react-lazy-load) 优化性能,这里可以设置相关参数。设为 `false` 可以关闭懒加载。 | object\|boolean | `{ height: 32, offset: 32 }` | |
|
||||
| listStyle | 两个穿梭框的自定义样式 | object | | |
|
||||
| locale | 各种语言 | { itemUnit: string; itemsUnit: string; searchPlaceholder: string; notFoundContent: ReactNode; } | `{ itemUnit: '项', itemsUnit: '项', searchPlaceholder: '请输入搜索内容' }` | 3.9.0 |
|
||||
| operations | 操作文案集合,顺序从上至下 | string\[] | \['>', '<'] | |
|
||||
| render | 每行数据渲染函数,该函数的入参为 `dataSource` 中的项,返回值为 ReactElement。或者返回一个普通对象,其中 `label` 字段为 ReactElement,`value` 字段为 title | Function(record) | | |
|
||||
| render | 每行数据渲染函数,该函数的入参为 `dataSource` 中的项,返回值为 ReactElement。或者返回一个普通对象,其中 `label` 字段为 ReactElement,`value` 字段为 title | (record) => ReactNode | | |
|
||||
| selectedKeys | 设置哪些项应该被选中 | string\[] | \[] | |
|
||||
| showSearch | 是否显示搜索框 | boolean | false | |
|
||||
| showSelectAll | 是否展示全选勾选框 | boolean | true | 3.18.0 |
|
||||
| style | 容器的自定义样式 | object | | 3.6.0 |
|
||||
| targetKeys | 显示在右侧框数据的 key 集合 | string\[] | \[] | |
|
||||
| titles | 标题集合,顺序从左至右 | string\[] | \['', ''] | |
|
||||
| titles | 标题集合,顺序从左至右 | ReactNode\[] | \['', ''] | |
|
||||
| onChange | 选项在两栏之间转移时的回调函数 | (targetKeys, direction, moveKeys): void | | |
|
||||
| onScroll | 选项列表滚动时的回调函数 | (direction, event): void | | |
|
||||
| onSearch | 搜索框内容时改变时的回调函数 | (direction: 'left'\|'right', value: string): void | - | 3.11.0 |
|
||||
|
@ -154,6 +154,8 @@ export interface TreeProps {
|
||||
onDragOver?: (options: AntTreeNodeMouseEvent) => void;
|
||||
onDragLeave?: (options: AntTreeNodeMouseEvent) => void;
|
||||
onDragEnd?: (options: AntTreeNodeMouseEvent) => void;
|
||||
onMouseEnter?: (options: AntTreeNodeMouseEvent) => void;
|
||||
onMouseLeave?: (options: AntTreeNodeMouseEvent) => void;
|
||||
onDrop?: (options: AntTreeNodeDropEvent) => void;
|
||||
style?: React.CSSProperties;
|
||||
showIcon?: boolean;
|
||||
|
@ -33,6 +33,7 @@ Almost anything can be represented in a tree structure. Examples include directo
|
||||
| loadData | Load data asynchronously | function(node) | - | |
|
||||
| loadedKeys | (Controlled) Set loaded tree nodes. Need work with `loadData` | string\[] | \[] | 3.7.0 |
|
||||
| multiple | Allows selecting multiple treeNodes | boolean | false | |
|
||||
| selectable | whether can be selected | boolean | true | |
|
||||
| selectedKeys | (Controlled) Specifies the keys of the selected treeNodes | string\[] | - | |
|
||||
| showIcon | Shows the icon before a TreeNode's title. There is no default style; you must set a custom style for it if set to `true` | boolean | false | |
|
||||
| switcherIcon | customize collapse/expand icon of tree node | React.ReactElement | - | 3.12.0 |
|
||||
|
@ -34,6 +34,7 @@ subtitle: 树形控件
|
||||
| loadData | 异步加载数据 | function(node) | - | |
|
||||
| loadedKeys | (受控)已经加载的节点,需要配合 `loadData` 使用 | string\[] | \[] | 3.7.0 |
|
||||
| multiple | 支持点选多个节点(节点本身) | boolean | false | |
|
||||
| selectable | 是否可选中 | boolean | true | |
|
||||
| selectedKeys | (受控)设置选中的树节点 | string\[] | - | |
|
||||
| showIcon | 是否展示 TreeNode title 前的图标,没有默认样式,如设置为 true,需要自行定义图标相关样式 | boolean | false | |
|
||||
| switcherIcon | 自定义树节点的展开/折叠图标 | React.ReactElement | - | 3.12.0 |
|
||||
|
@ -26,5 +26,5 @@ The complete design pattern will include examples of templates, components (ETC)
|
||||
We work with engineers to transform design patterns into reusable code that maximizes your productivity and communication efficiency.
|
||||
|
||||
- [Ant Design Pro](https://pro.ant.design): Out-of-the-box solution with 20+ templates and 10+ business components
|
||||
- [Ant Design Components](https://ant.design/docs/react/introduce): Ant Design's React implementation is a global component library with 50+ base components
|
||||
- [Ant Design Components](https://ant.design/docs/react/introduce): Ant Design's React UI library is a global component library with 50+ base components
|
||||
- [Ant Design Library](http://library.ant.design/): Axure resource packs are included with the code to make your prototype look like a visual draft, including templates, components, and more.
|
||||
|
162
package.json
162
package.json
@ -1,46 +1,91 @@
|
||||
{
|
||||
"name": "antd",
|
||||
"version": "3.23.2",
|
||||
"title": "Ant Design",
|
||||
"description": "An enterprise-class UI design language and React components implementation",
|
||||
"homepage": "http://ant.design/",
|
||||
"keywords": [
|
||||
"ant",
|
||||
"design",
|
||||
"react",
|
||||
"react-component",
|
||||
"component",
|
||||
"components",
|
||||
"ui",
|
||||
"design",
|
||||
"framework",
|
||||
"frontend"
|
||||
"frontend",
|
||||
"react",
|
||||
"react-component",
|
||||
"ui"
|
||||
],
|
||||
"contributors": [
|
||||
"ant"
|
||||
],
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
"homepage": "http://ant.design/",
|
||||
"bugs": {
|
||||
"url": "https://github.com/ant-design/ant-design/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ant-design/ant-design"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/ant-design/ant-design/issues"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
"license": "MIT",
|
||||
"contributors": [
|
||||
"ant"
|
||||
],
|
||||
"files": [
|
||||
"dist",
|
||||
"lib",
|
||||
"es"
|
||||
],
|
||||
"sideEffects": [
|
||||
"dist/*",
|
||||
"es/**/style/*",
|
||||
"lib/**/style/*",
|
||||
"*.less"
|
||||
],
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
"typings": "lib/index.d.ts",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.0.0",
|
||||
"react-dom": ">=16.0.0"
|
||||
"scripts": {
|
||||
"api-collection": "antd-tools run api-collection",
|
||||
"authors": "git log --format='%aN <%aE>' | sort -u | grep -v 'users.noreply.github.com' | grep -v 'gitter.im' | grep -v '.local>' | grep -v 'alibaba-inc.com' | grep -v 'alipay.com' | grep -v 'taobao.com' > AUTHORS.txt",
|
||||
"bundlesize": "bundlesize",
|
||||
"check-commit": "node ./scripts/check-commit.js",
|
||||
"compile": "antd-tools run compile",
|
||||
"predeploy": "antd-tools run clean && npm run site && cp netlify.toml CNAME _site && cp .circleci/config.yml _site",
|
||||
"deploy": "bisheng gh-pages --push-only",
|
||||
"deploy:china-mirror": "git checkout gh-pages && git pull origin gh-pages && git push git@gitee.com:ant-design/ant-design.git gh-pages",
|
||||
"dist": "antd-tools run dist",
|
||||
"lint": "npm run lint:tsc && npm run lint:script && npm run lint:demo && npm run lint:style && npm run lint:deps",
|
||||
"lint-fix": "npm run lint-fix:script && npm run lint-fix:demo && npm run lint-fix:style",
|
||||
"lint-fix:demo": "eslint-tinker ./components/*/demo/*.md",
|
||||
"lint-fix:script": "npm run lint:script -- --fix",
|
||||
"lint-fix:style": "npm run lint:style -- --fix",
|
||||
"lint:demo": "cross-env RUN_ENV=DEMO eslint components/*/demo/*.md --ext '.md'",
|
||||
"lint:deps": "antd-tools run deps-lint",
|
||||
"lint:md": "remark components/",
|
||||
"lint:script": "eslint . --ext '.js,.jsx,.ts,.tsx'",
|
||||
"lint:style": "stylelint '{site,components}/**/*.less' --syntax less",
|
||||
"lint:tsc": "npm run tsc",
|
||||
"pre-publish": "npm run check-commit && npm run test-all",
|
||||
"prettier": "prettier -c --write '**/*'",
|
||||
"pretty-quick": "pretty-quick",
|
||||
"pub": "antd-tools run pub",
|
||||
"prepublish": "antd-tools run guard",
|
||||
"site": "cross-env NODE_ICU_DATA=node_modules/full-icu bisheng build --ssr -c ./site/bisheng.config.js && node ./scripts/generateColorLess.js",
|
||||
"sort": "npx sort-package-json",
|
||||
"sort-api": "antd-tools run sort-api-table",
|
||||
"start": "rimraf _site && mkdir _site && node ./scripts/generateColorLess.js && cross-env NODE_ENV=development bisheng start -c ./site/bisheng.config.js",
|
||||
"start:preact": "node ./scripts/generateColorLess.js && cross-env NODE_ENV=development REACT_ENV=preact bisheng start -c ./site/bisheng.config.js",
|
||||
"test": "jest --config .jest.js --no-cache",
|
||||
"test-all": "./scripts/test-all.sh",
|
||||
"test-node": "jest --config .jest.node.js --no-cache",
|
||||
"tsc": "tsc"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "pretty-quick --staged"
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"last 2 version",
|
||||
"Firefox ESR",
|
||||
"> 1%",
|
||||
"ie >= 9"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ant-design/create-react-context": "^0.2.4",
|
||||
"@ant-design/icons": "~2.1.1",
|
||||
@ -112,7 +157,7 @@
|
||||
"antd-theme-generator": "^1.1.6",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-plugin-add-react-displayname": "^0.0.5",
|
||||
"bisheng": "^1.3.0",
|
||||
"bisheng": "^1.3.1-alpha.0",
|
||||
"bisheng-plugin-antd": "^1.0.2",
|
||||
"bisheng-plugin-description": "^0.1.4",
|
||||
"bisheng-plugin-react": "^1.0.0",
|
||||
@ -138,7 +183,6 @@
|
||||
"eslint-plugin-react": "^7.14.2",
|
||||
"eslint-tinker": "^0.5.0",
|
||||
"fetch-jsonp": "^1.1.3",
|
||||
"fs-extra": "^8.1.0",
|
||||
"full-icu": "^1.3.0",
|
||||
"glob": "^7.1.4",
|
||||
"husky": "^3.0.2",
|
||||
@ -165,7 +209,6 @@
|
||||
"react-copy-to-clipboard": "^5.0.1",
|
||||
"react-dnd": "^9.0.0",
|
||||
"react-dnd-html5-backend": "^9.0.0",
|
||||
"react-document-title": "^2.0.3",
|
||||
"react-dom": "^16.5.2",
|
||||
"react-github-button": "^0.1.11",
|
||||
"react-helmet": "^6.0.0-beta",
|
||||
@ -193,63 +236,22 @@
|
||||
"xhr2": "^0.2.0",
|
||||
"yaml-front-matter": "^4.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest --config .jest.js --no-cache",
|
||||
"test-node": "jest --config .jest.node.js --no-cache",
|
||||
"test-all": "./scripts/test-all.sh",
|
||||
"check-commit": "node ./scripts/check-commit.js",
|
||||
"lint": "npm run lint:tsc && npm run lint:script && npm run lint:demo && npm run lint:style && npm run lint:deps",
|
||||
"lint:deps": "antd-tools run deps-lint",
|
||||
"lint:tsc": "npm run tsc",
|
||||
"lint:script": "eslint . --ext '.js,.jsx,.ts,.tsx'",
|
||||
"lint:md": "remark components/",
|
||||
"lint:demo": "cross-env RUN_ENV=DEMO eslint components/*/demo/*.md --ext '.md'",
|
||||
"lint:style": "stylelint '{site,components}/**/*.less' --syntax less",
|
||||
"lint-fix": "npm run lint-fix:script && npm run lint-fix:demo && npm run lint-fix:style",
|
||||
"lint-fix:script": "npm run lint:script -- --fix",
|
||||
"lint-fix:demo": "eslint-tinker ./components/*/demo/*.md",
|
||||
"lint-fix:style": "npm run lint:style -- --fix",
|
||||
"sort-api": "antd-tools run sort-api-table",
|
||||
"api-collection": "antd-tools run api-collection",
|
||||
"dist": "antd-tools run dist",
|
||||
"bundlesize": "bundlesize",
|
||||
"compile": "antd-tools run compile",
|
||||
"tsc": "tsc",
|
||||
"start": "rimraf _site && mkdir _site && node ./scripts/generateColorLess.js && cross-env NODE_ENV=development bisheng start -c ./site/bisheng.config.js",
|
||||
"start:preact": "node ./scripts/generateColorLess.js && cross-env NODE_ENV=development REACT_ENV=preact bisheng start -c ./site/bisheng.config.js",
|
||||
"site": "cross-env NODE_ICU_DATA=node_modules/full-icu bisheng build --ssr -c ./site/bisheng.config.js && node ./scripts/generateColorLess.js",
|
||||
"predeploy": "antd-tools run clean && npm run site && cp netlify.toml CNAME _site && cp .circleci/config.yml _site",
|
||||
"deploy": "bisheng gh-pages --push-only",
|
||||
"deploy:china-mirror": "git checkout gh-pages && git pull origin gh-pages && git push git@gitee.com:ant-design/ant-design.git gh-pages",
|
||||
"pub": "antd-tools run pub",
|
||||
"prepublish": "antd-tools run guard",
|
||||
"pre-publish": "npm run check-commit && npm run test-all",
|
||||
"authors": "git log --format='%aN <%aE>' | sort -u | grep -v 'users.noreply.github.com' | grep -v 'gitter.im' | grep -v '.local>' | grep -v 'alibaba-inc.com' | grep -v 'alipay.com' | grep -v 'taobao.com' > AUTHORS.txt",
|
||||
"prettier": "prettier -c --write '**/*'",
|
||||
"pretty-quick": "pretty-quick"
|
||||
"peerDependencies": {
|
||||
"react": ">=16.0.0",
|
||||
"react-dom": ">=16.0.0"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "pretty-quick --staged"
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"bundlesize": [
|
||||
{
|
||||
"path": "./dist/antd.min.js",
|
||||
"maxSize": "540 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/antd.min.css",
|
||||
"maxSize": "60 kB"
|
||||
}
|
||||
},
|
||||
"sideEffects": [
|
||||
"dist/*",
|
||||
"es/**/style/*",
|
||||
"lib/**/style/*",
|
||||
"*.less"
|
||||
],
|
||||
"browserslist": [
|
||||
"last 2 version",
|
||||
"Firefox ESR",
|
||||
"> 1%",
|
||||
"ie >= 9"
|
||||
],
|
||||
"bundlesize": [{
|
||||
"path": "./dist/antd.min.js",
|
||||
"maxSize": "540 kB"
|
||||
}, {
|
||||
"path": "./dist/antd.min.css",
|
||||
"maxSize": "60 kB"
|
||||
}]
|
||||
"title": "Ant Design"
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
const path = require('path');
|
||||
const yfm = require('yaml-front-matter');
|
||||
const glob = require('glob');
|
||||
const fs = require('fs-extra');
|
||||
const fs = require('fs');
|
||||
|
||||
const demoFiles = glob.sync(path.join(process.cwd(), 'components/**/demo/*.md'));
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
|
@ -31,7 +31,7 @@ module.exports = {
|
||||
'app.home.design-language': 'Design Language',
|
||||
'app.home.solution': 'Solution',
|
||||
'app.home.components-explain':
|
||||
'Based on the Ant Design language, we have provided a suite of out-of-the-box with high quality for developing and serving enterprise background applications, including the official React implementation and Angular, Vue implementations',
|
||||
'Based on the Ant Design language, we have provided a suite of out-of-the-box with high quality for developing and serving enterprise background applications, including the official React UI library and Angular, Vue implementations',
|
||||
'app.home.product-pro-slogan': 'Out-of-the-box front-end / Design solution',
|
||||
'app.home.product-mobile-slogan':
|
||||
"antd-mobile is the implementation of Ant Design's mobile specification",
|
||||
|
@ -1,14 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html {{ htmlAttributes | safe }}>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta
|
||||
name="description"
|
||||
content="An enterprise-class UI design language and React implementation with a set of high-quality React components, one of best React UI library for enterprises"
|
||||
/>
|
||||
<title>{% if title %}{{ title }}{% else %}Ant Design - A UI Design Language{% endif %}</title>
|
||||
<title>{% if title %}{{ title }}{% else %}{% endif %}</title>
|
||||
{% if meta %}{{ meta | safe }}{% endif %}
|
||||
<link
|
||||
rel="icon"
|
||||
href="https://gw.alipayobjects.com/zos/rmsportal/rlpTLlbMzTNYuZGGCVYM.png"
|
||||
|
@ -1,9 +1,10 @@
|
||||
import React, { Children, cloneElement } from 'react';
|
||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||
import DocumentTitle from 'react-document-title';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { getChildren } from 'jsonml.js/lib/utils';
|
||||
import { Timeline, Alert, Affix } from 'antd';
|
||||
import EditButton from './EditButton';
|
||||
import { getMetaDescription } from '../utils';
|
||||
|
||||
class Article extends React.Component {
|
||||
shouldComponentUpdate(nextProps) {
|
||||
@ -64,62 +65,69 @@ class Article extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { content, intl: { locale }, utils } = this.props;
|
||||
const {
|
||||
content,
|
||||
intl: { locale },
|
||||
utils,
|
||||
} = this.props;
|
||||
const { meta, description } = content;
|
||||
const { title, subtitle, filename } = meta;
|
||||
const isNotTranslated = locale === 'en-US' && typeof title === 'object';
|
||||
const helmetTitle = `${title[locale] || title} - Ant Design`;
|
||||
const helmetDesc = getMetaDescription(description);
|
||||
const contentChild = getMetaDescription(getChildren(content.content));
|
||||
const metaDesc = helmetDesc || contentChild;
|
||||
|
||||
return (
|
||||
<DocumentTitle title={`${title[locale] || title} - Ant Design`}>
|
||||
{/* eslint-disable-next-line */}
|
||||
<article className="markdown" onClick={this.onResourceClick}>
|
||||
{isNotTranslated && (
|
||||
<Alert
|
||||
type="warning"
|
||||
message={
|
||||
<span>
|
||||
This article has not been translated yet. Wanna help us out?
|
||||
<a href="https://github.com/ant-design/ant-design/issues/1471">
|
||||
See this issue on GitHub.
|
||||
</a>
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<h1>
|
||||
{title[locale] || title}
|
||||
{!subtitle || locale === 'en-US' ? null : <span className="subtitle">{subtitle}</span>}
|
||||
<EditButton
|
||||
title={<FormattedMessage id="app.content.edit-page" />}
|
||||
filename={filename}
|
||||
/>
|
||||
</h1>
|
||||
{!description
|
||||
? null
|
||||
: utils.toReactComponent(
|
||||
['section', { className: 'markdown' }].concat(getChildren(description)),
|
||||
)}
|
||||
{!content.toc || content.toc.length <= 1 || meta.toc === false ? null : (
|
||||
<Affix className="toc-affix" offsetTop={16}>
|
||||
{utils.toReactComponent(
|
||||
['ul', { className: 'toc' }].concat(getChildren(content.toc)),
|
||||
)}
|
||||
</Affix>
|
||||
)}
|
||||
{this.getArticle(
|
||||
utils.toReactComponent(
|
||||
['section', { className: 'markdown' }].concat(getChildren(content.content)),
|
||||
),
|
||||
)}
|
||||
{utils.toReactComponent(
|
||||
[
|
||||
'section',
|
||||
{
|
||||
className: 'markdown api-container',
|
||||
},
|
||||
].concat(getChildren(content.api || ['placeholder'])),
|
||||
)}
|
||||
</article>
|
||||
</DocumentTitle>
|
||||
/* eslint-disable-next-line */
|
||||
<article className="markdown" onClick={this.onResourceClick}>
|
||||
<Helmet>
|
||||
{helmetTitle && <title>{helmetTitle}</title>}
|
||||
{helmetTitle && <meta property="og:title" content={helmetTitle} />}
|
||||
{metaDesc && <meta name="description" content={metaDesc} />}
|
||||
</Helmet>
|
||||
{isNotTranslated && (
|
||||
<Alert
|
||||
type="warning"
|
||||
message={
|
||||
<span>
|
||||
This article has not been translated yet. Wanna help us out?
|
||||
<a href="https://github.com/ant-design/ant-design/issues/1471">
|
||||
See this issue on GitHub.
|
||||
</a>
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<h1>
|
||||
{title[locale] || title}
|
||||
{!subtitle || locale === 'en-US' ? null : <span className="subtitle">{subtitle}</span>}
|
||||
<EditButton title={<FormattedMessage id="app.content.edit-page" />} filename={filename} />
|
||||
</h1>
|
||||
{!description
|
||||
? null
|
||||
: utils.toReactComponent(
|
||||
['section', { className: 'markdown' }].concat(getChildren(description)),
|
||||
)}
|
||||
{!content.toc || content.toc.length <= 1 || meta.toc === false ? null : (
|
||||
<Affix className="toc-affix" offsetTop={16}>
|
||||
{utils.toReactComponent(['ul', { className: 'toc' }].concat(getChildren(content.toc)))}
|
||||
</Affix>
|
||||
)}
|
||||
{this.getArticle(
|
||||
utils.toReactComponent(
|
||||
['section', { className: 'markdown' }].concat(getChildren(content.content)),
|
||||
),
|
||||
)}
|
||||
{utils.toReactComponent(
|
||||
[
|
||||
'section',
|
||||
{
|
||||
className: 'markdown api-container',
|
||||
},
|
||||
].concat(getChildren(content.api || ['placeholder'])),
|
||||
)}
|
||||
</article>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import React from 'react';
|
||||
import DocumentTitle from 'react-document-title';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import { Row, Col, Icon, Affix, Tooltip } from 'antd';
|
||||
import { getChildren } from 'jsonml.js/lib/utils';
|
||||
import Demo from './Demo';
|
||||
import EditButton from './EditButton';
|
||||
import { ping } from '../utils';
|
||||
import { ping, getMetaDescription } from '../utils';
|
||||
|
||||
class ComponentDoc extends React.Component {
|
||||
state = {
|
||||
@ -106,66 +106,72 @@ class ComponentDoc extends React.Component {
|
||||
const articleClassName = classNames({
|
||||
'show-riddle-button': showRiddleButton,
|
||||
});
|
||||
const helmetTitle = `${subtitle || ''} ${title[locale] || title} - Ant Design`;
|
||||
const contentChild = getMetaDescription(getChildren(content));
|
||||
|
||||
return (
|
||||
<DocumentTitle title={`${subtitle || ''} ${title[locale] || title} - Ant Design`}>
|
||||
<article className={articleClassName}>
|
||||
<Affix className="toc-affix" offsetTop={16}>
|
||||
<ul id="demo-toc" className="toc">
|
||||
{jumper}
|
||||
</ul>
|
||||
</Affix>
|
||||
<section className="markdown">
|
||||
<h1>
|
||||
{title[locale] || title}
|
||||
{!subtitle ? null : <span className="subtitle">{subtitle}</span>}
|
||||
<EditButton
|
||||
title={<FormattedMessage id="app.content.edit-page" />}
|
||||
filename={filename}
|
||||
/>
|
||||
</h1>
|
||||
{utils.toReactComponent(
|
||||
['section', { className: 'markdown' }].concat(getChildren(content)),
|
||||
)}
|
||||
<h2>
|
||||
<FormattedMessage id="app.component.examples" />
|
||||
<Tooltip
|
||||
title={
|
||||
<FormattedMessage
|
||||
id={`app.component.examples.${expandAll ? 'collapse' : 'expand'}`}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
type={`${expandAll ? 'appstore' : 'appstore-o'}`}
|
||||
className={expandTriggerClass}
|
||||
onClick={this.handleExpandToggle}
|
||||
/>
|
||||
</Tooltip>
|
||||
</h2>
|
||||
</section>
|
||||
<Row gutter={16}>
|
||||
<Col
|
||||
span={isSingleCol ? 24 : 12}
|
||||
className={isSingleCol ? 'code-boxes-col-1-1' : 'code-boxes-col-2-1'}
|
||||
>
|
||||
{leftChildren}
|
||||
</Col>
|
||||
{isSingleCol ? null : (
|
||||
<Col className="code-boxes-col-2-1" span={12}>
|
||||
{rightChildren}
|
||||
</Col>
|
||||
)}
|
||||
</Row>
|
||||
<article className={articleClassName}>
|
||||
<Helmet>
|
||||
{helmetTitle && <title>{helmetTitle}</title>}
|
||||
{helmetTitle && <meta property="og:title" content={helmetTitle} />}
|
||||
{contentChild && <meta name="description" content={contentChild} />}
|
||||
</Helmet>
|
||||
<Affix className="toc-affix" offsetTop={16}>
|
||||
<ul id="demo-toc" className="toc">
|
||||
{jumper}
|
||||
</ul>
|
||||
</Affix>
|
||||
<section className="markdown">
|
||||
<h1>
|
||||
{title[locale] || title}
|
||||
{!subtitle ? null : <span className="subtitle">{subtitle}</span>}
|
||||
<EditButton
|
||||
title={<FormattedMessage id="app.content.edit-page" />}
|
||||
filename={filename}
|
||||
/>
|
||||
</h1>
|
||||
{utils.toReactComponent(
|
||||
[
|
||||
'section',
|
||||
{
|
||||
className: 'markdown api-container',
|
||||
},
|
||||
].concat(getChildren(doc.api || ['placeholder'])),
|
||||
['section', { className: 'markdown' }].concat(getChildren(content)),
|
||||
)}
|
||||
</article>
|
||||
</DocumentTitle>
|
||||
<h2>
|
||||
<FormattedMessage id="app.component.examples" />
|
||||
<Tooltip
|
||||
title={
|
||||
<FormattedMessage
|
||||
id={`app.component.examples.${expandAll ? 'collapse' : 'expand'}`}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
type={`${expandAll ? 'appstore' : 'appstore-o'}`}
|
||||
className={expandTriggerClass}
|
||||
onClick={this.handleExpandToggle}
|
||||
/>
|
||||
</Tooltip>
|
||||
</h2>
|
||||
</section>
|
||||
<Row gutter={16}>
|
||||
<Col
|
||||
span={isSingleCol ? 24 : 12}
|
||||
className={isSingleCol ? 'code-boxes-col-1-1' : 'code-boxes-col-2-1'}
|
||||
>
|
||||
{leftChildren}
|
||||
</Col>
|
||||
{isSingleCol ? null : (
|
||||
<Col className="code-boxes-col-2-1" span={12}>
|
||||
{rightChildren}
|
||||
</Col>
|
||||
)}
|
||||
</Row>
|
||||
{utils.toReactComponent(
|
||||
[
|
||||
'section',
|
||||
{
|
||||
className: 'markdown api-container',
|
||||
},
|
||||
].concat(getChildren(doc.api || ['placeholder'])),
|
||||
)}
|
||||
</article>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import DocumentTitle from 'react-document-title';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import PropTypes from 'prop-types';
|
||||
import Banner from './Banner';
|
||||
import Page1 from './Page1';
|
||||
@ -69,16 +69,17 @@ class Home extends React.Component {
|
||||
const { isMobile } = this.context;
|
||||
const childProps = { ...this.props, isMobile, locale: intl.locale };
|
||||
return (
|
||||
<DocumentTitle title={`Ant Design - ${intl.formatMessage({ id: 'app.home.slogan' })}`}>
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: getStyle() }} /> {/* eslint-disable-line */}
|
||||
<Banner {...childProps} />
|
||||
<Page1 {...childProps} />
|
||||
<Page2 {...childProps} />
|
||||
<Page3 {...childProps} />
|
||||
<Footer />
|
||||
</>
|
||||
</DocumentTitle>
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: getStyle() }} /> {/* eslint-disable-line */}
|
||||
<Helmet>
|
||||
<title>{`Ant Design - ${intl.formatMessage({ id: 'app.home.slogan' })}`}</title>
|
||||
</Helmet>
|
||||
<Banner {...childProps} />
|
||||
<Page1 {...childProps} />
|
||||
<Page2 {...childProps} />
|
||||
<Page3 {...childProps} />
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -110,10 +110,26 @@ export default class Layout extends React.Component {
|
||||
render() {
|
||||
const { children, ...restProps } = this.props;
|
||||
const { appLocale } = this.state;
|
||||
const title =
|
||||
appLocale.locale === 'zh-CN'
|
||||
? 'Ant Design - 一套企业级 UI 设计语言和 React 组件库'
|
||||
: 'Ant Design - A UI Design Language and React UI library';
|
||||
const description =
|
||||
appLocale.locale === 'zh-CN'
|
||||
? '基于 Ant Design 设计体系的 React UI 组件库,用于研发企业级中后台产品。'
|
||||
: 'An enterprise-class UI design language and React UI library with a set of high-quality React components, one of best React UI library for enterprises';
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<html lang={appLocale.locale === 'zh-CN' ? 'zh' : 'en'} />
|
||||
<title>{title}</title>
|
||||
<meta name="description" content={description} />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta
|
||||
property="og:image"
|
||||
content="https://gw.alipayobjects.com/zos/rmsportal/rlpTLlbMzTNYuZGGCVYM.png"
|
||||
/>
|
||||
</Helmet>
|
||||
<IntlProvider locale={appLocale.locale} messages={appLocale.messages} defaultLocale="en-US">
|
||||
<ConfigProvider locale={appLocale.locale === 'zh-CN' ? zhCN : null}>
|
||||
|
@ -1,3 +1,6 @@
|
||||
import flattenDeep from 'lodash/flattenDeep';
|
||||
import flatten from 'lodash/flatten';
|
||||
|
||||
export function getMenuItems(moduleData, locale, categoryOrder, typeOrder) {
|
||||
const menuMeta = moduleData.map(item => item.meta);
|
||||
const menuItems = [];
|
||||
@ -108,3 +111,27 @@ export function loadScript(src) {
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
}
|
||||
|
||||
export function getMetaDescription(jml) {
|
||||
const COMMON_TAGS = ['h1', 'h2', 'h3', 'p', 'img', 'a', 'code', 'strong'];
|
||||
if (!Array.isArray(jml)) return '';
|
||||
const paragraph = flattenDeep(
|
||||
jml
|
||||
.filter(item => {
|
||||
if (Array.isArray(item)) {
|
||||
const [tag] = item;
|
||||
return tag === 'p';
|
||||
}
|
||||
return false;
|
||||
})
|
||||
// ['p', ['code', 'aa'], 'bb'] => ['p', 'aabb']
|
||||
.map(item => {
|
||||
const [tag, ...others] = flatten(item);
|
||||
const content = others
|
||||
.filter(other => typeof other === 'string' && !COMMON_TAGS.includes(other))
|
||||
.join('');
|
||||
return [tag, content];
|
||||
}),
|
||||
).find(p => p && typeof p === 'string' && !COMMON_TAGS.includes(p));
|
||||
return paragraph;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user