Merge pull request #22435 from ant-design/master

chore: 🔀 merge master into feature
This commit is contained in:
偏右 2020-03-20 16:04:26 +08:00 committed by GitHub
commit a399d05ace
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
105 changed files with 1706 additions and 1016 deletions

View File

@ -1,16 +1,9 @@
import scrollTo from '../scrollTo';
import { sleep } from '../../../tests/utils';
describe('Test ScrollTo function', () => {
let dateNowMock;
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
beforeEach(() => {
dateNowMock = jest
.spyOn(Date, 'now')
@ -29,8 +22,8 @@ describe('Test ScrollTo function', () => {
});
scrollTo(1000);
await sleep(20);
jest.runAllTimers();
expect(window.pageYOffset).toBe(1000);
scrollToSpy.mockRestore();
@ -41,7 +34,7 @@ describe('Test ScrollTo function', () => {
scrollTo(1000, {
callback: cbMock,
});
jest.runAllTimers();
await sleep(20);
expect(cbMock).toHaveBeenCalledTimes(1);
});
@ -50,7 +43,7 @@ describe('Test ScrollTo function', () => {
scrollTo(1000, {
getContainer: () => div,
});
jest.runAllTimers();
await sleep(20);
expect(div.scrollTop).toBe(1000);
});
});

View File

@ -8,37 +8,30 @@ import getDataOrAriaProps from '../getDataOrAriaProps';
import Wave from '../wave';
import TransButton from '../transButton';
import openAnimation from '../openAnimation';
import { sleep } from '../../../tests/utils';
describe('Test utils function', () => {
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
it('throttle function should work', () => {
it('throttle function should work', async () => {
const callback = jest.fn();
const throttled = throttleByAnimationFrame(callback);
expect(callback).not.toHaveBeenCalled();
throttled();
throttled();
await sleep(20);
jest.runAllTimers();
expect(callback).toHaveBeenCalled();
expect(callback.mock.calls.length).toBe(1);
});
it('throttle function should be canceled', () => {
it('throttle function should be canceled', async () => {
const callback = jest.fn();
const throttled = throttleByAnimationFrame(callback);
throttled();
throttled.cancel();
await sleep(20);
jest.runAllTimers();
expect(callback).not.toHaveBeenCalled();
});

View File

@ -0,0 +1,107 @@
import React from 'react';
import { mount } from 'enzyme';
import Wave from '../wave';
import ConfigProvider from '../../config-provider';
import mountTest from '../../../tests/shared/mountTest';
import { sleep } from '../../../tests/utils';
describe('Wave component', () => {
mountTest(Wave);
afterEach(() => {
const styles = document.getElementsByTagName('style');
for (let i = 0; i < styles.length; i += 1) {
styles[i].remove();
}
});
it('isHidden works', () => {
const TEST_NODE_ENV = process.env.NODE_ENV;
process.env.NODE_ENV = 'development';
const wrapper = mount(<Wave><button type="button">button</button></Wave>);
expect(wrapper.find('button').getDOMNode().className).toBe('');
wrapper.find('button').getDOMNode().click();
expect(wrapper.find('button').getDOMNode().hasAttribute('ant-click-animating-without-extra-node')).toBe(false);
wrapper.unmount();
process.env.NODE_ENV = TEST_NODE_ENV;
});
it('isHidden is mocked', () => {
const wrapper = mount(<Wave><button type="button">button</button></Wave>);
expect(wrapper.find('button').getDOMNode().className).toBe('');
wrapper.find('button').getDOMNode().click();
expect(wrapper.find('button').getDOMNode().getAttribute('ant-click-animating-without-extra-node')).toBe('false');
wrapper.unmount();
});
it('wave color is grey', async () => {
const wrapper = mount(<Wave><button type="button" style={{ borderColor: 'rgb(0, 0, 0)' }}>button</button></Wave>);
wrapper.find('button').getDOMNode().click();
await sleep(0);
const styles = document.getElementsByTagName('style');
expect(styles.length).toBe(0);
wrapper.unmount();
});
it('wave color is not grey', async () => {
const wrapper = mount(<Wave><button type="button" style={{ borderColor: 'red' }}>button</button></Wave>);
wrapper.find('button').getDOMNode().click();
await sleep(200);
const styles = document.getElementsByTagName('style');
expect(styles.length).toBe(1);
expect(styles[0].innerHTML).toContain('--antd-wave-shadow-color: red;');
wrapper.unmount();
});
it('read wave color from border-top-color', async () => {
const wrapper = mount(<Wave><div style={{ borderTopColor: 'blue' }}>button</div></Wave>);
wrapper.find('div').getDOMNode().click();
await sleep(0);
const styles = document.getElementsByTagName('style');
expect(styles.length).toBe(1);
expect(styles[0].innerHTML).toContain('--antd-wave-shadow-color: blue;');
wrapper.unmount();
});
it('read wave color from background color', async () => {
const wrapper = mount(<Wave><div style={{ backgroundColor: 'green' }}>button</div></Wave>);
wrapper.find('div').getDOMNode().click();
await sleep(0);
const styles = document.getElementsByTagName('style');
expect(styles.length).toBe(1);
expect(styles[0].innerHTML).toContain('--antd-wave-shadow-color: green;');
wrapper.unmount();
});
it('read wave color from border firstly', async () => {
const wrapper = mount(<Wave><div style={{ borderColor: 'yellow', backgroundColor: 'green' }}>button</div></Wave>);
wrapper.find('div').getDOMNode().click();
await sleep(0);
const styles = document.getElementsByTagName('style');
expect(styles.length).toBe(1);
expect(styles[0].innerHTML).toContain('--antd-wave-shadow-color: yellow;');
wrapper.unmount();
});
it('hidden element with -leave className', async () => {
const wrapper = mount(<Wave><button type="button" className="xx-leave">button</button></Wave>);
wrapper.find('button').getDOMNode().click();
await sleep(0);
const styles = document.getElementsByTagName('style');
expect(styles.length).toBe(0);
wrapper.unmount();
});
it('ConfigProvider csp', async () => {
const wrapper = mount(
<ConfigProvider csp={{ nonce: 'YourNonceCode' }}>
<Wave><button type="button">button</button></Wave>
</ConfigProvider>,
);
wrapper.find('button').getDOMNode().click();
await sleep(0);
const styles = document.getElementsByTagName('style');
expect(styles[0].getAttribute('nonce')).toBe('YourNonceCode');
wrapper.unmount();
});
});

View File

@ -36,7 +36,7 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
private animationStart: boolean = false;
private destroy: boolean = false;
private destroyed: boolean = false;
private csp?: CSPConfig;
@ -56,7 +56,7 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
clearTimeout(this.clickWaveTimeoutId);
}
this.destroy = true;
this.destroyed = true;
}
onClick = (node: HTMLElement, waveColor: string) => {
@ -101,16 +101,16 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
};
onTransitionStart = (e: AnimationEvent) => {
if (this.destroy) return;
const node = findDOMNode(this) as HTMLElement;
if (!e || e.target !== node) {
if (this.destroyed) {
return;
}
if (!this.animationStart) {
this.resetEffect(node);
const node = findDOMNode(this) as HTMLElement;
if (!e || e.target !== node || this.animationStart) {
return;
}
this.resetEffect(node);
};
onTransitionEnd = (e: AnimationEvent) => {

View File

@ -5,6 +5,7 @@ import { getObserverEntities } from '../utils';
import Button from '../../button';
import { spyElementPrototype } from '../../__tests__/util/domHook';
import rtlTest from '../../../tests/shared/rtlTest';
import { sleep } from '../../../tests/utils';
const events = {};
@ -54,7 +55,6 @@ describe('Affix Render', () => {
};
beforeAll(() => {
jest.useFakeTimers();
domMock = spyElementPrototype(HTMLElement, 'getBoundingClientRect', function mockBounding() {
return (
classRect[this.className] || {
@ -66,10 +66,10 @@ describe('Affix Render', () => {
});
afterAll(() => {
jest.useRealTimers();
domMock.mockRestore();
});
const movePlaceholder = top => {
const movePlaceholder = async top => {
classRect.fixed = {
top,
bottom: top,
@ -77,58 +77,58 @@ describe('Affix Render', () => {
events.scroll({
type: 'scroll',
});
jest.runAllTimers();
await sleep(20);
};
it('Anchor render perfectly', () => {
it('Anchor render perfectly', async () => {
document.body.innerHTML = '<div id="mounter" />';
wrapper = mount(<AffixMounter />, { attachTo: document.getElementById('mounter') });
jest.runAllTimers();
await sleep(20);
movePlaceholder(0);
await movePlaceholder(0);
expect(wrapper.instance().affix.state.affixStyle).toBeFalsy();
movePlaceholder(-100);
await movePlaceholder(-100);
expect(wrapper.instance().affix.state.affixStyle).toBeTruthy();
movePlaceholder(0);
await movePlaceholder(0);
expect(wrapper.instance().affix.state.affixStyle).toBeFalsy();
});
it('support offsetBottom', () => {
it('support offsetBottom', async () => {
document.body.innerHTML = '<div id="mounter" />';
wrapper = mount(<AffixMounter offsetBottom={0} />, {
attachTo: document.getElementById('mounter'),
});
jest.runAllTimers();
await sleep(20);
movePlaceholder(300);
await movePlaceholder(300);
expect(wrapper.instance().affix.state.affixStyle).toBeTruthy();
movePlaceholder(0);
await movePlaceholder(0);
expect(wrapper.instance().affix.state.affixStyle).toBeFalsy();
movePlaceholder(300);
await movePlaceholder(300);
expect(wrapper.instance().affix.state.affixStyle).toBeTruthy();
});
it('updatePosition when offsetTop changed', () => {
it('updatePosition when offsetTop changed', async () => {
document.body.innerHTML = '<div id="mounter" />';
wrapper = mount(<AffixMounter offsetTop={0} />, {
attachTo: document.getElementById('mounter'),
});
jest.runAllTimers();
await sleep(20);
movePlaceholder(-100);
await movePlaceholder(-100);
expect(wrapper.instance().affix.state.affixStyle.top).toBe(0);
wrapper.setProps({
offsetTop: 10,
});
jest.runAllTimers();
await sleep(20);
expect(wrapper.instance().affix.state.affixStyle.top).toBe(10);
});
@ -144,7 +144,7 @@ describe('Affix Render', () => {
expect(wrapper.instance().state.placeholderStyle).toBe(undefined);
});
it('instance change', () => {
it('instance change', async () => {
const getObserverLength = () => Object.keys(getObserverEntities()).length;
const container = document.createElement('div');
@ -154,20 +154,20 @@ describe('Affix Render', () => {
const originLength = getObserverLength();
const getTarget = () => target;
wrapper = mount(<Affix target={getTarget} />);
jest.runAllTimers();
await sleep(20);
expect(getObserverLength()).toBe(originLength + 1);
target = null;
wrapper.setProps({});
wrapper.update();
jest.runAllTimers();
await sleep(20);
expect(getObserverLength()).toBe(originLength);
});
});
describe('updatePosition when size changed', () => {
function test(name, index) {
it(name, () => {
it(name, async () => {
document.body.innerHTML = '<div id="mounter" />';
const updateCalled = jest.fn();
@ -175,11 +175,11 @@ describe('Affix Render', () => {
attachTo: document.getElementById('mounter'),
});
jest.runAllTimers();
await sleep(20);
movePlaceholder(300);
await movePlaceholder(300);
expect(wrapper.instance().affix.state.affixStyle).toBeTruthy();
jest.runAllTimers();
await sleep(20);
wrapper.update();
// Mock trigger resize
@ -189,7 +189,7 @@ describe('Affix Render', () => {
.at(index)
.instance()
.onResize([{ target: { getBoundingClientRect: () => ({ width: 99, height: 99 }) } }]);
jest.runAllTimers();
await sleep(20);
expect(updateCalled).toHaveBeenCalled();
});

View File

@ -273,9 +273,7 @@ describe('Anchor Render', () => {
expect(wrapper.instance().state.activeLink).toBe('#API2');
});
it('Anchor targetOffset prop', () => {
jest.useFakeTimers();
it('Anchor targetOffset prop', async () => {
let dateNowMock;
function dataNowMockFn() {
@ -304,23 +302,22 @@ describe('Anchor Render', () => {
</Anchor>,
);
wrapper.instance().handleScrollTo('#API');
jest.runAllTimers();
await sleep(20);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 1000);
dateNowMock = dataNowMockFn();
wrapper.setProps({ offsetTop: 100 });
wrapper.instance().handleScrollTo('#API');
jest.runAllTimers();
await sleep(20);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 900);
dateNowMock = dataNowMockFn();
wrapper.setProps({ targetOffset: 200 });
wrapper.instance().handleScrollTo('#API');
jest.runAllTimers();
await sleep(20);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
dateNowMock.mockRestore();
jest.useRealTimers();
});
it('Anchor onChange prop', async () => {

View File

@ -1,6 +1,5 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './rtl';
@badge-prefix-cls: ~'@{ant-prefix}-badge';
@number-prefix-cls: ~'@{ant-prefix}-scroll-number';
@ -190,3 +189,5 @@
opacity: 0;
}
}
@import './rtl';

View File

@ -1,6 +1,5 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './rtl';
@breadcrumb-prefix-cls: ~'@{ant-prefix}-breadcrumb';
@ -50,3 +49,5 @@
}
}
}
@import './rtl';

View File

@ -1,7 +1,6 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './mixin';
@import './rtl';
@btn-prefix-cls: ~'@{ant-prefix}-btn';
@ -247,3 +246,5 @@ a.@{btn-prefix-cls} {
line-height: @btn-height-sm - 2px;
}
}
@import './rtl';

View File

@ -1,5 +1,3 @@
@import './mixin.rtl.less';
// mixins for button
// ------------------------
.button-size(@height; @padding-horizontal; @font-size; @border-radius) {

View File

@ -1,60 +0,0 @@
.btn-group(@btnClassName: btn) {
.@{btnClassName} + .@{btnClassName},
.@{btnClassName} + &,
span + .@{btnClassName},
.@{btnClassName} + span,
> span + span,
& + .@{btnClassName},
& + & {
.@{btnClassName}-rtl& {
margin-right: -1px;
margin-left: auto;
}
}
&.@{btnClassName}-group-rtl {
direction: rtl;
}
> .@{btnClassName}:first-child:not(:last-child),
> span:first-child:not(:last-child) > .@{btnClassName} {
.@{btnClassName}-group-rtl& {
border-top-left-radius: 0;
border-top-right-radius: @btn-border-radius-base;
border-bottom-right-radius: @btn-border-radius-base;
border-bottom-left-radius: 0;
}
}
> .@{btnClassName}:last-child:not(:first-child),
> span:last-child:not(:first-child) > .@{btnClassName} {
.@{btnClassName}-group-rtl& {
border-top-left-radius: @btn-border-radius-base;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: @btn-border-radius-base;
}
}
&-sm {
> .@{btnClassName}:first-child:not(:last-child),
> span:first-child:not(:last-child) > .@{btnClassName} {
.@{btnClassName}-group-rtl& {
border-top-left-radius: 0;
border-top-right-radius: @btn-border-radius-sm;
border-bottom-right-radius: @btn-border-radius-sm;
border-bottom-left-radius: 0;
}
}
> .@{btnClassName}:last-child:not(:first-child),
> span:last-child:not(:first-child) > .@{btnClassName} {
.@{btnClassName}-group-rtl& {
border-top-left-radius: @btn-border-radius-sm;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: @btn-border-radius-sm;
}
}
}
}

View File

@ -60,3 +60,65 @@
}
}
}
// mixin
.btn-group(@btnClassName: btn) {
.@{btnClassName} + .@{btnClassName},
.@{btnClassName} + &,
span + .@{btnClassName},
.@{btnClassName} + span,
> span + span,
& + .@{btnClassName},
& + & {
.@{btnClassName}-rtl& {
margin-right: -1px;
margin-left: auto;
}
}
&.@{btnClassName}-group-rtl {
direction: rtl;
}
> .@{btnClassName}:first-child:not(:last-child),
> span:first-child:not(:last-child) > .@{btnClassName} {
.@{btnClassName}-group-rtl& {
border-top-left-radius: 0;
border-top-right-radius: @btn-border-radius-base;
border-bottom-right-radius: @btn-border-radius-base;
border-bottom-left-radius: 0;
}
}
> .@{btnClassName}:last-child:not(:first-child),
> span:last-child:not(:first-child) > .@{btnClassName} {
.@{btnClassName}-group-rtl& {
border-top-left-radius: @btn-border-radius-base;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: @btn-border-radius-base;
}
}
&-sm {
> .@{btnClassName}:first-child:not(:last-child),
> span:first-child:not(:last-child) > .@{btnClassName} {
.@{btnClassName}-group-rtl& {
border-top-left-radius: 0;
border-top-right-radius: @btn-border-radius-sm;
border-bottom-right-radius: @btn-border-radius-sm;
border-bottom-left-radius: 0;
}
}
> .@{btnClassName}:last-child:not(:first-child),
> span:last-child:not(:first-child) > .@{btnClassName} {
.@{btnClassName}-group-rtl& {
border-top-left-radius: @btn-border-radius-sm;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: @btn-border-radius-sm;
}
}
}
}

View File

@ -1,6 +1,5 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './rtl';
@carousel-prefix-cls: ~'@{ant-prefix}-carousel';
@ -253,3 +252,5 @@
}
}
}
@import './rtl';

View File

@ -335,6 +335,18 @@ describe('Cascader', () => {
expect(wrapper.find('.ant-cascader-menu-item').length).toBe(1);
});
it('should select item immediately when searching and pressing down arrow key', () => {
const wrapper = mount(<Cascader options={options} showSearch={{ filter }} />);
wrapper.find('input').simulate('click');
wrapper.find('input').simulate('change', { target: { value: 'a' } });
expect(wrapper.find('.ant-cascader-menu-item').length).toBe(2);
expect(wrapper.find('.ant-cascader-menu-item-active').length).toBe(0);
wrapper.find('input').simulate('keyDown', {
keyCode: KeyCode.DOWN,
});
expect(wrapper.find('.ant-cascader-menu-item-active').length).toBe(1);
});
it('can use fieldNames', () => {
const customerOptions = [
{
@ -491,6 +503,7 @@ describe('Cascader', () => {
});
expect(wrapper.find('input').prop('placeholder')).toBe(customPlaceholder);
});
it('popup correctly with defaultValue RTL', () => {
const wrapper = mount(
<ConfigProvider direction="rtl">
@ -511,6 +524,7 @@ describe('Cascader', () => {
),
).toMatchSnapshot();
});
it('can be selected in RTL direction', () => {
const options2 = [
{

View File

@ -3,6 +3,7 @@ import RcCascader from 'rc-cascader';
import arrayTreeFilter from 'array-tree-filter';
import classNames from 'classnames';
import omit from 'omit.js';
import isEqual from 'lodash/isEqual';
import KeyCode from 'rc-util/lib/KeyCode';
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import DownOutlined from '@ant-design/icons/DownOutlined';
@ -521,7 +522,8 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
const names: FilledFieldNamesType = getFilledFieldNames(this.props);
if (options && options.length > 0) {
if (state.inputValue) {
options = this.generateFilteredOptions(prefixCls, renderEmpty);
const filteredOptions = this.generateFilteredOptions(prefixCls, renderEmpty);
options = isEqual(filteredOptions, this.cachedOptions) ? this.cachedOptions : filteredOptions;
}
} else {
options = [

View File

@ -1,5 +1,5 @@
@import '../../style/themes/index';
@import './mixin';
@import './rtl';
.antCheckboxFn();
@import './rtl';

View File

@ -2,6 +2,7 @@ import React from 'react';
import { mount } from 'enzyme';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { sleep } from '../../../tests/utils';
describe('Collapse', () => {
// Fix css-animation deps on these
@ -55,8 +56,7 @@ describe('Collapse', () => {
expect(wrapper.render()).toMatchSnapshot();
});
it('could be expand and collapse', () => {
jest.useFakeTimers();
it('could be expand and collapse', async () => {
const wrapper = mount(
<Collapse>
<Collapse.Panel header="This is panel header 1" key="1">
@ -69,10 +69,8 @@ describe('Collapse', () => {
.find('.ant-collapse-header')
.at(0)
.simulate('click');
await sleep(400);
expect(wrapper.find('.ant-collapse-item').hasClass('ant-collapse-item-active')).toBe(true);
jest.runAllTimers();
expect(wrapper.find('.ant-collapse-item').hasClass('ant-collapse-item-active')).toBe(true);
jest.useRealTimers();
});
it('could override default openAnimation', () => {

View File

@ -1,6 +1,5 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './rtl';
@collapse-prefix-cls: ~'@{ant-prefix}-collapse';
@ -134,3 +133,5 @@
}
}
}
@import './rtl';

View File

@ -1,6 +1,5 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './rtl';
@comment-prefix-cls: ~'@{ant-prefix}-comment';
@ -96,3 +95,5 @@
margin-left: @comment-nest-indent;
}
}
@import './rtl';

View File

@ -33,10 +33,6 @@
border-radius: @border-radius-base;
transition: border @animation-duration-slow, box-shadow @animation-duration-slow;
&-rtl {
direction: rtl;
}
&:hover,
&-focused {
.hover();
@ -111,11 +107,6 @@
margin-left: @padding-xs / 2;
color: @disabled-color;
pointer-events: none;
.@{picker-prefix-cls}-rtl & {
margin-right: @padding-xs / 2;
margin-left: 0;
}
}
&-clear {
@ -132,11 +123,6 @@
&:hover {
color: @text-color-secondary;
}
.@{picker-prefix-cls}-rtl & {
right: auto;
left: 0;
}
}
&-separator {
@ -149,11 +135,6 @@
line-height: @font-size-lg;
text-align: center;
cursor: default;
.@{picker-prefix-cls}-rtl & {
transform: rotate(180deg);
transform-origin: 50% 60%;
}
}
// ======================== Range =========================
@ -164,11 +145,6 @@
// Clear
.@{picker-prefix-cls}-clear {
right: @input-padding-horizontal-base;
.@{picker-prefix-cls}-rtl& {
right: auto;
left: @input-padding-horizontal-base;
}
}
&:hover {
@ -244,10 +220,6 @@
text-align: left;
list-style: none;
.@{picker-prefix-cls}-dropdown-rtl & {
text-align: right;
}
> li {
display: inline-block;
}
@ -259,12 +231,6 @@
.@{picker-prefix-cls}-ok {
float: right;
margin-left: @padding-xs;
.@{picker-prefix-cls}-dropdown-rtl & {
float: left;
margin-right: @padding-xs;
margin-left: 0;
}
}
}
@ -279,6 +245,7 @@
width: @arrow-size;
height: @arrow-size;
margin-left: @input-padding-horizontal-base * 1.5;
box-shadow: 2px -2px 6px fade(@black, 6%);
transition: left @animation-duration-slow ease-out;
&::after {
@ -318,3 +285,5 @@
}
}
}
@import './rtl';

View File

@ -15,10 +15,6 @@
border-radius: @border-radius-base;
outline: none;
&-rtl {
direction: rtl;
}
&-focused {
border-color: @primary-color;
}
@ -129,19 +125,11 @@
&-prev-icon,
&-super-prev-icon {
transform: rotate(-45deg);
.@{picker-prefix-cls}-panel-rtl & {
transform: rotate(135deg);
}
}
&-next-icon,
&-super-next-icon {
transform: rotate(135deg);
.@{picker-prefix-cls}-panel-rtl & {
transform: rotate(-45deg);
}
}
// ======================== Body ========================
@ -627,10 +615,6 @@
width: auto;
min-width: auto;
.@{picker-prefix-cls}-panel-rtl & {
direction: ltr;
}
.@{picker-prefix-cls}-content {
display: flex;
flex: auto;

View File

@ -0,0 +1,87 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import '../../input/style/mixin';
@picker-prefix-cls: ~'@{ant-prefix}-picker';
.@{picker-prefix-cls} {
&-rtl {
direction: rtl;
}
&-suffix {
.@{picker-prefix-cls}-rtl & {
margin-right: @padding-xs / 2;
margin-left: 0;
}
}
&-clear {
.@{picker-prefix-cls}-rtl & {
right: auto;
left: 0;
}
}
&-separator {
.@{picker-prefix-cls}-rtl & {
transform: rotate(180deg);
transform-origin: 50% 60%;
}
}
// ======================== Range =========================
&-range {
// Clear
.@{picker-prefix-cls}-clear {
.@{picker-prefix-cls}-rtl& {
right: auto;
left: @input-padding-horizontal-base;
}
}
}
// ======================== Ranges ========================
&-ranges {
.@{picker-prefix-cls}-dropdown-rtl & {
text-align: right;
}
.@{picker-prefix-cls}-ok {
.@{picker-prefix-cls}-dropdown-rtl & {
float: left;
margin-right: @padding-xs;
margin-left: 0;
}
}
}
// ======================== Panel ========================
&-panel {
&-rtl {
direction: rtl;
}
}
&-prev-icon,
&-super-prev-icon {
.@{picker-prefix-cls}-panel-rtl & {
transform: rotate(135deg);
}
}
&-next-icon,
&-super-next-icon {
.@{picker-prefix-cls}-panel-rtl & {
transform: rotate(-45deg);
}
}
// ::before and ::after is not recommended for splitting
&-time-panel {
.@{picker-prefix-cls}-panel-rtl & {
direction: ltr;
}
}
}

View File

@ -1,6 +1,5 @@
@import '../../style/themes/default';
@import '../../style/mixins/index';
@import './rtl';
@descriptions-prefix-cls: ~'@{ant-prefix}-descriptions';
@ -42,7 +41,6 @@
font-weight: normal;
font-size: @font-size-base;
line-height: @line-height-base;
white-space: nowrap;
&::after {
position: relative;
@ -144,3 +142,5 @@
}
}
}
@import './rtl';

View File

@ -2,3 +2,4 @@
@import '../../style/mixins/index';
@import './drawer';
@import './customize';
@import './rtl.less';

View File

@ -1,4 +1,3 @@
// deps-lint-skip: empty
import '../../style/index.less';
import './index.less';
import './rtl.less';

View File

@ -1,6 +1,5 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './rtl';
@dropdown-prefix-cls: ~'@{ant-prefix}-dropdown';
@ -285,3 +284,5 @@
}
}
}
@import './rtl';

View File

@ -1,6 +1,5 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './rtl';
@empty-prefix-cls: ~'@{ant-prefix}-empty';
@empty-img-prefix-cls: ~'@{ant-prefix}-empty-img';
@ -136,3 +135,5 @@
}
}
}
@import './rtl';

View File

@ -12,7 +12,7 @@ import warning from '../_util/warning';
import FormItemLabel, { FormItemLabelProps } from './FormItemLabel';
import FormItemInput, { FormItemInputProps } from './FormItemInput';
import { FormContext, FormItemContext } from './context';
import { toArray, getFieldId } from './util';
import { toArray, getFieldId, useFrameState } from './util';
const ValidateStatuses = tuple('success', 'warning', 'error', 'validating', '');
export type ValidateStatus = typeof ValidateStatuses[number];
@ -87,18 +87,14 @@ function FormItem(props: FormItemProps): React.ReactElement {
const formContext = React.useContext(FormContext);
const { updateItemErrors } = React.useContext(FormItemContext);
const [domErrorVisible, innerSetDomErrorVisible] = React.useState(!!help);
const [inlineErrors, innerSetInlineErrors] = React.useState<Record<string, string[]>>({});
// const [inlineErrors, innerSetInlineErrors] = React.useState<Record<string, string[]>>({});
const [inlineErrors, setInlineErrors] = useFrameState<Record<string, string[]>>({});
function setDomErrorVisible(visible: boolean) {
if (!destroyRef.current) {
innerSetDomErrorVisible(visible);
}
}
function setInlineErrors(errors: Record<string, string[]>) {
if (!destroyRef.current) {
innerSetInlineErrors(errors);
}
}
const { name: formName } = formContext;
const hasName = hasValidName(name);
@ -122,12 +118,10 @@ function FormItem(props: FormItemProps): React.ReactElement {
? updateItemErrors
: (subName: string, subErrors: string[]) => {
if (!isEqual(inlineErrors[subName], subErrors)) {
Promise.resolve().then(() => {
setInlineErrors({
...inlineErrors,
[subName]: subErrors,
});
});
setInlineErrors(prevInlineErrors => ({
...prevInlineErrors,
[subName]: subErrors,
}));
}
};

View File

@ -50,7 +50,7 @@ const validateMessages = {
<Form validateMessages={validateMessages} />;
```
Besides,[ConfigProvider](/components/config-provider/) also provides a global configuration scheme that allows for uniform configuration error notification templates:
Besides, [ConfigProvider](/components/config-provider/) also provides a global configuration scheme that allows for uniform configuration error notification templates:
```jsx
const validateMessages = {
@ -92,6 +92,12 @@ Form field component for data bidirectional binding, validation, layout, and so
| valuePropName | Props of children node, for example, the prop of Switch is 'checked' | string | 'value' |
| wrapperCol | The layout for input controls, same as `labelCol`. You can set `wrapperCol` on Form. If both exists, use Item first | [object](/components/grid/#Col) | - |
After wrapped by `Form.Item` with `name` property, `value`(or other property defined by `valuePropName`) `onChange`(or other property defined by `trigger`) props will be added to form controls, the flow of form data will be handled by Form which will cause:
1. You shouldn't use `onChange` on each form control to **collect data**(use `onValuesChange` of Form), but you can still listen to `onChange`.
2. You cannot set value for each form control via `value` or `defaultValue` prop, you should set default value with `initialValues` of Form. Note that `initialValues` cannot be updated by `setState` dynamiclly, you should use `setFieldsValue` in that situation.
3. You shouldn't call `setState` manually, please use `form.setFieldsValue` to change value programmatically.
### dependencies
Used when there are dependencies between fields. If a field has the `dependencies` prop, this field will automatically trigger updates and validations when upstream is updated. A common scenario is a user registration form with "password" and "confirm password" fields. The "Confirm Password" validation depends on the "Password" field. After setting `dependencies`, the "Password" field update will re-trigger the validation of "Check Password". You can refer [examples](#components-form-demo-register).

View File

@ -93,6 +93,12 @@ const validateMessages = {
| valuePropName | 子节点的值的属性,如 Switch 的是 'checked' | string | 'value' |
| wrapperCol | 需要为输入控件设置布局样式时,使用该属性,用法同 `labelCol`。你可以通过 Form 的 `wrapperCol` 进行统一设置。当和 Form 同时设置时,以 Item 为准。 | [object](/components/grid/#Col) | - |
被设置了 `name` 属性的 `Form.Item` 包装的控件,表单控件会自动添加 `value`(或 `valuePropName` 指定的其他属性) `onChange`(或 `trigger` 指定的其他属性),数据同步将被 Form 接管,这会导致以下结果:
1. 你**不再需要也不应该**用 `onChange` 来做数据收集同步(你可以使用 Form 的 `onValuesChange`),但还是可以继续监听 `onChange` 事件。
2. 你不能用控件的 `value``defaultValue` 等属性来设置表单域的值,默认值可以用 Form 里的 `initialValues` 来设置。注意 `initialValues` 不能被 `setState` 动态更新,你需要用 `setFieldsValue` 来更新。
3. 你不应该用 `setState`,可以使用 `form.setFieldsValue` 来动态改变表单值。
### dependencies
当字段间存在依赖关系时使用。如果一个字段设置了 `dependencies` 属性。那么它所依赖的字段更新时,该字段将自动触发更新与校验。一种常见的场景,就是注册用户表单的“密码”与“确认密码”字段。“确认密码”校验依赖于“密码”字段,设置 `dependencies` 后,“密码”字段更新会重新触发“校验密码”的校验逻辑。你可以参考[具体例子](#components-form-demo-register)。

View File

@ -24,10 +24,6 @@
padding-right: 8px;
}
&-rtl {
direction: rtl;
}
// ================================================================
// = Size =
// ================================================================
@ -80,10 +76,6 @@
text-align: right;
vertical-align: middle;
.@{form-prefix-cls}-rtl & {
text-align: right;
}
&-left {
text-align: left;
}
@ -111,11 +103,6 @@
line-height: 1;
content: '*';
.@{form-prefix-cls}-rtl & {
margin-right: 0;
margin-left: 4px;
}
.@{form-prefix-cls}-hide-required-mark & {
display: none;
}
@ -148,8 +135,7 @@
flex-direction: column;
flex-grow: 1;
&:first-child:not([class^=~"'@{ant-prefix}-col-'"]):not([class*=~"' @{ant-prefix}-col-'"]),
.@{ant-prefix}-col-rtl &:first-child {
&:first-child:not([class^=~"'@{ant-prefix}-col-'"]):not([class*=~"' @{ant-prefix}-col-'"]) {
width: 100%;
}
}
@ -238,3 +224,5 @@
transform: scale(1);
}
}
@import './rtl.less';

View File

@ -10,11 +10,6 @@
margin-right: 16px;
margin-bottom: 0;
.@{form-prefix-cls}-rtl& {
margin-right: 0;
margin-left: 16px;
}
&-with-help {
margin-bottom: @form-item-margin-bottom;
}

View File

@ -0,0 +1,175 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import '../../input/style/mixin';
@import '../../button/style/mixin';
@import '../../grid/style/mixin';
@form-prefix-cls: ~'@{ant-prefix}-form';
@form-item-prefix-cls: ~'@{form-prefix-cls}-item';
.@{form-prefix-cls} {
&-rtl {
direction: rtl;
}
}
// ================================================================
// = Item =
// ================================================================
.@{form-item-prefix-cls} {
// ==============================================================
// = Label =
// ==============================================================
&-label {
.@{form-prefix-cls}-rtl & {
text-align: right;
}
> label {
&.@{form-item-prefix-cls}-required::before {
.@{form-prefix-cls}-rtl & {
margin-right: 0;
margin-left: 4px;
}
}
}
}
// ==============================================================
// = Input =
// ==============================================================
&-control {
.@{ant-prefix}-col-rtl &:first-child {
width: 100%;
}
}
// status
&-has-feedback {
.@{ant-prefix}-input {
.@{form-prefix-cls}-rtl & {
padding-right: @input-padding-horizontal-base;
padding-left: 24px;
}
}
.@{ant-prefix}-input-affix-wrapper {
.@{ant-prefix}-input-suffix {
.@{form-prefix-cls}-rtl & {
padding-right: @input-padding-horizontal-base;
padding-left: 18px;
}
}
.@{ant-prefix}-input {
.@{form-prefix-cls}-rtl & {
padding: 0;
}
}
}
.@{ant-prefix}-input-search:not(.@{ant-prefix}-input-search-enter-button) {
.@{ant-prefix}-input-suffix {
.@{form-prefix-cls}-rtl & {
right: auto;
left: 28px;
}
}
}
.@{ant-prefix}-input-number {
.@{form-prefix-cls}-rtl & {
padding-left: 18px;
}
}
> .@{ant-prefix}-select .@{ant-prefix}-select-arrow,
> .@{ant-prefix}-select .@{ant-prefix}-select-selection__clear,
:not(.@{ant-prefix}-input-group-addon) > .@{ant-prefix}-select .@{ant-prefix}-select-arrow,
:not(.@{ant-prefix}-input-group-addon)
> .@{ant-prefix}-select
.@{ant-prefix}-select-selection__clear {
.@{form-prefix-cls}-rtl & {
right: auto;
left: 28px;
}
}
> .@{ant-prefix}-select .@{ant-prefix}-select-selection-selected-value,
:not(.@{ant-prefix}-input-group-addon)
> .@{ant-prefix}-select
.@{ant-prefix}-select-selection-selected-value {
.@{form-prefix-cls}-rtl & {
padding-right: 0;
padding-left: 42px;
}
}
.@{ant-prefix}-cascader-picker {
&-arrow {
.@{form-prefix-cls}-rtl & {
margin-right: 0;
margin-left: 17px;
}
}
&-clear {
.@{form-prefix-cls}-rtl & {
right: auto;
left: 28px;
}
}
}
.@{ant-prefix}-picker {
.@{form-prefix-cls}-rtl & {
padding-right: @input-padding-horizontal-base;
padding-left: @input-padding-horizontal-base + @font-size-base * 1.3;
}
&-large {
.@{form-prefix-cls}-rtl & {
padding-right: @input-padding-horizontal-lg;
padding-left: @input-padding-horizontal-lg + @font-size-base * 1.3;
}
}
&-small {
.@{form-prefix-cls}-rtl & {
padding-right: @input-padding-horizontal-sm;
padding-left: @input-padding-horizontal-sm + @font-size-base * 1.3;
}
}
}
&.@{form-item-prefix-cls} {
&-has-success,
&-has-warning,
&-has-error,
&-is-validating {
// ====================== Icon ======================
.@{form-item-prefix-cls}-children-icon {
.@{form-prefix-cls}-rtl & {
right: auto;
left: 0;
}
}
}
}
}
}
// inline
.@{form-prefix-cls}-inline {
.@{form-prefix-cls}-item {
.@{form-prefix-cls}-rtl& {
margin-right: 0;
margin-left: 16px;
}
}
}
// vertical
.make-vertical-layout-label() {
.@{form-prefix-cls}-rtl& {
text-align: right;
}
}

View File

@ -10,26 +10,11 @@
// ========================= Input =========================
.@{ant-prefix}-input {
padding-right: 24px;
.@{form-prefix-cls}-rtl & {
padding-right: @input-padding-horizontal-base;
padding-left: 24px;
}
}
// https://github.com/ant-design/ant-design/issues/19884
.@{ant-prefix}-input-affix-wrapper {
.@{ant-prefix}-input-suffix {
padding-right: 18px;
.@{form-prefix-cls}-rtl & {
padding-right: @input-padding-horizontal-base;
padding-left: 18px;
}
}
.@{ant-prefix}-input {
.@{form-prefix-cls}-rtl & {
padding: 0;
}
}
}
@ -37,17 +22,6 @@
.@{ant-prefix}-input-search:not(.@{ant-prefix}-input-search-enter-button) {
.@{ant-prefix}-input-suffix {
right: 28px;
.@{form-prefix-cls}-rtl & {
right: auto;
left: 28px;
}
}
}
.@{ant-prefix}-input-number {
.@{form-prefix-cls}-rtl & {
padding-left: 18px;
}
}
@ -66,41 +40,21 @@
> .@{ant-prefix}-select
.@{ant-prefix}-select-selection__clear {
right: 28px;
.@{form-prefix-cls}-rtl & {
right: auto;
left: 28px;
}
}
> .@{ant-prefix}-select .@{ant-prefix}-select-selection-selected-value,
:not(.@{ant-prefix}-input-group-addon)
> .@{ant-prefix}-select
.@{ant-prefix}-select-selection-selected-value {
padding-right: 42px;
.@{form-prefix-cls}-rtl & {
padding-right: 0;
padding-left: 42px;
}
}
// ======================= Cascader ========================
.@{ant-prefix}-cascader-picker {
&-arrow {
margin-right: 17px;
.@{form-prefix-cls}-rtl & {
margin-right: 0;
margin-left: 17px;
}
}
&-clear {
right: 28px;
.@{form-prefix-cls}-rtl & {
right: auto;
left: 28px;
}
}
}
@ -109,27 +63,12 @@
.@{ant-prefix}-picker {
padding-right: @input-padding-horizontal-base + @font-size-base * 1.3;
.@{form-prefix-cls}-rtl & {
padding-right: @input-padding-horizontal-base;
padding-left: @input-padding-horizontal-base + @font-size-base * 1.3;
}
&-large {
padding-right: @input-padding-horizontal-lg + @font-size-base * 1.3;
.@{form-prefix-cls}-rtl & {
padding-right: @input-padding-horizontal-lg;
padding-left: @input-padding-horizontal-lg + @font-size-base * 1.3;
}
}
&-small {
padding-right: @input-padding-horizontal-sm + @font-size-base * 1.3;
.@{form-prefix-cls}-rtl & {
padding-right: @input-padding-horizontal-sm;
padding-left: @input-padding-horizontal-sm + @font-size-base * 1.3;
}
}
}
@ -155,11 +94,6 @@
animation: zoomIn 0.3s @ease-out-back;
pointer-events: none;
.@{form-prefix-cls}-rtl & {
right: auto;
left: 0;
}
& svg {
position: absolute;
top: 0;

View File

@ -8,9 +8,6 @@
white-space: initial;
text-align: left;
.@{form-prefix-cls}-rtl& {
text-align: right;
}
> label {
margin: 0;

View File

@ -1,4 +1,5 @@
import * as React from 'react';
import raf from 'raf';
import { useForm as useRcForm, FormInstance as RcFormInstance } from 'rc-field-form';
import scrollIntoView from 'scroll-into-view-if-needed';
import { ScrollOptions } from './interface';
@ -99,3 +100,42 @@ export function useForm(form?: FormInstance): [FormInstance] {
return [wrapForm];
}
type Updater<ValueType> = (prev?: ValueType) => ValueType;
export function useFrameState<ValueType>(
defaultValue: ValueType,
): [ValueType, (updater: Updater<ValueType>) => void] {
const [value, setValue] = React.useState(defaultValue);
const frameRef = React.useRef<number | null>(null);
const batchRef = React.useRef<Updater<ValueType>[]>([]);
React.useEffect(
() => () => {
raf.cancel(frameRef.current!);
},
[],
);
function setFrameValue(updater: Updater<ValueType>) {
if (frameRef.current === null) {
batchRef.current = [];
frameRef.current = raf(() => {
frameRef.current = null;
setValue(prevValue => {
let current = prevValue;
batchRef.current.forEach(func => {
current = func(current);
});
return current;
});
});
}
batchRef.current.push(updater);
}
return [value, setFrameValue];
}

View File

@ -1,7 +1,6 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './mixin';
@import './rtl';
// Grid system
.@{ant-prefix}-row {
@ -111,3 +110,5 @@
@media (min-width: @screen-xxl-min) {
.make-grid(-xxl);
}
@import './rtl';

View File

@ -1,5 +1,4 @@
@import '../../style/mixins/index';
@import './mixin.rtl.less';
// mixins for grid system
// ------------------------

View File

@ -1,60 +0,0 @@
@import '../../style/mixins/index';
.loop-grid-columns(@index, @class) when (@index > 0) {
.@{ant-prefix}-col@{class}-push-@{index} {
// reset property in RTL direction
&.@{ant-prefix}-col-rtl {
right: percentage((@index / @grid-columns));
left: auto;
}
}
.@{ant-prefix}-col@{class}-pull-@{index} {
// reset property in RTL direction
&.@{ant-prefix}-col-rtl {
right: auto;
left: percentage((@index / @grid-columns));
}
}
.@{ant-prefix}-col@{class}-offset-@{index} {
// reset property in RTL direction
&.@{ant-prefix}-col-rtl {
margin-right: percentage((@index / @grid-columns));
margin-left: 0;
}
}
}
.loop-grid-columns(@index, @class) when (@index = 0) {
.@{ant-prefix}-col-push-@{index} {
// reset property in RTL direction
&.@{ant-prefix}-col-rtl {
right: auto;
}
}
.@{ant-prefix}-col-pull-@{index} {
&.@{ant-prefix}-col-rtl {
left: auto;
}
}
.@{ant-prefix}-col@{class}-push-@{index} {
&.@{ant-prefix}-col-rtl {
right: auto;
}
}
.@{ant-prefix}-col@{class}-pull-@{index} {
&.@{ant-prefix}-col-rtl {
left: auto;
}
}
.@{ant-prefix}-col@{class}-offset-@{index} {
&.@{ant-prefix}-col-rtl {
margin-right: 0;
}
}
}

View File

@ -12,3 +12,63 @@
float: right;
}
}
// mixin
.loop-grid-columns(@index, @class) when (@index > 0) {
.@{ant-prefix}-col@{class}-push-@{index} {
// reset property in RTL direction
&.@{ant-prefix}-col-rtl {
right: percentage((@index / @grid-columns));
left: auto;
}
}
.@{ant-prefix}-col@{class}-pull-@{index} {
// reset property in RTL direction
&.@{ant-prefix}-col-rtl {
right: auto;
left: percentage((@index / @grid-columns));
}
}
.@{ant-prefix}-col@{class}-offset-@{index} {
// reset property in RTL direction
&.@{ant-prefix}-col-rtl {
margin-right: percentage((@index / @grid-columns));
margin-left: 0;
}
}
}
.loop-grid-columns(@index, @class) when (@index = 0) {
.@{ant-prefix}-col-push-@{index} {
// reset property in RTL direction
&.@{ant-prefix}-col-rtl {
right: auto;
}
}
.@{ant-prefix}-col-pull-@{index} {
&.@{ant-prefix}-col-rtl {
left: auto;
}
}
.@{ant-prefix}-col@{class}-push-@{index} {
&.@{ant-prefix}-col-rtl {
right: auto;
}
}
.@{ant-prefix}-col@{class}-pull-@{index} {
&.@{ant-prefix}-col-rtl {
left: auto;
}
}
.@{ant-prefix}-col@{class}-offset-@{index} {
&.@{ant-prefix}-col-rtl {
margin-right: 0;
}
}
}

View File

@ -2,7 +2,7 @@
exports[`InputNumber rtl render component should be rendered correctly in RTL direction 1`] = `
<div
class="ant-input-number"
class="ant-input-number ant-input-number-rtl"
>
<div
class="ant-input-number-handler-wrap"

View File

@ -54,7 +54,7 @@ export default class InputNumber extends React.Component<InputNumberProps, any>
this.inputNumberRef.blur();
}
renderInputNumber = ({ getPrefixCls }: ConfigConsumerProps) => {
renderInputNumber = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
const { className, size: customizeSize, prefixCls: customizePrefixCls, ...others } = this.props;
const prefixCls = getPrefixCls('input-number', customizePrefixCls);
const upIcon = <UpOutlined className={`${prefixCls}-handler-up-inner`} />;
@ -68,6 +68,7 @@ export default class InputNumber extends React.Component<InputNumberProps, any>
{
[`${prefixCls}-lg`]: mergeSize === 'large',
[`${prefixCls}-sm`]: mergeSize === 'small',
[`${prefixCls}-rtl`]: direction === 'rtl',
},
className,
);

View File

@ -182,3 +182,5 @@
color: @disabled-color;
}
}
@import './rtl';

View File

@ -0,0 +1,24 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import '../../input/style/mixin';
@input-number-prefix-cls: ~'@{ant-prefix}-input-number';
.@{input-number-prefix-cls} {
&-handler-wrap {
.@{input-number-prefix-cls}-rtl & {
right: auto;
left: 0;
border-right: @border-width-base @border-style-base @input-number-handler-border-color;
border-left: 0;
border-radius: @border-radius-base 0 0 @border-radius-base;
}
}
&-input {
.@{input-number-prefix-cls}-rtl & {
direction: rtl;
text-align: right;
}
}
}

View File

@ -4,6 +4,7 @@ import { mount } from 'enzyme';
import Input from '..';
import focusTest from '../../../tests/shared/focusTest';
import calculateNodeHeight, { calculateNodeStyling } from '../calculateNodeHeight';
import { sleep } from '../../../tests/utils';
const { TextArea } = Input;
@ -22,17 +23,15 @@ describe('TextArea', () => {
},
}),
});
jest.useFakeTimers();
});
afterAll(() => {
Object.defineProperty(window, 'getComputedStyle', {
value: originalGetComputedStyle,
});
jest.useRealTimers();
});
it('should auto calculate height according to content length', () => {
it('should auto calculate height according to content length', async () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const wrapper = mount(
@ -40,10 +39,10 @@ describe('TextArea', () => {
);
const mockFunc = jest.spyOn(wrapper.instance().resizableTextArea, 'resizeTextarea');
wrapper.setProps({ value: '1111\n2222\n3333' });
jest.runAllTimers();
await sleep(0);
expect(mockFunc).toHaveBeenCalledTimes(1);
wrapper.setProps({ value: '1111' });
jest.runAllTimers();
await sleep(0);
expect(mockFunc).toHaveBeenCalledTimes(2);
wrapper.update();
expect(wrapper.find('textarea').props().style.overflow).toBeFalsy();
@ -143,10 +142,10 @@ describe('TextArea', () => {
expect(onKeyDown).toHaveBeenCalled();
});
it('should trigger onResize', () => {
it('should trigger onResize', async () => {
const onResize = jest.fn();
const wrapper = mount(<TextArea onResize={onResize} autoSize />);
jest.runAllTimers();
await sleep(100);
wrapper
.find('ResizeObserver')
.instance()
@ -285,8 +284,7 @@ describe('TextArea allowClear', () => {
expect(onFocus).toHaveBeenCalled();
});
it('scroll to bottom when autoSize', () => {
jest.useFakeTimers();
it('scroll to bottom when autoSize', async () => {
const wrapper = mount(<Input.TextArea autoSize />, { attachTo: document.body });
wrapper.find('textarea').simulate('focus');
wrapper
@ -298,8 +296,7 @@ describe('TextArea allowClear', () => {
'setSelectionRange',
);
wrapper.find('textarea').simulate('input', { target: { value: '\n1' } });
jest.runAllTimers();
jest.useRealTimers();
await sleep(50);
expect(setSelectionRangeFn).toHaveBeenCalled();
wrapper.unmount();
});

View File

@ -31,15 +31,4 @@
&-suffix {
margin-left: @input-affix-margin;
}
// ======================== RTL ========================
&-affix-wrapper-rtl {
.@{ant-prefix}-input-prefix {
margin: 0 0 0 @input-affix-margin;
}
.@{ant-prefix}-input-suffix {
margin: 0 @input-affix-margin 0 0;
}
}
}

View File

@ -19,12 +19,6 @@
width: 100%;
text-align: start;
vertical-align: top; // https://github.com/ant-design/ant-design/issues/6403
&-rtl {
direction: rtl;
}
}
&-rtl {
direction: rtl;
}
}
@ -39,3 +33,4 @@
}
@import './search-input';
@import './rtl';

View File

@ -1,8 +1,6 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@input-rtl-cls: ~'@{ant-prefix}-input-rtl';
@input-affix-with-clear-btn-width: 38px;
// size mixins for input
@ -27,22 +25,12 @@
border-right-width: @border-width-base !important;
outline: 0;
box-shadow: @input-outline-offset @outline-blur-size @outline-width fade(@color, @outline-fade);
.@{input-rtl-cls} & {
border-right-width: 0;
border-left-width: @border-width-base !important;
}
}
// == when hoverd
.hover(@color: @input-hover-border-color) {
border-color: @color;
border-right-width: @border-width-base !important;
.@{input-rtl-cls} & {
border-right-width: 0;
border-left-width: @border-width-base !important;
}
}
.disabled() {
@ -108,10 +96,6 @@
&-sm {
.input-sm();
}
&-rtl {
direction: rtl;
}
}
// label input
@ -231,13 +215,6 @@
}
}
> .@{inputClass}-rtl:first-child,
&-rtl &-addon:first-child {
border-radius: @border-radius-base;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
> .@{inputClass}-affix-wrapper {
&:not(:first-child) .@{inputClass} {
border-top-left-radius: 0;
@ -252,20 +229,10 @@
&-addon:first-child {
border-right: 0;
.@{inputClass}-group-rtl & {
border-right: @border-width-base @border-style-base @input-border-color;
border-left: 0;
}
}
&-addon:last-child {
border-left: 0;
.@{inputClass}-group-rtl & {
border-right: 0;
border-left: @border-width-base @border-style-base @input-border-color;
}
}
> .@{inputClass}:last-child,
@ -273,12 +240,6 @@
border-top-left-radius: 0;
border-bottom-left-radius: 0;
.@{inputClass}-group-rtl & {
border-radius: @border-radius-base;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
// Reset Select's style in addon
.@{ant-prefix}-select .@{ant-prefix}-select-selector {
border-top-left-radius: 0;
@ -389,13 +350,6 @@
& > .@{ant-prefix}-time-picker:first-child .@{ant-prefix}-time-picker-input {
border-top-left-radius: @border-radius-base;
border-bottom-left-radius: @border-radius-base;
.@{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;
}
}
& > *:last-child,
@ -409,15 +363,6 @@
border-right-width: @border-width-base;
border-top-right-radius: @border-radius-base;
border-bottom-right-radius: @border-radius-base;
.@{inputClass}-group-rtl& {
border-right-width: 0;
border-left-width: @border-width-base;
border-top-left-radius: @border-radius-base;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: @border-radius-base;
}
}
// https://github.com/ant-design/ant-design/issues/12493

View File

@ -0,0 +1,151 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
//== Style for input-group: input with label, with button or dropdown...
.@{ant-prefix}-input-group {
&-wrapper {
&-rtl {
direction: rtl;
}
}
&-rtl {
direction: rtl;
}
}
// affix
@input-affix-margin: 4px;
.@{ant-prefix}-input {
&-affix-wrapper-rtl {
.@{ant-prefix}-input-prefix {
margin: 0 0 0 @input-affix-margin;
}
.@{ant-prefix}-input-suffix {
margin: 0 @input-affix-margin 0 0;
}
}
}
// mixin
@input-rtl-cls: ~'@{ant-prefix}-input-rtl';
.active() {
.@{input-rtl-cls} & {
border-right-width: 0;
border-left-width: @border-width-base !important;
}
}
.hover() {
.@{input-rtl-cls} & {
border-right-width: 0;
border-left-width: @border-width-base !important;
}
}
.input() {
&-rtl {
direction: rtl;
}
}
// label input
.input-group(@inputClass) {
> .@{inputClass}-rtl:first-child,
&-rtl &-addon:first-child {
border-radius: @border-radius-base;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
&-addon:first-child {
.@{inputClass}-group-rtl & {
border-right: @border-width-base @border-style-base @input-border-color;
border-left: 0;
}
}
&-addon:last-child {
.@{inputClass}-group-rtl & {
border-right: 0;
border-left: @border-width-base @border-style-base @input-border-color;
}
}
> .@{inputClass}:last-child,
&-addon:last-child {
.@{inputClass}-group-rtl & {
border-radius: @border-radius-base;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
&&-compact {
& > *:first-child,
& > .@{ant-prefix}-select:first-child > .@{ant-prefix}-select-selector,
& > .@{ant-prefix}-calendar-picker:first-child .@{ant-prefix}-input,
& > .@{ant-prefix}-select-auto-complete:first-child .@{ant-prefix}-input,
& > .@{ant-prefix}-cascader-picker:first-child .@{ant-prefix}-input,
& > .@{ant-prefix}-mention-wrapper:first-child .@{ant-prefix}-mention-editor,
& > .@{ant-prefix}-time-picker:first-child .@{ant-prefix}-time-picker-input {
.@{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;
}
}
& > *:last-child,
& > .@{ant-prefix}-select:last-child > .@{ant-prefix}-select-selector,
& > .@{ant-prefix}-calendar-picker:last-child .@{ant-prefix}-input,
& > .@{ant-prefix}-select-auto-complete:last-child .@{ant-prefix}-input,
& > .@{ant-prefix}-cascader-picker:last-child .@{ant-prefix}-input,
& > .@{ant-prefix}-cascader-picker-focused:last-child .@{ant-prefix}-input,
& > .@{ant-prefix}-mention-wrapper:last-child .@{ant-prefix}-mention-editor,
& > .@{ant-prefix}-time-picker:last-child .@{ant-prefix}-time-picker-input {
.@{inputClass}-group-rtl& {
border-right-width: 0;
border-left-width: @border-width-base;
border-top-left-radius: @border-radius-base;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: @border-radius-base;
}
}
}
}
// search-input
@search-rtl-cls: ~'@{search-prefix}-rtl';
.@{search-prefix} {
&-rtl {
direction: rtl;
}
&-enter-button {
input {
.@{search-rtl-cls}& {
border: @border-width-base @border-style-base @input-border-color;
border-left: 0;
}
}
& + .@{ant-prefix}-input-group-addon,
input + .@{ant-prefix}-input-group-addon {
.@{search-rtl-cls}& {
.@{search-prefix}-button {
width: 100%;
border-top-left-radius: @border-radius-base;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: @border-radius-base;
}
}
}
}
}

View File

@ -4,12 +4,8 @@
@import './mixin';
@search-prefix: ~'@{ant-prefix}-input-search';
@search-rtl-cls: ~'@{search-prefix}-rtl';
.@{search-prefix} {
&-rtl {
direction: rtl;
}
&-icon {
color: @text-color-secondary;
cursor: pointer;
@ -23,11 +19,6 @@
input {
border-right: 0;
.@{search-rtl-cls}& {
border: @border-width-base @border-style-base @input-border-color;
border-left: 0;
}
&:hover,
&:focus {
border-color: @input-hover-border-color;
@ -47,16 +38,6 @@
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.@{search-rtl-cls}& {
.@{search-prefix}-button {
width: 100%;
border-top-left-radius: @border-radius-base;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: @border-radius-base;
}
}
}
}
}

View File

@ -23,7 +23,7 @@ A list can be used to display content related to a single subject. The content c
| header | List header renderer | string\|ReactNode | - | |
| itemLayout | The layout of list, default is `horizontal`, If a vertical list is desired, set the itemLayout property to `vertical` | string | - | |
| rowKey | Item's unique key, could be a string or function that returns a string | string\|Function(record):string | `key` | |
| loading | Shows a loading indicator while the contents of the list are being fetched | boolean\|[object](https://ant.design/components/spin-cn/#API) ([more](https://github.com/ant-design/ant-design/issues/8659)) | false | |
| loading | Shows a loading indicator while the contents of the list are being fetched | boolean\|[SpinProps](https://ant.design/components/spin/#API) ([more](https://github.com/ant-design/ant-design/issues/8659)) | false | |
| loadMore | Shows a load more content | string\|ReactNode | - | |
| locale | i18n text including empty text | object | emptyText: 'No Data' <br> | |
| pagination | Pagination [config](https://ant.design/components/pagination/), hide it by setting it to false | boolean \| object | false | |

View File

@ -235,4 +235,4 @@
@import './bordered';
@import './responsive';
@import './rtl.less';
@import './rtl';

View File

@ -38,5 +38,3 @@
}
}
}
@import './responsive.rtl.less';

View File

@ -1,47 +0,0 @@
@media screen and (max-width: @screen-md) {
.@{list-prefix-cls} {
&-item {
&-action {
.@{list-prefix-cls}-rtl & {
margin-right: 24px;
margin-left: 0;
}
}
}
}
.@{list-prefix-cls}-vertical {
.@{list-prefix-cls}-item {
&-extra {
.@{list-prefix-cls}-rtl & {
margin-right: 24px;
margin-left: 0;
}
}
}
}
}
@media screen and (max-width: @screen-sm) {
.@{list-prefix-cls} {
&-item {
&-action {
.@{list-prefix-cls}-rtl & {
margin-right: 22px;
margin-left: 0;
}
}
}
}
.@{list-prefix-cls}-vertical {
.@{list-prefix-cls}-item {
&-extra {
// to override margins on rtl view
.@{list-prefix-cls}-rtl& {
margin: auto auto 16px;
}
}
}
}
}

View File

@ -88,3 +88,52 @@
}
}
}
// responsive
@media screen and (max-width: @screen-md) {
.@{list-prefix-cls} {
&-item {
&-action {
.@{list-prefix-cls}-rtl & {
margin-right: 24px;
margin-left: 0;
}
}
}
}
.@{list-prefix-cls}-vertical {
.@{list-prefix-cls}-item {
&-extra {
.@{list-prefix-cls}-rtl & {
margin-right: 24px;
margin-left: 0;
}
}
}
}
}
@media screen and (max-width: @screen-sm) {
.@{list-prefix-cls} {
&-item {
&-action {
.@{list-prefix-cls}-rtl & {
margin-right: 22px;
margin-left: 0;
}
}
}
}
.@{list-prefix-cls}-vertical {
.@{list-prefix-cls}-item {
&-extra {
// to override margins on rtl view
.@{list-prefix-cls}-rtl& {
margin: auto auto 16px;
}
}
}
}
}

View File

@ -1,6 +1,5 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './rtl';
@menu-prefix-cls: ~'@{ant-prefix}-menu';
@ -558,3 +557,4 @@
}
@import './dark';
@import './rtl';

View File

@ -3,3 +3,4 @@
@import './modal';
@import './confirm';
@import './customize.less';
@import './rtl.less';

View File

@ -3,5 +3,3 @@ import './index.less';
// style dependencies
import '../../button/style';
import './rtl.less';

View File

@ -1,6 +1,5 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './rtl';
@pageheader-prefix-cls: ~'@{ant-prefix}-page-header';
@ -122,3 +121,5 @@
}
}
}
@import './rtl';

View File

@ -1,7 +1,6 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import '../../input/style/mixin';
@import './rtl';
@pagination-prefix-cls: ~'@{ant-prefix}-pagination';
@ -399,3 +398,5 @@
display: none;
}
}
@import './rtl';

View File

@ -195,3 +195,5 @@
opacity: 0;
}
}
@import './rtl.less';

View File

@ -1,3 +1,2 @@
import '../../style/index.less';
import './index.less';
import './rtl.less';

View File

@ -14,10 +14,6 @@
display: inline-block;
line-height: unset;
&-rtl {
direction: rtl;
}
.@{ant-prefix}-badge-count {
z-index: 1;
}
@ -36,11 +32,6 @@
margin-right: 8px;
white-space: nowrap;
cursor: pointer;
&-rtl {
margin-right: 0;
margin-left: 8px;
}
}
.@{radio-prefix-cls} {
@ -183,11 +174,6 @@ span.@{radio-prefix-cls} + * {
cursor: pointer;
transition: color 0.3s, background 0.3s, border-color 0.3s, box-shadow 0.3s;
&-rtl {
border-right-width: 0;
border-left-width: @border-width-base;
}
a {
color: @radio-button-color;
}
@ -224,30 +210,16 @@ span.@{radio-prefix-cls} + * {
background-color: @border-color-base;
transition: background-color 0.3s;
content: '';
.@{radio-prefix-cls}-button-wrapper-rtl& {
right: -1px;
left: 0;
}
}
}
&:first-child {
border-left: @border-width-base @border-style-base @border-color-base;
border-radius: @border-radius-base 0 0 @border-radius-base;
.@{radio-prefix-cls}-button-wrapper-rtl& {
border-right: @border-width-base @border-style-base @border-color-base;
border-radius: 0 @border-radius-base @border-radius-base 0;
}
}
&:last-child {
border-radius: 0 @border-radius-base @border-radius-base 0;
.@{radio-prefix-cls}-button-wrapper-rtl& {
border-radius: @border-radius-base 0 0 @border-radius-base;
}
}
&:first-child:last-child {
@ -340,10 +312,6 @@ span.@{radio-prefix-cls} + * {
}
&:first-child {
border-left-color: @border-color-base;
.@{radio-prefix-cls}-button-wrapper-rtl& {
border-right-color: @border-color-base;
}
}
}
@ -372,3 +340,5 @@ span.@{radio-prefix-cls} + * {
vertical-align: text-bottom;
}
}
@import './rtl';

View File

@ -0,0 +1,59 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@radio-prefix-cls: ~'@{ant-prefix}-radio';
@radio-group-prefix-cls: ~'@{radio-prefix-cls}-group';
.@{radio-group-prefix-cls} {
&-rtl {
direction: rtl;
}
}
// 一般状态
.@{radio-prefix-cls}-wrapper {
&-rtl {
margin-right: 0;
margin-left: 8px;
}
}
.@{radio-prefix-cls}-button-wrapper {
&-rtl {
border-right-width: 0;
border-left-width: @border-width-base;
}
&:not(:first-child) {
&::before {
.@{radio-prefix-cls}-button-wrapper-rtl& {
right: -1px;
left: 0;
}
}
}
&:first-child {
.@{radio-prefix-cls}-button-wrapper-rtl& {
border-right: @border-width-base @border-style-base @border-color-base;
border-radius: 0 @border-radius-base @border-radius-base 0;
}
.@{radio-prefix-cls}-button-wrapper-checked:not([class*=~"' @{radio-prefix-cls}-button-wrapper-disabled'"])& {
border-right-color: @radio-button-hover-color;
}
}
&:last-child {
.@{radio-prefix-cls}-button-wrapper-rtl& {
border-radius: @border-radius-base 0 0 @border-radius-base;
}
}
&-disabled {
&:first-child {
.@{radio-prefix-cls}-button-wrapper-rtl& {
border-right-color: @border-color-base;
}
}
}
}

View File

@ -1,6 +1,5 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './rtl';
@rate-prefix-cls: ~'@{ant-prefix}-rate';
@ -84,3 +83,5 @@
font-size: @font-size-base;
}
}
@import './rtl';

View File

@ -70,3 +70,5 @@
background-color: @background-color-light;
}
}
@import './rtl.less';

View File

@ -1,3 +1,2 @@
import '../../style/index.less';
import './index.less';
import './rtl.less';

View File

@ -4,7 +4,6 @@
@import './single';
@import './multiple';
@import './rtl';
@select-prefix-cls: ~'@{ant-prefix}-select';
@select-height-without-border: @input-height-base - 2 * @border-width-base;
@ -267,3 +266,5 @@
box-shadow: none !important;
}
}
@import './rtl';

View File

@ -1,5 +1,4 @@
@import './index';
@import './multiple.rtl.less';
@select-multiple-item-border-width: 1px;
@select-multiple-item-height: @input-height-base - @input-padding-vertical-base * 2; // Normal 24px

View File

@ -1,69 +0,0 @@
@import './index';
@select-multiple-item-border-width: 1px;
@select-multiple-item-spacing-half: ceil(@input-padding-vertical-base / 2);
@select-multiple-padding: max(
@input-padding-vertical-base - @select-multiple-item-border-width -
@select-multiple-item-spacing-half,
0
);
/**
* Do not merge `height` & `line-height` under style with `selection` & `search`,
* since chrome may update to redesign with its align logic.
*/
.@{select-prefix-cls}-multiple {
// ======================== Selections ========================
.@{select-prefix-cls}-selection-item {
.@{select-prefix-cls}-rtl& {
margin-right: 0;
margin-left: @input-padding-vertical-base;
text-align: right;
}
// It's ok not to do this, but 24px makes bottom narrow in view should adjust
&-content {
.@{select-prefix-cls}-rtl& {
margin-right: 0;
margin-left: @padding-xs / 2;
text-align: right;
}
}
}
// ========================== Input ==========================
.@{select-prefix-cls}-selection-search {
.@{select-prefix-cls}-rtl& {
margin-right: @select-multiple-padding / 2;
margin-left: @input-padding-vertical-base;
}
&-mirror {
.@{select-prefix-cls}-rtl& {
right: 0;
left: auto;
}
}
}
// ======================= Placeholder =======================
.@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
right: @input-padding-horizontal;
left: auto;
}
}
// ============================================================
// == Size ==
// ============================================================
// Size small need additional set padding
&.@{select-prefix-cls}-sm {
.@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
right: @input-padding-horizontal-sm;
}
}
}
}

View File

@ -32,3 +32,136 @@
}
}
}
// multiple
@select-multiple-item-border-width: 1px;
@select-multiple-item-spacing-half: ceil(@input-padding-vertical-base / 2);
@select-multiple-padding: max(
@input-padding-vertical-base - @select-multiple-item-border-width -
@select-multiple-item-spacing-half,
0
);
.@{select-prefix-cls}-multiple {
// ======================== Selections ========================
.@{select-prefix-cls}-selection-item {
.@{select-prefix-cls}-rtl& {
margin-right: 0;
margin-left: @input-padding-vertical-base;
text-align: right;
}
// It's ok not to do this, but 24px makes bottom narrow in view should adjust
&-content {
.@{select-prefix-cls}-rtl& {
margin-right: 0;
margin-left: @padding-xs / 2;
text-align: right;
}
}
}
// ========================== Input ==========================
.@{select-prefix-cls}-selection-search {
.@{select-prefix-cls}-rtl& {
margin-right: @select-multiple-padding / 2;
margin-left: @input-padding-vertical-base;
}
&-mirror {
.@{select-prefix-cls}-rtl& {
right: 0;
left: auto;
}
}
}
// ======================= Placeholder =======================
.@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
right: @input-padding-horizontal;
left: auto;
}
}
// ============================================================
// == Size ==
// ============================================================
// Size small need additional set padding
&.@{select-prefix-cls}-sm {
.@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
right: @input-padding-horizontal-sm;
}
}
}
}
// single
@selection-item-padding: ceil(@font-size-base * 1.25);
.@{select-prefix-cls}-single {
// ========================= Selector =========================
.@{select-prefix-cls}-selector {
.@{select-prefix-cls}-selection-item,
.@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
right: 0;
left: 9px;
text-align: right;
}
}
}
// With arrow should provides `padding-right` to show the arrow
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-search {
.@{select-prefix-cls}-rtl& {
right: @input-padding-horizontal-base;
left: @input-padding-horizontal-base + @font-size-base;
}
}
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-item,
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
padding-right: 0;
padding-left: @selection-item-padding;
}
}
// ========================== Input ==========================
// We only change the style of non-customize input which is only support by `combobox` mode.
// Not customize
&:not(.@{select-prefix-cls}-customize-input) {
.@{select-prefix-cls}-selector {
.@{select-prefix-cls}-rtl& {
padding: 0 @input-padding-horizontal-base;
}
}
}
// ============================================================
// == Size ==
// ============================================================
// Size small need additional set padding
&.@{select-prefix-cls}-sm {
&:not(.@{select-prefix-cls}-customize-input) {
// With arrow should provides `padding-right` to show the arrow
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-search {
.@{select-prefix-cls}-rtl& {
right: 0;
}
}
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-item,
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
padding-right: 0;
padding-left: @font-size-base * 1.5;
}
}
}
}
}

View File

@ -1,5 +1,4 @@
@import './index';
@import './single.rtl.less';
@selection-item-padding: ceil(@font-size-base * 1.25);

View File

@ -1,69 +0,0 @@
@import './index';
@selection-item-padding: ceil(@font-size-base * 1.25);
.@{select-prefix-cls}-single {
// ========================= Selector =========================
.@{select-prefix-cls}-selector {
.@{select-prefix-cls}-selection-item,
.@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
right: 0;
left: 9px;
text-align: right;
}
}
}
// With arrow should provides `padding-right` to show the arrow
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-search {
.@{select-prefix-cls}-rtl& {
right: @input-padding-horizontal-base;
left: @input-padding-horizontal-base + @font-size-base;
}
}
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-item,
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
padding-right: 0;
padding-left: @selection-item-padding;
}
}
// ========================== Input ==========================
// We only change the style of non-customize input which is only support by `combobox` mode.
// Not customize
&:not(.@{select-prefix-cls}-customize-input) {
.@{select-prefix-cls}-selector {
.@{select-prefix-cls}-rtl& {
padding: 0 @input-padding-horizontal-base;
}
}
}
// ============================================================
// == Size ==
// ============================================================
// Size small need additional set padding
&.@{select-prefix-cls}-sm {
&:not(.@{select-prefix-cls}-customize-input) {
// With arrow should provides `padding-right` to show the arrow
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-search {
.@{select-prefix-cls}-rtl& {
right: 0;
}
}
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-item,
&.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-placeholder {
.@{select-prefix-cls}-rtl& {
padding-right: 0;
padding-left: @font-size-base * 1.5;
}
}
}
}
}

View File

@ -12,20 +12,11 @@
display: table;
width: 100%;
&-rtl {
direction: rtl;
}
&-header {
display: table-cell;
padding-right: 16px;
vertical-align: top;
.@{skeleton-prefix-cls}-rtl & {
padding-right: 0;
padding-left: 16px;
}
// Avatar
.@{skeleton-avatar-prefix-cls} {
.skeleton-element-avatar();
@ -87,19 +78,11 @@
.@{skeleton-title-prefix-cls},
.@{skeleton-paragraph-prefix-cls} > li {
.skeleton-color();
.@{skeleton-prefix-cls}-rtl& {
animation-name: ~'@{skeleton-prefix-cls}-loading-rtl';
}
}
}
.@{skeleton-avatar-prefix-cls} {
.skeleton-color();
.@{skeleton-prefix-cls}-rtl& {
animation-name: ~'@{skeleton-prefix-cls}-loading-rtl';
}
}
.@{skeleton-button-prefix-cls} {
@ -231,11 +214,4 @@
}
}
@keyframes ~"@{skeleton-prefix-cls}-loading-rtl" {
0% {
background-position: 0% 50%;
}
100% {
background-position: 100% 50%;
}
}
@import './rtl.less';

View File

@ -0,0 +1,47 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@skeleton-prefix-cls: ~'@{ant-prefix}-skeleton';
@skeleton-avatar-prefix-cls: ~'@{skeleton-prefix-cls}-avatar';
@skeleton-title-prefix-cls: ~'@{skeleton-prefix-cls}-title';
@skeleton-paragraph-prefix-cls: ~'@{skeleton-prefix-cls}-paragraph';
.@{skeleton-prefix-cls} {
&-rtl {
direction: rtl;
}
&-header {
.@{skeleton-prefix-cls}-rtl & {
padding-right: 0;
padding-left: 16px;
}
}
// With active animation
&.@{skeleton-prefix-cls}-active {
& .@{skeleton-prefix-cls}-content {
.@{skeleton-title-prefix-cls},
.@{skeleton-paragraph-prefix-cls} > li {
.@{skeleton-prefix-cls}-rtl& {
animation-name: ~'@{skeleton-prefix-cls}-loading-rtl';
}
}
}
.@{skeleton-avatar-prefix-cls} {
.@{skeleton-prefix-cls}-rtl& {
animation-name: ~'@{skeleton-prefix-cls}-loading-rtl';
}
}
}
}
@keyframes ~"@{skeleton-prefix-cls}-loading-rtl" {
0% {
background-position: 0% 50%;
}
100% {
background-position: 100% 50%;
}
}

View File

@ -84,7 +84,7 @@ describe('Slider', () => {
it('should keepAlign by calling forcePopupAlign', async () => {
const wrapper = mount(<Slider defaultValue={30} tooltipVisible />);
wrapper.find('Tooltip').instance().tooltip.forcePopupAlign = jest.fn();
await sleep(0);
await sleep(20);
expect(wrapper.find('Tooltip').instance().tooltip.forcePopupAlign).toHaveBeenCalled();
});
});

View File

@ -1,6 +1,5 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './rtl';
@slider-prefix-cls: ~'@{ant-prefix}-slider';
@ -202,3 +201,5 @@
}
}
}
@import './rtl';

View File

@ -15,10 +15,6 @@
opacity: 0;
transition: transform 0.3s @ease-in-out-circ;
&-rtl {
direction: rtl;
}
&-spinning {
position: static;
display: inline-block;
@ -166,11 +162,6 @@
&-spin {
transform: rotate(45deg);
animation: antRotate 1.2s infinite linear;
.@{spin-prefix-cls}-rtl & {
transform: rotate(-45deg);
animation-name: antRotateRtl;
}
}
}
@ -222,8 +213,4 @@
}
}
@keyframes antRotateRtl {
to {
transform: rotate(-405deg);
}
}
@import './rtl.less';

View File

@ -0,0 +1,25 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@spin-prefix-cls: ~'@{ant-prefix}-spin';
.@{spin-prefix-cls} {
&-rtl {
direction: rtl;
}
&-dot {
&-spin {
.@{spin-prefix-cls}-rtl & {
transform: rotate(-45deg);
animation-name: antRotateRtl;
}
}
}
}
@keyframes antRotateRtl {
to {
transform: rotate(-405deg);
}
}

View File

@ -1,5 +1,3 @@
@import './custom-icon.rtl.less';
.@{steps-prefix-cls}-item-custom {
.@{steps-prefix-cls}-item-icon {
height: auto;

View File

@ -1,10 +0,0 @@
.@{steps-prefix-cls}-item-custom {
.@{steps-prefix-cls}-item-icon {
> .@{steps-prefix-cls}-icon {
.@{steps-prefix-cls}-rtl & {
right: 0.5px;
left: auto;
}
}
}
}

View File

@ -1,6 +1,5 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './rtl';
@steps-prefix-cls: ~'@{ant-prefix}-steps';
@process-icon-color: @primary-color;
@ -244,3 +243,4 @@
@import 'label-placement';
@import 'progress-dot';
@import 'nav';
@import './rtl';

View File

@ -1,5 +1,3 @@
@import './nav.rtl.less';
.@{steps-prefix-cls}-navigation {
padding-top: 12px;

View File

@ -1,37 +0,0 @@
.@{steps-prefix-cls}-navigation {
&.@{steps-prefix-cls}-small {
.@{steps-prefix-cls}-item {
&-container {
.@{steps-prefix-cls}-rtl& {
margin-right: -12px;
margin-left: 0;
}
}
}
}
.@{steps-prefix-cls}-item {
&-container {
.@{steps-prefix-cls}-rtl& {
margin-right: -16px;
margin-left: 0;
text-align: right;
}
.@{steps-prefix-cls}-item-title {
.@{steps-prefix-cls}-rtl& {
padding-left: 0;
}
}
}
&::after {
.@{steps-prefix-cls}-rtl& {
right: 100%;
left: auto;
margin-right: -2px;
margin-left: 0;
transform: rotate(225deg);
}
}
}
}

View File

@ -58,3 +58,108 @@
}
}
}
// custom-icon
.@{steps-prefix-cls}-item-custom {
.@{steps-prefix-cls}-item-icon {
> .@{steps-prefix-cls}-icon {
.@{steps-prefix-cls}-rtl & {
right: 0.5px;
left: auto;
}
}
}
}
// nav
.@{steps-prefix-cls}-navigation {
&.@{steps-prefix-cls}-small {
.@{steps-prefix-cls}-item {
&-container {
.@{steps-prefix-cls}-rtl& {
margin-right: -12px;
margin-left: 0;
}
}
}
}
.@{steps-prefix-cls}-item {
&-container {
.@{steps-prefix-cls}-rtl& {
margin-right: -16px;
margin-left: 0;
text-align: right;
}
.@{steps-prefix-cls}-item-title {
.@{steps-prefix-cls}-rtl& {
padding-left: 0;
}
}
}
&::after {
.@{steps-prefix-cls}-rtl& {
right: 100%;
left: auto;
margin-right: -2px;
margin-left: 0;
transform: rotate(225deg);
}
}
}
}
// small
.@{steps-prefix-cls}-small {
&.@{steps-prefix-cls}-horizontal:not(.@{steps-prefix-cls}-label-vertical)
.@{steps-prefix-cls}-item {
.@{steps-prefix-cls}-rtl& {
margin-right: 0;
margin-left: 12px;
}
&:last-child {
.@{steps-prefix-cls}-rtl& {
margin-left: 0;
}
}
}
.@{steps-prefix-cls}-item-title {
.@{steps-prefix-cls}-rtl& {
padding-right: 0;
}
}
}
// vertical
.steps-vertical() {
.@{steps-prefix-cls}-item {
&-icon {
.@{steps-prefix-cls}-rtl& {
float: right;
margin-right: 0;
margin-left: 16px;
}
}
}
> .@{steps-prefix-cls}-item
> .@{steps-prefix-cls}-item-container
> .@{steps-prefix-cls}-item-tail {
.@{steps-prefix-cls}-rtl& {
right: 16px;
left: auto;
}
}
&.@{steps-prefix-cls}-small .@{steps-prefix-cls}-item-container {
.@{steps-prefix-cls}-item-tail {
.@{steps-prefix-cls}-rtl& {
right: 12px;
left: auto;
}
}
}
}

View File

@ -1,5 +1,3 @@
@import './small.rtl.less';
.@{steps-prefix-cls}-small {
&.@{steps-prefix-cls}-horizontal:not(.@{steps-prefix-cls}-label-vertical)
.@{steps-prefix-cls}-item {

View File

@ -1,21 +0,0 @@
.@{steps-prefix-cls}-small {
&.@{steps-prefix-cls}-horizontal:not(.@{steps-prefix-cls}-label-vertical)
.@{steps-prefix-cls}-item {
.@{steps-prefix-cls}-rtl& {
margin-right: 0;
margin-left: 12px;
}
&:last-child {
.@{steps-prefix-cls}-rtl& {
margin-left: 0;
}
}
}
.@{steps-prefix-cls}-item-title {
.@{steps-prefix-cls}-rtl& {
padding-right: 0;
}
}
}

View File

@ -1,5 +1,3 @@
@import './vertical.rtl.less';
.steps-vertical() {
display: block;
.@{steps-prefix-cls}-item {

View File

@ -1,29 +0,0 @@
.steps-vertical() {
.@{steps-prefix-cls}-item {
&-icon {
.@{steps-prefix-cls}-rtl& {
float: right;
margin-right: 0;
margin-left: 16px;
}
}
}
> .@{steps-prefix-cls}-item
> .@{steps-prefix-cls}-item-container
> .@{steps-prefix-cls}-item-tail {
.@{steps-prefix-cls}-rtl& {
right: 16px;
left: auto;
}
}
&.@{steps-prefix-cls}-small .@{steps-prefix-cls}-item-container {
.@{steps-prefix-cls}-item-tail {
.@{steps-prefix-cls}-rtl& {
right: 12px;
left: auto;
}
}
}
}

View File

@ -1,6 +1,5 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './rtl';
@switch-prefix-cls: ~'@{ant-prefix}-switch';
@switch-duration: 0.36s;
@ -177,3 +176,5 @@
transform-origin: 50% 50%;
}
}
@import './rtl';

View File

@ -123,7 +123,7 @@ export interface TableRowSelection<T> {
type?: RowSelectionType;
selectedRowKeys?: Key[];
onChange?: (selectedRowKeys: Key[], selectedRows: T[]) => void;
getCheckboxProps?: (record: T) => Partial<CheckboxProps>;
getCheckboxProps?: (record: T) => Partial<Omit<CheckboxProps, 'checked' | 'defaultChecked'>>;
onSelect?: SelectionSelectFn<T>;
onSelectMultiple?: (selected: boolean, selectedRows: T[], changeRows: T[]) => void;
/** @deprecated This function is meaningless and should use `onChange` instead */

View File

@ -5,7 +5,6 @@
@table-prefix-cls: ~'@{ant-prefix}-table';
@dropdown-prefix-cls: ~'@{ant-prefix}-dropdown';
@table-wrapepr-rtl-cls: ~'@{table-prefix-cls}-wrapper-rtl';
@table-header-icon-color: #bfbfbf;
@table-header-icon-color-hover: darken(@table-header-icon-color, 10%);
@table-header-sort-active-filter-bg: lighten(@table-header-sort-active-bg, 2%);
@ -14,9 +13,6 @@
.@{table-prefix-cls}-wrapper {
.clearfix;
&-rtl {
direction: rtl;
}
}
.@{table-prefix-cls} {
@ -25,6 +21,7 @@
z-index: 0;
clear: both;
background: @table-bg;
border-radius: @border-radius-base;
// https://github.com/ant-design/ant-design/issues/17611
table {
@ -33,10 +30,6 @@
border-radius: @table-border-radius-base @table-border-radius-base 0 0;
border-collapse: separate;
border-spacing: 0;
.@{table-wrapepr-rtl-cls} & {
text-align: right;
}
}
// ============================= Cell =============================
@ -93,14 +86,6 @@
&[colspan]:not([colspan='1']) {
text-align: center;
.@{table-wrapepr-rtl-cls} & {
text-align: center;
}
}
.@{table-wrapepr-rtl-cls} & {
text-align: right;
}
}
}
@ -143,9 +128,6 @@
margin: -@table-padding-vertical -@table-padding-horizontal -@table-padding-vertical (@table-padding-horizontal +
ceil(@font-size-sm * 1.4));
&.@{table-prefix-cls}-rtl {
margin: -@table-padding-vertical (@table-padding-horizontal + ceil(@font-size-sm * 1.4)) -@table-padding-vertical -@table-padding-horizontal;
}
td {
background: transparent;
}
@ -176,10 +158,6 @@
&-pagination.@{ant-prefix}-pagination {
float: right;
margin: 16px 0;
.@{table-wrapepr-rtl-cls} & {
float: left;
}
}
// ================================================================
@ -221,11 +199,6 @@
margin-left: @padding-xs;
color: @table-header-icon-color;
.@{table-wrapepr-rtl-cls} & {
margin-right: @padding-xs;
margin-left: 0;
}
&-full {
margin-top: -0.2em;
margin-bottom: 0;
@ -261,10 +234,6 @@
&-filter-column-title {
flex: auto;
padding: @table-padding-vertical 2.3em @table-padding-vertical @table-padding-horizontal;
.@{table-wrapepr-rtl-cls} & {
padding: @table-padding-vertical @table-padding-horizontal @table-padding-vertical 2.3em;
}
}
&-filter-trigger-container {
@ -279,11 +248,6 @@
cursor: pointer;
transition: background-color 0.3s;
.@{table-wrapepr-rtl-cls} & {
right: auto;
left: 0;
}
&-open,
&:hover,
thead th.@{table-prefix-cls}-column-has-sorters:hover &:hover {
@ -346,11 +310,6 @@
&-submenu {
.@{ant-prefix}-checkbox-wrapper + span {
padding-left: 8px;
.@{ant-prefix}-dropdown-rtl & {
padding-right: 8px;
padding-left: 0;
}
}
}
@ -384,22 +343,12 @@
&-selection {
position: relative;
.@{table-wrapepr-rtl-cls} & {
text-align: center;
}
&-extra {
position: absolute;
top: 50%;
right: 0;
transform: translate(100%, -50%);
.@{table-wrapepr-rtl-cls} & {
right: auto;
left: 0;
transform: translate(-100%, -50%);
}
.@{iconfont-css-prefix} {
.iconfont-size-under-12px(10px);
color: @table-header-icon-color;
@ -423,10 +372,6 @@
&-row-indent {
float: left;
height: 1px;
.@{table-wrapepr-rtl-cls} & {
float: right;
}
}
&-row-expand-icon {
@ -449,10 +394,6 @@
transition: all 0.3s;
user-select: none;
.@{table-wrapepr-rtl-cls} & {
float: right;
}
&:focus,
&:hover,
&:active {
@ -503,11 +444,6 @@
.@{table-prefix-cls}-row-indent + & {
margin-top: (@font-size-base * @line-height-base - ceil(@font-size-sm * 1.4)) / 2;
margin-right: @padding-xs;
.@{table-wrapepr-rtl-cls} & {
margin-right: 0;
margin-left: @padding-xs;
}
}
}
@ -636,3 +572,4 @@
}
@import './radius.less';
@import './rtl';

View File

@ -0,0 +1,130 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@table-prefix-cls: ~'@{ant-prefix}-table';
@table-wrapepr-rtl-cls: ~'@{table-prefix-cls}-wrapper-rtl';
.@{table-prefix-cls}-wrapper {
&-rtl {
direction: rtl;
}
}
.@{table-prefix-cls} {
table {
.@{table-wrapepr-rtl-cls} & {
text-align: right;
}
}
// ============================ Header ============================
thead {
> tr {
> th {
&[colspan]:not([colspan='1']) {
.@{table-wrapepr-rtl-cls} & {
text-align: center;
}
}
.@{table-wrapepr-rtl-cls} & {
text-align: right;
}
}
}
}
// ============================= Body =============================
tbody {
> tr {
// ========================= Nest Table ===========================
.@{table-prefix-cls} {
&.@{table-prefix-cls}-rtl {
margin: -@table-padding-vertical (@table-padding-horizontal + ceil(@font-size-sm * 1.4)) -@table-padding-vertical -@table-padding-horizontal;
}
}
}
}
// ========================== Pagination ==========================
&-pagination.@{ant-prefix}-pagination {
.@{table-wrapepr-rtl-cls} & {
float: left;
}
}
// ================================================================
// = Function =
// ================================================================
// ============================ Sorter ============================
&-column-sorter {
.@{table-wrapepr-rtl-cls} & {
margin-right: @padding-xs;
margin-left: 0;
}
}
// ============================ Filter ============================
&-filter-column-title {
.@{table-wrapepr-rtl-cls} & {
padding: @table-padding-vertical @table-padding-horizontal @table-padding-vertical 2.3em;
}
}
&-filter-trigger-container {
.@{table-wrapepr-rtl-cls} & {
right: auto;
left: 0;
}
}
// Dropdown
&-filter-dropdown {
// Checkbox
&,
&-submenu {
.@{ant-prefix}-checkbox-wrapper + span {
.@{ant-prefix}-dropdown-rtl & {
padding-right: 8px;
padding-left: 0;
}
}
}
}
// ========================== Selections ==========================
&-selection {
.@{table-wrapepr-rtl-cls} & {
text-align: center;
}
&-extra {
.@{table-wrapepr-rtl-cls} & {
right: auto;
left: 0;
transform: translate(-100%, -50%);
}
}
}
// ========================== Expandable ==========================
&-row-indent {
.@{table-wrapepr-rtl-cls} & {
float: right;
}
}
&-row-expand-icon {
.@{table-wrapepr-rtl-cls} & {
float: right;
}
.@{table-prefix-cls}-row-indent + & {
.@{table-wrapepr-rtl-cls} & {
margin-right: 0;
margin-left: @padding-xs;
}
}
}
}

View File

@ -277,8 +277,29 @@ describe('Tooltip', () => {
<Tooltip
title="xxxxx"
placement="bottomLeft"
mouseEnterDelay={0}
mouseLeaveDelay={0}
visible
transitionName=""
>
<span>
Hello world!
</span>
</Tooltip>,
);
await sleep(300);
expect(wrapper.instance().getPopupDomNode().className).toContain('placement-bottomLeft');
wrapper.setProps({
placement: 'topRight',
});
await sleep(300);
expect(wrapper.instance().getPopupDomNode().className).toContain('placement-topRight');
});
it('other placement when mouse enter', async () => {
const wrapper = mount(
<Tooltip
title="xxxxx"
placement="topRight"
transitionName=""
>
<span>
Hello world!
@ -289,14 +310,7 @@ describe('Tooltip', () => {
expect(wrapper.find('span')).toHaveLength(1);
const button = wrapper.find('span').at(0);
button.simulate('mouseenter');
await sleep(50);
expect(wrapper.instance().getPopupDomNode().className).toContain('placement-bottomLeft');
button.simulate('mouseleave');
wrapper.setProps({
placement: 'topRight',
});
button.simulate('mouseenter');
await sleep(50);
await sleep(300);
expect(wrapper.instance().getPopupDomNode().className).toContain('placement-topRight');
});
});

View File

@ -2,7 +2,6 @@
@import '../../style/mixins/index';
@import '../../checkbox/style/mixin';
@import './customize.less';
@import './rtl.less';
@transfer-prefix-cls: ~'@{ant-prefix}-transfer';
@ -183,3 +182,5 @@
}
}
}
@import './rtl';

View File

@ -1,5 +1,125 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TreeSelect TreeSelect Custom Icons should \`treeIcon\` work 1`] = `
<div
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow ant-select-open"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="true"
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="ant-select-selection-search-input"
id="rc_select_TEST_OR_SSR"
readonly=""
role="combobox"
style="opacity: 0;"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
/>
</div>
<div>
<div
class="ant-select-dropdown ant-tree-select-dropdown"
style="opacity: 0; width: 0px;"
>
<div>
<div>
<div
class="ant-select-tree"
>
<div
role="tree"
>
<input
disabled=""
style="width: 0px; height: 0px; display: flex; overflow: hidden; opacity: 0; border: 0px; padding: 0px; margin: 0px;"
value=""
/>
</div>
<div
class="ant-select-tree-list"
style="height: 256px;"
>
<div>
<div
class="ant-select-tree-list-holder-inner"
style="display: flex; flex-direction: column;"
>
<div
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close"
>
<span
class="ant-select-tree-switcher ant-select-tree-switcher-noop"
/>
<span
class="ant-select-tree-node-content-wrapper ant-select-tree-node-content-wrapper-normal"
title="parent 1"
>
<span
class="ant-select-tree-iconEle ant-select-tree-icon__customize"
>
<span>
Bamboo
</span>
</span>
<span
class="ant-select-tree-title"
>
parent 1
</span>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select: none;"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
`;
exports[`TreeSelect TreeSelect Custom Icons should support customized icons 1`] = `
<div
class="ant-select ant-tree-select ant-select-multiple ant-select-allow-clear ant-select-show-search"

View File

@ -34,5 +34,15 @@ describe('TreeSelect', () => {
expect(wrapper.render()).toMatchSnapshot();
});
it('should `treeIcon` work', () => {
const wrapper = mount(
<TreeSelect treeIcon open>
<TreeNode value="parent 1" title="parent 1" icon={<span>Bamboo</span>} />
</TreeSelect>,
);
expect(wrapper.render()).toMatchSnapshot();
});
});
});

View File

@ -94,6 +94,7 @@ class TreeSelect<T> extends React.Component<TreeSelectProps<T>, {}> {
getPopupContainer,
dropdownClassName,
bordered,
treeIcon = false,
} = this.props;
const prefixCls = getPrefixCls('select', customizePrefixCls);
@ -173,7 +174,7 @@ class TreeSelect<T> extends React.Component<TreeSelectProps<T>, {}> {
switcherIcon={(nodeProps: AntTreeNodeProps) =>
renderSwitcherIcon(treePrefixCls, switcherIcon, treeLine, nodeProps)
}
showTreeIcon={false}
showTreeIcon={treeIcon}
notFoundContent={mergedNotFound}
getPopupContainer={getPopupContainer || getContextPopupContainer}
treeMotion={null}

View File

@ -8,6 +8,7 @@ import Base from '../Base'; // eslint-disable-line import/no-named-as-default
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import Typography from '../Typography';
import { sleep } from '../../../tests/utils';
jest.mock('copy-to-clipboard');
@ -43,16 +44,11 @@ describe('Typography', () => {
return style;
};
beforeAll(() => {
jest.useFakeTimers();
});
afterEach(() => {
errorSpy.mockReset();
});
afterAll(() => {
jest.useRealTimers();
errorSpy.mockRestore();
Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
get: originOffsetHeight,
@ -75,33 +71,33 @@ describe('Typography', () => {
const fullStr =
'Bamboo is Little Light Bamboo is Little Light Bamboo is Little Light Bamboo is Little Light Bamboo is Little Light';
it('should trigger update', () => {
it('should trigger update', async () => {
const wrapper = mount(
<Base ellipsis component="p" editable>
{fullStr}
</Base>,
);
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('span:not(.anticon)').text()).toEqual('Bamboo is Little ...');
wrapper.setProps({ ellipsis: { rows: 2 } });
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('span:not(.anticon)').text()).toEqual(
'Bamboo is Little Light Bamboo is Litt...',
);
wrapper.setProps({ ellipsis: { rows: 99 } });
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('p').text()).toEqual(fullStr);
wrapper.unmount();
});
it('should middle ellipsis', () => {
it('should middle ellipsis', async () => {
const suffix = '--suffix';
const wrapper = mount(
<Base ellipsis={{ rows: 1, suffix }} component="p">
@ -109,13 +105,13 @@ describe('Typography', () => {
</Base>,
);
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('p').text()).toEqual('Bamboo is...--suffix');
wrapper.unmount();
});
it('should front or middle ellipsis', () => {
it('should front or middle ellipsis', async () => {
const suffix = '--The information is very important';
const wrapper = mount(
<Base ellipsis={{ rows: 1, suffix }} component="p">
@ -123,24 +119,24 @@ describe('Typography', () => {
</Base>,
);
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('p').text()).toEqual('...--The information is very important');
wrapper.setProps({ ellipsis: { rows: 2, suffix } });
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('p').text()).toEqual('Ba...--The information is very important');
wrapper.setProps({ ellipsis: { rows: 99, suffix } });
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('p').text()).toEqual(fullStr + suffix);
wrapper.unmount();
});
it('connect children', () => {
it('connect children', async () => {
const bamboo = 'Bamboo';
const is = ' is ';
@ -153,13 +149,13 @@ describe('Typography', () => {
</Base>,
);
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('span:not(.anticon)').text()).toEqual('Bamboo is Little...');
});
it('should expandable work', () => {
it('should expandable work', async () => {
const onExpand = jest.fn();
const wrapper = mount(
<Base ellipsis={{ expandable: true, onExpand }} component="p" copyable editable>
@ -167,12 +163,12 @@ describe('Typography', () => {
</Base>,
);
jest.runAllTimers();
await sleep(20);
wrapper.update();
wrapper.find('.ant-typography-expand').simulate('click');
expect(onExpand).toHaveBeenCalled();
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('p').text()).toEqual(fullStr);
@ -187,6 +183,7 @@ describe('Typography', () => {
describe('copyable', () => {
function copyTest(name, text, target) {
it(name, () => {
jest.useFakeTimers();
const onCopy = jest.fn();
const wrapper = mount(
<Base component="p" copyable={{ text, onCopy }}>
@ -210,6 +207,7 @@ describe('Typography', () => {
// Will set back when 3 seconds pass
expect(wrapper.find('.anticon-check').length).toBeFalsy();
jest.useRealTimers();
});
}

View File

@ -1,6 +1,5 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './rtl';
@typography-prefix-cls: ~'@{ant-prefix}-typography';
@ -203,3 +202,5 @@
overflow: hidden;
}
}
@import './rtl';

Some files were not shown because too many files have changed in this diff Show More