mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-12-01 11:39:28 +08:00
Merge pull request #17732 from ant-design/master
Merge master into feature
This commit is contained in:
commit
1147ae6949
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -21,20 +21,18 @@ Please makes sure that these form are filled before submitting your pull request
|
||||
- [ ] Branch merge
|
||||
- [ ] Other (about what?)
|
||||
|
||||
### 👻 What's the background?
|
||||
### 🔗 Related issue link
|
||||
|
||||
<!--
|
||||
1. Describe the source of requirement, like related issue link.
|
||||
|
||||
2. Describe the problem and the scenario.
|
||||
-->
|
||||
|
||||
### 💡 Solution
|
||||
### 💡 Background and solution
|
||||
|
||||
<!--
|
||||
1. How to fix the problem, and list final API implementation and usage sample if that is an new feature.
|
||||
|
||||
1. Describe the problem and the scenario.
|
||||
2. GIF or snapshot should be provided if includes UI/interactive modification.
|
||||
3. How to fix the problem, and list final API implementation and usage sample if that is an new feature.
|
||||
-->
|
||||
|
||||
### 📝 Changelog
|
||||
|
12
.github/PULL_REQUEST_TEMPLATE/pr_cn.md
vendored
12
.github/PULL_REQUEST_TEMPLATE/pr_cn.md
vendored
@ -21,20 +21,18 @@
|
||||
- [ ] 分支合并
|
||||
- [ ] 其他改动(是关于什么的改动?)
|
||||
|
||||
### 👻 需求背景
|
||||
### 🔗 相关 Issue
|
||||
|
||||
<!--
|
||||
1. 描述相关需求的来源,如相关的 issue 讨论链接。
|
||||
|
||||
2. 要解决的具体问题。
|
||||
-->
|
||||
|
||||
### 💡 解决方案和最终实现是?
|
||||
### 💡 需求背景和解决方案
|
||||
|
||||
<!--
|
||||
1. 列出最终的 API 实现和用法。
|
||||
|
||||
2. 涉及UI/交互变动需要有截图或 GIF。
|
||||
1. 要解决的具体问题。
|
||||
2. 列出最终的 API 实现和用法。
|
||||
3. 涉及UI/交互变动需要有截图或 GIF。
|
||||
-->
|
||||
|
||||
### 📝 更新日志怎么写?
|
||||
|
@ -162,29 +162,37 @@ describe('Affix Render', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('updatePosition when size changed', () => {
|
||||
document.body.innerHTML = '<div id="mounter" />';
|
||||
describe('updatePosition when size changed', () => {
|
||||
function test(name, index) {
|
||||
it(name, () => {
|
||||
document.body.innerHTML = '<div id="mounter" />';
|
||||
|
||||
const updateCalled = jest.fn();
|
||||
wrapper = mount(<AffixMounter offsetBottom={0} onTestUpdatePosition={updateCalled} />, {
|
||||
attachTo: document.getElementById('mounter'),
|
||||
});
|
||||
const updateCalled = jest.fn();
|
||||
wrapper = mount(<AffixMounter offsetBottom={0} onTestUpdatePosition={updateCalled} />, {
|
||||
attachTo: document.getElementById('mounter'),
|
||||
});
|
||||
|
||||
jest.runAllTimers();
|
||||
jest.runAllTimers();
|
||||
|
||||
movePlaceholder(300);
|
||||
expect(wrapper.instance().affix.state.affixStyle).toBeTruthy();
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
movePlaceholder(300);
|
||||
expect(wrapper.instance().affix.state.affixStyle).toBeTruthy();
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
|
||||
// Mock trigger resize
|
||||
updateCalled.mockReset();
|
||||
wrapper
|
||||
.find('ReactResizeObserver')
|
||||
.instance()
|
||||
.onResize();
|
||||
jest.runAllTimers();
|
||||
// Mock trigger resize
|
||||
updateCalled.mockReset();
|
||||
wrapper
|
||||
.find('ReactResizeObserver')
|
||||
.at(index)
|
||||
.instance()
|
||||
.onResize();
|
||||
jest.runAllTimers();
|
||||
|
||||
expect(updateCalled).toHaveBeenCalled();
|
||||
expect(updateCalled).toHaveBeenCalled();
|
||||
});
|
||||
}
|
||||
|
||||
test('inner', 0);
|
||||
test('outer', 1);
|
||||
});
|
||||
});
|
||||
|
@ -34,6 +34,37 @@ exports[`renders ./components/affix/demo/basic.md correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/affix/demo/debug.md correctly 1`] = `
|
||||
<div
|
||||
style="height:10000px"
|
||||
>
|
||||
<div>
|
||||
Top
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
style="background:red"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Affix top
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
Bottom
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/affix/demo/on-change.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
|
50
components/affix/demo/debug.md
Normal file
50
components/affix/demo/debug.md
Normal file
@ -0,0 +1,50 @@
|
||||
---
|
||||
order: 99
|
||||
title:
|
||||
zh-CN: 调试
|
||||
en-US: Debug
|
||||
debug: true
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
DEBUG
|
||||
|
||||
## en-US
|
||||
|
||||
DEBUG
|
||||
|
||||
```jsx
|
||||
import { Affix, Button } from 'antd';
|
||||
|
||||
class Demo extends React.Component {
|
||||
state = {
|
||||
top: 10,
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{ height: 10000 }}>
|
||||
<div>Top</div>
|
||||
<Affix offsetTop={this.state.top}>
|
||||
<div style={{ background: 'red' }}>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
this.setState({
|
||||
top: this.state.top + 10,
|
||||
});
|
||||
}}
|
||||
>
|
||||
Affix top
|
||||
</Button>
|
||||
</div>
|
||||
</Affix>
|
||||
<div>Bottom</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<Demo />, mountNode);
|
||||
```
|
@ -256,8 +256,8 @@ class Affix extends React.Component<AffixProps, AffixState> {
|
||||
|
||||
// =================== Render ===================
|
||||
renderAffix = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const { affixStyle, placeholderStyle, status } = this.state;
|
||||
const { prefixCls, style, children } = this.props;
|
||||
const { affixStyle, placeholderStyle } = this.state;
|
||||
const { prefixCls, children } = this.props;
|
||||
const className = classNames({
|
||||
[getPrefixCls('affix', prefixCls)]: affixStyle,
|
||||
});
|
||||
@ -267,22 +267,26 @@ class Affix extends React.Component<AffixProps, AffixState> {
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
props = omit(props, ['onTestUpdatePosition']);
|
||||
}
|
||||
const mergedPlaceholderStyle = {
|
||||
...(status === AffixStatus.None ? placeholderStyle : null),
|
||||
...style,
|
||||
};
|
||||
|
||||
return (
|
||||
<div {...props} style={mergedPlaceholderStyle} ref={this.savePlaceholderNode}>
|
||||
<div className={className} ref={this.saveFixedNode} style={this.state.affixStyle}>
|
||||
<ResizeObserver
|
||||
onResize={() => {
|
||||
this.updatePosition();
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ResizeObserver>
|
||||
<ResizeObserver
|
||||
onResize={() => {
|
||||
this.updatePosition();
|
||||
}}
|
||||
>
|
||||
<div {...props} ref={this.savePlaceholderNode}>
|
||||
{affixStyle && <div style={placeholderStyle} aria-hidden="true" />}
|
||||
<div className={className} ref={this.saveFixedNode} style={affixStyle}>
|
||||
<ResizeObserver
|
||||
onResize={() => {
|
||||
this.updatePosition();
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ResizeObserver>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ResizeObserver>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -145,6 +145,8 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
|
||||
};
|
||||
|
||||
private inkNode: HTMLSpanElement;
|
||||
// scroll scope's container
|
||||
private scrollContainer: HTMLElement | Window;
|
||||
|
||||
private links: string[] = [];
|
||||
private scrollEvent: any;
|
||||
@ -174,7 +176,8 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
|
||||
|
||||
componentDidMount() {
|
||||
const { getContainer } = this.props as AnchorDefaultProps;
|
||||
this.scrollEvent = addEventListener(getContainer(), 'scroll', this.handleScroll);
|
||||
this.scrollContainer = getContainer();
|
||||
this.scrollEvent = addEventListener(this.scrollContainer, 'scroll', this.handleScroll);
|
||||
this.handleScroll();
|
||||
}
|
||||
|
||||
@ -185,6 +188,16 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.scrollEvent) {
|
||||
const { getContainer } = this.props as AnchorDefaultProps;
|
||||
const currentContainer = getContainer();
|
||||
if (this.scrollContainer !== currentContainer) {
|
||||
this.scrollContainer = currentContainer;
|
||||
this.scrollEvent.remove();
|
||||
this.scrollEvent = addEventListener(this.scrollContainer, 'scroll', this.handleScroll);
|
||||
this.handleScroll();
|
||||
}
|
||||
}
|
||||
this.updateInk();
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ import Anchor from '..';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout));
|
||||
|
||||
describe('Anchor Render', () => {
|
||||
it('Anchor render perfectly', () => {
|
||||
const wrapper = mount(
|
||||
@ -62,7 +64,7 @@ describe('Anchor Render', () => {
|
||||
wrapper.instance().handleScrollTo('##API');
|
||||
expect(wrapper.instance().state.activeLink).toBe('##API');
|
||||
expect(scrollToSpy).not.toHaveBeenCalled();
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
await delay(1000);
|
||||
expect(scrollToSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -130,4 +132,116 @@ describe('Anchor Render', () => {
|
||||
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 delay(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 delay(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 delay(1000);
|
||||
holdContainer.container = document.getElementById('API2');
|
||||
wrapper.setProps({ 'data-only-trigger-re-render': true });
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@ -66,26 +66,6 @@
|
||||
}
|
||||
.button-disabled();
|
||||
}
|
||||
.button-variant-danger(@color; @background; @border) {
|
||||
.button-color(@color; @background; @border);
|
||||
&:hover {
|
||||
.button-color(
|
||||
@btn-primary-color; ~`colorPalette('@{color}', 5) `; ~`colorPalette('@{color}', 5) `
|
||||
);
|
||||
}
|
||||
&:focus {
|
||||
.button-color(
|
||||
~`colorPalette('@{color}', 5) `; @component-background; ~`colorPalette('@{color}', 5) `
|
||||
);
|
||||
}
|
||||
&:active,
|
||||
&.active {
|
||||
.button-color(
|
||||
@btn-primary-color; ~`colorPalette('@{color}', 7) `; ~`colorPalette('@{color}', 7) `
|
||||
);
|
||||
}
|
||||
.button-disabled();
|
||||
}
|
||||
.button-variant-ghost(@color; @border: @color) {
|
||||
.button-color(@color; transparent; @border);
|
||||
text-shadow: none;
|
||||
@ -230,7 +210,7 @@
|
||||
}
|
||||
// danger button style
|
||||
.btn-danger() {
|
||||
.button-variant-danger(@btn-danger-color, @btn-danger-bg, @btn-danger-border);
|
||||
.button-variant-primary(@btn-danger-color, @btn-danger-bg);
|
||||
}
|
||||
// link button style
|
||||
.btn-link() {
|
||||
|
@ -40,14 +40,14 @@ cols: 1
|
||||
|
||||
### Card.Grid
|
||||
|
||||
| Property | Description | Type | Default | 版本 |
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --------- | ---------------------- | ------ | ------- | ---- |
|
||||
| className | 网格容器类名 | string | - | |
|
||||
| style | 定义网格容器类名的样式 | object | - | |
|
||||
|
||||
### Card.Meta
|
||||
|
||||
| Property | Description | Type | Default | 版本 |
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| ----------- | ------------------ | --------- | ------- | ---- |
|
||||
| avatar | 头像/图标 | ReactNode | - | |
|
||||
| className | 容器类名 | string | - | |
|
||||
|
@ -139,7 +139,7 @@
|
||||
|
||||
& > span {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
display: block;
|
||||
min-width: 32px;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
@ -155,7 +155,8 @@
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
a {
|
||||
a,
|
||||
i {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
color: @text-color-secondary;
|
||||
@ -163,6 +164,7 @@
|
||||
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ cols: 1
|
||||
|
||||
## API
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| actions | 在评论内容下面呈现的操作项列表 | Array<ReactNode> | - | 3.11.0 |
|
||||
| author | 要显示为注释作者的元素 | string\|ReactNode | - | 3.11.0 |
|
||||
|
@ -9607,7 +9607,7 @@ exports[`ConfigProvider components Progress configProvider 1`] = `
|
||||
>
|
||||
<div
|
||||
class="config-progress-bg"
|
||||
style="width:0%;height:8px;border-radius:100px"
|
||||
style="width:0%;height:8px;border-radius:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -9634,7 +9634,7 @@ exports[`ConfigProvider components Progress normal 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width:0%;height:8px;border-radius:100px"
|
||||
style="width:0%;height:8px;border-radius:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -9661,7 +9661,7 @@ exports[`ConfigProvider components Progress prefixCls 1`] = `
|
||||
>
|
||||
<div
|
||||
class="prefix-Progress-bg"
|
||||
style="width:0%;height:8px;border-radius:100px"
|
||||
style="width:0%;height:8px;border-radius:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -354,7 +354,7 @@ describe('ConfigProvider', () => {
|
||||
// Modal
|
||||
testPair('Modal', props => (
|
||||
<div>
|
||||
<Modal {...props} visible>
|
||||
<Modal {...props} visible getContainer={false}>
|
||||
Bamboo is Little Light
|
||||
</Modal>
|
||||
</div>
|
||||
|
@ -4,11 +4,12 @@ import Drawer from '..';
|
||||
import Button from '../../button';
|
||||
|
||||
class MultiDrawer extends React.Component {
|
||||
state = { visible: false, childrenDrawer: false };
|
||||
state = { visible: false, childrenDrawer: false, hasChildren: true };
|
||||
|
||||
showDrawer = () => {
|
||||
this.setState({
|
||||
visible: true,
|
||||
hasChildren: true,
|
||||
});
|
||||
};
|
||||
|
||||
@ -21,6 +22,7 @@ class MultiDrawer extends React.Component {
|
||||
showChildrenDrawer = () => {
|
||||
this.setState({
|
||||
childrenDrawer: true,
|
||||
hasChildren: true,
|
||||
});
|
||||
};
|
||||
|
||||
@ -30,14 +32,23 @@ class MultiDrawer extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
onRemoveChildDrawer = () => {
|
||||
this.setState({
|
||||
hasChildren: false,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { childrenDrawer, visible } = this.state;
|
||||
const { childrenDrawer, visible, hasChildren } = this.state;
|
||||
const { placement } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<Button type="primary" id="open_drawer" onClick={this.showDrawer}>
|
||||
Open drawer
|
||||
</Button>
|
||||
<Button type="primary" id="remove_drawer" onClick={this.onRemoveChildDrawer}>
|
||||
rm child drawer
|
||||
</Button>
|
||||
<Drawer
|
||||
title="Multi-level drawer"
|
||||
className="test_drawer"
|
||||
@ -50,17 +61,19 @@ class MultiDrawer extends React.Component {
|
||||
<Button type="primary" id="open_two_drawer" onClick={this.showChildrenDrawer}>
|
||||
Two-level drawer
|
||||
</Button>
|
||||
<Drawer
|
||||
title="Two-level Drawer"
|
||||
width={320}
|
||||
className="Two-level"
|
||||
getContainer={false}
|
||||
placement={placement}
|
||||
onClose={this.onChildrenDrawerClose}
|
||||
visible={childrenDrawer}
|
||||
>
|
||||
<div id="two_drawer_text">This is two-level drawer</div>
|
||||
</Drawer>
|
||||
{hasChildren && (
|
||||
<Drawer
|
||||
title="Two-level Drawer"
|
||||
width={320}
|
||||
className="Two-level"
|
||||
getContainer={false}
|
||||
placement={placement}
|
||||
onClose={this.onChildrenDrawerClose}
|
||||
visible={childrenDrawer}
|
||||
>
|
||||
<div id="two_drawer_text">This is two-level drawer</div>
|
||||
</Drawer>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
@ -121,4 +134,17 @@ describe('Drawer', () => {
|
||||
expect(translateX).toEqual('translateY(180px)');
|
||||
expect(wrapper.find('#two_drawer_text').exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('render MultiDrawer is child in unmount', () => {
|
||||
const wrapper = mount(<MultiDrawer placement="top" mask={false} />);
|
||||
wrapper.find('button#open_drawer').simulate('click');
|
||||
wrapper.find('button#open_two_drawer').simulate('click');
|
||||
wrapper.find('button#remove_drawer').simulate('click');
|
||||
let translateX = wrapper.find('.ant-drawer.test_drawer').get(0).props.style.transform;
|
||||
expect(translateX).toEqual(undefined);
|
||||
wrapper.find('button#open_two_drawer').simulate('click');
|
||||
translateX = wrapper.find('.ant-drawer.test_drawer').get(0).props.style.transform;
|
||||
expect(translateX).toEqual('translateY(180px)');
|
||||
expect(wrapper.find('#two_drawer_text').exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
@ -21,7 +21,7 @@ A Drawer is a panel that is typically overlaid on top of a page and slides in fr
|
||||
| --- | --- | --- | --- | --- |
|
||||
| closable | Whether a close (x) button is visible on top right of the Drawer dialog or not. | boolean | true | 3.7.0 |
|
||||
| destroyOnClose | Whether to unmount child components on closing drawer or not. | boolean | false | 3.7.0 |
|
||||
| getContainer | Return the mounted node for Drawer. | HTMLElement \| `() => HTMLElement` \| Selectors | 'body' | 3.7.0 |
|
||||
| getContainer | Return the mounted node for Drawer. | HTMLElement \| `() => HTMLElement` \| Selectors \| false | 'body' | 3.7.0 |
|
||||
| mask | Whether to show mask or not. | Boolean | true | 3.7.0 |
|
||||
| maskClosable | Clicking on the mask (area outside the Drawer) to close the Drawer or not. | boolean | true | 3.7.0 |
|
||||
| maskStyle | Style for Drawer's mask element. | object | {} | 3.7.0 |
|
||||
|
@ -20,7 +20,7 @@ type placementType = (typeof PlacementTypes)[number];
|
||||
export interface DrawerProps {
|
||||
closable?: boolean;
|
||||
destroyOnClose?: boolean;
|
||||
getContainer?: string | HTMLElement | getContainerFunc;
|
||||
getContainer?: string | HTMLElement | getContainerFunc | false;
|
||||
maskClosable?: boolean;
|
||||
mask?: boolean;
|
||||
maskStyle?: React.CSSProperties;
|
||||
@ -63,9 +63,19 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
|
||||
push: false,
|
||||
};
|
||||
|
||||
parentDrawer: Drawer;
|
||||
parentDrawer: Drawer | null;
|
||||
|
||||
destroyClose: boolean;
|
||||
|
||||
public componentDidMount() {
|
||||
// fix: delete drawer in child and re-render, no push started.
|
||||
// <Drawer>{show && <Drawer />}</Drawer>
|
||||
const { visible } = this.props;
|
||||
if (visible && this.parentDrawer) {
|
||||
this.parentDrawer.push();
|
||||
}
|
||||
}
|
||||
|
||||
public componentDidUpdate(preProps: DrawerProps) {
|
||||
const { visible } = this.props;
|
||||
if (preProps.visible !== visible && this.parentDrawer) {
|
||||
@ -77,19 +87,13 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
|
||||
}
|
||||
}
|
||||
|
||||
close = (e: EventType) => {
|
||||
const { visible, onClose } = this.props;
|
||||
if (visible !== undefined && onClose) {
|
||||
onClose(e);
|
||||
public componentWillUnmount() {
|
||||
// unmount drawer in child, clear push.
|
||||
if (this.parentDrawer) {
|
||||
this.parentDrawer.pull();
|
||||
this.parentDrawer = null;
|
||||
}
|
||||
};
|
||||
|
||||
onMaskClick = (e: EventType) => {
|
||||
if (!this.props.maskClosable && !(e.nativeEvent instanceof KeyboardEvent)) {
|
||||
return;
|
||||
}
|
||||
this.close(e);
|
||||
};
|
||||
}
|
||||
|
||||
push = () => {
|
||||
this.setState({
|
||||
@ -116,7 +120,7 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
|
||||
|
||||
getDestroyOnClose = () => this.props.destroyOnClose && !this.props.visible;
|
||||
|
||||
// get drawar push width or height
|
||||
// get drawer push width or height
|
||||
getPushTransform = (placement?: placementType) => {
|
||||
if (placement === 'left' || placement === 'right') {
|
||||
return `translateX(${placement === 'left' ? 180 : -180}px)`;
|
||||
@ -152,10 +156,10 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
|
||||
}
|
||||
|
||||
renderCloseIcon() {
|
||||
const { closable, prefixCls } = this.props;
|
||||
const { closable, prefixCls, onClose } = this.props;
|
||||
return (
|
||||
closable && (
|
||||
<button onClick={this.close} aria-label="Close" className={`${prefixCls}-close`}>
|
||||
<button onClick={onClose} aria-label="Close" className={`${prefixCls}-close`}>
|
||||
<Icon type="close" />
|
||||
</button>
|
||||
)
|
||||
@ -200,7 +204,7 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
|
||||
);
|
||||
};
|
||||
|
||||
// render Provider for Multi-level drawe
|
||||
// render Provider for Multi-level drawer
|
||||
renderProvider = (value: Drawer) => {
|
||||
const {
|
||||
prefixCls,
|
||||
@ -214,11 +218,9 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
|
||||
closable,
|
||||
destroyOnClose,
|
||||
mask,
|
||||
maskClosable,
|
||||
bodyStyle,
|
||||
title,
|
||||
push,
|
||||
onClose,
|
||||
visible,
|
||||
// ConfigConsumerProps
|
||||
getPopupContainer,
|
||||
@ -250,7 +252,6 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
|
||||
{...offsetStyle}
|
||||
prefixCls={prefixCls}
|
||||
open={this.props.visible}
|
||||
onMaskClick={this.onMaskClick}
|
||||
showMask={mask}
|
||||
placement={placement}
|
||||
style={this.getRcDrawerStyle()}
|
||||
|
@ -20,9 +20,9 @@ title: Drawer
|
||||
| --- | --- | --- | --- | --- |
|
||||
| closable | 是否显示右上角的关闭按钮 | boolean | true | 3.7.0 |
|
||||
| destroyOnClose | 关闭时销毁 Drawer 里的子元素 | boolean | false | 3.7.0 |
|
||||
| getContainer | 指定 Drawer 挂载的 HTML 节点 | HTMLElement \| `() => HTMLElement` \| Selectors | 'body' | 3.7.0 |
|
||||
| maskClosable | 点击蒙层是否允许关闭 | boolean | true | 3.7.0 | 3.7.0 |
|
||||
| mask | 是否展示遮罩 | Boolean | true |
|
||||
| getContainer | 指定 Drawer 挂载的 HTML 节点, false 为挂载在当前 dom | HTMLElement \| `() => HTMLElement` \| Selectors \| false | 'body' | 3.7.0 |
|
||||
| maskClosable | 点击蒙层是否允许关闭 | boolean | true | 3.7.0 |
|
||||
| mask | 是否展示遮罩 | Boolean | true | 3.7.0 |
|
||||
| maskStyle | 遮罩样式 | object | {} | 3.7.0 |
|
||||
| style | 可用于设置 Drawer 最外层容器的样式 | object | - | 3.7.0 |
|
||||
| bodyStyle | 可用于设置 Drawer 的样式,调整浮层位置等 | object | - | 3.12.0 |
|
||||
|
@ -11,10 +11,10 @@
|
||||
z-index: @zindex-modal;
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
|
||||
transition: transform @animation-duration-slow @ease-base-out;
|
||||
> * {
|
||||
transition: transform @animation-duration-slow @ease-base-in,
|
||||
box-shadow @animation-duration-slow @ease-base-in;
|
||||
transition: transform @animation-duration-slow @ease-base-out,
|
||||
box-shadow @animation-duration-slow @ease-base-out;
|
||||
}
|
||||
|
||||
&-content-wrapper {
|
||||
@ -197,7 +197,6 @@
|
||||
transition: opacity @animation-duration-slow linear, height 0s ease @animation-duration-slow;
|
||||
}
|
||||
&-open {
|
||||
transition: transform @animation-duration-slow @ease-base-out;
|
||||
&-content {
|
||||
box-shadow: @shadow-2;
|
||||
}
|
||||
|
@ -531,6 +531,21 @@ exports[`renders ./components/empty/demo/customize.md correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/empty/demo/description.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-empty"
|
||||
>
|
||||
<div
|
||||
class="ant-empty-image"
|
||||
>
|
||||
<img
|
||||
alt="empty"
|
||||
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTg0IiBoZWlnaHQ9IjE1MiIgdmlld0JveD0iMCAwIDE4NCAxNTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDI0IDMxLjY3KSI+CiAgICAgIDxlbGxpcHNlIGZpbGwtb3BhY2l0eT0iLjgiIGZpbGw9IiNGNUY1RjciIGN4PSI2Ny43OTciIGN5PSIxMDYuODkiIHJ4PSI2Ny43OTciIHJ5PSIxMi42NjgiLz4KICAgICAgPHBhdGggZD0iTTEyMi4wMzQgNjkuNjc0TDk4LjEwOSA0MC4yMjljLTEuMTQ4LTEuMzg2LTIuODI2LTIuMjI1LTQuNTkzLTIuMjI1aC01MS40NGMtMS43NjYgMC0zLjQ0NC44MzktNC41OTIgMi4yMjVMMTMuNTYgNjkuNjc0djE1LjM4M2gxMDguNDc1VjY5LjY3NHoiIGZpbGw9IiNBRUI4QzIiLz4KICAgICAgPHBhdGggZD0iTTEwMS41MzcgODYuMjE0TDgwLjYzIDYxLjEwMmMtMS4wMDEtMS4yMDctMi41MDctMS44NjctNC4wNDgtMS44NjdIMzEuNzI0Yy0xLjU0IDAtMy4wNDcuNjYtNC4wNDggMS44NjdMNi43NjkgODYuMjE0djEzLjc5Mmg5NC43NjhWODYuMjE0eiIgZmlsbD0idXJsKCNsaW5lYXJHcmFkaWVudC0xKSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTMuNTYpIi8+CiAgICAgIDxwYXRoIGQ9Ik0zMy44MyAwaDY3LjkzM2E0IDQgMCAwIDEgNCA0djkzLjM0NGE0IDQgMCAwIDEtNCA0SDMzLjgzYTQgNCAwIDAgMS00LTRWNGE0IDQgMCAwIDEgNC00eiIgZmlsbD0iI0Y1RjVGNyIvPgogICAgICA8cGF0aCBkPSJNNDIuNjc4IDkuOTUzaDUwLjIzN2EyIDIgMCAwIDEgMiAyVjM2LjkxYTIgMiAwIDAgMS0yIDJINDIuNjc4YTIgMiAwIDAgMS0yLTJWMTEuOTUzYTIgMiAwIDAgMSAyLTJ6TTQyLjk0IDQ5Ljc2N2g0OS43MTNhMi4yNjIgMi4yNjIgMCAxIDEgMCA0LjUyNEg0Mi45NGEyLjI2MiAyLjI2MiAwIDAgMSAwLTQuNTI0ek00Mi45NCA2MS41M2g0OS43MTNhMi4yNjIgMi4yNjIgMCAxIDEgMCA0LjUyNUg0Mi45NGEyLjI2MiAyLjI2MiAwIDAgMSAwLTQuNTI1ek0xMjEuODEzIDEwNS4wMzJjLS43NzUgMy4wNzEtMy40OTcgNS4zNi02LjczNSA1LjM2SDIwLjUxNWMtMy4yMzggMC01Ljk2LTIuMjktNi43MzQtNS4zNmE3LjMwOSA3LjMwOSAwIDAgMS0uMjIyLTEuNzlWNjkuNjc1aDI2LjMxOGMyLjkwNyAwIDUuMjUgMi40NDggNS4yNSA1LjQydi4wNGMwIDIuOTcxIDIuMzcgNS4zNyA1LjI3NyA1LjM3aDM0Ljc4NWMyLjkwNyAwIDUuMjc3LTIuNDIxIDUuMjc3LTUuMzkzVjc1LjFjMC0yLjk3MiAyLjM0My01LjQyNiA1LjI1LTUuNDI2aDI2LjMxOHYzMy41NjljMCAuNjE3LS4wNzcgMS4yMTYtLjIyMSAxLjc4OXoiIGZpbGw9IiNEQ0UwRTYiLz4KICAgIDwvZz4KICAgIDxwYXRoIGQ9Ik0xNDkuMTIxIDMzLjI5MmwtNi44MyAyLjY1YTEgMSAwIDAgMS0xLjMxNy0xLjIzbDEuOTM3LTYuMjA3Yy0yLjU4OS0yLjk0NC00LjEwOS02LjUzNC00LjEwOS0xMC40MDhDMTM4LjgwMiA4LjEwMiAxNDguOTIgMCAxNjEuNDAyIDAgMTczLjg4MSAwIDE4NCA4LjEwMiAxODQgMTguMDk3YzAgOS45OTUtMTAuMTE4IDE4LjA5Ny0yMi41OTkgMTguMDk3LTQuNTI4IDAtOC43NDQtMS4wNjYtMTIuMjgtMi45MDJ6IiBmaWxsPSIjRENFMEU2Ii8+CiAgICA8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxNDkuNjUgMTUuMzgzKSIgZmlsbD0iI0ZGRiI+CiAgICAgIDxlbGxpcHNlIGN4PSIyMC42NTQiIGN5PSIzLjE2NyIgcng9IjIuODQ5IiByeT0iMi44MTUiLz4KICAgICAgPHBhdGggZD0iTTUuNjk4IDUuNjNIMEwyLjg5OC43MDR6TTkuMjU5LjcwNGg0Ljk4NVY1LjYzSDkuMjU5eiIvPgogICAgPC9nPgogIDwvZz4KPC9zdmc+Cg=="
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/empty/demo/simple.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-empty ant-empty-normal"
|
||||
|
@ -7,4 +7,9 @@ describe('Empty', () => {
|
||||
const wrapper = mount(<Empty imageStyle={{ height: 20 }} />);
|
||||
expect(wrapper.find('.ant-empty-image').props().style.height).toBe(20);
|
||||
});
|
||||
|
||||
it('description can be false', () => {
|
||||
const wrapper = mount(<Empty description={false} />);
|
||||
expect(wrapper.find('.ant-empty-description').length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
20
components/empty/demo/description.md
Normal file
20
components/empty/demo/description.md
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
order: 4
|
||||
title:
|
||||
zh-CN: 无描述
|
||||
en-US: No description
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
无描述展示。
|
||||
|
||||
## en-US
|
||||
|
||||
Simplest Usage with no description.
|
||||
|
||||
```jsx
|
||||
import { Empty } from 'antd';
|
||||
|
||||
ReactDOM.render(<Empty description={false} />, mountNode);
|
||||
```
|
@ -39,7 +39,7 @@ const OriginEmpty: React.SFC<EmptyProps> = (props: EmptyProps) => (
|
||||
<LocaleReceiver componentName="Empty">
|
||||
{(locale: TransferLocale) => {
|
||||
const prefixCls = getPrefixCls('empty', customizePrefixCls);
|
||||
const des = description || locale.description;
|
||||
const des = typeof description !== 'undefined' ? description : locale.description;
|
||||
const alt = typeof des === 'string' ? des : 'empty';
|
||||
|
||||
let imageNode: React.ReactNode = null;
|
||||
@ -64,7 +64,7 @@ const OriginEmpty: React.SFC<EmptyProps> = (props: EmptyProps) => (
|
||||
<div className={`${prefixCls}-image`} style={imageStyle}>
|
||||
{imageNode}
|
||||
</div>
|
||||
<p className={`${prefixCls}-description`}>{des}</p>
|
||||
{des && <p className={`${prefixCls}-description`}>{des}</p>}
|
||||
{children && <div className={`${prefixCls}-footer`}>{children}</div>}
|
||||
</div>
|
||||
);
|
||||
|
@ -141,7 +141,7 @@ export type WrappedFormUtils<V = any> = {
|
||||
/** 获取一个输入控件的值 */
|
||||
getFieldValue(fieldName: string): any;
|
||||
/** 设置一组输入控件的值 */
|
||||
setFieldsValue(obj: Object): void;
|
||||
setFieldsValue(obj: Object, callback?: Function): void;
|
||||
/** 设置一组输入控件的值 */
|
||||
setFields(obj: Object): void;
|
||||
/** 校验并获取一组输入域的值与 Error */
|
||||
|
@ -92,7 +92,7 @@ If the form has been decorated by `Form.create` then it has `this.props.form` pr
|
||||
| isFieldValidating | Check if the specified field is being validated. | Function(name) | |
|
||||
| resetFields | Reset the specified fields' value(to `initialValue`) and status. If you don't specify a parameter, all the fields will be reset. | Function(\[names: string\[]]) | |
|
||||
| setFields | Set value and error state of fields. [Code Sample](https://github.com/react-component/form/blob/3b9959b57ab30b41d8890ff30c79a7e7c383cad3/examples/server-validate.js#L74-L79) | ({<br /> \[fieldName\]: {value: any, errors: \[Error\] }<br />}) => void | |
|
||||
| setFieldsValue | Set the value of a field. (Note: please don't use it in `componentWillReceiveProps`, otherwise, it will cause an endless loop, [reason](https://github.com/ant-design/ant-design/issues/2985)) | ({ \[fieldName\]: value }) => void | |
|
||||
| setFieldsValue | Set the value of a field. (Note: please don't use it in `componentWillReceiveProps`, otherwise, it will cause an endless loop, [reason](https://github.com/ant-design/ant-design/issues/2985)) | (<br /> { \[fieldName\]: value },<br /> callback: Function<br />) => void | |
|
||||
| validateFields | Validate the specified fields and get theirs values and errors. If you don't specify the parameter of fieldNames, you will validate all fields. | (<br /> \[fieldNames: string\[]],<br /> \[options: object\],<br /> callback(errors, values)<br />) => void | |
|
||||
| validateFieldsAndScroll | This function is similar to `validateFields`, but after validation, if the target field is not in visible area of form, form will be automatically scrolled to the target field area. | same as `validateFields` | |
|
||||
|
||||
|
@ -95,7 +95,7 @@ this.form // => The instance of CustomizedForm
|
||||
| isFieldValidating | 判断一个输入控件是否在校验状态 | Function(name) | |
|
||||
| resetFields | 重置一组输入控件的值(为 `initialValue`)与状态,如不传入参数,则重置所有组件 | Function(\[names: string\[]]) | |
|
||||
| setFields | 设置一组输入控件的值与错误状态:[代码](https://github.com/react-component/form/blob/3b9959b57ab30b41d8890ff30c79a7e7c383cad3/examples/server-validate.js#L74-L79) | ({<br /> \[fieldName\]: {value: any, errors: \[Error\] }<br />}) => void | |
|
||||
| setFieldsValue | 设置一组输入控件的值(注意:不要在 `componentWillReceiveProps` 内使用,否则会导致死循环,[原因](https://github.com/ant-design/ant-design/issues/2985)) | ({ \[fieldName\]: value }) => void | |
|
||||
| setFieldsValue | 设置一组输入控件的值(注意:不要在 `componentWillReceiveProps` 内使用,否则会导致死循环,[原因](https://github.com/ant-design/ant-design/issues/2985)) | (<br /> { \[fieldName\]: value },<br /> callback: Function<br />) => void | |
|
||||
| validateFields | 校验并获取一组输入域的值与 Error,若 fieldNames 参数为空,则校验全部组件 | (<br /> \[fieldNames: string\[]],<br /> \[options: object\],<br /> callback(errors, values)<br />) => void | |
|
||||
| validateFieldsAndScroll | 与 `validateFields` 相似,但校验完后,如果校验不通过的菜单域不在可见范围内,则自动滚动进可见范围 | 参考 `validateFields` | |
|
||||
|
||||
@ -205,7 +205,7 @@ validateFields(['field1', 'field2'], options, (errors, values) => {
|
||||
| labelCol | label 标签布局,同 `<Col>` 组件,设置 `span` `offset` 值,如 `{span: 3, offset: 12}` 或 `sm: {span: 3, offset: 12}`。在 3.14.0 之后,你可以通过 Form 的 labelCol 进行统一设置。当和 Form 同时设置时,以 FormItem 为准。 | [object](https://ant.design/components/grid/#Col) | | |
|
||||
| required | 是否必填,如不设置,则会根据校验规则自动生成 | boolean | false | |
|
||||
| validateStatus | 校验状态,如不设置,则会根据校验规则自动生成,可选:'success' 'warning' 'error' 'validating' | string | | |
|
||||
| wrapperCol | 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol。在 3.14.0 之后,你可以通过 Form 的 labelCol 进行统一设置。当和 Form 同时设置时,以 FormItem 为准。 | [object](https://ant.design/components/grid/#Col) | | |
|
||||
| wrapperCol | 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol。在 3.14.0 之后,你可以通过 Form 的 wrapperCol 进行统一设置。当和 Form 同时设置时,以 FormItem 为准。 | [object](https://ant.design/components/grid/#Col) | | |
|
||||
|
||||
### 校验规则
|
||||
|
||||
|
@ -147,7 +147,7 @@ const App = () => (
|
||||
<Transfer dataSource={[]} showSearch targetKeys={[]} render={item => item.title} />
|
||||
<Calendar fullscreen={false} value={moment()} />
|
||||
<Table dataSource={[]} columns={columns} />
|
||||
<Modal title="Locale Modal" visible>
|
||||
<Modal title="Locale Modal" visible getContainer={false}>
|
||||
<p>Locale Modal</p>
|
||||
</Modal>
|
||||
</div>
|
||||
|
@ -569,7 +569,6 @@ describe('Menu', () => {
|
||||
.instance()
|
||||
.getMenuOpenAnimation(''),
|
||||
).toBe('');
|
||||
expect(wrapper.find('InternalMenu').state().switchingModeFromInline).toBe(false);
|
||||
});
|
||||
|
||||
it('MenuItem should not render Tooltip when inlineCollapsed is false', () => {
|
||||
|
@ -276,10 +276,6 @@ class InternalMenu extends React.Component<InternalMenuProps, MenuState> {
|
||||
// submenu should hide without animation
|
||||
if (this.state.switchingModeFromInline) {
|
||||
menuOpenAnimation = '';
|
||||
this.setState({
|
||||
switchingModeFromInline: false,
|
||||
});
|
||||
// this.switchingModeFromInline = false;
|
||||
} else {
|
||||
menuOpenAnimation = 'zoom-big';
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ export interface ModalProps {
|
||||
maskTransitionName?: string;
|
||||
transitionName?: string;
|
||||
className?: string;
|
||||
getContainer?: (instance: React.ReactInstance) => HTMLElement;
|
||||
getContainer?: string | HTMLElement | getContainerFunc | false | null;
|
||||
zIndex?: number;
|
||||
bodyStyle?: React.CSSProperties;
|
||||
maskStyle?: React.CSSProperties;
|
||||
@ -78,6 +78,8 @@ export interface ModalProps {
|
||||
prefixCls?: string;
|
||||
}
|
||||
|
||||
type getContainerFunc = () => HTMLElement;
|
||||
|
||||
export interface ModalFuncProps {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
@ -106,7 +108,7 @@ export interface ModalFuncProps {
|
||||
maskStyle?: React.CSSProperties;
|
||||
type?: string;
|
||||
keyboard?: boolean;
|
||||
getContainer?: (instance: React.ReactInstance) => HTMLElement;
|
||||
getContainer?: string | HTMLElement | getContainerFunc | false | null;
|
||||
autoFocusButton?: null | 'ok' | 'cancel';
|
||||
transitionName?: string;
|
||||
maskTransitionName?: string;
|
||||
@ -221,7 +223,7 @@ export default class Modal extends React.Component<ModalProps, {}> {
|
||||
return (
|
||||
<Dialog
|
||||
{...restProps}
|
||||
getContainer={getContainer || getContextPopupContainer}
|
||||
getContainer={getContainer === undefined ? getContextPopupContainer : getContainer}
|
||||
prefixCls={prefixCls}
|
||||
wrapClassName={classNames({ [`${prefixCls}-centered`]: !!centered }, wrapClassName)}
|
||||
footer={footer === undefined ? defaultFooter : footer}
|
||||
|
@ -2,91 +2,94 @@
|
||||
|
||||
exports[`Modal render correctly 1`] = `
|
||||
<div>
|
||||
<div />
|
||||
<div>
|
||||
<div
|
||||
class="ant-modal-mask fade-appear"
|
||||
/>
|
||||
<div
|
||||
class="ant-modal-wrap "
|
||||
role="dialog"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
class="ant-modal zoom-appear"
|
||||
role="document"
|
||||
style="width: 520px;"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="width: 0px; height: 0px; overflow: hidden;"
|
||||
tabindex="0"
|
||||
class="ant-modal-mask fade-appear"
|
||||
/>
|
||||
<div
|
||||
class="ant-modal-content"
|
||||
class="ant-modal-wrap "
|
||||
role="dialog"
|
||||
tabindex="-1"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-modal-close"
|
||||
type="button"
|
||||
<div
|
||||
class="ant-modal zoom-appear"
|
||||
role="document"
|
||||
style="width: 520px;"
|
||||
>
|
||||
<span
|
||||
class="ant-modal-close-x"
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="width: 0px; height: 0px; overflow: hidden;"
|
||||
tabindex="0"
|
||||
/>
|
||||
<div
|
||||
class="ant-modal-content"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: close"
|
||||
class="anticon anticon-close ant-modal-close-icon"
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-modal-close"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="ant-modal-body"
|
||||
>
|
||||
Here is content of Modal
|
||||
</div>
|
||||
<div
|
||||
class="ant-modal-footer"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Cancel
|
||||
<i
|
||||
aria-label="icon: close"
|
||||
class="anticon anticon-close ant-modal-close-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
<div
|
||||
class="ant-modal-body"
|
||||
>
|
||||
<span>
|
||||
OK
|
||||
</span>
|
||||
</button>
|
||||
Here is content of Modal
|
||||
</div>
|
||||
<div
|
||||
class="ant-modal-footer"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Cancel
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
OK
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="width: 0px; height: 0px; overflow: hidden;"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="width: 0px; height: 0px; overflow: hidden;"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -95,69 +98,72 @@ exports[`Modal render correctly 1`] = `
|
||||
|
||||
exports[`Modal render without footer 1`] = `
|
||||
<div>
|
||||
<div />
|
||||
<div>
|
||||
<div
|
||||
class="ant-modal-mask fade-appear"
|
||||
/>
|
||||
<div
|
||||
class="ant-modal-wrap "
|
||||
role="dialog"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
class="ant-modal zoom-appear"
|
||||
role="document"
|
||||
style="width: 520px;"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="width: 0px; height: 0px; overflow: hidden;"
|
||||
tabindex="0"
|
||||
class="ant-modal-mask fade-appear"
|
||||
/>
|
||||
<div
|
||||
class="ant-modal-content"
|
||||
class="ant-modal-wrap "
|
||||
role="dialog"
|
||||
tabindex="-1"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-modal-close"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: close"
|
||||
class="anticon anticon-close ant-modal-close-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="ant-modal-body"
|
||||
class="ant-modal zoom-appear"
|
||||
role="document"
|
||||
style="width: 520px;"
|
||||
>
|
||||
Here is content of Modal
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="width: 0px; height: 0px; overflow: hidden;"
|
||||
tabindex="0"
|
||||
/>
|
||||
<div
|
||||
class="ant-modal-content"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="ant-modal-close"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<i
|
||||
aria-label="icon: close"
|
||||
class="anticon anticon-close ant-modal-close-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="close"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="ant-modal-body"
|
||||
>
|
||||
Here is content of Modal
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="width: 0px; height: 0px; overflow: hidden;"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="width: 0px; height: 0px; overflow: hidden;"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -84,8 +84,8 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
it('shows animation when close', () => {
|
||||
jest.useFakeTimers();
|
||||
open();
|
||||
$$('.ant-btn')[0].click();
|
||||
expect($$('.ant-modal-confirm')).toHaveLength(1);
|
||||
$$('.ant-btn')[0].click();
|
||||
jest.runAllTimers();
|
||||
expect($$('.ant-modal-confirm')).toHaveLength(0);
|
||||
jest.useRealTimers();
|
||||
|
@ -165,7 +165,7 @@ export default function confirm(config: ModalFuncProps) {
|
||||
}
|
||||
|
||||
function render(props: any) {
|
||||
ReactDOM.render(<ConfirmDialog {...props} />, div);
|
||||
ReactDOM.render(<ConfirmDialog {...props} getContainer={false}/>, div);
|
||||
}
|
||||
|
||||
render(currentConfig);
|
||||
|
@ -23,7 +23,7 @@ When requiring users to interact with the application, but without jumping to a
|
||||
| destroyOnClose | Whether to unmount child components on onClose | boolean | false | 3.1.0 |
|
||||
| footer | Footer content, set as `footer={null}` when you don't need default buttons | string\|ReactNode | OK and Cancel buttons | |
|
||||
| forceRender | Force render Modal | boolean | false | 3.12.0 |
|
||||
| getContainer | Return the mount node for Modal | (instance): HTMLElement | () => document.body | |
|
||||
| getContainer | Return the mount node for Modal | HTMLElement \| `() => HTMLElement` \| Selectors \| false | document.body | 3.20.2 |
|
||||
| mask | Whether show mask or not. | Boolean | true | |
|
||||
| maskClosable | Whether to close the modal dialog when the mask (area outside the modal) is clicked | boolean | true | |
|
||||
| maskStyle | Style for modal's mask element. | object | {} | |
|
||||
|
@ -26,7 +26,7 @@ title: Modal
|
||||
| destroyOnClose | 关闭时销毁 Modal 里的子元素 | boolean | false | 3.1.0 |
|
||||
| footer | 底部内容,当不需要默认底部按钮时,可以设为 `footer={null}` | string\|ReactNode | 确定取消按钮 | |
|
||||
| forceRender | 强制渲染 Modal | boolean | false | 3.12.0 |
|
||||
| getContainer | 指定 Modal 挂载的 HTML 节点 | (instance): HTMLElement | () => document.body | |
|
||||
| getContainer | 指定 Modal 挂载的 HTML 节点, false 为挂载在当前 dom | HTMLElement \| `() => HTMLElement` \| Selectors \| false | document.body | 3.20.2 |
|
||||
| keyboard | 是否支持键盘 esc 关闭 | boolean | true | 3.4.2 |
|
||||
| mask | 是否展示遮罩 | Boolean | true | |
|
||||
| maskClosable | 点击蒙层是否允许关闭 | boolean | true | |
|
||||
|
@ -53,6 +53,10 @@
|
||||
padding: 0 6px;
|
||||
color: @text-color;
|
||||
transition: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus,
|
||||
|
@ -78,13 +78,13 @@ const Line: React.SFC<LineProps> = props => {
|
||||
const percentStyle = {
|
||||
width: `${validProgress(percent)}%`,
|
||||
height: strokeWidth || (size === 'small' ? 6 : 8),
|
||||
borderRadius: strokeLinecap === 'square' ? 0 : '100px',
|
||||
borderRadius: strokeLinecap === 'square' ? 0 : '',
|
||||
...backgroundProps,
|
||||
};
|
||||
const successPercentStyle = {
|
||||
width: `${validProgress(successPercent)}%`,
|
||||
height: strokeWidth || (size === 'small' ? 6 : 8),
|
||||
borderRadius: strokeLinecap === 'square' ? 0 : '100px',
|
||||
borderRadius: strokeLinecap === 'square' ? 0 : '',
|
||||
};
|
||||
const successSegment =
|
||||
successPercent !== undefined ? (
|
||||
|
@ -491,7 +491,7 @@ exports[`renders ./components/progress/demo/dynamic.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width:0%;height:8px;border-radius:100px"
|
||||
style="width:0%;height:8px;border-radius:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -664,7 +664,7 @@ exports[`renders ./components/progress/demo/gradient-line.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width:99.9%;height:8px;border-radius:100px;background-image:linear-gradient(to right, #108ee9 0%, #87d068 100%)"
|
||||
style="width:99.9%;height:8px;border-radius:;background-image:linear-gradient(to right, #108ee9 0%, #87d068 100%)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -688,7 +688,7 @@ exports[`renders ./components/progress/demo/gradient-line.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width:99.9%;height:8px;border-radius:100px;background-image:linear-gradient(to right, #108ee9, #87d068)"
|
||||
style="width:99.9%;height:8px;border-radius:;background-image:linear-gradient(to right, #108ee9, #87d068)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -854,7 +854,7 @@ exports[`renders ./components/progress/demo/line.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width:30%;height:8px;border-radius:100px"
|
||||
style="width:30%;height:8px;border-radius:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -878,7 +878,7 @@ exports[`renders ./components/progress/demo/line.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width:50%;height:8px;border-radius:100px"
|
||||
style="width:50%;height:8px;border-radius:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -902,7 +902,7 @@ exports[`renders ./components/progress/demo/line.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width:70%;height:8px;border-radius:100px"
|
||||
style="width:70%;height:8px;border-radius:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -943,7 +943,7 @@ exports[`renders ./components/progress/demo/line.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width:100%;height:8px;border-radius:100px"
|
||||
style="width:100%;height:8px;border-radius:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -984,7 +984,7 @@ exports[`renders ./components/progress/demo/line.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width:50%;height:8px;border-radius:100px"
|
||||
style="width:50%;height:8px;border-radius:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -1009,7 +1009,7 @@ exports[`renders ./components/progress/demo/line-mini.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width:30%;height:6px;border-radius:100px"
|
||||
style="width:30%;height:6px;border-radius:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -1033,7 +1033,7 @@ exports[`renders ./components/progress/demo/line-mini.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width:50%;height:6px;border-radius:100px"
|
||||
style="width:50%;height:6px;border-radius:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -1057,7 +1057,7 @@ exports[`renders ./components/progress/demo/line-mini.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width:70%;height:6px;border-radius:100px"
|
||||
style="width:70%;height:6px;border-radius:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -1098,7 +1098,7 @@ exports[`renders ./components/progress/demo/line-mini.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width:100%;height:6px;border-radius:100px"
|
||||
style="width:100%;height:6px;border-radius:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -1257,11 +1257,11 @@ exports[`renders ./components/progress/demo/segment.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width:60%;height:8px;border-radius:100px"
|
||||
style="width:60%;height:8px;border-radius:"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-success-bg"
|
||||
style="width:30%;height:8px;border-radius:100px"
|
||||
style="width:30%;height:8px;border-radius:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -13,11 +13,11 @@ exports[`Progress render format 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width: 50%; height: 8px; border-radius: 100px;"
|
||||
style="width: 50%; height: 8px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-success-bg"
|
||||
style="width: 10%; height: 8px; border-radius: 100px;"
|
||||
style="width: 10%; height: 8px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -44,7 +44,7 @@ exports[`Progress render negetive progress 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width: 0%; height: 8px; border-radius: 100px;"
|
||||
style="width: 0%; height: 8px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -71,11 +71,11 @@ exports[`Progress render negetive successPercent 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width: 50%; height: 8px; border-radius: 100px;"
|
||||
style="width: 50%; height: 8px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-success-bg"
|
||||
style="width: 0%; height: 8px; border-radius: 100px;"
|
||||
style="width: 0%; height: 8px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -102,7 +102,7 @@ exports[`Progress render normal progress 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width: 0%; height: 8px; border-radius: 100px;"
|
||||
style="width: 0%; height: 8px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -129,7 +129,7 @@ exports[`Progress render out-of-range progress 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width: 100%; height: 8px; border-radius: 100px;"
|
||||
style="width: 100%; height: 8px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -173,7 +173,7 @@ exports[`Progress render out-of-range progress with info 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width: 100%; height: 8px; border-radius: 100px;"
|
||||
style="width: 100%; height: 8px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -296,7 +296,7 @@ exports[`Progress render strokeColor 2`] = `
|
||||
style={
|
||||
Object {
|
||||
"backgroundImage": "linear-gradient(to right, #108ee9, #87d068)",
|
||||
"borderRadius": "100px",
|
||||
"borderRadius": "",
|
||||
"height": 8,
|
||||
"width": "50%",
|
||||
}
|
||||
@ -363,7 +363,7 @@ exports[`Progress render strokeColor 3`] = `
|
||||
style={
|
||||
Object {
|
||||
"backgroundImage": "linear-gradient(to right, #108ee9 0%, #87d068 100%)",
|
||||
"borderRadius": "100px",
|
||||
"borderRadius": "",
|
||||
"height": 8,
|
||||
"width": "50%",
|
||||
}
|
||||
|
@ -36,7 +36,7 @@
|
||||
width: 100%;
|
||||
vertical-align: middle;
|
||||
background-color: @progress-remaining-color;
|
||||
border-radius: 100px;
|
||||
border-radius: @progress-radius;
|
||||
}
|
||||
|
||||
&-circle-trail {
|
||||
@ -52,6 +52,7 @@
|
||||
&-bg {
|
||||
position: relative;
|
||||
background-color: @progress-default-color;
|
||||
border-radius: @progress-radius;
|
||||
transition: all 0.4s @ease-out-circ 0s;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background-color: @slider-rail-background-color;
|
||||
border-radius: 2px;
|
||||
border-radius: @border-radius-sm;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
height: 4px;
|
||||
background-color: @slider-track-background-color;
|
||||
border-radius: @border-radius-base;
|
||||
transition: background-color 0.3s ease;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
&-handle {
|
||||
@ -42,10 +42,10 @@
|
||||
height: 14px;
|
||||
margin-top: -5px;
|
||||
margin-left: -7px;
|
||||
background-color: @component-background;
|
||||
border: solid 2px @slider-handle-color;
|
||||
background-color: @slider-handle-background-color;
|
||||
border: solid @slider-handle-border-width @slider-handle-color;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0;
|
||||
box-shadow: @slider-handle-shadow;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.3s, box-shadow 0.6s,
|
||||
transform 0.3s cubic-bezier(0.18, 0.89, 0.32, 1.28);
|
||||
|
@ -156,9 +156,9 @@
|
||||
@btn-default-bg: @component-background;
|
||||
@btn-default-border: @border-color-base;
|
||||
|
||||
@btn-danger-color: @error-color;
|
||||
@btn-danger-bg: @background-color-base;
|
||||
@btn-danger-border: @border-color-base;
|
||||
@btn-danger-color: #fff;
|
||||
@btn-danger-bg: color(~`colorPalette('@{error-color}', 5) `);
|
||||
@btn-danger-border: color(~`colorPalette('@{error-color}', 5) `);
|
||||
|
||||
@btn-disable-color: @disabled-color;
|
||||
@btn-disable-bg: @disabled-bg;
|
||||
@ -370,6 +370,7 @@
|
||||
@progress-default-color: @processing-color;
|
||||
@progress-remaining-color: @background-color-base;
|
||||
@progress-text-color: @text-color;
|
||||
@progress-radius: 100px;
|
||||
|
||||
// Menu
|
||||
// ---
|
||||
@ -491,6 +492,8 @@
|
||||
@tabs-highlight-color: @primary-color;
|
||||
@tabs-hover-color: @primary-5;
|
||||
@tabs-active-color: @primary-7;
|
||||
@tabs-card-gutter: 2px;
|
||||
@tabs-card-tab-active-border-top: 2px solid transparent;
|
||||
|
||||
// BackTop
|
||||
// ---
|
||||
@ -550,11 +553,14 @@
|
||||
@slider-rail-background-color-hover: #e1e1e1;
|
||||
@slider-track-background-color: @primary-3;
|
||||
@slider-track-background-color-hover: @primary-4;
|
||||
@slider-handle-border-width: 2px;
|
||||
@slider-handle-background-color: @component-background;
|
||||
@slider-handle-color: @primary-3;
|
||||
@slider-handle-color-hover: @primary-4;
|
||||
@slider-handle-color-focus: tint(@primary-color, 20%);
|
||||
@slider-handle-color-focus-shadow: fade(@primary-color, 20%);
|
||||
@slider-handle-color-tooltip-open: @primary-color;
|
||||
@slider-handle-shadow: 0;
|
||||
@slider-dot-border-color: @border-color-split;
|
||||
@slider-dot-border-color-active: tint(@primary-color, 50%);
|
||||
@slider-disabled-color: @disabled-color;
|
||||
@ -629,3 +635,11 @@
|
||||
// ---
|
||||
@drawer-header-padding: 16px 24px;
|
||||
@drawer-body-padding: 24px;
|
||||
|
||||
// Timeline
|
||||
// ---
|
||||
@timeline-width: 2px;
|
||||
@timeline-color: @border-color-split;
|
||||
@timeline-dot-border-width: 2px;
|
||||
@timeline-dot-color: @primary-color;
|
||||
@timeline-dot-bg: @component-background;
|
||||
|
@ -23,7 +23,7 @@ Ant Design has 3 types of Tabs for different situations.
|
||||
| --- | --- | --- | --- | --- |
|
||||
| activeKey | Current TabPane's key | string | - | |
|
||||
| animated | Whether to change tabs with animation. Only works while `tabPosition="top"\|"bottom"` | boolean \| {inkBar:boolean, tabPane:boolean} | `true`, `false` when `type="card"` | |
|
||||
| renderTabBar | replace the TabBar | (props: DefaultTabBarProps, DefaultTabBar: React.ReactNode) => React.ReactNode | - | 3.9.0 |
|
||||
| renderTabBar | replace the TabBar | (props: DefaultTabBarProps, DefaultTabBar: React.ComponentClass) => React.ReactElement | - | 3.9.0 |
|
||||
| defaultActiveKey | Initial active TabPane's key, if `activeKey` is not set. | string | - | |
|
||||
| hideAdd | Hide plus icon or not. Only works while `type="editable-card"` | boolean | `false` | |
|
||||
| size | preset tab bar size | `large` \| `default` \| `small` | `default` | |
|
||||
|
@ -31,7 +31,10 @@ export interface TabsProps {
|
||||
className?: string;
|
||||
animated?: boolean | { inkBar: boolean; tabPane: boolean };
|
||||
tabBarGutter?: number;
|
||||
renderTabBar?: (props: TabsProps, DefaultTabBar: React.ReactNode) => React.ReactElement<any>;
|
||||
renderTabBar?: (
|
||||
props: TabsProps,
|
||||
DefaultTabBar: React.ComponentClass<any>,
|
||||
) => React.ReactElement<any>;
|
||||
destroyInactiveTabPane?: boolean;
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ Ant Design 依次提供了三级选项卡,分别用于不同的场景。
|
||||
| --- | --- | --- | --- | --- |
|
||||
| activeKey | 当前激活 tab 面板的 key | string | 无 | |
|
||||
| animated | 是否使用动画切换 Tabs,在 `tabPosition=top|bottom` 时有效 | boolean \| {inkBar:boolean, tabPane:boolean} | true, 当 type="card" 时为 false | |
|
||||
| renderTabBar | 替换 TabBar,用于二次封装标签头 | (props: DefaultTabBarProps, DefaultTabBar: React.ReactNode) => React.ReactNode | 无 | 3.9.0 |
|
||||
| renderTabBar | 替换 TabBar,用于二次封装标签头 | (props: DefaultTabBarProps, DefaultTabBar: React.ComponentClass) => React.ReactElement | 无 | 3.9.0 |
|
||||
| defaultActiveKey | 初始化选中面板的 key,如果没有设置 activeKey | string | 第一个面板 | |
|
||||
| hideAdd | 是否隐藏加号图标,在 `type="editable-card"` 时有效 | boolean | false | |
|
||||
| size | 大小,提供 `large` `default` 和 `small` 三种大小 | string | 'default' | |
|
||||
|
@ -14,7 +14,7 @@
|
||||
&&-card &-card-bar &-tab {
|
||||
height: @tabs-card-height;
|
||||
margin: 0;
|
||||
margin-right: 2px;
|
||||
margin-right: @tabs-card-gutter;
|
||||
padding: 0 16px;
|
||||
line-height: @tabs-card-height - 2px;
|
||||
background: @tabs-card-head-background;
|
||||
@ -28,6 +28,10 @@
|
||||
background: @component-background;
|
||||
border-color: @border-color-split;
|
||||
border-bottom: @border-width-base solid @component-background;
|
||||
|
||||
&::before {
|
||||
border-top: @tabs-card-tab-active-border-top;
|
||||
}
|
||||
}
|
||||
&&-card &-card-bar &-tab-disabled {
|
||||
color: @tabs-card-active-color;
|
||||
|
@ -181,6 +181,18 @@
|
||||
cursor: pointer;
|
||||
transition: color 0.3s @ease-in-out;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
border-top: 2px solid transparent;
|
||||
border-radius: @border-radius-base @border-radius-base 0 0;
|
||||
transition: all 0.3s;
|
||||
content: '';
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
@import '../../style/mixins/index';
|
||||
|
||||
@timeline-prefix-cls: ~'@{ant-prefix}-timeline';
|
||||
@timeline-color: @border-color-split;
|
||||
|
||||
.@{timeline-prefix-cls} {
|
||||
.reset-component;
|
||||
@ -23,7 +22,7 @@
|
||||
top: 0.75em;
|
||||
left: 4px;
|
||||
height: 100%;
|
||||
border-left: 2px solid @timeline-color;
|
||||
border-left: @timeline-width solid @timeline-color;
|
||||
}
|
||||
|
||||
&-pending &-head {
|
||||
@ -38,18 +37,20 @@
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: @component-background;
|
||||
border: 2px solid transparent;
|
||||
background-color: @timeline-dot-bg;
|
||||
border: @timeline-dot-border-width solid transparent;
|
||||
border-radius: 100px;
|
||||
|
||||
&-blue {
|
||||
color: @primary-color;
|
||||
border-color: @primary-color;
|
||||
}
|
||||
|
||||
&-red {
|
||||
color: @error-color;
|
||||
border-color: @error-color;
|
||||
}
|
||||
|
||||
&-green {
|
||||
color: @success-color;
|
||||
border-color: @success-color;
|
||||
|
@ -36,7 +36,7 @@
|
||||
padding: 3px 5px;
|
||||
color: @text-color;
|
||||
text-decoration: none;
|
||||
border-radius: 2px;
|
||||
border-radius: @border-radius-sm;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
&:hover {
|
||||
|
@ -97,7 +97,7 @@ exports[`Upload List handle error 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width: 0%; height: 2px; border-radius: 100px;"
|
||||
style="width: 0%; height: 2px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -206,7 +206,7 @@ exports[`Upload List should be uploading when upload a file 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width: 0%; height: 2px; border-radius: 100px;"
|
||||
style="width: 0%; height: 2px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -315,7 +315,7 @@ exports[`Upload List should be uploading when upload a file 2`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width: 0%; height: 2px; border-radius: 100px;"
|
||||
style="width: 0%; height: 2px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -201,7 +201,7 @@ We use `modifyVars` option of [less-loader](https://github.com/webpack/less-load
|
||||
|
||||
## eject
|
||||
|
||||
You can also could try [yarn run eject](https://github.com/facebookincubator/create-react-app#converting-to-a-custom-setup) for a custom setup of create-react-app, although you should dig into it by yourself.
|
||||
You can also eject your application using [yarn run eject](https://github.com/facebookincubator/create-react-app#converting-to-a-custom-setup) for a custom setup of create-react-app, although you should dig into it by yourself.
|
||||
|
||||
## Source code and other boilerplates
|
||||
|
||||
|
@ -63,8 +63,8 @@
|
||||
"rc-cascader": "~0.17.4",
|
||||
"rc-checkbox": "~2.1.6",
|
||||
"rc-collapse": "~1.11.3",
|
||||
"rc-dialog": "~7.4.0",
|
||||
"rc-drawer": "~1.10.1",
|
||||
"rc-dialog": "~7.5.2",
|
||||
"rc-drawer": "~2.0.1",
|
||||
"rc-dropdown": "~2.4.1",
|
||||
"rc-editor-mention": "^1.1.13",
|
||||
"rc-form": "^2.4.5",
|
||||
@ -75,7 +75,7 @@
|
||||
"rc-pagination": "~1.20.1",
|
||||
"rc-progress": "~2.5.0",
|
||||
"rc-rate": "~2.5.0",
|
||||
"rc-select": "~9.1.4",
|
||||
"rc-select": "~9.2.0",
|
||||
"rc-slider": "~8.6.11",
|
||||
"rc-steps": "~3.4.1",
|
||||
"rc-switch": "~1.9.0",
|
||||
|
@ -45,6 +45,7 @@ module.exports = {
|
||||
其他: 6,
|
||||
Other: 6,
|
||||
Components: 100,
|
||||
组件: 100,
|
||||
},
|
||||
typeOrder: {
|
||||
General: 0,
|
||||
|
@ -100,13 +100,21 @@ a {
|
||||
}
|
||||
|
||||
// reset menu text color
|
||||
.menu-site .ant-menu-item > a {
|
||||
color: @site-text-color;
|
||||
}
|
||||
.menu-site {
|
||||
.ant-menu-item > a {
|
||||
color: @site-text-color;
|
||||
}
|
||||
|
||||
.menu-site .ant-menu-item-selected > a,
|
||||
.menu-site .ant-menu-item > a:hover {
|
||||
color: @primary-color;
|
||||
.ant-menu-item-selected > a,
|
||||
.ant-menu-item > a:hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
.menu-antd-components-count {
|
||||
margin-left: .5em;
|
||||
color: @disabled-color;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
#react-content {
|
||||
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'bisheng/router';
|
||||
import { Row, Col, Menu, Icon, Affix } from 'antd';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import get from 'lodash/get';
|
||||
import MobileMenu from 'rc-drawer';
|
||||
@ -56,6 +57,26 @@ const getSideBarOpenKeys = nextProps => {
|
||||
return shouldOpenKeys;
|
||||
};
|
||||
|
||||
const getSubMenuTitle = (menuItem) => {
|
||||
if (menuItem.title !== 'Components') {
|
||||
return menuItem.title;
|
||||
}
|
||||
let count = 0;
|
||||
menuItem.children.forEach(item => {
|
||||
if (item.children) {
|
||||
count += item.children.length;
|
||||
}
|
||||
});
|
||||
return (
|
||||
<h4>
|
||||
{menuItem.title === 'Components' ? (
|
||||
<FormattedMessage id="app.header.menu.components" />
|
||||
) : menuItem.title}
|
||||
<span className="menu-antd-components-count">{count}</span>
|
||||
</h4>
|
||||
);
|
||||
};
|
||||
|
||||
export default class MainContent extends Component {
|
||||
static contextTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
@ -117,7 +138,10 @@ export default class MainContent extends Component {
|
||||
return menuItems.map(menuItem => {
|
||||
if (menuItem.children) {
|
||||
return (
|
||||
<SubMenu title={<h4>{menuItem.title}</h4>} key={menuItem.title}>
|
||||
<SubMenu
|
||||
title={getSubMenuTitle(menuItem)}
|
||||
key={menuItem.title}
|
||||
>
|
||||
{menuItem.children.map(child => {
|
||||
if (child.type === 'type') {
|
||||
return (
|
||||
|
@ -7,7 +7,12 @@ $('lib')
|
||||
.hasFile('index.d.ts');
|
||||
|
||||
$('lib/*')
|
||||
.filter(filename => !filename.endsWith('index.js') && !filename.endsWith('index.d.ts'))
|
||||
.filter(
|
||||
filename =>
|
||||
!filename.endsWith('index.js') &&
|
||||
!filename.endsWith('index.d.ts') &&
|
||||
!filename.endsWith('.map'),
|
||||
)
|
||||
.isDirectory()
|
||||
.filter(filename => !filename.endsWith('style') && !filename.endsWith('_util'))
|
||||
.hasFile('index.js')
|
||||
|
Loading…
Reference in New Issue
Block a user