mirror of
https://github.com/ant-design/ant-design.git
synced 2025-06-11 19:42:54 +08:00
merge master
This commit is contained in:
parent
2ea28af6ed
commit
fa8ddb4104
4
.github/workflows/deploy-site.yml
vendored
4
.github/workflows/deploy-site.yml
vendored
@ -1,10 +1,10 @@
|
|||||||
name: Deploy website
|
name: Deploy website
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
actions:
|
types: [published]
|
||||||
- published
|
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-deploy:
|
build-and-deploy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
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
|
||||||
- 🐞 修复 Descriptions.Item 最后一个宽度计算不正确的问题。[#18568](https://github.com/ant-design/ant-design/pull/18568)
|
- 🐞 修复 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)
|
- 🐞 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)
|
- 🐞 修复 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)
|
- 🐞 修复 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)
|
- 🐞 修复 `Button[href]` 在 Card `actions` 中样式变形的问题。[#18588](https://github.com/ant-design/ant-design/pull/18588)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
一套企业级的 UI 设计语言和 React 实现。
|
一套企业级 UI 设计语言和 React 组件库。
|
||||||
|
|
||||||
[](https://circleci.com/gh/ant-design/ant-design) [](https://codecov.io/gh/ant-design/ant-design/branch/master) [](https://www.npmjs.org/package/antd) [](http://npmjs.com/antd)
|
[](https://circleci.com/gh/ant-design/ant-design) [](https://codecov.io/gh/ant-design/ant-design/branch/master) [](https://www.npmjs.org/package/antd) [](http://npmjs.com/antd)
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
An enterprise-class UI design language and React implementation.
|
An enterprise-class UI design language and React UI library.
|
||||||
|
|
||||||
[](https://circleci.com/gh/ant-design/ant-design) [](https://codecov.io/gh/ant-design/ant-design/branch/master) [](https://www.npmjs.com/package/antd) [](http://npmjs.com/antd)
|
[](https://circleci.com/gh/ant-design/ant-design) [](https://codecov.io/gh/ant-design/ant-design/branch/master) [](https://www.npmjs.com/package/antd) [](http://npmjs.com/antd)
|
||||||
|
|
||||||
|
@ -68,10 +68,10 @@ exports[`renders ./components/alert/demo/banner.md correctly 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="ant-alert-description"
|
class="ant-alert-description"
|
||||||
/>
|
/>
|
||||||
<span
|
<button
|
||||||
class="ant-alert-close-icon"
|
class="ant-alert-close-icon"
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-label="close"
|
aria-label="close"
|
||||||
@ -93,7 +93,7 @@ exports[`renders ./components/alert/demo/banner.md correctly 1`] = `
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<div
|
<div
|
||||||
@ -176,10 +176,10 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="ant-alert-description"
|
class="ant-alert-description"
|
||||||
/>
|
/>
|
||||||
<span
|
<button
|
||||||
class="ant-alert-close-icon"
|
class="ant-alert-close-icon"
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-label="close"
|
aria-label="close"
|
||||||
@ -201,7 +201,7 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="ant-alert ant-alert-error ant-alert-with-description ant-alert-no-icon ant-alert-closable"
|
class="ant-alert ant-alert-error ant-alert-with-description ant-alert-no-icon ant-alert-closable"
|
||||||
@ -217,10 +217,10 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
|
|||||||
>
|
>
|
||||||
Error Description Error Description Error Description Error Description Error Description Error Description
|
Error Description Error Description Error Description Error Description Error Description Error Description
|
||||||
</span>
|
</span>
|
||||||
<span
|
<button
|
||||||
class="ant-alert-close-icon"
|
class="ant-alert-close-icon"
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-label="close"
|
aria-label="close"
|
||||||
@ -242,7 +242,7 @@ exports[`renders ./components/alert/demo/closable.md correctly 1`] = `
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@ -260,17 +260,17 @@ exports[`renders ./components/alert/demo/close-text.md correctly 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="ant-alert-description"
|
class="ant-alert-description"
|
||||||
/>
|
/>
|
||||||
<span
|
<button
|
||||||
class="ant-alert-close-icon"
|
class="ant-alert-close-icon"
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="ant-alert-close-text"
|
class="ant-alert-close-text"
|
||||||
>
|
>
|
||||||
Close Now
|
Close Now
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -932,10 +932,10 @@ exports[`renders ./components/alert/demo/smooth-closed.md correctly 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="ant-alert-description"
|
class="ant-alert-description"
|
||||||
/>
|
/>
|
||||||
<span
|
<button
|
||||||
class="ant-alert-close-icon"
|
class="ant-alert-close-icon"
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-label="close"
|
aria-label="close"
|
||||||
@ -957,7 +957,7 @@ exports[`renders ./components/alert/demo/smooth-closed.md correctly 1`] = `
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
placeholder text here
|
placeholder text here
|
||||||
|
@ -33,7 +33,7 @@ export interface AlertProps {
|
|||||||
/** Additional content of Alert */
|
/** Additional content of Alert */
|
||||||
description?: React.ReactNode;
|
description?: React.ReactNode;
|
||||||
/** Callback when close Alert */
|
/** Callback when close Alert */
|
||||||
onClose?: React.MouseEventHandler<HTMLAnchorElement>;
|
onClose?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
/** Trigger when animation ending of Alert */
|
/** Trigger when animation ending of Alert */
|
||||||
afterClose?: () => void;
|
afterClose?: () => void;
|
||||||
/** Whether to show icon */
|
/** Whether to show icon */
|
||||||
@ -70,7 +70,7 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
|
|||||||
closed: false,
|
closed: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
handleClose = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
handleClose = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const dom = ReactDOM.findDOMNode(this) as HTMLElement;
|
const dom = ReactDOM.findDOMNode(this) as HTMLElement;
|
||||||
dom.style.height = `${dom.offsetHeight}px`;
|
dom.style.height = `${dom.offsetHeight}px`;
|
||||||
@ -134,14 +134,14 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const closeIcon = closable ? (
|
const closeIcon = closable ? (
|
||||||
<span
|
<button
|
||||||
role="button"
|
type="button"
|
||||||
onClick={this.handleClose}
|
onClick={this.handleClose}
|
||||||
className={`${prefixCls}-close-icon`}
|
className={`${prefixCls}-close-icon`}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
{closeText ? <span className={`${prefixCls}-close-text`}>{closeText}</span> : <Close />}
|
{closeText ? <span className={`${prefixCls}-close-text`}>{closeText}</span> : <Close />}
|
||||||
</span>
|
</button>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
const dataOrAriaProps = getDataOrAriaProps(this.props);
|
const dataOrAriaProps = getDataOrAriaProps(this.props);
|
||||||
|
@ -74,6 +74,8 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: @font-size-sm;
|
font-size: @font-size-sm;
|
||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
.@{iconfont-css-prefix}-close {
|
.@{iconfont-css-prefix}-close {
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +155,17 @@ exports[`Button renders Chinese characters correctly 6`] = `
|
|||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`Button renders Chinese characters correctly 7`] = `
|
||||||
|
<button
|
||||||
|
class="ant-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
按 钮
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`Button renders correctly 1`] = `
|
exports[`Button renders correctly 1`] = `
|
||||||
<button
|
<button
|
||||||
class="ant-btn"
|
class="ant-btn"
|
||||||
@ -189,6 +200,17 @@ exports[`Button should merge text if children using variable 1`] = `
|
|||||||
</button>
|
</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`] = `
|
exports[`Button should not render as link button when href is undefined 1`] = `
|
||||||
<button
|
<button
|
||||||
class="ant-btn ant-btn-primary"
|
class="ant-btn ant-btn-primary"
|
||||||
@ -200,6 +222,23 @@ exports[`Button should not render as link button when href is undefined 1`] = `
|
|||||||
</button>
|
</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`] = `
|
exports[`Button should support link button 1`] = `
|
||||||
<a
|
<a
|
||||||
class="ant-btn"
|
class="ant-btn"
|
||||||
|
@ -4,10 +4,15 @@ import renderer from 'react-test-renderer';
|
|||||||
import { Search } from '@ant-design/icons';
|
import { Search } from '@ant-design/icons';
|
||||||
import Button from '..';
|
import Button from '..';
|
||||||
import mountTest from '../../../tests/shared/mountTest';
|
import mountTest from '../../../tests/shared/mountTest';
|
||||||
|
import { sleep } from '../../../tests/utils';
|
||||||
|
|
||||||
describe('Button', () => {
|
describe('Button', () => {
|
||||||
mountTest(Button);
|
mountTest(Button);
|
||||||
|
mountTest(() => <Button size="large" />);
|
||||||
|
mountTest(() => <Button size="small" />);
|
||||||
mountTest(Button.Group);
|
mountTest(Button.Group);
|
||||||
|
mountTest(() => <Button.Group size="large" />);
|
||||||
|
mountTest(() => <Button.Group size="small" />);
|
||||||
|
|
||||||
it('renders correctly', () => {
|
it('renders correctly', () => {
|
||||||
const wrapper = render(<Button>Follow</Button>);
|
const wrapper = render(<Button>Follow</Button>);
|
||||||
@ -45,6 +50,14 @@ describe('Button', () => {
|
|||||||
// should insert space while loading
|
// should insert space while loading
|
||||||
const wrapper5 = render(<Button loading>按钮</Button>);
|
const wrapper5 = render(<Button loading>按钮</Button>);
|
||||||
expect(wrapper5).toMatchSnapshot();
|
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', () => {
|
it('renders Chinese characters correctly in HOC', () => {
|
||||||
@ -67,6 +80,22 @@ describe('Button', () => {
|
|||||||
expect(wrapper.find('.ant-btn').hasClass('ant-btn-two-chinese-chars')).toBe(true);
|
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', () => {
|
it('have static property for type detecting', () => {
|
||||||
const wrapper = mount(<Button>Button Text</Button>);
|
const wrapper = mount(<Button>Button Text</Button>);
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
@ -122,6 +151,17 @@ describe('Button', () => {
|
|||||||
expect(wrapper.hasClass('ant-btn-loading')).toBe(false);
|
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', () => {
|
it('should support link button', () => {
|
||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
<Button target="_blank" href="http://ant.design">
|
<Button target="_blank" href="http://ant.design">
|
||||||
@ -169,4 +209,27 @@ describe('Button', () => {
|
|||||||
|
|
||||||
expect(wrapper.render()).toMatchSnapshot();
|
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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -135,16 +135,6 @@ class Button extends React.Component<ButtonProps, ButtonState> {
|
|||||||
title: PropTypes.string,
|
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 delayTimeout: number;
|
||||||
|
|
||||||
private buttonNode: HTMLElement | null;
|
private buttonNode: HTMLElement | null;
|
||||||
@ -170,8 +160,10 @@ class Button extends React.Component<ButtonProps, ButtonState> {
|
|||||||
|
|
||||||
const { loading } = this.props;
|
const { loading } = this.props;
|
||||||
if (loading && typeof loading !== 'boolean' && loading.delay) {
|
if (loading && typeof loading !== 'boolean' && loading.delay) {
|
||||||
this.delayTimeout = window.setTimeout(() => this.setState({ loading }), loading.delay);
|
this.delayTimeout = window.setTimeout(() => {
|
||||||
} else if (prevProps.loading !== this.props.loading) {
|
this.setState({ loading });
|
||||||
|
}, loading.delay);
|
||||||
|
} else if (prevProps.loading !== loading) {
|
||||||
// eslint-disable-next-line react/no-did-update-set-state
|
// eslint-disable-next-line react/no-did-update-set-state
|
||||||
this.setState({ loading });
|
this.setState({ loading });
|
||||||
}
|
}
|
||||||
@ -218,8 +210,8 @@ class Button extends React.Component<ButtonProps, ButtonState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isNeedInserted() {
|
isNeedInserted() {
|
||||||
const { icon, children } = this.props;
|
const { icon, children, type } = this.props;
|
||||||
return React.Children.count(children) === 1 && !icon;
|
return React.Children.count(children) === 1 && !icon && type !== 'link';
|
||||||
}
|
}
|
||||||
|
|
||||||
renderButton = ({ getPrefixCls, autoInsertSpaceInButton }: ConfigConsumerProps) => {
|
renderButton = ({ getPrefixCls, autoInsertSpaceInButton }: ConfigConsumerProps) => {
|
||||||
@ -261,7 +253,7 @@ class Button extends React.Component<ButtonProps, ButtonState> {
|
|||||||
[`${prefixCls}-${shape}`]: shape,
|
[`${prefixCls}-${shape}`]: shape,
|
||||||
[`${prefixCls}-${sizeCls}`]: sizeCls,
|
[`${prefixCls}-${sizeCls}`]: sizeCls,
|
||||||
[`${prefixCls}-icon-only`]: !children && children !== 0 && iconType,
|
[`${prefixCls}-icon-only`]: !children && children !== 0 && iconType,
|
||||||
[`${prefixCls}-loading`]: loading,
|
[`${prefixCls}-loading`]: !!loading,
|
||||||
[`${prefixCls}-background-ghost`]: ghost,
|
[`${prefixCls}-background-ghost`]: ghost,
|
||||||
[`${prefixCls}-two-chinese-chars`]: hasTwoCNChar && autoInsertSpace,
|
[`${prefixCls}-two-chinese-chars`]: hasTwoCNChar && autoInsertSpace,
|
||||||
[`${prefixCls}-block`]: block,
|
[`${prefixCls}-block`]: block,
|
||||||
|
@ -2,10 +2,16 @@ import React from 'react';
|
|||||||
import { mount } from 'enzyme';
|
import { mount } from 'enzyme';
|
||||||
import ConfigProvider from '..';
|
import ConfigProvider from '..';
|
||||||
import LocaleProvider from '../../locale-provider';
|
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 TimePicker from '../../time-picker';
|
||||||
|
import Modal from '../../modal';
|
||||||
|
|
||||||
describe('ConfigProvider.Locale', () => {
|
describe('ConfigProvider.Locale', () => {
|
||||||
|
function $$(className) {
|
||||||
|
return document.body.querySelectorAll(className);
|
||||||
|
}
|
||||||
|
|
||||||
it('not throw', () => {
|
it('not throw', () => {
|
||||||
if (process.env.REACT === '15') {
|
if (process.env.REACT === '15') {
|
||||||
return;
|
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', () => {
|
describe('support legacy LocaleProvider', () => {
|
||||||
function testLocale(wrapper) {
|
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', () => {
|
it('LocaleProvider', () => {
|
||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
<LocaleProvider locale={locale}>
|
<LocaleProvider locale={zhCN}>
|
||||||
<TimePicker />
|
<TimePicker />
|
||||||
</LocaleProvider>,
|
</LocaleProvider>,
|
||||||
);
|
);
|
||||||
@ -36,7 +82,7 @@ describe('ConfigProvider.Locale', () => {
|
|||||||
|
|
||||||
it('LocaleProvider > ConfigProvider', () => {
|
it('LocaleProvider > ConfigProvider', () => {
|
||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
<LocaleProvider locale={locale}>
|
<LocaleProvider locale={zhCN}>
|
||||||
<ConfigProvider>
|
<ConfigProvider>
|
||||||
<TimePicker />
|
<TimePicker />
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
@ -48,7 +94,7 @@ describe('ConfigProvider.Locale', () => {
|
|||||||
|
|
||||||
it('ConfigProvider > ConfigProvider', () => {
|
it('ConfigProvider > ConfigProvider', () => {
|
||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
<ConfigProvider locale={locale}>
|
<ConfigProvider locale={zhCN}>
|
||||||
<ConfigProvider>
|
<ConfigProvider>
|
||||||
<TimePicker />
|
<TimePicker />
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
|
@ -32,4 +32,4 @@ cols: 1
|
|||||||
| label | 内容的描述 | ReactNode | - | 3.19.0 |
|
| label | 内容的描述 | ReactNode | - | 3.19.0 |
|
||||||
| span | 包含列的数量 | number | 1 | 3.19.0 |
|
| span | 包含列的数量 | number | 1 | 3.19.0 |
|
||||||
|
|
||||||
> span Description.Item 的数量。 span={2} 会占用两个 DescriptionItem 的宽度。
|
> span 是 Description.Item 的数量。 span={2} 会占用两个 DescriptionItem 的宽度。
|
||||||
|
@ -4030,20 +4030,16 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
|
|||||||
<div
|
<div
|
||||||
class="ant-form-item-control-input"
|
class="ant-form-item-control-input"
|
||||||
>
|
>
|
||||||
<div
|
<span
|
||||||
class="dropbox"
|
class=""
|
||||||
>
|
>
|
||||||
<span
|
<div
|
||||||
class=""
|
class="ant-upload ant-upload-drag"
|
||||||
>
|
/>
|
||||||
<div
|
<div
|
||||||
class="ant-upload ant-upload-drag"
|
class="ant-upload-list ant-upload-list-text"
|
||||||
/>
|
/>
|
||||||
<div
|
</span>
|
||||||
class="ant-upload-list ant-upload-list-text"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -171,17 +171,15 @@ const Demo = () => {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label="Dragger">
|
<Form.Item label="Dragger">
|
||||||
<div className="dropbox">
|
<Form.Item name="dragger" valuePropName="fileList" getValueFromEvent={normFile} noStyle>
|
||||||
<Form.Item name="dragger" valuePropName="fileList" getValueFromEvent={normFile} noStyle>
|
<Upload.Dragger name="files" action="/upload.do">
|
||||||
<Upload.Dragger name="files" action="/upload.do">
|
<p className="ant-upload-drag-icon">
|
||||||
<p className="ant-upload-drag-icon">
|
<Inbox />
|
||||||
<Inbox />
|
</p>
|
||||||
</p>
|
<p className="ant-upload-text">Click or drag file to this area to upload</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>
|
||||||
<p className="ant-upload-hint">Support for a single or bulk upload.</p>
|
</Upload.Dragger>
|
||||||
</Upload.Dragger>
|
</Form.Item>
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item wrapperCol={{ span: 12, offset: 6 }}>
|
<Form.Item wrapperCol={{ span: 12, offset: 6 }}>
|
||||||
@ -195,10 +193,3 @@ const Demo = () => {
|
|||||||
|
|
||||||
ReactDOM.render(<Demo />, mountNode);
|
ReactDOM.render(<Demo />, mountNode);
|
||||||
```
|
```
|
||||||
|
|
||||||
```css
|
|
||||||
#components-form-demo-validate-other .dropbox {
|
|
||||||
height: 180px;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
@ -19,7 +19,7 @@ High performance Form component with data scope management. Including data colle
|
|||||||
| Property | Description | Type | Default |
|
| Property | Description | Type | Default |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| component | Set the Form rendering element. Do not create a DOM node for `false` | ComponentType \| false | form |
|
| component | Set the Form rendering element. Do not create a DOM node for `false` | ComponentType \| false | form |
|
||||||
| colon | Configure the default value of `colon` for Form.Item. Indicates whether the colon after the label is displayed | boolean | true |
|
| colon | Configure the default value of `colon` for Form.Item. Indicates whether the colon after the label is displayed (only effective when prop layout is horizontal) | boolean | true |
|
||||||
| fields | Control of form fields through state management (such as redux). Not recommended for non-strong demand. View [example](#components-form-demo-global-state) | [FieldData](#FieldData)\[] | - |
|
| fields | Control of form fields through state management (such as redux). Not recommended for non-strong demand. View [example](#components-form-demo-global-state) | [FieldData](#FieldData)\[] | - |
|
||||||
| form | Form control instance created by `Form.useForm()`. Automatically created when not provided | [FormInstance](#FormInstance) | - |
|
| form | Form control instance created by `Form.useForm()`. Automatically created when not provided | [FormInstance](#FormInstance) | - |
|
||||||
| hideRequiredMark | Hide required mark for all form items | boolean | false |
|
| hideRequiredMark | Hide required mark for all form items | boolean | false |
|
||||||
|
@ -20,7 +20,7 @@ title: Form
|
|||||||
| 参数 | 说明 | 类型 | 默认值 |
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| component | 设置 Form 渲染元素,为 `false` 则不创建 DOM 节点 | ComponentType \| false | form |
|
| component | 设置 Form 渲染元素,为 `false` 则不创建 DOM 节点 | ComponentType \| false | form |
|
||||||
| colon | 配置 Form.Item 的 `colon` 的默认值。表示是否显示 label 后面的冒号 | boolean | true |
|
| colon | 配置 Form.Item 的 `colon` 的默认值。表示是否显示 label 后面的冒号 (只有在属性 layout 为 horizontal 时有效) | boolean | true |
|
||||||
| fields | 通过状态管理(如 redux)控制表单字段,如非强需求不推荐使用。查看[示例](#components-form-demo-global-state) | [FieldData](#FieldData)\[] | - |
|
| fields | 通过状态管理(如 redux)控制表单字段,如非强需求不推荐使用。查看[示例](#components-form-demo-global-state) | [FieldData](#FieldData)\[] | - |
|
||||||
| form | 经 `Form.useForm()` 创建的 form 控制实例,不提供时会自动创建 | [FormInstance](#FormInstance) | - |
|
| form | 经 `Form.useForm()` 创建的 form 控制实例,不提供时会自动创建 | [FormInstance](#FormInstance) | - |
|
||||||
| hideRequiredMark | 隐藏所有表单项的必选标记 | boolean | false |
|
| hideRequiredMark | 隐藏所有表单项的必选标记 | boolean | false |
|
||||||
|
@ -141,6 +141,7 @@
|
|||||||
|
|
||||||
&-handler-up {
|
&-handler-up {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
border-top-right-radius: @border-radius-base;
|
||||||
&-inner {
|
&-inner {
|
||||||
top: 50%;
|
top: 50%;
|
||||||
margin-top: -5px;
|
margin-top: -5px;
|
||||||
@ -154,6 +155,7 @@
|
|||||||
&-handler-down {
|
&-handler-down {
|
||||||
top: 0;
|
top: 0;
|
||||||
border-top: @border-width-base @border-style-base @border-color-base;
|
border-top: @border-width-base @border-style-base @border-color-base;
|
||||||
|
border-bottom-right-radius: @border-radius-base;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
&-inner {
|
&-inner {
|
||||||
top: 50%;
|
top: 50%;
|
||||||
|
@ -10,7 +10,10 @@ export interface SearchProps extends InputProps {
|
|||||||
inputPrefixCls?: string;
|
inputPrefixCls?: string;
|
||||||
onSearch?: (
|
onSearch?: (
|
||||||
value: string,
|
value: string,
|
||||||
event?: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLInputElement>,
|
event?:
|
||||||
|
| React.ChangeEvent<HTMLInputElement>
|
||||||
|
| React.MouseEvent<HTMLElement>
|
||||||
|
| React.KeyboardEvent<HTMLInputElement>,
|
||||||
) => void;
|
) => void;
|
||||||
enterButton?: boolean | React.ReactNode;
|
enterButton?: boolean | React.ReactNode;
|
||||||
}
|
}
|
||||||
@ -26,6 +29,16 @@ export default class Search extends React.Component<SearchProps, any> {
|
|||||||
this.input = node;
|
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>) => {
|
onSearch = (e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
const { onSearch } = this.props;
|
const { onSearch } = this.props;
|
||||||
if (onSearch) {
|
if (onSearch) {
|
||||||
@ -137,6 +150,7 @@ export default class Search extends React.Component<SearchProps, any> {
|
|||||||
prefixCls={inputPrefixCls}
|
prefixCls={inputPrefixCls}
|
||||||
addonAfter={this.renderAddonAfter(prefixCls)}
|
addonAfter={this.renderAddonAfter(prefixCls)}
|
||||||
suffix={this.renderSuffix(prefixCls)}
|
suffix={this.renderSuffix(prefixCls)}
|
||||||
|
onChange={this.onChange}
|
||||||
ref={this.saveInput}
|
ref={this.saveInput}
|
||||||
className={inputClassName}
|
className={inputClassName}
|
||||||
/>
|
/>
|
||||||
|
@ -137,4 +137,19 @@ describe('Input.Search', () => {
|
|||||||
expect(wrapper.render()).toMatchSnapshot();
|
expect(wrapper.render()).toMatchSnapshot();
|
||||||
expect(wrapperWithEnterButton.render()).toMatchSnapshot();
|
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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -294,6 +294,7 @@ exports[`Input.Search should support suffix 1`] = `
|
|||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
className="ant-input-search"
|
className="ant-input-search"
|
||||||
|
onChange={[Function]}
|
||||||
onPressEnter={[Function]}
|
onPressEnter={[Function]}
|
||||||
prefixCls="ant-input"
|
prefixCls="ant-input"
|
||||||
suffix={
|
suffix={
|
||||||
|
@ -73,8 +73,8 @@ export default class LocaleProvider extends React.Component<LocaleProviderProps,
|
|||||||
const { locale } = this.props;
|
const { locale } = this.props;
|
||||||
if (prevProps.locale !== locale) {
|
if (prevProps.locale !== locale) {
|
||||||
setMomentLocale(locale);
|
setMomentLocale(locale);
|
||||||
|
changeConfirmLocale(locale && locale.Modal);
|
||||||
}
|
}
|
||||||
changeConfirmLocale(locale && locale.Modal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
@ -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 |
|
| 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 |
|
| footer | PageHeader's footer, generally used to render TabBar | ReactNode | - | 3.14.0 |
|
||||||
| onBack | back icon click event | `()=>void` | `()=>history.back()` | 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 |
|
| breadcrumb | 面包屑的配置 | [breadcrumb](https://ant.design/components/breadcrumb-cn/) | - | 3.14.0 |
|
||||||
| footer | PageHeader 的页脚,一般用于渲染 TabBar | ReactNode | - | 3.14.0 |
|
| footer | PageHeader 的页脚,一般用于渲染 TabBar | ReactNode | - | 3.14.0 |
|
||||||
| onBack | 返回按钮的点击事件 | `()=>void` | `()=>history.back()` | 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 | |
|
| dropdownMatchSelectWidth | Whether dropdown's width is same with select. | boolean | true | |
|
||||||
| dropdownRender | Customize dropdown content | (menuNode: ReactNode, props) => ReactNode | - | 3.11.0 |
|
| dropdownRender | Customize dropdown content | (menuNode: ReactNode, props) => ReactNode | - | 3.11.0 |
|
||||||
| dropdownStyle | style of dropdown menu | object | - | |
|
| 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 | |
|
| 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\[] | - | |
|
| 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 | |
|
| 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 | |
|
| dropdownMatchSelectWidth | 下拉菜单和选择器同宽 | boolean | true | |
|
||||||
| dropdownRender | 自定义下拉框内容 | (menuNode: ReactNode, props) => ReactNode | - | 3.11.0 |
|
| dropdownRender | 自定义下拉框内容 | (menuNode: ReactNode, props) => ReactNode | - | 3.11.0 |
|
||||||
| dropdownStyle | 下拉菜单的 style 属性 | object | - | |
|
| dropdownStyle | 下拉菜单的 style 属性 | object | - | |
|
||||||
|
| dropdownMenuStyle | dropdown 菜单自定义样式 | object | - | |
|
||||||
| filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。 | boolean or function(inputValue, option) | true | |
|
| filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。 | boolean or function(inputValue, option) | true | |
|
||||||
| firstActiveValue | 默认高亮的选项 | string\|string\[] | - | |
|
| firstActiveValue | 默认高亮的选项 | string\|string\[] | - | |
|
||||||
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。[示例](https://codesandbox.io/s/4j168r7jw0) | Function(triggerNode) | () => document.body | |
|
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。[示例](https://codesandbox.io/s/4j168r7jw0) | Function(triggerNode) | () => document.body | |
|
||||||
|
@ -141,7 +141,7 @@ const columns = [
|
|||||||
| sorter | 排序函数,本地排序使用一个函数(参考 [Array.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) 的 compareFunction),需要服务端排序可设为 true | Function\|boolean | - | |
|
| 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 | - | |
|
| sortOrder | 排序的受控属性,外界可用此控制列的排序,可设置为 `'ascend'` `'descend'` `false` | boolean\|string | - | |
|
||||||
| sortDirections | 支持的排序方式,取值为 `'ascend'` `'descend'` | Array | `['ascend', 'descend']` | 3.15.2 |
|
| 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 | - | |
|
| width | 列宽度([指定了也不生效?](https://github.com/ant-design/ant-design/issues/13825#issuecomment-449889241)) | string\|number | - | |
|
||||||
| onCell | 设置单元格属性 | Function(record, rowIndex) | - | |
|
| onCell | 设置单元格属性 | Function(record, rowIndex) | - | |
|
||||||
| onFilter | 本地模式下,确定筛选的运行函数 | Function | - | |
|
| 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)\[] | \[] | |
|
| 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 |
|
| 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 | | |
|
| 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 }` | |
|
| 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 | | |
|
| 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 |
|
| 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\[] | \['>', '<'] | |
|
| 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 |
|
| 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\[] | \[] | |
|
| selectedKeys | A set of keys of selected items. | string\[] | \[] | |
|
||||||
| showSearch | If included, a search box is shown on each column. | boolean | false | |
|
| 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 |
|
| 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 |
|
| 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\[] | \[] | |
|
| 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 | | |
|
| 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 | | |
|
| 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 |
|
| 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)\[] | \[] | |
|
| dataSource | 数据源,其中的数据将会被渲染到左边一栏中,`targetKeys` 中指定的除外。 | [TransferItem](https://git.io/vMM64)\[] | \[] | |
|
||||||
| disabled | 是否禁用 | boolean | false | 3.10.0 |
|
| disabled | 是否禁用 | boolean | false | 3.10.0 |
|
||||||
| filterOption | 接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。 | | (inputValue, option): boolean | | |
|
| 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 }` | |
|
| lazy | Transfer 使用了 [react-lazy-load](https://github.com/loktar00/react-lazy-load) 优化性能,这里可以设置相关参数。设为 `false` 可以关闭懒加载。 | object\|boolean | `{ height: 32, offset: 32 }` | |
|
||||||
| listStyle | 两个穿梭框的自定义样式 | object | | |
|
| listStyle | 两个穿梭框的自定义样式 | object | | |
|
||||||
| locale | 各种语言 | { itemUnit: string; itemsUnit: string; searchPlaceholder: string; notFoundContent: ReactNode; } | `{ itemUnit: '项', itemsUnit: '项', searchPlaceholder: '请输入搜索内容' }` | 3.9.0 |
|
| locale | 各种语言 | { itemUnit: string; itemsUnit: string; searchPlaceholder: string; notFoundContent: ReactNode; } | `{ itemUnit: '项', itemsUnit: '项', searchPlaceholder: '请输入搜索内容' }` | 3.9.0 |
|
||||||
| operations | 操作文案集合,顺序从上至下 | string\[] | \['>', '<'] | |
|
| operations | 操作文案集合,顺序从上至下 | string\[] | \['>', '<'] | |
|
||||||
| render | 每行数据渲染函数,该函数的入参为 `dataSource` 中的项,返回值为 ReactElement。或者返回一个普通对象,其中 `label` 字段为 ReactElement,`value` 字段为 title | Function(record) | | |
|
| render | 每行数据渲染函数,该函数的入参为 `dataSource` 中的项,返回值为 ReactElement。或者返回一个普通对象,其中 `label` 字段为 ReactElement,`value` 字段为 title | (record) => ReactNode | | |
|
||||||
| selectedKeys | 设置哪些项应该被选中 | string\[] | \[] | |
|
| selectedKeys | 设置哪些项应该被选中 | string\[] | \[] | |
|
||||||
| showSearch | 是否显示搜索框 | boolean | false | |
|
| showSearch | 是否显示搜索框 | boolean | false | |
|
||||||
| showSelectAll | 是否展示全选勾选框 | boolean | true | 3.18.0 |
|
| showSelectAll | 是否展示全选勾选框 | boolean | true | 3.18.0 |
|
||||||
| style | 容器的自定义样式 | object | | 3.6.0 |
|
| style | 容器的自定义样式 | object | | 3.6.0 |
|
||||||
| targetKeys | 显示在右侧框数据的 key 集合 | string\[] | \[] | |
|
| targetKeys | 显示在右侧框数据的 key 集合 | string\[] | \[] | |
|
||||||
| titles | 标题集合,顺序从左至右 | string\[] | \['', ''] | |
|
| titles | 标题集合,顺序从左至右 | ReactNode\[] | \['', ''] | |
|
||||||
| onChange | 选项在两栏之间转移时的回调函数 | (targetKeys, direction, moveKeys): void | | |
|
| onChange | 选项在两栏之间转移时的回调函数 | (targetKeys, direction, moveKeys): void | | |
|
||||||
| onScroll | 选项列表滚动时的回调函数 | (direction, event): void | | |
|
| onScroll | 选项列表滚动时的回调函数 | (direction, event): void | | |
|
||||||
| onSearch | 搜索框内容时改变时的回调函数 | (direction: 'left'\|'right', value: string): void | - | 3.11.0 |
|
| onSearch | 搜索框内容时改变时的回调函数 | (direction: 'left'\|'right', value: string): void | - | 3.11.0 |
|
||||||
|
@ -156,6 +156,8 @@ export interface TreeProps {
|
|||||||
onDragOver?: (options: AntTreeNodeMouseEvent) => void;
|
onDragOver?: (options: AntTreeNodeMouseEvent) => void;
|
||||||
onDragLeave?: (options: AntTreeNodeMouseEvent) => void;
|
onDragLeave?: (options: AntTreeNodeMouseEvent) => void;
|
||||||
onDragEnd?: (options: AntTreeNodeMouseEvent) => void;
|
onDragEnd?: (options: AntTreeNodeMouseEvent) => void;
|
||||||
|
onMouseEnter?: (options: AntTreeNodeMouseEvent) => void;
|
||||||
|
onMouseLeave?: (options: AntTreeNodeMouseEvent) => void;
|
||||||
onDrop?: (options: AntTreeNodeDropEvent) => void;
|
onDrop?: (options: AntTreeNodeDropEvent) => void;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
showIcon?: boolean;
|
showIcon?: boolean;
|
||||||
|
@ -33,6 +33,7 @@ Almost anything can be represented in a tree structure. Examples include directo
|
|||||||
| loadData | Load data asynchronously | function(node) | - | |
|
| loadData | Load data asynchronously | function(node) | - | |
|
||||||
| loadedKeys | (Controlled) Set loaded tree nodes. Need work with `loadData` | string\[] | \[] | 3.7.0 |
|
| loadedKeys | (Controlled) Set loaded tree nodes. Need work with `loadData` | string\[] | \[] | 3.7.0 |
|
||||||
| multiple | Allows selecting multiple treeNodes | boolean | false | |
|
| multiple | Allows selecting multiple treeNodes | boolean | false | |
|
||||||
|
| selectable | whether can be selected | boolean | true | |
|
||||||
| selectedKeys | (Controlled) Specifies the keys of the selected treeNodes | string\[] | - | |
|
| 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 | |
|
| 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 |
|
| switcherIcon | customize collapse/expand icon of tree node | React.ReactElement | - | 3.12.0 |
|
||||||
|
@ -34,6 +34,7 @@ subtitle: 树形控件
|
|||||||
| loadData | 异步加载数据 | function(node) | - | |
|
| loadData | 异步加载数据 | function(node) | - | |
|
||||||
| loadedKeys | (受控)已经加载的节点,需要配合 `loadData` 使用 | string\[] | \[] | 3.7.0 |
|
| loadedKeys | (受控)已经加载的节点,需要配合 `loadData` 使用 | string\[] | \[] | 3.7.0 |
|
||||||
| multiple | 支持点选多个节点(节点本身) | boolean | false | |
|
| multiple | 支持点选多个节点(节点本身) | boolean | false | |
|
||||||
|
| selectable | 是否可选中 | boolean | true | |
|
||||||
| selectedKeys | (受控)设置选中的树节点 | string\[] | - | |
|
| selectedKeys | (受控)设置选中的树节点 | string\[] | - | |
|
||||||
| showIcon | 是否展示 TreeNode title 前的图标,没有默认样式,如设置为 true,需要自行定义图标相关样式 | boolean | false | |
|
| showIcon | 是否展示 TreeNode title 前的图标,没有默认样式,如设置为 true,需要自行定义图标相关样式 | boolean | false | |
|
||||||
| switcherIcon | 自定义树节点的展开/折叠图标 | React.ReactElement | - | 3.12.0 |
|
| 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.
|
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 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.
|
- [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.
|
||||||
|
149
package.json
149
package.json
@ -1,46 +1,91 @@
|
|||||||
{
|
{
|
||||||
"name": "antd",
|
"name": "antd",
|
||||||
"version": "4.0.0-alpha.3",
|
"version": "4.0.0-alpha.3",
|
||||||
"title": "Ant Design",
|
|
||||||
"description": "An enterprise-class UI design language and React components implementation",
|
"description": "An enterprise-class UI design language and React components implementation",
|
||||||
"homepage": "http://ant.design/",
|
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"ant",
|
"ant",
|
||||||
"design",
|
|
||||||
"react",
|
|
||||||
"react-component",
|
|
||||||
"component",
|
"component",
|
||||||
"components",
|
"components",
|
||||||
"ui",
|
"design",
|
||||||
"framework",
|
"framework",
|
||||||
"frontend"
|
"frontend",
|
||||||
|
"react",
|
||||||
|
"react-component",
|
||||||
|
"ui"
|
||||||
],
|
],
|
||||||
"contributors": [
|
"homepage": "http://ant.design/",
|
||||||
"ant"
|
"bugs": {
|
||||||
],
|
"url": "https://github.com/ant-design/ant-design/issues"
|
||||||
"publishConfig": {
|
|
||||||
"registry": "https://registry.npmjs.org/"
|
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/ant-design/ant-design"
|
"url": "https://github.com/ant-design/ant-design"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"license": "MIT",
|
||||||
"url": "https://github.com/ant-design/ant-design/issues"
|
"contributors": [
|
||||||
},
|
"ant"
|
||||||
"main": "lib/index.js",
|
],
|
||||||
"module": "es/index.js",
|
|
||||||
"files": [
|
"files": [
|
||||||
"dist",
|
"dist",
|
||||||
"lib",
|
"lib",
|
||||||
"es"
|
"es"
|
||||||
],
|
],
|
||||||
|
"sideEffects": [
|
||||||
|
"dist/*",
|
||||||
|
"es/**/style/*",
|
||||||
|
"lib/**/style/*",
|
||||||
|
"*.less"
|
||||||
|
],
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"module": "es/index.js",
|
||||||
"typings": "lib/index.d.ts",
|
"typings": "lib/index.d.ts",
|
||||||
"license": "MIT",
|
"scripts": {
|
||||||
"peerDependencies": {
|
"api-collection": "antd-tools run api-collection",
|
||||||
"react": ">=16.0.0",
|
"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",
|
||||||
"react-dom": ">=16.0.0"
|
"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": {
|
"dependencies": {
|
||||||
"@ant-design/create-react-context": "^0.2.4",
|
"@ant-design/create-react-context": "^0.2.4",
|
||||||
"@ant-design/icons": "^4.0.0-alpha.7",
|
"@ant-design/icons": "^4.0.0-alpha.7",
|
||||||
@ -115,7 +160,7 @@
|
|||||||
"antd-theme-generator": "^1.1.6",
|
"antd-theme-generator": "^1.1.6",
|
||||||
"babel-eslint": "^10.0.1",
|
"babel-eslint": "^10.0.1",
|
||||||
"babel-plugin-add-react-displayname": "^0.0.5",
|
"babel-plugin-add-react-displayname": "^0.0.5",
|
||||||
"bisheng": "^1.3.0",
|
"bisheng": "^1.3.1-alpha.0",
|
||||||
"bisheng-plugin-antd": "^1.2.1",
|
"bisheng-plugin-antd": "^1.2.1",
|
||||||
"bisheng-plugin-description": "^0.1.4",
|
"bisheng-plugin-description": "^0.1.4",
|
||||||
"bisheng-plugin-react": "^1.1.0",
|
"bisheng-plugin-react": "^1.1.0",
|
||||||
@ -141,7 +186,6 @@
|
|||||||
"eslint-plugin-react": "^7.14.2",
|
"eslint-plugin-react": "^7.14.2",
|
||||||
"eslint-tinker": "^0.5.0",
|
"eslint-tinker": "^0.5.0",
|
||||||
"fetch-jsonp": "^1.1.3",
|
"fetch-jsonp": "^1.1.3",
|
||||||
"fs-extra": "^8.1.0",
|
|
||||||
"full-icu": "^1.3.0",
|
"full-icu": "^1.3.0",
|
||||||
"glob": "^7.1.4",
|
"glob": "^7.1.4",
|
||||||
"husky": "^3.0.2",
|
"husky": "^3.0.2",
|
||||||
@ -168,7 +212,6 @@
|
|||||||
"react-copy-to-clipboard": "^5.0.1",
|
"react-copy-to-clipboard": "^5.0.1",
|
||||||
"react-dnd": "^9.0.0",
|
"react-dnd": "^9.0.0",
|
||||||
"react-dnd-html5-backend": "^9.0.0",
|
"react-dnd-html5-backend": "^9.0.0",
|
||||||
"react-document-title": "^2.0.3",
|
|
||||||
"react-dom": "^16.9.0",
|
"react-dom": "^16.9.0",
|
||||||
"react-github-button": "^0.1.11",
|
"react-github-button": "^0.1.11",
|
||||||
"react-helmet": "^6.0.0-beta",
|
"react-helmet": "^6.0.0-beta",
|
||||||
@ -196,58 +239,13 @@
|
|||||||
"xhr2": "^0.2.0",
|
"xhr2": "^0.2.0",
|
||||||
"yaml-front-matter": "^4.0.0"
|
"yaml-front-matter": "^4.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"peerDependencies": {
|
||||||
"test": "jest --config .jest.js --no-cache",
|
"react": ">=16.0.0",
|
||||||
"test-node": "jest --config .jest.node.js --no-cache",
|
"react-dom": ">=16.0.0"
|
||||||
"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"
|
|
||||||
},
|
},
|
||||||
"husky": {
|
"publishConfig": {
|
||||||
"hooks": {
|
"registry": "https://registry.npmjs.org/"
|
||||||
"pre-commit": "pretty-quick --staged"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"sideEffects": [
|
|
||||||
"dist/*",
|
|
||||||
"es/**/style/*",
|
|
||||||
"lib/**/style/*",
|
|
||||||
"*.less"
|
|
||||||
],
|
|
||||||
"browserslist": [
|
|
||||||
"last 2 version",
|
|
||||||
"Firefox ESR",
|
|
||||||
"> 1%",
|
|
||||||
"ie >= 9"
|
|
||||||
],
|
|
||||||
"bundlesize": [
|
"bundlesize": [
|
||||||
{
|
{
|
||||||
"path": "./dist/antd.min.js",
|
"path": "./dist/antd.min.js",
|
||||||
@ -257,5 +255,6 @@
|
|||||||
"path": "./dist/antd.min.css",
|
"path": "./dist/antd.min.css",
|
||||||
"maxSize": "60 kB"
|
"maxSize": "60 kB"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"title": "Ant Design"
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const yfm = require('yaml-front-matter');
|
const yfm = require('yaml-front-matter');
|
||||||
const glob = require('glob');
|
const glob = require('glob');
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs');
|
||||||
|
|
||||||
const demoFiles = glob.sync(path.join(process.cwd(), 'components/**/demo/*.md'));
|
const demoFiles = glob.sync(path.join(process.cwd(), 'components/**/demo/*.md'));
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
|
@ -31,7 +31,7 @@ module.exports = {
|
|||||||
'app.home.design-language': 'Design Language',
|
'app.home.design-language': 'Design Language',
|
||||||
'app.home.solution': 'Solution',
|
'app.home.solution': 'Solution',
|
||||||
'app.home.components-explain':
|
'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-pro-slogan': 'Out-of-the-box front-end / Design solution',
|
||||||
'app.home.product-mobile-slogan':
|
'app.home.product-mobile-slogan':
|
||||||
"antd-mobile is the implementation of Ant Design's mobile specification",
|
"antd-mobile is the implementation of Ant Design's mobile specification",
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html {{ htmlAttributes | safe }}>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta
|
<title>{% if title %}{{ title }}{% else %}{% endif %}</title>
|
||||||
name="description"
|
{% if meta %}{{ meta | safe }}{% endif %}
|
||||||
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>
|
|
||||||
<link
|
<link
|
||||||
rel="icon"
|
rel="icon"
|
||||||
href="https://gw.alipayobjects.com/zos/rmsportal/rlpTLlbMzTNYuZGGCVYM.png"
|
href="https://gw.alipayobjects.com/zos/rmsportal/rlpTLlbMzTNYuZGGCVYM.png"
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import React, { Children, cloneElement } from 'react';
|
import React, { Children, cloneElement } from 'react';
|
||||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
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 { getChildren } from 'jsonml.js/lib/utils';
|
||||||
import { Timeline, Alert, Affix } from 'antd';
|
import { Timeline, Alert, Affix } from 'antd';
|
||||||
import EditButton from './EditButton';
|
import EditButton from './EditButton';
|
||||||
|
import { getMetaDescription } from '../utils';
|
||||||
|
|
||||||
class Article extends React.Component {
|
class Article extends React.Component {
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps) {
|
||||||
@ -72,58 +73,61 @@ class Article extends React.Component {
|
|||||||
const { meta, description } = content;
|
const { meta, description } = content;
|
||||||
const { title, subtitle, filename } = meta;
|
const { title, subtitle, filename } = meta;
|
||||||
const isNotTranslated = locale === 'en-US' && typeof title === 'object';
|
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 (
|
return (
|
||||||
<DocumentTitle title={`${title[locale] || title} - Ant Design`}>
|
/* eslint-disable-next-line */
|
||||||
{/* eslint-disable-next-line */}
|
<article className="markdown" onClick={this.onResourceClick}>
|
||||||
<article className="markdown" onClick={this.onResourceClick}>
|
<Helmet>
|
||||||
{isNotTranslated && (
|
{helmetTitle && <title>{helmetTitle}</title>}
|
||||||
<Alert
|
{helmetTitle && <meta property="og:title" content={helmetTitle} />}
|
||||||
type="warning"
|
{metaDesc && <meta name="description" content={metaDesc} />}
|
||||||
message={
|
</Helmet>
|
||||||
<span>
|
{isNotTranslated && (
|
||||||
This article has not been translated yet. Wanna help us out?
|
<Alert
|
||||||
<a href="https://github.com/ant-design/ant-design/issues/1471">
|
type="warning"
|
||||||
See this issue on GitHub.
|
message={
|
||||||
</a>
|
<span>
|
||||||
</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>
|
||||||
<h1>
|
</span>
|
||||||
{title[locale] || title}
|
}
|
||||||
{!subtitle || locale === 'en-US' ? null : <span className="subtitle">{subtitle}</span>}
|
/>
|
||||||
<EditButton
|
)}
|
||||||
title={<FormattedMessage id="app.content.edit-page" />}
|
<h1>
|
||||||
filename={filename}
|
{title[locale] || title}
|
||||||
/>
|
{!subtitle || locale === 'en-US' ? null : <span className="subtitle">{subtitle}</span>}
|
||||||
</h1>
|
<EditButton title={<FormattedMessage id="app.content.edit-page" />} filename={filename} />
|
||||||
{!description
|
</h1>
|
||||||
? null
|
{!description
|
||||||
: utils.toReactComponent(
|
? null
|
||||||
['section', { className: 'markdown' }].concat(getChildren(description)),
|
: utils.toReactComponent(
|
||||||
)}
|
['section', { className: 'markdown' }].concat(getChildren(description)),
|
||||||
{!content.toc || content.toc.length <= 1 || meta.toc === false ? null : (
|
)}
|
||||||
<Affix className="toc-affix" offsetTop={16}>
|
{!content.toc || content.toc.length <= 1 || meta.toc === false ? null : (
|
||||||
{utils.toReactComponent(
|
<Affix className="toc-affix" offsetTop={16}>
|
||||||
['ul', { className: 'toc' }].concat(getChildren(content.toc)),
|
{utils.toReactComponent(['ul', { className: 'toc' }].concat(getChildren(content.toc)))}
|
||||||
)}
|
</Affix>
|
||||||
</Affix>
|
)}
|
||||||
)}
|
{this.getArticle(
|
||||||
{this.getArticle(
|
utils.toReactComponent(
|
||||||
utils.toReactComponent(
|
['section', { className: 'markdown' }].concat(getChildren(content.content)),
|
||||||
['section', { className: 'markdown' }].concat(getChildren(content.content)),
|
),
|
||||||
),
|
)}
|
||||||
)}
|
{utils.toReactComponent(
|
||||||
{utils.toReactComponent(
|
[
|
||||||
[
|
'section',
|
||||||
'section',
|
{
|
||||||
{
|
className: 'markdown api-container',
|
||||||
className: 'markdown api-container',
|
},
|
||||||
},
|
].concat(getChildren(content.api || ['placeholder'])),
|
||||||
].concat(getChildren(content.api || ['placeholder'])),
|
)}
|
||||||
)}
|
</article>
|
||||||
</article>
|
|
||||||
</DocumentTitle>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import DocumentTitle from 'react-document-title';
|
import { Helmet } from 'react-helmet';
|
||||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Row, Col, Affix, Tooltip } from 'antd';
|
import { Row, Col, Affix, Tooltip } from 'antd';
|
||||||
import { getChildren } from 'jsonml.js/lib/utils';
|
import { getChildren } from 'jsonml.js/lib/utils';
|
||||||
|
import { AppstoreFilled, Appstore } from '@ant-design/icons';
|
||||||
import Demo from './Demo';
|
import Demo from './Demo';
|
||||||
import EditButton from './EditButton';
|
import EditButton from './EditButton';
|
||||||
import Icon from '../Icon';
|
import { ping, getMetaDescription } from '../utils';
|
||||||
import { ping } from '../utils';
|
|
||||||
|
|
||||||
class ComponentDoc extends React.Component {
|
class ComponentDoc extends React.Component {
|
||||||
state = {
|
state = {
|
||||||
@ -107,66 +107,70 @@ class ComponentDoc extends React.Component {
|
|||||||
const articleClassName = classNames({
|
const articleClassName = classNames({
|
||||||
'show-riddle-button': showRiddleButton,
|
'show-riddle-button': showRiddleButton,
|
||||||
});
|
});
|
||||||
|
const helmetTitle = `${subtitle || ''} ${title[locale] || title} - Ant Design`;
|
||||||
|
const contentChild = getMetaDescription(getChildren(content));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DocumentTitle title={`${subtitle || ''} ${title[locale] || title} - Ant Design`}>
|
<article className={articleClassName}>
|
||||||
<article className={articleClassName}>
|
<Helmet>
|
||||||
<Affix className="toc-affix" offsetTop={16}>
|
{helmetTitle && <title>{helmetTitle}</title>}
|
||||||
<ul id="demo-toc" className="toc">
|
{helmetTitle && <meta property="og:title" content={helmetTitle} />}
|
||||||
{jumper}
|
{contentChild && <meta name="description" content={contentChild} />}
|
||||||
</ul>
|
</Helmet>
|
||||||
</Affix>
|
<Affix className="toc-affix" offsetTop={16}>
|
||||||
<section className="markdown">
|
<ul id="demo-toc" className="toc">
|
||||||
<h1>
|
{jumper}
|
||||||
{title[locale] || title}
|
</ul>
|
||||||
{!subtitle ? null : <span className="subtitle">{subtitle}</span>}
|
</Affix>
|
||||||
<EditButton
|
<section className="markdown">
|
||||||
title={<FormattedMessage id="app.content.edit-page" />}
|
<h1>
|
||||||
filename={filename}
|
{title[locale] || title}
|
||||||
/>
|
{!subtitle ? null : <span className="subtitle">{subtitle}</span>}
|
||||||
</h1>
|
<EditButton
|
||||||
{utils.toReactComponent(
|
title={<FormattedMessage id="app.content.edit-page" />}
|
||||||
['section', { className: 'markdown' }].concat(getChildren(content)),
|
filename={filename}
|
||||||
)}
|
/>
|
||||||
<h2>
|
</h1>
|
||||||
<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(
|
{utils.toReactComponent(
|
||||||
[
|
['section', { className: 'markdown' }].concat(getChildren(content)),
|
||||||
'section',
|
|
||||||
{
|
|
||||||
className: 'markdown api-container',
|
|
||||||
},
|
|
||||||
].concat(getChildren(doc.api || ['placeholder'])),
|
|
||||||
)}
|
)}
|
||||||
</article>
|
<h2>
|
||||||
</DocumentTitle>
|
<FormattedMessage id="app.component.examples" />
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id={`app.component.examples.${expandAll ? 'collapse' : 'expand'}`}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className={expandTriggerClass} onClick={this.handleExpandToggle}>
|
||||||
|
{expandAll ? <AppstoreFilled /> : <Appstore />}
|
||||||
|
</span>
|
||||||
|
</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 React from 'react';
|
||||||
import { injectIntl } from 'react-intl';
|
import { injectIntl } from 'react-intl';
|
||||||
import DocumentTitle from 'react-document-title';
|
import { Helmet } from 'react-helmet';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Banner from './Banner';
|
import Banner from './Banner';
|
||||||
import Page1 from './Page1';
|
import Page1 from './Page1';
|
||||||
@ -69,16 +69,17 @@ class Home extends React.Component {
|
|||||||
const { isMobile } = this.context;
|
const { isMobile } = this.context;
|
||||||
const childProps = { ...this.props, isMobile, locale: intl.locale };
|
const childProps = { ...this.props, isMobile, locale: intl.locale };
|
||||||
return (
|
return (
|
||||||
<DocumentTitle title={`Ant Design - ${intl.formatMessage({ id: 'app.home.slogan' })}`}>
|
<>
|
||||||
<>
|
<style dangerouslySetInnerHTML={{ __html: getStyle() }} /> {/* eslint-disable-line */}
|
||||||
<style dangerouslySetInnerHTML={{ __html: getStyle() }} /> {/* eslint-disable-line */}
|
<Helmet>
|
||||||
<Banner {...childProps} />
|
<title>{`Ant Design - ${intl.formatMessage({ id: 'app.home.slogan' })}`}</title>
|
||||||
<Page1 {...childProps} />
|
</Helmet>
|
||||||
<Page2 {...childProps} />
|
<Banner {...childProps} />
|
||||||
<Page3 {...childProps} />
|
<Page1 {...childProps} />
|
||||||
<Footer />
|
<Page2 {...childProps} />
|
||||||
</>
|
<Page3 {...childProps} />
|
||||||
</DocumentTitle>
|
<Footer />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,10 +112,26 @@ export default class Layout extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
const { children, ...restProps } = this.props;
|
const { children, ...restProps } = this.props;
|
||||||
const { appLocale } = this.state;
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<html lang={appLocale.locale === 'zh-CN' ? 'zh' : 'en'} />
|
<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>
|
</Helmet>
|
||||||
<IntlProvider locale={appLocale.locale} messages={appLocale.messages} defaultLocale="en-US">
|
<IntlProvider locale={appLocale.locale} messages={appLocale.messages} defaultLocale="en-US">
|
||||||
<ConfigProvider locale={appLocale.locale === 'zh-CN' ? zhCN : null}>
|
<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) {
|
export function getMenuItems(moduleData, locale, categoryOrder, typeOrder) {
|
||||||
const menuMeta = moduleData.map(item => item.meta).filter(meta => !meta.skip);
|
const menuMeta = moduleData.map(item => item.meta).filter(meta => !meta.skip);
|
||||||
|
|
||||||
@ -109,3 +112,27 @@ export function loadScript(src) {
|
|||||||
document.head.appendChild(script);
|
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