mirror of
https://github.com/ant-design/ant-design.git
synced 2025-01-18 06:03:38 +08:00
Merge branch 'master' of github.com:ant-design/ant-design
This commit is contained in:
commit
5f8b176c69
@ -1,10 +1,18 @@
|
||||
---
|
||||
order: 4
|
||||
title: 参考对象
|
||||
title:
|
||||
zh-CN: 滚动容器
|
||||
en-US: Container to scroll.
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
用 `target` 设置 `Affix` 需要监听其滚动事件的元素,默认为 `window`。
|
||||
|
||||
## en-US
|
||||
|
||||
Set a `target` for 'Affix', which is listen to scroll event of target element (default is `window`).
|
||||
|
||||
````jsx
|
||||
import { Affix, Button } from 'antd';
|
||||
|
||||
@ -17,7 +25,7 @@ const Demo = () => {
|
||||
<br />
|
||||
<br />
|
||||
<Affix target={() => document.getElementById('affix-target')} offsetTop={20}>
|
||||
<Button type="primary">固定在容器顶部</Button>
|
||||
<Button type="primary">Fixed at the top of container</Button>
|
||||
</Affix>
|
||||
</div>
|
||||
</div>
|
||||
|
50
components/cascader/demo/search.md
Normal file
50
components/cascader/demo/search.md
Normal file
@ -0,0 +1,50 @@
|
||||
---
|
||||
order: 9
|
||||
title:
|
||||
zh-CN: 搜索
|
||||
en-US: Search
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
可以直接搜索选项并选择。
|
||||
|
||||
## en-US
|
||||
|
||||
Search and select options directly.
|
||||
|
||||
````jsx
|
||||
import { Cascader } from 'antd';
|
||||
|
||||
const options = [{
|
||||
value: 'zhejiang',
|
||||
label: '浙江',
|
||||
children: [{
|
||||
value: 'hangzhou',
|
||||
label: '杭州',
|
||||
children: [{
|
||||
value: 'xihu',
|
||||
label: '西湖',
|
||||
}],
|
||||
}],
|
||||
}, {
|
||||
value: 'jiangsu',
|
||||
label: '江苏',
|
||||
children: [{
|
||||
value: 'nanjing',
|
||||
label: '南京',
|
||||
children: [{
|
||||
value: 'zhonghuamen',
|
||||
label: '中华门',
|
||||
}],
|
||||
}],
|
||||
}];
|
||||
|
||||
function onChange(value) {
|
||||
console.log(value);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Cascader options={options} onChange={onChange} placeholder="请选择地区" showSearch />
|
||||
, mountNode);
|
||||
````
|
@ -36,3 +36,15 @@ Cascade selection box.
|
||||
| allowClear | whether allow clear | boolean | true |
|
||||
| expandTrigger | expand current item when click or hover, one of 'click' 'hover' | string | 'click' |
|
||||
| changeOnSelect | change value on each selection if set to true, see above demo for details | boolean | false |
|
||||
| showSearch | Whether show search input in single mode. | Boolean or Object | false |
|
||||
| notFoundContent | Specify content to show when no result matches. | String | 'Not Found' |
|
||||
|
||||
Fields in `showSearch`:
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
|----------|-------------|------|---------|
|
||||
| filter | The function will receive two arguments, inputValue and option, if the function returns true, the option will be included in the filtered set; Otherwise, it will be excluded. | `function(inputValue, path): boolean` | |
|
||||
| render | Used to render filtered options. | `function(inputValue, path): React.ReactNode` | |
|
||||
| sort | Used to sort filtered options. | `function(a, b, inputValue)` | |
|
||||
| matchInputWidth | Whether the width of result list equals to input's | boolean | |
|
||||
|
||||
|
@ -15,6 +15,14 @@ export interface CascaderOptionType {
|
||||
}
|
||||
|
||||
export type CascaderExpandTrigger = 'click' | 'hover'
|
||||
|
||||
export interface ShowSearchType {
|
||||
filter?: (inputValue: string, path: CascaderOptionType[]) => boolean;
|
||||
render?: (inputValue: string, path: CascaderOptionType[]) => React.ReactNode;
|
||||
sort?: (a: CascaderOptionType[], b: CascaderOptionType[], inputValue: string) => number;
|
||||
matchInputWidth?: boolean;
|
||||
}
|
||||
|
||||
export interface CascaderProps {
|
||||
/** 可选项数据源 */
|
||||
options: Array<CascaderOptionType>;
|
||||
@ -42,6 +50,8 @@ export interface CascaderProps {
|
||||
disabled?: boolean;
|
||||
/** 是否支持清除*/
|
||||
allowClear?: boolean;
|
||||
showSearch?: boolean | ShowSearchType;
|
||||
notFoundContent?: React.ReactNode;
|
||||
/** 次级菜单的展开方式,可选 'click' 和 'hover' */
|
||||
expandTrigger?: CascaderExpandTrigger;
|
||||
/** 当此项为 true 时,点选每级菜单选项值都会发生变化 */
|
||||
@ -50,6 +60,33 @@ export interface CascaderProps {
|
||||
onPopupVisibleChange?: (popupVisible: boolean) => void;
|
||||
}
|
||||
|
||||
function highlightKeyword(str: string, keyword: string) {
|
||||
return str.split(keyword)
|
||||
.map((node: string, index: number) => index === 0 ? node : [
|
||||
<span className="ant-cascader-menu-item-keyword" key="seperator">{keyword}</span>,
|
||||
node,
|
||||
]);
|
||||
}
|
||||
|
||||
function defaultFilterOption(inputValue, path) {
|
||||
return path.some(option => option.label.indexOf(inputValue) > -1);
|
||||
}
|
||||
|
||||
function defaultRenderFilteredOption(inputValue, path) {
|
||||
return path.map(({ label }, index) => {
|
||||
const node = label.indexOf(inputValue) > -1 ? highlightKeyword(label, inputValue) : label;
|
||||
return index === 0 ? node : [' / ', node];
|
||||
});
|
||||
}
|
||||
|
||||
function defaultSortFilteredOption(a, b, inputValue) {
|
||||
function callback(elem) {
|
||||
return elem.label.indexOf(inputValue) > -1;
|
||||
}
|
||||
|
||||
return a.findIndex(callback) - b.findIndex(callback);
|
||||
}
|
||||
|
||||
export default class Cascader extends React.Component<CascaderProps, any> {
|
||||
static defaultProps = {
|
||||
prefixCls: 'ant-cascader',
|
||||
@ -61,20 +98,27 @@ export default class Cascader extends React.Component<CascaderProps, any> {
|
||||
displayRender: label => label.join(' / '),
|
||||
disabled: false,
|
||||
allowClear: true,
|
||||
showSearch: false,
|
||||
notFoundContent: 'Not Found',
|
||||
onPopupVisibleChange() {},
|
||||
};
|
||||
|
||||
cachedOptions: CascaderOptionType[];
|
||||
refs: {
|
||||
[key: string]: any;
|
||||
input: {
|
||||
refs: { input: HTMLElement }
|
||||
};
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let value;
|
||||
if ('value' in props) {
|
||||
value = props.value;
|
||||
} else if ('defaultValue' in props) {
|
||||
value = props.defaultValue;
|
||||
}
|
||||
this.state = {
|
||||
value: value || [],
|
||||
value: props.value || props.defautValue || [],
|
||||
inputValue: '',
|
||||
inputFocused: false,
|
||||
popupVisible: false,
|
||||
flattenOptions: props.showSearch && this.flattenTree(props.options, props.changeOnSelect),
|
||||
};
|
||||
}
|
||||
|
||||
@ -82,17 +126,45 @@ export default class Cascader extends React.Component<CascaderProps, any> {
|
||||
if ('value' in nextProps) {
|
||||
this.setState({ value: nextProps.value || [] });
|
||||
}
|
||||
if (nextProps.showSearch && this.props.options !== nextProps.options) {
|
||||
this.setState({ flattenOptions: this.flattenTree(nextProps.options, nextProps.changeOnSelect) });
|
||||
}
|
||||
}
|
||||
|
||||
handleChange = (value, selectedOptions) => {
|
||||
this.setValue(value, selectedOptions);
|
||||
const unwrappedValue = Array.isArray(value[0]) ? value[0] : value;
|
||||
this.setState({ inputValue: '' });
|
||||
this.setValue(unwrappedValue, selectedOptions);
|
||||
}
|
||||
|
||||
handlePopupVisibleChange = (popupVisible) => {
|
||||
this.setState({ popupVisible });
|
||||
this.setState({
|
||||
popupVisible,
|
||||
inputFocused: popupVisible,
|
||||
});
|
||||
this.props.onPopupVisibleChange(popupVisible);
|
||||
}
|
||||
|
||||
handleInputBlur = () => {
|
||||
this.setState({
|
||||
inputFocused: false,
|
||||
});
|
||||
}
|
||||
|
||||
handleInputClick = (e) => {
|
||||
const { inputFocused, popupVisible } = this.state;
|
||||
// Prevent `Trigger` behaviour.
|
||||
if (inputFocused || popupVisible) {
|
||||
e.stopPropagation();
|
||||
e.nativeEvent.stopImmediatePropagation();
|
||||
}
|
||||
}
|
||||
|
||||
handleInputChange = (e) => {
|
||||
const inputValue = e.target.value;
|
||||
this.setState({ inputValue });
|
||||
}
|
||||
|
||||
setValue = (value, selectedOptions = []) => {
|
||||
if (!('value' in this.props)) {
|
||||
this.setState({ value });
|
||||
@ -102,7 +174,9 @@ export default class Cascader extends React.Component<CascaderProps, any> {
|
||||
|
||||
getLabel() {
|
||||
const { options, displayRender } = this.props;
|
||||
const selectedOptions = arrayTreeFilter(options, (o, level) => o.value === this.state.value[level]);
|
||||
const value = this.state.value;
|
||||
const unwrappedValue = Array.isArray(value[0]) ? value[0] : value;
|
||||
const selectedOptions = arrayTreeFilter(options, (o, level) => o.value === unwrappedValue[level]);
|
||||
const label = selectedOptions.map(o => o.label);
|
||||
return displayRender(label, selectedOptions);
|
||||
}
|
||||
@ -110,28 +184,71 @@ export default class Cascader extends React.Component<CascaderProps, any> {
|
||||
clearSelection = (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.setValue([]);
|
||||
this.setState({ popupVisible: false });
|
||||
if (!this.state.inputValue) {
|
||||
this.setValue([]);
|
||||
this.setState({ popupVisible: false });
|
||||
} else {
|
||||
this.setState({ inputValue: '' });
|
||||
}
|
||||
}
|
||||
|
||||
flattenTree(options, changeOnSelect, ancestor = []) {
|
||||
let flattenOptions = [];
|
||||
options.forEach((option) => {
|
||||
const path = ancestor.concat(option);
|
||||
if (changeOnSelect || !option.children) {
|
||||
flattenOptions.push(path);
|
||||
}
|
||||
if (option.children) {
|
||||
flattenOptions = flattenOptions.concat(this.flattenTree(option.children, changeOnSelect, path));
|
||||
}
|
||||
});
|
||||
return flattenOptions;
|
||||
}
|
||||
|
||||
generateFilteredOptions() {
|
||||
const { showSearch, notFoundContent } = this.props;
|
||||
const {
|
||||
filter = defaultFilterOption,
|
||||
render = defaultRenderFilteredOption,
|
||||
sort = defaultSortFilteredOption,
|
||||
} = showSearch as ShowSearchType;
|
||||
const { flattenOptions, inputValue } = this.state;
|
||||
const filtered = flattenOptions.filter((path) => filter(this.state.inputValue, path))
|
||||
.sort((a, b) => sort(a, b, inputValue));
|
||||
|
||||
if (filtered.length > 0) {
|
||||
return filtered.map((path) => {
|
||||
return {
|
||||
label: render(inputValue, path),
|
||||
value: path.map(o => o.value),
|
||||
};
|
||||
});
|
||||
}
|
||||
return [{ label: notFoundContent, value: 'ANT_CASCADER_NOT_FOUND', disabled: true }];
|
||||
}
|
||||
|
||||
render() {
|
||||
const props = this.props;
|
||||
const state = this.state;
|
||||
const [{ prefixCls, children, placeholder, size, disabled,
|
||||
className, style, allowClear }, otherProps] = splitObject(props,
|
||||
['prefixCls', 'children', 'placeholder', 'size', 'disabled', 'className', 'style', 'allowClear']);
|
||||
className, style, allowClear, showSearch }, otherProps] = splitObject(props,
|
||||
['prefixCls', 'children', 'placeholder', 'size', 'disabled', 'className',
|
||||
'style', 'allowClear', 'showSearch']);
|
||||
const value = state.value;
|
||||
|
||||
const sizeCls = classNames({
|
||||
'ant-input-lg': size === 'large',
|
||||
'ant-input-sm': size === 'small',
|
||||
});
|
||||
const clearIcon = (allowClear && !disabled && this.state.value.length > 0) ?
|
||||
const clearIcon = (allowClear && !disabled && value.length > 0) || state.inputValue ?
|
||||
<Icon type="cross-circle"
|
||||
className={`${prefixCls}-picker-clear`}
|
||||
onClick={this.clearSelection}
|
||||
/> : null;
|
||||
const arrowCls = classNames({
|
||||
[`${prefixCls}-picker-arrow`]: true,
|
||||
[`${prefixCls}-picker-arrow-expand`]: this.state.popupVisible,
|
||||
[`${prefixCls}-picker-arrow-expand`]: state.popupVisible,
|
||||
});
|
||||
const pickerCls = classNames({
|
||||
[className]: !!className,
|
||||
@ -154,14 +271,44 @@ export default class Cascader extends React.Component<CascaderProps, any> {
|
||||
'getPopupContainer',
|
||||
'loadData',
|
||||
'popupClassName',
|
||||
'filterOption',
|
||||
'renderFilteredOption',
|
||||
'sortFilteredOption',
|
||||
'notFoundContent',
|
||||
]);
|
||||
|
||||
let options = props.options;
|
||||
if (state.inputValue) {
|
||||
options = this.generateFilteredOptions();
|
||||
}
|
||||
// Dropdown menu should keep previous status until it is fully closed.
|
||||
if (!state.popupVisible) {
|
||||
options = this.cachedOptions;
|
||||
} else {
|
||||
this.cachedOptions = options;
|
||||
}
|
||||
|
||||
const dropdownMenuColumnStyle = {
|
||||
width: undefined,
|
||||
height: undefined,
|
||||
};
|
||||
const isNotFound = (options || []).length === 1 && options[0].value === 'ANT_CASCADER_NOT_FOUND';
|
||||
if (isNotFound) {
|
||||
dropdownMenuColumnStyle.height = 'auto'; // Height of one row.
|
||||
}
|
||||
// The default value of `matchInputWidth` is `true`
|
||||
const resultListMatchInputWidth = showSearch.matchInputWidth === false ? false : true;
|
||||
if (resultListMatchInputWidth && state.inputValue && this.refs.input) {
|
||||
dropdownMenuColumnStyle.width = this.refs.input.refs.input.offsetWidth;
|
||||
}
|
||||
return (
|
||||
<RcCascader {...props}
|
||||
value={this.state.value}
|
||||
popupVisible={this.state.popupVisible}
|
||||
options={options}
|
||||
value={value}
|
||||
popupVisible={state.popupVisible}
|
||||
onPopupVisibleChange={this.handlePopupVisibleChange}
|
||||
onChange={this.handleChange}
|
||||
dropdownMenuColumnStyle={dropdownMenuColumnStyle}
|
||||
>
|
||||
{children ||
|
||||
<span
|
||||
@ -169,11 +316,15 @@ export default class Cascader extends React.Component<CascaderProps, any> {
|
||||
className={pickerCls}
|
||||
>
|
||||
<Input {...inputProps}
|
||||
placeholder={this.state.value && this.state.value.length > 0 ? null : placeholder}
|
||||
ref="input"
|
||||
placeholder={value && value.length > 0 ? null : placeholder}
|
||||
className={`${prefixCls}-input ${sizeCls}`}
|
||||
value=""
|
||||
value={state.inputValue}
|
||||
disabled={disabled}
|
||||
readOnly
|
||||
readOnly={!showSearch}
|
||||
onClick={showSearch ? this.handleInputClick : null}
|
||||
onBlur={showSearch ? this.handleInputBlur : null}
|
||||
onChange={showSearch ? this.handleInputChange : null}
|
||||
/>
|
||||
<span className={`${prefixCls}-picker-label`}>{this.getLabel()}</span>
|
||||
{clearIcon}
|
||||
|
@ -1,8 +1,8 @@
|
||||
---
|
||||
category: Components
|
||||
type: Form Controls
|
||||
chinese: 级联选择
|
||||
english: Cascader
|
||||
title: Cascader
|
||||
subtitle: 级联选择
|
||||
---
|
||||
|
||||
级联选择框。
|
||||
@ -22,18 +22,29 @@ english: Cascader
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|------|------|------|--------|
|
||||
| options | 可选项数据源 | object | - |
|
||||
| defaultValue | 默认的选中项 | array |[] |
|
||||
| value | 指定选中项 | array | - |
|
||||
| options | 可选项数据源 | Object | - |
|
||||
| defaultValue | 默认的选中项 | Array |[] |
|
||||
| value | 指定选中项 | Array | - |
|
||||
| onChange | 选择完成后的回调 | `function(value, selectedOptions)` | - |
|
||||
| displayRender | 选择后展示的渲染函数 | `function(label, selectedOptions)` | `label => label.join(' / ')` |
|
||||
| style | 自定义样式 | string | - |
|
||||
| className | 自定义类名 | string | - |
|
||||
| popupClassName | 自定义浮层类名 | string | - |
|
||||
| popupPlacement | 浮层预设位置:`bottomLeft` `bottomRight` `topLeft` `topRight` | string | `bottomLeft` |
|
||||
| placeholder | 输入框占位文本 | string | '请选择' |
|
||||
| size | 输入框大小,可选 `large` `default` `small` | string | `default` |
|
||||
| disabled | 禁用 | boolean | false |
|
||||
| allowClear | 是否支持清除 | boolean | true |
|
||||
| expandTrigger | 次级菜单的展开方式,可选 'click' 和 'hover' | string | 'click' |
|
||||
| changeOnSelect | 当此项为 true 时,点选每级菜单选项值都会发生变化,具体见上面的演示 | boolean | false |
|
||||
| style | 自定义样式 | String | - |
|
||||
| className | 自定义类名 | String | - |
|
||||
| popupClassName | 自定义浮层类名 | String | - |
|
||||
| popupPlacement | 浮层预设位置:`bottomLeft` `bottomRight` `topLeft` `topRight` | Enum | `bottomLeft` |
|
||||
| placeholder | 输入框占位文本 | String | '请选择' |
|
||||
| size | 输入框大小,可选 `large` `default` `small` | String | `default` |
|
||||
| disabled | 禁用 | Boolean | false |
|
||||
| allowClear | 是否支持清除 | Boolean | true |
|
||||
| expandTrigger | 次级菜单的展开方式,可选 'click' 和 'hover' | String | 'click' |
|
||||
| changeOnSelect | 当此项为 true 时,点选每级菜单选项值都会发生变化,具体见上面的演示 | Boolean | false |
|
||||
| showSearch | 在选择框中显示搜索框 | Boolean | false |
|
||||
| notFoundContent | 当下拉列表为空时显示的内容 | String | 'Not Found' |
|
||||
|
||||
`showSearch` 为对象时,其中的字段:
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|------|------|------|--------|
|
||||
| filter | 接收 `inputValue` `path` 两个参数,当 `path` 符合筛选条件时,应返回 true,反之则返回 false。 | `function(inputValue, path): boolean` | |
|
||||
| render | 用于渲染 filter 后的选项 | `function(inputValue, path): React.ReactNode` | |
|
||||
| sort | 用于排序 filter 后的选项 | `function(a, b, inputValue)` | |
|
||||
| matchInputWidth | 搜索结果列表是否与输入框同宽 | boolean | |
|
||||
|
@ -6,6 +6,7 @@
|
||||
.@{cascader-prefix-cls} {
|
||||
font-size: @font-size-base;
|
||||
&-input.ant-input {
|
||||
background-color: transparent;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
@ -22,6 +23,10 @@
|
||||
|
||||
&-disabled {
|
||||
cursor: not-allowed;
|
||||
|
||||
.@{cascader-prefix-cls}-input {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
&-label {
|
||||
@ -36,7 +41,6 @@
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
padding: 0 12px 0 8px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&-clear {
|
||||
@ -171,5 +175,9 @@
|
||||
right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
& &-keyword {
|
||||
color: @error-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,6 +116,15 @@ export default class Form extends React.Component<FormProps, any> {
|
||||
};
|
||||
},
|
||||
render() {
|
||||
const getFieldProps = this.props.form.getFieldProps;
|
||||
function deprecatedGetFieldProps(name, option) {
|
||||
warning(
|
||||
false,
|
||||
'`getFieldProps` is deprecated and will be removed in future, please use `getFieldDecorator` instead'
|
||||
);
|
||||
return getFieldProps(name, option);
|
||||
}
|
||||
this.props.form.getFieldProps = deprecatedGetFieldProps;
|
||||
return <Component {...this.props} />;
|
||||
},
|
||||
}));
|
||||
|
@ -14,7 +14,7 @@ export interface FormItemLabelColOption {
|
||||
export interface FormItemProps {
|
||||
prefixCls?: string;
|
||||
id?: string;
|
||||
label?: string;
|
||||
label?: string | React.ReactNode;
|
||||
labelCol?: FormItemLabelColOption;
|
||||
wrapperCol?: FormItemLabelColOption;
|
||||
help?: React.ReactNode;
|
||||
@ -40,7 +40,7 @@ export default class FormItem extends React.Component<FormItemProps, any> {
|
||||
|
||||
static propTypes = {
|
||||
prefixCls: React.PropTypes.string,
|
||||
label: React.PropTypes.string,
|
||||
label: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.node]),
|
||||
labelCol: React.PropTypes.object,
|
||||
help: React.PropTypes.oneOfType([React.PropTypes.node, React.PropTypes.bool]),
|
||||
validateStatus: React.PropTypes.oneOf(['', 'success', 'warning', 'error', 'validating']),
|
||||
@ -187,7 +187,7 @@ export default class FormItem extends React.Component<FormItemProps, any> {
|
||||
// remove user input colon
|
||||
let label = props.label;
|
||||
if (typeof label === 'string' && label.trim() !== '') {
|
||||
label = props.label.replace(/[:|:]\s*$/, '');
|
||||
label = (props.label as string).replace(/[:|:]\s*$/, '');
|
||||
}
|
||||
|
||||
return props.label ? (
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
order: 15
|
||||
title:
|
||||
title:
|
||||
zh-CN: 动态增减表单项
|
||||
en-US: Dynamic form item
|
||||
---
|
||||
@ -18,6 +18,11 @@ import { Form, Input, Button } from 'antd';
|
||||
|
||||
let uuid = 0;
|
||||
let Demo = React.createClass({
|
||||
componentWillMount() {
|
||||
this.props.form.setFieldsValue({
|
||||
keys: [0],
|
||||
});
|
||||
},
|
||||
remove(k) {
|
||||
const { form } = this.props;
|
||||
// can use data-binding to get
|
||||
@ -52,10 +57,7 @@ let Demo = React.createClass({
|
||||
});
|
||||
},
|
||||
render() {
|
||||
const { getFieldProps, getFieldValue } = this.props.form;
|
||||
getFieldProps('keys', {
|
||||
initialValue: [0],
|
||||
});
|
||||
const { getFieldDecorator, getFieldValue } = this.props.form;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
@ -65,14 +67,15 @@ let Demo = React.createClass({
|
||||
const formItems = getFieldValue('keys').map((k) => {
|
||||
return (
|
||||
<Form.Item {...formItemLayout} label={`good friend${k}:`} key={k}>
|
||||
<Input {...getFieldProps(`name${k}`, {
|
||||
{getFieldDecorator(`name${k}`, {
|
||||
rules: [{
|
||||
required: true,
|
||||
whitespace: true,
|
||||
message: "Your good friend's name",
|
||||
}],
|
||||
})} style={{ width: '80%', marginRight: 8 }}
|
||||
/>
|
||||
})(
|
||||
<Input style={{ width: '80%', marginRight: 8 }} />
|
||||
)}
|
||||
<Button onClick={() => this.remove(k)}>remove</Button>
|
||||
</Form.Item>
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
order: 3
|
||||
title:
|
||||
title:
|
||||
zh-CN: 表单控件
|
||||
en-US: Form controls
|
||||
---
|
||||
@ -15,7 +15,7 @@ title:
|
||||
|
||||
A list off all the controls that can be used with form.
|
||||
|
||||
**Note**: Input control: Only if set correct type for it, then it will be set correct style
|
||||
**Note**: Input control: Only if set correct type for it, then it will be set correct style.
|
||||
|
||||
````jsx
|
||||
import { Form, Input, Select, Checkbox, Radio } from 'antd';
|
||||
|
@ -37,7 +37,7 @@ let Demo = React.createClass({
|
||||
},
|
||||
|
||||
render() {
|
||||
const { getFieldProps } = this.props.form;
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 4 },
|
||||
@ -52,13 +52,17 @@ let Demo = React.createClass({
|
||||
{...formItemLayout}
|
||||
label="User name"
|
||||
>
|
||||
<Input {...getFieldProps('username', {})} type="text" autoComplete="off" />
|
||||
{getFieldDecorator('username')(
|
||||
<Input type="text" autoComplete="off" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="Password"
|
||||
>
|
||||
<Input {...getFieldProps('password', {})} type="password" autoComplete="off" />
|
||||
{getFieldDecorator('password')(
|
||||
<Input type="password" autoComplete="off" />
|
||||
)}
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
order: 2
|
||||
title:
|
||||
title:
|
||||
zh-CN: 典型表单
|
||||
en-US: Horizontal form
|
||||
---
|
||||
@ -25,7 +25,7 @@ let Demo = React.createClass({
|
||||
},
|
||||
|
||||
render() {
|
||||
const { getFieldProps } = this.props.form;
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 14 },
|
||||
@ -42,29 +42,37 @@ let Demo = React.createClass({
|
||||
{...formItemLayout}
|
||||
label="Password"
|
||||
>
|
||||
<Input type="password" {...getFieldProps('pass', { initialValue: '' })} placeholder="Please input the password" />
|
||||
{getFieldDecorator('pass', { initialValue: '' })(
|
||||
<Input type="password" placeholder="Please input the password" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="Gender"
|
||||
>
|
||||
<RadioGroup {...getFieldProps('gender', { initialValue: 'female' })}>
|
||||
<Radio value="male">male</Radio>
|
||||
<Radio value="female">female</Radio>
|
||||
</RadioGroup>
|
||||
{getFieldDecorator('gender', { initialValue: 'female' })(
|
||||
<RadioGroup>
|
||||
<Radio value="male">male</Radio>
|
||||
<Radio value="female">female</Radio>
|
||||
</RadioGroup>
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="remarks"
|
||||
help="Please input something"
|
||||
>
|
||||
<Input type="textarea" placeholder="Please input something" {...getFieldProps('remark', { initialValue: '' })} />
|
||||
{getFieldDecorator('remark', { initialValue: '' })(
|
||||
<Input type="textarea" placeholder="Please input something" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label={<span>Sold myself <Tooltip title="I come for Qiu Xiang"><Icon type="question-circle-o" /></Tooltip></span>}
|
||||
>
|
||||
<Checkbox {...getFieldProps('agreement', { initialValue: false, valuePropName: 'checked' })}>agree</Checkbox>
|
||||
{getFieldDecorator('agreement', { initialValue: false, valuePropName: 'checked' })(
|
||||
<Checkbox>agree</Checkbox>
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem wrapperCol={{ span: 16, offset: 6 }} style={{ marginTop: 24 }}>
|
||||
<Button type="primary" htmlType="submit">OK</Button>
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
order: 1
|
||||
title:
|
||||
title:
|
||||
zh-CN: 平行排列
|
||||
en-US: Inline form
|
||||
---
|
||||
@ -11,7 +11,7 @@ title:
|
||||
|
||||
## en-US
|
||||
|
||||
Inline form is often used for login.
|
||||
Inline form is often used for login.
|
||||
|
||||
````jsx
|
||||
import { Form, Input, Button, Checkbox } from 'antd';
|
||||
@ -24,25 +24,27 @@ let Demo = React.createClass({
|
||||
},
|
||||
|
||||
render() {
|
||||
const { getFieldProps } = this.props.form;
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
return (
|
||||
<Form inline onSubmit={this.handleSubmit}>
|
||||
<FormItem
|
||||
label="Account"
|
||||
>
|
||||
<Input placeholder="Please input the account"
|
||||
{...getFieldProps('userName')}
|
||||
/>
|
||||
{getFieldDecorator('userName')(
|
||||
<Input placeholder="Please input the account" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label="Password"
|
||||
>
|
||||
<Input type="password" placeholder="Please input the password"
|
||||
{...getFieldProps('password')}
|
||||
/>
|
||||
{getFieldDecorator('password')(
|
||||
<Input type="password" placeholder="Please input the password" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Checkbox {...getFieldProps('agreement')}>Remember me</Checkbox>
|
||||
{getFieldDecorator('agreement')(
|
||||
<Checkbox>Remember me</Checkbox>
|
||||
)}
|
||||
</FormItem>
|
||||
<Button type="primary" htmlType="submit">Submit</Button>
|
||||
</Form>
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
order: 4
|
||||
title:
|
||||
title:
|
||||
zh-CN: 输入框组合
|
||||
en-US: Input group
|
||||
---
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
order: 5
|
||||
title:
|
||||
title:
|
||||
zh-CN: 表单组合
|
||||
en-US: mix
|
||||
---
|
||||
@ -48,7 +48,7 @@ let Demo = React.createClass({
|
||||
},
|
||||
|
||||
render() {
|
||||
const { getFieldProps } = this.props.form;
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
return (
|
||||
<Form horizontal onSubmit={this.handleSubmit} >
|
||||
<FormItem
|
||||
@ -56,9 +56,9 @@ let Demo = React.createClass({
|
||||
labelCol={{ span: 8 }}
|
||||
wrapperCol={{ span: 10 }}
|
||||
>
|
||||
<InputNumber min={1} max={10} style={{ width: 100 }}
|
||||
{...getFieldProps('inputNumber', { initialValue: 3 })}
|
||||
/>
|
||||
{getFieldDecorator('inputNumber', { initialValue: 3 })(
|
||||
<InputNumber min={1} max={10} style={{ width: 100 }} />
|
||||
)}
|
||||
<span className="ant-form-text"> machines</span>
|
||||
</FormItem>
|
||||
|
||||
@ -79,7 +79,9 @@ let Demo = React.createClass({
|
||||
wrapperCol={{ span: 10 }}
|
||||
required
|
||||
>
|
||||
<Switch {...getFieldProps('switch', { valuePropName: 'checked' })} />
|
||||
{getFieldDecorator('switch', { valuePropName: 'checked' })(
|
||||
<Switch />
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
@ -88,7 +90,9 @@ let Demo = React.createClass({
|
||||
wrapperCol={{ span: 10 }}
|
||||
required
|
||||
>
|
||||
<Slider marks={['A', 'B', 'C', 'D', 'E', 'F', 'G']} {...getFieldProps('slider')} />
|
||||
{getFieldDecorator('slider')(
|
||||
<Slider marks={{ 0: 'A', 20: 'B', 40: 'C', 60: 'D', 80: 'E', 100: 'F' }} />
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
@ -97,14 +101,14 @@ let Demo = React.createClass({
|
||||
wrapperCol={{ span: 16 }}
|
||||
required
|
||||
>
|
||||
<Select style={{ width: 200 }}
|
||||
{...getFieldProps('select')}
|
||||
>
|
||||
<Option value="jack">jack</Option>
|
||||
<Option value="lucy">lucy</Option>
|
||||
<Option value="disabled" disabled>disabled</Option>
|
||||
<Option value="yiminghe">yiminghe</Option>
|
||||
</Select>
|
||||
{getFieldDecorator('select')(
|
||||
<Select style={{ width: 200 }}>
|
||||
<Option value="jack">jack</Option>
|
||||
<Option value="lucy">lucy</Option>
|
||||
<Option value="disabled" disabled>disabled</Option>
|
||||
<Option value="yiminghe">yiminghe</Option>
|
||||
</Select>
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
@ -114,7 +118,9 @@ let Demo = React.createClass({
|
||||
required
|
||||
hasFeedback
|
||||
>
|
||||
<Cascader style={{ width: 200 }} options={areaData} {...getFieldProps('area')} />
|
||||
{getFieldDecorator('area')(
|
||||
<Cascader style={{ width: 200 }} options={areaData} />
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
@ -124,7 +130,9 @@ let Demo = React.createClass({
|
||||
>
|
||||
<Col span="6">
|
||||
<FormItem>
|
||||
<DatePicker {...getFieldProps('startDate')} />
|
||||
{getFieldDecorator('startDate')(
|
||||
<DatePicker />
|
||||
)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="1">
|
||||
@ -132,7 +140,9 @@ let Demo = React.createClass({
|
||||
</Col>
|
||||
<Col span="6">
|
||||
<FormItem>
|
||||
<DatePicker {...getFieldProps('endDate')} />
|
||||
{getFieldDecorator('endDate')(
|
||||
<DatePicker />
|
||||
)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
</FormItem>
|
||||
@ -144,18 +154,22 @@ let Demo = React.createClass({
|
||||
wrapperCol={{ span: 16 }}
|
||||
required
|
||||
>
|
||||
<TimePicker {...getFieldProps('time')} />
|
||||
{getFieldDecorator('time')(
|
||||
<TimePicker />
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
label="Options"
|
||||
labelCol={{ span: 8 }}
|
||||
>
|
||||
<RadioGroup {...getFieldProps('rg')}>
|
||||
<RadioButton value="a">item 1</RadioButton>
|
||||
<RadioButton value="b">item 2</RadioButton>
|
||||
<RadioButton value="c">item 3</RadioButton>
|
||||
</RadioGroup>
|
||||
{getFieldDecorator('rg')(
|
||||
<RadioGroup>
|
||||
<RadioButton value="a">item 1</RadioButton>
|
||||
<RadioButton value="b">item 2</RadioButton>
|
||||
<RadioButton value="c">item 3</RadioButton>
|
||||
</RadioGroup>
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
@ -164,16 +178,16 @@ let Demo = React.createClass({
|
||||
wrapperCol={{ span: 16 }}
|
||||
help="longgggggggggggggggggggggggggggggggggg"
|
||||
>
|
||||
<Upload name="logo" action="/upload.do" listType="picture" onChange={this.handleUpload}
|
||||
{...getFieldProps('upload', {
|
||||
valuePropName: 'fileList',
|
||||
normalize: this.normFile,
|
||||
})}
|
||||
>
|
||||
<Button type="ghost">
|
||||
<Icon type="upload" /> Click to upload
|
||||
</Button>
|
||||
</Upload>
|
||||
{getFieldDecorator('upload', {
|
||||
valuePropName: 'fileList',
|
||||
normalize: this.normFile,
|
||||
})(
|
||||
<Upload name="logo" action="/upload.do" listType="picture" onChange={this.handleUpload}>
|
||||
<Button type="ghost">
|
||||
<Icon type="upload" /> Click to upload
|
||||
</Button>
|
||||
</Upload>
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem wrapperCol={{ span: 16, offset: 8 }} style={{ marginTop: 24 }}>
|
||||
|
@ -72,46 +72,7 @@ let BasicDemo = React.createClass({
|
||||
},
|
||||
|
||||
render() {
|
||||
const { getFieldProps, getFieldError, isFieldValidating } = this.props.form;
|
||||
const nameProps = getFieldProps('name', {
|
||||
rules: [
|
||||
{ required: true, min: 5, message: 'User name for at least 5 characters' },
|
||||
{ validator: this.userExists },
|
||||
],
|
||||
});
|
||||
const emailProps = getFieldProps('email', {
|
||||
validate: [{
|
||||
rules: [
|
||||
{ required: true },
|
||||
],
|
||||
trigger: 'onBlur',
|
||||
}, {
|
||||
rules: [
|
||||
{ type: 'email', message: 'Please input the correct email' },
|
||||
],
|
||||
trigger: ['onBlur', 'onChange'],
|
||||
}],
|
||||
});
|
||||
const passwdProps = getFieldProps('passwd', {
|
||||
rules: [
|
||||
{ required: true, whitespace: true, message: 'Please enter your password' },
|
||||
{ validator: this.checkPass },
|
||||
],
|
||||
});
|
||||
const rePasswdProps = getFieldProps('rePasswd', {
|
||||
rules: [{
|
||||
required: true,
|
||||
whitespace: true,
|
||||
message: 'Please confirm your password',
|
||||
}, {
|
||||
validator: this.checkPass2,
|
||||
}],
|
||||
});
|
||||
const textareaProps = getFieldProps('textarea', {
|
||||
rules: [
|
||||
{ required: true, message: 'Really not supposed to write something?' },
|
||||
],
|
||||
});
|
||||
const { getFieldDecorator, getFieldError, isFieldValidating } = this.props.form;
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 7 },
|
||||
wrapperCol: { span: 12 },
|
||||
@ -124,7 +85,14 @@ let BasicDemo = React.createClass({
|
||||
hasFeedback
|
||||
help={isFieldValidating('name') ? 'validating...' : (getFieldError('name') || []).join(', ')}
|
||||
>
|
||||
<Input {...nameProps} placeholder="Real-tiem validation, try to input JasonWood" />
|
||||
{getFieldDecorator('name', {
|
||||
rules: [
|
||||
{ required: true, min: 5, message: 'User name for at least 5 characters' },
|
||||
{ validator: this.userExists },
|
||||
],
|
||||
})(
|
||||
<Input placeholder="Real-tiem validation, try to input JasonWood" />
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
@ -132,7 +100,21 @@ let BasicDemo = React.createClass({
|
||||
label="Email"
|
||||
hasFeedback
|
||||
>
|
||||
<Input {...emailProps} type="email" placeholder="This control uses onBlur and onChange" />
|
||||
{getFieldDecorator('email', {
|
||||
validate: [{
|
||||
rules: [
|
||||
{ required: true },
|
||||
],
|
||||
trigger: 'onBlur',
|
||||
}, {
|
||||
rules: [
|
||||
{ type: 'email', message: 'Please input the correct email' },
|
||||
],
|
||||
trigger: ['onBlur', 'onChange'],
|
||||
}],
|
||||
})(
|
||||
<Input type="email" placeholder="This control uses onBlur and onChange" />
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
@ -140,9 +122,16 @@ let BasicDemo = React.createClass({
|
||||
label="Password"
|
||||
hasFeedback
|
||||
>
|
||||
<Input {...passwdProps} type="password" autoComplete="off"
|
||||
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
|
||||
/>
|
||||
{getFieldDecorator('passwd', {
|
||||
rules: [
|
||||
{ required: true, whitespace: true, message: 'Please enter your password' },
|
||||
{ validator: this.checkPass },
|
||||
],
|
||||
})(
|
||||
<Input type="password" autoComplete="off"
|
||||
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
|
||||
/>
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
@ -150,16 +139,32 @@ let BasicDemo = React.createClass({
|
||||
label="Confirm password"
|
||||
hasFeedback
|
||||
>
|
||||
<Input {...rePasswdProps} type="password" autoComplete="off" placeholder="Two passwords that you enter must be consistent"
|
||||
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
|
||||
/>
|
||||
{getFieldDecorator('rePasswd', {
|
||||
rules: [{
|
||||
required: true,
|
||||
whitespace: true,
|
||||
message: 'Please confirm your password',
|
||||
}, {
|
||||
validator: this.checkPass2,
|
||||
}],
|
||||
})(
|
||||
<Input type="password" autoComplete="off" placeholder="Two passwords that you enter must be consistent"
|
||||
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
|
||||
/>
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="remark"
|
||||
>
|
||||
<Input {...textareaProps} type="textarea" placeholder="Please write something" id="textarea" name="textarea" />
|
||||
{getFieldDecorator('textarea', {
|
||||
rules: [
|
||||
{ required: true, message: 'Really not supposed to write something?' },
|
||||
],
|
||||
})(
|
||||
<Input type="textarea" placeholder="Please write something" id="textarea" name="textarea" />
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem wrapperCol={{ span: 12, offset: 7 }}>
|
||||
|
@ -122,40 +122,31 @@ let Demo = React.createClass({
|
||||
},
|
||||
|
||||
render() {
|
||||
const { getFieldProps } = this.props.form;
|
||||
|
||||
const passProps = getFieldProps('pass', {
|
||||
rules: [
|
||||
{ required: true, whitespace: true, message: 'Please enter your password' },
|
||||
{ validator: this.checkPass },
|
||||
],
|
||||
onChange: (e) => {
|
||||
console.log('Your password is stolen in this way', e.target.value);
|
||||
},
|
||||
});
|
||||
const rePassProps = getFieldProps('rePass', {
|
||||
rules: [{
|
||||
required: true,
|
||||
whitespace: true,
|
||||
message: 'Please confirm your password',
|
||||
}, {
|
||||
validator: this.checkPass2,
|
||||
}],
|
||||
});
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
return (
|
||||
<div>
|
||||
<Form vertical style={{ maxWidth: 600 }} form={this.props.form}>
|
||||
<Row type="flex" align="middle">
|
||||
<Col span={12}>
|
||||
<FormItem label="Password">
|
||||
<Input {...passProps} type="password"
|
||||
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
|
||||
autoComplete="off" id="pass"
|
||||
onBlur={(e) => {
|
||||
const value = e.target.value;
|
||||
this.setState({ dirty: this.state.dirty || !!value });
|
||||
}}
|
||||
/>
|
||||
{getFieldDecorator('pass', {
|
||||
rules: [
|
||||
{ required: true, whitespace: true, message: 'Please enter your password' },
|
||||
{ validator: this.checkPass },
|
||||
],
|
||||
})(
|
||||
<Input type="password"
|
||||
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
|
||||
autoComplete="off" id="pass"
|
||||
onChange={(e) => {
|
||||
console.log('Your password is stolen in this way', e.target.value);
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
const value = e.target.value;
|
||||
this.setState({ dirty: this.state.dirty || !!value });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
@ -165,10 +156,20 @@ let Demo = React.createClass({
|
||||
<Row type="flex" align="middle">
|
||||
<Col span={12}>
|
||||
<FormItem label="Confirm">
|
||||
<Input {...rePassProps} type="password"
|
||||
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
|
||||
autoComplete="off" id="rePass"
|
||||
/>
|
||||
{getFieldDecorator('rePass', {
|
||||
rules: [{
|
||||
required: true,
|
||||
whitespace: true,
|
||||
message: 'Please confirm your password',
|
||||
}, {
|
||||
validator: this.checkPass2,
|
||||
}],
|
||||
})(
|
||||
<Input type="password"
|
||||
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
|
||||
autoComplete="off" id="rePass"
|
||||
/>
|
||||
)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
|
@ -56,7 +56,7 @@ let Demo = React.createClass({
|
||||
|
||||
checkPrime(rule, value, callback) {
|
||||
if (value !== 11) {
|
||||
callback(new Error('The prime number between 8 to 12 is obiviously 11!'));
|
||||
callback(new Error('The prime number between 8 to 12 is 11!'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
@ -71,45 +71,7 @@ let Demo = React.createClass({
|
||||
label: 'Hang Zhou',
|
||||
}],
|
||||
}];
|
||||
const { getFieldProps } = this.props.form;
|
||||
const selectProps = getFieldProps('select', {
|
||||
rules: [
|
||||
{ required: true, message: 'Please select your country' },
|
||||
],
|
||||
});
|
||||
const multiSelectProps = getFieldProps('multiSelect', {
|
||||
rules: [
|
||||
{ required: true, message: 'Please select your favourite colors', type: 'array' },
|
||||
],
|
||||
});
|
||||
const radioProps = getFieldProps('radio', {
|
||||
rules: [
|
||||
{ required: true, message: 'Please select your gender' },
|
||||
],
|
||||
});
|
||||
const birthdayProps = getFieldProps('birthday', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
type: 'date',
|
||||
message: 'When is your birthday?',
|
||||
}, {
|
||||
validator: this.checkBirthday,
|
||||
},
|
||||
],
|
||||
});
|
||||
const timeProps = getFieldProps('time', {
|
||||
getValueFromEvent: (value, timeString) => timeString,
|
||||
rules: [
|
||||
{ required: true, message: 'Please select the time' },
|
||||
],
|
||||
});
|
||||
const primeNumberProps = getFieldProps('primeNumber', {
|
||||
rules: [{ validator: this.checkPrime }],
|
||||
});
|
||||
const addressProps = getFieldProps('address', {
|
||||
rules: [{ required: true, type: 'array' }],
|
||||
});
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 7 },
|
||||
wrapperCol: { span: 12 },
|
||||
@ -120,80 +82,131 @@ let Demo = React.createClass({
|
||||
{...formItemLayout}
|
||||
label="Country"
|
||||
>
|
||||
<Select {...selectProps} placeholder="Please select a country" style={{ width: '100%' }}>
|
||||
<Option value="china">China</Option>
|
||||
<Option value="use">U.S.A</Option>
|
||||
<Option value="japan">Japan</Option>
|
||||
<Option value="korean">Korea</Option>
|
||||
<Option value="Thailand">Thai</Option>
|
||||
</Select>
|
||||
{getFieldDecorator('select', {
|
||||
rules: [
|
||||
{ required: true, message: 'Please select your country' },
|
||||
],
|
||||
})(
|
||||
<Select placeholder="Please select a country" style={{ width: '100%' }}>
|
||||
<Option value="china">China</Option>
|
||||
<Option value="use">U.S.A</Option>
|
||||
<Option value="japan">Japan</Option>
|
||||
<Option value="korean">Korea</Option>
|
||||
<Option value="Thailand">Thai</Option>
|
||||
</Select>
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="Favourite colors"
|
||||
>
|
||||
<Select {...multiSelectProps} multiple placeholder="Please select favourite colors" style={{ width: '100%' }}>
|
||||
<Option value="red">Red</Option>
|
||||
<Option value="orange">Orange</Option>
|
||||
<Option value="yellow">Yellow</Option>
|
||||
<Option value="green">Green</Option>
|
||||
<Option value="blue">Blue</Option>
|
||||
</Select>
|
||||
{getFieldDecorator('multiSelect', {
|
||||
rules: [
|
||||
{ required: true, message: 'Please select your favourite colors', type: 'array' },
|
||||
],
|
||||
})(
|
||||
<Select multiple placeholder="Please select favourite colors" style={{ width: '100%' }}>
|
||||
<Option value="red">Red</Option>
|
||||
<Option value="orange">Orange</Option>
|
||||
<Option value="yellow">Yellow</Option>
|
||||
<Option value="green">Green</Option>
|
||||
<Option value="blue">Blue</Option>
|
||||
</Select>
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="Gender"
|
||||
>
|
||||
<RadioGroup {...radioProps}>
|
||||
<Radio value="male">male</Radio>
|
||||
<Radio value="female">female</Radio>
|
||||
</RadioGroup>
|
||||
<span><Icon type="info-circle-o" /> Temporarily does not support ohter gender</span>
|
||||
{getFieldDecorator('radio', {
|
||||
rules: [
|
||||
{ required: true, message: 'Please select your gender' },
|
||||
],
|
||||
})(
|
||||
<RadioGroup>
|
||||
<Radio value="male">male</Radio>
|
||||
<Radio value="female">female</Radio>
|
||||
</RadioGroup>
|
||||
)}
|
||||
<span><Icon type="info-circle-o" /> Temporarily no ohter gender</span>
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="Hobby"
|
||||
>
|
||||
<Checkbox {...getFieldProps('eat', {
|
||||
{getFieldDecorator('eat', {
|
||||
valuePropName: 'checked',
|
||||
})}>eat</Checkbox>
|
||||
<Checkbox {...getFieldProps('sleep', {
|
||||
})(
|
||||
<Checkbox>eat</Checkbox>
|
||||
)}
|
||||
{getFieldDecorator('sleep', {
|
||||
valuePropName: 'checked',
|
||||
})}>sleeping</Checkbox>
|
||||
<Checkbox {...getFieldProps('beat', {
|
||||
})(
|
||||
<Checkbox>sleeping</Checkbox>
|
||||
)}
|
||||
{getFieldDecorator('beat', {
|
||||
valuePropName: 'checked',
|
||||
})}>dozen doug</Checkbox>
|
||||
})(
|
||||
<Checkbox>dozen doug</Checkbox>
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="Birthday"
|
||||
>
|
||||
<DatePicker {...birthdayProps} />
|
||||
{getFieldDecorator('birthday', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
type: 'date',
|
||||
message: 'When is your birthday?',
|
||||
}, {
|
||||
validator: this.checkBirthday,
|
||||
},
|
||||
],
|
||||
})(
|
||||
<DatePicker />
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="Select the time"
|
||||
>
|
||||
<TimePicker {...timeProps} />
|
||||
{getFieldDecorator('time', {
|
||||
getValueFromEvent: (value, timeString) => timeString,
|
||||
rules: [
|
||||
{ required: true, message: 'Please select the time' },
|
||||
],
|
||||
})(
|
||||
<TimePicker />
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="A prime number between 8 to 12"
|
||||
label="Prime num between 8, 12"
|
||||
>
|
||||
<InputNumber {...primeNumberProps} min={8} max={12} />
|
||||
{getFieldDecorator('primeNumber', {
|
||||
rules: [{ validator: this.checkPrime }],
|
||||
})(
|
||||
<InputNumber min={8} max={12} />
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="Please select address"
|
||||
>
|
||||
<Cascader {...addressProps} options={address} />
|
||||
{getFieldDecorator('address', {
|
||||
rules: [{ required: true, type: 'array' }],
|
||||
})(
|
||||
<Cascader options={address} />
|
||||
)}
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
order: 6
|
||||
title:
|
||||
title:
|
||||
zh-CN: 校验提示
|
||||
en-US: Validation message
|
||||
---
|
||||
|
@ -73,19 +73,15 @@ If the form has been decorated by `Form.create` then it has `this.props.form` pr
|
||||
| getFieldError | Get the error of a field. | Function(name) |
|
||||
| isFieldValidating | Check if the specified field is being validated. | Function(name) |
|
||||
| resetFields | Reset the specified fields' value and status. If you don't specify a parameter, all the fields will be reset. | Function([names: string[]]) |
|
||||
| getFieldProps | Two-way binding for form, please read below for details. | |
|
||||
| getFieldDecorator | Two-way binding for form, please read below for details. | |
|
||||
|
||||
### this.props.form.getFieldProps(id, options)
|
||||
### this.props.form.getFieldDecorator(id, options)
|
||||
|
||||
#### Special attention
|
||||
|
||||
If you use `react@<15.3.0`, then, you can't use `getFieldProps` in functional components: https://github.com/facebook/react/pull/6534
|
||||
If you use `react@<15.3.0`, then, you can't use `getFieldDecorator` in stateless component: https://github.com/facebook/react/pull/6534
|
||||
|
||||
The return value of `getFieldProps` contains `id`、`value`(or any other props `valuePropName` that you specified),`ref`,`onChange`(or any other `trigger` `validateTrigger` that you specified), **shouldn't set same property again** in order to avoid conflict. If you concerntate on the details on return value, you can print them to console by `console.log`.
|
||||
|
||||
> Don't use `defaultValue` in form, please use `initialValue` instead of it.
|
||||
|
||||
#### getFieldProps options
|
||||
#### getFieldDecorator's parameters
|
||||
|
||||
| Property | Description | Type | Default Value |
|
||||
|-----------|-----------------------------------------|-----|--------|
|
||||
@ -96,7 +92,6 @@ The return value of `getFieldProps` contains `id`、`value`(or any other props `
|
||||
| options.getValueFromEvent | To convert parameters of onChange to the value of control, for example, set value of DatePicker: `(date, dateString) => dateString` | function(..args) | [reference](https://github.com/react-component/form#optiongetvaluefromevent) |
|
||||
| options.validateTrigger | When to validate the value of children node. | string | 'onChange' |
|
||||
| options.rules | Includes validation rules. Please refer to [async-validator](https://github.com/yiminghe/async-validator) for details. | array | n/a |
|
||||
| options.onXXX | Because `getFieldProps` will replace events like `onChange`, `trigger`, `validateTrigger`, if you still want to bind these events, you may set them in `options` | function | n/a |
|
||||
| options.exclusive | Whether it is exclusive with other controls, particularly for Radio. | boolean | false |
|
||||
|
||||
### Form.Item
|
||||
|
@ -75,30 +75,25 @@ CustomizedForm = Form.create({})(CustomizedForm);
|
||||
| getFieldError | 获取某个输入控件的 Error | Function(name) |
|
||||
| isFieldValidating | 判断一个输入控件是否在校验状态 | Function(name) |
|
||||
| resetFields | 重置一组输入控件的值与状态,如不传入参数,则重置所有组件 | Function([names: string[]]) |
|
||||
| getFieldProps | 用于和表单进行双向绑定,详见下方描述 | |
|
||||
| getFieldDecorator | 用于和表单进行双向绑定,详见下方描述 | |
|
||||
|
||||
### this.props.form.getFieldProps(id, options)
|
||||
### this.props.form.getFieldDecorator(id, options)
|
||||
|
||||
#### 特别注意
|
||||
|
||||
如果使用的是 `react@<15.3.0`,则 `getFieldProps` 调用不能位于纯函数组件中: https://github.com/facebook/react/pull/6534
|
||||
如果使用的是 `react@<15.3.0`,则 `getFieldDecorator` 调用不能位于纯函数组件中: https://github.com/facebook/react/pull/6534
|
||||
|
||||
`getFieldProps` 返回的属性包括 `id`、`value`(或你设置的其它 `valuePropName`)、`ref`、`onChange`(或者你设置的其它 `trigger` `validateTrigger`),**所以不应再设置同样的属性**,以免冲突。如果对其返回值的细节有兴趣,可以 `console.log` 出来查看。
|
||||
|
||||
> 在表单中 `defaultValue` 也不应该被设置,请使用下面的 `initialValue`。
|
||||
|
||||
#### getFieldProps options
|
||||
#### getFieldDecorator 参数
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|-----------|-----------------------------------------|-----|--------|
|
||||
| options.id | 必填输入控件唯一标志 | string | |
|
||||
| id | 必填输入控件唯一标志 | string | |
|
||||
| options.valuePropName | 子节点的值的属性,如 Switch 的是 'checked' | string | 'value' |
|
||||
| options.initialValue | 子节点的初始值,类型、可选值均由子节点决定 | | |
|
||||
| options.trigger | 收集子节点的值的时机 | string | 'onChange' |
|
||||
| options.getValueFromEvent | 可以把 onChange 的参数转化为控件的值,例如 DatePicker 可设为:`(date, dateString) => dateString` | function(..args) | [reference](https://github.com/react-component/form#optiongetvaluefromevent) |
|
||||
| options.validateTrigger | 校验子节点值的时机 | string | 'onChange' |
|
||||
| options.rules | 校验规则,参见 [async-validator](https://github.com/yiminghe/async-validator) | array | |
|
||||
| options.onXXX | 由于 `getFieldProps` 会占用 `onChange` 等事件(即你所设置的 `trigger` `validateTrigger`),所以如果仍需绑定事件,请在 `options` 内设置 | function | 无 |
|
||||
| options.exclusive | 是否和其他控件互斥,特别用于 Radio 单选控件 | boolean | false |
|
||||
|
||||
### Form.Item
|
||||
|
@ -48,13 +48,14 @@ export interface InputProps {
|
||||
onPressEnter?: React.FormEventHandler;
|
||||
onKeyDown?: React.FormEventHandler;
|
||||
onChange?: React.FormEventHandler;
|
||||
onClick?: React.FormEventHandler;
|
||||
onBlur?: React.FormEventHandler;
|
||||
autosize?: boolean | AutoSizeType;
|
||||
}
|
||||
|
||||
export default class Input extends Component<InputProps, any> {
|
||||
static Group: any;
|
||||
static defaultProps = {
|
||||
defaultValue: '',
|
||||
disabled: false,
|
||||
prefixCls: 'ant-input',
|
||||
type: 'text',
|
||||
|
@ -9,10 +9,14 @@ title:
|
||||
|
||||
点击菜单,收起其他展开的所有菜单,保持菜单聚焦简洁。
|
||||
|
||||
> 该用法要求 antd@2.0+
|
||||
|
||||
## en-US
|
||||
|
||||
Click the menu and you will see that all the other menus gets collapsed to keep the entire menu compact.
|
||||
|
||||
> This demo is for antd@2.0+.
|
||||
|
||||
````jsx
|
||||
import { Menu, Icon } from 'antd';
|
||||
const SubMenu = Menu.SubMenu;
|
||||
@ -26,25 +30,30 @@ const Sider = React.createClass({
|
||||
},
|
||||
handleClick(e) {
|
||||
console.log('click ', e);
|
||||
this.setState({
|
||||
current: e.key,
|
||||
openKeys: e.keyPath.slice(1),
|
||||
});
|
||||
this.setState({ current: e.key });
|
||||
},
|
||||
onToggle(info) {
|
||||
this.setState({
|
||||
openKeys: info.open ? info.keyPath : info.keyPath.slice(1),
|
||||
});
|
||||
onOpenChange(openKeys) {
|
||||
const latestOpenKey = openKeys.find((key) => !(this.state.openKeys.indexOf(key) > -1));
|
||||
this.setState({ openKeys: this.getKeyPath(latestOpenKey) });
|
||||
},
|
||||
getKeyPath(key) {
|
||||
const map = {
|
||||
sub1: ['sub1'],
|
||||
sub2: ['sub2'],
|
||||
sub3: ['sub2', 'sub3'],
|
||||
sub4: ['sub4'],
|
||||
};
|
||||
return map[key] || [];
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Menu onClick={this.handleClick}
|
||||
style={{ width: 240 }}
|
||||
openKeys={this.state.openKeys}
|
||||
onOpen={this.onToggle}
|
||||
onClose={this.onToggle}
|
||||
selectedKeys={[this.state.current]}
|
||||
<Menu
|
||||
mode="inline"
|
||||
openKeys={this.state.openKeys}
|
||||
selectedKeys={[this.state.current]}
|
||||
style={{ width: 240 }}
|
||||
onOpenChange={this.onOpenChange}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
<SubMenu key="sub1" title={<span><Icon type="mail" /><span>导航一</span></span>}>
|
||||
<Menu.Item key="1">选项1</Menu.Item>
|
||||
|
@ -5,15 +5,6 @@ import animation from '../_util/openAnimation';
|
||||
function noop() {
|
||||
}
|
||||
|
||||
interface OpenCloseParam {
|
||||
openKeys: Array<string>;
|
||||
key: string;
|
||||
item: any;
|
||||
trigger: string;
|
||||
open: boolean;
|
||||
keyPath: Array<string>;
|
||||
}
|
||||
|
||||
interface SelectParam {
|
||||
key: string;
|
||||
keyPath: Array<string>;
|
||||
@ -43,8 +34,7 @@ export interface MenuProps {
|
||||
openKeys?: Array<string>;
|
||||
/** 初始展开的菜单项 key 数组*/
|
||||
defaultOpenKeys?: Array<string>;
|
||||
onOpen?: (param: OpenCloseParam) => void;
|
||||
onClose?: (param: OpenCloseParam) => void;
|
||||
onOpenChange?: (openKeys: string[]) => void;
|
||||
/**
|
||||
* 被选中时调用
|
||||
*
|
||||
@ -71,8 +61,7 @@ export default class Menu extends React.Component<MenuProps, any> {
|
||||
static defaultProps = {
|
||||
prefixCls: 'ant-menu',
|
||||
onClick: noop,
|
||||
onOpen: noop,
|
||||
onClose: noop,
|
||||
onOpenChange: noop,
|
||||
className: '',
|
||||
theme: 'light', // or dark
|
||||
};
|
||||
@ -96,15 +85,9 @@ export default class Menu extends React.Component<MenuProps, any> {
|
||||
this.setOpenKeys([]);
|
||||
this.props.onClick(e);
|
||||
}
|
||||
handleOpenKeys = (e) => {
|
||||
const { openKeys } = e;
|
||||
handleOpenChange = (openKeys: string[]) => {
|
||||
this.setOpenKeys(openKeys);
|
||||
this.props.onOpen(e);
|
||||
}
|
||||
handleCloseKeys = (e) => {
|
||||
const { openKeys } = e;
|
||||
this.setOpenKeys(openKeys);
|
||||
this.props.onClose(e);
|
||||
this.props.onOpenChange(openKeys);
|
||||
}
|
||||
setOpenKeys(openKeys) {
|
||||
if (!('openKeys' in this.props)) {
|
||||
@ -144,8 +127,7 @@ export default class Menu extends React.Component<MenuProps, any> {
|
||||
props = {
|
||||
openKeys: this.state.openKeys,
|
||||
onClick: this.handleClick,
|
||||
onOpen: this.handleOpenKeys,
|
||||
onClose: this.handleCloseKeys,
|
||||
onOpenChange: this.handleOpenChange,
|
||||
openTransitionName: openAnimation,
|
||||
className,
|
||||
};
|
||||
|
@ -35,8 +35,7 @@ subtitle: 导航菜单
|
||||
| defaultSelectedKeys | 初始选中的菜单项 key 数组 | Array | |
|
||||
| openKeys | 当前展开的 SubMenu 菜单项 key 数组 | Array | |
|
||||
| defaultOpenKeys | 初始展开的 SubMenu 菜单项 key 数组 | | |
|
||||
| onOpen | SubMenu 展开回调 | Function({ key, item, keyPath }) | |
|
||||
| onClose | SubMenu 收起回调 | Function({ key, item, keyPath }) | |
|
||||
| onOpenChange | SubMenu 展开/关闭的回调 | Function(openKeys: string[]) | noop |
|
||||
| onSelect | 被选中时调 | Function({ item, key, selectedKeys }) | 无 |
|
||||
| onDeselect | 取消选中时调用,仅在 multiple 生效 | Function({ item, key, selectedKeys }) | - |
|
||||
| onClick | 点击 menuitem 调用此函数,参数为 {item, key, keyPath} | function | - |
|
||||
|
@ -33,8 +33,8 @@
|
||||
"typings": "lib/index.d.ts",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"babel-runtime": "6.x",
|
||||
"array-tree-filter": "~1.0.0",
|
||||
"babel-runtime": "6.x",
|
||||
"classnames": "~2.2.0",
|
||||
"css-animation": "^1.2.5",
|
||||
"gregorian-calendar": "~4.1.0",
|
||||
@ -49,16 +49,16 @@
|
||||
"rc-dialog": "~6.2.1",
|
||||
"rc-dropdown": "~1.4.8",
|
||||
"rc-editor-mention": "^0.2.2",
|
||||
"rc-form": "~0.17.1",
|
||||
"rc-form": "~1.0.0",
|
||||
"rc-input-number": "~2.6.3",
|
||||
"rc-menu": "~4.13.0",
|
||||
"rc-menu": "^5.0.0",
|
||||
"rc-notification": "~1.3.4",
|
||||
"rc-pagination": "~1.5.3",
|
||||
"rc-progress": "~1.0.4",
|
||||
"rc-queue-anim": "~0.12.4",
|
||||
"rc-radio": "~2.0.0",
|
||||
"rc-rate": "~1.1.2",
|
||||
"rc-select": "~6.4.6",
|
||||
"rc-select": "^6.5.1",
|
||||
"rc-slider": "~4.0.0",
|
||||
"rc-steps": "~2.1.5",
|
||||
"rc-switch": "~1.4.2",
|
||||
|
@ -11,5 +11,33 @@ module.exports = {
|
||||
'app.header.menu.spec': 'Specification',
|
||||
'app.header.menu.resource': 'Resource',
|
||||
'app.header.lang': '中文',
|
||||
'app.home.slogan': 'One Design Language for UI',
|
||||
'app.home.start': 'Getting Started',
|
||||
'app.home.best-practice': 'Best Practice',
|
||||
'app.home.experience': 'Designed by experienced team, and showcase dozens of inspiring projects.',
|
||||
'app.home.design-pattern': 'Design Pattern',
|
||||
'app.home.pattern': 'Provide solutions for usual problems that may be encountered while developing enterprise-like complex UIs.',
|
||||
'app.home.reusable-components': 'Dozens of Reusable Components',
|
||||
'app.home.components-intro': 'Dozens of flexible and practical reusable components that increase your productivity.',
|
||||
'app.home.learn-more': 'Learn more',
|
||||
'app.home.sub-slogan': 'A Little Happiness in Hand',
|
||||
'app.home.vision': 'This is a design language dedicated to improve the user and design experience.',
|
||||
'app.footer.repo': 'Repository',
|
||||
'app.footer.scaffold': 'Scaffold',
|
||||
'app.footer.dev-tools': 'Developer Tools',
|
||||
'app.footer.dva': 'Framework',
|
||||
'app.footer.links': 'Links',
|
||||
'app.footer.mobile': 'Mobile',
|
||||
'app.footer.data-vis': 'Data Visualization',
|
||||
'app.footer.data-vis-spec': 'Specification of Data Visualization',
|
||||
'app.footer.motion': 'Motion',
|
||||
'app.footer.material': 'Sitemap Template',
|
||||
'app.footer.community': 'Community',
|
||||
'app.footer.change-log': 'Change Log',
|
||||
'app.footer.feedback': 'Feedback',
|
||||
'app.footer.discuss': 'Chat Room',
|
||||
'app.footer.bug-report': 'Bug Report',
|
||||
'app.footer.version': 'Version: ',
|
||||
'app.footer.author': 'Created by Ant UED',
|
||||
},
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import ScrollElement from 'rc-scroll-anim/lib/ScrollElement';
|
||||
import GitHubButton from 'react-github-button';
|
||||
import 'react-github-button/assets/style.css';
|
||||
@ -22,11 +23,12 @@ export default class Banner extends React.Component {
|
||||
<ScrollElement scrollName="banner" className="page">
|
||||
<QueueAnim className="banner-text-wrapper" type={this.typeFunc} delay={300}>
|
||||
<h2 key="h2">ANT <p>DESIGN</p></h2>
|
||||
<p key="content">一个 UI 设计语言</p>
|
||||
<p key="content"><FormattedMessage id="app.home.slogan" /></p>
|
||||
<span className="line" key="line" />
|
||||
<div key="button" className="start-button clearfix">
|
||||
<Link to="/docs/spec/introduce">
|
||||
<Icon type="smile-circle" /> 开始探索
|
||||
<Icon type="smile-circle" />
|
||||
<FormattedMessage id="app.home.start" />
|
||||
</Link>
|
||||
</div>
|
||||
<GitHubButton key="github-button" type="stargazers"
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import TweenOne from 'rc-tween-one';
|
||||
import ScrollOverPack from 'rc-scroll-anim/lib/ScrollOverPack';
|
||||
import { Icon, Button } from 'antd';
|
||||
@ -28,12 +29,12 @@ export default function Page1() {
|
||||
style={{ transform: 'translateX(-100px)', opacity: 0 }}
|
||||
/>
|
||||
<QueueAnim className="text-wrapper" delay={300} key="text" duration={550} leaveReverse>
|
||||
<h2 key="h2">最佳实践</h2>
|
||||
<p key="p" style={{ maxWidth: 310 }}>近一年的中后台设计实践,积累了大量的优秀案例。</p>
|
||||
<h2 key="h2"><FormattedMessage id="app.home.best-practice" /></h2>
|
||||
<p key="p" style={{ maxWidth: 310 }}><FormattedMessage id="app.home.experience" /></p>
|
||||
<div key="button">
|
||||
<Link to="/docs/practice/cases">
|
||||
<Button type="primary" size="large">
|
||||
了解更多
|
||||
<FormattedMessage id="app.home.learn-more" />
|
||||
<Icon type="right" />
|
||||
</Button>
|
||||
</Link>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Link } from 'react-router';
|
||||
import TweenOne from 'rc-tween-one';
|
||||
import ScrollOverPack from 'rc-scroll-anim/lib/ScrollOverPack';
|
||||
@ -14,12 +15,12 @@ export default function Page2() {
|
||||
<QueueAnim className="text-wrapper left-text" delay={300} key="text"
|
||||
duration={550} type="bottom" leaveReverse
|
||||
>
|
||||
<h2 key="h2">设计模式</h2>
|
||||
<p key="p" style={{ maxWidth: 260 }}>总结中后台设计中反复出现的问题,并提供相应的解决方案。</p>
|
||||
<h2 key="h2"><FormattedMessage id="app.home.design-pattern" /></h2>
|
||||
<p key="p" style={{ maxWidth: 260 }}><FormattedMessage id="app.home.pattern" /></p>
|
||||
<div key="button">
|
||||
<Link to="/docs/pattern/navigation">
|
||||
<Button type="primary" size="large">
|
||||
了解更多
|
||||
<FormattedMessage id="app.home.learn-more" />
|
||||
<Icon type="right" />
|
||||
</Button>
|
||||
</Link>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import TweenOne from 'rc-tween-one';
|
||||
import ScrollOverPack from 'rc-scroll-anim/lib/ScrollOverPack';
|
||||
import { Icon, Button } from 'antd';
|
||||
@ -17,12 +18,12 @@ export default function Page3() {
|
||||
<QueueAnim className="text-wrapper" delay={300} key="text" duration={550}
|
||||
leaveReverse style={{ top: '40%' }}
|
||||
>
|
||||
<h2 key="h2">丰富的基础组件</h2>
|
||||
<p key="p" style={{ maxWidth: 280 }}>丰富、灵活、实用的基础组件,为业务产品提供强有力的设计支持。</p>
|
||||
<h2 key="h2"><FormattedMessage id="app.home.reusable-components" /></h2>
|
||||
<p key="p" style={{ maxWidth: 280 }}><FormattedMessage id="app.home.components-intro" /></p>
|
||||
<div key="button">
|
||||
<Link to="/docs/react/introduce">
|
||||
<Button type="primary" size="large">
|
||||
了解更多
|
||||
<FormattedMessage id="app.home.learn-more" />
|
||||
<Icon type="right" />
|
||||
</Button>
|
||||
</Link>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import TweenOne from 'rc-tween-one';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import ScrollOverPack from 'rc-scroll-anim/lib/ScrollOverPack';
|
||||
import QueueAnim from 'rc-queue-anim';
|
||||
|
||||
@ -11,8 +12,8 @@ export default function Page4() {
|
||||
<QueueAnim className="text-wrapper-bottom" delay={300} key="text" duration={550}
|
||||
leaveReverse type="bottom"
|
||||
>
|
||||
<h2 key="h2">微小·确定·幸福</h2>
|
||||
<p key="p">这是一套致力于提升『用户』和『设计者』使用体验的中后台设计语言。</p>
|
||||
<h2 key="h2"><FormattedMessage id="app.home.sub-slogan" /></h2>
|
||||
<p key="p"><FormattedMessage id="app.home.vision" /></p>
|
||||
</QueueAnim>
|
||||
<TweenOne key="image" className="image4 bottom-wrapper" animation={{ y: 0, opacity: 1, duration: 550, delay: 550 }}
|
||||
style={{ transform: 'translateY(50px)', opacity: 0 }}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Select, Modal } from 'antd';
|
||||
import { version as antdVersion } from 'antd/package.json';
|
||||
import { docVersions } from '../../';
|
||||
@ -68,54 +69,67 @@ export default class Footer extends React.Component {
|
||||
<li>
|
||||
<h2>GitHub</h2>
|
||||
<div>
|
||||
<a target="_blank " href="https://github.com/ant-design/ant-design">仓库</a>
|
||||
<a target="_blank " href="https://github.com/ant-design/ant-design">
|
||||
<FormattedMessage id="app.footer.repo" />
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://github.com/ant-design/antd-init">antd-init</a> - 脚手架
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://github.com/ant-design/antd-init">antd-init</a> -
|
||||
<FormattedMessage id="app.footer.scaffold" />
|
||||
</div>
|
||||
<div>
|
||||
<a target="_blank" rel="noopener noreferrer" href="http://ant-tool.github.io">ant-tool</a> - 开发工具
|
||||
<a target="_blank" rel="noopener noreferrer" href="http://ant-tool.github.io">ant-tool</a> - <FormattedMessage id="app.footer.dev-tools" />
|
||||
</div>
|
||||
<div>
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://github.com/dvajs/dva">dva</a> - 应用框架
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://github.com/dvajs/dva">dva</a> - <FormattedMessage id="app.footer.dva" />
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<h2>相关站点</h2>
|
||||
<div><a href="http://mobile.ant.design">Ant Design Mobile</a> - 移动版</div>
|
||||
<div><a href="https://g2.alipay.com/">G2</a> - 数据可视化</div>
|
||||
<div><a href="https://antv.alipay.com/">AntV</a> - 数据可视化规范</div>
|
||||
<div><a href="http://motion.ant.design">Ant Motion</a> - 设计动效</div>
|
||||
<div><a href="http://ux.ant.design">Ant UX</a> - 页面逻辑素材</div>
|
||||
<h2><FormattedMessage id="app.footer.links" /></h2>
|
||||
<div><a href="http://mobile.ant.design">Ant Design Mobile</a> -
|
||||
<FormattedMessage id="app.footer.mobile" />
|
||||
</div>
|
||||
<div><a href="https://g2.alipay.com/">G2</a> -
|
||||
<FormattedMessage id="app.footer.data-vis" />
|
||||
</div>
|
||||
<div><a href="https://antv.alipay.com/">AntV</a> -
|
||||
<FormattedMessage id="app.footer.data-vis-spec" />
|
||||
</div>
|
||||
<div><a href="http://motion.ant.design">Ant Motion</a> -
|
||||
<FormattedMessage id="app.footer.motion" />
|
||||
</div>
|
||||
<div><a href="http://ux.ant.design">Ant UX</a> -
|
||||
<FormattedMessage id="app.footer.material" />
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<h2>社区</h2>
|
||||
<h2><FormattedMessage id="app.footer.community" /></h2>
|
||||
<div>
|
||||
<a target="_blank" rel="noopener noreferrer" href="http://ant.design/changelog">
|
||||
更新记录
|
||||
<FormattedMessage id="app.footer.change-log" />
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://github.com/ant-design/ant-design/issues">
|
||||
反馈和建议
|
||||
<FormattedMessage id="app.footer.feedback" />
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://gitter.im/ant-design/ant-design">
|
||||
讨论
|
||||
<FormattedMessage id="app.footer.discuss" />
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://github.com/ant-design/ant-design/issues/new">
|
||||
报告 Bug
|
||||
<FormattedMessage id="app.footer.bug-report" />
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>©2016 蚂蚁金服体验技术部出品</div>
|
||||
<div>©2016 <FormattedMessage id="app.footer.author" /></div>
|
||||
<div>Powered by <a href="https://github.com/benjycui/bisheng">BiSheng</a></div>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
文档版本:
|
||||
<FormattedMessage id="app.footer.version" />
|
||||
<Select
|
||||
size="small"
|
||||
dropdownMatchSelectWidth={false}
|
||||
|
@ -11,5 +11,33 @@ module.exports = {
|
||||
'app.header.menu.spec': '语言',
|
||||
'app.header.menu.resource': '资源',
|
||||
'app.header.lang': 'EN',
|
||||
'app.home.slogan': '一个 UI 设计语言',
|
||||
'app.home.start': '开始探索',
|
||||
'app.home.best-practice': '最佳实践',
|
||||
'app.home.experience': '近一年的中后台设计实践,积累了大量的优秀案例。',
|
||||
'app.home.design-pattern': '设计模式',
|
||||
'app.home.pattern': '总结中后台设计中反复出现的问题,并提供相应的解决方案。',
|
||||
'app.home.reusable-components': '丰富的基础组件',
|
||||
'app.home.components-intro': '丰富、灵活、实用的基础组件,为业务产品提供强有力的设计支持。',
|
||||
'app.home.learn-more': '了解更多',
|
||||
'app.home.sub-slogan': '微小·确定·幸福',
|
||||
'app.home.vision': '这是一套致力于提升『用户』和『设计者』使用体验的中后台设计语言。',
|
||||
'app.footer.repo': '仓库',
|
||||
'app.footer.scaffold': '脚手架',
|
||||
'app.footer.dev-tools': '开发工具',
|
||||
'app.footer.dva': '应用框架',
|
||||
'app.footer.links': '相关站点',
|
||||
'app.footer.mobile': '移动版',
|
||||
'app.footer.data-vis': '数据可视化',
|
||||
'app.footer.data-vis-spec': '数据可视化规范',
|
||||
'app.footer.motion': '设计动效',
|
||||
'app.footer.material': '页面逻辑素材',
|
||||
'app.footer.community': '社区',
|
||||
'app.footer.change-log': '更新记录',
|
||||
'app.footer.feedback': '反馈和建议',
|
||||
'app.footer.discuss': '讨论',
|
||||
'app.footer.bug-report': '报告 Bug,',
|
||||
'app.footer.version': '文档版本:',
|
||||
'app.footer.author': '蚂蚁金服体验技术部出品',
|
||||
},
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user