mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-28 13:09:40 +08:00
Merge pull request #23796 from ant-design/master
chore: Merge master into feature
This commit is contained in:
commit
35e390018c
16
.snyk
Normal file
16
.snyk
Normal file
@ -0,0 +1,16 @@
|
||||
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
|
||||
version: v1.14.1
|
||||
ignore: {}
|
||||
# patches apply the minimum changes required to fix a vulnerability
|
||||
patch:
|
||||
SNYK-JS-LODASH-567746:
|
||||
- lodash:
|
||||
patched: '2020-05-01T06:50:59.565Z'
|
||||
- '@ant-design/react-slick > lodash':
|
||||
patched: '2020-05-01T06:50:59.565Z'
|
||||
- rc-steps > lodash:
|
||||
patched: '2020-05-01T06:50:59.565Z'
|
||||
- rc-table > lodash:
|
||||
patched: '2020-05-01T06:50:59.565Z'
|
||||
- rc-tabs > lodash:
|
||||
patched: '2020-05-01T06:50:59.565Z'
|
@ -15,6 +15,61 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 4.2.0
|
||||
|
||||
`2020-04-29`
|
||||
|
||||
- 🆕 List `grid` support all column count like 5. [#23630](https://github.com/ant-design/ant-design/pull/23630)
|
||||
- 🆕 Divider add `plain` prop which allows a non-heading style divider text. [#23405](https://github.com/ant-design/ant-design/pull/23405)
|
||||
- 🆕 Typography `ellipsis` support `onEllipsis` event handler. [#23414](https://github.com/ant-design/ant-design/pull/23414)
|
||||
- 🆕 Space support `align` prop. [#23306](https://github.com/ant-design/ant-design/pull/23306)
|
||||
- 🆕 Upload support `isImageUrl` to force trade file as image. [#23248](https://github.com/ant-design/ant-design/pull/23248) [@onjuju](https://github.com/onjuju)
|
||||
- 🆕 Form.Item support `initialValue` and `getValueProps` props. [#22993](https://github.com/ant-design/ant-design/pull/22993)
|
||||
- ConfigProvider
|
||||
- 🆕 ConfigProvider support `getTargetContainer` to config Affix `target` props. [#23751](https://github.com/ant-design/ant-design/pull/23751)
|
||||
- 🆕 ConfigProvider support `input` prop to config Input `autoComplete`. [#23455](https://github.com/ant-design/ant-design/pull/23455)
|
||||
- 🐞 Fix ConfigProvider `getPopupContainer` not working on DatePicker and Slider. [#23594](https://github.com/ant-design/ant-design/pull/23594) [@hengkx](https://github.com/hengkx)
|
||||
- Table
|
||||
- 🆕 Table `summary` support fixed columns. [#23647](https://github.com/ant-design/ant-design/pull/23647)
|
||||
- 🆕 Table support responsive columns. [#23298](https://github.com/ant-design/ant-design/pull/23298) [@vbudovski](https://github.com/vbudovski)
|
||||
- 🐞 Fix Table pagination default position in RTL. [#23747](https://github.com/ant-design/ant-design/pull/23747)
|
||||
- 🐞 Fix Table crash when `pageSize` is `undefined`. [#23724](https://github.com/ant-design/ant-design/pull/23724)
|
||||
- 🐞 fix Table nested margin when size is `small` or `middle`. [#23602](https://github.com/ant-design/ant-design/pull/23602) [@hengkx](https://github.com/hengkx)
|
||||
- 🐞 Fix RangePicker `ranges` tag color to primary color. [#23705](https://github.com/ant-design/ant-design/pull/23705)
|
||||
- 🐞 Fix Transfer with custom empty style issue. [#23694](https://github.com/ant-design/ant-design/pull/23694) [@hengkx](https://github.com/hengkx)
|
||||
- Input
|
||||
- 🐞 Fix Password caret position. [#23633](https://github.com/ant-design/ant-design/pull/23633) [@huntdream](https://github.com/huntdream)
|
||||
- 💄 Adjust Input.Search icon style. [#23406](https://github.com/ant-design/ant-design/pull/23406)
|
||||
- Button
|
||||
- 🐞 Fix Button align problem of icon only. [#23671](https://github.com/ant-design/ant-design/pull/23671)
|
||||
- 🐞 Fix Button of icon only wrong `loading` style. [#23614](https://github.com/ant-design/ant-design/pull/23614)
|
||||
- 🐞 fix Button cannot be directly called by `react-dnd`. [#23571](https://github.com/ant-design/ant-design/pull/23571) [@hengkx](https://github.com/hengkx)
|
||||
- Menu
|
||||
- 🆕 Menu Item and SubMenu support `icon` prop. [#23629](https://github.com/ant-design/ant-design/pull/23629)
|
||||
- 🐞 Fix Menu duplicated shadow style. [#23664](https://github.com/ant-design/ant-design/pull/23664)
|
||||
- 🐞 Fix Tag cannot be directly called by `react-dnd`. [#23632](https://github.com/ant-design/ant-design/pull/23632) [@hengkx](https://github.com/hengkx)
|
||||
- Anchor
|
||||
- 🐞 Fix Anchor Link with multiple `#` can not jump correctly. [#23595](https://github.com/ant-design/ant-design/pull/23595) [@wuzekang](https://github.com/wuzekang)
|
||||
- 🐞 Fix Input with `suffix` align problem. [#23606](https://github.com/ant-design/ant-design/pull/23606)
|
||||
- 💄 Select arrow won't rotate when open. [#23468](https://github.com/ant-design/ant-design/pull/23468)
|
||||
- 💄 Rate support `direction`. [#23321](https://github.com/ant-design/ant-design/pull/23321)
|
||||
- 💄 Adjust font-size in compact mode. [#23135](https://github.com/ant-design/ant-design/pull/23135)
|
||||
- RTL
|
||||
- 💄 Optimize Result button style in RTL. [#23733](https://github.com/ant-design/ant-design/pull/23733)
|
||||
- 💄 Add Divider RTL support. [#23734](https://github.com/ant-design/ant-design/pull/23734)
|
||||
- 💄 Fix Alert style in RTL when no-icon. [#23714](https://github.com/ant-design/ant-design/pull/23714)
|
||||
- 💄 Optimize Table expand animation and pagination style in RTL. [#23706](https://github.com/ant-design/ant-design/pull/23706)
|
||||
- 💄 Fix Table filter dropdown position in RTL. [#23695](https://github.com/ant-design/ant-design/pull/23695)
|
||||
- 💄 Fix Table rowSelect icon style in RTL. [#23690](https://github.com/ant-design/ant-design/pull/23690)
|
||||
- 💄 Optimize List style in RTL. [#23676](https://github.com/ant-design/ant-design/pull/23676)
|
||||
- 💄 Add Calendar RTL. [#23394](https://github.com/ant-design/ant-design/pull/23394)
|
||||
- 💄 Optimize Input.Search style in RTL. [#23424](https://github.com/ant-design/ant-design/pull/23424)
|
||||
- 💄 Add Notification RTL config. [#23185](https://github.com/ant-design/ant-design/pull/23185)
|
||||
- TypeScript
|
||||
- 🐞 Fix PageHeader `tag` definition. [#23712](https://github.com/ant-design/ant-design/pull/23712) [@hengkx](https://github.com/hengkx)
|
||||
- 🗑 Remove Button deprecated `type="danger"` TypeScript definition and warn it. [#23709](https://github.com/ant-design/ant-design/pull/23709)
|
||||
- 🐞 Fix Table pagination `position` definition. [#23681](https://github.com/ant-design/ant-design/pull/23681) [@hengkx](https://github.com/hengkx)
|
||||
|
||||
## 4.1.5
|
||||
|
||||
`2020-04-25`
|
||||
|
@ -15,6 +15,61 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 4.2.0
|
||||
|
||||
`2020-04-29`
|
||||
|
||||
- 🆕 List `grid` 支持所有分栏数字,比如分为 5 栏。[#23630](https://github.com/ant-design/ant-design/pull/23630)
|
||||
- 🆕 Divider 新增 `plain` 属性,可用于设置一个非标题样式的分割文字。[#23405](https://github.com/ant-design/ant-design/pull/23405)
|
||||
- 🆕 Typography `ellipsis` 支持 `onEllipsis` 事件。[#23414](https://github.com/ant-design/ant-design/pull/23414)
|
||||
- 🆕 Space 支持 `align` 属性。[#23306](https://github.com/ant-design/ant-design/pull/23306)
|
||||
- 🆕 Upload 添加 `isImageUrl` 属性以强制将文件作为图标文件。[#23248](https://github.com/ant-design/ant-design/pull/23248) [@onjuju](https://github.com/onjuju)
|
||||
- 🆕 Form.Item 支持 `initialValue` 和 `getValueProps` 属性。[#22993](https://github.com/ant-design/ant-design/pull/22993)
|
||||
- ConfigProvider
|
||||
- 🆕 ConfigProvider 支持 `getTargetContainer` 以配置 Affix `target` 属性。[#23751](https://github.com/ant-design/ant-design/pull/23751)
|
||||
- 🆕 ConfigProvider 添加 `input` 属性以支持全局化配置 Input `autoComplete` 的默认值。[#23455](https://github.com/ant-design/ant-design/pull/23455)
|
||||
- 🐞 修复 ConfigProvider `getPopupContainer` 对 DatePicker 和 Slider 不生效的问题。[#23594](https://github.com/ant-design/ant-design/pull/23594) [@hengkx](https://github.com/hengkx)
|
||||
- Table
|
||||
- 🆕 Table `summary` 支持固定列。[#23647](https://github.com/ant-design/ant-design/pull/23647)
|
||||
- 🆕 Table 支持响应式展现列。[#23298](https://github.com/ant-design/ant-design/pull/23298) [@vbudovski](https://github.com/vbudovski)
|
||||
- 🐞 修复 Table pagination 在 RTL 下默认位置。[#23747](https://github.com/ant-design/ant-design/pull/23747)
|
||||
- 🐞 修复 Table 在 `pageSize` 是 `undefined` 时崩溃的问题。[#23724](https://github.com/ant-design/ant-design/pull/23724)
|
||||
- 🐞 修复 Table 大小为 `small` 和 `middle` 时嵌套表格错位的问题。[#23602](https://github.com/ant-design/ant-design/pull/23602) [@hengkx](https://github.com/hengkx)
|
||||
- 🐞 修正 RangePicker 范围标签的颜色为主色。[#23705](https://github.com/ant-design/ant-design/pull/23705)
|
||||
- 🐞 修复 Transfer 为空自定义图片样式问题。[#23694](https://github.com/ant-design/ant-design/pull/23694) [@hengkx](https://github.com/hengkx)
|
||||
- Input
|
||||
- 🐞 修复 Password 组件输入光标位置。[#23633](https://github.com/ant-design/ant-design/pull/23633) [@huntdream](https://github.com/huntdream)
|
||||
- 💄 调整 Input.Search 的搜索图标样式。[#23406](https://github.com/ant-design/ant-design/pull/23406)
|
||||
- Button
|
||||
- 🐞 修复 Button 图标类型按钮的对齐问题。[#23671](https://github.com/ant-design/ant-design/pull/23671)
|
||||
- 🐞 修复 Button 图标按钮 `loading` 样式错误的问题。[#23614](https://github.com/ant-design/ant-design/pull/23614)
|
||||
- 🐞 解决 Button 无法直接被 `react-dnd` 调用的问题。[#23571](https://github.com/ant-design/ant-design/pull/23571) [@hengkx](https://github.com/hengkx)
|
||||
- Menu
|
||||
- 🆕 Menu Item 和 SubMenu 新增 `icon` 属性。[#23629](https://github.com/ant-design/ant-design/pull/23629)
|
||||
- 🐞 修复 Menu 菜单重复阴影的问题。[#23664](https://github.com/ant-design/ant-design/pull/23664)
|
||||
- 🐞 解决 Tag 无法直接被 `react-dnd` 调用的问题。[#23632](https://github.com/ant-design/ant-design/pull/23632) [@hengkx](https://github.com/hengkx)
|
||||
- Anchor
|
||||
- 🐞 修复 Anchor Link 包含多个 `#` 时无法跳转的问题。[#23595](https://github.com/ant-design/ant-design/pull/23595) [@wuzekang](https://github.com/wuzekang)
|
||||
- 🐞 修复 Input 带 `suffix` 时的元素对齐问题。[#23606](https://github.com/ant-design/ant-design/pull/23606)
|
||||
- 💄 Select 箭头打开时不再翻转。[#23468](https://github.com/ant-design/ant-design/pull/23468)
|
||||
- 💄 新增 Rate 的 `direction` 支持优化。[#23321](https://github.com/ant-design/ant-design/pull/23321)
|
||||
- 💄 调整紧凑模式下默认的字体大小。[#23135](https://github.com/ant-design/ant-design/pull/23135)
|
||||
- RTL
|
||||
- 💄 优化 Result RTL 下按钮样式。[#23733](https://github.com/ant-design/ant-design/pull/23733)
|
||||
- 💄 新增 Divider RTL 支持。[#23734](https://github.com/ant-design/ant-design/pull/23734)
|
||||
- 💄 修复 Alert 在 RTL 下无 icon 的间隔问题。[#23714](https://github.com/ant-design/ant-design/pull/23714)
|
||||
- 💄 优化 Table RTL 模式下扩展按钮动画与分页样式问题。[#23706](https://github.com/ant-design/ant-design/pull/23706)
|
||||
- 💄 修复 Table 筛选下拉框在 RTL 下的位置。[#23695](https://github.com/ant-design/ant-design/pull/23695)
|
||||
- 💄 修复 Table 勾选框图标 RTL 样式。[#23690](https://github.com/ant-design/ant-design/pull/23690)
|
||||
- 💄 优化 List RTL 样式。[#23676](https://github.com/ant-design/ant-design/pull/23676)
|
||||
- 💄 新增 Calendar RTL 支持。[#23394](https://github.com/ant-design/ant-design/pull/23394)
|
||||
- 💄 优化 Input.Search RTL 样式。[#23424](https://github.com/ant-design/ant-design/pull/23424)
|
||||
- 💄 增加 Notification RTL 设置。[#23185](https://github.com/ant-design/ant-design/pull/23185)
|
||||
- TypeScript
|
||||
- 🐞 修复 PageHeader `tag` 属性定义错误。[#23712](https://github.com/ant-design/ant-design/pull/23712) [@hengkx](https://github.com/hengkx)
|
||||
- 🗑 移除已废弃的 Button `type="danger"` TypeScript 定义并增加警告信息。[#23709](https://github.com/ant-design/ant-design/pull/23709)
|
||||
- 🐞 修复 Table pagination `position` Typescript 定义错误。[#23681](https://github.com/ant-design/ant-design/pull/23681) [@hengkx](https://github.com/hengkx)
|
||||
|
||||
## 4.1.5
|
||||
|
||||
`2020-04-25`
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import * as React from 'react';
|
||||
|
||||
export function fillRef<T>(ref: React.Ref<T>, node: T) {
|
||||
if (typeof ref === 'function') {
|
||||
|
@ -1,360 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Anchor from '..';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
describe('Anchor Render', () => {
|
||||
const getBoundingClientRectMock = jest.spyOn(
|
||||
HTMLHeadingElement.prototype,
|
||||
'getBoundingClientRect',
|
||||
);
|
||||
const getClientRectsMock = jest.spyOn(HTMLHeadingElement.prototype, 'getClientRects');
|
||||
|
||||
beforeAll(() => {
|
||||
getBoundingClientRectMock.mockReturnValue({
|
||||
width: 100,
|
||||
height: 100,
|
||||
top: 1000,
|
||||
});
|
||||
getClientRectsMock.mockReturnValue({ length: 1 });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
getBoundingClientRectMock.mockRestore();
|
||||
getClientRectsMock.mockRestore();
|
||||
});
|
||||
|
||||
it('Anchor render perfectly', () => {
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="#API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
wrapper.find('a[href="#API"]').simulate('click');
|
||||
|
||||
wrapper.instance().handleScroll();
|
||||
expect(wrapper.instance().state).not.toBe(null);
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - click', () => {
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="http://www.example.com/#API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.find('a[href="http://www.example.com/#API"]').simulate('click');
|
||||
expect(wrapper.instance().state.activeLink).toBe('http://www.example.com/#API');
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - hash router', async () => {
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
let root = document.getElementById('root');
|
||||
if (!root) {
|
||||
root = document.createElement('div', { id: 'root' });
|
||||
root.id = 'root';
|
||||
document.body.appendChild(root);
|
||||
}
|
||||
mount(<div id="/faq?locale=en#Q1">Q1</div>, { attachTo: root });
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="/#/faq?locale=en#Q1" title="Q1" />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
wrapper.instance().handleScrollTo('/#/faq?locale=en#Q1');
|
||||
expect(wrapper.instance().state.activeLink).toBe('/#/faq?locale=en#Q1');
|
||||
expect(scrollToSpy).not.toHaveBeenCalled();
|
||||
await sleep(1000);
|
||||
expect(scrollToSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - scroll', () => {
|
||||
let root = document.getElementById('root');
|
||||
if (!root) {
|
||||
root = document.createElement('div', { id: 'root' });
|
||||
root.id = 'root';
|
||||
document.body.appendChild(root);
|
||||
}
|
||||
mount(<div id="API">Hello</div>, { attachTo: root });
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="http://www.example.com/#API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.instance().handleScroll();
|
||||
expect(wrapper.instance().state.activeLink).toBe('http://www.example.com/#API');
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - scrollTo', async () => {
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
let root = document.getElementById('root');
|
||||
if (!root) {
|
||||
root = document.createElement('div', { id: 'root' });
|
||||
root.id = 'root';
|
||||
document.body.appendChild(root);
|
||||
}
|
||||
mount(<div id="#API">Hello</div>, { attachTo: root });
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="##API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.instance().handleScrollTo('##API');
|
||||
expect(wrapper.instance().state.activeLink).toBe('##API');
|
||||
const calls = scrollToSpy.mock.calls.length;
|
||||
await sleep(1000);
|
||||
expect(scrollToSpy.mock.calls.length).toBeGreaterThan(calls);
|
||||
});
|
||||
|
||||
it('should remove listener when unmount', async () => {
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="#API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
const removeListenerSpy = jest.spyOn(wrapper.instance().scrollEvent, 'remove');
|
||||
wrapper.unmount();
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should unregister link when unmount children', async () => {
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="#API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
expect(wrapper.instance().links).toEqual(['#API']);
|
||||
wrapper.setProps({ children: null });
|
||||
expect(wrapper.instance().links).toEqual([]);
|
||||
});
|
||||
|
||||
it('should update links when link href update', async () => {
|
||||
let anchorInstance = null;
|
||||
function AnchorUpdate({ href }) {
|
||||
return (
|
||||
<Anchor
|
||||
ref={c => {
|
||||
anchorInstance = c;
|
||||
}}
|
||||
>
|
||||
<Link href={href} title="API" />
|
||||
</Anchor>
|
||||
);
|
||||
}
|
||||
const wrapper = mount(<AnchorUpdate href="#API" />);
|
||||
|
||||
expect(anchorInstance.links).toEqual(['#API']);
|
||||
wrapper.setProps({ href: '#API_1' });
|
||||
expect(anchorInstance.links).toEqual(['#API_1']);
|
||||
});
|
||||
|
||||
it('Anchor onClick event', () => {
|
||||
let event;
|
||||
let link;
|
||||
const handleClick = (...arg) => {
|
||||
[event, link] = arg;
|
||||
};
|
||||
|
||||
const href = '#API';
|
||||
const title = 'API';
|
||||
|
||||
const wrapper = mount(
|
||||
<Anchor onClick={handleClick}>
|
||||
<Link href={href} title={title} />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
wrapper.find(`a[href="${href}"]`).simulate('click');
|
||||
|
||||
wrapper.instance().handleScroll();
|
||||
expect(event).not.toBe(undefined);
|
||||
expect(link).toEqual({ href, title });
|
||||
});
|
||||
|
||||
it('Different function returns the same DOM', async () => {
|
||||
let root = document.getElementById('root');
|
||||
if (!root) {
|
||||
root = document.createElement('div', { id: 'root' });
|
||||
root.id = 'root';
|
||||
document.body.appendChild(root);
|
||||
}
|
||||
mount(<div id="API">Hello</div>, { attachTo: root });
|
||||
const getContainerA = () => {
|
||||
return document.getElementById('API');
|
||||
};
|
||||
const getContainerB = () => {
|
||||
return document.getElementById('API');
|
||||
};
|
||||
|
||||
const wrapper = mount(
|
||||
<Anchor getContainer={getContainerA}>
|
||||
<Link href="#API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
const removeListenerSpy = jest.spyOn(wrapper.instance().scrollEvent, 'remove');
|
||||
await sleep(1000);
|
||||
wrapper.setProps({ getContainer: getContainerB });
|
||||
expect(removeListenerSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Different function returns different DOM', async () => {
|
||||
let root = document.getElementById('root');
|
||||
if (!root) {
|
||||
root = document.createElement('div', { id: 'root' });
|
||||
root.id = 'root';
|
||||
document.body.appendChild(root);
|
||||
}
|
||||
mount(
|
||||
<div>
|
||||
<div id="API1">Hello</div>
|
||||
<div id="API2">World</div>
|
||||
</div>,
|
||||
{ attachTo: root },
|
||||
);
|
||||
const getContainerA = () => {
|
||||
return document.getElementById('API1');
|
||||
};
|
||||
const getContainerB = () => {
|
||||
return document.getElementById('API2');
|
||||
};
|
||||
const wrapper = mount(
|
||||
<Anchor getContainer={getContainerA}>
|
||||
<Link href="#API1" title="API1" />
|
||||
<Link href="#API2" title="API2" />
|
||||
</Anchor>,
|
||||
);
|
||||
const removeListenerSpy = jest.spyOn(wrapper.instance().scrollEvent, 'remove');
|
||||
expect(removeListenerSpy).not.toHaveBeenCalled();
|
||||
await sleep(1000);
|
||||
wrapper.setProps({ getContainer: getContainerB });
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Same function returns the same DOM', () => {
|
||||
let root = document.getElementById('root');
|
||||
if (!root) {
|
||||
root = document.createElement('div', { id: 'root' });
|
||||
root.id = 'root';
|
||||
document.body.appendChild(root);
|
||||
}
|
||||
mount(<div id="API">Hello</div>, { attachTo: root });
|
||||
const getContainer = () => document.getElementById('API');
|
||||
const wrapper = mount(
|
||||
<Anchor getContainer={getContainer}>
|
||||
<Link href="#API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.find('a[href="#API"]').simulate('click');
|
||||
wrapper.instance().handleScroll();
|
||||
expect(wrapper.instance().state).not.toBe(null);
|
||||
});
|
||||
|
||||
it('Same function returns different DOM', async () => {
|
||||
let root = document.getElementById('root');
|
||||
if (!root) {
|
||||
root = document.createElement('div', { id: 'root' });
|
||||
root.id = 'root';
|
||||
document.body.appendChild(root);
|
||||
}
|
||||
mount(
|
||||
<div>
|
||||
<div id="API1">Hello</div>
|
||||
<div id="API2">World</div>
|
||||
</div>,
|
||||
{ attachTo: root },
|
||||
);
|
||||
const holdContainer = {
|
||||
container: document.getElementById('API1'),
|
||||
};
|
||||
const getContainer = () => {
|
||||
return holdContainer.container;
|
||||
};
|
||||
const wrapper = mount(
|
||||
<Anchor getContainer={getContainer}>
|
||||
<Link href="#API1" title="API1" />
|
||||
<Link href="#API2" title="API2" />
|
||||
</Anchor>,
|
||||
);
|
||||
const removeListenerSpy = jest.spyOn(wrapper.instance().scrollEvent, 'remove');
|
||||
expect(removeListenerSpy).not.toHaveBeenCalled();
|
||||
await sleep(1000);
|
||||
holdContainer.container = document.getElementById('API2');
|
||||
wrapper.setProps({ 'data-only-trigger-re-render': true });
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Anchor getCurrentAnchor prop', () => {
|
||||
const getCurrentAnchor = () => '#API2';
|
||||
const wrapper = mount(
|
||||
<Anchor getCurrentAnchor={getCurrentAnchor}>
|
||||
<Link href="#API1" title="API1" />
|
||||
<Link href="#API2" title="API2" />
|
||||
</Anchor>,
|
||||
);
|
||||
expect(wrapper.instance().state.activeLink).toBe('#API2');
|
||||
});
|
||||
|
||||
it('Anchor targetOffset prop', async () => {
|
||||
let dateNowMock;
|
||||
|
||||
function dataNowMockFn() {
|
||||
let start = 0;
|
||||
|
||||
const handler = () => {
|
||||
return (start += 1000);
|
||||
};
|
||||
|
||||
return jest.spyOn(Date, 'now').mockImplementation(handler);
|
||||
}
|
||||
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
let root = document.getElementById('root');
|
||||
if (!root) {
|
||||
root = document.createElement('div', { id: 'root' });
|
||||
root.id = 'root';
|
||||
document.body.appendChild(root);
|
||||
}
|
||||
mount(<h1 id="API">Hello</h1>, { attachTo: root });
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="#API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.instance().handleScrollTo('#API');
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 1000);
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
wrapper.setProps({ offsetTop: 100 });
|
||||
wrapper.instance().handleScrollTo('#API');
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 900);
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
wrapper.setProps({ targetOffset: 200 });
|
||||
wrapper.instance().handleScrollTo('#API');
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
|
||||
|
||||
dateNowMock.mockRestore();
|
||||
});
|
||||
|
||||
it('Anchor onChange prop', async () => {
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mount(
|
||||
<Anchor onChange={onChange}>
|
||||
<Link href="#API1" title="API1" />
|
||||
<Link href="#API2" title="API2" />
|
||||
</Anchor>,
|
||||
);
|
||||
expect(onChange).toHaveBeenCalledTimes(1);
|
||||
wrapper.instance().handleScrollTo('#API2');
|
||||
expect(onChange).toHaveBeenCalledTimes(2);
|
||||
expect(onChange).toHaveBeenCalledWith('#API2');
|
||||
});
|
||||
});
|
360
components/anchor/__tests__/Anchor.test.tsx
Normal file
360
components/anchor/__tests__/Anchor.test.tsx
Normal file
@ -0,0 +1,360 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Anchor from '..';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
function createGetContainer(id: string) {
|
||||
return () => {
|
||||
const container = document.getElementById(id);
|
||||
if (container == null) {
|
||||
throw new Error();
|
||||
}
|
||||
return container;
|
||||
};
|
||||
}
|
||||
|
||||
function createDiv() {
|
||||
const root = document.createElement('div');
|
||||
document.body.appendChild(root);
|
||||
return root;
|
||||
}
|
||||
|
||||
let idCounter = 0;
|
||||
const getHashUrl = () => `Anchor-API-${idCounter++}`;
|
||||
|
||||
describe('Anchor Render', () => {
|
||||
const getBoundingClientRectMock = jest.spyOn(
|
||||
HTMLHeadingElement.prototype,
|
||||
'getBoundingClientRect',
|
||||
);
|
||||
const getClientRectsMock = jest.spyOn(HTMLHeadingElement.prototype, 'getClientRects');
|
||||
|
||||
beforeAll(() => {
|
||||
getBoundingClientRectMock.mockReturnValue({
|
||||
width: 100,
|
||||
height: 100,
|
||||
top: 1000,
|
||||
} as DOMRect);
|
||||
getClientRectsMock.mockReturnValue({ length: 1 } as DOMRectList);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
getBoundingClientRectMock.mockRestore();
|
||||
getClientRectsMock.mockRestore();
|
||||
});
|
||||
|
||||
it('Anchor render perfectly', () => {
|
||||
const hash = getHashUrl();
|
||||
const wrapper = mount<Anchor>(
|
||||
<Anchor>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
wrapper.find(`a[href="#${hash}"]`).simulate('click');
|
||||
|
||||
wrapper.instance().handleScroll();
|
||||
expect(wrapper.instance().state).not.toBe(null);
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - click', () => {
|
||||
const hash = getHashUrl();
|
||||
const wrapper = mount<Anchor>(
|
||||
<Anchor>
|
||||
<Link href={`http://www.example.com/#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.find(`a[href="http://www.example.com/#${hash}"]`).simulate('click');
|
||||
expect(wrapper.instance().state.activeLink).toBe(`http://www.example.com/#${hash}`);
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - hash router', async () => {
|
||||
const root = createDiv();
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
mount(<div id="/faq?locale=en#Q1">Q1</div>, { attachTo: root });
|
||||
const wrapper = mount<Anchor>(
|
||||
<Anchor>
|
||||
<Link href="/#/faq?locale=en#Q1" title="Q1" />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
wrapper.instance().handleScrollTo('/#/faq?locale=en#Q1');
|
||||
expect(wrapper.instance().state.activeLink).toBe('/#/faq?locale=en#Q1');
|
||||
expect(scrollToSpy).not.toHaveBeenCalled();
|
||||
await sleep(1000);
|
||||
expect(scrollToSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - scroll', () => {
|
||||
const hash = getHashUrl();
|
||||
const root = createDiv();
|
||||
mount(<div id={hash}>Hello</div>, { attachTo: root });
|
||||
const wrapper = mount<Anchor>(
|
||||
<Anchor>
|
||||
<Link href={`http://www.example.com/#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.instance().handleScroll();
|
||||
expect(wrapper.instance().state.activeLink).toBe(`http://www.example.com/#${hash}`);
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - scrollTo', async () => {
|
||||
const hash = getHashUrl();
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
const root = createDiv();
|
||||
mount(<div id={`#${hash}`}>Hello</div>, { attachTo: root });
|
||||
const wrapper = mount<Anchor>(
|
||||
<Anchor>
|
||||
<Link href={`##${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.instance().handleScrollTo(`##${hash}`);
|
||||
expect(wrapper.instance().state.activeLink).toBe(`##${hash}`);
|
||||
const calls = scrollToSpy.mock.calls.length;
|
||||
await sleep(1000);
|
||||
expect(scrollToSpy.mock.calls.length).toBeGreaterThan(calls);
|
||||
});
|
||||
|
||||
it('should remove listener when unmount', async () => {
|
||||
const hash = getHashUrl();
|
||||
const wrapper = mount<Anchor>(
|
||||
<Anchor>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
const removeListenerSpy = jest.spyOn((wrapper.instance() as any).scrollEvent, 'remove');
|
||||
wrapper.unmount();
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should unregister link when unmount children', async () => {
|
||||
const hash = getHashUrl();
|
||||
const wrapper = mount<Anchor>(
|
||||
<Anchor>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
expect((wrapper.instance() as any).links).toEqual([`#${hash}`]);
|
||||
wrapper.setProps({ children: null });
|
||||
expect((wrapper.instance() as any).links).toEqual([]);
|
||||
});
|
||||
|
||||
it('should update links when link href update', async () => {
|
||||
const hash = getHashUrl();
|
||||
let anchorInstance: Anchor | null = null;
|
||||
function AnchorUpdate({ href }: { href: string }) {
|
||||
return (
|
||||
<Anchor
|
||||
ref={c => {
|
||||
anchorInstance = c;
|
||||
}}
|
||||
>
|
||||
<Link href={href} title={hash} />
|
||||
</Anchor>
|
||||
);
|
||||
}
|
||||
const wrapper = mount(<AnchorUpdate href={`#${hash}`} />);
|
||||
|
||||
if (anchorInstance == null) {
|
||||
throw new Error('anchorInstance should not be null');
|
||||
}
|
||||
expect((anchorInstance as any).links).toEqual([`#${hash}`]);
|
||||
wrapper.setProps({ href: `#${hash}_1` });
|
||||
expect((anchorInstance as any).links).toEqual([`#${hash}_1`]);
|
||||
});
|
||||
|
||||
it('Anchor onClick event', () => {
|
||||
const hash = getHashUrl();
|
||||
let event;
|
||||
let link;
|
||||
const handleClick = (
|
||||
e: React.MouseEvent<HTMLElement>,
|
||||
_link: { title: React.ReactNode; href: string },
|
||||
) => {
|
||||
event = e;
|
||||
link = _link;
|
||||
};
|
||||
|
||||
const href = `#${hash}`;
|
||||
const title = hash;
|
||||
|
||||
const wrapper = mount<Anchor>(
|
||||
<Anchor onClick={handleClick}>
|
||||
<Link href={href} title={title} />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
wrapper.find(`a[href="${href}"]`).simulate('click');
|
||||
|
||||
wrapper.instance().handleScroll();
|
||||
expect(event).not.toBe(undefined);
|
||||
expect(link).toEqual({ href, title });
|
||||
});
|
||||
|
||||
it('Different function returns the same DOM', async () => {
|
||||
const hash = getHashUrl();
|
||||
const root = createDiv();
|
||||
mount(<div id={hash}>Hello</div>, { attachTo: root });
|
||||
const getContainerA = createGetContainer(hash);
|
||||
const getContainerB = createGetContainer(hash);
|
||||
|
||||
const wrapper = mount<Anchor>(
|
||||
<Anchor getContainer={getContainerA}>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
const removeListenerSpy = jest.spyOn((wrapper.instance() as any).scrollEvent, 'remove');
|
||||
await sleep(1000);
|
||||
wrapper.setProps({ getContainer: getContainerB });
|
||||
expect(removeListenerSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Different function returns different DOM', async () => {
|
||||
const hash1 = getHashUrl();
|
||||
const hash2 = getHashUrl();
|
||||
const root = createDiv();
|
||||
mount(
|
||||
<div>
|
||||
<div id={hash1}>Hello</div>
|
||||
<div id={hash2}>World</div>
|
||||
</div>,
|
||||
{ attachTo: root },
|
||||
);
|
||||
const getContainerA = createGetContainer(hash1);
|
||||
const getContainerB = createGetContainer(hash2);
|
||||
const wrapper = mount<Anchor>(
|
||||
<Anchor getContainer={getContainerA}>
|
||||
<Link href={`#${hash1}`} title={hash1} />
|
||||
<Link href={`#${hash2}`} title={hash2} />
|
||||
</Anchor>,
|
||||
);
|
||||
const removeListenerSpy = jest.spyOn((wrapper.instance() as any).scrollEvent, 'remove');
|
||||
expect(removeListenerSpy).not.toHaveBeenCalled();
|
||||
await sleep(1000);
|
||||
wrapper.setProps({ getContainer: getContainerB });
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Same function returns the same DOM', () => {
|
||||
const hash = getHashUrl();
|
||||
const root = createDiv();
|
||||
mount(<div id={hash}>Hello</div>, { attachTo: root });
|
||||
const getContainer = createGetContainer(hash);
|
||||
const wrapper = mount(
|
||||
<Anchor getContainer={getContainer}>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.find(`a[href="#${hash}"]`).simulate('click');
|
||||
(wrapper.instance() as any).handleScroll();
|
||||
expect(wrapper.instance().state).not.toBe(null);
|
||||
});
|
||||
|
||||
it('Same function returns different DOM', async () => {
|
||||
const hash1 = getHashUrl();
|
||||
const hash2 = getHashUrl();
|
||||
const root = createDiv();
|
||||
mount(
|
||||
<div>
|
||||
<div id={hash1}>Hello</div>
|
||||
<div id={hash2}>World</div>
|
||||
</div>,
|
||||
{ attachTo: root },
|
||||
);
|
||||
const holdContainer = {
|
||||
container: document.getElementById(hash1),
|
||||
};
|
||||
const getContainer = () => {
|
||||
if (holdContainer.container == null) {
|
||||
throw new Error('container should not be null');
|
||||
}
|
||||
return holdContainer.container;
|
||||
};
|
||||
const wrapper = mount(
|
||||
<Anchor getContainer={getContainer}>
|
||||
<Link href={`#${hash1}`} title={hash1} />
|
||||
<Link href={`#${hash2}`} title={hash2} />
|
||||
</Anchor>,
|
||||
);
|
||||
const removeListenerSpy = jest.spyOn((wrapper.instance() as any).scrollEvent, 'remove');
|
||||
expect(removeListenerSpy).not.toHaveBeenCalled();
|
||||
await sleep(1000);
|
||||
holdContainer.container = document.getElementById(hash2);
|
||||
wrapper.setProps({ 'data-only-trigger-re-render': true });
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Anchor getCurrentAnchor prop', () => {
|
||||
const hash1 = getHashUrl();
|
||||
const hash2 = getHashUrl();
|
||||
const getCurrentAnchor = () => `#${hash2}`;
|
||||
const wrapper = mount<Anchor>(
|
||||
<Anchor getCurrentAnchor={getCurrentAnchor}>
|
||||
<Link href={`#${hash1}`} title={hash1} />
|
||||
<Link href={`#${hash2}`} title={hash2} />
|
||||
</Anchor>,
|
||||
);
|
||||
expect(wrapper.instance().state.activeLink).toBe(`#${hash2}`);
|
||||
});
|
||||
|
||||
it('Anchor targetOffset prop', async () => {
|
||||
const hash = getHashUrl();
|
||||
let dateNowMock;
|
||||
|
||||
function dataNowMockFn() {
|
||||
let start = 0;
|
||||
|
||||
const handler = () => {
|
||||
return (start += 1000);
|
||||
};
|
||||
|
||||
return jest.spyOn(Date, 'now').mockImplementation(handler);
|
||||
}
|
||||
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
const root = createDiv();
|
||||
mount(<h1 id={hash}>Hello</h1>, { attachTo: root });
|
||||
const wrapper = mount<Anchor>(
|
||||
<Anchor>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.instance().handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 1000);
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
wrapper.setProps({ offsetTop: 100 });
|
||||
wrapper.instance().handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 900);
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
wrapper.setProps({ targetOffset: 200 });
|
||||
wrapper.instance().handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
|
||||
|
||||
dateNowMock.mockRestore();
|
||||
});
|
||||
|
||||
it('Anchor onChange prop', async () => {
|
||||
const hash1 = getHashUrl();
|
||||
const hash2 = getHashUrl();
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mount<Anchor>(
|
||||
<Anchor onChange={onChange}>
|
||||
<Link href={`#${hash1}`} title={hash1} />
|
||||
<Link href={`#${hash2}`} title={hash2} />
|
||||
</Anchor>,
|
||||
);
|
||||
expect(onChange).toHaveBeenCalledTimes(1);
|
||||
wrapper.instance().handleScrollTo(hash2);
|
||||
expect(onChange).toHaveBeenCalledTimes(2);
|
||||
expect(onChange).toHaveBeenCalledWith(hash2);
|
||||
});
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import * as React from 'react';
|
||||
import { AntAnchor } from './Anchor';
|
||||
|
||||
const AnchorContext = React.createContext<AntAnchor>(null as any);
|
||||
|
@ -150,13 +150,18 @@
|
||||
}
|
||||
|
||||
& > &-loading-icon {
|
||||
padding-right: @margin-xs;
|
||||
transition: all 0.3s @ease-in-out;
|
||||
|
||||
.@{iconfont-css-prefix} {
|
||||
padding-right: @margin-xs;
|
||||
}
|
||||
|
||||
&:only-child {
|
||||
.@{iconfont-css-prefix} {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-group {
|
||||
.btn-group(@btn-prefix-cls);
|
||||
|
@ -66,8 +66,14 @@ exports[`renders ./components/drawer/demo/multi-level-drawer.md correctly 1`] =
|
||||
exports[`renders ./components/drawer/demo/placement.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-radio-group ant-radio-group-outline"
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<div
|
||||
class="ant-radio-group ant-radio-group-outline"
|
||||
>
|
||||
<label
|
||||
class="ant-radio-wrapper"
|
||||
@ -147,6 +153,10 @@ exports[`renders ./components/drawer/demo/placement.md correctly 1`] = `
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
@ -155,6 +165,8 @@ exports[`renders ./components/drawer/demo/placement.md correctly 1`] = `
|
||||
Open
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
@ -14,7 +14,7 @@ title:
|
||||
The Drawer can appear from any edge of the screen.
|
||||
|
||||
```jsx
|
||||
import { Drawer, Button, Radio } from 'antd';
|
||||
import { Drawer, Button, Radio, Space } from 'antd';
|
||||
|
||||
const RadioGroup = Radio.Group;
|
||||
|
||||
@ -42,11 +42,8 @@ class App extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<RadioGroup
|
||||
style={{ marginRight: 8 }}
|
||||
defaultValue={this.state.placement}
|
||||
onChange={this.onChange}
|
||||
>
|
||||
<Space>
|
||||
<RadioGroup defaultValue={this.state.placement} onChange={this.onChange}>
|
||||
<Radio value="top">top</Radio>
|
||||
<Radio value="right">right</Radio>
|
||||
<Radio value="bottom">bottom</Radio>
|
||||
@ -55,6 +52,7 @@ class App extends React.Component {
|
||||
<Button type="primary" onClick={this.showDrawer}>
|
||||
Open
|
||||
</Button>
|
||||
</Space>
|
||||
<Drawer
|
||||
title="Basic Drawer"
|
||||
placement={this.state.placement}
|
||||
|
@ -194,7 +194,7 @@ Provide linkage between forms. If a sub form with `name` prop update, it will au
|
||||
| isFieldValidating | Check fields if is in validating | (name: [NamePath](#NamePath)) => boolean |
|
||||
| resetFields | Reset fields to `initialValues` | (fields?: [NamePath](#NamePath)[]) => void |
|
||||
| scrollToField | Scroll to field position | (name: [NamePath](#NamePath), options: [[ScrollOptions](https://github.com/stipsan/scroll-into-view-if-needed/blob/ece40bd9143f48caf4b99503425ecb16b0ad8249/src/types.ts#L10)]) => void |
|
||||
| setFields | Set fields status | (fields: FieldData[]) => void |
|
||||
| setFields | Set fields status | (fields: [FieldData](#FieldData)[]) => void |
|
||||
| setFieldsValue | Set fields value | (values) => void |
|
||||
| submit | Submit the form. It's same as click `submit` button | () => void |
|
||||
| validateFields | Validate fields | (nameList?: [NamePath](#NamePath)[]) => Promise |
|
||||
@ -325,6 +325,16 @@ In most case, we always recommend to use Form `initialValues`. Use Item `initial
|
||||
1. Form `initialValues` is the first priority
|
||||
2. Field `initialValue` is secondary \*. Not work when multiple Item with same `name` setting the `initialValue`
|
||||
|
||||
### Why `onFieldsChange` trigger three times on change when field set `rules`?
|
||||
|
||||
Validating is also part of the value updating. It pass follow steps:
|
||||
|
||||
1. Trigger value change
|
||||
2. Rule validating
|
||||
3. Rule validated
|
||||
|
||||
In each `onFieldsChange`, you will get `false` > `true` > `false` with `isFieldValidating`.
|
||||
|
||||
<style>
|
||||
.site-form-item-icon {
|
||||
color: rgba(0, 0, 0, 0.25);
|
||||
|
@ -195,7 +195,7 @@ Form 通过增量更新方式,只更新被修改的字段相关组件以达到
|
||||
| isFieldValidating | 检查一组字段是否正在校验 | (name: [NamePath](#NamePath)) => boolean |
|
||||
| resetFields | 重置一组字段到 `initialValues` | (fields?: [NamePath](#NamePath)[]) => void |
|
||||
| scrollToField | 滚动到对应字段位置 | (name: [NamePath](#NamePath), options: [[ScrollOptions](https://github.com/stipsan/scroll-into-view-if-needed/blob/ece40bd9143f48caf4b99503425ecb16b0ad8249/src/types.ts#L10)]) => void |
|
||||
| setFields | 设置一组字段状态 | (fields: FieldData[]) => void |
|
||||
| setFields | 设置一组字段状态 | (fields: [FieldData](#FieldData)[]) => void |
|
||||
| setFieldsValue | 设置表单的值 | (values) => void |
|
||||
| submit | 提交表单,与点击 `submit` 按钮效果相同 | () => void |
|
||||
| validateFields | 触发表单验证 | (nameList?: [NamePath](#NamePath)[]) => Promise |
|
||||
@ -326,6 +326,16 @@ validator(rule, value, callback) => {
|
||||
1. Form 的 `initialValues` 拥有最高优先级
|
||||
2. Field 的 `initialValue` 次之 \*. 多个同 `name` Item 都设置 `initialValue` 时,则 Item 的 `initialValue` 不生效
|
||||
|
||||
### 为什么字段设置 `rules` 后更改值 `onFieldsChange` 会触发三次?
|
||||
|
||||
字段除了本身的值变化外,校验也是其状态之一。因而在触发字段变化会经历以下几个阶段:
|
||||
|
||||
1. Trigger value change
|
||||
2. Rule validating
|
||||
3. Rule validated
|
||||
|
||||
在触发过程中,调用 `isFieldValidating` 会经历 `false` > `true` > `false` 的变化过程。
|
||||
|
||||
<style>
|
||||
.site-form-item-icon {
|
||||
color: rgba(0, 0, 0, 0.25);
|
||||
|
@ -16,30 +16,26 @@ A simple playground for column count and gutter.
|
||||
```jsx
|
||||
import { Row, Col, Slider } from 'antd';
|
||||
|
||||
const gutters = {};
|
||||
const vgutters = {};
|
||||
const colCounts = {};
|
||||
|
||||
[8, 16, 24, 32, 40, 48].forEach((value, i) => {
|
||||
gutters[i] = value;
|
||||
});
|
||||
[8, 16, 24, 32, 40, 48].forEach((value, i) => {
|
||||
vgutters[i] = value;
|
||||
});
|
||||
[2, 3, 4, 6, 8, 12].forEach((value, i) => {
|
||||
colCounts[i] = value;
|
||||
});
|
||||
|
||||
class App extends React.Component {
|
||||
gutters = {};
|
||||
|
||||
vgutters = {};
|
||||
|
||||
colCounts = {};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
state = {
|
||||
gutterKey: 1,
|
||||
vgutterKey: 1,
|
||||
colCountKey: 2,
|
||||
};
|
||||
[8, 16, 24, 32, 40, 48].forEach((value, i) => {
|
||||
this.gutters[i] = value;
|
||||
});
|
||||
[8, 16, 24, 32, 40, 48].forEach((value, i) => {
|
||||
this.vgutters[i] = value;
|
||||
});
|
||||
[2, 3, 4, 6, 8, 12].forEach((value, i) => {
|
||||
this.colCounts[i] = value;
|
||||
});
|
||||
}
|
||||
|
||||
onGutterChange = gutterKey => {
|
||||
this.setState({ gutterKey });
|
||||
@ -56,7 +52,7 @@ class App extends React.Component {
|
||||
render() {
|
||||
const { gutterKey, vgutterKey, colCountKey } = this.state;
|
||||
const cols = [];
|
||||
const colCount = this.colCounts[colCountKey];
|
||||
const colCount = colCounts[colCountKey];
|
||||
let colCode = '';
|
||||
for (let i = 0; i < colCount; i++) {
|
||||
cols.push(
|
||||
@ -72,39 +68,42 @@ class App extends React.Component {
|
||||
<div style={{ width: '50%' }}>
|
||||
<Slider
|
||||
min={0}
|
||||
max={Object.keys(this.gutters).length - 1}
|
||||
max={Object.keys(gutters).length - 1}
|
||||
value={gutterKey}
|
||||
onChange={this.onGutterChange}
|
||||
marks={this.gutters}
|
||||
marks={gutters}
|
||||
step={null}
|
||||
tipFormatter={value => gutters[value]}
|
||||
/>
|
||||
</div>
|
||||
<span style={{ marginRight: 6 }}>Vertical Gutter (px): </span>
|
||||
<div style={{ width: '50%' }}>
|
||||
<Slider
|
||||
min={0}
|
||||
max={Object.keys(this.vgutters).length - 1}
|
||||
max={Object.keys(vgutters).length - 1}
|
||||
value={vgutterKey}
|
||||
onChange={this.onVGutterChange}
|
||||
marks={this.vgutters}
|
||||
marks={vgutters}
|
||||
step={null}
|
||||
tipFormatter={value => vgutters[value]}
|
||||
/>
|
||||
</div>
|
||||
<span style={{ marginRight: 6 }}>Column Count:</span>
|
||||
<div style={{ width: '50%', marginBottom: 48 }}>
|
||||
<Slider
|
||||
min={0}
|
||||
max={Object.keys(this.colCounts).length - 1}
|
||||
max={Object.keys(colCounts).length - 1}
|
||||
value={colCountKey}
|
||||
onChange={this.onColCountChange}
|
||||
marks={this.colCounts}
|
||||
marks={colCounts}
|
||||
step={null}
|
||||
tipFormatter={value => colCounts[value]}
|
||||
/>
|
||||
</div>
|
||||
<Row gutter={[this.gutters[gutterKey], this.vgutters[vgutterKey]]}>{cols}</Row>
|
||||
<Row gutter={[this.gutters[gutterKey], this.vgutters[vgutterKey]]}>{cols}</Row>
|
||||
<pre className="demo-code">{`<Row gutter={[${this.gutters[gutterKey]}, ${this.vgutters[vgutterKey]}]}>\n${colCode}</Row>`}</pre>
|
||||
<pre className="demo-code">{`<Row gutter={[${this.gutters[gutterKey]}, ${this.vgutters[vgutterKey]}]}>\n${colCode}</Row>`}</pre>
|
||||
<Row gutter={[gutters[gutterKey], vgutters[vgutterKey]]}>{cols}</Row>
|
||||
<Row gutter={[gutters[gutterKey], vgutters[vgutterKey]]}>{cols}</Row>
|
||||
<pre className="demo-code">{`<Row gutter={[${gutters[gutterKey]}, ${vgutters[vgutterKey]}]}>\n${colCode}</Row>`}</pre>
|
||||
<pre className="demo-code">{`<Row gutter={[${gutters[gutterKey]}, ${vgutters[vgutterKey]}]}>\n${colCode}</Row>`}</pre>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -2237,7 +2237,7 @@ Array [
|
||||
aria-label="audio"
|
||||
class="anticon anticon-audio"
|
||||
role="img"
|
||||
style="font-size:16px;color:#1890ff;padding-right:4px"
|
||||
style="font-size:16px;color:#1890ff"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
|
@ -182,6 +182,14 @@ ReactDOM.render(<App />, mountNode);
|
||||
.site-input-group-wrapper .site-input-right:hover {
|
||||
border-left-width: 1px;
|
||||
}
|
||||
|
||||
.site-input-group-wrapper .ant-input-rtl.site-input-right {
|
||||
border-right-width: 0;
|
||||
}
|
||||
|
||||
.site-input-group-wrapper .ant-input-rtl.site-input-right:hover {
|
||||
border-right-width: 1px;
|
||||
}
|
||||
```
|
||||
|
||||
<style>
|
||||
|
@ -24,7 +24,6 @@ const suffix = (
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: '#1890ff',
|
||||
paddingRight: 4,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
@ -17,6 +17,13 @@
|
||||
@input-affix-margin: 4px;
|
||||
|
||||
.@{ant-prefix}-input {
|
||||
&-affix-wrapper&-affix-wrapper-rtl {
|
||||
> input.@{ant-prefix}-input {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-affix-wrapper-rtl {
|
||||
.@{ant-prefix}-input-prefix {
|
||||
margin: 0 0 0 @input-affix-margin;
|
||||
@ -83,6 +90,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
.@{inputClass}-affix-wrapper {
|
||||
&:not(:first-child) {
|
||||
.@{inputClass}-group-rtl& {
|
||||
border-top-left-radius: @border-radius-base;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-left-radius: @border-radius-base;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
.@{inputClass}-group-rtl& {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: @border-radius-base;
|
||||
border-bottom-right-radius: @border-radius-base;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&&-compact {
|
||||
& > *:not(:last-child) {
|
||||
.@{inputClass}-group-rtl& {
|
||||
@ -127,6 +154,7 @@
|
||||
}
|
||||
|
||||
// search-input
|
||||
@search-prefix: ~'@{ant-prefix}-input-search';
|
||||
@search-rtl-cls: ~'@{search-prefix}-rtl';
|
||||
|
||||
.@{search-prefix} {
|
||||
@ -166,15 +194,31 @@
|
||||
&-enter-button {
|
||||
input {
|
||||
.@{search-rtl-cls}& {
|
||||
border: @border-width-base @border-style-base @input-border-color;
|
||||
border-right: @border-width-base @border-style-base @input-border-color;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
.@{search-rtl-cls}& {
|
||||
border-color: @input-hover-border-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.@{ant-prefix}-input-affix-wrapper {
|
||||
.@{search-rtl-cls}& {
|
||||
border-right: @border-width-base @border-style-base @input-border-color;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
.@{search-rtl-cls}& {
|
||||
border-color: @input-hover-border-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& + .@{ant-prefix}-input-group-addon,
|
||||
input + .@{ant-prefix}-input-group-addon {
|
||||
|
@ -158,18 +158,19 @@ class InternalMenu extends React.Component<InternalMenuProps, MenuState> {
|
||||
}
|
||||
|
||||
getRealMenuMode() {
|
||||
const { mode } = this.props;
|
||||
const { switchingModeFromInline } = this.state;
|
||||
const inlineCollapsed = this.getInlineCollapsed();
|
||||
if (this.state.switchingModeFromInline && inlineCollapsed) {
|
||||
if (switchingModeFromInline && inlineCollapsed) {
|
||||
return 'inline';
|
||||
}
|
||||
const { mode } = this.props;
|
||||
return inlineCollapsed ? 'vertical' : mode;
|
||||
}
|
||||
|
||||
getInlineCollapsed() {
|
||||
const { inlineCollapsed } = this.props;
|
||||
if (this.props.siderCollapsed !== undefined) {
|
||||
return this.props.siderCollapsed;
|
||||
const { inlineCollapsed, siderCollapsed } = this.props;
|
||||
if (siderCollapsed !== undefined) {
|
||||
return siderCollapsed;
|
||||
}
|
||||
return inlineCollapsed;
|
||||
}
|
||||
@ -178,6 +179,7 @@ class InternalMenu extends React.Component<InternalMenuProps, MenuState> {
|
||||
menuMode: MenuMode,
|
||||
): { openTransitionName?: any; openAnimation?: any; motion?: Object } {
|
||||
const { openTransitionName, openAnimation, motion } = this.props;
|
||||
const { switchingModeFromInline } = this.state;
|
||||
|
||||
// Provides by user
|
||||
if (motion) {
|
||||
@ -210,7 +212,7 @@ class InternalMenu extends React.Component<InternalMenuProps, MenuState> {
|
||||
// submenu should hide without animation
|
||||
return {
|
||||
motion: {
|
||||
motionName: this.state.switchingModeFromInline ? '' : 'zoom-big',
|
||||
motionName: switchingModeFromInline ? '' : 'zoom-big',
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -277,6 +279,7 @@ class InternalMenu extends React.Component<InternalMenuProps, MenuState> {
|
||||
|
||||
renderMenu = ({ getPopupContainer, getPrefixCls, direction }: ConfigConsumerProps) => {
|
||||
const { prefixCls: customizePrefixCls, className, theme, collapsedWidth } = this.props;
|
||||
const { openKeys } = this.state;
|
||||
const passProps = omit(this.props, ['collapsedWidth', 'siderCollapsed']);
|
||||
const menuMode = this.getRealMenuMode();
|
||||
const menuOpenMotion = this.getOpenMotionProps(menuMode!);
|
||||
@ -287,7 +290,7 @@ class InternalMenu extends React.Component<InternalMenuProps, MenuState> {
|
||||
});
|
||||
|
||||
const menuProps: MenuProps = {
|
||||
openKeys: this.state.openKeys,
|
||||
openKeys,
|
||||
onOpenChange: this.handleOpenChange,
|
||||
className: menuClassName,
|
||||
mode: menuMode,
|
||||
@ -313,7 +316,7 @@ class InternalMenu extends React.Component<InternalMenuProps, MenuState> {
|
||||
<MenuContext.Provider
|
||||
value={{
|
||||
inlineCollapsed: this.getInlineCollapsed() || false,
|
||||
antdMenuTheme: this.props.theme,
|
||||
antdMenuTheme: theme,
|
||||
direction,
|
||||
}}
|
||||
>
|
||||
|
@ -34,7 +34,13 @@ exports[`renders ./components/message/demo/loading.md correctly 1`] = `
|
||||
`;
|
||||
|
||||
exports[`renders ./components/message/demo/other.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
@ -43,6 +49,11 @@ exports[`renders ./components/message/demo/other.md correctly 1`] = `
|
||||
Success
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
@ -51,6 +62,10 @@ exports[`renders ./components/message/demo/other.md correctly 1`] = `
|
||||
Error
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
@ -59,6 +74,7 @@ exports[`renders ./components/message/demo/other.md correctly 1`] = `
|
||||
Warning
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
@ -14,7 +14,7 @@ title:
|
||||
Messages of success, error and warning types.
|
||||
|
||||
```jsx
|
||||
import { message, Button } from 'antd';
|
||||
import { message, Button, Space } from 'antd';
|
||||
|
||||
const success = () => {
|
||||
message.success('This is a success message');
|
||||
@ -29,17 +29,11 @@ const warning = () => {
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Space>
|
||||
<Button onClick={success}>Success</Button>
|
||||
<Button onClick={error}>Error</Button>
|
||||
<Button onClick={warning}>Warning</Button>
|
||||
</div>,
|
||||
</Space>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
||||
<style>
|
||||
#components-message-demo-other .ant-btn {
|
||||
margin-right: 8px;
|
||||
}
|
||||
</style>
|
||||
|
@ -14,7 +14,7 @@ title:
|
||||
Use `confirm()` to show a confirmation modal dialog.
|
||||
|
||||
```jsx
|
||||
import { Modal, Button } from 'antd';
|
||||
import { Modal, Button, Space } from 'antd';
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons';
|
||||
|
||||
const { confirm } = Modal;
|
||||
@ -71,7 +71,7 @@ function showPropsConfirm() {
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Space>
|
||||
<Button onClick={showConfirm}>Confirm</Button>
|
||||
<Button onClick={showDeleteConfirm} type="dashed">
|
||||
Delete
|
||||
@ -79,7 +79,7 @@ ReactDOM.render(
|
||||
<Button onClick={showPropsConfirm} type="dashed">
|
||||
With extra props
|
||||
</Button>
|
||||
</div>,
|
||||
</Space>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
@ -14,7 +14,7 @@ title:
|
||||
Use `Modal.useModal` to get `contextHolder` with context accessible issue.
|
||||
|
||||
```jsx
|
||||
import { Modal, Button } from 'antd';
|
||||
import { Modal, Button, Space } from 'antd';
|
||||
|
||||
const ReachableContext = React.createContext();
|
||||
const UnreachableContext = React.createContext();
|
||||
@ -35,6 +35,7 @@ const App = () => {
|
||||
|
||||
return (
|
||||
<ReachableContext.Provider value="Light">
|
||||
<Space>
|
||||
<Button
|
||||
onClick={() => {
|
||||
modal.confirm(config);
|
||||
@ -63,7 +64,7 @@ const App = () => {
|
||||
>
|
||||
Error
|
||||
</Button>
|
||||
|
||||
</Space>
|
||||
{/* `contextHolder` should always under the context you want to access */}
|
||||
{contextHolder}
|
||||
|
||||
|
@ -14,7 +14,7 @@ title:
|
||||
In the various types of information modal dialog, only one button to close dialog is provided.
|
||||
|
||||
```jsx
|
||||
import { Modal, Button } from 'antd';
|
||||
import { Modal, Button, Space } from 'antd';
|
||||
|
||||
function info() {
|
||||
Modal.info({
|
||||
@ -50,12 +50,12 @@ function warning() {
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Space>
|
||||
<Button onClick={info}>Info</Button>
|
||||
<Button onClick={success}>Success</Button>
|
||||
<Button onClick={error}>Error</Button>
|
||||
<Button onClick={warning}>Warning</Button>
|
||||
</div>,
|
||||
</Space>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
@ -91,12 +91,6 @@ modal.update({
|
||||
modal.destroy();
|
||||
```
|
||||
|
||||
<style>
|
||||
.code-box-demo .ant-btn {
|
||||
margin-right: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
- `Modal.destroyAll`
|
||||
|
||||
`Modal.destroyAll()` could destroy all confirmation modal dialogs(Modal.info/Modal.success/Modal.error/Modal.warning/Modal.confirm). Usually, you can use it in router change event to destroy confirm modal dialog automatically without use modal reference to close( it's too complex to use for all modal dialogs)
|
||||
|
@ -93,12 +93,6 @@ modal.update({
|
||||
modal.destroy();
|
||||
```
|
||||
|
||||
<style>
|
||||
.code-box-demo .ant-btn {
|
||||
margin-right: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
- `Modal.destroyAll`
|
||||
|
||||
使用 `Modal.destroyAll()` 可以销毁弹出的确认窗(即上述的 Modal.info、Modal.success、Modal.error、Modal.warning、Modal.confirm)。通常用于路由监听当中,处理路由前进、后退不能销毁确认对话框的问题,而不用各处去使用实例的返回值进行关闭(modal.destroy() 适用于主动关闭,而不是路由这样被动关闭)
|
||||
|
@ -46,6 +46,13 @@ exports[`renders ./components/notification/demo/duration.md correctly 1`] = `
|
||||
|
||||
exports[`renders ./components/notification/demo/hooks.md correctly 1`] = `
|
||||
Array [
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
@ -73,7 +80,11 @@ Array [
|
||||
<span>
|
||||
topLeft
|
||||
</span>
|
||||
</button>,
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
@ -101,11 +112,20 @@ Array [
|
||||
<span>
|
||||
topRight
|
||||
</span>
|
||||
</button>,
|
||||
</button>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-divider ant-divider-horizontal"
|
||||
role="separator"
|
||||
/>,
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
@ -133,7 +153,11 @@ Array [
|
||||
<span>
|
||||
bottomLeft
|
||||
</span>
|
||||
</button>,
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
@ -161,12 +185,21 @@ Array [
|
||||
<span>
|
||||
bottomRight
|
||||
</span>
|
||||
</button>,
|
||||
</button>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/notification/demo/placement.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
@ -195,6 +228,10 @@ exports[`renders ./components/notification/demo/placement.md correctly 1`] = `
|
||||
topLeft
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
@ -223,10 +260,19 @@ exports[`renders ./components/notification/demo/placement.md correctly 1`] = `
|
||||
topRight
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-divider ant-divider-horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
@ -255,6 +301,10 @@ exports[`renders ./components/notification/demo/placement.md correctly 1`] = `
|
||||
bottomLeft
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
@ -283,6 +333,8 @@ exports[`renders ./components/notification/demo/placement.md correctly 1`] = `
|
||||
bottomRight
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -309,7 +361,13 @@ exports[`renders ./components/notification/demo/with-btn.md correctly 1`] = `
|
||||
`;
|
||||
|
||||
exports[`renders ./components/notification/demo/with-icon.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
@ -318,6 +376,11 @@ exports[`renders ./components/notification/demo/with-icon.md correctly 1`] = `
|
||||
Success
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
@ -326,6 +389,11 @@ exports[`renders ./components/notification/demo/with-icon.md correctly 1`] = `
|
||||
Info
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
@ -334,6 +402,10 @@ exports[`renders ./components/notification/demo/with-icon.md correctly 1`] = `
|
||||
Warning
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
@ -342,5 +414,6 @@ exports[`renders ./components/notification/demo/with-icon.md correctly 1`] = `
|
||||
Error
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -14,7 +14,7 @@ title:
|
||||
Use `notification.useNotification` to get `contextHolder` with context accessible issue.
|
||||
|
||||
```jsx
|
||||
import { Button, notification, Divider } from 'antd';
|
||||
import { Button, notification, Divider, Space } from 'antd';
|
||||
import {
|
||||
RadiusUpleftOutlined,
|
||||
RadiusUprightOutlined,
|
||||
@ -38,6 +38,7 @@ const Demo = () => {
|
||||
return (
|
||||
<Context.Provider value={{ name: 'Ant Design' }}>
|
||||
{contextHolder}
|
||||
<Space>
|
||||
<Button type="primary" onClick={() => openNotification('topLeft')}>
|
||||
<RadiusUpleftOutlined />
|
||||
topLeft
|
||||
@ -46,7 +47,9 @@ const Demo = () => {
|
||||
<RadiusUprightOutlined />
|
||||
topRight
|
||||
</Button>
|
||||
</Space>
|
||||
<Divider />
|
||||
<Space>
|
||||
<Button type="primary" onClick={() => openNotification('bottomLeft')}>
|
||||
<RadiusBottomleftOutlined />
|
||||
bottomLeft
|
||||
@ -55,6 +58,7 @@ const Demo = () => {
|
||||
<RadiusBottomrightOutlined />
|
||||
bottomRight
|
||||
</Button>
|
||||
</Space>
|
||||
</Context.Provider>
|
||||
);
|
||||
};
|
||||
|
@ -14,7 +14,7 @@ title:
|
||||
A notification box can appear from the `topRight`, `bottomRight`, `bottomLeft` or `topLeft` of the viewport.
|
||||
|
||||
```jsx
|
||||
import { Button, notification, Divider } from 'antd';
|
||||
import { Button, notification, Divider, Space } from 'antd';
|
||||
import {
|
||||
RadiusUpleftOutlined,
|
||||
RadiusUprightOutlined,
|
||||
@ -33,6 +33,7 @@ const openNotification = placement => {
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Space>
|
||||
<Button type="primary" onClick={() => openNotification('topLeft')}>
|
||||
<RadiusUpleftOutlined />
|
||||
topLeft
|
||||
@ -41,7 +42,9 @@ ReactDOM.render(
|
||||
<RadiusUprightOutlined />
|
||||
topRight
|
||||
</Button>
|
||||
</Space>
|
||||
<Divider />
|
||||
<Space>
|
||||
<Button type="primary" onClick={() => openNotification('bottomLeft')}>
|
||||
<RadiusBottomleftOutlined />
|
||||
bottomLeft
|
||||
@ -50,6 +53,7 @@ ReactDOM.render(
|
||||
<RadiusBottomrightOutlined />
|
||||
bottomRight
|
||||
</Button>
|
||||
</Space>
|
||||
</div>,
|
||||
mountNode,
|
||||
);
|
||||
|
@ -14,7 +14,7 @@ title:
|
||||
A notification box with a icon at the left side.
|
||||
|
||||
```jsx
|
||||
import { Button, notification } from 'antd';
|
||||
import { Button, notification, Space } from 'antd';
|
||||
|
||||
const openNotificationWithIcon = type => {
|
||||
notification[type]({
|
||||
@ -25,18 +25,12 @@ const openNotificationWithIcon = type => {
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Space>
|
||||
<Button onClick={() => openNotificationWithIcon('success')}>Success</Button>
|
||||
<Button onClick={() => openNotificationWithIcon('info')}>Info</Button>
|
||||
<Button onClick={() => openNotificationWithIcon('warning')}>Warning</Button>
|
||||
<Button onClick={() => openNotificationWithIcon('error')}>Error</Button>
|
||||
</div>,
|
||||
</Space>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
||||
<style>
|
||||
.code-box-demo .ant-btn {
|
||||
margin-right: 1em;
|
||||
}
|
||||
</style>
|
||||
|
@ -85,6 +85,11 @@ ReactDOM.render(
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.code-box-demo .ant-btn-rtl {
|
||||
margin-right: 0;
|
||||
margin-left: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
#components-popover-demo-placement .ant-btn {
|
||||
width: 70px;
|
||||
text-align: center;
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
&:last-child {
|
||||
.@{result-prefix-cls}-rtl & {
|
||||
margin-left: 8px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,14 +25,14 @@ To input a value in a range.
|
||||
| range | dual thumb mode | boolean | false | |
|
||||
| reverse | reverse the component | boolean | false | |
|
||||
| step | The granularity the slider can step through values. Must greater than 0, and be divided by (max - min) . When `marks` no null, `step` can be `null`. | number\|null | 1 | |
|
||||
| tipFormatter | Slider will pass its value to `tipFormatter`, and display its value in Tooltip, and hide Tooltip when return value is null. | Function\|null | IDENTITY | |
|
||||
| tipFormatter | Slider will pass its value to `tipFormatter`, and display its value in Tooltip, and hide Tooltip when return value is null. | value => ReactNode\|null | IDENTITY | |
|
||||
| value | The value of slider. When `range` is `false`, use `number`, otherwise, use `[number, number]` | number\|\[number, number] | |
|
||||
| vertical | If true, the slider will be vertical. | Boolean | false | |
|
||||
| onAfterChange | Fire when `onmouseup` is fired. | Function(value) | NOOP | |
|
||||
| onChange | Callback function that is fired when the user changes the slider's value. | Function(value) | NOOP | |
|
||||
| onAfterChange | Fire when `onmouseup` is fired. | (value) => void | NOOP | |
|
||||
| onChange | Callback function that is fired when the user changes the slider's value. | (value) => void | NOOP | |
|
||||
| tooltipPlacement | Set Tooltip display position. Ref [`Tooltip`](/components/tooltip/). | string | | |
|
||||
| tooltipVisible | If true, Tooltip will show always, or it will not show anyway, even if dragging or hovering. | Boolean | | |
|
||||
| getTooltipPopupContainer | The DOM container of the Tooltip, the default behavior is to create a div element in body. | Function | () => document.body | |
|
||||
| getTooltipPopupContainer | The DOM container of the Tooltip, the default behavior is to create a div element in body. | (triggerNode) => HTMLElement | () => document.body | |
|
||||
|
||||
## Methods
|
||||
|
||||
|
@ -26,14 +26,14 @@ title: Slider
|
||||
| range | 双滑块模式 | boolean | false | |
|
||||
| reverse | 反向坐标轴 | boolean | false | |
|
||||
| step | 步长,取值必须大于 0,并且可被 (max - min) 整除。当 `marks` 不为空对象时,可以设置 `step` 为 `null`,此时 Slider 的可选值仅有 marks 标出来的部分。 | number\|null | 1 | |
|
||||
| tipFormatter | Slider 会把当前值传给 `tipFormatter`,并在 Tooltip 中显示 `tipFormatter` 的返回值,若为 null,则隐藏 Tooltip。 | Function\|null | IDENTITY | |
|
||||
| tipFormatter | Slider 会把当前值传给 `tipFormatter`,并在 Tooltip 中显示 `tipFormatter` 的返回值,若为 null,则隐藏 Tooltip。 | value => ReactNode\|null | IDENTITY | |
|
||||
| value | 设置当前取值。当 `range` 为 `false` 时,使用 `number`,否则用 `[number, number]` | number\|\[number, number] | | |
|
||||
| vertical | 值为 `true` 时,Slider 为垂直方向 | Boolean | false | |
|
||||
| onAfterChange | 与 `onmouseup` 触发时机一致,把当前值作为参数传入。 | Function(value) | NOOP | |
|
||||
| onChange | 当 Slider 的值发生改变时,会触发 onChange 事件,并把改变后的值作为参数传入。 | Function(value) | NOOP | |
|
||||
| onAfterChange | 与 `onmouseup` 触发时机一致,把当前值作为参数传入。 | (value) => void | NOOP | |
|
||||
| onChange | 当 Slider 的值发生改变时,会触发 onChange 事件,并把改变后的值作为参数传入。 | (value) => void | NOOP | |
|
||||
| tooltipPlacement | 设置 Tooltip 展示位置。参考 [`Tooltip`](/components/tooltip/)。 | string | | |
|
||||
| tooltipVisible | 值为`true`时,Tooltip 将会始终显示;否则始终不显示,哪怕在拖拽及移入时。 | Boolean | | |
|
||||
| getTooltipPopupContainer | Tooltip 渲染父节点,默认渲染到 body 上。 | Function | () => document.body | |
|
||||
| getTooltipPopupContainer | Tooltip 渲染父节点,默认渲染到 body 上。 | (triggerNode) => HTMLElement | () => document.body | |
|
||||
|
||||
## 方法
|
||||
|
||||
|
@ -92,6 +92,7 @@
|
||||
text-align: center;
|
||||
word-break: keep-all;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&-active {
|
||||
color: @text-color;
|
||||
|
@ -165,7 +165,13 @@ exports[`renders ./components/spin/demo/nested.md correctly 1`] = `
|
||||
`;
|
||||
|
||||
exports[`renders ./components/spin/demo/size.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:16px"
|
||||
>
|
||||
<div
|
||||
class="ant-spin ant-spin-sm ant-spin-spinning"
|
||||
>
|
||||
@ -186,6 +192,11 @@ exports[`renders ./components/spin/demo/size.md correctly 1`] = `
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:16px"
|
||||
>
|
||||
<div
|
||||
class="ant-spin ant-spin-spinning"
|
||||
>
|
||||
@ -206,6 +217,10 @@ exports[`renders ./components/spin/demo/size.md correctly 1`] = `
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
class="ant-spin ant-spin-lg ant-spin-spinning"
|
||||
>
|
||||
@ -226,6 +241,7 @@ exports[`renders ./components/spin/demo/size.md correctly 1`] = `
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
@ -14,20 +14,14 @@ title:
|
||||
A small `Spin` is used for loading text, default sized `Spin` for loading a card-level block, and large `Spin` used for loading a **page**.
|
||||
|
||||
```jsx
|
||||
import { Spin } from 'antd';
|
||||
import { Spin, Space } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Space size="middle">
|
||||
<Spin size="small" />
|
||||
<Spin />
|
||||
<Spin size="large" />
|
||||
</div>,
|
||||
</Space>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
||||
<style>
|
||||
.ant-spin.ant-spin-spinning {
|
||||
margin-right: 16px;
|
||||
}
|
||||
</style>
|
||||
|
@ -93,7 +93,8 @@
|
||||
@switch-sm-height: 14px;
|
||||
@switch-min-width: 40px;
|
||||
@switch-sm-min-width: 24px;
|
||||
@switch-inner-margin: 0 22px 0 4px;
|
||||
@switch-inner-margin-min: 4px;
|
||||
@switch-inner-margin-max: 22px;
|
||||
|
||||
// Slider
|
||||
// ---
|
||||
|
@ -729,7 +729,8 @@
|
||||
@switch-color: @primary-color;
|
||||
@switch-bg: @component-background;
|
||||
@switch-shadow-color: fade(#00230b, 20%);
|
||||
@switch-inner-margin: 0 24px 0 6px;
|
||||
@switch-inner-margin-min: 6px;
|
||||
@switch-inner-margin-max: 24px;
|
||||
|
||||
// Pagination
|
||||
// ---
|
||||
|
@ -23,7 +23,8 @@
|
||||
|
||||
&-inner {
|
||||
display: block;
|
||||
margin: @switch-inner-margin;
|
||||
margin-right: @switch-inner-margin-min;
|
||||
margin-left: @switch-inner-margin-max;
|
||||
color: @text-color-inverse;
|
||||
font-size: @font-size-sm;
|
||||
}
|
||||
@ -135,7 +136,8 @@
|
||||
background-color: @switch-color;
|
||||
|
||||
.@{switch-prefix-cls}-inner {
|
||||
margin: @switch-inner-margin;
|
||||
margin-right: @switch-inner-margin-max;
|
||||
margin-left: @switch-inner-margin-min;
|
||||
}
|
||||
|
||||
&::after {
|
||||
|
@ -10,8 +10,8 @@
|
||||
|
||||
&-inner {
|
||||
.@{switch-prefix-cls}-rtl & {
|
||||
margin-right: 24px;
|
||||
margin-left: 6px;
|
||||
margin-right: @switch-inner-margin-max;
|
||||
margin-left: @switch-inner-margin-min;
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,8 +51,8 @@
|
||||
&-checked {
|
||||
.@{switch-prefix-cls}-inner {
|
||||
.@{switch-prefix-cls}-rtl& {
|
||||
margin-right: 6px;
|
||||
margin-left: 24px;
|
||||
margin-right: @switch-inner-margin-min;
|
||||
margin-left: @switch-inner-margin-max;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -403,18 +403,19 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
|
||||
paginationSize = mergedSize === 'small' || mergedSize === 'middle' ? 'small' : undefined;
|
||||
}
|
||||
|
||||
const renderPagination = (position: string = 'right') => (
|
||||
const renderPagination = (position: string) => (
|
||||
<Pagination
|
||||
className={`${prefixCls}-pagination ${prefixCls}-pagination-${position}`}
|
||||
{...mergedPagination}
|
||||
size={paginationSize}
|
||||
/>
|
||||
);
|
||||
const defaultPosition = direction === 'rtl' ? 'left' : 'right';
|
||||
if (mergedPagination.position !== null && Array.isArray(mergedPagination.position)) {
|
||||
const topPos = mergedPagination.position.find(p => p.indexOf('top') !== -1);
|
||||
const bottomPos = mergedPagination.position.find(p => p.indexOf('bottom') !== -1);
|
||||
if (!topPos && !bottomPos) {
|
||||
bottomPaginationNode = renderPagination();
|
||||
bottomPaginationNode = renderPagination(defaultPosition);
|
||||
} else {
|
||||
if (topPos) {
|
||||
topPaginationNode = renderPagination(topPos!.toLowerCase().replace('top', ''));
|
||||
@ -424,7 +425,7 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bottomPaginationNode = renderPagination();
|
||||
bottomPaginationNode = renderPagination(defaultPosition);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,9 @@ exports[`Table.rowSelection fix expand on th left when selection column fixed on
|
||||
<col
|
||||
class="ant-table-expand-icon-col"
|
||||
/>
|
||||
<col
|
||||
class="ant-table-selection-column"
|
||||
/>
|
||||
</colgroup>
|
||||
<thead
|
||||
class="ant-table-thead"
|
||||
@ -354,7 +357,11 @@ exports[`Table.rowSelection fix selection column on the left 1`] = `
|
||||
<table
|
||||
style="width:903px;min-width:100%;table-layout:fixed"
|
||||
>
|
||||
<colgroup />
|
||||
<colgroup>
|
||||
<col
|
||||
class="ant-table-selection-column"
|
||||
/>
|
||||
</colgroup>
|
||||
<thead
|
||||
class="ant-table-thead"
|
||||
>
|
||||
@ -634,7 +641,11 @@ exports[`Table.rowSelection fix selection column on the left when any other colu
|
||||
<table
|
||||
style="width:903px;min-width:100%;table-layout:fixed"
|
||||
>
|
||||
<colgroup />
|
||||
<colgroup>
|
||||
<col
|
||||
class="ant-table-selection-column"
|
||||
/>
|
||||
</colgroup>
|
||||
<thead
|
||||
class="ant-table-thead"
|
||||
>
|
||||
@ -945,7 +956,11 @@ exports[`Table.rowSelection should support getPopupContainer 1`] = `
|
||||
<table
|
||||
style="table-layout: auto;"
|
||||
>
|
||||
<colgroup />
|
||||
<colgroup>
|
||||
<col
|
||||
class="ant-table-selection-column"
|
||||
/>
|
||||
</colgroup>
|
||||
<thead
|
||||
class="ant-table-thead"
|
||||
>
|
||||
@ -1268,7 +1283,11 @@ exports[`Table.rowSelection should support getPopupContainer from ConfigProvider
|
||||
<table
|
||||
style="table-layout: auto;"
|
||||
>
|
||||
<colgroup />
|
||||
<colgroup>
|
||||
<col
|
||||
class="ant-table-selection-column"
|
||||
/>
|
||||
</colgroup>
|
||||
<thead
|
||||
class="ant-table-thead"
|
||||
>
|
||||
@ -1591,7 +1610,11 @@ exports[`Table.rowSelection use column as selection column when key is \`selecti
|
||||
<table
|
||||
style="table-layout:auto"
|
||||
>
|
||||
<colgroup />
|
||||
<colgroup>
|
||||
<col
|
||||
class="ant-table-selection-column"
|
||||
/>
|
||||
</colgroup>
|
||||
<thead
|
||||
class="ant-table-thead"
|
||||
>
|
||||
|
@ -2378,6 +2378,9 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
|
||||
<col
|
||||
class="ant-table-expand-icon-col"
|
||||
/>
|
||||
<col
|
||||
class="ant-table-selection-column"
|
||||
/>
|
||||
</colgroup>
|
||||
<thead
|
||||
class="ant-table-thead"
|
||||
@ -4932,7 +4935,9 @@ exports[`renders ./components/table/demo/expand-children.md correctly 1`] = `
|
||||
style="table-layout:auto"
|
||||
>
|
||||
<colgroup>
|
||||
<col />
|
||||
<col
|
||||
class="ant-table-selection-column"
|
||||
/>
|
||||
<col />
|
||||
<col
|
||||
style="width:12%;min-width:12%"
|
||||
@ -10821,9 +10826,14 @@ exports[`renders ./components/table/demo/pagination.md correctly 1`] = `
|
||||
`;
|
||||
|
||||
exports[`renders ./components/table/demo/reset-filter.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div
|
||||
class="table-operations"
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
style="margin-bottom:16px"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
@ -10833,6 +10843,11 @@ exports[`renders ./components/table/demo/reset-filter.md correctly 1`] = `
|
||||
Sort age
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
@ -10841,6 +10856,10 @@ exports[`renders ./components/table/demo/reset-filter.md correctly 1`] = `
|
||||
Clear filters
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
@ -10850,6 +10869,7 @@ exports[`renders ./components/table/demo/reset-filter.md correctly 1`] = `
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-table-wrapper"
|
||||
>
|
||||
@ -11317,8 +11337,8 @@ exports[`renders ./components/table/demo/reset-filter.md correctly 1`] = `
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/table/demo/resizable-column.md correctly 1`] = `
|
||||
@ -11852,7 +11872,11 @@ exports[`renders ./components/table/demo/row-selection.md correctly 1`] = `
|
||||
<table
|
||||
style="table-layout:auto"
|
||||
>
|
||||
<colgroup />
|
||||
<colgroup>
|
||||
<col
|
||||
class="ant-table-selection-column"
|
||||
/>
|
||||
</colgroup>
|
||||
<thead
|
||||
class="ant-table-thead"
|
||||
>
|
||||
@ -12195,7 +12219,11 @@ exports[`renders ./components/table/demo/row-selection-and-operation.md correctl
|
||||
<table
|
||||
style="table-layout:auto"
|
||||
>
|
||||
<colgroup />
|
||||
<colgroup>
|
||||
<col
|
||||
class="ant-table-selection-column"
|
||||
/>
|
||||
</colgroup>
|
||||
<thead
|
||||
class="ant-table-thead"
|
||||
>
|
||||
@ -12778,7 +12806,11 @@ exports[`renders ./components/table/demo/row-selection-custom.md correctly 1`] =
|
||||
<table
|
||||
style="table-layout:auto"
|
||||
>
|
||||
<colgroup />
|
||||
<colgroup>
|
||||
<col
|
||||
class="ant-table-selection-column"
|
||||
/>
|
||||
</colgroup>
|
||||
<thead
|
||||
class="ant-table-thead"
|
||||
>
|
||||
@ -13388,7 +13420,11 @@ exports[`renders ./components/table/demo/row-selection-custom-debug.md correctly
|
||||
<table
|
||||
style="table-layout:auto"
|
||||
>
|
||||
<colgroup />
|
||||
<colgroup>
|
||||
<col
|
||||
class="ant-table-selection-column"
|
||||
/>
|
||||
</colgroup>
|
||||
<thead
|
||||
class="ant-table-thead"
|
||||
>
|
||||
|
@ -14,7 +14,7 @@ title:
|
||||
Implement a customized column search example via `filterDropdown`.
|
||||
|
||||
```jsx
|
||||
import { Table, Input, Button } from 'antd';
|
||||
import { Table, Input, Button, Space } from 'antd';
|
||||
import Highlighter from 'react-highlight-words';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
|
||||
@ -64,26 +64,25 @@ class App extends React.Component {
|
||||
onPressEnter={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
|
||||
style={{ width: 188, marginBottom: 8, display: 'block' }}
|
||||
/>
|
||||
<Space>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
|
||||
icon={<SearchOutlined />}
|
||||
size="small"
|
||||
style={{ width: 90, marginRight: 8 }}
|
||||
style={{ width: 90 }}
|
||||
>
|
||||
Search
|
||||
</Button>
|
||||
<Button onClick={() => this.handleReset(clearFilters)} size="small" style={{ width: 90 }}>
|
||||
Reset
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
),
|
||||
filterIcon: filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />,
|
||||
onFilter: (value, record) =>
|
||||
record[dataIndex]
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.includes(value.toLowerCase()),
|
||||
record[dataIndex].toString().toLowerCase().includes(value.toLowerCase()),
|
||||
onFilterDropdownVisibleChange: visible => {
|
||||
if (visible) {
|
||||
setTimeout(() => this.searchInput.select());
|
||||
|
@ -22,7 +22,7 @@ Control filters and sorters by `filteredValue` and `sortOrder`.
|
||||
> 3. `column.key` is required.
|
||||
|
||||
```jsx
|
||||
import { Table, Button } from 'antd';
|
||||
import { Table, Button, Space } from 'antd';
|
||||
|
||||
const data = [
|
||||
{
|
||||
@ -128,27 +128,17 @@ class App extends React.Component {
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<div className="table-operations">
|
||||
<>
|
||||
<Space style={{ marginBottom: 16 }}>
|
||||
<Button onClick={this.setAgeSort}>Sort age</Button>
|
||||
<Button onClick={this.clearFilters}>Clear filters</Button>
|
||||
<Button onClick={this.clearAll}>Clear filters and sorters</Button>
|
||||
</div>
|
||||
</Space>
|
||||
<Table columns={columns} dataSource={data} onChange={this.handleChange} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<App />, mountNode);
|
||||
```
|
||||
|
||||
```css
|
||||
.table-operations {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.table-operations > button {
|
||||
margin-right: 8px;
|
||||
}
|
||||
```
|
||||
|
@ -1,5 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import DownOutlined from '@ant-design/icons/DownOutlined';
|
||||
import { INTERNAL_COL_DEFINE } from 'rc-table';
|
||||
import { FixedType } from 'rc-table/lib/interface';
|
||||
import Checkbox, { CheckboxProps } from '../../checkbox';
|
||||
import Dropdown from '../../dropdown';
|
||||
@ -440,6 +441,9 @@ export default function useSelection<RecordType>(
|
||||
className: `${prefixCls}-selection-column`,
|
||||
title: rowSelection.columnTitle || title,
|
||||
render: renderSelectionCell,
|
||||
[INTERNAL_COL_DEFINE]: {
|
||||
className: `${prefixCls}-selection-column`,
|
||||
},
|
||||
};
|
||||
|
||||
if (expandType === 'row' && columns.length && !expandIconColumnIndex) {
|
||||
|
@ -360,6 +360,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-selection-column,
|
||||
table tr th&-selection-column,
|
||||
table tr td&-selection-column {
|
||||
width: @table-selection-column-width;
|
||||
|
@ -2526,9 +2526,18 @@ exports[`renders ./components/tabs/demo/nest.md correctly 1`] = `
|
||||
exports[`renders ./components/tabs/demo/position.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
style="margin-bottom:16px"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
Tab position:
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
class="ant-select ant-select-single ant-select-show-arrow"
|
||||
>
|
||||
@ -2587,6 +2596,7 @@ exports[`renders ./components/tabs/demo/position.md correctly 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tabs ant-tabs-top ant-tabs-line"
|
||||
>
|
||||
|
@ -14,7 +14,7 @@ title:
|
||||
Tab's position: left, right, top or bottom.
|
||||
|
||||
```jsx
|
||||
import { Tabs, Select } from 'antd';
|
||||
import { Tabs, Select, Space } from 'antd';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
const { Option } = Select;
|
||||
@ -31,7 +31,7 @@ class Demo extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<Space style={{ marginBottom: 16 }}>
|
||||
Tab position:
|
||||
<Select
|
||||
value={this.state.tabPosition}
|
||||
@ -43,7 +43,7 @@ class Demo extends React.Component {
|
||||
<Option value="left">left</Option>
|
||||
<Option value="right">right</Option>
|
||||
</Select>
|
||||
</div>
|
||||
</Space>
|
||||
<Tabs tabPosition={this.state.tabPosition}>
|
||||
<TabPane tab="Tab 1" key="1">
|
||||
Content of Tab 1
|
||||
|
@ -204,19 +204,29 @@ exports[`renders ./components/tag/demo/basic.md correctly 1`] = `
|
||||
exports[`renders ./components/tag/demo/checkable.md correctly 1`] = `
|
||||
Array [
|
||||
<span
|
||||
class="ant-tag ant-tag-checkable"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
Tag1
|
||||
Categories:
|
||||
</span>,
|
||||
<span
|
||||
class="ant-tag ant-tag-checkable"
|
||||
>
|
||||
Tag2
|
||||
Movies
|
||||
</span>,
|
||||
<span
|
||||
class="ant-tag ant-tag-checkable ant-tag-checkable-checked"
|
||||
>
|
||||
Books
|
||||
</span>,
|
||||
<span
|
||||
class="ant-tag ant-tag-checkable"
|
||||
>
|
||||
Tag3
|
||||
Music
|
||||
</span>,
|
||||
<span
|
||||
class="ant-tag ant-tag-checkable"
|
||||
>
|
||||
Sports
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
@ -456,36 +466,6 @@ exports[`renders ./components/tag/demo/controlled.md correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/tag/demo/hot-tags.md correctly 1`] = `
|
||||
Array [
|
||||
<span
|
||||
style="margin-right:8px"
|
||||
>
|
||||
Categories:
|
||||
</span>,
|
||||
<span
|
||||
class="ant-tag ant-tag-checkable"
|
||||
>
|
||||
Movies
|
||||
</span>,
|
||||
<span
|
||||
class="ant-tag ant-tag-checkable ant-tag-checkable-checked"
|
||||
>
|
||||
Books
|
||||
</span>,
|
||||
<span
|
||||
class="ant-tag ant-tag-checkable"
|
||||
>
|
||||
Music
|
||||
</span>,
|
||||
<span
|
||||
class="ant-tag ant-tag-checkable"
|
||||
>
|
||||
Sports
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/tag/demo/icon.md correctly 1`] = `
|
||||
<div>
|
||||
<span
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
order: 3
|
||||
title:
|
||||
zh-CN: 可选择
|
||||
zh-CN: 可选择标签
|
||||
en-US: Checkable
|
||||
---
|
||||
|
||||
@ -22,12 +22,38 @@ import { Tag } from 'antd';
|
||||
|
||||
const { CheckableTag } = Tag;
|
||||
|
||||
ReactDOM.render(
|
||||
const tagsData = ['Movies', 'Books', 'Music', 'Sports'];
|
||||
|
||||
class HotTags extends React.Component {
|
||||
state = {
|
||||
selectedTags: ['Books'],
|
||||
};
|
||||
|
||||
handleChange(tag, checked) {
|
||||
const { selectedTags } = this.state;
|
||||
const nextSelectedTags = checked ? [...selectedTags, tag] : selectedTags.filter(t => t !== tag);
|
||||
console.log('You are interested in: ', nextSelectedTags);
|
||||
this.setState({ selectedTags: nextSelectedTags });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { selectedTags } = this.state;
|
||||
return (
|
||||
<>
|
||||
<CheckableTag>Tag1</CheckableTag>
|
||||
<CheckableTag>Tag2</CheckableTag>
|
||||
<CheckableTag>Tag3</CheckableTag>
|
||||
</>,
|
||||
mountNode,
|
||||
);
|
||||
<span style={{ marginRight: 8 }}>Categories:</span>
|
||||
{tagsData.map(tag => (
|
||||
<CheckableTag
|
||||
key={tag}
|
||||
checked={selectedTags.indexOf(tag) > -1}
|
||||
onChange={checked => this.handleChange(tag, checked)}
|
||||
>
|
||||
{tag}
|
||||
</CheckableTag>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<HotTags />, mountNode);
|
||||
```
|
||||
|
@ -44,12 +44,6 @@ ReactDOM.render(
|
||||
);
|
||||
```
|
||||
|
||||
```css
|
||||
.ant-tag {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
```
|
||||
|
||||
<style>
|
||||
.code-box-demo .ant-tag {
|
||||
margin-bottom: 8px;
|
||||
|
@ -1,55 +0,0 @@
|
||||
---
|
||||
order: 4
|
||||
title:
|
||||
zh-CN: 热门标签
|
||||
en-US: Hot Tags
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
选择你感兴趣的话题。
|
||||
|
||||
## en-US
|
||||
|
||||
Select your favourite topics.
|
||||
|
||||
```jsx
|
||||
import { Tag } from 'antd';
|
||||
|
||||
const { CheckableTag } = Tag;
|
||||
|
||||
const tagsData = ['Movies', 'Books', 'Music', 'Sports'];
|
||||
|
||||
class HotTags extends React.Component {
|
||||
state = {
|
||||
selectedTags: ['Books'],
|
||||
};
|
||||
|
||||
handleChange(tag, checked) {
|
||||
const { selectedTags } = this.state;
|
||||
const nextSelectedTags = checked ? [...selectedTags, tag] : selectedTags.filter(t => t !== tag);
|
||||
console.log('You are interested in: ', nextSelectedTags);
|
||||
this.setState({ selectedTags: nextSelectedTags });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { selectedTags } = this.state;
|
||||
return (
|
||||
<>
|
||||
<span style={{ marginRight: 8 }}>Categories:</span>
|
||||
{tagsData.map(tag => (
|
||||
<CheckableTag
|
||||
key={tag}
|
||||
checked={selectedTags.indexOf(tag) > -1}
|
||||
onChange={checked => this.handleChange(tag, checked)}
|
||||
>
|
||||
{tag}
|
||||
</CheckableTag>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<HotTags />, mountNode);
|
||||
```
|
@ -297,4 +297,22 @@ describe('Tooltip', () => {
|
||||
await sleep(500);
|
||||
expect(wrapper.instance().getPopupDomNode().className).toContain('placement-topRight');
|
||||
});
|
||||
|
||||
it('should works for mismatch placement', async () => {
|
||||
const wrapper = mount(
|
||||
<Tooltip
|
||||
title="xxxxx"
|
||||
align={{
|
||||
points: ['bc', 'tl'],
|
||||
}}
|
||||
mouseEnterDelay={0}
|
||||
>
|
||||
<span>Hello world!</span>
|
||||
</Tooltip>,
|
||||
);
|
||||
const button = wrapper.find('span').at(0);
|
||||
button.simulate('mouseenter');
|
||||
await sleep(600);
|
||||
expect(wrapper.instance().getPopupDomNode().className).toContain('ant-tooltip');
|
||||
});
|
||||
});
|
||||
|
@ -28,10 +28,3 @@ ReactDOM.render(
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
||||
<style>
|
||||
.code-box-demo .ant-btn {
|
||||
margin-right: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
</style>
|
||||
|
@ -46,10 +46,3 @@ ReactDOM.render(
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
||||
<style>
|
||||
.code-box-demo .ant-btn {
|
||||
margin-right: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
</style>
|
||||
|
@ -79,6 +79,11 @@ ReactDOM.render(
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.code-box-demo .ant-btn-rtl {
|
||||
margin-right: 0;
|
||||
margin-left: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
#components-tooltip-demo-placement .ant-btn {
|
||||
width: 70px;
|
||||
text-align: center;
|
||||
|
@ -186,6 +186,9 @@ class Tooltip extends React.Component<TooltipProps, any> {
|
||||
placements[key].points[0] === align.points[0] &&
|
||||
placements[key].points[1] === align.points[1],
|
||||
)[0];
|
||||
if (!placement) {
|
||||
return;
|
||||
}
|
||||
// 根据当前坐标设置动画点
|
||||
const rect = domNode.getBoundingClientRect();
|
||||
const transformOrigin = {
|
||||
|
@ -2243,7 +2243,11 @@ exports[`renders ./components/transfer/demo/table-transfer.md correctly 1`] = `
|
||||
<table
|
||||
style="table-layout:auto"
|
||||
>
|
||||
<colgroup />
|
||||
<colgroup>
|
||||
<col
|
||||
class="ant-table-selection-column"
|
||||
/>
|
||||
</colgroup>
|
||||
<thead
|
||||
class="ant-table-thead"
|
||||
>
|
||||
@ -2920,7 +2924,11 @@ exports[`renders ./components/transfer/demo/table-transfer.md correctly 1`] = `
|
||||
<table
|
||||
style="table-layout:auto"
|
||||
>
|
||||
<colgroup />
|
||||
<colgroup>
|
||||
<col
|
||||
class="ant-table-selection-column"
|
||||
/>
|
||||
</colgroup>
|
||||
<thead
|
||||
class="ant-table-thead"
|
||||
>
|
||||
|
@ -33,7 +33,7 @@ Uploading is the process of publishing information (web pages, text, pictures, v
|
||||
| multiple | Whether to support selected multiple file. `IE10+` supported. You can select multiple files with CTRL holding down while multiple is set to be true | boolean | false | |
|
||||
| name | The name of uploading file | string | 'file' | |
|
||||
| previewFile | Customize preview file logic | (file: File \| Blob) => Promise<dataURL: string> | - | |
|
||||
| isImageUrl | Customize if render <img /> in thumbnail | (file: UploadFile) => boolean | [inside implementation](https://github.com/ant-design/ant-design/blob/4ad5830eecfb87471cd8ac588c5d992862b70770/components/upload/utils.tsx#L47-L68) | |
|
||||
| isImageUrl | Customize if render `<img />` in thumbnail | (file: UploadFile) => boolean | [inside implementation](https://github.com/ant-design/ant-design/blob/4ad5830eecfb87471cd8ac588c5d992862b70770/components/upload/utils.tsx#L47-L68) | |
|
||||
| showUploadList | Whether to show default upload list, could be an object to specify `showPreviewIcon`, `showRemoveIcon`, `showDownloadIcon`, `removeIcon` and `downloadIcon` individually | Boolean or { showPreviewIcon?: boolean, showDownloadIcon?: boolean, showRemoveIcon?: boolean, removeIcon?: React.ReactNode, downloadIcon?: React.ReactNode } | true | |
|
||||
| supportServerRender | Need to be turned on while the server side is rendering | boolean | false | |
|
||||
| withCredentials | ajax upload with cookie sent | boolean | false | |
|
||||
|
@ -34,7 +34,7 @@ title: Upload
|
||||
| multiple | 是否支持多选文件,`ie10+` 支持。开启后按住 ctrl 可选择多个文件 | boolean | false | |
|
||||
| name | 发到后台的文件参数名 | string | 'file' | |
|
||||
| previewFile | 自定义文件预览逻辑 | (file: File \| Blob) => Promise<dataURL: string> | 无 | |
|
||||
| isImageUrl | 自定义缩略图是否使用 img 标签进行显示 | (file: UploadFile) => boolean | [内部实现](https://github.com/ant-design/ant-design/blob/4ad5830eecfb87471cd8ac588c5d992862b70770/components/upload/utils.tsx#L47-L68) | |
|
||||
| isImageUrl | 自定义缩略图是否使用 `<img />` 标签进行显示 | (file: UploadFile) => boolean | [内部实现](https://github.com/ant-design/ant-design/blob/4ad5830eecfb87471cd8ac588c5d992862b70770/components/upload/utils.tsx#L47-L68) | |
|
||||
| showUploadList | 是否展示文件列表, 可设为一个对象,用于单独设定 `showPreviewIcon`, `showRemoveIcon`, `showDownloadIcon`, `removeIcon` 和 `downloadIcon` | Boolean or { showPreviewIcon?: boolean, showRemoveIcon?: boolean, showDownloadIcon?: boolean, removeIcon?: React.ReactNode, downloadIcon?: React.ReactNode } | true | |
|
||||
| supportServerRender | 服务端渲染时需要打开这个 | boolean | false | |
|
||||
| withCredentials | 上传请求时是否携带 cookie | boolean | false | |
|
||||
|
@ -47,45 +47,34 @@ const LinksList = () => (
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://ng.ant.design" target="_blank">
|
||||
NG-ZORRO - Ant Design of Angular<LinkIcon />
|
||||
NG-ZORRO - Ant Design of Angular
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://ng.mobile.ant.design" target="_blank">
|
||||
NG-ZORRO-MOBILE - Ant Design Mobile of Angular<LinkIcon />
|
||||
NG-ZORRO-MOBILE - Ant Design Mobile of Angular
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://vue.ant.design" target="_blank">Ant Design of Vue<LinkIcon /></a>
|
||||
<a href="http://vue.ant.design" target="_blank">Ant Design of Vue</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://ecomfe.github.io/santd" target="_blank">
|
||||
San UI Toolkit for Ant Design<LinkIcon />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/FE-Driver/vue-beauty" target="_blank">
|
||||
vue-beauty (vue)<LinkIcon />
|
||||
San UI Toolkit for Ant Design
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/priornix/antizer" target="_blank">
|
||||
antizer (ClojureScript)<LinkIcon />
|
||||
antizer (ClojureScript)
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/idcos/antd-ember" target="_blank">
|
||||
antd-ember<LinkIcon />
|
||||
<a href="https://ant-design-blazor.github.io/" target="_blank">
|
||||
ant-design-blazor/ant-design-blazor
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/zzuu666/antue" target="_blank">
|
||||
antue (vue)<LinkIcon />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<span class="ant-divider ant-divider-vertical" />
|
||||
<a href="https://append-it.github.io/ant-design-blazor/" target="_blank">
|
||||
Ant Design of Blazor<LinkIcon />
|
||||
append-it/ant-design-blazor
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -47,45 +47,36 @@ const LinksList = () => (
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://ng.ant.design" target="_blank">
|
||||
NG-ZORRO - Ant Design of Angular<LinkIcon />
|
||||
NG-ZORRO - Ant Design of Angular
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://ng.mobile.ant.design" target="_blank">
|
||||
NG-ZORRO-MOBILE - Ant Design Mobile of Angular<LinkIcon />
|
||||
NG-ZORRO-MOBILE - Ant Design Mobile of Angular
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://vue.ant.design" target="_blank">Ant Design of Vue<LinkIcon /></a>
|
||||
<a href="http://vue.ant.design" target="_blank">Ant Design of Vue</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://ecomfe.github.io/santd" target="_blank">
|
||||
San UI Toolkit for Ant Design<LinkIcon />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/FE-Driver/vue-beauty" target="_blank">
|
||||
vue-beauty (vue)<LinkIcon />
|
||||
San UI Toolkit for Ant Design
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/priornix/antizer" target="_blank">
|
||||
antizer (ClojureScript)<LinkIcon />
|
||||
antizer (ClojureScript)
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/idcos/antd-ember" target="_blank">
|
||||
antd-ember<LinkIcon />
|
||||
<a href="https://ant-design-blazor.github.io/" target="_blank">
|
||||
ant-design-blazor/ant-design-blazor
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/zzuu666/antue" target="_blank">
|
||||
antue (vue)<LinkIcon />
|
||||
<span class="ant-divider ant-divider-vertical" />
|
||||
<a href="https://append-it.github.io/ant-design-blazor/" target="_blank">
|
||||
append-it/ant-design-blazor
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://append-it.github.io/ant-design-blazor/" target="_blank">Ant Design of Blazor<LinkIcon /></a>
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
|
||||
|
17
package.json
17
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "antd",
|
||||
"version": "4.1.5",
|
||||
"version": "4.2.0",
|
||||
"description": "An enterprise-class UI design language and React components implementation",
|
||||
"keywords": [
|
||||
"ant",
|
||||
@ -71,7 +71,7 @@
|
||||
"prettier": "prettier -c --write '**/*'",
|
||||
"pretty-quick": "pretty-quick",
|
||||
"pub": "antd-tools run pub",
|
||||
"prepublish": "antd-tools run guard",
|
||||
"prepublish": "npm run snyk-protect && antd-tools run guard",
|
||||
"site": "cross-env NODE_ICU_DATA=node_modules/full-icu concurrently \"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",
|
||||
@ -82,7 +82,8 @@
|
||||
"test-all": "./scripts/test-all.sh",
|
||||
"test-node": "jest --config .jest.node.js --no-cache",
|
||||
"tsc": "tsc",
|
||||
"site:test": "jest --config .jest.site.js --cache=false"
|
||||
"site:test": "jest --config .jest.site.js --cache=false",
|
||||
"snyk-protect": "snyk protect"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
@ -103,7 +104,7 @@
|
||||
"copy-to-clipboard": "^3.2.0",
|
||||
"css-animation": "^1.5.0",
|
||||
"lodash": "^4.17.13",
|
||||
"moment": "^2.24.0",
|
||||
"moment": "~2.24.0",
|
||||
"omit.js": "^1.0.2",
|
||||
"prop-types": "^15.7.2",
|
||||
"raf": "^3.4.1",
|
||||
@ -128,7 +129,7 @@
|
||||
"rc-slider": "~9.2.3",
|
||||
"rc-steps": "~3.5.0",
|
||||
"rc-switch": "~1.9.0",
|
||||
"rc-table": "~7.5.2",
|
||||
"rc-table": "~7.5.3",
|
||||
"rc-tabs": "~10.1.1",
|
||||
"rc-tooltip": "~4.0.2",
|
||||
"rc-tree": "~3.1.0",
|
||||
@ -139,7 +140,8 @@
|
||||
"rc-virtual-list": "^1.1.0",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"scroll-into-view-if-needed": "^2.2.20",
|
||||
"warning": "~4.0.3"
|
||||
"warning": "~4.0.3",
|
||||
"snyk": "^1.316.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ant-design/bisheng-plugin": "^2.3.0",
|
||||
@ -290,5 +292,6 @@
|
||||
"tnpm": {
|
||||
"mode": "npm"
|
||||
},
|
||||
"title": "Ant Design"
|
||||
"title": "Ant Design",
|
||||
"snyk": true
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
@import './colors';
|
||||
|
||||
.rc-footer {
|
||||
z-index: 9;
|
||||
z-index: 8;
|
||||
|
||||
&-container {
|
||||
max-width: unset;
|
||||
|
@ -258,16 +258,6 @@ export default function DesignPage() {
|
||||
{IconComponent}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://append-it.github.io/ant-design-blazor/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Ant Design of Blazor
|
||||
{IconComponent}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</Col>
|
||||
<Col xs={24} sm={15} style={{ alignSelf: 'flex-end', textAlign: 'right' }}>
|
||||
|
@ -79,11 +79,6 @@ class Footer extends React.Component<WrappedComponentProps> {
|
||||
url: 'https://vue.ant.design',
|
||||
openExternal: true,
|
||||
},
|
||||
{
|
||||
title: 'Ant Design Blazor',
|
||||
url: 'https://append-it.github.io/ant-design-blazor/',
|
||||
openExternal: true,
|
||||
},
|
||||
{
|
||||
title: 'Ant Design Landing',
|
||||
description: <FormattedMessage id="app.footer.landing" />,
|
||||
|
@ -37,16 +37,6 @@ export function getEcosystemGroup({ isZhCN }: SharedProps): React.ReactElement {
|
||||
Ant Design of Vue
|
||||
</a>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="blazor">
|
||||
<a
|
||||
href="https://append-it.github.io/ant-design-blazor/"
|
||||
className="header-link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Ant Design of Blazor
|
||||
</a>
|
||||
</Menu.Item>
|
||||
{isZhCN ? (
|
||||
<Menu.Item key="course" className="hide-in-home-page">
|
||||
<a
|
||||
|
Loading…
Reference in New Issue
Block a user