Merge branch 'master' into feature

This commit is contained in:
陈帅 2019-06-28 21:55:15 +08:00
commit 722b39ec16
24 changed files with 264 additions and 387 deletions

View File

@ -1,5 +0,0 @@
const config = {
plugins: ['remark-preset-lint-recommended', ['remark-lint-list-item-indent', 'space']],
};
module.exports = config;

View File

@ -136,7 +136,16 @@ class CheckboxGroup extends React.Component<CheckboxGroupProps, CheckboxGroupSta
}
const onChange = this.props.onChange;
if (onChange) {
onChange(value.filter(val => registeredValues.indexOf(val) !== -1));
const options = this.getOptions();
onChange(
value
.filter(val => registeredValues.indexOf(val) !== -1)
.sort((a, b) => {
const indexA = options.findIndex(opt => opt.value === a);
const indexB = options.findIndex(opt => opt.value === b);
return indexA - indexB;
}),
);
}
};

View File

@ -133,4 +133,38 @@ describe('CheckboxGroup', () => {
expect(onChange).toHaveBeenCalledWith([2]);
});
// https://github.com/ant-design/ant-design/issues/17297
it('onChange should keep the order of the original values', () => {
const onChange = jest.fn();
const wrapper = mount(
<Checkbox.Group onChange={onChange}>
<Checkbox key={1} value={1} />
<Checkbox key={2} value={2} />
<Checkbox key={3} value={3} />
<Checkbox key={4} value={4} />
</Checkbox.Group>,
);
wrapper
.find('.ant-checkbox-input')
.at(0)
.simulate('change');
expect(onChange).toHaveBeenCalledWith([1]);
wrapper
.find('.ant-checkbox-input')
.at(1)
.simulate('change');
expect(onChange).toHaveBeenCalledWith([1, 2]);
wrapper
.find('.ant-checkbox-input')
.at(0)
.simulate('change');
expect(onChange).toHaveBeenCalledWith([2]);
wrapper
.find('.ant-checkbox-input')
.at(0)
.simulate('change');
expect(onChange).toHaveBeenCalledWith([1, 2]);
});
});

View File

@ -56,7 +56,7 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke
| dropdownClassName | to customize the className of the popup calendar | string | - |
| getCalendarContainer | to set the container of the floating layer, while the default is to create a `div` element in `body` | function(trigger) | - |
| locale | localization configuration | object | [default](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json) |
| mode | picker panel mode | `time|date|month|year|decade` | 'date' |
| mode | picker panel mode[Cannot select year or month anymore?](/docs/react/faq#When-set-mode-to-DatePicker/RangePicker,-cannot-select-year-or-month-anymore?) | `time|date|month|year|decade` | 'date' |
| open | open state of picker | boolean | - |
| placeholder | placeholder of date input | string\|RangePicker\[] | - |
| popupStyle | to customize the style of the popup calendar | object | {} |
@ -88,6 +88,7 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke
| value | to set date | [moment](http://momentjs.com/) | - |
| onChange | a callback function, can be executed when the selected time is changing | function(date: moment, dateString: string) | - |
| onOk | callback when click ok button | function() | - |
| onPanelChange | Callback function for panel changing | function(value, mode) | - |
### MonthPicker

View File

@ -58,6 +58,7 @@ moment.locale('zh-cn');
| dropdownClassName | 额外的弹出日历 className | string | - |
| getCalendarContainer | 定义浮层的容器,默认为 body 上新建 div | function(trigger) | 无 |
| locale | 国际化配置 | object | [默认配置](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json) |
| mode | 日期面板的状态([设置后无法选择年份/月份?](/docs/react/faq#当我指定了-DatePicker/RangePicker-的-mode-属性后,点击后无法选择年份/月份?) | `time|date|month|year|decade` | 'date' |
| open | 控制弹层是否展开 | boolean | - |
| placeholder | 输入框提示文字 | string\|RangePicker\[] | - |
| popupStyle | 额外的弹出日历样式 | object | {} |
@ -82,7 +83,6 @@ moment.locale('zh-cn');
| defaultPickerValue | 默认面板日期 | [moment](http://momentjs.com/) | 无 |
| disabledTime | 不可选择的时间 | function(date) | 无 |
| format | 设置日期格式,为数组时支持多格式匹配,展示以第一个为准。配置参考 [moment.js](http://momentjs.com/) | string \| string[] | "YYYY-MM-DD" |
| mode | 日期面板的状态 | `time|date|month|year|decade` | 'date' |
| renderExtraFooter | 在面板中添加额外的页脚 | (mode) => React.ReactNode | - |
| showTime | 增加时间选择功能 | Object\|boolean | [TimePicker Options](/components/time-picker/#API) |
| showTime.defaultValue | 设置用户选择日期时默认的时分秒,[例子](#components-date-picker-demo-disabled-date) | [moment](http://momentjs.com/) | moment() |
@ -141,4 +141,4 @@ moment.locale('zh-cn');
## FAQ
- [当我指定了 DatePicker/RangePicker 的 `mode` 属性后,点击后无法选择年份/月份?](/docs/react/faq-cn#当我指定了-DatePicker/RangePicker-的-mode-属性后,点击后无法选择年份/月份?)
- [当我指定了 DatePicker/RangePicker 的 mode 属性后,点击后无法选择年份/月份?](/docs/react/faq#当我指定了-DatePicker/RangePicker-的-mode-属性后,点击后无法选择年份/月份?)

View File

@ -105,7 +105,7 @@ exports[`renders ./components/descriptions/demo/basic.md correctly 1`] = `
exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
<div
class="ant-descriptions bordered"
class="ant-descriptions ant-descriptions-bordered"
>
<div
class="ant-descriptions-title"
@ -120,33 +120,33 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
<tr
class="ant-descriptions-row"
>
<td
<th
class="ant-descriptions-item-label"
>
Product
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="1"
>
Cloud Database
</td>
<td
<th
class="ant-descriptions-item-label"
>
Billing Mode
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="1"
>
Prepaid
</td>
<td
<th
class="ant-descriptions-item-label"
>
Automatic Renewal
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="1"
@ -157,22 +157,22 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
<tr
class="ant-descriptions-row"
>
<td
<th
class="ant-descriptions-item-label"
>
Order time
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="1"
>
2018-04-24 18:00:00
</td>
<td
<th
class="ant-descriptions-item-label"
>
Usage Time
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="5"
@ -183,11 +183,11 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
<tr
class="ant-descriptions-row"
>
<td
<th
class="ant-descriptions-item-label"
>
Status
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="5"
@ -209,33 +209,33 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
<tr
class="ant-descriptions-row"
>
<td
<th
class="ant-descriptions-item-label"
>
Negotiated Amount
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="1"
>
$80.00
</td>
<td
<th
class="ant-descriptions-item-label"
>
Discount
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="1"
>
$20.00
</td>
<td
<th
class="ant-descriptions-item-label"
>
Official Receipts
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="1"
@ -246,11 +246,11 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
<tr
class="ant-descriptions-row"
>
<td
<th
class="ant-descriptions-item-label"
>
Config Info
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="5"
@ -491,7 +491,7 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
<br />
<br />
<div
class="ant-descriptions bordered"
class="ant-descriptions ant-descriptions-bordered"
>
<div
class="ant-descriptions-title"
@ -506,33 +506,33 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
<tr
class="ant-descriptions-row"
>
<td
<th
class="ant-descriptions-item-label"
>
Product
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="1"
>
Cloud Database
</td>
<td
<th
class="ant-descriptions-item-label"
>
Billing
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="1"
>
Prepaid
</td>
<td
<th
class="ant-descriptions-item-label"
>
time
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="1"
@ -543,33 +543,33 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
<tr
class="ant-descriptions-row"
>
<td
<th
class="ant-descriptions-item-label"
>
Amount
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="1"
>
$80.00
</td>
<td
<th
class="ant-descriptions-item-label"
>
Discount
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="1"
>
$20.00
</td>
<td
<th
class="ant-descriptions-item-label"
>
Official
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="1"
@ -580,11 +580,11 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
<tr
class="ant-descriptions-row"
>
<td
<th
class="ant-descriptions-item-label"
>
Config Info
</td>
</th>
<td
class="ant-descriptions-item-content"
colspan="5"

View File

@ -1,5 +1,56 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Descriptions Descriptions.Item support className 1`] = `
<Descriptions
column={
Object {
"lg": 3,
"md": 3,
"sm": 2,
"xl": 3,
"xs": 1,
"xxl": 3,
}
}
size="default"
>
<div
className="ant-descriptions"
>
<div
className="ant-descriptions-view"
>
<table>
<tbody>
<tr
className="ant-descriptions-row"
key="0"
>
<td
className="ant-descriptions-item my-class"
colSpan={1}
>
<span
className="ant-descriptions-item-label"
key="label"
>
Product
</span>
<span
className="ant-descriptions-item-content"
key="content"
>
Cloud Database
</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</Descriptions>
`;
exports[`Descriptions column is number 1`] = `
<Descriptions
column="3"

View File

@ -42,9 +42,11 @@ describe('Descriptions', () => {
<Descriptions.Item label="Billing">Prepaid</Descriptions.Item>
<Descriptions.Item label="time">18:00:00</Descriptions.Item>
<Descriptions.Item label="Amount">$80.00</Descriptions.Item>
<Descriptions.Item>No-Label</Descriptions.Item>
</Descriptions>,
);
expect(wrapper.find('tr')).toHaveLength(4);
expect(wrapper.find('tr')).toHaveLength(5);
expect(wrapper.find('.ant-descriptions-item-no-label')).toHaveLength(1);
enquire.callunmatch();
wrapper.unmount();
@ -138,4 +140,15 @@ describe('Descriptions', () => {
expect(wrapper).toMatchSnapshot();
wrapper.unmount();
});
it('Descriptions.Item support className', () => {
const wrapper = mount(
<Descriptions>
<Descriptions.Item label="Product" className="my-class">
Cloud Database
</Descriptions.Item>
</Descriptions>,
);
expect(wrapper).toMatchSnapshot();
});
});

View File

@ -10,6 +10,7 @@ import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface DescriptionsItemProps {
prefixCls?: string;
className?: string;
label?: React.ReactNode;
children: React.ReactNode;
span?: number;
@ -70,29 +71,43 @@ const generateChildrenRows = (
/**
* This code is for handling react15 does not support returning an array,
* It can convert a children into two td
* It can convert a children into th and td
* @param child DescriptionsItem
* @returns
* <>
* <td>{DescriptionsItem.label}</td>
* <th>{DescriptionsItem.label}</th>
* <td>{DescriptionsItem.children}</td>
* </>
*/
const renderCol = (child: React.ReactElement<DescriptionsItemProps>, bordered: boolean) => {
const { prefixCls, label, children, span = 1 } = child.props;
const { prefixCls, label, className, children, span = 1 } = child.props;
if (bordered) {
return [
<td className={`${prefixCls}-item-label`} key="label">
<th
className={classNames(`${prefixCls}-item-label`, className, {
[`${prefixCls}-item-no-label`]: !label,
})}
key="label"
>
{label}
</td>,
<td className={`${prefixCls}-item-content`} key="content" colSpan={span * 2 - 1}>
</th>,
<td
className={classNames(`${prefixCls}-item-content`, className)}
key="content"
colSpan={span * 2 - 1}
>
{children}
</td>,
];
}
return (
<td colSpan={span} className={`${prefixCls}-item`}>
<span className={`${prefixCls}-item-label`} key="label">
<td colSpan={span} className={classNames(`${prefixCls}-item`, className)}>
<span
className={classNames(`${prefixCls}-item-label`, {
[`${prefixCls}-item-no-label`]: !label,
})}
key="label"
>
{label}
</span>
<span className={`${prefixCls}-item-content`} key="content">
@ -288,8 +303,8 @@ class Descriptions extends React.Component<
return (
<div
className={classNames(prefixCls, className, {
[size as string]: size !== 'default',
bordered,
[`${prefixCls}-${size}`]: size !== 'default',
[`${prefixCls}-bordered`]: !!bordered,
})}
>
{title && <div className={`${prefixCls}-title`}>{title}</div>}

View File

@ -27,6 +27,7 @@
}
&-row {
> th,
> td {
padding-bottom: 16px;
}
@ -37,9 +38,11 @@
&-item-label {
color: @heading-color;
font-weight: normal;
font-size: @font-size-base;
line-height: @line-height-base;
white-space: nowrap;
&::after {
position: relative;
top: -0.5px;
@ -48,6 +51,13 @@
}
}
&-item-no-label {
&::after {
content: '';
margin: 0;
}
}
&-item-content {
display: table-cell;
color: @text-color;
@ -60,55 +70,23 @@
> span {
display: inline-block;
}
.@{descriptions-prefix-cls}-item-label {
float: left;
padding: 0 !important;
}
.@{descriptions-prefix-cls}-item-content {
float: left;
padding: 0 !important;
}
}
// padding setting
.@{descriptions-prefix-cls}-item-label,
.@{descriptions-prefix-cls}-item-content {
padding: @descriptions-default-padding;
}
&.bordered.middle {
.@{descriptions-prefix-cls}-item-label,
.@{descriptions-prefix-cls}-item-content {
padding: @descriptions-middle-padding;
}
}
&.bordered.small {
.@{descriptions-prefix-cls}-item-label,
.@{descriptions-prefix-cls}-item-content {
padding: @descriptions-small-padding;
}
}
&.bordered {
&-bordered {
.@{descriptions-prefix-cls}-view {
border: 1px solid @border-color-split;
> table {
table-layout: auto;
}
}
.@{descriptions-prefix-cls}-item-label,
.@{descriptions-prefix-cls}-item-content {
padding: @descriptions-default-padding;
border-right: 1px solid @border-color-split;
}
.@{descriptions-prefix-cls}-item-label:last-child,
.@{descriptions-prefix-cls}-item-content:last-child {
border-right: none;
}
.@{descriptions-prefix-cls}-row {
border-bottom: 1px solid @border-color-split;
&:last-child {
border-bottom: none;
border-right: none;
}
}
@ -118,5 +96,26 @@
display: none;
}
}
.@{descriptions-prefix-cls}-row {
border-bottom: 1px solid @border-color-split;
&:last-child {
border-bottom: none;
}
}
&.@{descriptions-prefix-cls}-middle {
.@{descriptions-prefix-cls}-item-label,
.@{descriptions-prefix-cls}-item-content {
padding: @descriptions-middle-padding;
}
}
&.@{descriptions-prefix-cls}-small {
.@{descriptions-prefix-cls}-item-label,
.@{descriptions-prefix-cls}-item-content {
padding: @descriptions-small-padding;
}
}
}
}

View File

@ -211,6 +211,14 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
wrapClassName,
width,
height,
closable,
destroyOnClose,
mask,
maskClosable,
bodyStyle,
title,
push,
onClose,
...rest
} = this.props;
warning(
@ -218,7 +226,7 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
'Drawer',
'wrapClassName is deprecated, please use className instead.',
);
const haveMask = rest.mask ? '' : 'no-mask';
const haveMask = mask ? '' : 'no-mask';
this.parentDrawer = value;
const offsetStyle: any = {};
if (placement === 'left' || placement === 'right') {
@ -235,7 +243,7 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
prefixCls={prefixCls}
open={this.props.visible}
onMaskClick={this.onMaskClick}
showMask={this.props.mask}
showMask={mask}
placement={placement}
style={this.getRcDrawerStyle()}
className={classNames(wrapClassName, className, haveMask)}

View File

@ -56,35 +56,6 @@
}
}
// Radio && Checkbox
input[type='radio'],
input[type='checkbox'] {
&[disabled],
&.disabled {
cursor: not-allowed;
}
}
// These classes are used directly on <label>s
.@{ant-prefix}-radio-inline,
.@{ant-prefix}-radio-vertical,
.@{ant-prefix}-checkbox-inline,
.@{ant-prefix}-checkbox-vertical {
&.disabled {
cursor: not-allowed;
}
}
// These classes are used on elements with <label> descendants
.@{ant-prefix}-radio,
.@{ant-prefix}-checkbox {
&.disabled {
label {
cursor: not-allowed;
}
}
}
// Form items
// You should wrap labels and controls in .@{form-prefix-cls}-item for optimum spacing
.@{form-prefix-cls}-item {
@ -287,33 +258,6 @@ form {
}
}
// Input combined with select
.@{ant-prefix}-input-group-wrap {
.@{ant-prefix}-select-selection {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
&:hover {
border-color: @border-color-base;
}
}
.@{ant-prefix}-select-selection--single {
height: @input-height-lg;
margin-left: -1px;
background-color: fade(@black, 7%);
.@{ant-prefix}-select-selection__rendered {
padding-right: 25px;
padding-left: 8px;
line-height: 30px;
}
}
.@{ant-prefix}-select-open .@{ant-prefix}-select-selection {
border-color: @border-color-base;
box-shadow: none;
}
}
// Form layout
//== Vertical Form
.make-vertical-layout-label() {

View File

@ -11,6 +11,7 @@
position: relative;
display: inline-block;
height: auto;
line-height: unset;
padding: 0;
overflow: hidden;
white-space: pre-wrap;
@ -58,6 +59,7 @@
border: none;
outline: none;
resize: none;
.placeholder();
&:read-only {
cursor: default;

View File

@ -7,14 +7,18 @@ import Wave from '../_util/wave';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export type SwitchSize = 'small' | 'default';
export type SwitchChangeEventHandler = (checked: boolean, event: MouseEvent) => void;
export type SwitchClickEventHandler = SwitchChangeEventHandler;
export interface SwitchProps {
prefixCls?: string;
size?: 'small' | 'default';
size?: SwitchSize;
className?: string;
checked?: boolean;
defaultChecked?: boolean;
onChange?: (checked: boolean, event: MouseEvent) => void;
onClick?: (checked: boolean, event: MouseEvent) => void;
onChange?: SwitchChangeEventHandler;
onClick?: SwitchChangeEventHandler;
checkedChildren?: React.ReactNode;
unCheckedChildren?: React.ReactNode;
disabled?: boolean;

View File

@ -191,28 +191,28 @@ Properties for row selection.
import { Table } from 'antd';
import { ColumnProps } from 'antd/lib/table';
interface IUser {
interface User {
key: number,
name: string;
}
const columns: ColumnProps<IUser>[] = [{
const columns: ColumnProps<User>[] = [{
key: 'name',
title: 'Name',
dataIndex: 'name',
}];
const data: IUser[] = [{
const data: User[] = [{
key: 0,
name: 'Jack',
}];
class UserTable extends Table<IUser> {}
class UserTable extends Table<User> {}
<UserTable columns={columns} dataSource={data} />
// Use JSX style API
class NameColumn extends Table.Column<IUser> {}
class NameColumn extends Table.Column<User> {}
<UserTable dataSource={data}>
<NameColumn key="name" title="Name" dataIndex="name" />
@ -220,9 +220,9 @@ class NameColumn extends Table.Column<IUser> {}
// after TypeScript 2.9 can write like this
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#generic-type-arguments-in-jsx-elements
<Table<IUser> columns={columns} dataSource={data} />
<Table<IUser> dataSource={data}>
<Table.Column<IUser> key="name" title="Name" dataIndex="name" />
<Table<User> columns={columns} dataSource={data} />
<Table<User> dataSource={data}>
<Table.Column<User> key="name" title="Name" dataIndex="name" />
</Table>
```

View File

@ -196,27 +196,27 @@ const columns = [
import { Table } from 'antd';
import { ColumnProps } from 'antd/lib/table';
interface IUser {
interface User {
key: number;
name: string;
}
const columns: ColumnProps<IUser>[] = [{
const columns: ColumnProps<User>[] = [{
key: 'name',
title: 'Name',
dataIndex: 'name',
}];
const data: IUser[] = [{
const data: User[] = [{
key: 0,
name: 'Jack',
}];
class UserTable extends Table<IUser> {}
class UserTable extends Table<User> {}
<UserTable columns={columns} dataSource={data} />
// 使用 JSX 风格的 API
class NameColumn extends Table.Column<IUser> {}
class NameColumn extends Table.Column<User> {}
<UserTable dataSource={data}>
<NameColumn key="name" title="Name" dataIndex="name" />
@ -224,9 +224,9 @@ class NameColumn extends Table.Column<IUser> {}
// TypeScript 2.9 之后也可以这样写
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#generic-type-arguments-in-jsx-elements
<Table<IUser> columns={columns} dataSource={data} />
<Table<IUser> dataSource={data}>
<Table.Column<IUser> key="name" title="Name" dataIndex="name" />
<Table<User> columns={columns} dataSource={data} />
<Table<User> dataSource={data}>
<Table.Column<User> key="name" title="Name" dataIndex="name" />
</Table>
```

View File

@ -73,9 +73,9 @@
> .@{table-prefix-cls}-thead > tr > th,
> .@{table-prefix-cls}-tbody > tr > td {
padding: @table-padding-vertical-sm @table-padding-horizontal-sm;
background-color: transparent;
}
> .@{table-prefix-cls}-thead > tr {
background-color: transparent;
border-bottom: @border-width-base @border-style-base @border-color-split;
}
> .@{table-prefix-cls}-thead > tr > th.@{table-prefix-cls}-column-sort {

View File

@ -86,6 +86,16 @@ export interface AntTreeNodeDropEvent {
event: React.MouseEvent<HTMLElement>;
}
export interface TreeNodeNormal {
title?: React.ReactNode;
key: string;
isLeaf?: boolean;
disabled?: boolean;
disableCheckbox?: boolean;
selectable?: boolean;
children?: TreeNodeNormal[];
}
export interface TreeProps {
showLine?: boolean;
className?: string;
@ -153,6 +163,7 @@ export interface TreeProps {
filterTreeNode?: (node: AntTreeNode) => boolean;
children?: React.ReactNode;
blockNode?: boolean;
treeData?: Array<TreeNodeNormal>;
}
export default class Tree extends React.Component<TreeProps, any> {

View File

@ -46,6 +46,7 @@ Almost anything can be represented in a tree structure. Examples include directo
| onLoad | Callback function for when a treeNode is loaded | function(loadedKeys, {event, node}) | - |
| onRightClick | Callback function for when the user right clicks a treeNode | function({event, node}) | - |
| onSelect | Callback function for when the user clicks a treeNode | function(selectedKeys, e:{selected: bool, selectedNodes, node, event}) | - |
| treeData | treeNodes data Array, if set it then you need not to construct children TreeNode. (key should be unique across the whole array) | array\<{ key, title, children, \[disabled, selectable] }> | - |
### TreeNode props

View File

@ -47,6 +47,7 @@ subtitle: 树形控件
| onLoad | 节点加载完毕时触发 | function(loadedKeys, {event, node}) | - |
| onRightClick | 响应右键点击 | function({event, node}) | - |
| onSelect | 点击树节点触发 | function(selectedKeys, e:{selected: bool, selectedNodes, node, event}) | - |
| treeData | treeNodes 数据,如果设置则不需要手动构造 TreeNode 节点key 在整个树范围内唯一) | array\<{key, title, children, \[disabled, selectable]}> | - |
### TreeNode props

View File

@ -2,10 +2,6 @@
publish = "_site"
command = "npm run site"
[context.production]
command = "echo build"
publish = "."
[[redirects]]
from = "/docs/resource/download"
to = "/docs/spec/download"

View File

@ -64,7 +64,7 @@
"rc-checkbox": "~2.1.6",
"rc-collapse": "~1.11.3",
"rc-dialog": "~7.4.0",
"rc-drawer": "~1.9.8",
"rc-drawer": "~1.10.1",
"rc-dropdown": "~2.4.1",
"rc-editor-mention": "^1.1.13",
"rc-form": "^2.4.5",
@ -106,9 +106,8 @@
"@types/react-intl": "^2.3.17",
"@types/warning": "^3.0.0",
"@yesmeck/offline-plugin": "^5.0.5",
"ansi-styles": "^4.0.0",
"antd-theme-generator": "^1.1.6",
"antd-tools": "^7.3.5",
"antd-tools": "^7.6.0",
"babel-eslint": "^10.0.1",
"babel-plugin-add-react-displayname": "^0.0.5",
"bisheng": "^1.2.4",
@ -128,7 +127,7 @@
"enzyme-to-json": "^3.3.5",
"eslint": "^6.0.0",
"eslint-config-airbnb": "^17.1.0",
"eslint-config-prettier": "^5.0.0",
"eslint-config-prettier": "^6.0.0",
"eslint-plugin-babel": "^5.3.0",
"eslint-plugin-import": "^2.17.3",
"eslint-plugin-jest": "^22.6.4",
@ -147,7 +146,6 @@
"logrocket": "^1.0.0",
"logrocket-react": "^3.0.0",
"lz-string": "^1.4.4",
"majo": "^0.8.0",
"mockdate": "^2.0.2",
"node-fetch": "^2.6.0",
"pre-commit": "^1.2.2",
@ -170,18 +168,11 @@
"react-infinite-scroller": "^1.2.4",
"react-intl": "^2.9.0",
"react-resizable": "^1.8.0",
"react-router": "3.2.1",
"react-router": "^3.2.3",
"react-router-dom": "^5.0.1",
"react-sticky": "^6.0.3",
"react-test-renderer": "^16.8.6",
"react-virtualized": "~9.21.1",
"remark-cli": "^6.0.1",
"remark-frontmatter": "^1.3.1",
"remark-lint": "^6.0.4",
"remark-parse": "^6.0.3",
"remark-preset-lint-recommended": "^3.0.2",
"remark-stringify": "^6.0.4",
"remark-yaml-config": "^4.0.3",
"reqwest": "^2.0.5",
"rimraf": "^2.6.3",
"scrollama": "^2.0.0",
@ -193,7 +184,6 @@
"stylelint-declaration-block-no-ignored-properties": "^2.1.0",
"stylelint-order": "^3.0.0",
"typescript": "~3.5.1",
"unified": "^7.1.0",
"xhr-mock": "^2.4.1",
"xhr2": "^0.2.0"
},
@ -214,7 +204,8 @@
"lint-fix:code": "eslint --fix tests site scripts components ./.*.js ./webpack.config.js --ext '.js,.jsx'",
"lint-fix:demo": "eslint-tinker ./components/*/demo/*.md",
"lint-fix:style": "stylelint --fix '{site,components}/**/*.less' --syntax less",
"sort-api": "node ./scripts/sort-api-table.js",
"sort-api": "antd-tools run sort-api-table",
"api-collection": "antd-tools run api-collection",
"dist": "antd-tools run dist",
"compile": "antd-tools run compile",
"tsc": "tsc",

View File

@ -1,66 +0,0 @@
// Read all the api from current documents
const glob = require('glob');
const fs = require('fs');
const COMPONENT_NAME = /components\/([^/]*)/;
const PROP_NAME = /^\s*\|\s*([^\s|]*)/;
const components = {};
function mappingPropLine(component, line) {
const propMatch = line.match(PROP_NAME);
if (!propMatch) return;
const propName = propMatch[1];
if (!/^[a-z]/.test(propName)) return;
components[component] = Array.from(new Set([...(components[component] || []), propName]));
}
function apiReport(entities) {
const apis = {};
Object.keys(entities).forEach(component => {
const apiList = entities[component];
apiList.forEach(api => {
if (typeof apis[api] === 'function') {
apis[api] = [];
}
apis[api] = [...(apis[api] || []), component];
});
});
return apis;
}
function printReport(apis) {
const apiList = Object.keys(apis).map(api => ({
name: api,
componentList: apis[api],
}));
apiList.sort((a, b) => b.componentList.length - a.componentList.length);
// eslint-disable-next-line no-console
console.log('| name | components | comments |');
// eslint-disable-next-line no-console
console.log('| ---- | ---------- | -------- |');
apiList.forEach(({ name, componentList }) => {
// eslint-disable-next-line no-console
console.log('|', name, '|', componentList.join(', '), '| |');
});
}
glob('components/*/*.md', (error, files) => {
files.forEach(filePath => {
// Read md file to parse content
const content = fs.readFileSync(filePath, 'utf8');
const component = filePath.match(COMPONENT_NAME)[1];
// Parse lines to get API
const lines = content.split(/[\r\n]+/);
lines.forEach(line => {
mappingPropLine(component, line);
});
});
printReport(apiReport(components));
});

View File

@ -1,132 +0,0 @@
const program = require('commander');
const majo = require('majo');
const style = require('ansi-styles');
const unified = require('unified');
const parse = require('remark-parse');
const stringify = require('remark-stringify');
const yamlConfig = require('remark-yaml-config');
const frontmatter = require('remark-frontmatter');
const remarkWithYaml = unified()
.use(parse)
.use(stringify, {
paddedTable: false,
listItemIndent: 1,
})
.use(frontmatter)
.use(yamlConfig);
const stream = majo();
function getCellValue(node) {
return node.children[0].children[0].value;
}
// from small to large
const sizeBreakPoints = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
const groups = {
isDynamic: val => /^on[A-Z]/.test(val),
isSize: val => sizeBreakPoints.indexOf(val) > -1,
};
function asciiSort(prev, next) {
if (prev > next) {
return 1;
}
if (prev < next) {
return -1;
}
return 0;
}
// follow the alphabet order
function alphabetSort(nodes) {
// use toLowerCase to keep `case insensitive`
return nodes.sort((...comparison) =>
asciiSort(...comparison.map(val => getCellValue(val).toLowerCase())),
);
}
function sizeSort(nodes) {
return nodes.sort((...comparison) =>
asciiSort(...comparison.map(val => sizeBreakPoints.indexOf(getCellValue(val).toLowerCase()))),
);
}
function sort(ast) {
ast.children.forEach(child => {
const staticProps = [];
// prefix with `on`
const dynamicProps = [];
// one of ['xs', 'sm', 'md', 'lg', 'xl']
const sizeProps = [];
// find table markdown type
if (child.type === 'table') {
// slice will create new array, so sort can affect the original array.
// slice(1) cut down the thead
child.children.slice(1).forEach(node => {
const value = getCellValue(node);
if (groups.isDynamic(value)) {
dynamicProps.push(node);
} else if (groups.isSize(value)) {
sizeProps.push(node);
} else {
staticProps.push(node);
}
});
// eslint-disable-next-line
child.children = [
child.children[0],
...alphabetSort(staticProps),
...sizeSort(sizeProps),
...alphabetSort(dynamicProps),
];
}
});
return ast;
}
function sortAPI(md) {
return remarkWithYaml.stringify(sort(remarkWithYaml.parse(md)));
}
program
.version('0.1.0')
.option(
'-f, --file [file]',
'Specify which file to be transformed',
// default value
'components/**/index.+(zh-CN|en-US).md',
)
.parse(process.argv);
function sortMiddleware(ctx) {
Object.keys(ctx.files).forEach(filename => {
const content = ctx.fileContents(filename);
ctx.writeContents(filename, sortAPI(content));
});
}
// Get the markdown file all need to be transformed
stream
.source(program.file)
.use(sortMiddleware)
.dest('.')
.then(() => {
/* eslint-disable no-console */
console.log(`${style.green.open}sort ant-design api successfully!${style.green.close}`);
/* eslint-enable no-console */
});
module.exports = {
getCellValue,
sort,
};