Merge branch 'feature' into tree-select-showSearch

This commit is contained in:
zombiej 2019-04-08 22:23:16 +08:00
commit 58768b90f6
12 changed files with 87 additions and 41 deletions

1
.npmignore Normal file
View File

@ -0,0 +1 @@
~*

View File

@ -62,20 +62,23 @@ export interface BaseButtonProps {
children?: React.ReactNode; children?: React.ReactNode;
} }
// Typescript will make optional not optional if use Pick with union.
// Should change to `AnchorButtonProps | NativeButtonProps` and `any` to `HTMLAnchorElement | HTMLButtonElement` if it fixed.
// ref: https://github.com/ant-design/ant-design/issues/15930
export type AnchorButtonProps = { export type AnchorButtonProps = {
href: string; href: string;
target?: string; target?: string;
onClick?: React.MouseEventHandler<HTMLAnchorElement>; onClick?: React.MouseEventHandler<any>;
} & BaseButtonProps & } & BaseButtonProps &
Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'type'>; Omit<React.AnchorHTMLAttributes<any>, 'type'>;
export type NativeButtonProps = { export type NativeButtonProps = {
htmlType?: ButtonHTMLType; htmlType?: ButtonHTMLType;
onClick?: React.MouseEventHandler<HTMLButtonElement>; onClick?: React.MouseEventHandler<any>;
} & BaseButtonProps & } & BaseButtonProps &
Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'type'>; Omit<React.ButtonHTMLAttributes<any>, 'type'>;
export type ButtonProps = AnchorButtonProps | NativeButtonProps; export type ButtonProps = Partial<AnchorButtonProps & NativeButtonProps>;
interface ButtonState { interface ButtonState {
loading?: boolean | { delay?: number }; loading?: boolean | { delay?: number };

View File

@ -7,6 +7,8 @@ import { selectDate, openPanel, clearInput, nextYear, nextMonth, hasSelected } f
import focusTest from '../../../tests/shared/focusTest'; import focusTest from '../../../tests/shared/focusTest';
describe('DatePicker', () => { describe('DatePicker', () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
focusTest(DatePicker); focusTest(DatePicker);
beforeEach(() => { beforeEach(() => {
@ -15,6 +17,11 @@ describe('DatePicker', () => {
afterEach(() => { afterEach(() => {
MockDate.reset(); MockDate.reset();
errorSpy.mockReset();
});
afterAll(() => {
errorSpy.mockRestore();
}); });
it('support name prop', () => { it('support name prop', () => {
@ -210,4 +217,22 @@ describe('DatePicker', () => {
wrapper.find('.ant-calendar-input').simulate('change', { target: { value: '02/07/18' } }); wrapper.find('.ant-calendar-input').simulate('change', { target: { value: '02/07/18' } });
expect(wrapper.find('.ant-calendar-picker-input').getDOMNode().value).toBe('02/07/2018'); expect(wrapper.find('.ant-calendar-picker-input').getDOMNode().value).toBe('02/07/2018');
}); });
describe('warning use if use invalidate moment', () => {
const invalidateTime = moment('I AM INVALIDATE');
it('defaultValue', () => {
mount(<DatePicker defaultValue={invalidateTime} />);
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: DatePicker] `defaultValue` provides invalidate moment time. If you want to set empty value, use `null` instead.',
);
});
it('value', () => {
mount(<DatePicker value={invalidateTime} />);
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: DatePicker] `value` provides invalidate moment time. If you want to set empty value, use `null` instead.',
);
});
});
}); });

View File

@ -1,10 +1,13 @@
import * as React from 'react'; import * as React from 'react';
import { polyfill } from 'react-lifecycles-compat';
import TimePickerPanel from 'rc-time-picker/lib/Panel'; import TimePickerPanel from 'rc-time-picker/lib/Panel';
import classNames from 'classnames'; import classNames from 'classnames';
import * as moment from 'moment';
import enUS from './locale/en_US'; import enUS from './locale/en_US';
import LocaleReceiver from '../locale-provider/LocaleReceiver'; import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { generateShowHourMinuteSecond } from '../time-picker'; import { generateShowHourMinuteSecond } from '../time-picker';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
type PickerType = 'date' | 'week' | 'month'; type PickerType = 'date' | 'week' | 'month';
@ -43,8 +46,21 @@ function getColumns({ showHour, showMinute, showSecond, use12Hours }: any) {
return column; return column;
} }
function checkValidate(value: any, propName: string) {
const values: any[] = Array.isArray(value) ? value : [value];
values.forEach(val => {
if (!val) return;
warning(
!moment.isMoment(val) || val.isValid(),
'DatePicker',
`\`${propName}\` provides invalidate moment time. If you want to set empty value, use \`null\` instead.`,
);
});
}
export default function wrapPicker(Picker: React.ComponentClass<any>, pickerType: PickerType): any { export default function wrapPicker(Picker: React.ComponentClass<any>, pickerType: PickerType): any {
return class PickerWrapper extends React.Component<any, any> { class PickerWrapper extends React.Component<any, any> {
static defaultProps = { static defaultProps = {
transitionName: 'slide-up', transitionName: 'slide-up',
popupStyle: {}, popupStyle: {},
@ -54,6 +70,15 @@ export default function wrapPicker(Picker: React.ComponentClass<any>, pickerType
locale: {}, locale: {},
}; };
static getDerivedStateFromProps({ value, defaultValue }: any) {
checkValidate(defaultValue, 'defaultValue');
checkValidate(value, 'value');
return {};
}
// Since we need call `getDerivedStateFromProps` for check. Need leave an empty `state` here.
state = {};
private picker: any; private picker: any;
componentDidMount() { componentDidMount() {
@ -199,5 +224,8 @@ export default function wrapPicker(Picker: React.ComponentClass<any>, pickerType
</LocaleReceiver> </LocaleReceiver>
); );
} }
}; }
polyfill(PickerWrapper);
return PickerWrapper;
} }

View File

@ -304,8 +304,7 @@ export default class FormItem extends React.Component<FormItemProps, any> {
// Resolve duplicated ids bug between different forms // Resolve duplicated ids bug between different forms
// https://github.com/ant-design/ant-design/issues/7351 // https://github.com/ant-design/ant-design/issues/7351
onLabelClick = (e: any) => { onLabelClick = () => {
const { label } = this.props;
const id = this.props.id || this.getId(); const id = this.props.id || this.getId();
if (!id) { if (!id) {
return; return;
@ -313,17 +312,8 @@ export default class FormItem extends React.Component<FormItemProps, any> {
const formItemNode = ReactDOM.findDOMNode(this) as Element; const formItemNode = ReactDOM.findDOMNode(this) as Element;
const control = formItemNode.querySelector(`[id="${id}"]`) as HTMLElement; const control = formItemNode.querySelector(`[id="${id}"]`) as HTMLElement;
if (control && control.focus) {
if (control) { control.focus();
// Only prevent in default situation
// Avoid preventing event in `label={<a href="xx">link</a>}``
if (typeof label === 'string') {
e.preventDefault();
}
if (control.focus) {
control.focus();
}
} }
}; };

View File

@ -9,10 +9,6 @@ Semantic vector graphics.
## List of icons ## List of icons
> Click the icon and copy the code.
We are still adding two-tone icons right now.
```__react ```__react
import IconDisplay from 'site/theme/template/IconDisplay'; import IconDisplay from 'site/theme/template/IconDisplay';
ReactDOM.render(<IconDisplay />, mountNode); ReactDOM.render(<IconDisplay />, mountNode);

View File

@ -14,10 +14,6 @@ toc: false
## 图标列表 ## 图标列表
> 点击图标即可复制代码。
新版图标可能略有缺失,我们还在持续补充中。
```__react ```__react
import IconDisplay from 'site/theme/template/IconDisplay'; import IconDisplay from 'site/theme/template/IconDisplay';
ReactDOM.render(<IconDisplay />, mountNode); ReactDOM.render(<IconDisplay />, mountNode);

View File

@ -218,8 +218,14 @@
position: absolute; position: absolute;
width: 6px; width: 6px;
height: 1.5px; height: 1.5px;
// background + background-image to makes before & after cross have same color.
// Since `linear-gradient` not work on IE9, we should hack it.
// ref: https://github.com/ant-design/ant-design/issues/15910
background: @menu-bg; background: @menu-bg;
background: ~'@{menu-item-color} \9';
background-image: linear-gradient(to right, @menu-item-color, @menu-item-color); background-image: linear-gradient(to right, @menu-item-color, @menu-item-color);
background-image: ~'none \9';
border-radius: 2px; border-radius: 2px;
transition: background 0.3s @ease-in-out, transform 0.3s @ease-in-out, transition: background 0.3s @ease-in-out, transform 0.3s @ease-in-out,
top 0.3s @ease-in-out; top 0.3s @ease-in-out;

View File

@ -18,6 +18,9 @@
"contributors": [ "contributors": [
"ant" "ant"
], ],
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/ant-design/ant-design" "url": "https://github.com/ant-design/ant-design"

View File

@ -104,7 +104,7 @@ module.exports = {
'app.publish.old-version-guide': 'If you need documentation of older version, please visit ', 'app.publish.old-version-guide': 'If you need documentation of older version, please visit ',
'app.publish.old-version-tips': ', or switch version with the select at header navigation.', 'app.publish.old-version-tips': ', or switch version with the select at header navigation.',
'app.docs.color.pick-primary': 'Pick your primary color', 'app.docs.color.pick-primary': 'Pick your primary color',
'app.docs.components.icon.pick-theme': 'Select the Icon Theme', 'app.docs.components.icon.search.placeholder': 'Search icon here, click icon to copy code',
'app.docs.components.icon.outlined': 'Outlined', 'app.docs.components.icon.outlined': 'Outlined',
'app.docs.components.icon.filled': 'Filled', 'app.docs.components.icon.filled': 'Filled',
'app.docs.components.icon.two-tone': 'Two Tone', 'app.docs.components.icon.two-tone': 'Two Tone',

View File

@ -18,11 +18,6 @@ interface IconDisplayState {
} }
class IconDisplay extends React.Component<IconDisplayProps, IconDisplayState> { class IconDisplay extends React.Component<IconDisplayProps, IconDisplayState> {
constructor(props: IconDisplayProps) {
super(props);
this.handleSearchIcon = debounce(this.handleSearchIcon, 300);
}
static categories: Categories = categories; static categories: Categories = categories;
static newIconNames: string[] = []; static newIconNames: string[] = [];
@ -38,6 +33,11 @@ class IconDisplay extends React.Component<IconDisplayProps, IconDisplayState> {
searchKey: '', searchKey: '',
}; };
constructor(props: IconDisplayProps) {
super(props);
this.handleSearchIcon = debounce(this.handleSearchIcon, 300);
}
getComputedDisplayList() { getComputedDisplayList() {
return Object.keys(IconDisplay.categories) return Object.keys(IconDisplay.categories)
.map((category: CategoriesKeys) => ({ .map((category: CategoriesKeys) => ({
@ -89,8 +89,7 @@ class IconDisplay extends React.Component<IconDisplayProps, IconDisplayState> {
} = this.props; } = this.props;
const list = this.getComputedDisplayList(); const list = this.getComputedDisplayList();
return ( return (
<div> <>
<h3>{messages['app.docs.components.icon.pick-theme']}</h3>
<div style={{ display: 'flex', justifyContent: 'space-between' }}> <div style={{ display: 'flex', justifyContent: 'space-between' }}>
<Radio.Group value={this.state.theme} onChange={this.handleChangeTheme} size="large"> <Radio.Group value={this.state.theme} onChange={this.handleChangeTheme} size="large">
<Radio.Button value="outlined"> <Radio.Button value="outlined">
@ -103,18 +102,17 @@ class IconDisplay extends React.Component<IconDisplayProps, IconDisplayState> {
<Icon component={TwoToneIcon} /> {messages['app.docs.components.icon.two-tone']} <Icon component={TwoToneIcon} /> {messages['app.docs.components.icon.two-tone']}
</Radio.Button> </Radio.Button>
</Radio.Group> </Radio.Group>
<Input.Search <Input.Search
placeholder="icon name" placeholder={messages['app.docs.components.icon.search.placeholder']}
style={{ marginLeft: 10, flex: 1 }} style={{ marginLeft: 10, flex: 1 }}
allowClear allowClear
onChange={e => this.handleSearchIcon(e.currentTarget.value)} onChange={e => this.handleSearchIcon(e.currentTarget.value)}
size="large" size="large"
autoFocus
/> />
</div> </div>
{this.renderCategories(list)} {this.renderCategories(list)}
</div> </>
); );
} }
} }

View File

@ -101,7 +101,7 @@ module.exports = {
'app.publish.old-version-guide': '如果您还需要使用旧版,请查阅 ', 'app.publish.old-version-guide': '如果您还需要使用旧版,请查阅 ',
'app.publish.old-version-tips': ',也可通过页面右上角的文档版本选择框进行切换。', 'app.publish.old-version-tips': ',也可通过页面右上角的文档版本选择框进行切换。',
'app.docs.color.pick-primary': '选择你的主色', 'app.docs.color.pick-primary': '选择你的主色',
'app.docs.components.icon.pick-theme': '选择图标主题风格', 'app.docs.components.icon.search.placeholder': '在此搜索图标,点击图标可复制代码',
'app.docs.components.icon.outlined': '线框风格', 'app.docs.components.icon.outlined': '线框风格',
'app.docs.components.icon.filled': '实底风格', 'app.docs.components.icon.filled': '实底风格',
'app.docs.components.icon.two-tone': '双色风格', 'app.docs.components.icon.two-tone': '双色风格',