Merge pull request #19049 from ant-design/master

chore: Merge master into feature
This commit is contained in:
只捱宅 2019-09-28 19:27:19 +08:00 committed by GitHub
commit dc0dfea201
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 746 additions and 35 deletions

View File

@ -433,6 +433,7 @@ exports[`renders ./components/avatar/demo/dynamic.md correctly 1`] = `
>
<span
class="ant-avatar-string"
style="opacity:0"
>
U
</span>
@ -486,6 +487,7 @@ exports[`renders ./components/avatar/demo/toggle-debug.md correctly 1`] = `
>
<span
class="ant-avatar-string"
style="opacity:0"
>
Avatar
</span>
@ -507,6 +509,7 @@ exports[`renders ./components/avatar/demo/toggle-debug.md correctly 1`] = `
>
<span
class="ant-avatar-string"
style="opacity:0"
>
Avatar
</span>
@ -554,6 +557,7 @@ exports[`renders ./components/avatar/demo/type.md correctly 1`] = `
>
<span
class="ant-avatar-string"
style="opacity:0"
>
U
</span>
@ -563,6 +567,7 @@ exports[`renders ./components/avatar/demo/type.md correctly 1`] = `
>
<span
class="ant-avatar-string"
style="opacity:0"
>
USER
</span>
@ -580,6 +585,7 @@ exports[`renders ./components/avatar/demo/type.md correctly 1`] = `
>
<span
class="ant-avatar-string"
style="opacity:0"
>
U
</span>

View File

@ -29,6 +29,7 @@ export interface AvatarProps {
export interface AvatarState {
scale: number;
mounted: boolean;
isImgExist: boolean;
}
@ -40,6 +41,7 @@ export default class Avatar extends React.Component<AvatarProps, AvatarState> {
state = {
scale: 1,
mounted: false,
isImgExist: true,
};
@ -53,6 +55,7 @@ export default class Avatar extends React.Component<AvatarProps, AvatarState> {
componentDidMount() {
this.setScale();
this.setState({ mounted: true });
}
componentDidUpdate(prevProps: AvatarProps) {
@ -105,7 +108,7 @@ export default class Avatar extends React.Component<AvatarProps, AvatarState> {
...others
} = this.props;
const { isImgExist, scale } = this.state;
const { isImgExist, scale, mounted } = this.state;
const prefixCls = getPrefixCls('avatar', customizePrefixCls);
@ -144,6 +147,7 @@ export default class Avatar extends React.Component<AvatarProps, AvatarState> {
WebkitTransform: transformString,
transform: transformString,
};
const sizeChildrenStyle: React.CSSProperties =
typeof size === 'number'
? {
@ -160,9 +164,15 @@ export default class Avatar extends React.Component<AvatarProps, AvatarState> {
</span>
);
} else {
const childrenStyle: React.CSSProperties = {};
if (!mounted) {
childrenStyle.opacity = 0;
}
children = (
<span
className={`${prefixCls}-string`}
style={{ opacity: 0 }}
ref={(node: HTMLElement) => (this.avatarChildren = node)}
>
{children}

View File

@ -130,6 +130,11 @@
.button-size(@btn-height-lg; @btn-padding-lg; @btn-font-size-lg; 0);
line-height: @btn-height-lg - 2px;
}
&-lg > .@{btnClassName}.@{btnClassName}-icon-only {
.square(@btn-height-lg);
padding-right: 0;
padding-left: 0;
}
&-sm > .@{btnClassName},
&-sm > span > .@{btnClassName} {
.button-size(@btn-height-sm; @btn-padding-sm; @font-size-base; 0);
@ -138,6 +143,11 @@
font-size: @font-size-base;
}
}
&-sm > .@{btnClassName}.@{btnClassName}-icon-only {
.square(@btn-height-sm);
padding-right: 0;
padding-left: 0;
}
}
// Base styles of buttons
// --------------------------------------------------

View File

@ -1,9 +1,21 @@
import React from 'react';
import { mount } from 'enzyme';
import Collapse from '..';
import mountTest from '../../../tests/shared/mountTest';
describe('Collapse', () => {
// Fix css-animation deps on these
// https://github.com/yiminghe/css-animation/blob/a5986d73fd7dfce75665337f39b91483d63a4c8c/src/Event.js#L44
window.AnimationEvent = window.AnimationEvent || (() => {});
window.TransitionEvent = window.TransitionEvent || (() => {});
afterAll(() => {
// restore it
delete window.AnimationEvent;
delete window.TransitionEvent;
});
// eslint-disable-next-line global-require
const Collapse = require('..').default;
mountTest(Collapse);
it('should support remove expandIcon', () => {
@ -24,4 +36,24 @@ describe('Collapse', () => {
);
expect(wrapper.render()).toMatchSnapshot();
});
it('could be expand and collapse', () => {
jest.useFakeTimers();
const wrapper = mount(
<Collapse>
<Collapse.Panel header="This is panel header 1" key="1">
content
</Collapse.Panel>
</Collapse>,
);
expect(wrapper.find('.ant-collapse-item').hasClass('ant-collapse-item-active')).toBe(false);
wrapper
.find('.ant-collapse-header')
.at(0)
.simulate('click');
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();
});
});

View File

@ -360,6 +360,7 @@ exports[`ConfigProvider components Avatar configProvider 1`] = `
>
<span
class="config-avatar-string"
style="opacity:0"
/>
</span>
`;
@ -370,6 +371,7 @@ exports[`ConfigProvider components Avatar normal 1`] = `
>
<span
class="ant-avatar-string"
style="opacity:0"
/>
</span>
`;
@ -380,6 +382,7 @@ exports[`ConfigProvider components Avatar prefixCls 1`] = `
>
<span
class="prefix-Avatar-string"
style="opacity:0"
/>
</span>
`;

View File

@ -47,7 +47,7 @@ class WeekPicker extends React.Component<any, WeekPickerState> {
const value = props.value || props.defaultValue;
if (value && !interopDefault(moment).isMoment(value)) {
throw new Error(
'The value/defaultValue of DatePicker or MonthPicker must be ' +
'The value/defaultValue of WeekPicker must be ' +
'a moment object after `antd@2.0`, see: https://u.ant.design/date-picker-value',
);
}

View File

@ -1,5 +1,6 @@
import React from 'react';
import { mount, render } from 'enzyme';
import moment from 'moment';
import { setMockDate, resetMockDate } from '../../../tests/utils';
import DatePicker from '..';
import focusTest from '../../../tests/shared/focusTest';
@ -71,4 +72,16 @@ describe('WeekPicker', () => {
),
).toMatchSnapshot();
});
it('should support allowClear', () => {
const onChange = jest.fn();
const wrapper = mount(
<WeekPicker defaultValue={moment()} onChange={onChange} />,
);
wrapper
.find('.ant-calendar-picker-clear')
.hostNodes()
.simulate('click');
expect(onChange).toHaveBeenCalledWith(null, '');
});
});

View File

@ -0,0 +1,52 @@
import React from 'react';
import { mount } from 'enzyme';
import DatePicker from '..';
const { MonthPicker, WeekPicker, RangePicker } = DatePicker;
describe('invalid value or defaultValue', () => {
beforeAll(() => {
jest.spyOn(console, 'error').mockImplementation(() => undefined);
});
afterAll(() => {
// eslint-disable-next-line no-console
console.error.mockRestore();
});
it('DatePicker should throw error when value or defaultValue is not moment object', () => {
expect(() => {
mount(<DatePicker value={{}} />);
}).toThrow('The value/defaultValue of DatePicker or MonthPicker must be a moment object after `antd@2.0`, see: https://u.ant.design/date-picker-value');
expect(() => {
mount(<DatePicker defaultValue={{}} />);
}).toThrow('The value/defaultValue of DatePicker or MonthPicker must be a moment object after `antd@2.0`, see: https://u.ant.design/date-picker-value')
});
it('WeekPicker should throw error when value or defaultValue is not moment object', () => {
expect(() => {
mount(<WeekPicker value={{}} />);
}).toThrow('The value/defaultValue of WeekPicker must be a moment object after `antd@2.0`, see: https://u.ant.design/date-picker-value');
expect(() => {
mount(<WeekPicker defaultValue={{}} />);
}).toThrow('The value/defaultValue of WeekPicker must be a moment object after `antd@2.0`, see: https://u.ant.design/date-picker-value');
});
it('RangePicker should throw error when value or defaultValue is not moment object', () => {
expect(() => {
mount(<RangePicker value={[{}, {}]} />);
}).toThrow('The value/defaultValue of RangePicker must be a moment object array after `antd@2.0`, see: https://u.ant.design/date-picker-value');
expect(() => {
mount(<RangePicker defaultValue={[{}, {}]} />);
}).toThrow('The value/defaultValue of RangePicker must be a moment object array after `antd@2.0`, see: https://u.ant.design/date-picker-value')
});
it('MonthPicker should throw error when value or defaultValue is not moment object', () => {
expect(() => {
mount(<MonthPicker value={{}} />);
}).toThrow('The value/defaultValue of DatePicker or MonthPicker must be a moment object after `antd@2.0`, see: https://u.ant.design/date-picker-value');
expect(() => {
mount(<MonthPicker defaultValue={{}} />);
}).toThrow('The value/defaultValue of DatePicker or MonthPicker must be a moment object after `antd@2.0`, see: https://u.ant.design/date-picker-value')
});
});

View File

@ -290,6 +290,7 @@ class Input extends React.Component<InputProps, any> {
// Input elements must be either controlled or uncontrolled,
// specify either the value prop, or the defaultValue prop, but not both.
'defaultValue',
'size',
]);
return this.renderLabeledIcon(

View File

@ -114,11 +114,14 @@ export default class Search extends React.Component<SearchProps, any> {
let button: React.ReactNode;
const enterButtonAsElement = enterButton as React.ReactElement<any>;
if (enterButtonAsElement.type === Button || enterButtonAsElement.type === 'button') {
const isAntdButton =
enterButtonAsElement.type &&
(enterButtonAsElement.type as typeof Button).__ANT_BUTTON === true;
if (isAntdButton || enterButtonAsElement.type === 'button') {
button = React.cloneElement(enterButtonAsElement, {
onClick: this.onSearch,
key: 'enterButton',
...(enterButtonAsElement.type === Button
...(isAntdButton
? {
className: btnClassName,
size,

View File

@ -201,7 +201,7 @@ exports[`renders ./components/input/demo/addon.md correctly 1`] = `
</div>
`;
exports[`renders ./components/input/demo/algin.md correctly 1`] = `
exports[`renders ./components/input/demo/align.md correctly 1`] = `
<div>
<div
class="ant-mentions"

View File

@ -4,7 +4,6 @@ import Select from '..';
import Icon from '../../icon';
import focusTest from '../../../tests/shared/focusTest';
import mountTest from '../../../tests/shared/mountTest';
import { resetWarned } from '../../_util/warning';
const { Option } = Select;
@ -133,16 +132,4 @@ describe('Select', () => {
expect(wrapper.render()).toMatchSnapshot();
});
});
it('warning if user use `inputValue`', () => {
resetWarned();
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
mount(<Select inputValue="" />);
expect(errorSpy).toHaveBeenLastCalledWith(
'Warning: [antd: Select] `inputValue` is deprecated. Please use `searchValue` instead.',
);
errorSpy.mockRestore();
});
});

View File

@ -46,7 +46,6 @@ Select component to select value from options.
| optionFilterProp | Which prop value of option will be used for filter if filterOption is true | string | value | |
| optionLabelProp | Which prop value of option will render as content of select. [Example](https://codesandbox.io/s/antd-reproduction-template-tk678) | string | `value` for `combobox`, `children` for other modes | |
| placeholder | Placeholder of select | string\|ReactNode | - | |
| searchValue | Search input value | string | - | 3.23.2 |
| showArrow | Whether to show the drop-down arrow | boolean | true | 3.2.1 |
| showSearch | Whether show search input in single mode. | boolean | false | |
| size | Size of Select input. `default` `large` `small` | string | default | |

View File

@ -53,9 +53,6 @@ export type SelectValue = string | string[] | number | number[] | LabeledValue |
export interface SelectProps<T = SelectValue> extends AbstractSelectProps {
value?: T;
/** @deprecated Use `searchValue` instead. */
inputValue?: string;
searchValue?: string;
defaultValue?: T;
mode?: 'default' | 'multiple' | 'tags' | 'combobox' | string;
optionLabelProp?: string;
@ -139,12 +136,6 @@ export default class Select<T = SelectValue> extends React.Component<SelectProps
'it will be removed in next major version, ' +
'please use AutoComplete instead',
);
warning(
!('inputValue' in props),
'Select',
'`inputValue` is deprecated. Please use `searchValue` instead.',
);
}
getNotFoundContent(renderEmpty: RenderEmptyHandler) {
@ -207,8 +198,6 @@ export default class Select<T = SelectValue> extends React.Component<SelectProps
clearIcon,
menuItemSelectedIcon,
showArrow,
inputValue,
searchValue,
...restProps
} = this.props;
const rest = omit(restProps, ['inputIcon']);
@ -270,7 +259,6 @@ export default class Select<T = SelectValue> extends React.Component<SelectProps
showArrow={showArrow}
{...rest}
{...modeConfig}
inputValue={searchValue || inputValue}
prefixCls={prefixCls}
className={cls}
optionLabelProp={optionLabelProp || 'children'}

View File

@ -47,7 +47,6 @@ title: Select
| optionFilterProp | 搜索时过滤对应的 option 属性,如设置为 children 表示对内嵌内容进行搜索。[示例](https://codesandbox.io/s/antd-reproduction-template-tk678) | string | value | |
| optionLabelProp | 回填到选择框的 Option 的属性值,默认是 Option 的子元素。比如在子元素需要高亮效果时,此值可以设为 `value`。 | string | `children` combobox 模式下为 `value` | |
| placeholder | 选择框默认文字 | string | - | |
| searchValue | 搜索框文本 | string | - | 3.23.2 |
| showArrow | 是否显示下拉小箭头 | boolean | true | 3.2.1 |
| showSearch | 使单选模式可搜索 | boolean | false | |
| size | 选择框大小,可选 `large` `small` | string | default | |

View File

@ -428,3 +428,543 @@ exports[`Transfer should show sorted targetkey 1`] = `
</div>
</div>
`;
exports[`Transfer should support render value and label in item 1`] = `
<Transfer
dataSource={
Array [
Object {
"key": "a",
"title": "title",
},
]
}
locale={Object {}}
render={[Function]}
showSearch={false}
>
<LocaleReceiver
componentName="Transfer"
defaultLocale={
Object {
"itemUnit": "item",
"itemsUnit": "items",
"searchPlaceholder": "Search here",
"titles": Array [
"",
"",
],
}
}
>
<div
className="ant-transfer"
>
<TransferList
checkedKeys={Array []}
dataSource={
Array [
Object {
"key": "a",
"title": "title",
},
]
}
direction="left"
handleClear={[Function]}
handleFilter={[Function]}
handleSelect={[Function]}
handleSelectAll={[Function]}
itemUnit="item"
itemsUnit="items"
lazy={Object {}}
notFoundContent={
<Context.Consumer>
[Function]
</Context.Consumer>
}
onItemSelect={[Function]}
onItemSelectAll={[Function]}
onScroll={[Function]}
prefixCls="ant-transfer-list"
render={[Function]}
searchPlaceholder="Search here"
showSearch={false}
titleText=""
titles={
Array [
"",
"",
]
}
>
<div
className="ant-transfer-list"
>
<div
className="ant-transfer-list-header"
>
<Checkbox
checked={false}
indeterminate={false}
onChange={[Function]}
>
<label
className="ant-checkbox-wrapper"
>
<Checkbox
checked={false}
className=""
defaultChecked={false}
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
prefixCls="ant-checkbox"
style={Object {}}
type="checkbox"
>
<span
className="ant-checkbox"
style={Object {}}
>
<input
checked={false}
className="ant-checkbox-input"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
type="checkbox"
/>
<span
className="ant-checkbox-inner"
/>
</span>
</Checkbox>
</label>
</Checkbox>
<span
className="ant-transfer-list-header-selected"
>
<span>
1
item
</span>
<span
className="ant-transfer-list-header-title"
/>
</span>
</div>
<div
className="ant-transfer-list-body"
>
<ListBody
dataSource={
Array [
Object {
"key": "a",
"title": "title",
},
]
}
direction="left"
filteredItems={
Array [
Object {
"key": "a",
"title": "title",
},
]
}
filteredRenderItems={
Array [
Object {
"item": Object {
"key": "a",
"title": "title",
},
"renderedEl": "label",
"renderedText": "title value",
},
]
}
itemUnit="item"
itemsUnit="items"
lazy={Object {}}
notFoundContent={
<Context.Consumer>
[Function]
</Context.Consumer>
}
onItemSelect={[Function]}
onItemSelectAll={[Function]}
onScroll={[Function]}
prefixCls="ant-transfer-list"
render={[Function]}
searchPlaceholder="Search here"
selectedKeys={Array []}
showSearch={false}
titleText=""
titles={
Array [
"",
"",
]
}
>
<Animate
animation={Object {}}
className="ant-transfer-list-content"
component="ul"
componentProps={
Object {
"onScroll": [Function],
}
}
onAppear={[Function]}
onEnd={[Function]}
onEnter={[Function]}
onLeave={[Function]}
transitionAppear={false}
transitionEnter={true}
transitionLeave={false}
transitionName=""
>
<ul
className="ant-transfer-list-content"
onScroll={[Function]}
>
<AnimateChild
animation={Object {}}
key="a"
transitionAppear={false}
transitionEnter={true}
transitionLeave={false}
transitionName=""
>
<ListItem
checked={false}
item={
Object {
"key": "a",
"title": "title",
}
}
key="a"
lazy={Object {}}
onClick={[Function]}
prefixCls="ant-transfer-list"
renderedEl="label"
renderedText="title value"
>
<LazyLoad
debounce={false}
elementType="div"
height={32}
offset={500}
offsetBottom={0}
offsetHorizontal={0}
offsetLeft={0}
offsetRight={0}
offsetTop={0}
offsetVertical={0}
throttle={0}
>
<div
className="LazyLoad"
style={
Object {
"height": 32,
"width": undefined,
}
}
/>
</LazyLoad>
</ListItem>
</AnimateChild>
</ul>
</Animate>
</ListBody>
</div>
</div>
</TransferList>
<Operation
className="ant-transfer-operation"
leftActive={false}
moveToLeft={[Function]}
moveToRight={[Function]}
rightActive={false}
>
<div
className="ant-transfer-operation"
>
<Button
block={false}
disabled={true}
ghost={false}
htmlType="button"
icon="right"
loading={false}
onClick={[Function]}
size="small"
type="primary"
>
<Wave>
<button
className="ant-btn ant-btn-primary ant-btn-sm ant-btn-icon-only"
disabled={true}
onClick={[Function]}
type="button"
>
<Icon
type="right"
>
<LocaleReceiver
componentName="Icon"
>
<i
aria-label="icon: right"
className="anticon anticon-right"
>
<IconReact
className=""
type="right-o"
>
<svg
aria-hidden="true"
className=""
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
key="svg-right"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 0 0 302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 0 0 0-50.4z"
key="svg-right-svg-0"
/>
</svg>
</IconReact>
</i>
</LocaleReceiver>
</Icon>
</button>
</Wave>
</Button>
<Button
block={false}
disabled={true}
ghost={false}
htmlType="button"
icon="left"
loading={false}
onClick={[Function]}
size="small"
type="primary"
>
<Wave>
<button
className="ant-btn ant-btn-primary ant-btn-sm ant-btn-icon-only"
disabled={true}
onClick={[Function]}
type="button"
>
<Icon
type="left"
>
<LocaleReceiver
componentName="Icon"
>
<i
aria-label="icon: left"
className="anticon anticon-left"
>
<IconReact
className=""
type="left-o"
>
<svg
aria-hidden="true"
className=""
data-icon="left"
fill="currentColor"
focusable="false"
height="1em"
key="svg-left"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 0 0 0 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
key="svg-left-svg-0"
/>
</svg>
</IconReact>
</i>
</LocaleReceiver>
</Icon>
</button>
</Wave>
</Button>
</div>
</Operation>
<TransferList
checkedKeys={Array []}
dataSource={Array []}
direction="right"
handleClear={[Function]}
handleFilter={[Function]}
handleSelect={[Function]}
handleSelectAll={[Function]}
itemUnit="item"
itemsUnit="items"
lazy={Object {}}
notFoundContent={
<Context.Consumer>
[Function]
</Context.Consumer>
}
onItemSelect={[Function]}
onItemSelectAll={[Function]}
onScroll={[Function]}
prefixCls="ant-transfer-list"
render={[Function]}
searchPlaceholder="Search here"
showSearch={false}
titleText=""
titles={
Array [
"",
"",
]
}
>
<div
className="ant-transfer-list"
>
<div
className="ant-transfer-list-header"
>
<Checkbox
checked={false}
indeterminate={false}
onChange={[Function]}
>
<label
className="ant-checkbox-wrapper"
>
<Checkbox
checked={false}
className=""
defaultChecked={false}
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
prefixCls="ant-checkbox"
style={Object {}}
type="checkbox"
>
<span
className="ant-checkbox"
style={Object {}}
>
<input
checked={false}
className="ant-checkbox-input"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
type="checkbox"
/>
<span
className="ant-checkbox-inner"
/>
</span>
</Checkbox>
</label>
</Checkbox>
<span
className="ant-transfer-list-header-selected"
>
<span>
0
item
</span>
<span
className="ant-transfer-list-header-title"
/>
</span>
</div>
<div
className="ant-transfer-list-body"
>
<div
className="ant-transfer-list-body-not-found"
>
<Empty
className="ant-empty-small"
image={<Simple />}
>
<LocaleReceiver
componentName="Empty"
>
<div
className="ant-empty ant-empty-normal ant-empty-small"
>
<div
className="ant-empty-image"
>
<Simple>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fillRule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#F5F5F5"
rx="32"
ry="7"
/>
<g
fillRule="nonzero"
stroke="#D9D9D9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#FAFAFA"
/>
</g>
</g>
</svg>
</Simple>
</div>
<p
className="ant-empty-description"
>
No Data
</p>
</div>
</LocaleReceiver>
</Empty>
</div>
</div>
</div>
</TransferList>
</div>
</LocaleReceiver>
</Transfer>
`;

View File

@ -113,6 +113,24 @@ describe('Transfer', () => {
expect(handleChange).toHaveBeenCalledWith(['a', 'b'], 'right', ['a']);
});
it('should move selected keys to left list', () => {
const handleChange = jest.fn();
const wrapper = mount(
<Transfer
{...listCommonProps}
selectedKeys={['a']}
targetKeys={['a']}
onChange={handleChange}
/>
);
wrapper
.find(TransferOperation)
.find(Button)
.at(1)
.simulate('click'); // move selected keys to left list
expect(handleChange).toHaveBeenCalledWith([], 'left', ['a']);
});
it('should move selected keys expect disabled to corresponding list', () => {
const handleChange = jest.fn();
const wrapper = mount(<Transfer {...listDisabledProps} onChange={handleChange} />);
@ -450,4 +468,44 @@ describe('Transfer', () => {
expect(listTarget.prop('style')).toHaveProperty('backgroundColor', 'blue');
expect(operation.prop('style')).toHaveProperty('backgroundColor', 'yellow');
});
it('should support onScroll', () => {
const onScroll = jest.fn();
const component = mount(
<Transfer
{...listCommonProps}
onScroll={onScroll}
/>,
);
component.find('.ant-transfer-list').at(0).find('.ant-transfer-list-content').at(0).simulate('scroll');
expect(onScroll).toHaveBeenLastCalledWith('left', expect.anything());
component.find('.ant-transfer-list').at(1).find('.ant-transfer-list-content').at(0).simulate('scroll');
expect(onScroll).toHaveBeenLastCalledWith('right', expect.anything());
});
it('should support rowKey is function', () => {
expect(() => {
mount(
<Transfer
{...listCommonProps}
rowKey={record => record.key}
/>,
);
}).not.toThrow();
});
it('should support render value and label in item', () => {
const component = mount(
<Transfer
dataSource={[
{
key: 'a',
title: 'title',
},
]}
render={record => ({ value: `${record.title} value`, label: 'label' })}
/>,
);
expect(component).toMatchSnapshot();
});
});

View File

@ -25,6 +25,7 @@ describe('Transfer.Search', () => {
});
it('onSearch', () => {
jest.useFakeTimers();
const dataSource = [
{
key: 'a',
@ -59,6 +60,7 @@ describe('Transfer.Search', () => {
.find('.ant-input')
.at(0)
.simulate('change', { target: { value: 'a' } });
jest.runAllTimers();
expect(onSearch).toHaveBeenCalledWith('left', 'a');
onSearch.mockReset();
@ -68,9 +70,11 @@ describe('Transfer.Search', () => {
.at(0)
.simulate('click');
expect(onSearch).toHaveBeenCalledWith('left', '');
jest.useRealTimers();
});
it('legacy onSearchChange', () => {
jest.useFakeTimers();
const onSearchChange = jest.fn();
const wrapper = mount(
@ -81,11 +85,13 @@ describe('Transfer.Search', () => {
.find('.ant-input')
.at(0)
.simulate('change', { target: { value: 'a' } });
jest.runAllTimers();
expect(errorSpy.mock.calls[0][0]).toMatch(
'Warning: [antd: Transfer] `onSearchChange` is deprecated. Please use `onSearch` instead.',
);
expect(onSearchChange.mock.calls[0][0]).toEqual('left');
expect(onSearchChange.mock.calls[0][1].target.value).toEqual('a');
jest.useRealTimers();
});
});

View File

@ -190,6 +190,8 @@
> span {
display: block;
width: 100%;
height: 100%;
}
.@{iconfont-css-prefix}-loading,
@ -423,6 +425,7 @@
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.@{upload-item}-name {

View File

@ -23,10 +23,10 @@ As a part of nature, it will have deep influence on user behavior, and designers
- The visual system plays the most important role in human perception and cognition. By refining the objective laws in nature and applying it to the interface design, a more layered product experience is created. In addition, hearing systems or tactile systems could be added in future to bring more dimensions and more real product experience. See visual language.
- In the real product design, a series of methods such as behavior analysis, artificial intelligence and sensors could be applied to assist users to make effective decisions and reduce extra operations of users, so as to save users' mental and physical resources and make human-computer interaction more natural.
## Determinacy
## Certainty
<div>
<img src="https://gw.alipayobjects.com/zos/rmsportal/ZxgRAMzXNrxHTcvMLchq.png" alt="Determine" />
<img src="https://gw.alipayobjects.com/zos/rmsportal/ZxgRAMzXNrxHTcvMLchq.png" alt="Certainty" />
</div>
The designers needs to make better design decisions and create a high-definition and low-entropy atmosphere for developer team. Meanwhile, different designers could produce the same design output which fit business needs based on the same understanding of business requirements and design system.

View File

@ -100,6 +100,7 @@ module.exports = {
antd: path.join(process.cwd(), 'index'),
site: path.join(process.cwd(), 'site'),
'react-router': 'react-router/umd/ReactRouter',
'react-intl': 'react-intl/dist',
};
// eslint-disable-next-line