merge master

This commit is contained in:
zombiej 2019-08-12 13:34:23 +08:00
commit 1cb346573c
63 changed files with 575 additions and 334 deletions

View File

@ -15,6 +15,31 @@ timeline: true
---
## 3.21.4
`2019-08-09`
- 🐞 Fix the problem that Dropdown.Button requires `title` props.
## 3.21.3
`2019-08-09`
- Timeline
- 🐞 Fix the problem that `content` content does not wrap when it is too long. [#18092](https://github.com/ant-design/ant-design/pull/18092) [@xrkffgg](https://github.com/xrkffgg)
- 🐞 Fixed inconsistency in styles in `alternate` and `right` modes and width overflow of `content`. [#18093](https://github.com/ant-design/ant-design/pull/18093) [@xrkffgg](https://github.com/xrkffgg)
- 🐞 Fix Tabs content with margin collapse with navigation. [#18112](https://github.com/ant-design/ant-design/pull/18112)
- 🐞 Fix Textarea `autosize` shows scrollbar after resize. [#18114](https://github.com/ant-design/ant-design/pull/18114)
- 🐞 Fix Tooltip not work correctly on `disabled` Checkbox. [#18138](https://github.com/ant-design/ant-design/pull/18138)
- 🐞 Fix a Button line-height align issue. [#18139](https://github.com/ant-design/ant-design/pull/18139)
- 🐞 Fix missing `blur` and `focus` methods on Mentions. [#18132](https://github.com/ant-design/ant-design/pull/18132) [@yoyo837](https://github.com/yoyo837)
- 🐞 Fix missing `title` on Button. [#18130](https://github.com/ant-design/ant-design/pull/18130) [@yoyo837](https://github.com/yoyo837)
- 🐞 Fix Upload throw File not defined in IE9. [#18115](https://github.com/ant-design/ant-design/pull/18115)
- 🐞 Fix Input clear icon not align correctly. [#18151](https://github.com/ant-design/ant-design/pull/18151)
- 🐞 Fix Card broken style when using Button as `actions`. [#18179](https://github.com/ant-design/ant-design/pull/18179)
- 🐞 Fix the problem that Modal.confirm can't set `getContainer`. [#18182](https://github.com/ant-design/ant-design/pull/18182)
- ⌨️ Improve Divider accessibility by adding role="separator". [#18116](https://github.com/ant-design/ant-design/pull/18116)
## 3.21.2
`2019-08-06`

View File

@ -15,6 +15,31 @@ timeline: true
---
## 3.21.4
`2019-08-09`
- 🐞 修复 Dropdown.Button 的 `title` 类型。
## 3.21.3
`2019-08-09`
- Timeline
- 🐞 修复 `content` 内容连续过长时不换行的问题。[#18092](https://github.com/ant-design/ant-design/pull/18092) [@xrkffgg](https://github.com/xrkffgg)
- 🐞 修复 `alternate``right` 模式下样式不一致和 `content` 的宽度溢出的问题。 [#18093](https://github.com/ant-design/ant-design/pull/18093) [@xrkffgg](https://github.com/xrkffgg)
- 🐞 修复 Tabs 内容带有 margin 时会与标题相互作用的问题。[#18112](https://github.com/ant-design/ant-design/pull/18112)
- 🐞 修复 Textarea `autosize` 在调整尺寸后仍然显示滚动条的问题。[#18114](https://github.com/ant-design/ant-design/pull/18114)
- 🐞 修复 Tooltip 在 `disabled` Checkbox 上不能正确工作的问题。[#18138](https://github.com/ant-design/ant-design/pull/18138)
- 🐞 修复 Button 的行高对齐问题。[#18139](https://github.com/ant-design/ant-design/pull/18139)
- 🐞 修复 Mentions 没有 `blur``focus` 方法的问题。[#18132](https://github.com/ant-design/ant-design/pull/18132) [@yoyo837](https://github.com/yoyo837)
- 🐞 修复 Button 无法设置 `title` 的问题。[#18130](https://github.com/ant-design/ant-design/pull/18130) [@yoyo837](https://github.com/yoyo837)
- 🐞 修复 Upload 在 IE9 下报 File 未定义的问题。[#18115](https://github.com/ant-design/ant-design/pull/18115)
- 🐞 修复 Input 清除图标不居中对齐的问题。[#18151](https://github.com/ant-design/ant-design/pull/18151)
- 🐞 修复 Card `actions` 内使用 Button 的样式问题。[#18179](https://github.com/ant-design/ant-design/pull/18179)
- 🐞 修复 Modal.confirm 无法设置 `getContainer` 的问题。[#18182](https://github.com/ant-design/ant-design/pull/18182)
- ⌨️ 增强 Divider 可访问性支持。[#18116](https://github.com/ant-design/ant-design/pull/18116)
## 3.21.2
`2019-08-06`

View File

@ -1,31 +1,11 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
export interface InputElementProps {
children: React.ReactElement<any>;
}
export default class InputElement extends React.Component<InputElementProps, any> {
private ele: HTMLInputElement;
focus = () => {
if (this.ele.focus) {
this.ele.focus();
} else {
(ReactDOM.findDOMNode(this.ele) as HTMLInputElement).focus();
}
};
blur = () => {
if (this.ele.blur) {
this.ele.blur();
} else {
(ReactDOM.findDOMNode(this.ele) as HTMLInputElement).blur();
}
};
saveRef = (ele: HTMLInputElement) => {
this.ele = ele;
const { ref: childRef } = this.props.children as any;
if (typeof childRef === 'function') {
childRef(ele);

View File

@ -52,4 +52,29 @@ describe('AutoComplete children could be focus', () => {
jest.runAllTimers();
expect(handleBlur).toHaveBeenCalled();
});
it('child.ref should work', () => {
const mockRef = jest.fn();
mount(
<AutoComplete dataSource={[]}>
<input ref={mockRef} />
</AutoComplete>,
);
expect(mockRef).toHaveBeenCalled();
});
it('child.ref instance should support be focused and blured', () => {
let inputRef;
mount(
<AutoComplete dataSource={[]}>
<input
ref={node => {
inputRef = node;
}}
/>
</AutoComplete>,
);
expect(typeof inputRef.focus).toBe('function');
expect(typeof inputRef.blur).toBe('function');
});
});

View File

@ -23,13 +23,35 @@ describe('AutoComplete with Custom Input Element Render', () => {
expect(dropdownWrapper.find('MenuItem').length).toBe(3);
});
it('child.ref should work', () => {
const mockRef = jest.fn();
mount(
<AutoComplete dataSource={[]}>
<input ref={mockRef} />
it('AutoComplete should work when dataSource is object array', () => {
const wrapper = mount(
<AutoComplete dataSource={[{ text: 'text', value: 'value' }, { text: 'abc', value: 'xxx' }]}>
<input />
</AutoComplete>,
);
expect(mockRef).toHaveBeenCalled();
expect(wrapper.find('input').length).toBe(1);
wrapper.find('input').simulate('change', { target: { value: 'a' } });
const dropdownWrapper = mount(
wrapper
.find('Trigger')
.instance()
.getComponent(),
);
// should not filter data source defaultly
expect(dropdownWrapper.find('MenuItem').length).toBe(2);
});
it('AutoComplete throws error when contains invalid dataSource', () => {
jest.spyOn(console, 'error').mockImplementation(() => undefined);
expect(() => {
mount(
<AutoComplete dataSource={[() => {}]}>
<textarea />
</AutoComplete>,
);
}).toThrow();
// eslint-disable-next-line no-console
console.error.mockRestore();
});
});

View File

@ -23,8 +23,8 @@ const dataSource = ['12345', '23456', '34567'];
| allowClear | Show clear button, effective in multiple mode only. | boolean | false | |
| autoFocus | get focus when component mounted | boolean | false | |
| backfill | backfill selected item the input when using keyboard | boolean | false | |
| children (for customize input element) | customize input element | HTMLInputElement / HTMLTextAreaElement / React.ReactElement<InputProps> | `<Input />` | |
| children (for dataSource) | Data source for autocomplete | React.ReactElement<OptionProps> / Array&lt;React.ReactElement<OptionProps>> | - | |
| children (for customize input element) | customize input element | HTMLInputElement <br /><br /> HTMLTextAreaElement <br /><br /> `React.ReactElement<InputProps>` | `<Input />` | |
| children (for dataSource) | Data source to auto complete | `React.ReactElement<OptionProps>` <br /><br /> `Array<React.ReactElement<OptionProps>>` | - | |
| dataSource | Data source for autocomplete | [DataSourceItemType](https://git.io/vMMKF)\[] | - | |
| defaultActiveFirstOption | Whether active first option by default | boolean | true | |
| defaultValue | Initial selected option. | string\|string\[] | - | |

View File

@ -24,8 +24,8 @@ const dataSource = ['12345', '23456', '34567'];
| allowClear | 支持清除, 单选模式有效 | boolean | false | |
| autoFocus | 自动获取焦点 | boolean | false | |
| backfill | 使用键盘选择选项的时候把选中项回填到输入框中 | boolean | false | |
| children (自动完成的数据源) | 自动完成的数据源 | React.ReactElement<OptionProps> / Array&lt;React.ReactElement<OptionProps>> | - | | |
| children (自定义输入框) | 自定义输入框 | HTMLInputElement / HTMLTextAreaElement / React.ReactElement<InputProps> | `<Input />` | @todo.muyu |
| children (自定义输入框) | 自定义输入框 | HTMLInputElement <br /><br /> HTMLTextAreaElement <br /><br /> `React.ReactElement<InputProps>` | `<Input />` | |
| children (自动完成的数据源) | 自动完成的数据源 | `React.ReactElement<OptionProps>` <br /><br /> `Array<React.ReactElement<OptionProps>>` | - | |
| dataSource | 自动完成的数据源 | [DataSourceItemType](https://git.io/vMMKF)\[] | | |
| defaultActiveFirstOption | 是否默认高亮第一个选项。 | boolean | true | |
| defaultValue | 指定默认选中的条目 | string\|string\[]\| 无 | |

View File

@ -131,6 +131,7 @@ class Button extends React.Component<ButtonProps, ButtonState> {
className: PropTypes.string,
icon: PropTypes.string,
block: PropTypes.bool,
title: PropTypes.string,
};
static getDerivedStateFromProps(nextProps: ButtonProps, prevState: ButtonState) {
@ -270,7 +271,7 @@ class Button extends React.Component<ButtonProps, ButtonState> {
? spaceChildren(children, this.isNeedInserted() && autoInsertSpace)
: null;
const linkButtonRestProps = omit(rest as AnchorButtonProps, ['htmlType']);
const linkButtonRestProps = omit(rest as AnchorButtonProps, ['htmlType', 'loading']);
if (linkButtonRestProps.href !== undefined) {
return (
<a

View File

@ -11,7 +11,7 @@ title:
## en-US
`ghost` property will make button's background transparent, it is common used in colored background.
`ghost` property will make button's background transparent, it is commonly used in colored background.
```jsx
import { Button } from 'antd';

View File

@ -12,10 +12,7 @@
// Button styles
// -----------------------------
.@{btn-prefix-cls} {
// Fixing https://github.com/ant-design/ant-design/issues/12978
// It is a render problem of chrome, which is only happened in the codesandbox demo
// 0.001px solution works and I don't why
line-height: @line-height-base - 0.001;
line-height: @line-height-base;
.btn;
.btn-default;
@ -196,7 +193,12 @@
}
a.@{btn-prefix-cls} {
// Fixing https://github.com/ant-design/ant-design/issues/12978
// It is a render problem of chrome, which is only happened in the codesandbox demo
// 0.1px for padding-top solution works and I don't why
padding-top: 0.1px;
line-height: @btn-height-base - 2px;
&-lg {
line-height: @btn-height-lg - 2px;
}

View File

@ -4,6 +4,7 @@
@card-prefix-cls: ~'@{ant-prefix}-card';
@card-head-height: 48px;
@card-hover-border: fade(@black, 9%);
@card-action-icon-size: 16px;
@gradient-min: fade(@card-background, 20%);
@gradient-max: fade(@card-background, 40%);
@ -137,7 +138,7 @@
color: @text-color-secondary;
text-align: center;
& > span {
> span {
position: relative;
display: block;
min-width: 32px;
@ -150,23 +151,23 @@
transition: color 0.3s;
}
& > .anticon {
font-size: 16px;
line-height: 22px;
}
a,
i {
> .anticon {
display: inline-block;
width: 100%;
color: @text-color-secondary;
line-height: 22px;
transition: color 0.3s;
&:hover {
color: @primary-color;
transition: color 0.3s;
}
}
> .anticon {
font-size: @card-action-icon-size;
line-height: 22px;
}
}
&:not(:last-child) {

View File

@ -496,7 +496,7 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
]);
let { options } = props;
if (options.length > 0) {
if (options && options.length > 0) {
if (state.inputValue) {
options = this.generateFilteredOptions(prefixCls, renderEmpty);
}

View File

@ -46,6 +46,8 @@ export interface CheckboxChangeEvent {
class Checkbox extends React.Component<CheckboxProps, {}> {
static Group: typeof CheckboxGroup;
static __ANT_CHECKBOX = true;
static defaultProps = {
indeterminate: false,
};

View File

@ -6750,18 +6750,21 @@ exports[`ConfigProvider components DatePicker WeekPicker prefixCls 1`] = `
exports[`ConfigProvider components Divider configProvider 1`] = `
<div
class="config-divider config-divider-horizontal"
role="separator"
/>
`;
exports[`ConfigProvider components Divider normal 1`] = `
<div
class="ant-divider ant-divider-horizontal"
role="separator"
/>
`;
exports[`ConfigProvider components Divider prefixCls 1`] = `
<div
class="prefix-Divider prefix-Divider-horizontal"
role="separator"
/>
`;

View File

@ -56,7 +56,7 @@ export interface DatePickerProps extends PickerProps, SinglePickerProps {
}
export interface MonthPickerProps extends PickerProps, SinglePickerProps {
// - currently no own props -
monthCellContentRender?: (date: moment.Moment, locale: any) => React.ReactNode;
}
export type RangePickerValue =

View File

@ -4,18 +4,22 @@ exports[`renders ./components/divider/demo/customize-style.md correctly 1`] = `
<div>
<div
class="ant-divider ant-divider-horizontal"
role="separator"
style="height:2px;background-color:#7cb305"
/>
<div
class="ant-divider ant-divider-horizontal ant-divider-dashed"
role="separator"
style="border-color:#7cb305"
/>
<div
class="ant-divider ant-divider-vertical"
role="separator"
style="height:60px;background-color:#7cb305"
/>
<div
class="ant-divider ant-divider-vertical ant-divider-dashed"
role="separator"
style="height:60px;border-color:#7cb305"
/>
</div>
@ -28,12 +32,14 @@ exports[`renders ./components/divider/demo/horizontal.md correctly 1`] = `
</p>
<div
class="ant-divider ant-divider-horizontal"
role="separator"
/>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae sunt a te dicta? Refert tamen, quo modo.
</p>
<div
class="ant-divider ant-divider-horizontal ant-divider-dashed"
role="separator"
/>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae sunt a te dicta? Refert tamen, quo modo.
@ -46,6 +52,7 @@ exports[`renders ./components/divider/demo/vertical.md correctly 1`] = `
Text
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="#"
@ -54,6 +61,7 @@ exports[`renders ./components/divider/demo/vertical.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="#"
@ -70,6 +78,7 @@ exports[`renders ./components/divider/demo/with-text.md correctly 1`] = `
</p>
<div
class="ant-divider ant-divider-horizontal ant-divider-with-text-center"
role="separator"
>
<span
class="ant-divider-inner-text"
@ -82,6 +91,7 @@ exports[`renders ./components/divider/demo/with-text.md correctly 1`] = `
</p>
<div
class="ant-divider ant-divider-horizontal ant-divider-with-text-left"
role="separator"
>
<span
class="ant-divider-inner-text"
@ -94,6 +104,7 @@ exports[`renders ./components/divider/demo/with-text.md correctly 1`] = `
</p>
<div
class="ant-divider ant-divider-horizontal ant-divider-with-text-right"
role="separator"
>
<span
class="ant-divider-inner-text"

View File

@ -31,7 +31,7 @@ const Divider: React.SFC<DividerProps> = props => (
[`${prefixCls}-dashed`]: !!dashed,
});
return (
<div className={classString} {...restProps}>
<div className={classString} {...restProps} role="separator">
{children && <span className={`${prefixCls}-inner-text`}>{children}</span>}
</div>
);

View File

@ -156,6 +156,69 @@ exports[`renders ./components/drawer/demo/placement.md correctly 1`] = `
</div>
`;
exports[`renders ./components/drawer/demo/render-in-current.md correctly 1`] = `
<div
style="height:200px;overflow:hidden;position:relative;border:1px solid #ebedf0;border-radius:2px;padding:48px;text-align:center;background:#fafafa"
>
Render in this
<div
style="margin-top:16px"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open
</span>
</button>
</div>
<div
class=""
>
<div
class="ant-drawer ant-drawer-right"
style="position:absolute"
tabindex="-1"
>
<div
class="ant-drawer-mask"
/>
<div
class="ant-drawer-content-wrapper"
style="transform:translateX(100%);-ms-transform:translateX(100%);width:256px"
>
<div
class="ant-drawer-content"
>
<div
class="ant-drawer-wrapper-body"
style="overflow:auto;height:100%"
>
<div
class="ant-drawer-header"
>
<div
class="ant-drawer-title"
>
Basic Drawer
</div>
</div>
<div
class="ant-drawer-body"
>
<p>
Some contents...
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/drawer/demo/user-profile.md correctly 1`] = `
<div>
<div

View File

@ -0,0 +1,71 @@
---
order: 2
title:
zh-CN: 渲染在当前 DOM
en-US: Render in current dom
---
## zh-CN
渲染在当前 dom 里。自定义容器,查看 getContainer。
## en-US
Render in current dom. custom container, check getContainer.
```jsx
import { Drawer, Button } from 'antd';
class App extends React.Component {
state = { visible: false };
showDrawer = () => {
this.setState({
visible: true,
});
};
onClose = () => {
this.setState({
visible: false,
});
};
render() {
return (
<div
style={{
height: 200,
overflow: 'hidden',
position: 'relative',
border: '1px solid #ebedf0',
borderRadius: 2,
padding: 48,
textAlign: 'center',
background: '#fafafa',
}}
>
Render in this
<div style={{ marginTop: 16 }}>
<Button type="primary" onClick={this.showDrawer}>
Open
</Button>
</div>
<Drawer
title="Basic Drawer"
placement="right"
closable={false}
onClose={this.onClose}
visible={this.state.visible}
getContainer={false}
style={{ position: 'absolute' }}
>
<p>Some contents...</p>
</Drawer>
</div>
);
}
}
ReactDOM.render(<App />, mountNode);
```

View File

@ -11,14 +11,15 @@
z-index: @zindex-modal;
width: 0%;
height: 100%;
transition: transform @animation-duration-slow @ease-base-out;
transition: transform @animation-duration-slow @ease-base-out,
height 0s ease @animation-duration-slow, width 0s ease @animation-duration-slow;
> * {
transition: transform @animation-duration-slow @ease-base-out,
box-shadow @animation-duration-slow @ease-base-out;
}
&-content-wrapper {
position: fixed;
position: absolute;
}
.@{drawer-prefix-cls}-content {
width: 100%;
@ -35,6 +36,7 @@
}
&.@{drawer-prefix-cls}-open {
width: 100%;
transition: transform @animation-duration-slow @ease-base-out;
}
&.@{drawer-prefix-cls}-open.no-mask {
width: 0%;
@ -75,6 +77,7 @@
}
&.@{drawer-prefix-cls}-open {
height: 100%;
transition: transform @animation-duration-slow @ease-base-out;
}
&.@{drawer-prefix-cls}-open.no-mask {
height: 0%;
@ -186,7 +189,7 @@
}
&-mask {
position: fixed;
position: absolute;
top: 0;
left: 0;
width: 100%;

View File

@ -22,6 +22,7 @@ export interface DropdownButtonProps extends ButtonGroupProps, DropDownProps {
icon?: React.ReactNode;
href?: string;
children?: React.ReactNode;
title?: string;
}
export default class DropdownButton extends React.Component<DropdownButtonProps, any> {
@ -51,6 +52,7 @@ export default class DropdownButton extends React.Component<DropdownButtonProps,
getPopupContainer,
href,
icon = <Icon type="ellipsis" />,
title,
...restProps
} = this.props;
@ -70,7 +72,14 @@ export default class DropdownButton extends React.Component<DropdownButtonProps,
return (
<ButtonGroup {...restProps} className={classNames(prefixCls, className)}>
<Button type={type} disabled={disabled} onClick={onClick} htmlType={htmlType} href={href}>
<Button
type={type}
disabled={disabled}
onClick={onClick}
htmlType={htmlType}
href={href}
title={title}
>
{children}
</Button>
<Dropdown {...dropdownProps}>

View File

@ -91,6 +91,7 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
</button>
<div
class="ant-divider ant-divider-horizontal"
role="separator"
/>
<div
class="config-provider"

View File

@ -1207,7 +1207,7 @@ exports[`renders ./components/form/demo/global-state.md correctly 1`] = `
</div>
`;
exports[`renders ./components/form/demo/horizontal-login.md correctly 1`] = `
exports[`renders ./components/form/demo/inline-login.md correctly 1`] = `
<form
class="ant-form ant-form-inline"
id="horizontal_login"

View File

@ -1,17 +1,17 @@
---
order: 10
title:
zh-CN: 水平登录栏
en-US: Horizontal Login Form
zh-CN: 内联登录栏
en-US: Inline Login Form
---
## zh-CN
水平登录栏,常用在顶部导航栏中。
内联登录栏,常用在顶部导航栏中。
## en-US
Horizontal login form is often used in navigation bar.
Inline login form is often used in navigation bar.
```tsx
import { Form, Icon, Input, Button } from 'antd';

View File

@ -44,7 +44,9 @@
.@{ant-prefix}-input-clear-icon {
color: @disabled-color;
font-size: @font-size-sm;
vertical-align: top;
// https://github.com/ant-design/ant-design/pull/18151
// https://codesandbox.io/s/wizardly-sun-u10br
vertical-align: 0;
cursor: pointer;
transition: color 0.3s;

View File

@ -1,6 +1,7 @@
import React from 'react';
import { mount } from 'enzyme';
import Mentions from '..';
import focusTest from '../../../tests/shared/focusTest';
const { getMentions } = Mentions;
@ -71,6 +72,8 @@ describe('Mentions', () => {
expect(onBlur).toHaveBeenCalled();
});
focusTest(Mentions);
it('loading', () => {
const wrapper = mount(<Mentions loading />);
simulateInput(wrapper, '@');

View File

@ -75,6 +75,8 @@ class Mentions extends React.Component<MentionProps, MentionState> {
focused: false,
};
private rcMentions: any;
onFocus: React.FocusEventHandler<HTMLTextAreaElement> = (...args) => {
const { onFocus } = this.props;
if (onFocus) {
@ -125,6 +127,18 @@ class Mentions extends React.Component<MentionProps, MentionState> {
return filterOption;
};
saveMentions = (node: typeof RcMentions) => {
this.rcMentions = node;
};
focus() {
this.rcMentions.focus();
}
blur() {
this.rcMentions.blur();
}
renderMentions = ({ getPrefixCls, renderEmpty }: ConfigConsumerProps) => {
const { focused } = this.state;
const { prefixCls: customizePrefixCls, className, disabled, ...restProps } = this.props;
@ -146,6 +160,7 @@ class Mentions extends React.Component<MentionProps, MentionState> {
filterOption={this.getFilterOption()}
onFocus={this.onFocus}
onBlur={this.onBlur}
ref={this.saveMentions}
>
{this.getOptions()}
</RcMentions>

View File

@ -139,7 +139,7 @@ export default function confirm(config: ModalFuncProps) {
}
function render(props: any) {
ReactDOM.render(<ConfirmDialog {...props} getContainer={false} />, div);
ReactDOM.render(<ConfirmDialog getContainer={false} {...props} />, div);
}
function close(...args: any[]) {

View File

@ -36,6 +36,7 @@ exports[`renders ./components/page-header/demo/actions.md correctly 1`] = `
</div>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
</div>
<div
@ -445,6 +446,7 @@ exports[`renders ./components/page-header/demo/basic.md correctly 1`] = `
</div>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
</div>
<div

View File

@ -31,7 +31,7 @@ A long list can be divided into several pages by `Pagination`, and only one page
| showLessItems | show less page items | boolean | false | 3.16.3 |
| showQuickJumper | determine whether you can jump to pages directly | boolean \| `{ goButton: ReactNode }` | false | |
| showSizeChanger | determine whether `pageSize` can be changed | boolean | false | |
| showTitle | show page items title | boolean | true | 3.19.3 |
| showTitle | show page items title | boolean | true | |
| showTotal | to display the total number and range | Function(total, range) | - | |
| simple | whether to use simple mode | boolean | - | |
| size | specify the size of `Pagination`, can be set to `small` | string | "" | |

View File

@ -24,7 +24,7 @@ cols: 1
| current | 当前页数 | number | - | |
| defaultCurrent | 默认的当前页数 | number | 1 | |
| defaultPageSize | 默认的每页条数 | number | 10 | |
| disabled | 禁用分页 | boolean | - | 3.10.0 | 3.18.0 |
| disabled | 禁用分页 | boolean | - | 3.18.0 |
| hideOnSinglePage | 只有一页时是否隐藏分页器 | boolean | false | 3.1.0 |
| itemRender | 用于自定义页码的结构,可用于优化 SEO | (page, type: 'page' \| 'prev' \| 'next', originalElement) => React.ReactNode | - | |
| pageSize | 每页条数 | number | - | |

View File

@ -104,6 +104,7 @@ exports[`renders ./components/steps/demo/clickable.md correctly 1`] = `
</div>
<div
class="ant-divider ant-divider-horizontal"
role="separator"
/>
<div
class="ant-steps ant-steps-vertical"

View File

@ -397,6 +397,7 @@ exports[`renders ./components/table/demo/basic.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -451,6 +452,7 @@ exports[`renders ./components/table/demo/basic.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -510,6 +512,7 @@ exports[`renders ./components/table/demo/basic.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -2540,6 +2543,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -2548,6 +2552,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
class="ant-dropdown-link"
@ -2642,6 +2647,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -2650,6 +2656,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
class="ant-dropdown-link"
@ -2744,6 +2751,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -2752,6 +2760,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
class="ant-dropdown-link"
@ -2846,6 +2855,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -2854,6 +2864,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
class="ant-dropdown-link"
@ -2948,6 +2959,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -2956,6 +2968,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
class="ant-dropdown-link"
@ -3050,6 +3063,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -3058,6 +3072,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
class="ant-dropdown-link"
@ -3152,6 +3167,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -3160,6 +3176,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
class="ant-dropdown-link"
@ -3254,6 +3271,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -3262,6 +3280,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
class="ant-dropdown-link"
@ -3356,6 +3375,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -3364,6 +3384,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
class="ant-dropdown-link"
@ -3458,6 +3479,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -3466,6 +3488,7 @@ exports[`renders ./components/table/demo/dynamic-settings.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
class="ant-dropdown-link"
@ -10445,6 +10468,7 @@ exports[`renders ./components/table/demo/jsx.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -10500,6 +10524,7 @@ exports[`renders ./components/table/demo/jsx.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"
@ -10560,6 +10585,7 @@ exports[`renders ./components/table/demo/jsx.md correctly 1`] = `
</a>
<div
class="ant-divider ant-divider-vertical"
role="separator"
/>
<a
href="javascript:;"

View File

@ -11,7 +11,7 @@ title:
## en-US
Another type Tabs, which doesn't support vertical mode.
Another type of Tabs, which doesn't support vertical mode.
```jsx
import { Tabs } from 'antd';

View File

@ -11,7 +11,7 @@ title:
## en-US
use react-sticky.
Use react-sticky.
```jsx
import { Tabs } from 'antd';

View File

@ -11,7 +11,7 @@ title:
## en-US
Large size tabs are usally used in page header, and small size could be used in Modal.
Large size tabs are usually used in page header, and small size could be used in Modal.
```jsx
import { Tabs, Radio } from 'antd';

View File

@ -242,10 +242,10 @@
}
}
// Create a empty element to aovid margin merge
// Create an empty element to avoid margin collapsing
// https://github.com/ant-design/ant-design/issues/18103
&-content::before {
display: inline-block;
display: table;
content: '';
}

View File

@ -13,6 +13,31 @@ exports[`Tooltip should hide when mouse leave antd disabled component Button 1`]
</span>
`;
exports[`Tooltip should hide when mouse leave antd disabled component Checkbox 1`] = `
<span
style="display: inline-block; cursor: not-allowed;"
>
<label
class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled"
style="pointer-events: none;"
>
<span
class="ant-checkbox ant-checkbox-disabled"
>
<input
class="ant-checkbox-input"
disabled=""
type="checkbox"
value=""
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
</span>
`;
exports[`Tooltip should hide when mouse leave antd disabled component Switch 1`] = `
<span
style="display: inline-block; cursor: not-allowed;"

View File

@ -3,6 +3,7 @@ import { mount } from 'enzyme';
import Tooltip from '..';
import Button from '../../button';
import Switch from '../../switch';
import Checkbox from '../../checkbox';
import DatePicker from '../../date-picker';
import Input from '../../input';
import Group from '../../input/Group';
@ -107,6 +108,7 @@ describe('Tooltip', () => {
testComponent('Button', Button);
testComponent('Switch', Switch);
testComponent('Checkbox', Checkbox);
});
it('should render disabled Button style properly', () => {

View File

@ -87,7 +87,10 @@ const splitObject = (obj: any, keys: string[]) => {
function getDisabledCompatibleChildren(element: React.ReactElement<any>) {
const elementType = element.type as any;
if (
(elementType.__ANT_BUTTON || elementType.__ANT_SWITCH || element.type === 'button') &&
(elementType.__ANT_BUTTON ||
elementType.__ANT_SWITCH ||
elementType.__ANT_CHECKBOX ||
element.type === 'button') &&
element.props.disabled
) {
// Pick some layout related style properties up to span

View File

@ -82,6 +82,7 @@ exports[`renders ./components/typography/demo/basic.md correctly 1`] = `
</div>
<div
class="ant-divider ant-divider-horizontal"
role="separator"
/>
<h1
class="ant-typography"

View File

@ -4,7 +4,7 @@ import { UploadProps } from './interface';
export type DraggerProps = UploadProps & { height?: number };
const Dragger = (props: DraggerProps) => (
const Dragger: React.FC<DraggerProps> = props => (
<Upload {...props} type="drag" style={{ ...props.style, height: props.height }} />
);

View File

@ -26,15 +26,12 @@ export default class UploadList extends React.Component<UploadListProps, any> {
return;
}
(items || []).forEach(file => {
const isValidateFile =
file.originFileObj instanceof File || file.originFileObj instanceof Blob;
if (
typeof document === 'undefined' ||
typeof window === 'undefined' ||
!(window as any).FileReader ||
!(window as any).File ||
!isValidateFile ||
!(file.originFileObj instanceof File || file.originFileObj instanceof Blob) ||
file.thumbUrl !== undefined
) {
return;

View File

@ -3,7 +3,7 @@ order: 9
title: FAQ
---
Here are the frequently asked questions about Ant Design and antd that you should look up before you ask in the community or create new a issue. We also maintain a [FAQ issues label](http://u.ant.design/faq) for common github issues.
Here are the frequently asked questions about Ant Design and antd that you should look up before you ask in the community or create a new issue. We also maintain a [FAQ issues label](http://u.ant.design/faq) for common github issues.
---

View File

@ -27,7 +27,7 @@ return (
| 语言 | 文件名 |
| ---------------- | ------ |
| 阿拉伯 | ar_EG |
| 阿拉伯 | ar_EG |
| 保加利亚语 | bg_BG |
| 加泰罗尼亚语 | ca_ES |
| 捷克语 | cs_CZ |
@ -44,14 +44,14 @@ return (
| 希伯来语 | he_IL |
| 印地语 | hi_IN |
| 克罗地亚语 | hr_HR |
| 匈牙利 | hu_HU |
| 匈牙利 | hu_HU |
| 冰岛语 | is_IS |
| 印度尼西亚语 | id_ID |
| 意大利语 | it_IT |
| 日语 | ja_JP |
| 卡纳达语 | kn_IN |
| 韩语/朝鲜语 | ko_KR |
| 挪威 | nb_NO |
| 挪威 | nb_NO |
| 尼泊尔语 | ne_NP |
| 荷兰语(比利时) | nl_BE |
| 荷兰语 | nl_NL |
@ -59,10 +59,10 @@ return (
| 葡萄牙语(巴西) | pt_BR |
| 葡萄牙语 | pt_PT |
| 斯洛伐克语 | sk_SK |
| 塞尔维亚 | sr_RS |
| 斯洛文尼亚 | sl_SI |
| 塞尔维亚 | sr_RS |
| 斯洛文尼亚 | sl_SI |
| 瑞典语 | sv_SE |
| 泰米尔 | ta_IN |
| 泰米尔 | ta_IN |
| 泰语 | th_TH |
| 土耳其语 | tr_TR |
| 俄罗斯语 | ru_RU |

View File

@ -4,7 +4,7 @@ order: 7
title: Keep it Lightweight
---
Fitts's Law is an ergonomic principle that ties the size of a target and its contextual proximity to ease of use.In other words, if a tool is close at hand and large enough to target, then we can improve the user's interaction. Putting tools in context makes for lightweight interaction.
Fitts's Law is an ergonomic principle that ties the size of a target and its contextual proximity to ease of use. In other words, if a tool is close at hand and large enough to target, then we can improve the user's interaction. Putting tools in context makes for lightweight interaction.
> <img src="https://os.alipayobjects.com/rmsportal/wAcbQmeqTWDqsnu.png" width="150" />
> ** Fitts's Law **: The time to acquire a target is a function of the distance to and size of the target. It is proportional to the distance to the target and inversely proportional to the width of the target.

View File

@ -1,6 +1,6 @@
{
"name": "antd",
"version": "4.0.0-alpha.0",
"version": "4.0.0-alpha.1",
"title": "Ant Design",
"description": "An enterprise-class UI design language and React components implementation",
"homepage": "http://ant.design/",
@ -99,14 +99,13 @@
},
"devDependencies": {
"@ant-design/colors": "^3.1.0",
"@ant-design/tools": "^8.0.0",
"@ant-design/tools": "^8.0.4",
"@packtracker/webpack-plugin": "^2.0.1",
"@sentry/browser": "^5.4.0",
"@types/classnames": "^2.2.8",
"@types/prop-types": "^15.7.1",
"@types/react": "~16.9.1",
"@types/react-dom": "^16.8.4",
"@types/react-intl": "^2.3.17",
"@types/warning": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^1.13.0",
"@typescript-eslint/parser": "^1.13.0",
@ -120,7 +119,6 @@
"bisheng-plugin-react": "^1.1.0",
"bisheng-plugin-toc": "^0.4.4",
"chalk": "^2.4.2",
"commander": "^2.20.0",
"cross-env": "^5.2.0",
"css-split-webpack-plugin": "^0.2.6",
"dekko": "^0.2.1",
@ -170,7 +168,7 @@
"react-github-button": "^0.1.11",
"react-highlight-words": "^0.16.0",
"react-infinite-scroller": "^1.2.4",
"react-intl": "^2.9.0",
"react-intl": "^3.1.1",
"react-resizable": "^1.8.0",
"react-router": "^3.2.3",
"react-router-dom": "^5.0.1",
@ -216,7 +214,7 @@
"tsc": "tsc",
"start": "rimraf _site && mkdir _site && node ./scripts/generateColorLess.js && cross-env NODE_ENV=development bisheng start -c ./site/bisheng.config.js",
"start:preact": "node ./scripts/generateColorLess.js && cross-env NODE_ENV=development REACT_ENV=preact bisheng start -c ./site/bisheng.config.js",
"site": "cross-env NODE_ENV=production bisheng build --ssr -c ./site/bisheng.config.js && node ./scripts/generateColorLess.js",
"site": "bisheng build --ssr -c ./site/bisheng.config.js && node ./scripts/generateColorLess.js",
"predeploy": "antd-tools run clean && npm run site && cp netlify.toml CNAME _site && cp .circleci/config.yml _site",
"deploy": "bisheng gh-pages --push-only",
"deploy:china-mirror": "git checkout gh-pages && git pull origin gh-pages && git push git@gitee.com:ant-design/ant-design.git gh-pages",
@ -244,4 +242,4 @@
"> 1%",
"ie >= 9"
]
}
}

View File

@ -125,6 +125,12 @@ module.exports = {
alertBabelConfig(config.module.rules);
config.module.rules.push({
test: /\.mjs$/,
include: /node_modules/,
type: 'javascript/auto',
});
config.plugins.push(new CSSSplitWebpackPlugin({ size: 4000 }));
return config;

View File

@ -1,8 +1,5 @@
const appLocaleData = require('react-intl/locale-data/en');
module.exports = {
locale: 'en-US',
data: appLocaleData,
messages: {
'app.header.search': 'Search...',
'app.header.menu.home': 'Home',

View File

@ -2,7 +2,6 @@ const path = require('path');
const homeTmpl = './template/Home/index';
const contentTmpl = './template/Content/index';
const redirectTmpl = './template/Redirect';
const appShellTmpl = './template/AppShell';
function pickerGenerator(module) {
@ -43,9 +42,7 @@ module.exports = {
}
return null;
},
'docs/pattern': pickerGenerator('pattern'),
'docs/react': pickerGenerator('react'),
'docs/resource': pickerGenerator('resource'),
'docs/spec': pickerGenerator('spec'),
},
plugins: [
@ -67,10 +64,6 @@ module.exports = {
path: 'index-cn',
component: homeTmpl,
},
{
path: 'docs/pattern/:children',
component: redirectTmpl,
},
{
path: 'docs/react/:children',
component: contentTmpl,
@ -95,22 +88,10 @@ module.exports = {
path: 'components/:children/',
component: contentTmpl,
},
{
path: 'docs/spec/feature',
component: redirectTmpl,
},
{
path: 'docs/spec/feature-cn',
component: redirectTmpl,
},
{
path: 'docs/spec/:children',
component: contentTmpl,
},
{
path: 'docs/resource/:children',
component: redirectTmpl,
},
],
},
};

View File

@ -23,7 +23,7 @@
}
</style>
<link rel="stylesheet/less" type="text/css" href="{{ root }}color.less" />
<script src="https://polyfill.alicdn.com/polyfill.min.js?features=default,es2015,matchMedia"></script>
<script src="https://polyfill.alicdn.com/polyfill.min.js?features=default,es2015,matchMedia,Intl"></script>
<script>
(function() {
function isLocalStorageNameSupported() {

View File

@ -1,16 +1,11 @@
import React, { Children, cloneElement } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { FormattedMessage, injectIntl } from 'react-intl';
import DocumentTitle from 'react-document-title';
import { getChildren } from 'jsonml.js/lib/utils';
import { Timeline, Alert, Affix } from 'antd';
import EditButton from './EditButton';
export default class Article extends React.Component {
static contextTypes = {
intl: PropTypes.object.isRequired,
};
class Article extends React.Component {
shouldComponentUpdate(nextProps) {
const { location } = this.props;
const { location: nextLocation } = nextProps;
@ -69,13 +64,13 @@ export default class Article extends React.Component {
}
render() {
const { props } = this;
const { content } = props;
const {
content,
intl: { locale },
utils,
} = this.props;
const { meta, description } = content;
const { title, subtitle, filename } = meta;
const {
intl: { locale },
} = this.context;
const isNotTranslated = locale === 'en-US' && typeof title === 'object';
return (
<DocumentTitle title={`${title[locale] || title} - Ant Design`}>
@ -104,22 +99,22 @@ export default class Article extends React.Component {
</h1>
{!description
? null
: props.utils.toReactComponent(
: utils.toReactComponent(
['section', { className: 'markdown' }].concat(getChildren(description)),
)}
{!content.toc || content.toc.length <= 1 || meta.toc === false ? null : (
<Affix className="toc-affix" offsetTop={16}>
{props.utils.toReactComponent(
{utils.toReactComponent(
['ul', { className: 'toc' }].concat(getChildren(content.toc)),
)}
</Affix>
)}
{this.getArticle(
props.utils.toReactComponent(
utils.toReactComponent(
['section', { className: 'markdown' }].concat(getChildren(content.content)),
),
)}
{props.utils.toReactComponent(
{utils.toReactComponent(
[
'section',
{
@ -132,3 +127,5 @@ export default class Article extends React.Component {
);
}
}
export default injectIntl(Article);

View File

@ -1,7 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import DocumentTitle from 'react-document-title';
import { FormattedMessage } from 'react-intl';
import { FormattedMessage, injectIntl } from 'react-intl';
import classNames from 'classnames';
import { Row, Col, Icon, Affix, Tooltip } from 'antd';
import { getChildren } from 'jsonml.js/lib/utils';
@ -9,11 +8,7 @@ import Demo from './Demo';
import EditButton from './EditButton';
import { ping } from '../utils';
export default class ComponentDoc extends React.Component {
static contextTypes = {
intl: PropTypes.object,
};
class ComponentDoc extends React.Component {
state = {
expandAll: false,
showRiddleButton: false,
@ -57,21 +52,23 @@ export default class ComponentDoc extends React.Component {
};
render() {
const { props } = this;
const { doc, location } = props;
const { content, meta } = doc;
const {
doc,
location,
intl: { locale },
} = this.context;
const demos = Object.keys(props.demos).map(key => props.demos[key]);
utils,
demos,
} = this.props;
const { content, meta } = doc;
const demoValues = Object.keys(demos).map(key => demos[key]);
const { expandAll, showRiddleButton } = this.state;
const isSingleCol = meta.cols === 1;
const leftChildren = [];
const rightChildren = [];
const showedDemo = demos.some(demo => demo.meta.only)
? demos.filter(demo => demo.meta.only)
: demos.filter(demo => demo.preview);
const showedDemo = demoValues.some(demo => demo.meta.only)
? demoValues.filter(demo => demo.meta.only)
: demoValues.filter(demo => demo.preview);
showedDemo
.sort((a, b) => a.meta.order - b.meta.order)
.forEach((demoData, index) => {
@ -79,7 +76,7 @@ export default class ComponentDoc extends React.Component {
<Demo
{...demoData}
key={demoData.meta.filename}
utils={props.utils}
utils={utils}
expand={expandAll}
location={location}
/>
@ -126,7 +123,7 @@ export default class ComponentDoc extends React.Component {
filename={filename}
/>
</h1>
{props.utils.toReactComponent(
{utils.toReactComponent(
['section', { className: 'markdown' }].concat(getChildren(content)),
)}
<h2>
@ -159,7 +156,7 @@ export default class ComponentDoc extends React.Component {
</Col>
)}
</Row>
{props.utils.toReactComponent(
{utils.toReactComponent(
[
'section',
{
@ -172,3 +169,5 @@ export default class ComponentDoc extends React.Component {
);
}
}
export default injectIntl(ComponentDoc);

View File

@ -1,8 +1,7 @@
/* eslint jsx-a11y/no-noninteractive-element-interactions: 0 */
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { FormattedMessage, injectIntl } from 'react-intl';
import CopyToClipboard from 'react-copy-to-clipboard';
import classNames from 'classnames';
import LZString from 'lz-string';
@ -19,11 +18,7 @@ function compress(string) {
.replace(/=+$/, ''); // Remove ending '='
}
export default class Demo extends React.Component {
static contextTypes = {
intl: PropTypes.object,
};
class Demo extends React.Component {
state = {
codeExpand: false,
copied: false,
@ -114,8 +109,10 @@ export default class Demo extends React.Component {
style,
highlightedStyle,
expand,
utils,
intl: { locale },
} = props;
const { copied } = state;
const { copied, copyTooltipVisible } = state;
if (!this.liveDemo) {
this.liveDemo = meta.iframe ? (
<BrowserFrame>
@ -125,17 +122,14 @@ export default class Demo extends React.Component {
preview(React, ReactDOM)
);
}
const codeExpand = state.codeExpand || expand;
const codeExpand = this.state.codeExpand || expand;
const codeBoxClass = classNames('code-box', {
expand: codeExpand,
'code-box-debug': meta.debug,
});
const {
intl: { locale },
} = this.context;
const localizedTitle = meta.title[locale] || meta.title;
const localizeIntro = content[locale] || content;
const introChildren = props.utils.toReactComponent(['div'].concat(localizeIntro));
const introChildren = utils.toReactComponent(['div'].concat(localizeIntro));
const highlightClass = classNames({
'highlight-wrapper': true,
@ -295,12 +289,12 @@ ${sourceCode.replace('mountNode', "document.getElementById('container')")}
</form>
<CopyToClipboard text={sourceCode} onCopy={() => this.handleCodeCopied(meta.id)}>
<Tooltip
visible={state.copyTooltipVisible}
visible={copyTooltipVisible}
onVisibleChange={this.onCopyTooltipVisibleChange}
title={<FormattedMessage id={`app.demo.${copied ? 'copied' : 'copy'}`} />}
>
<Icon
type={state.copied && state.copyTooltipVisible ? 'check' : 'snippets'}
type={copied && copyTooltipVisible ? 'check' : 'snippets'}
className="code-box-code-copy"
/>
</Tooltip>
@ -339,3 +333,5 @@ ${sourceCode.replace('mountNode', "document.getElementById('container')")}
);
}
}
export default injectIntl(Demo);

View File

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'bisheng/router';
import { Row, Col, Menu, Icon, Affix } from 'antd';
import { FormattedMessage } from 'react-intl';
import { FormattedMessage, injectIntl } from 'react-intl';
import classNames from 'classnames';
import get from 'lodash/get';
import MobileMenu from 'rc-drawer';
@ -14,13 +14,6 @@ import * as utils from '../utils';
const { SubMenu } = Menu;
function getActiveMenuItem(props) {
const { children } = props.params;
return (
(children && children.replace('-cn', '')) || props.location.pathname.replace(/(^\/|-cn$)/g, '')
);
}
function getModuleData(props) {
const { pathname } = props.location;
const moduleName = /^\/?components/.test(pathname)
@ -69,19 +62,14 @@ const getSubMenuTitle = menuItem => {
});
return (
<h4>
{menuItem.title === 'Components' ? (
<FormattedMessage id="app.header.menu.components" />
) : (
menuItem.title
)}
<FormattedMessage id="app.header.menu.components" />
<span className="menu-antd-components-count">{count}</span>
</h4>
);
};
export default class MainContent extends Component {
class MainContent extends Component {
static contextTypes = {
intl: PropTypes.object.isRequired,
isMobile: PropTypes.bool.isRequired,
};
@ -126,10 +114,10 @@ export default class MainContent extends Component {
}
getMenuItems(footerNavIcons = {}) {
const { themeConfig } = this.props;
const {
themeConfig,
intl: { locale },
} = this.context;
} = this.props;
const moduleData = getModuleData(this.props);
const menuItems = utils.getMenuItems(
moduleData,
@ -173,6 +161,16 @@ export default class MainContent extends Component {
return { prev, next };
}
getActiveMenuItem() {
const {
params: { children },
location,
} = this.props;
return (
(children && children.replace('-cn', '')) || location.pathname.replace(/(^\/|-cn$)/g, '')
);
}
handleMenuOpenChange = openKeys => {
this.setState({ openKeys });
};
@ -195,6 +193,9 @@ export default class MainContent extends Component {
if (this.scroller) {
this.scroller.destroy();
}
if (!document.querySelector('.markdown > h2, .code-box')) {
return;
}
require('intersection-observer'); // eslint-disable-line
const scrollama = require('scrollama'); // eslint-disable-line
this.scroller = scrollama();
@ -217,7 +218,7 @@ export default class MainContent extends Component {
generateMenuItem(isTop, item, { before = null, after = null }) {
const {
intl: { locale },
} = this.context;
} = this.props;
const key = fileNameToPath(item.filename);
if (!item.title) {
return null;
@ -280,19 +281,18 @@ export default class MainContent extends Component {
}
render() {
const { props } = this;
const { isMobile } = this.context;
const { openKeys } = this.state;
const activeMenuItem = getActiveMenuItem(props);
const { localizedPageData, demos } = this.props;
const activeMenuItem = this.getActiveMenuItem();
const menuItems = this.getMenuItems();
const menuItemsForFooterNav = this.getMenuItems({
before: <Icon className="footer-nav-icon-before" type="left" />,
after: <Icon className="footer-nav-icon-after" type="right" />,
});
const { prev, next } = this.getFooterNav(menuItemsForFooterNav, activeMenuItem);
const { localizedPageData } = props;
const mainContainerClass = classNames('main-container', {
'main-container-component': !!props.demos,
'main-container-component': !!demos,
});
const menuChild = (
<Menu
@ -329,10 +329,10 @@ export default class MainContent extends Component {
)}
<Col xxl={20} xl={19} lg={18} md={24} sm={24} xs={24}>
<section className={mainContainerClass}>
{props.demos ? (
<ComponentDoc {...props} doc={localizedPageData} demos={props.demos} />
{demos ? (
<ComponentDoc {...this.props} doc={localizedPageData} demos={demos} />
) : (
<Article {...props} content={localizedPageData} />
<Article {...this.props} content={localizedPageData} />
)}
</section>
<PrevAndNext prev={prev} next={next} />
@ -343,3 +343,5 @@ export default class MainContent extends Component {
);
}
}
export default injectIntl(MainContent);

View File

@ -1,10 +1,9 @@
import React from 'react';
import PropTypes from 'prop-types';
import TweenOne from 'rc-tween-one';
import QueueAnim from 'rc-queue-anim';
import ScrollParallax from 'rc-scroll-anim/lib/ScrollParallax';
import { Link } from 'bisheng/router';
import { FormattedMessage } from 'react-intl';
import { FormattedMessage, useIntl } from 'react-intl';
import GitHubButton from 'react-github-button';
import { Button } from 'antd';
import BannerImage from './BannerImage';
@ -16,96 +15,79 @@ const loop = {
repeat: -1,
};
class Banner extends React.PureComponent {
static contextTypes = {
intl: PropTypes.object.isRequired,
};
static propTypes = {
className: PropTypes.string,
};
static defaultProps = {
className: 'banner',
};
render() {
const { className, isMobile } = this.props;
const {
intl: { locale },
} = this.context;
const isZhCN = locale === 'zh-CN';
return (
<div className="home-page-wrapper banner-wrapper" id="banner">
<div className="banner-bg-wrapper">
<svg width="400px" height="576px" viewBox="0 0 400 576" fill="none">
<TweenOne component="g" animation={[{ opacity: 0, type: 'from' }, { ...loop, y: 15 }]}>
<ellipse cx="100" cy="100" rx="6" ry="6" stroke="#2F54EB" strokeWidth="1.6" />
</TweenOne>
<TweenOne component="g" animation={[{ opacity: 0, type: 'from' }, { ...loop, y: -15 }]}>
<g transform="translate(200 450)">
<g style={{ transformOrigin: '50% 50%', transform: 'rotate(-340deg)' }}>
<rect stroke="#FADB14" strokeWidth="1.6" width="9" height="9" />
</g>
const Banner = ({ isMobile }) => {
const { locale } = useIntl();
const isZhCN = locale === 'zh-CN';
return (
<div className="home-page-wrapper banner-wrapper" id="banner">
<div className="banner-bg-wrapper">
<svg width="400px" height="576px" viewBox="0 0 400 576" fill="none">
<TweenOne component="g" animation={[{ opacity: 0, type: 'from' }, { ...loop, y: 15 }]}>
<ellipse cx="100" cy="100" rx="6" ry="6" stroke="#2F54EB" strokeWidth="1.6" />
</TweenOne>
<TweenOne component="g" animation={[{ opacity: 0, type: 'from' }, { ...loop, y: -15 }]}>
<g transform="translate(200 450)">
<g style={{ transformOrigin: '50% 50%', transform: 'rotate(-340deg)' }}>
<rect stroke="#FADB14" strokeWidth="1.6" width="9" height="9" />
</g>
</TweenOne>
</svg>
<ScrollParallax
location="banner"
className="banner-bg"
animation={{ playScale: [1, 1.5], rotate: 0 }}
/>
</div>
<QueueAnim className={`${className} page`} type="alpha" delay={150}>
{isMobile && (
<div className="img-wrapper" key="image">
<BannerImage />
</div>
)}
<QueueAnim className="text-wrapper" key="text" type="bottom">
<h1 key="h1">Ant Design</h1>
<p key="p">
<FormattedMessage id="app.home.introduce" />
</p>
<div className="banner-btns" key="buttons">
<Link to={utils.getLocalizedPathname('/docs/react/introduce', isZhCN)}>
<Button type="primary" className="banner-btn components">
<FormattedMessage id="app.home.getting-started" />
</Button>
</Link>
<Link
to={utils.getLocalizedPathname('/docs/spec/introduce', isZhCN)}
style={{ marginLeft: 16 }}
>
<Button className="banner-btn language">
<FormattedMessage id="app.home.design-language" />
</Button>
</Link>
{!isMobile && (
<GitHubButton
style={{ marginLeft: 16 }}
key="github-button"
size="large"
type="stargazers"
namespace="ant-design"
repo="ant-design"
/>
)}
</div>
</QueueAnim>
{!isMobile && (
<div className="img-wrapper" key="image">
<ScrollParallax
location="banner"
component={BannerImage}
animation={{ playScale: [1, 1.5], y: 80 }}
/>
</div>
)}
</QueueAnim>
</g>
</TweenOne>
</svg>
<ScrollParallax
location="banner"
className="banner-bg"
animation={{ playScale: [1, 1.5], rotate: 0 }}
/>
</div>
);
}
}
<QueueAnim className="banner page" type="alpha" delay={150}>
{isMobile && (
<div className="img-wrapper" key="image">
<BannerImage />
</div>
)}
<QueueAnim className="text-wrapper" key="text" type="bottom">
<h1 key="h1">Ant Design</h1>
<p key="p">
<FormattedMessage id="app.home.introduce" />
</p>
<div className="banner-btns" key="buttons">
<Link to={utils.getLocalizedPathname('/docs/react/introduce', isZhCN)}>
<Button type="primary" className="banner-btn components">
<FormattedMessage id="app.home.getting-started" />
</Button>
</Link>
<Link
to={utils.getLocalizedPathname('/docs/spec/introduce', isZhCN)}
style={{ marginLeft: 16 }}
>
<Button className="banner-btn language">
<FormattedMessage id="app.home.design-language" />
</Button>
</Link>
{!isMobile && (
<GitHubButton
style={{ marginLeft: 16 }}
key="github-button"
size="large"
type="stargazers"
namespace="ant-design"
repo="ant-design"
/>
)}
</div>
</QueueAnim>
{!isMobile && (
<div className="img-wrapper" key="image">
<ScrollParallax
location="banner"
component={BannerImage}
animation={{ playScale: [1, 1.5], y: 80 }}
/>
</div>
)}
</QueueAnim>
</div>
);
};
export default Banner;

View File

@ -61,12 +61,12 @@ function getStyle() {
// eslint-disable-next-line react/prefer-stateless-function
class Home extends React.Component {
static contextTypes = {
intl: PropTypes.object.isRequired,
isMobile: PropTypes.bool.isRequired,
};
render() {
const { isMobile, intl } = this.context;
const { intl } = this.props;
const { isMobile } = this.context;
const childProps = { ...this.props, isMobile, locale: intl.locale };
return (
<DocumentTitle title={`Ant Design - ${intl.formatMessage({ id: 'app.home.slogan' })}`}>

View File

@ -2,14 +2,15 @@ import * as React from 'react';
import { message } from 'antd';
import { ThemeType } from '../../../../components/icon';
import CopyableIcon from './CopyableIcon';
import { injectIntl, InjectedIntlProps } from 'react-intl';
import { injectIntl } from 'react-intl';
import { CategoriesKeys } from './fields';
interface CategoryProps extends InjectedIntlProps {
interface CategoryProps {
title: CategoriesKeys;
icons: string[];
theme: ThemeType;
newIcons: string[];
intl: any;
}
interface CategoryState {

View File

@ -3,14 +3,16 @@ import manifest from '@ant-design/icons/lib/manifest';
import { ThemeType as ThemeFolderType } from '@ant-design/icons/lib/types';
import { Radio, Icon, Input } from 'antd';
import { RadioChangeEvent } from 'antd/es/radio/interface';
import { injectIntl, InjectedIntlProps } from 'react-intl';
import { injectIntl } from 'react-intl';
import debounce from 'lodash/debounce';
import Category from './Category';
import { FilledIcon, OutlinedIcon, TwoToneIcon } from './themeIcons';
import { categories, Categories, CategoriesKeys } from './fields';
import { ThemeType } from 'antd/es/icon';
interface IconDisplayProps extends InjectedIntlProps {}
interface IconDisplayProps {
intl: any;
}
interface IconDisplayState {
theme: ThemeType;

View File

@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'bisheng/router';
import { FormattedMessage } from 'react-intl';
import { FormattedMessage, injectIntl } from 'react-intl';
import classNames from 'classnames';
import { Select, Menu, Row, Col, Icon, Popover, Input, Button, Badge } from 'antd';
import Santa from './Santa';
@ -36,10 +36,9 @@ function initDocSearch(locale) {
});
}
export default class Header extends React.Component {
class Header extends React.Component {
static contextTypes = {
router: PropTypes.object.isRequired,
intl: PropTypes.object.isRequired,
isMobile: PropTypes.bool.isRequired,
};
@ -48,7 +47,8 @@ export default class Header extends React.Component {
};
componentDidMount() {
const { intl, router } = this.context;
const { intl } = this.props;
const { router } = this.context;
router.listen(this.handleHideMenu);
const { searchInput } = this;
document.addEventListener('keyup', event => {
@ -108,7 +108,11 @@ export default class Header extends React.Component {
const { menuVisible } = this.state;
const { isMobile } = this.context;
const menuMode = isMobile ? 'inline' : 'horizontal';
const { location, themeConfig } = this.props;
const {
location,
themeConfig,
intl: { locale },
} = this.props;
const docVersions = { ...themeConfig.docVersions, [antdVersion]: antdVersion };
const versionOptions = Object.keys(docVersions).map(version => (
<Option value={docVersions[version]} key={version}>
@ -124,9 +128,6 @@ export default class Header extends React.Component {
if (activeMenuItem === 'components' || location.pathname === 'changelog') {
activeMenuItem = 'docs/react';
}
const {
intl: { locale },
} = this.context;
const isZhCN = locale === 'zh-CN';
const headerClassName = classNames({
@ -280,3 +281,5 @@ export default class Header extends React.Component {
);
}
}
export default injectIntl(Header);

View File

@ -2,7 +2,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { enquireScreen } from 'enquire-js';
import { addLocaleData, IntlProvider } from 'react-intl';
import { IntlProvider } from 'react-intl';
import 'moment/locale/zh-cn';
import { ConfigProvider } from 'antd';
import LogRocket from 'logrocket';
@ -63,7 +63,6 @@ export default class Layout extends React.Component {
super(props);
const { pathname } = props.location;
const appLocale = utils.isZhCN(pathname) ? cnLocale : enLocale;
addLocaleData(appLocale.data);
this.state = {
appLocale,
@ -110,10 +109,8 @@ export default class Layout extends React.Component {
render() {
const { children, ...restProps } = this.props;
const { appLocale } = this.state;
// Temp remove SentryBoundary
return (
<IntlProvider locale={appLocale.locale} messages={appLocale.messages}>
<IntlProvider locale={appLocale.locale} messages={appLocale.messages} defaultLocale="en-US">
<ConfigProvider locale={appLocale.locale === 'zh-CN' ? zhCN : null}>
<div className="page-wrapper">
<Header {...restProps} />

View File

@ -1,38 +0,0 @@
import React from 'react';
const redirect = {
'/docs/resource/download': '/docs/spec/download',
'/docs/resource/download-cn': '/docs/spec/download-cn',
'/docs/resource/reference': '/docs/spec/reference',
'/docs/resource/reference-cn': '/docs/spec/reference-cn',
'/docs/spec/feature': '/docs/spec/values',
'/docs/spec/feature-cn': '/docs/spec/values-cn',
'/docs/pattern/advanced-search': '/docs/spec/overview',
'/docs/pattern/advanced-search-cn': '/docs/spec/overview-cn',
'/docs/pattern/complex-table': '/docs/spec/overview',
'/docs/pattern/complex-table-cn': '/docs/spec/overview-cn',
'/docs/pattern/form': '/docs/spec/overview',
'/docs/pattern/form-cn': '/docs/spec/overview-cn',
'/docs/pattern/list': '/docs/spec/overview',
'/docs/pattern/list-cn': '/docs/spec/overview-cn',
'/docs/pattern/navigation': '/docs/spec/navigation',
'/docs/pattern/navigation-cn': '/docs/spec/navigation-cn',
'/docs/pattern/table': '/docs/spec/overview',
'/docs/pattern/table-cn': '/docs/spec/overview-cn',
};
export default class Redirect extends React.Component {
componentDidMount() {
const { location } = this.props;
const pathname = `/${location.pathname}`;
Object.keys(redirect).forEach(from => {
if (pathname.indexOf(from) === 0) {
window.location.href = redirect[from];
}
});
}
render() {
return <div />;
}
}

View File

@ -1,8 +1,5 @@
const appLocaleData = require('react-intl/locale-data/zh');
module.exports = {
locale: 'zh-CN',
data: appLocaleData,
messages: {
'app.header.search': '全文本搜索...',
'app.header.menu.home': '首页',