diff --git a/docs/date-picker/index.en-us.md b/docs/date-picker/index.en-us.md
index af11ebb5e4..b735a43974 100644
--- a/docs/date-picker/index.en-us.md
+++ b/docs/date-picker/index.en-us.md
@@ -27,7 +27,7 @@ DatePicker are used to select a single date for an input.
| format | Format of date value (it will also effect user input) | String | 'YYYY-MM-DD' |
| showTime | Enable time-picker, pass object like `{ defaultValue, format, ... }` | Object/Boolean | false |
| resetTime | If reset time for every re-select | Boolean | false |
-| disabledDate | Function to disable date
**signature**:
Function(dateValue: MomentObject) => Boolean
**parameter**:
_dateValue_: {MomentObject} null
**return**:
{Boolean} if disable current date
| Function | () => false |
+| disabledDate | Function to disable date
**signature**:
Function(dateValue: MomentObject) => Boolean
**parameter**:
_dateValue_: {MomentObject} null
_view_: {Enum} current view type: 'year', 'month', 'date'
**return**:
{Boolean} if disable current date
| Function | () => false |
| footerRender | Template render for custom footer
**signature**:
Function() => Node
**return**:
{Node} Custom footer
| Function | () => null |
| onChange | Callback when date changes
**signature**:
Function() => MomentObject
**return**:
{MomentObject} dateValue
| Function | func.noop |
| onOk | Callback when click the ok button
**signature**:
Function() => MomentObject
**return**:
{MomentObject} dateValue
| Function | func.noop |
@@ -54,7 +54,7 @@ DatePicker are used to select a single date for an input.
| format | Date format | String | 'YYYY-MM-DD' |
| showTime | Enable time picker | Object/Boolean | false |
| resetTime | If reset time for every select | Boolean | false |
-| disabledDate | Function to disable dates
**signature**:
Function(dateValue: MomentObject) => Boolean
**parameter**:
_dateValue_: {MomentObject} null
**return**:
{Boolean} if disabled
| Function | () => false |
+| disabledDate | Function to disable dates
**signature**:
Function(dateValue: MomentObject) => Boolean
**parameter**:
_dateValue_: {MomentObject} null
_view_: {Enum} current view type: 'year', 'month', 'date'
**return**:
{Boolean} if disabled
| Function | () => false |
| footerRender | Template render for footer
**signature**:
Function() => Node
**return**:
{Node} custom footer
| Function | () => null |
| onChange | Callback when date changes
**signature**:
Function() => MomentObject
**return**:
{MomentObject} range values
| Function | func.noop |
| onOk | Callback when click ok button
**signature**:
Function() => MomentObject
**return**:
{MomentObject} range values
| Function | func.noop |
@@ -82,4 +82,3 @@ DatePicker are used to select a single date for an input.
| number key | Need to manual input the date, the specified date format |
| Enter | open the calendar or select date |
| Esc | close the calendar |
-
\ No newline at end of file
diff --git a/docs/date-picker/index.md b/docs/date-picker/index.md
index 5cd564b838..07c6e904a9 100644
--- a/docs/date-picker/index.md
+++ b/docs/date-picker/index.md
@@ -89,123 +89,123 @@ DatePicker 默认情况下接收和返回的数据类型都是 Moment 对象。
### DatePicker
-| 参数 | 说明 | 类型 | 默认值 |
-| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | ------------ |
-| label | 输入框内置标签 | ReactNode | - |
-| size | 输入框尺寸
**可选值**:
'small', 'medium', 'large' | Enum | 'medium' |
-| state | 输入框状态
**可选值**:
'success', 'loading', 'error' | Enum | - |
-| placeholder | 输入提示 | String | - |
-| defaultVisibleMonth | 默认展现的月
**签名**:
Function() => MomentObject
**返回值**:
{MomentObject} 返回包含指定月份的 moment 对象实例
| Function | - |
-| value | 日期值(受控)moment 对象 | custom | - |
-| defaultValue | 初始日期值,moment 对象 | custom | - |
-| format | 日期值的格式(用于限定用户输入和展示) | String | 'YYYY-MM-DD' |
-| showTime | 是否使用时间控件,传入 TimePicker 的属性 { defaultValue, format, ... } | Object/Boolean | false |
-| resetTime | 每次选择日期时是否重置时间(仅在 showTime 开启时有效) | Boolean | false |
-| disabledDate | 禁用日期函数
**签名**:
Function(日期值: MomentObject) => Boolean
**参数**:
_日期值_: {MomentObject} null
**返回值**:
{Boolean} 是否禁用
| Function | () => false |
-| footerRender | 自定义面板页脚
**签名**:
Function() => Node
**返回值**:
{Node} 自定义的面板页脚组件
| Function | () => null |
-| onChange | 日期值改变时的回调
**签名**:
Function(value: MomentObject/String) => void
**参数**:
_value_: {MomentObject/String} 日期值 | Function | func.noop |
-| onOk | 点击确认按钮时的回调
**签名**:
Function() => MomentObject/String
**返回值**:
{MomentObject/String} 日期值
| Function | func.noop |
-| disabled | 是否禁用 | Boolean | - |
-| hasClear | 是否显示清空按钮 | Boolean | true |
-| visible | 弹层显示状态 | Boolean | - |
-| defaultVisible | 弹层默认是否显示 | Boolean | - |
-| onVisibleChange | 弹层展示状态变化时的回调
**签名**:
Function(visible: Boolean, reason: String) => void
**参数**:
_visible_: {Boolean} 弹层是否显示
_reason_: {String} 触发弹层显示和隐藏的来源 | Function | func.noop |
-| popupTriggerType | 弹层触发方式
**可选值**:
'click', 'hover' | Enum | 'click' |
-| popupAlign | 弹层对齐方式,具体含义见 OverLay文档 | String | 'tl tl' |
-| popupContainer | 弹层容器
**签名**:
Function(target: Element) => Element
**参数**:
_target_: {Element} 目标元素
**返回值**:
{Element} 弹层的容器元素
| Function | - |
-| popupStyle | 弹层自定义样式 | Object | - |
-| popupClassName | 弹层自定义样式类 | String | - |
-| popupProps | 弹层其他属性 | Object | - |
-| inputProps | 输入框其他属性 | Object | - |
-| dateCellRender | 自定义日期渲染函数
**签名**:
Function(value: Object) => ReactNode
**参数**:
_value_: {Object} 日期值(moment对象)
**返回值**:
{ReactNode} null
| Function | - |
-| monthCellRender | 自定义月份渲染函数
**签名**:
Function(calendarDate: Object) => ReactNode
**参数**:
_calendarDate_: {Object} 对应 Calendar 返回的自定义日期对象
**返回值**:
{ReactNode} null
| Function | - |
+| 参数 | 说明 | 类型 | 默认值 |
+| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | ------------ |
+| label | 输入框内置标签 | ReactNode | - |
+| size | 输入框尺寸
**可选值**:
'small', 'medium', 'large' | Enum | 'medium' |
+| state | 输入框状态
**可选值**:
'success', 'loading', 'error' | Enum | - |
+| placeholder | 输入提示 | String | - |
+| defaultVisibleMonth | 默认展现的月
**签名**:
Function() => MomentObject
**返回值**:
{MomentObject} 返回包含指定月份的 moment 对象实例
| Function | - |
+| value | 日期值(受控)moment 对象 | custom | - |
+| defaultValue | 初始日期值,moment 对象 | custom | - |
+| format | 日期值的格式(用于限定用户输入和展示) | String | 'YYYY-MM-DD' |
+| showTime | 是否使用时间控件,传入 TimePicker 的属性 { defaultValue, format, ... } | Object/Boolean | false |
+| resetTime | 每次选择日期时是否重置时间(仅在 showTime 开启时有效) | Boolean | false |
+| disabledDate | 禁用日期函数
**签名**:
Function(日期值: MomentObject, view: String) => Boolean
**参数**:
_日期值_: {MomentObject} null
_view_: {String} 当前视图类型,year: 年, month: 月, date: 日
**返回值**:
{Boolean} 是否禁用
| Function | () => false |
+| footerRender | 自定义面板页脚
**签名**:
Function() => Node
**返回值**:
{Node} 自定义的面板页脚组件
| Function | () => null |
+| onChange | 日期值改变时的回调
**签名**:
Function(value: MomentObject/String) => void
**参数**:
_value_: {MomentObject/String} 日期值 | Function | func.noop |
+| onOk | 点击确认按钮时的回调
**签名**:
Function() => MomentObject/String
**返回值**:
{MomentObject/String} 日期值
| Function | func.noop |
+| disabled | 是否禁用 | Boolean | - |
+| hasClear | 是否显示清空按钮 | Boolean | true |
+| visible | 弹层显示状态 | Boolean | - |
+| defaultVisible | 弹层默认是否显示 | Boolean | - |
+| onVisibleChange | 弹层展示状态变化时的回调
**签名**:
Function(visible: Boolean, reason: String) => void
**参数**:
_visible_: {Boolean} 弹层是否显示
_reason_: {String} 触发弹层显示和隐藏的来源 | Function | func.noop |
+| popupTriggerType | 弹层触发方式
**可选值**:
'click', 'hover' | Enum | 'click' |
+| popupAlign | 弹层对齐方式,具体含义见 OverLay文档 | String | 'tl tl' |
+| popupContainer | 弹层容器
**签名**:
Function(target: Element) => Element
**参数**:
_target_: {Element} 目标元素
**返回值**:
{Element} 弹层的容器元素
| Function | - |
+| popupStyle | 弹层自定义样式 | Object | - |
+| popupClassName | 弹层自定义样式类 | String | - |
+| popupProps | 弹层其他属性 | Object | - |
+| inputProps | 输入框其他属性 | Object | - |
+| dateCellRender | 自定义日期渲染函数
**签名**:
Function(value: Object) => ReactNode
**参数**:
_value_: {Object} 日期值(moment对象)
**返回值**:
{ReactNode} null
| Function | - |
+| monthCellRender | 自定义月份渲染函数
**签名**:
Function(calendarDate: Object) => ReactNode
**参数**:
_calendarDate_: {Object} 对应 Calendar 返回的自定义日期对象
**返回值**:
{ReactNode} null
| Function | - |
### DatePicker.MonthPicker
-| 参数 | 说明 | 类型 | 默认值 |
-| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------- |
-| label | 输入框内置标签 | ReactNode | - |
-| size | 输入框尺寸
**可选值**:
'small', 'medium', 'large' | Enum | 'medium' |
-| state | 输入框状态
**可选值**:
'success', 'loading', 'error' | Enum | - |
-| placeholder | 输入提示 | String | - |
-| defaultVisibleYear | 默认展现的年
**签名**:
Function() => MomentObject
**返回值**:
{MomentObject} 返回包含指定年份的 moment 对象实例
| Function | - |
-| value | 日期值(受控)moment 对象 | custom | - |
-| defaultValue | 初始日期值,moment 对象 | custom | - |
-| format | 日期值的格式(用于限定用户输入和展示) | String | 'YYYY-MM' |
-| disabledDate | 禁用日期函数
**签名**:
Function(日期值: MomentObject) => Boolean
**参数**:
_日期值_: {MomentObject} null
**返回值**:
{Boolean} 是否禁用
| Function | () => false |
-| footerRender | 自定义面板页脚
**签名**:
Function() => Node
**返回值**:
{Node} 自定义的面板页脚组件
| Function | () => null |
-| onChange | 日期值改变时的回调
**签名**:
Function(value: MomentObject/String) => void
**参数**:
_value_: {MomentObject/String} 日期值 | Function | func.noop |
-| disabled | 是否禁用 | Boolean | - |
-| hasClear | 是否显示清空按钮 | Boolean | true |
-| visible | 弹层显示状态 | Boolean | - |
-| defaultVisible | 弹层默认是否显示 | Boolean | - |
-| onVisibleChange | 弹层展示状态变化时的回调
**签名**:
Function(visible: Boolean, reason: String) => void
**参数**:
_visible_: {Boolean} 弹层是否显示
_reason_: {String} 触发弹层显示和隐藏的来源 | Function | func.noop |
-| popupTriggerType | 弹层触发方式
**可选值**:
'click', 'hover' | Enum | 'click' |
-| popupAlign | 弹层对齐方式, 具体含义见 OverLay文档 | String | 'tl tl' |
-| popupContainer | 弹层容器
**签名**:
Function(target: Element) => Element
**参数**:
_target_: {Element} 目标元素
**返回值**:
{Element} 弹层的容器元素
| Function | - |
-| popupStyle | 弹层自定义样式 | Object | - |
-| popupClassName | 弹层自定义样式类 | String | - |
-| popupProps | 弹层其他属性 | Object | - |
-| inputProps | 输入框其他属性 | Object | - |
-| monthCellRender | 自定义月份渲染函数
**签名**:
Function(calendarDate: Object) => ReactNode
**参数**:
_calendarDate_: {Object} 对应 Calendar 返回的自定义日期对象
**返回值**:
{ReactNode} null
| Function | - |
+| 参数 | 说明 | 类型 | 默认值 |
+| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------- |
+| label | 输入框内置标签 | ReactNode | - |
+| size | 输入框尺寸
**可选值**:
'small', 'medium', 'large' | Enum | 'medium' |
+| state | 输入框状态
**可选值**:
'success', 'loading', 'error' | Enum | - |
+| placeholder | 输入提示 | String | - |
+| defaultVisibleYear | 默认展现的年
**签名**:
Function() => MomentObject
**返回值**:
{MomentObject} 返回包含指定年份的 moment 对象实例
| Function | - |
+| value | 日期值(受控)moment 对象 | custom | - |
+| defaultValue | 初始日期值,moment 对象 | custom | - |
+| format | 日期值的格式(用于限定用户输入和展示) | String | 'YYYY-MM' |
+| disabledDate | 禁用日期函数
**签名**:
Function(日期值: MomentObject, view: String) => Boolean
**参数**:
_日期值_: {MomentObject} null
_view_: {String} 当前视图类型,year: 年, month: 月, date: 日
**返回值**:
{Boolean} 是否禁用
| Function | () => false |
+| footerRender | 自定义面板页脚
**签名**:
Function() => Node
**返回值**:
{Node} 自定义的面板页脚组件
| Function | () => null |
+| onChange | 日期值改变时的回调
**签名**:
Function(value: MomentObject/String) => void
**参数**:
_value_: {MomentObject/String} 日期值 | Function | func.noop |
+| disabled | 是否禁用 | Boolean | - |
+| hasClear | 是否显示清空按钮 | Boolean | true |
+| visible | 弹层显示状态 | Boolean | - |
+| defaultVisible | 弹层默认是否显示 | Boolean | - |
+| onVisibleChange | 弹层展示状态变化时的回调
**签名**:
Function(visible: Boolean, reason: String) => void
**参数**:
_visible_: {Boolean} 弹层是否显示
_reason_: {String} 触发弹层显示和隐藏的来源 | Function | func.noop |
+| popupTriggerType | 弹层触发方式
**可选值**:
'click', 'hover' | Enum | 'click' |
+| popupAlign | 弹层对齐方式, 具体含义见 OverLay文档 | String | 'tl tl' |
+| popupContainer | 弹层容器
**签名**:
Function(target: Element) => Element
**参数**:
_target_: {Element} 目标元素
**返回值**:
{Element} 弹层的容器元素
| Function | - |
+| popupStyle | 弹层自定义样式 | Object | - |
+| popupClassName | 弹层自定义样式类 | String | - |
+| popupProps | 弹层其他属性 | Object | - |
+| inputProps | 输入框其他属性 | Object | - |
+| monthCellRender | 自定义月份渲染函数
**签名**:
Function(calendarDate: Object) => ReactNode
**参数**:
_calendarDate_: {Object} 对应 Calendar 返回的自定义日期对象
**返回值**:
{ReactNode} null
| Function | - |
### DatePicker.RangePicker
-| 参数 | 说明 | 类型 | 默认值 | | |
-| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------- | -------- | --------- |
-| defaultVisibleMonth | 默认展示的起始月份
**签名**:
Function() => MomentObject
**返回值**:
{MomentObject} 返回包含指定月份的 moment 对象实例
| Function | - | | |
-| size | 输入框尺寸
**可选值**:
'small', 'medium', 'large' | Enum | 'medium' | | |
-| value | 日期范围值数组 [moment, moment] | Array | - | | |
-| defaultValue | 初始的日期范围值数组 [moment, moment] | Array | - | | |
-| format | 日期格式 | String | 'YYYY-MM-DD' | | |
-| showTime | 是否使用时间控件,支持传入 TimePicker 的属性 | Object/Boolean | false | | |
-| resetTime | 每次选择是否重置时间(仅在 showTime 开启时有效) | Boolean | false | | |
-| disabledDate | 禁用日期函数
**签名**:
Function(日期值: MomentObject) => Boolean
**参数**:
_日期值_: {MomentObject} null
**返回值**:
{Boolean} 是否禁用
| Function | () => false | | |
-| footerRender | 自定义面板页脚
**签名**:
Function() => Node
**返回值**:
{Node} 自定义的面板页脚组件
| Function | () => null | | |
-| onChange | 日期范围值改变时的回调 \[ MomentObject | String, MomentObject | String ]
**签名**:
Function(value: Array) => void
**参数**:
_value_: {Array} 日期值 | Function | func.noop |
-| onOk | 点击确认按钮时的回调 返回开始时间和结束时间`[ MomentObject|String, MomentObject|String ]`
**签名**:
Function() => Array
**返回值**:
{Array} 日期范围
| Function | func.noop | | |
-| label | 输入框内置标签 | ReactNode | - | | |
-| state | 输入框状态
**可选值**:
'error', 'loading', 'success' | Enum | - | | |
-| disabled | 是否禁用 | Boolean | - | | |
-| hasClear | 是否显示清空按钮 | Boolean | true | | |
-| visible | 弹层显示状态 | Boolean | - | | |
-| defaultVisible | 弹层默认是否显示 | Boolean | - | | |
-| onVisibleChange | 弹层展示状态变化时的回调
**签名**:
Function(visible: Boolean, reason: String) => void
**参数**:
_visible_: {Boolean} 弹层是否显示
_reason_: {String} 触发弹层显示和隐藏的来源 | Function | func.noop | | |
-| popupTriggerType | 弹层触发方式
**可选值**:
'click', 'hover' | Enum | 'click' | | |
-| popupAlign | 弹层对齐方式, 具体含义见 OverLay文档 | String | 'tl tl' | | |
-| popupContainer | 弹层容器
**签名**:
Function(target: Element) => Element
**参数**:
_target_: {Element} 目标元素
**返回值**:
{Element} 弹层的容器元素
| Function | - | | |
-| popupStyle | 弹层自定义样式 | Object | - | | |
-| popupClassName | 弹层自定义样式类 | String | - | | |
-| popupProps | 弹层其他属性 | Object | - | | |
-| inputProps | 输入框其他属性 | Object | - | | |
-| dateCellRender | 自定义日期单元格渲染
**签名**:
Function() => void | Function | - | | |
+| 参数 | 说明 | 类型 | 默认值 | | |
+| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------- | -------- | --------- |
+| defaultVisibleMonth | 默认展示的起始月份
**签名**:
Function() => MomentObject
**返回值**:
{MomentObject} 返回包含指定月份的 moment 对象实例
| Function | - | | |
+| size | 输入框尺寸
**可选值**:
'small', 'medium', 'large' | Enum | 'medium' | | |
+| value | 日期范围值数组 [moment, moment] | Array | - | | |
+| defaultValue | 初始的日期范围值数组 [moment, moment] | Array | - | | |
+| format | 日期格式 | String | 'YYYY-MM-DD' | | |
+| showTime | 是否使用时间控件,支持传入 TimePicker 的属性 | Object/Boolean | false | | |
+| resetTime | 每次选择是否重置时间(仅在 showTime 开启时有效) | Boolean | false | | |
+| disabledDate | 禁用日期函数
**签名**:
Function(日期值: MomentObject, view: String) => Boolean
**参数**:
_日期值_: {MomentObject} null
_view_: {String} 当前视图类型,year: 年, month: 月, date: 日
**返回值**:
{Boolean} 是否禁用
| Function | () => false | | |
+| footerRender | 自定义面板页脚
**签名**:
Function() => Node
**返回值**:
{Node} 自定义的面板页脚组件
| Function | () => null | | |
+| onChange | 日期范围值改变时的回调 \[ MomentObject | String, MomentObject | String ]
**签名**:
Function(value: Array) => void
**参数**:
_value_: {Array} 日期值 | Function | func.noop |
+| onOk | 点击确认按钮时的回调 返回开始时间和结束时间`[ MomentObject|String, MomentObject|String ]`
**签名**:
Function() => Array
**返回值**:
{Array} 日期范围
| Function | func.noop | | |
+| label | 输入框内置标签 | ReactNode | - | | |
+| state | 输入框状态
**可选值**:
'error', 'loading', 'success' | Enum | - | | |
+| disabled | 是否禁用 | Boolean | - | | |
+| hasClear | 是否显示清空按钮 | Boolean | true | | |
+| visible | 弹层显示状态 | Boolean | - | | |
+| defaultVisible | 弹层默认是否显示 | Boolean | - | | |
+| onVisibleChange | 弹层展示状态变化时的回调
**签名**:
Function(visible: Boolean, reason: String) => void
**参数**:
_visible_: {Boolean} 弹层是否显示
_reason_: {String} 触发弹层显示和隐藏的来源 | Function | func.noop | | |
+| popupTriggerType | 弹层触发方式
**可选值**:
'click', 'hover' | Enum | 'click' | | |
+| popupAlign | 弹层对齐方式, 具体含义见 OverLay文档 | String | 'tl tl' | | |
+| popupContainer | 弹层容器
**签名**:
Function(target: Element) => Element
**参数**:
_target_: {Element} 目标元素
**返回值**:
{Element} 弹层的容器元素
| Function | - | | |
+| popupStyle | 弹层自定义样式 | Object | - | | |
+| popupClassName | 弹层自定义样式类 | String | - | | |
+| popupProps | 弹层其他属性 | Object | - | | |
+| inputProps | 输入框其他属性 | Object | - | | |
+| dateCellRender | 自定义日期单元格渲染
**签名**:
Function() => void | Function | - | | |
### DatePicker.YearPicker
-| 参数 | 说明 | 类型 | 默认值 |
-| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------- |
-| label | 输入框内置标签 | ReactNode | - |
-| size | 输入框尺寸
**可选值**:
'small', 'medium', 'large' | Enum | 'medium' |
-| state | 输入框状态
**可选值**:
'success', 'loading', 'error' | Enum | - |
-| placeholder | 输入提示 | String | - |
-| value | 日期值(受控)moment 对象 | custom | - |
-| defaultValue | 初始日期值,moment 对象 | custom | - |
-| format | 日期值的格式(用于限定用户输入和展示) | String | 'YYYY' |
-| disabledDate | 禁用日期函数
**签名**:
Function(日期值: MomentObject) => Boolean
**参数**:
_日期值_: {MomentObject} null
**返回值**:
{Boolean} 是否禁用
| Function | () => false |
-| footerRender | 自定义面板页脚
**签名**:
Function() => Node
**返回值**:
{Node} 自定义的面板页脚组件
| Function | () => null |
-| onChange | 日期值改变时的回调
**签名**:
Function(value: MomentObject/String) => void
**参数**:
_value_: {MomentObject/String} 日期值 | Function | func.noop |
-| disabled | 是否禁用 | Boolean | - |
-| hasClear | 是否显示清空按钮 | Boolean | true |
-| visible | 弹层显示状态 | Boolean | - |
-| defaultVisible | 弹层默认是否显示 | Boolean | - |
-| onVisibleChange | 弹层展示状态变化时的回调
**签名**:
Function(visible: Boolean, reason: String) => void
**参数**:
_visible_: {Boolean} 弹层是否显示
_reason_: {String} 触发弹层显示和隐藏的来源 | Function | func.noop |
-| popupTriggerType | 弹层触发方式
**可选值**:
'click', 'hover' | Enum | 'click' |
-| popupAlign | 弹层对齐方式, 具体含义见 OverLay文档 | String | 'tl tl' |
-| popupContainer | 弹层容器
**签名**:
Function(target: Element) => Element
**参数**:
_target_: {Element} 目标元素
**返回值**:
{Element} 弹层的容器元素
| Function | - |
-| popupStyle | 弹层自定义样式 | Object | - |
-| popupClassName | 弹层自定义样式类 | String | - |
-| popupProps | 弹层其他属性 | Object | - |
-| inputProps | 输入框其他属性 | Object | - |
+| 参数 | 说明 | 类型 | 默认值 |
+| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------- |
+| label | 输入框内置标签 | ReactNode | - |
+| size | 输入框尺寸
**可选值**:
'small', 'medium', 'large' | Enum | 'medium' |
+| state | 输入框状态
**可选值**:
'success', 'loading', 'error' | Enum | - |
+| placeholder | 输入提示 | String | - |
+| value | 日期值(受控)moment 对象 | custom | - |
+| defaultValue | 初始日期值,moment 对象 | custom | - |
+| format | 日期值的格式(用于限定用户输入和展示) | String | 'YYYY' |
+| disabledDate | 禁用日期函数
**签名**:
Function(日期值: MomentObject, view: String) => Boolean
**参数**:
_日期值_: {MomentObject} null
_view_: {String} 当前视图类型,year: 年, month: 月, date: 日
**返回值**:
{Boolean} 是否禁用
| Function | () => false |
+| footerRender | 自定义面板页脚
**签名**:
Function() => Node
**返回值**:
{Node} 自定义的面板页脚组件
| Function | () => null |
+| onChange | 日期值改变时的回调
**签名**:
Function(value: MomentObject/String) => void
**参数**:
_value_: {MomentObject/String} 日期值 | Function | func.noop |
+| disabled | 是否禁用 | Boolean | - |
+| hasClear | 是否显示清空按钮 | Boolean | true |
+| visible | 弹层显示状态 | Boolean | - |
+| defaultVisible | 弹层默认是否显示 | Boolean | - |
+| onVisibleChange | 弹层展示状态变化时的回调
**签名**:
Function(visible: Boolean, reason: String) => void
**参数**:
_visible_: {Boolean} 弹层是否显示
_reason_: {String} 触发弹层显示和隐藏的来源 | Function | func.noop |
+| popupTriggerType | 弹层触发方式
**可选值**:
'click', 'hover' | Enum | 'click' |
+| popupAlign | 弹层对齐方式, 具体含义见 OverLay文档 | String | 'tl tl' |
+| popupContainer | 弹层容器
**签名**:
Function(target: Element) => Element
**参数**:
_target_: {Element} 目标元素
**返回值**:
{Element} 弹层的容器元素
| Function | - |
+| popupStyle | 弹层自定义样式 | Object | - |
+| popupClassName | 弹层自定义样式类 | String | - |
+| popupProps | 弹层其他属性 | Object | - |
+| inputProps | 输入框其他属性 | Object | - |
## ARIA and KeyBoard
diff --git a/docs/dialog/demo/accessibility.md b/docs/dialog/demo/accessibility.md
index 3507d4e7a6..a479266b11 100644
--- a/docs/dialog/demo/accessibility.md
+++ b/docs/dialog/demo/accessibility.md
@@ -28,9 +28,7 @@ class Demo extends React.Component {
visible: true
});
};
- onClose = reason => {
- console.log(reason);
-
+ onClose = () => {
this.setState({
visible: false
});
@@ -44,6 +42,7 @@ class Demo extends React.Component {
` 和 ` ` 会加上 `role="row"` 和 `role="gridcell"`, 但是为了完美的无障碍实现, 开发者还应该在外部容器加上 `role="grid"`。示例代码如下:
-````
-
- 1 2 3 4
- 1 2
-
-````
+
+ 1 2 3 4
+ 1 2
+
## API
diff --git a/docs/overlay/demo/accessibility.md b/docs/overlay/demo/accessibility.md
index 67dfb4e02f..744082f0cb 100644
--- a/docs/overlay/demo/accessibility.md
+++ b/docs/overlay/demo/accessibility.md
@@ -21,24 +21,20 @@ import { Overlay } from '@alifd/next';
class Demo extends React.Component {
constructor(props) {
super(props);
-
this.state = {
visible: false
};
- }
-
+ };
onClick = () => {
this.setState({
visible: !this.state.visible
});
- }
-
+ };
onClose = () => {
this.setState({
visible: false
});
- }
-
+ };
render() {
return (
@@ -48,6 +44,7 @@ class Demo extends React.Component {
overlay accessibility
this.btn}
safeNode={() => this.btn}
onRequestClose={this.onClose}>
diff --git a/docs/radio/index.md b/docs/radio/index.md
index bf9c61d767..ae9b6707b2 100644
--- a/docs/radio/index.md
+++ b/docs/radio/index.md
@@ -34,19 +34,19 @@
### Radio.Group
-| 参数 | 说明 | 类型 | 默认值 |
-| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | --------- |
-| name | name | String | - |
-| size | 与 `shape` 属性配套使用,shape设为button时有效 **可选值**: 'large'(大) 'medium'(中) 'small'(小) | Enum | 'medium' |
-| shape | 可以设置成 button 展示形状 **可选值**: 'button'(按钮状) | Enum | - |
-| value | radio group的选中项的值 | String/Number/Boolean | - |
-| defaultValue | radio group的默认值 | String/Number/Boolean | - |
-| component | 设置标签类型 | String/Function | 'div' |
-| onChange | 选中值改变时的事件 **签名**: Function(value: String/Number, e: Event) => void **参数**: _value_: {String/Number} 选中项的值 _e_: {Event} Dom 事件对象 | Function | () => { } |
-| disabled | 表示radio被禁用 | Boolean | - |
-| dataSource | 可选项列表, 数据项可为 String 或者 Object, 如 `['apple', 'pear', 'orange']` | Array<any> | \[] |
-| children | 通过子元素方式设置内部radio | Array<ReactElement>/ReactElement | - |
-| itemDirection | 子项目的排列方式 - hoz: 水平排列 (default) - ver: 垂直排列 **可选值**: 'hoz', 'ver' | Enum | 'hoz' |
+| 参数 | 说明 | 类型 | 默认值 |
+| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -------- |
+| name | name | String | - |
+| size | 与 `shape` 属性配套使用,shape设为button时有效 **可选值**: 'large'(大) 'medium'(中) 'small'(小) | Enum | 'medium' |
+| shape | 可以设置成 button 展示形状 **可选值**: 'button'(按钮状) | Enum | - |
+| value | radio group的选中项的值 | String/Number/Boolean | - |
+| defaultValue | radio group的默认值 | String/Number/Boolean | - |
+| component | 设置标签类型 | String/Function | 'div' |
+| onChange | 选中值改变时的事件 **签名**: Function(value: String/Number, e: Event) => void **参数**: _value_: {String/Number} 选中项的值 _e_: {Event} Dom 事件对象 | Function | () => {} |
+| disabled | 表示radio被禁用 | Boolean | - |
+| dataSource | 可选项列表, 数据项可为 String 或者 Object, 如 `['apple', 'pear', 'orange']` | Array<any> | \[] |
+| children | 通过子元素方式设置内部radio | Array<ReactElement>/ReactElement | - |
+| itemDirection | 子项目的排列方式 - hoz: 水平排列 (default) - ver: 垂直排列 **可选值**: 'hoz', 'ver' | Enum | 'hoz' |
## ARIA and KeyBoard
diff --git a/docs/range/demo/accessibility.md b/docs/range/demo/accessibility.md
index a3a5ce2cdd..40bfc1ba27 100644
--- a/docs/range/demo/accessibility.md
+++ b/docs/range/demo/accessibility.md
@@ -22,14 +22,10 @@ const style = {
marginBottom: '15px'
};
-ReactDOM.render((
-
-
+ReactDOM.render(
single slider - from left to right
single slider - from right to left
-
-
-), mountNode);
+
, mountNode);
````
\ No newline at end of file
diff --git a/docs/range/demo/basic.md b/docs/range/demo/basic.md
index 435b983743..0f90ce3615 100644
--- a/docs/range/demo/basic.md
+++ b/docs/range/demo/basic.md
@@ -24,9 +24,7 @@ const style = {
marginBottom: '15px'
};
-ReactDOM.render((
-
-
+ReactDOM.render(
single slider - from left to right
single slider - from right to left
@@ -47,6 +45,5 @@ ReactDOM.render((
tooltipVisible
-
-), mountNode);
+
, mountNode);
````
diff --git a/docs/range/demo/marks.md b/docs/range/demo/marks.md
index 44645d3160..21d6ee52a9 100644
--- a/docs/range/demo/marks.md
+++ b/docs/range/demo/marks.md
@@ -23,8 +23,7 @@ const style = {
marginTop: '20px'
};
-ReactDOM.render((
-
+ReactDOM.render(
With minimal and maximal value
@@ -41,6 +40,5 @@ ReactDOM.render((
-
-), mountNode);
+
, mountNode);
````
diff --git a/docs/range/demo/range.md b/docs/range/demo/range.md
index d26675c944..33cb41798b 100644
--- a/docs/range/demo/range.md
+++ b/docs/range/demo/range.md
@@ -22,7 +22,7 @@ const style = {
marginBottom: '40px',
marginTop: '40px'
};
-ReactDOM.render((
+ReactDOM.render(
Range 0 ~ 1024
@@ -30,5 +30,5 @@ ReactDOM.render((
-), mountNode);
+, mountNode);
````
diff --git a/docs/range/demo/reverse.md b/docs/range/demo/reverse.md
index 01988372b8..0627d7fd7c 100644
--- a/docs/range/demo/reverse.md
+++ b/docs/range/demo/reverse.md
@@ -22,7 +22,7 @@ const style = {
marginBottom: '15px'
};
-ReactDOM.render((
+ReactDOM.render(
@@ -32,6 +32,5 @@ ReactDOM.render((
-
-), mountNode);
+ , mountNode);
````
diff --git a/docs/range/index.md b/docs/range/index.md
index e17916cacd..495d75d06a 100644
--- a/docs/range/index.md
+++ b/docs/range/index.md
@@ -43,6 +43,7 @@
| pure | 是否pure render | Boolean | false |
| fixedWidth | 是否为拖动线段类型,默认slider为double, defaultValue必传且指定区间 | Boolean | false |
| tooltipVisible | tooltip是否默认展示 | Boolean | false |
+| rtl | 是否已rtl模式展示 | Boolean | false |
## ARIA and KeyBoard
diff --git a/docs/search/demo/accessibility.md b/docs/search/demo/accessibility.md
index 98ec43e64e..0f0d264679 100644
--- a/docs/search/demo/accessibility.md
+++ b/docs/search/demo/accessibility.md
@@ -34,7 +34,7 @@ class Demo extends React.Component {
onsearch() {
console.log(this.state.name);
}
- ender() {
+ render() {
return (
search} style={{width: '400px'}}/>
);
diff --git a/docs/select/demo/multiple.md b/docs/select/demo/multiple.md
index 3f2751b87d..02d92ed911 100644
--- a/docs/select/demo/multiple.md
+++ b/docs/select/demo/multiple.md
@@ -32,5 +32,33 @@ function handleChange(value) {
console.log(value);
}
-ReactDOM.render( , mountNode);
+
+class Demo extends React.Component{
+ constructor(props) {
+ super(props)
+ this.state = {
+ value: []
+ }
+ }
+
+ handleChange = (value) => {
+ this.setState({value})
+ }
+
+ render() {
+ return (
+ )
+ }
+}
+
+
+ReactDOM.render(
+
+
+
+
+
+
+
+, mountNode);
````
diff --git a/docs/step/index.md b/docs/step/index.md
index e844e7c496..3cc809dcdb 100644
--- a/docs/step/index.md
+++ b/docs/step/index.md
@@ -23,13 +23,13 @@
### Step.Item
-| 参数 | 说明 | 类型 | 默认值 |
-| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | --------- |
-| status | 步骤的状态,如不传,会根据外层的 Step 的 current 属性生成,可选值为 `wait`, `process`, `finish` **可选值**: 'wait', 'process', 'finish' | Enum | - |
-| title | 标题 | ReactNode | - |
-| icon | 图标 | String | - |
-| content | 内容,用于垂直状态下的内容填充 | ReactNode | - |
-| itemRender | StepItem 的自定义渲染, 会覆盖父节点设置的itemRender **签名**: Function(index: Number, status: String) => Node **参数**: _index_: {Number} 节点索引 _status_: {String} 节点状态 **返回值**: {Node} 节点的渲染结果 | Function | - |
-| percent | 百分比 | Number | - |
-| disabled | 是否禁用 | Boolean | - |
-| onClick | 点击步骤时的回调 **签名**: Function(index: Number) => void **参数**: _index_: {Number} 节点索引 | Function | () => { } |
+| 参数 | 说明 | 类型 | 默认值 |
+| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | -------- |
+| status | 步骤的状态,如不传,会根据外层的 Step 的 current 属性生成,可选值为 `wait`, `process`, `finish` **可选值**: 'wait', 'process', 'finish' | Enum | - |
+| title | 标题 | ReactNode | - |
+| icon | 图标 | String | - |
+| content | 内容,用于垂直状态下的内容填充 | ReactNode | - |
+| itemRender | StepItem 的自定义渲染, 会覆盖父节点设置的itemRender **签名**: Function(index: Number, status: String) => Node **参数**: _index_: {Number} 节点索引 _status_: {String} 节点状态 **返回值**: {Node} 节点的渲染结果 | Function | - |
+| percent | 百分比 | Number | - |
+| disabled | 是否禁用 | Boolean | - |
+| onClick | 点击步骤时的回调 **签名**: Function(index: Number) => void **参数**: _index_: {Number} 节点索引 | Function | () => {} |
diff --git a/docs/switch/index.md b/docs/switch/index.md
index 1991a98aa7..2acea77b23 100644
--- a/docs/switch/index.md
+++ b/docs/switch/index.md
@@ -23,17 +23,17 @@
### Switch
-| 参数 | 说明 | 类型 | 默认值 |
-| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------- |
-| checkedChildren | 打开时的内容 | any | - |
-| size | switch的尺寸 **可选值**: 'medium'(正常大小) 'small'(缩小版大小) | Enum | 'medium' |
-| unCheckedChildren | 关闭时的内容 | any | - |
-| onChange | 开关状态改变是触发此事件 **签名**: Function(checked: Boolean, e: Event) => void **参数**: _checked_: {Boolean} 是否为打开状态 _e_: {Event} DOM事件对象 | Function | () => { } |
-| checked | 开关当前的值(针对受控组件) | Boolean | - |
-| defaultChecked | 开关默认值 (针对非受控组件) | Boolean | - |
-| disabled | 表示开关被禁用 | Boolean | false |
-| onClick | 鼠标点击事件 **签名**: Function(e: Event) => void **参数**: _e_: {Event} DOM事件对象 | Function | - |
-| onKeyDown | 键盘按键事件 **签名**: Function(e: Event) => void **参数**: _e_: {Event} DOM事件对象 | Function | - |
+| 参数 | 说明 | 类型 | 默认值 |
+| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------- |
+| checkedChildren | 打开时的内容 | any | - |
+| size | switch的尺寸 **可选值**: 'medium'(正常大小) 'small'(缩小版大小) | Enum | 'medium' |
+| unCheckedChildren | 关闭时的内容 | any | - |
+| onChange | 开关状态改变是触发此事件 **签名**: Function(checked: Boolean, e: Event) => void **参数**: _checked_: {Boolean} 是否为打开状态 _e_: {Event} DOM事件对象 | Function | () => {} |
+| checked | 开关当前的值(针对受控组件) | Boolean | - |
+| defaultChecked | 开关默认值 (针对非受控组件) | Boolean | - |
+| disabled | 表示开关被禁用 | Boolean | false |
+| onClick | 鼠标点击事件 **签名**: Function(e: Event) => void **参数**: _e_: {Event} DOM事件对象 | Function | - |
+| onKeyDown | 键盘按键事件 **签名**: Function(e: Event) => void **参数**: _e_: {Event} DOM事件对象 | Function | - |
## 键盘支持
diff --git a/docs/table/demo/fixed-header.md b/docs/table/demo/fixed-header.md
index 067ae1ed31..edcd81896e 100644
--- a/docs/table/demo/fixed-header.md
+++ b/docs/table/demo/fixed-header.md
@@ -31,20 +31,39 @@ const dataSource = (length) => {
class App extends React.Component {
state = {
- sticky: false
+ sticky: false,
+ lock: false,
+ dataSource: dataSource(50),
}
- onSwitch() {
- this.setState({
- sticky: true
- });
+ onSwitch(tag) {
+ const props = {};
+ switch (tag) {
+ case 'sticky':
+ props.sticky = true;
+ break;
+ case 'lock':
+ props.lock = true;
+ break;
+ case 'dataSource':
+ props.dataSource = this.state.dataSource.length > 0 ? [] : dataSource(50);
+ break;
+ default:
+ break;
+ }
+
+ this.setState(props);
}
render() {
return (
-
enable sticky
-
-
-
-
+
+ enable sticky
+ enable lock
+ toggle dataSource
+
+
);
diff --git a/docs/table/index.md b/docs/table/index.md
index 31af14dc00..9250cfdfc1 100644
--- a/docs/table/index.md
+++ b/docs/table/index.md
@@ -106,7 +106,7 @@ ReactDOM.render(
| hasHeader | 表格是否具有头部 | Boolean | true |
| isZebra | 表格是否是斑马线 | Boolean | false |
| loading | 表格是否在加载中 | Boolean | false |
-| loadingComponent | 自定义 Loading 组件 **签名**: Function() => void | Function | - |
+| loadingComponent | 自定义 Loading 组件 请务必传递 props, 使用方式: loadingComponent={props => <Loading {...props}/>} **签名**: Function(props: Object) => void **参数**: _props_: {Object} 当前点击行的key | Function | - |
| filterParams | 当前过滤的的keys,使用此属性可以控制表格的头部的过滤选项中哪个菜单被选中,格式为 {dataIndex: {selectedKeys:\[]}} 示例: 假设要控制dataIndex为id的列的过滤菜单中key为one的菜单项选中 `` | Object | - |
| sort | 当前排序的字段,使用此属性可以控制表格的字段的排序,格式为{dataIndex: 'asc'} | Object | - |
| emptyContent | 设置数据为空的时候的表格内容展现 | ReactNode | - |
@@ -133,19 +133,19 @@ ReactDOM.render(
### Table.Column
-| 参数 | 说明 | 类型 | 默认值 |
-| ----------- | --------------------------------------------------------------------------------------------------- | ------------------------------- | ---------------- |
-| dataIndex | 指定列对应的字段,支持`a.b`形式的快速取值 | String | - |
-| cell | 行渲染的逻辑 value, rowIndex, record, context四个属性只可读不可被更改 Function(value, index, record) => Element | ReactElement/ReactNode/Function | (value) => value |
-| title | 表头显示的内容 value, rowIndex, record, context四个属性只可读不可被更改 | ReactElement/ReactNode/Function | - |
-| sortable | 是否支持排序 | Boolean | - |
-| width | 列宽,注意在锁列的情况下一定需要配置宽度 | Number/String | - |
-| align | 单元格的对齐方式 **可选值**: 'left', 'center', 'right' | Enum | - |
-| alignHeader | 单元格标题的对齐方式, 不配置默认读取align值 **可选值**: 'left', 'center', 'right' | Enum | - |
-| filters | 生成标题过滤的菜单, 格式为`[{label:'xxx', value:'xxx'}]` | Array<Object> | - |
-| filterMode | 过滤的模式是单选还是多选 **可选值**: 'single', 'multiple' | Enum | 'multiple' |
-| lock | 是否支持锁列,可选值为`left`,`right`, `true` | Boolean/String | - |
-| resizable | 是否支持列宽调整, 当该值设为true,table的布局方式会修改为fixed. | Boolean | false |
+| 参数 | 说明 | 类型 | 默认值 |
+| ----------- | --------------------------------------------------------------------------------------------------- | ------------------------------- | -------------- |
+| dataIndex | 指定列对应的字段,支持`a.b`形式的快速取值 | String | - |
+| cell | 行渲染的逻辑 value, rowIndex, record, context四个属性只可读不可被更改 Function(value, index, record) => Element | ReactElement/ReactNode/Function | value => value |
+| title | 表头显示的内容 value, rowIndex, record, context四个属性只可读不可被更改 | ReactElement/ReactNode/Function | - |
+| sortable | 是否支持排序 | Boolean | - |
+| width | 列宽,注意在锁列的情况下一定需要配置宽度 | Number/String | - |
+| align | 单元格的对齐方式 **可选值**: 'left', 'center', 'right' | Enum | - |
+| alignHeader | 单元格标题的对齐方式, 不配置默认读取align值 **可选值**: 'left', 'center', 'right' | Enum | - |
+| filters | 生成标题过滤的菜单, 格式为`[{label:'xxx', value:'xxx'}]` | Array<Object> | - |
+| filterMode | 过滤的模式是单选还是多选 **可选值**: 'single', 'multiple' | Enum | 'multiple' |
+| lock | 是否支持锁列,可选值为`left`,`right`, `true` | Boolean/String | - |
+| resizable | 是否支持列宽调整, 当该值设为true,table的布局方式会修改为fixed. | Boolean | false |
### Table.ColumnGroup
diff --git a/index.js b/index.js
index dc33f19c6a..181976134c 100644
--- a/index.js
+++ b/index.js
@@ -1,5 +1,5 @@
var next = require('./lib/index.js');
-next.version = '1.13.4';
+next.version = '1.13.8';
module.exports = next;
diff --git a/package.json b/package.json
index b96004ebc5..ec94703e89 100644
--- a/package.json
+++ b/package.json
@@ -1,179 +1,180 @@
{
- "name": "@alifd/next",
- "version": "1.13.4",
- "description": "A configurable component library for web built on React.",
- "keywords": [
- "fusion",
- "fusion design",
- "next",
- "component",
- "ui tookit"
+ "name": "@alifd/next",
+ "version": "1.13.8",
+ "description": "A configurable component library for web built on React.",
+ "keywords": [
+ "fusion",
+ "fusion design",
+ "next",
+ "component",
+ "ui tookit"
+ ],
+ "homepage": "https://github.com/alibaba-fusion/next",
+ "bugs": "https://github.com/alibaba-fusion/next/issues",
+ "license": "MIT",
+ "files": [
+ "dist",
+ "es",
+ "lib",
+ "index-noreset.scss",
+ "index-with-locales.js",
+ "index.js",
+ "index.scss",
+ "reset.scss",
+ "variables.scss",
+ ".fusion"
+ ],
+ "main": "index.js",
+ "module": "es/index.js",
+ "typings": "lib/index.d.ts",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/alibaba-fusion/next.git"
+ },
+ "scripts": {
+ "report-coverage": "codecov",
+ "dev": "node ./scripts/server/index.js",
+ "build": "node ./scripts/build/index.js",
+ "check": "node ./scripts/check/index.js",
+ "check-sass": "node ./scripts/check/sass.js",
+ "docs": "node ./scripts/docs/index.js",
+ "api": "node ./scripts/api.js",
+ "pack": "node ./scripts/pack.js",
+ "release": "node ./scripts/release/index.js",
+ "test": "node --max_old_space_size=8192 ./scripts/test/index.js",
+ "test:a11y": "node --max_old_space_size=8192 ./scripts/test/a11y-index.js",
+ "order-var": "node ./scripts/order-var.js",
+ "eslint": "eslint '@(src|scripts)/**/*.@(js|jsx)' && eslint --fix 'docs/**/@(demo|theme)/*.@(md)'",
+ "prettierjs": "prettier --write '@(src|test|scripts)/**/*.@(js|jsx)'",
+ "stylelint": "stylelint --fix 'src/**/*.@(css|scss)'",
+ "commitmsg": "commitlint -E GIT_PARAMS",
+ "precommit": "lint-staged",
+ "changelog": "node ./scripts/changelog.js",
+ "prepub": "npm run eslint && npm run stylelint && npm run changelog && npm run build && npm run check && npm run docs && npm run pack && npm run pack -- minimize"
+ },
+ "lint-staged": {
+ "@(src|scripts|docs/*/demo)/**/*.@(js|jsx)": [
+ "prettier --write"
],
- "homepage": "https://github.com/alibaba-fusion/next",
- "bugs": "https://github.com/alibaba-fusion/next/issues",
- "license": "MIT",
- "files": [
- "dist",
- "es",
- "lib",
- "index-noreset.scss",
- "index-with-locales.js",
- "index.js",
- "index.scss",
- "reset.scss",
- "variables.scss",
- ".fusion"
+ "@(src|scripts|docs/*/demo)/**/*.@(js|jsx|md)": [
+ "eslint",
+ "git add"
],
- "main": "index.js",
- "module": "es/index.js",
- "typings": "lib/index.d.ts",
- "repository": {
- "type": "git",
- "url": "https://github.com/alibaba-fusion/next.git"
- },
- "scripts": {
- "report-coverage": "codecov",
- "dev": "node ./scripts/server/index.js",
- "build": "node ./scripts/build/index.js",
- "check": "node ./scripts/check/index.js",
- "check-sass": "node ./scripts/check/sass.js",
- "docs": "node ./scripts/docs/index.js",
- "api": "node ./scripts/api.js",
- "pack": "node ./scripts/pack.js",
- "release": "node ./scripts/release/index.js",
- "test": "node --max_old_space_size=8192 ./scripts/test/index.js",
- "order-var": "node ./scripts/order-var.js",
- "eslint": "eslint '@(src|scripts)/**/*.@(js|jsx)' && eslint --fix 'docs/**/@(demo|theme)/*.@(md)'",
- "prettierjs": "prettier --write '@(src|test|scripts)/**/*.@(js|jsx)'",
- "stylelint": "stylelint --fix 'src/**/*.@(css|scss)'",
- "commitmsg": "commitlint -E GIT_PARAMS",
- "precommit": "lint-staged",
- "changelog": "node ./scripts/changelog.js",
- "prepub": "npm run eslint && npm run stylelint && npm run changelog && npm run build && npm run check && npm run docs && npm run pack && npm run pack -- minimize"
- },
- "lint-staged": {
- "@(src|scripts|docs/*/demo)/**/*.@(js|jsx)": [
- "prettier --write"
- ],
- "@(src|scripts|docs/*/demo)/**/*.@(js|jsx|md)": [
- "eslint",
- "git add"
- ],
- "src/**/*.@(css|scss)": [
- "stylelint",
- "git add"
- ]
- },
- "dependencies": {
- "babel-runtime": "^6.26.0",
- "classnames": "^2.2.3",
- "hoist-non-react-statics": "^2.1.0",
- "prop-types": "^15.6.0",
- "react-transition-group": "^2.2.1",
- "shallow-element-equals": "^1.0.1"
- },
- "devDependencies": {
- "@alifd/api-extractor": "^3.4.0",
- "@alifd/babel-preset-next": "^2.0.0",
- "@alifd/doc-parser": "^1.0.0",
- "@alifd/dts-generator": "^1.0.3",
- "@alifd/eslint-config-next": "^2.0.0",
- "@alifd/stylelint-config-next": "^1.0.0",
- "@commitlint/cli": "^7.0.0",
- "@no-repeat/sass-mapper": "^0.0.6",
- "@no-repeat/sass-tracker": "^0.0.10",
- "@no-repeat/sassdoc-parser": "^0.0.11",
- "@octokit/rest": "^15.15.1",
- "autoprefixer": "^7.1.4",
- "axe-core": "3.1.2",
- "babel-core": "^6.26.0",
- "babel-eslint": "^8.2.3",
- "babel-loader": "^7.0.0",
- "babel-plugin-espower": "^2.3.2",
- "babel-plugin-istanbul": "^4.1.5",
- "babel-polyfill": "^6.26.0",
- "case-sensitive-paths-webpack-plugin": "^2.1.1",
- "chalk": "^2.3.2",
- "cheerio": "^1.0.0-rc.2",
- "chokidar": "^2.0.4",
- "chrome-launcher": "^0.10.2",
- "co": "^4.6.0",
- "console-polyfill": "^0.3.0",
- "conventional-changelog": "^2.0.1",
- "css-loader": "^0.28.7",
- "css-split-webpack-plugin": "^0.2.5",
- "ejs": "^2.5.9",
- "enzyme": "^3.3.0",
- "enzyme-adapter-react-16": "^1.1.1",
- "es5-shim": "^4.5.9",
- "es6-promise-polyfill": "^1.2.0",
- "eslint": "^4.19.1",
- "eslint-config-prettier": "^4.0.0",
- "eslint-plugin-html": "^5.0.0",
- "eslint-plugin-import": "^2.12.0",
- "eslint-plugin-markdown": "^1.0.0-beta.6",
- "eslint-plugin-react": "7.11.1",
- "expect.js": "^0.3.1",
- "extract-text-webpack-plugin": "^3.0.0",
- "fast-sass-loader": "^1.2.5",
- "fs-extra": "^5.0.0",
- "glob": "^7.1.2",
- "highlight.js": "^9.12.0",
- "html5shiv": "^3.7.3",
- "husky": "^0.14.3",
- "inquirer": "^6.1.0",
- "jsonp": "^0.2.1",
- "karma": "^3.0.0",
- "karma-chrome-launcher": "^2.2.0",
- "karma-coverage": "^1.1.1",
- "karma-mocha": "^1.3.0",
- "karma-sourcemap-loader": "^0.3.7",
- "karma-spec-reporter": "^0.0.26",
- "karma-webdriver-launcher": "^1.0.5",
- "karma-webpack": "^3.0.5",
- "lint-staged": "^7.2.2",
- "loader-utils": "^1.1.0",
- "lodash": "^4.17.5",
- "markdown-it": "^8.4.2",
- "md5": "^2.2.1",
- "minimist": "^1.2.0",
- "mocha": "^3.5.3",
- "moment": "^2.20.1",
- "node-sass": "4.6.0",
- "node-sass-package-importer": "^5.2.0",
- "postcss-loader": "^2.0.6",
- "postcss-scss": "1.0.2",
- "power-assert": "^1.5.0",
- "prettier": "1.16.4",
- "promise-polyfill": "^8.1.0",
- "react": "^16.0.0",
- "react-axe": "^3.0.2",
- "react-copy-to-clipboard": "^5.0.1",
- "react-cropper": "^1.0.0",
- "react-dev-utils": "^4.2.1",
- "react-dom": "^16.0.0",
- "react-redux": "^5.0.7",
- "react-router": "^4.3.1",
- "redux": "^4.0.0",
- "remark": "^9.0.0",
- "sass": "^1.15.2",
- "sassaby-next": "^3.0.0",
- "simulate-event": "^1.4.0",
- "sinon": "^5.0.10",
- "style-loader": "^0.18.2",
- "stylelint": "^9.2.1",
- "stylelint-scss": "^3.1.1",
- "typescript": "^3.0.1",
- "webpack": "^3.0.0",
- "webpack-dev-server": "^2.x",
- "whatwg-fetch": "^2.0.3"
- },
- "peerDependencies": {
- "moment": "^2.22.1",
- "react": "^16.0.0",
- "react-dom": "^16.0.0"
- },
- "publishConfig": {
- "access": "public"
- }
+ "src/**/*.@(css|scss)": [
+ "stylelint",
+ "git add"
+ ]
+ },
+ "dependencies": {
+ "babel-runtime": "^6.26.0",
+ "classnames": "^2.2.3",
+ "hoist-non-react-statics": "^2.1.0",
+ "prop-types": "^15.6.0",
+ "react-transition-group": "^2.2.1",
+ "shallow-element-equals": "^1.0.1"
+ },
+ "devDependencies": {
+ "@alifd/api-extractor": "^3.4.0",
+ "@alifd/babel-preset-next": "^2.0.0",
+ "@alifd/doc-parser": "^1.0.0",
+ "@alifd/dts-generator": "^1.0.3",
+ "@alifd/eslint-config-next": "^2.0.0",
+ "@alifd/stylelint-config-next": "^1.0.0",
+ "@commitlint/cli": "^7.0.0",
+ "@no-repeat/sass-mapper": "^0.0.6",
+ "@no-repeat/sass-tracker": "^0.0.10",
+ "@no-repeat/sassdoc-parser": "^0.0.11",
+ "@octokit/rest": "^15.15.1",
+ "autoprefixer": "^7.1.4",
+ "axe-core": "^3.2.0",
+ "babel-core": "^6.26.0",
+ "babel-eslint": "^8.2.3",
+ "babel-loader": "^7.0.0",
+ "babel-plugin-espower": "^2.3.2",
+ "babel-plugin-istanbul": "^4.1.5",
+ "babel-polyfill": "^6.26.0",
+ "case-sensitive-paths-webpack-plugin": "^2.1.1",
+ "chalk": "^2.3.2",
+ "cheerio": "^1.0.0-rc.2",
+ "chokidar": "^2.0.4",
+ "chrome-launcher": "^0.10.2",
+ "co": "^4.6.0",
+ "console-polyfill": "^0.3.0",
+ "conventional-changelog": "^2.0.1",
+ "css-loader": "^0.28.7",
+ "css-split-webpack-plugin": "^0.2.5",
+ "ejs": "^2.5.9",
+ "enzyme": "^3.3.0",
+ "enzyme-adapter-react-16": "~1.10.0",
+ "es5-shim": "^4.5.9",
+ "es6-promise-polyfill": "^1.2.0",
+ "eslint": "^4.19.1",
+ "eslint-config-prettier": "^4.0.0",
+ "eslint-plugin-html": "^5.0.0",
+ "eslint-plugin-import": "^2.12.0",
+ "eslint-plugin-markdown": "^1.0.0-beta.6",
+ "eslint-plugin-react": "7.11.1",
+ "expect.js": "^0.3.1",
+ "extract-text-webpack-plugin": "^3.0.0",
+ "fast-sass-loader": "^1.2.5",
+ "fs-extra": "^5.0.0",
+ "glob": "^7.1.2",
+ "highlight.js": "^9.12.0",
+ "html5shiv": "^3.7.3",
+ "husky": "^0.14.3",
+ "inquirer": "^6.1.0",
+ "jsonp": "^0.2.1",
+ "karma": "^3.0.0",
+ "karma-chrome-launcher": "^2.2.0",
+ "karma-coverage": "^1.1.1",
+ "karma-mocha": "^1.3.0",
+ "karma-sourcemap-loader": "^0.3.7",
+ "karma-spec-reporter": "^0.0.26",
+ "karma-webdriver-launcher": "^1.0.5",
+ "karma-webpack": "^3.0.5",
+ "lint-staged": "^7.2.2",
+ "loader-utils": "^1.1.0",
+ "lodash": "^4.17.5",
+ "markdown-it": "^8.4.2",
+ "md5": "^2.2.1",
+ "minimist": "^1.2.0",
+ "mocha": "^3.5.3",
+ "moment": "^2.20.1",
+ "node-sass": "4.6.0",
+ "node-sass-package-importer": "^5.2.0",
+ "postcss-loader": "^2.0.6",
+ "postcss-scss": "1.0.2",
+ "power-assert": "^1.5.0",
+ "prettier": "1.16.4",
+ "promise-polyfill": "^8.1.0",
+ "react": "^16.0.0",
+ "react-axe": "^3.0.2",
+ "react-copy-to-clipboard": "^5.0.1",
+ "react-cropper": "^1.0.0",
+ "react-dev-utils": "^4.2.1",
+ "react-dom": "^16.0.0",
+ "react-redux": "^5.0.7",
+ "react-router": "^4.3.1",
+ "redux": "^4.0.0",
+ "remark": "^9.0.0",
+ "sass": "^1.15.2",
+ "sassaby-next": "^3.0.0",
+ "simulate-event": "^1.4.0",
+ "sinon": "^5.0.10",
+ "style-loader": "^0.18.2",
+ "stylelint": "^9.2.1",
+ "stylelint-scss": "^3.1.1",
+ "typescript": "^3.0.1",
+ "webpack": "^3.0.0",
+ "webpack-dev-server": "^2.x",
+ "whatwg-fetch": "^2.0.3"
+ },
+ "peerDependencies": {
+ "moment": "^2.22.1",
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0"
+ },
+ "publishConfig": {
+ "access": "public"
+ }
}
diff --git a/scripts/test/a11y-allinone.js b/scripts/test/a11y-allinone.js
new file mode 100644
index 0000000000..f6630e232a
--- /dev/null
+++ b/scripts/test/a11y-allinone.js
@@ -0,0 +1,2 @@
+const testsContext = require.context('../../test/', true, /a11y-spec.js$/);
+testsContext.keys().forEach(testsContext);
diff --git a/scripts/test/a11y-index.js b/scripts/test/a11y-index.js
new file mode 100644
index 0000000000..53a2e40b3c
--- /dev/null
+++ b/scripts/test/a11y-index.js
@@ -0,0 +1,47 @@
+// const fs = require('fs-extra');
+const { join } = require('path');
+const { Server } = require('karma');
+const co = require('co');
+const inquirer = require('inquirer');
+const { logger } = require('../utils');
+
+let server = null;
+
+const config = {
+ configFile: join(__dirname, 'karma.js'),
+ component: 'all',
+ runAll: true,
+ a11y: true,
+};
+
+const runAllTestA11y = () => {
+ config.runAll = true;
+ config.a11y = true;
+ server = new Server(config);
+ server.start();
+};
+
+co(function*() {
+ if (process.env.TRAVIS) {
+ runAllTestA11y();
+ } else {
+ const allTest = yield inquirer.prompt([
+ {
+ name: 'runAllTest',
+ type: 'list',
+ choices: ['yes', 'no'],
+ default: 1,
+ message: logger.success(
+ 'This will run ALL components test cases, are you sure to run all?'
+ ),
+ },
+ ]);
+
+ if (allTest.runAllTest === 'no') {
+ logger.success('quit');
+ return;
+ } else {
+ runAllTestA11y();
+ }
+ }
+});
diff --git a/scripts/test/allinone.js b/scripts/test/allinone.js
index d80b40742c..de21a8a722 100644
--- a/scripts/test/allinone.js
+++ b/scripts/test/allinone.js
@@ -1,2 +1,6 @@
-const testsContext = require.context('../../test/', true, /-spec.js$/);
+const testsContext = require.context(
+ '../../test/',
+ true,
+ /^.*(? {
@@ -63,11 +64,12 @@ const runRest = components => {
}
};
-const runAllTest = () => {
+const runAllTest = (a11y = false) => {
// const components = fs.readdirSync(join(process.cwd(), 'test'));
// runRest(components);
config.runAll = true;
+ config.a11y = a11y;
server = new Server(config);
server.start();
};
diff --git a/scripts/test/karma.js b/scripts/test/karma.js
index 538573f81e..e905f9d540 100644
--- a/scripts/test/karma.js
+++ b/scripts/test/karma.js
@@ -3,7 +3,7 @@ const _ = require('lodash');
const getWebpackConfig = require('./webpack');
module.exports = function(config) {
- const { runAll } = config;
+ const { runAll, a11y } = config;
const componentName = config.component
? _.kebabCase(config.component)
: config.component;
@@ -13,9 +13,15 @@ module.exports = function(config) {
// 'table' or 'table|tree|tree-select'
// const componentList = componentArray ? componentArray.join('|') : componentName;
- const specPath = runAll
- ? resolveCwd('scripts/test/allinone.js')
- : resolveCwd('test', `@(${componentName})/*-spec.js`);
+ let specPath;
+
+ if (runAll && a11y) {
+ specPath = resolveCwd('scripts/test/a11y-allinone.js');
+ } else if (runAll) {
+ specPath = resolveCwd('scripts/test/allinone.js');
+ } else {
+ specPath = resolveCwd('test', `@(${componentName})/*-spec.js`);
+ }
const options = {
frameworks: ['mocha'],
diff --git a/src/calendar/calendar.jsx b/src/calendar/calendar.jsx
index acdce2dc75..2d2ef56a0e 100644
--- a/src/calendar/calendar.jsx
+++ b/src/calendar/calendar.jsx
@@ -83,6 +83,7 @@ class Calendar extends Component {
/**
* 不可选择的日期
* @param {Object} calendarDate 对应 Calendar 返回的自定义日期对象
+ * @param {String} view 当前视图类型,year: 年, month: 月, date: 日
* @returns {Boolean}
*/
disabledDate: PropTypes.func,
diff --git a/src/calendar/range-calendar.jsx b/src/calendar/range-calendar.jsx
index e2ef1d7e07..0e7bd8f9a2 100644
--- a/src/calendar/range-calendar.jsx
+++ b/src/calendar/range-calendar.jsx
@@ -66,6 +66,7 @@ class RangeCalendar extends React.Component {
/**
* 不可选择的日期
* @param {Object} calendarDate 对应 Calendar 返回的自定义日期对象
+ * @param {String} view 当前视图类型,year: 年, month: 月, date: 日
* @returns {Boolean}
*/
disabledDate: PropTypes.func,
diff --git a/src/calendar/table/date-table.jsx b/src/calendar/table/date-table.jsx
index f1b993a3d8..e10290fec2 100644
--- a/src/calendar/table/date-table.jsx
+++ b/src/calendar/table/date-table.jsx
@@ -88,7 +88,11 @@ class DateTable extends PureComponent {
const isNextMonth = isNextMonthDate(currentDate, visibleMonth);
const isCurrentMonth = !isLastMonth && !isNextMonth;
- const isDisabled = isDisabledDate(currentDate, disabledDate);
+ const isDisabled = isDisabledDate(
+ currentDate,
+ disabledDate,
+ 'date'
+ );
const isToday =
!isDisabled &&
isSameDay(currentDate, today) &&
diff --git a/src/calendar/table/month-table.jsx b/src/calendar/table/month-table.jsx
index 7cf3cd9d9b..2f7d1c208b 100644
--- a/src/calendar/table/month-table.jsx
+++ b/src/calendar/table/month-table.jsx
@@ -38,7 +38,11 @@ class MonthTable extends PureComponent {
const rowList = [];
for (let j = 0; j < MONTH_TABLE_COL_COUNT; j++) {
const monthDate = visibleMonth.clone().month(counter);
- const isDisabled = isDisabledDate(monthDate, disabledDate);
+ const isDisabled = isDisabledDate(
+ monthDate,
+ disabledDate,
+ 'month'
+ );
const isSelected = isSameMonth(monthDate, value);
const isThisMonth = isSameMonth(monthDate, today);
const elementCls = classnames({
diff --git a/src/calendar/table/year-table.jsx b/src/calendar/table/year-table.jsx
index 39bd911f11..77070343f3 100644
--- a/src/calendar/table/year-table.jsx
+++ b/src/calendar/table/year-table.jsx
@@ -56,7 +56,7 @@ class YearTable extends React.PureComponent {
content = year;
title = year;
const yearDate = visibleMonth.clone().year(year);
- isDisabled = isDisabledDate(yearDate, disabledDate);
+ isDisabled = isDisabledDate(yearDate, disabledDate, 'year');
!isDisabled &&
(onClick = this.onYearCellClick.bind(this, yearDate));
diff --git a/src/calendar/utils/index.js b/src/calendar/utils/index.js
index 16a0018c83..3b834b162d 100644
--- a/src/calendar/utils/index.js
+++ b/src/calendar/utils/index.js
@@ -26,8 +26,8 @@ export const CALENDAR_MODES = [
CALENDAR_MODE_YEAR,
];
-export function isDisabledDate(date, fn) {
- if (typeof fn === 'function' && fn(date)) {
+export function isDisabledDate(date, fn, view) {
+ if (typeof fn === 'function' && fn(date, view)) {
return true;
}
return false;
diff --git a/src/cascader-select/cascader-select.jsx b/src/cascader-select/cascader-select.jsx
index b336bca338..2003ec5a35 100644
--- a/src/cascader-select/cascader-select.jsx
+++ b/src/cascader-select/cascader-select.jsx
@@ -392,9 +392,13 @@ export default class CascaderSelect extends Component {
return null;
}
+ if (Array.isArray(value)) value = value[0];
+
const data = this._v2n[value];
if (!data) {
- return null;
+ return {
+ value,
+ };
}
const labelPath = this.getLabelPath(data);
@@ -408,12 +412,21 @@ export default class CascaderSelect extends Component {
}
getMultipleData(value) {
+ if (!value.length) {
+ return null;
+ }
+
const { checkStrictly, canOnlyCheckLeaf, displayRender } = this.props;
- let data = this.getData(
- checkStrictly || canOnlyCheckLeaf ? value : this.flatValue(value)
- );
+ let data = (checkStrictly || canOnlyCheckLeaf
+ ? value
+ : this.flatValue(value)
+ ).map(v => this._v2n[v] || { value: v });
+
if (displayRender) {
data = data.map(item => {
+ if (!item.pos) {
+ return item;
+ }
const labelPath = this.getLabelPath(item);
return {
diff --git a/src/collapse/main.scss b/src/collapse/main.scss
index 8708c88e57..8d9bbe5ccf 100644
--- a/src/collapse/main.scss
+++ b/src/collapse/main.scss
@@ -11,6 +11,11 @@
border: $collapse-border-width solid $collapse-border-color;
border-radius: $collapse-border-corner;
overflow: hidden;
+ &:focus,
+ & *:focus {
+ outline: 0;
+ }
+
&-panel {
&:not(:first-child) {
border-top: $collapse-title-border-width solid $collapse-panel-border-color;
diff --git a/src/config-provider/config.jsx b/src/config-provider/config.jsx
index 8075b92ddf..efdedd8446 100644
--- a/src/config-provider/config.jsx
+++ b/src/config-provider/config.jsx
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import hoistNonReactStatic from 'hoist-non-react-statics';
import { obj, log } from '../util';
import getContextProps from './get-context-props';
+import ErrorBoundary from './error-boundary';
const { shallowEqual } = obj;
@@ -89,6 +90,10 @@ export function config(Component, options = {}) {
locale: PropTypes.object,
pure: PropTypes.bool,
rtl: PropTypes.bool,
+ errorBoundary: PropTypes.oneOfType([
+ PropTypes.bool,
+ PropTypes.object,
+ ]),
};
static contextTypes = {
...(Component.contextTypes || {}),
@@ -97,6 +102,10 @@ export function config(Component, options = {}) {
nextPure: PropTypes.bool,
nextRtl: PropTypes.bool,
nextWarning: PropTypes.bool,
+ nextErrorBoundary: PropTypes.oneOfType([
+ PropTypes.bool,
+ PropTypes.object,
+ ]),
};
constructor(props, context) {
@@ -132,18 +141,26 @@ export function config(Component, options = {}) {
}
render() {
- const { prefix, locale, pure, rtl, ...others } = this.props;
+ const {
+ prefix,
+ locale,
+ pure,
+ rtl,
+ errorBoundary,
+ ...others
+ } = this.props;
const {
nextPrefix,
nextLocale = {},
nextPure,
nextRtl,
+ nextErrorBoundary,
} = this.context;
const displayName =
options.componentName || getDisplayName(Component);
const contextProps = getContextProps(
- { prefix, locale, pure, rtl },
+ { prefix, locale, pure, rtl, errorBoundary },
{
nextPrefix,
nextLocale: { ...currentGlobalLocale, ...nextLocale },
@@ -154,10 +171,12 @@ export function config(Component, options = {}) {
: currentGlobalRtl === true
? true
: undefined,
+ nextErrorBoundary,
},
displayName
);
+ // errorBoundary is only for
const newContextProps = ['prefix', 'locale', 'pure', 'rtl'].reduce(
(ret, name) => {
if (typeof contextProps[name] !== 'undefined') {
@@ -172,13 +191,21 @@ export function config(Component, options = {}) {
? options.transform(others, this._deprecated)
: others;
- return (
+ const content = (
);
+
+ const { open, ...othersBoundary } = contextProps.errorBoundary;
+
+ return open ? (
+ {content}
+ ) : (
+ content
+ );
}
}
diff --git a/src/config-provider/error-boundary.jsx b/src/config-provider/error-boundary.jsx
new file mode 100644
index 0000000000..27041de87f
--- /dev/null
+++ b/src/config-provider/error-boundary.jsx
@@ -0,0 +1,63 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+DefaultUI.propTypes = {
+ error: PropTypes.object,
+ errorInfo: PropTypes.object,
+};
+
+function DefaultUI() {
+ return '';
+}
+
+export default class ErrorBoundary extends React.Component {
+ static propTypes = {
+ children: PropTypes.element,
+ /**
+ * 捕获错误后的自定义处理, 比如埋点上传
+ * @param {Object} error 错误
+ * @param {Object} errorInfo 错误详细信息
+ */
+ afterCatch: PropTypes.func,
+ /**
+ * 捕获错误后的展现 自定义组件
+ * @param {Object} error 错误
+ * @param {Object} errorInfo 错误详细信息
+ * @returns {Element} 捕获错误后的处理
+ */
+ fallbackUI: PropTypes.func,
+ };
+
+ constructor(props) {
+ super(props);
+ this.state = { error: null, errorInfo: null };
+ }
+
+ componentDidCatch(error, errorInfo) {
+ this.setState({
+ error: error,
+ errorInfo: errorInfo,
+ });
+
+ const { afterCatch } = this.props;
+
+ if ('afterCatch' in this.props && typeof afterCatch === 'function') {
+ this.props.afterCatch(error, errorInfo);
+ }
+ }
+
+ render() {
+ const { fallbackUI: FallbackUI = DefaultUI } = this.props;
+
+ if (this.state.errorInfo) {
+ return (
+
+ );
+ }
+ // Normally, just render children
+ return this.props.children;
+ }
+}
diff --git a/src/config-provider/get-context-props.jsx b/src/config-provider/get-context-props.jsx
index 8438162d26..e2382ef99d 100644
--- a/src/config-provider/get-context-props.jsx
+++ b/src/config-provider/get-context-props.jsx
@@ -1,6 +1,31 @@
+/**
+ *
+ * @param {Object|Boolean} input
+ * @returns {Object} typeof obj.open === 'boolean'
+ */
+const parseBoundary = input => {
+ let obj;
+ if (input === undefined || input === null) {
+ return {};
+ } else if (typeof input === 'boolean') {
+ obj = { open: input };
+ } else {
+ obj = { open: true, ...input };
+ }
+
+ return obj;
+};
+
export default function getContextProps(props, context, displayName) {
- const { prefix, locale, pure, rtl } = props;
- const { nextPrefix, nextLocale, nextPure, nextWarning, nextRtl } = context;
+ const { prefix, locale, pure, rtl, errorBoundary } = props;
+ const {
+ nextPrefix,
+ nextLocale,
+ nextPure,
+ nextWarning,
+ nextRtl,
+ nextErrorBoundary,
+ } = context;
const newPrefix = prefix || nextPrefix;
@@ -21,11 +46,24 @@ export default function getContextProps(props, context, displayName) {
const newPure = typeof pure === 'boolean' ? pure : nextPure;
const newRtl = typeof rtl === 'boolean' ? rtl : nextRtl;
+ // ProtoType of [nextE|e]rrorBoundary can be one of [boolean, object]
+ // but typeof newErrorBoundary === 'object'
+ // newErrorBoundary should always have the key 'open', which indicates ErrorBoundary on or off
+ const newErrorBoundary = {
+ ...parseBoundary(nextErrorBoundary),
+ ...parseBoundary(errorBoundary),
+ };
+
+ if (!('open' in newErrorBoundary)) {
+ newErrorBoundary.open = false;
+ }
+
return {
prefix: newPrefix,
locale: newLocale,
pure: newPure,
rtl: newRtl,
warning: nextWarning,
+ errorBoundary: newErrorBoundary,
};
}
diff --git a/src/config-provider/index.jsx b/src/config-provider/index.jsx
index 45db6ee964..a150d092cd 100644
--- a/src/config-provider/index.jsx
+++ b/src/config-provider/index.jsx
@@ -12,6 +12,7 @@ import {
getDirection,
} from './config';
import Consumer from './consumer';
+import ErrorBoundary from './error-boundary';
import Cache from './cache';
const childContextCache = new Cache();
@@ -30,6 +31,14 @@ class ConfigProvider extends Component {
* 国际化文案对象,属性为组件的 displayName
*/
locale: PropTypes.object,
+ /**
+ * 是否开启错误捕捉 errorBoundary
+ * 如需自定义参数,请传入对象 对象接受参数列表如下:
+ *
+ * fallbackUI `Function(error?: {}, errorInfo?: {}) => Element` 捕获错误后的展示
+ * afterCatch `Function(error?: {}, errorInfo?: {})` 捕获错误后的行为, 比如埋点上传
+ */
+ errorBoundary: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),
/**
* 是否开启 Pure Render 模式,会提高性能,但是也会带来副作用
*/
@@ -50,6 +59,7 @@ class ConfigProvider extends Component {
static defaultProps = {
warning: true,
+ errorBoundary: false,
};
static childContextTypes = {
@@ -58,6 +68,10 @@ class ConfigProvider extends Component {
nextPure: PropTypes.bool,
nextRtl: PropTypes.bool,
nextWarning: PropTypes.bool,
+ nextErrorBoundary: PropTypes.oneOfType([
+ PropTypes.bool,
+ PropTypes.object,
+ ]),
};
/**
@@ -92,10 +106,17 @@ class ConfigProvider extends Component {
static getLocale = getLocale;
static getDirection = getDirection;
static Consumer = Consumer;
+ static ErrorBoundary = ErrorBoundary;
static getContext = () => {
- const { nextPrefix, nextLocale, nextPure, nextRtl, nextWarning } =
- childContextCache.root() || {};
+ const {
+ nextPrefix,
+ nextLocale,
+ nextPure,
+ nextRtl,
+ nextWarning,
+ nextErrorBoundary,
+ } = childContextCache.root() || {};
return {
prefix: nextPrefix,
@@ -103,6 +124,7 @@ class ConfigProvider extends Component {
pure: nextPure,
rtl: nextRtl,
warning: nextWarning,
+ errorBoundary: nextErrorBoundary,
};
};
@@ -119,7 +141,14 @@ class ConfigProvider extends Component {
}
getChildContext() {
- const { prefix, locale, pure, warning, rtl } = this.props;
+ const {
+ prefix,
+ locale,
+ pure,
+ warning,
+ rtl,
+ errorBoundary,
+ } = this.props;
return {
nextPrefix: prefix,
@@ -127,6 +156,7 @@ class ConfigProvider extends Component {
nextPure: pure,
nextRtl: rtl,
nextWarning: warning,
+ nextErrorBoundary: errorBoundary,
};
}
diff --git a/src/date-picker/date-picker.jsx b/src/date-picker/date-picker.jsx
index c05550016f..9297db900d 100644
--- a/src/date-picker/date-picker.jsx
+++ b/src/date-picker/date-picker.jsx
@@ -68,6 +68,7 @@ export default class DatePicker extends Component {
/**
* 禁用日期函数
* @param {MomentObject} 日期值
+ * @param {String} view 当前视图类型,year: 年, month: 月, date: 日
* @return {Boolean} 是否禁用
*/
disabledDate: PropTypes.func,
@@ -300,7 +301,7 @@ export default class DatePicker extends Component {
inputing: false,
});
- if (parsed.isValid() && !disabledDate(parsed)) {
+ if (parsed.isValid() && !disabledDate(parsed, 'date')) {
this.handleChange(parsed, this.state.value);
}
}
diff --git a/src/date-picker/month-picker.jsx b/src/date-picker/month-picker.jsx
index b441b3d235..a6339e7e2f 100644
--- a/src/date-picker/month-picker.jsx
+++ b/src/date-picker/month-picker.jsx
@@ -50,6 +50,7 @@ class MonthPicker extends Component {
/**
* 禁用日期函数
* @param {MomentObject} 日期值
+ * @param {String} view 当前视图类型,year: 年, month: 月, date: 日
* @return {Boolean} 是否禁用
*/
disabledDate: PropTypes.func,
@@ -240,7 +241,7 @@ class MonthPicker extends Component {
inputing: false,
});
- if (parsed.isValid() && !disabledDate(parsed)) {
+ if (parsed.isValid() && !disabledDate(parsed, 'month')) {
this.handleChange(parsed, this.state.value);
}
}
diff --git a/src/date-picker/range-picker.jsx b/src/date-picker/range-picker.jsx
index 4f1e48a40c..3513e946dd 100644
--- a/src/date-picker/range-picker.jsx
+++ b/src/date-picker/range-picker.jsx
@@ -82,6 +82,7 @@ export default class RangePicker extends Component {
/**
* 禁用日期函数
* @param {MomentObject} 日期值
+ * @param {String} view 当前视图类型,year: 年, month: 月, date: 日
* @return {Boolean} 是否禁用
*/
disabledDate: PropTypes.func,
@@ -397,7 +398,7 @@ export default class RangePicker extends Component {
inputing: false,
});
- if (parsed.isValid() && !disabledDate(parsed)) {
+ if (parsed.isValid() && !disabledDate(parsed, 'date')) {
const valueName = this.state.activeDateInput;
const newValue = parsed;
diff --git a/src/date-picker/year-picker.jsx b/src/date-picker/year-picker.jsx
index 31c80ca21d..1ec41fc2e3 100644
--- a/src/date-picker/year-picker.jsx
+++ b/src/date-picker/year-picker.jsx
@@ -45,6 +45,7 @@ class YearPicker extends Component {
/**
* 禁用日期函数
* @param {MomentObject} 日期值
+ * @param {String} view 当前视图类型,year: 年, month: 月, date: 日
* @return {Boolean} 是否禁用
*/
disabledDate: PropTypes.func,
@@ -230,7 +231,7 @@ class YearPicker extends Component {
inputing: false,
});
- if (parsed.isValid() && !disabledDate(parsed)) {
+ if (parsed.isValid() && !disabledDate(parsed, 'year')) {
this.handleChange(parsed, this.state.value);
}
}
diff --git a/src/locale/en-us.js b/src/locale/en-us.js
index 7f2aa47a69..c0daaa8935 100644
--- a/src/locale/en-us.js
+++ b/src/locale/en-us.js
@@ -116,4 +116,7 @@ export default {
Tag: {
delete: 'Delete',
},
+ Rating: {
+ description: 'Rating Options',
+ },
};
diff --git a/src/locale/ja-jp.js b/src/locale/ja-jp.js
index f7a4ce84ff..cf945133d3 100644
--- a/src/locale/ja-jp.js
+++ b/src/locale/ja-jp.js
@@ -114,4 +114,7 @@ export default {
Tag: {
delete: 'デリート',
},
+ Rating: {
+ description: '評価オプション',
+ },
};
diff --git a/src/locale/zh-cn.js b/src/locale/zh-cn.js
index dcdc7bedcb..7b2b2342d1 100644
--- a/src/locale/zh-cn.js
+++ b/src/locale/zh-cn.js
@@ -114,4 +114,7 @@ export default {
Tag: {
delete: '删除',
},
+ Rating: {
+ description: '评分选项',
+ },
};
diff --git a/src/locale/zh-tw.js b/src/locale/zh-tw.js
index 1f0afd64ed..1cce051afa 100644
--- a/src/locale/zh-tw.js
+++ b/src/locale/zh-tw.js
@@ -114,4 +114,7 @@ export default {
Tag: {
delete: '删除',
},
+ Rating: {
+ description: '評分選項',
+ },
};
diff --git a/src/overlay/utils/position.js b/src/overlay/utils/position.js
index 8eacb0e6b0..67eead3014 100644
--- a/src/overlay/utils/position.js
+++ b/src/overlay/utils/position.js
@@ -150,7 +150,7 @@ export default class Position {
);
this._setPinElementPostion(
pinElement,
- { left: inViewportLeft, right: inViewportTop },
+ { left: inViewportLeft, top: inViewportTop },
this.offset
);
return expectedAlign[0];
diff --git a/src/range/main.scss b/src/range/main.scss
index 9960a57daf..37eb97fe3c 100644
--- a/src/range/main.scss
+++ b/src/range/main.scss
@@ -54,4 +54,18 @@
);
}
}
+
+ &range[dir=rtl] {
+ .#{$css-prefix}range-mark {
+ position: relative;
+ cursor: auto;
+ .#{$css-prefix}range-mark-text {
+ position: absolute;
+ right: 0;
+ transform: translateX(50%);
+ padding-right: 2px;
+ text-align: center;
+ }
+ }
+ }
}
diff --git a/src/range/view/fixedSlider.jsx b/src/range/view/fixedSlider.jsx
index bd358e91c2..cab75a3e18 100644
--- a/src/range/view/fixedSlider.jsx
+++ b/src/range/view/fixedSlider.jsx
@@ -7,7 +7,13 @@ import { getPercent } from '../utils';
const Tooltip = Balloon.Tooltip;
const { noop } = func;
-function _getStyle(min, max, value) {
+function _getStyle(min, max, value, rtl) {
+ if (rtl) {
+ return {
+ left: `${getPercent(min, max, max + min - value[1])}%`,
+ right: `${getPercent(min, max, value[0])}%`,
+ };
+ }
return {
left: `${getPercent(min, max, value[0])}%`,
right: `${100 - getPercent(min, max, value[1])}%`,
@@ -24,6 +30,7 @@ function sliderFrag(props) {
onMouseEnter,
onMouseLeave,
onMouseDown,
+ rtl,
} = props;
const activeClass =
@@ -32,7 +39,7 @@ function sliderFrag(props) {
return (
value,
reverse: false,
+ rtl: false,
};
constructor(props) {
diff --git a/src/range/view/mark.jsx b/src/range/view/mark.jsx
index efb8fb140c..5d8174ddf0 100644
--- a/src/range/view/mark.jsx
+++ b/src/range/view/mark.jsx
@@ -14,6 +14,7 @@ export default class Mark extends React.Component {
prefix: PropTypes.string,
marks: PropTypes.object,
marksPosition: PropTypes.string,
+ rtl: PropTypes.bool,
};
static defaultProps = {
@@ -22,10 +23,11 @@ export default class Mark extends React.Component {
max: 100,
value: 0,
marksPosition: '',
+ rtl: false,
};
_renderItems() {
- const { min, max, value, prefix, marks } = this.props;
+ const { min, max, value, prefix, marks, rtl } = this.props;
const items = [];
Object.keys(marks).forEach((mark, i) => {
@@ -33,11 +35,22 @@ export default class Mark extends React.Component {
[`${prefix}range-mark-text`]: true,
activated: inRange(mark, value, min),
});
- const left = `${getPercent(min, max, mark)}%`;
+ let style;
+ if (rtl) {
+ style = {
+ right: `${getPercent(min, max, mark)}%`,
+ left: 'auto',
+ };
+ } else {
+ style = {
+ left: `${getPercent(min, max, mark)}%`,
+ right: 'auto',
+ };
+ }
items.push(
// "key" is for https://fb.me/react-warning-keys
-
+
{marks[mark]}
);
diff --git a/src/range/view/range.jsx b/src/range/view/range.jsx
index 5095d2e9ba..bfb5354618 100644
--- a/src/range/view/range.jsx
+++ b/src/range/view/range.jsx
@@ -243,6 +243,10 @@ export default class Range extends React.Component {
* tooltip是否默认展示
*/
tooltipVisible: PropTypes.bool,
+ /**
+ * 是否已rtl模式展示
+ */
+ rtl: PropTypes.bool,
};
static defaultProps = {
@@ -262,6 +266,7 @@ export default class Range extends React.Component {
reverse: false,
pure: false,
marksPosition: 'above',
+ rtl: false,
};
constructor(props) {
@@ -553,15 +558,15 @@ export default class Range extends React.Component {
// position => current (value type)
_positionToCurrent(position) {
const { start, end } = this._moving;
- const { step, min, max } = this.props;
+ const { step, min, max, rtl } = this.props;
if (position < start) {
position = start;
} else if (position > end) {
position = end;
}
- const percent = getPercent(start, end, position);
-
+ let percent = getPercent(start, end, position);
+ percent = rtl ? 100 - percent : percent;
// reset by step
const newValue = parseFloat(
(Math.round(((percent / 100) * (max - min)) / step) * step).toFixed(
@@ -574,12 +579,12 @@ export default class Range extends React.Component {
_currentToValue(current, preValue, lastPosition, isFixedWidth) {
const { dragging } = this._moving;
+ const { min, max } = this.props;
if (!_isMultiple(this.props.slider, isFixedWidth)) {
return current;
} else {
let result;
- const { min, max } = this.props;
const precision = getPrecision(this.props.step);
const diff = current - lastPosition;
@@ -659,6 +664,7 @@ export default class Range extends React.Component {
fixedWidth,
defaultValue,
tooltipVisible,
+ rtl,
} = this.props;
const classes = classNames({
[`${prefix}range`]: true,
@@ -689,6 +695,7 @@ export default class Range extends React.Component {
tooltipVisible,
hasMovingClass: this.state.hasMovingClass,
disabled,
+ rtl,
};
this.isFixedWidth =
@@ -707,6 +714,7 @@ export default class Range extends React.Component {
style={style}
className={classes}
id={id}
+ dir={rtl ? 'rtl' : 'ltr'}
onMouseDown={disabled ? noop : this._onMouseDown.bind(this)}
>
{marks !== false && marksPosition === 'above' ? (
diff --git a/src/range/view/scale.jsx b/src/range/view/scale.jsx
index bfd0519443..002ee2b629 100644
--- a/src/range/view/scale.jsx
+++ b/src/range/view/scale.jsx
@@ -13,6 +13,7 @@ export default class Scale extends React.Component {
]),
prefix: PropTypes.string,
scales: PropTypes.arrayOf(PropTypes.number),
+ rtl: PropTypes.bool,
};
static defaultProps = {
@@ -20,10 +21,11 @@ export default class Scale extends React.Component {
min: 0,
max: 100,
value: 0,
+ rtl: false,
};
_renderItems() {
- const { min, max, value, prefix, scales } = this.props;
+ const { min, max, value, prefix, scales, rtl } = this.props;
const items = [];
scales.forEach((scale, i) => {
@@ -31,11 +33,22 @@ export default class Scale extends React.Component {
[`${prefix}range-scale-item`]: true,
activated: inRange(scale, value, min),
});
- const left = `${getPercent(min, max, scale)}%`;
+ let style;
+ if (rtl) {
+ style = {
+ right: `${getPercent(min, max, scale)}%`,
+ left: 'auto',
+ };
+ } else {
+ style = {
+ left: `${getPercent(min, max, scale)}%`,
+ right: 'auto',
+ };
+ }
items.push(
// "key" is for https://fb.me/react-warning-keys
-
+
);
});
diff --git a/src/range/view/selected.jsx b/src/range/view/selected.jsx
index 82f3843ae5..65c1bcb99e 100644
--- a/src/range/view/selected.jsx
+++ b/src/range/view/selected.jsx
@@ -14,6 +14,7 @@ export default class Selected extends React.Component {
]),
prefix: PropTypes.string,
reverse: PropTypes.bool,
+ rtl: PropTypes.bool,
};
static defaultProps = {
@@ -23,10 +24,11 @@ export default class Selected extends React.Component {
max: 100,
value: 0,
reverse: false,
+ rtl: false,
};
_getStyle() {
- const { min, max, reverse } = this.props;
+ const { min, max, reverse, rtl } = this.props;
let { value } = this.props;
if (!Array.isArray(value)) {
@@ -34,21 +36,39 @@ export default class Selected extends React.Component {
}
const width = ((value[1] - value[0]) * 100) / (max - min);
- let style = {
- width: `${width}%`,
- left: `${getPercent(min, max, value[0])}%`,
- };
- if (reverse) {
+ let style;
+
+ if (!rtl && !reverse) {
+ // normal select
+ style = {
+ width: `${width}%`,
+ left: `${getPercent(min, max, value[0])}%`,
+ };
+ } else if (rtl && !reverse) {
+ // select in rtl mode
+ style = {
+ width: `${width}%`,
+ left: `${getPercent(min, max, max + min - value[1])}%`,
+ };
+ } else if (!rtl && reverse) {
+ // select in reverse mode
style = {
width: `${100 - width}%`,
left: `${getPercent(min, max, value[0]) + width}%`,
};
+ } else {
+ // select in rtl & reverse mode
+ style = {
+ width: `${100 - width}%`,
+ left: `${getPercent(min, max, value[0])}%`,
+ };
}
+
return style;
}
_getStyleLeft() {
- const { min, max } = this.props;
+ const { min, max, rtl } = this.props;
let { value } = this.props;
if (!Array.isArray(value)) {
@@ -59,11 +79,14 @@ export default class Selected extends React.Component {
width: `${getPercent(min, max, value[0])}%`,
left: 0,
};
+ if (rtl) {
+ style.width = `${100 - getPercent(min, max, value[1])}%`;
+ }
return style;
}
_getStyleRight() {
- const { min, max } = this.props;
+ const { min, max, rtl } = this.props;
let { value } = this.props;
if (!Array.isArray(value)) {
@@ -71,15 +94,22 @@ export default class Selected extends React.Component {
}
const width = ((value[1] - value[0]) * 100) / (max - min);
- const style = {
+ let style = {
width: `${100 - getPercent(min, max, value[0]) - width}%`,
left: `${getPercent(min, max, value[0]) + width}%`,
};
+
+ if (rtl) {
+ style = {
+ width: `${getPercent(min, max, value[0])}%`,
+ left: `${100 - getPercent(min, max, value[0])}%`,
+ };
+ }
return style;
}
render() {
- const { prefix, slider, reverse } = this.props;
+ const { prefix, slider, reverse, rtl } = this.props;
const classes = classNames({
[`${prefix}range-selected`]: true,
});
diff --git a/src/range/view/slider.jsx b/src/range/view/slider.jsx
index 174cccc94a..b739b17649 100644
--- a/src/range/view/slider.jsx
+++ b/src/range/view/slider.jsx
@@ -3,10 +3,12 @@ import classNames from 'classnames';
import PropTypes from 'prop-types';
import { getPercent } from '../utils';
-function _getProps(min, max, value) {
+function _getProps(min, max, value, rtl) {
return {
style: {
- left: `${getPercent(min, max, value)}%`,
+ left: rtl
+ ? `${100 - getPercent(min, max, value)}%`
+ : `${getPercent(min, max, value)}%`,
zIndex: 100,
},
'aria-valuenow': value,
@@ -16,7 +18,7 @@ function _getProps(min, max, value) {
};
}
-function Slider({ prefix, hasMovingClass, min, max, value, onKeyDown }) {
+function Slider({ prefix, hasMovingClass, min, max, value, onKeyDown, rtl }) {
const classes = classNames({
[`${prefix}range-slider`]: true,
[`${prefix}range-slider-moving`]: hasMovingClass,
@@ -27,7 +29,7 @@ function Slider({ prefix, hasMovingClass, min, max, value, onKeyDown }) {
onKeyDown={onKeyDown}
role="slider"
tabIndex={0}
- {..._getProps(min, max, value)}
+ {..._getProps(min, max, value, rtl)}
>
@@ -40,6 +42,7 @@ Slider.propTypes = {
value: PropTypes.number,
prefix: PropTypes.string,
hasMovingClass: PropTypes.bool,
+ rtl: PropTypes.bool,
};
Slider.defaultProps = {
@@ -48,6 +51,7 @@ Slider.defaultProps = {
max: 100,
value: 0,
hasMovingClass: false,
+ rtl: false,
};
export default Slider;
diff --git a/src/rating/rating.jsx b/src/rating/rating.jsx
index 1734383780..4476ebebb0 100644
--- a/src/rating/rating.jsx
+++ b/src/rating/rating.jsx
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import classNames from 'classnames';
import Icon from '../icon';
import { func, KEYCODE, obj } from '../util';
+import zhCN from '../locale/zh-cn';
const { noop, bindCtx } = func;
const { ENTER, LEFT, UP, RIGHT, DOWN } = KEYCODE;
@@ -68,6 +69,10 @@ export default class Rating extends Component {
className: PropTypes.string,
id: PropTypes.string,
rtl: PropTypes.bool,
+ /**
+ * 自定义国际化文案对象
+ */
+ locale: PropTypes.object,
};
static defaultProps = {
@@ -82,6 +87,7 @@ export default class Rating extends Component {
iconType: 'favorites-filling',
onChange: noop,
onHoverChange: noop,
+ locale: zhCN.Rating,
};
static currentValue(min, max, hoverValue, stateValue) {
@@ -306,6 +312,7 @@ export default class Rating extends Component {
disabled,
readAs,
rtl,
+ locale,
} = this.props;
const others = obj.pickOthers(Rating.propTypes, this.props);
const { hoverValue, clicked } = this.state;
@@ -355,7 +362,6 @@ export default class Rating extends Component {
onChange={this.handleChecked.bind(this, i + 1)}
type="radio"
name="rating"
- aria-labelledby={id}
/>
);
}
@@ -419,11 +425,14 @@ export default class Rating extends Component {
className={ratingCls}
onKeyDown={this.onKeyDown}
tabIndex="0"
+ role="group"
+ aria-label={locale.description}
>
(this.underlayNode = n)}
+ aria-hidden
>
{underlay}
diff --git a/src/select/main.scss b/src/select/main.scss
index 110e2a54f2..cf577e3470 100644
--- a/src/select/main.scss
+++ b/src/select/main.scss
@@ -307,14 +307,20 @@
&-all {
display: block;
cursor: pointer;
- line-height: $select-menu-item-height;
- padding: $s-1 $s-2;
+ padding: 0 $s-2;
margin: 0 $s-3 $s-2;
border-bottom: 1px solid $color-line1-2;
&:hover {
color: $color-link-3;
}
+
+ .#{$css-prefix}menu-icon-selected.#{$css-prefix}icon {
+ // remove display: inline-block !important; in next Y
+ display: inline-block !important;
+ top: initial;
+ color: $select-menu-icon-color;
+ }
}
&-highlight {
diff --git a/src/select/scss/variable.scss b/src/select/scss/variable.scss
index 11826649dc..921ba53dde 100644
--- a/src/select/scss/variable.scss
+++ b/src/select/scss/variable.scss
@@ -52,3 +52,4 @@ $select-tag-spacing-lr: $s-1;
$select-tag-spacing-tb: 3px;
$select-tag-padding-lr: $s-1;
$select-menu-item-height: $s-5;
+$select-menu-icon-color: $color-brand1-6;
diff --git a/src/select/select.jsx b/src/select/select.jsx
index 053422ae27..00bf9ae911 100644
--- a/src/select/select.jsx
+++ b/src/select/select.jsx
@@ -232,6 +232,7 @@ class Select extends Base {
this.valueDataSource.mapValueDS,
this.dataStore.getMapDS()
);
+ this.updateSelectAllYet(this.valueDataSource.value);
} else if (
'defaultValue' in nextProps &&
nextProps.defaultValue === this.valueDataSource.value &&
@@ -375,6 +376,8 @@ class Select extends Base {
this.handleChange(itemObj.value, triggerType, itemObj.valueDS);
}
+ this.updateSelectAllYet(itemObj.value);
+
// 清空搜索
if (!('searchValue' in this.props) && this.state.searchValue) {
// 因为 SearchValue 被 clear 后会重新渲染 Menu,所以在 Overlay 检测 safeNode 的时候 e.target 可能会找不到导致弹窗关闭
@@ -384,6 +387,28 @@ class Select extends Base {
}
}
+ updateSelectAllYet(value) {
+ // multiple mode
+ // is current state select all or not
+ this.selectAllYet = false;
+ if (this.props.hasSelectAll && Array.isArray(value)) {
+ const selectAllValues = this.dataStore
+ .getEnableDS()
+ .map(item => item.value);
+
+ if (selectAllValues.length <= value.length) {
+ this.selectAllYet = true;
+
+ selectAllValues.forEach(val => {
+ if (value.indexOf(val) === -1) {
+ this.selectAllYet = false;
+ return;
+ }
+ });
+ }
+ }
+ }
+
handleSearchValue(value) {
if (this.state.searchValue === value) {
return;
@@ -595,7 +620,14 @@ class Select extends Base {
*/
handleSelectAll(e) {
e && e.preventDefault();
- const nextValues = this.dataStore.getEnableDS().map(item => item.value);
+ let nextValues;
+
+ if (this.selectAllYet) {
+ nextValues = [];
+ } else {
+ nextValues = this.dataStore.getEnableDS().map(item => item.value);
+ }
+
// 直接传 values,减少 toString 操作
this.handleMultipleSelect(nextValues, 'selectAll');
}
@@ -913,13 +945,34 @@ class Select extends Base {
const text =
typeof hasSelectAll === 'boolean' ? 'Select All' : hasSelectAll;
+ const selectAllYet = this.selectAllYet;
+
+ const cls = classNames({
+ [`${prefix}select-all`]: true,
+ [`${prefix}selected`]: selectAllYet,
+ });
+
+ const clsInner = classNames({
+ [`${prefix}select-all-inner`]: true,
+ });
+
+ // remove style={{'lineHeight': 'unset'}} in next Y
+ // remove style={{'display': 'none'}} in next Y
return (
- {text}
+ {selectAllYet ? (
+
+ ) : null}
+ {text}
);
}
diff --git a/src/step/view/step-item.jsx b/src/step/view/step-item.jsx
index b01d390c77..3ef186b5d0 100644
--- a/src/step/view/step-item.jsx
+++ b/src/step/view/step-item.jsx
@@ -108,6 +108,13 @@ class StepItem extends Component {
if (shape === 'arrow') {
return;
}
+ const resetTailStyle = () => {
+ dom.setStyle(this.tail, {
+ width: '',
+ // eslint-disable-next-line
+ top: '',
+ });
+ };
if (direction === 'vertical' || direction === 'ver') {
this.resize();
@@ -117,19 +124,18 @@ class StepItem extends Component {
width: '',
[pos]: '',
});
- } else if (
- shape === 'circle' &&
- (labelPlacement === 'horizontal' || labelPlacement === 'hoz') &&
- index !== total - 1
- ) {
- // 调整横向Content
- this.adjustTail();
+ if (
+ shape === 'circle' &&
+ (labelPlacement === 'horizontal' || labelPlacement === 'hoz') &&
+ index !== total - 1
+ ) {
+ // 调整横向Content
+ this.adjustTail();
+ } else {
+ resetTailStyle();
+ }
} else if (index !== total - 1) {
- dom.setStyle(this.tail, {
- width: '',
- // eslint-disable-next-line
- top: '',
- });
+ resetTailStyle();
}
}
diff --git a/src/tab/rtl.scss b/src/tab/rtl.scss
index b583674425..8d875b33e4 100644
--- a/src/tab/rtl.scss
+++ b/src/tab/rtl.scss
@@ -1,6 +1,27 @@
@import "../core/index-noreset.scss";
+@import "scss/variable";
#{$tab-prefix}[dir="rtl"] {
+ &.#{$css-prefix}medium {
+ & #{$tab-prefix}-nav-container-scrolling {
+ padding-left: $tab-nav-scroll-padding-right-m;
+ padding-right: 0;
+ }
+ .#{$css-prefix}tabs-tab-close {
+ padding-right: $tab-nav-close-icon-padding-l-size-m;
+ padding-left: 0;
+ }
+ }
+ &.#{$css-prefix}small {
+ & #{$tab-prefix}-nav-container-scrolling {
+ padding-left: $tab-nav-scroll-padding-right-s;
+ padding-right: 0;
+ }
+ .#{$css-prefix}tabs-tab-close {
+ padding-right: $tab-nav-close-icon-padding-l-size-s;
+ padding-left: 0;
+ }
+ }
{$tab-prefix}-wrapped#{$tab-prefix}-top > #{$tab-prefix}-bar {
#{$tab-prefix}-nav-extra {
right: auto;
@@ -21,4 +42,18 @@
left: 0;
}
}
+
+ #{$tab-prefix}-btn-next {
+ left: $tab-nav-arrow-right-positon-right;
+ right: auto;
+ }
+ #{$tab-prefix}-btn-prev {
+ left: $tab-nav-arrow-left-positon-right;
+ right: auto;
+ }
+ #{$tab-prefix}-btn-down {
+ left: $tab-nav-arrow-down-positon-right;
+ right: auto;
+ }
}
+
diff --git a/src/tab/tab.jsx b/src/tab/tab.jsx
index 278238f280..5991d689c1 100644
--- a/src/tab/tab.jsx
+++ b/src/tab/tab.jsx
@@ -243,7 +243,10 @@ export default class Tab extends Component {
const { activeKey } = this.state;
const tabs = toArray(children);
-
+ let newPosition = tabPosition;
+ if (rtl && ['left', 'right'].indexOf(tabPosition) >= 0) {
+ newPosition = tabPosition === 'left' ? 'right' : 'left';
+ }
const classNames = classnames(
{
[`${prefix}tabs`]: true,
@@ -251,7 +254,7 @@ export default class Tab extends Component {
[`${prefix}tabs-vertical`]:
shape === 'wrapped' &&
['left', 'right'].indexOf(tabPosition) >= 0,
- [`${prefix}tabs-${tabPosition}`]: shape === 'wrapped',
+ [`${prefix}tabs-${newPosition}`]: shape === 'wrapped',
[`${prefix + size}`]: size,
},
className
diff --git a/src/tab/tabs/nav.jsx b/src/tab/tabs/nav.jsx
index 443ff3e0be..d012903e66 100644
--- a/src/tab/tabs/nav.jsx
+++ b/src/tab/tabs/nav.jsx
@@ -109,15 +109,17 @@ class Nav extends React.Component {
const wrapperOffset = getOffsetLT(this.wrapper);
if (
+ // active tab partially in visible zone
wrapperOffset + wrapperWH < activeTabOffset + activeTabWH &&
activeTabOffset < wrapperOffset + wrapperWH
) {
- target -=
+ target -= // Move more to make active tab totally in visible zone
activeTabOffset + activeTabWH - (wrapperOffset + wrapperWH);
}
}
if (this.offset !== target) {
+ // needs move
this.offset = target;
let navOffset = {};
@@ -133,7 +135,7 @@ class Nav extends React.Component {
name: 'top',
value: `${target}px`,
};
- } else {
+ } else if (!this.props.rtl) {
navOffset = canTransform
? {
value: `translate3d(${target}px, 0, 0)`,
@@ -142,6 +144,15 @@ class Nav extends React.Component {
name: 'left',
value: `${target}px`,
};
+ } else {
+ navOffset = canTransform
+ ? {
+ value: `translate3d(${-target}px, 0, 0)`,
+ }
+ : {
+ name: 'right',
+ value: `${target}px`,
+ };
}
if (canTransform) {
@@ -346,12 +357,12 @@ class Nav extends React.Component {
onPrevClick = () => {
const wrapperWH = getOffsetWH(this.wrapper);
this.setOffset(this.offset + wrapperWH, true, false);
- }
+ };
onNextClick = () => {
const wrapperWH = getOffsetWH(this.wrapper);
this.setOffset(this.offset - wrapperWH, true, false);
- }
+ };
onNavItemClick(key, callback, e) {
this.props.onTriggerEvent(triggerEvents.CLICK, key);
@@ -394,7 +405,7 @@ class Nav extends React.Component {
return null;
}
- const { prefix, activeKey, triggerType, popupProps } = this.props;
+ const { prefix, activeKey, triggerType, popupProps, rtl } = this.props;
const trigger = (
@@ -403,12 +414,14 @@ class Nav extends React.Component {
return (
target.parentNode}
{...popupProps}
>
-
+
);
@@ -519,7 +532,7 @@ class Nav extends React.Component {
onClick={state.next ? this.onNextClick : noop}
className={nextBtnCls}
>
-
+
);
restButton = null;
diff --git a/src/table/lock.jsx b/src/table/lock.jsx
index 483c9204fc..eb97c00303 100644
--- a/src/table/lock.jsx
+++ b/src/table/lock.jsx
@@ -477,10 +477,13 @@ export default function lock(BaseComponent) {
);
setTimeout(() => {
- this.tableRightInc.affixRef &&
- this.tableRightInc.affixRef
- .getInstance()
- .updatePosition();
+ const affixRef = this.tableRightInc.affixRef;
+ // if rendered then update postion of affix
+ return (
+ affixRef &&
+ affixRef.getInstance() &&
+ affixRef.getInstance().updatePosition()
+ );
});
}
@@ -494,10 +497,13 @@ export default function lock(BaseComponent) {
);
setTimeout(() => {
- this.tableLeftInc.affixRef &&
- this.tableLeftInc.affixRef
- .getInstance()
- .updatePosition();
+ const affixRef = this.tableLeftInc.affixRef;
+ // if rendered then update postion of affix
+ return (
+ affixRef &&
+ affixRef.getInstance() &&
+ affixRef.getInstance().updatePosition()
+ );
});
}
});
diff --git a/src/table/main.scss b/src/table/main.scss
index 4293f4a318..9c73f81353 100644
--- a/src/table/main.scss
+++ b/src/table/main.scss
@@ -303,6 +303,9 @@
cursor: pointer;
width: 20px;
display: inline-block;
+ &:focus {
+ outline: 0;
+ }
.#{$css-prefix}icon {
@include icon-size($table-filter-icon-size);
color: $table-sort-color;
diff --git a/src/tag/main.scss b/src/tag/main.scss
index e17ca12140..6d56edf360 100644
--- a/src/tag/main.scss
+++ b/src/tag/main.scss
@@ -121,6 +121,18 @@
&tag-closable {
position: relative;
+ &.#{$css-prefix}tag-large > .#{$css-prefix}tag-body {
+ max-width: calc(100% - #{$tag-size-l-height});
+ }
+
+ &.#{$css-prefix}tag-medium > .#{$css-prefix}tag-body {
+ max-width: calc(100% - #{$tag-size-m-height});
+ }
+
+ &.#{$css-prefix}tag-small > .#{$css-prefix}tag-body {
+ max-width: calc(100% - #{$tag-size-s-height});
+ }
+
> .#{$css-prefix}tag-close-btn {
display: inline-block;
vertical-align: middle;
diff --git a/src/tag/scss/mixin.scss b/src/tag/scss/mixin.scss
index 19271a46af..80af2edc14 100644
--- a/src/tag/scss/mixin.scss
+++ b/src/tag/scss/mixin.scss
@@ -20,7 +20,7 @@
line-height: $height - $borderWidth * 2;
font-size: 0;
- $_marginLeft: $height / 4 - 1px;
+ $_marginLeft: $iconSize;
> .#{$css-prefix}tag-body {
font-size: $fontSize;
diff --git a/src/time-picker/module/time-menu.jsx b/src/time-picker/module/time-menu.jsx
index e1f1419cc2..00f9edab0c 100644
--- a/src/time-picker/module/time-menu.jsx
+++ b/src/time-picker/module/time-menu.jsx
@@ -96,7 +96,6 @@ class TimeMenu extends React.Component {
list.push(
{
@@ -450,10 +450,13 @@ class List extends Component {
if (rtl && listType === 'card' && Array.isArray(list)) {
list = list.reverse();
}
- const listclassNames = classNames({
- [`${prefixCls}-list`]: true,
- [`${prefixCls}-list-${this.props.listType}`]: true,
- });
+ const listclassNames = classNames(
+ {
+ [`${prefixCls}-list`]: true,
+ [`${prefixCls}-list-${this.props.listType}`]: true,
+ },
+ className
+ );
const others = obj.pickAttrsWith(this.props, 'data-');
return (
diff --git a/src/upload/main.scss b/src/upload/main.scss
index 4e67d192c9..91afbef6bd 100644
--- a/src/upload/main.scss
+++ b/src/upload/main.scss
@@ -208,6 +208,7 @@
text-align: center;
overflow: hidden;
box-sizing: border-box;
+
img {
width: 100%;
height: 100%;
@@ -291,6 +292,9 @@
img {
width: 100%;
height: 100%;
+ &:focus {
+ outline: 0;
+ }
}
.#{$css-prefix}icon {
diff --git a/src/upload/upload.jsx b/src/upload/upload.jsx
index ffcf9d1a62..35f55ac459 100644
--- a/src/upload/upload.jsx
+++ b/src/upload/upload.jsx
@@ -259,6 +259,7 @@ class Upload extends Base {
onDrop = files => {
this.onSelect(files);
+ this.props.onDrop(files);
};
/**
@@ -374,8 +375,8 @@ class Upload extends Base {
targetItem.imgURL = response.imgURL || response.url; // 缩略图地址(可选)
}
- this.props.onSuccess(targetItem, value);
this.onChange(value, targetItem);
+ this.props.onSuccess(targetItem, value);
};
onError = (err, response, file) => {
@@ -394,8 +395,8 @@ class Upload extends Base {
response,
});
- this.props.onError(targetItem, value);
this.onChange(value, targetItem);
+ this.props.onError(targetItem, value);
};
/**
diff --git a/src/util/log.js b/src/util/log.js
index 1492ad1ff9..f6bd1548e7 100644
--- a/src/util/log.js
+++ b/src/util/log.js
@@ -24,11 +24,12 @@ export function deprecated(props, instead, component) {
/**
* 控制台警告日志
- * @param {String} msg
+ * @param {String} msg
+ * @return {Console | void}
*/
export function warning(msg) {
/* istanbul ignore else */
- if (typeof console !== 'undefined' && console.error) {
+ if (!isProduction() && typeof console !== 'undefined' && console.error) {
return console.error(`Warning: ${msg}`);
}
}
diff --git a/test/calendar/index-spec.js b/test/calendar/index-spec.js
index 623ce1dd23..f4623ae825 100644
--- a/test/calendar/index-spec.js
+++ b/test/calendar/index-spec.js
@@ -85,7 +85,10 @@ describe('Calendar', () => {
});
it('should render with disabled dates', () => {
- const disabledDate = date => date.valueOf() > defaultVal.valueOf();
+ const disabledDate = (date, view) => {
+ assert(view === 'date');
+ return date.valueOf() > defaultVal.valueOf();
+ };
wrapper = mount(
defaultVal}
diff --git a/test/cascader-select/index-spec.js b/test/cascader-select/index-spec.js
index 083c1afa04..26c8c5317a 100644
--- a/test/cascader-select/index-spec.js
+++ b/test/cascader-select/index-spec.js
@@ -416,6 +416,33 @@ describe('CascaderSelect', () => {
done();
}, 2000);
});
+
+ it('should support signle value not in dataSource', () => {
+ const VALUE = '222333';
+ let called = false;
+ const valueRender = (item) => {
+ assert(!item.label);
+ assert(item.value === VALUE);
+ called = true;
+ }
+ wrapper = mount( );
+ assert(called);
+ });
+
+ it('should support multiple value not in dataSource', () => {
+ const VALUE = '222333';
+ let called = false;
+ const valueRender = (item) => {
+ assert(!item.label);
+ assert(item.value === VALUE);
+ called = true;
+ }
+ wrapper = mount( item.label || ''} dataSource={ChinaArea} valueRender={valueRender} />);
+ wrapper.setProps({
+ value: VALUE,
+ });
+ assert(called);
+ });
});
function findItem(menuIndex, itemIndex) {
diff --git a/test/config-provider/index-spec.js b/test/config-provider/index-spec.js
index 50a247d000..db4f3c4f8b 100644
--- a/test/config-provider/index-spec.js
+++ b/test/config-provider/index-spec.js
@@ -1,11 +1,12 @@
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
-import Enzyme, { mount } from 'enzyme';
+import Enzyme, { mount, shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import moment from 'moment';
import assert from 'power-assert';
import Select from '../../src/select';
+import Button from '../../src/button';
import enUS from '../../src/locale/en-us';
import zhCN from '../../src/locale/zh-cn';
import ConfigProvider from '../../src/config-provider';
@@ -15,7 +16,7 @@ import ConfigProvider from '../../src/config-provider';
Enzyme.configure({ adapter: new Adapter() });
-const { config, getContextProps } = ConfigProvider;
+const { config, getContextProps, ErrorBoundary } = ConfigProvider;
class Output extends Component {
static propTypes = {
@@ -408,3 +409,131 @@ describe('ConfigProvider.Consumer', () => {
assert(output.prop('warning') === contextState.warning);
});
});
+
+describe('ConfigProvider.ErrorBoundary', () => {
+ let wrapper;
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.unmount();
+ wrapper = null;
+ }
+ });
+
+ it('should catch errors with componentDidCatch', () => {
+ const Something = () => null;
+
+ wrapper = mount(
+
+
+
+ );
+ const error = new Error('test');
+
+ wrapper.find(Something).simulateError(error);
+ });
+
+ it('should catch errors with componentDidCatch as to basic component', () => {
+ const Something = () => null;
+ wrapper = mount(
+
+
+
+
+
+ );
+ const error = new Error('test');
+
+ wrapper.find(Something).simulateError(error);
+ });
+
+ it('should on: errorBoundary should work', () => {
+ wrapper = shallow(
+
+
+
+ );
+ assert(wrapper.dive().name() === 'ErrorBoundary');
+ });
+
+ it('should on: errorBoundary={{}} should work', () => {
+ wrapper = shallow(
+
+
+
+ );
+ assert(wrapper.dive().name() === 'ErrorBoundary');
+ });
+
+ it('should off: errorBoundary={false} should work', () => {
+ wrapper = shallow(
+
+
+
+ );
+ assert(wrapper.dive().name() === 'Button');
+ });
+
+ it('should on: errorBoundary={{open: true}} should work', () => {
+ wrapper = shallow(
+
+
+
+ );
+ assert(wrapper.dive().name() === 'ErrorBoundary');
+ });
+
+ it('should off: errorBoundary={{open: false}} should work', () => {
+ wrapper = shallow(
+
+
+
+ );
+ assert(wrapper.dive().name() === 'Button');
+ });
+
+ it('should off: config on component iteself > on ConfigProvider 1', () => {
+ wrapper = shallow(
+
+
+
+ );
+ assert(wrapper.dive().name() === 'Button');
+ });
+
+ it('should on: config on component iteself > on ConfigProvider 2', () => {
+ wrapper = shallow(
+
+
+
+ );
+ assert(wrapper.dive().name() === 'ErrorBoundary');
+ });
+
+ it('should on: config on component iteself > on ConfigProvider 3', () => {
+ wrapper = shallow(
+
+
+
+ );
+ assert(wrapper.dive().name() === 'ErrorBoundary');
+ });
+
+ it('should off: config on component iteself > on ConfigProvider 4', () => {
+ wrapper = shallow(
+
+
+
+ );
+ assert(wrapper.dive().name() === 'Button');
+ });
+
+ it('should on: config on component iteself > on ConfigProvider 5', () => {
+ wrapper = shallow(
+
+
+
+ );
+ assert(wrapper.dive().name() === 'ErrorBoundary');
+ });
+});
diff --git a/test/date-picker/index-spec.js b/test/date-picker/index-spec.js
index 52d22cbfe2..9ef805c989 100644
--- a/test/date-picker/index-spec.js
+++ b/test/date-picker/index-spec.js
@@ -13,7 +13,8 @@ const endValue = moment('2017-12-15', 'YYYY-MM-DD', true);
const defaultTimeValue = moment('09:00:00', 'HH:mm:ss', true);
// 禁止选择 startValue 之前的所有日期
-const disabledDate = function(date) {
+const disabledDate = function(date, view) {
+ if (!view) return true;
return date.valueOf() < startValue.valueOf();
};
diff --git a/test/range/index-spec.js b/test/range/index-spec.js
index 40a91a7c19..9bba3fc99f 100644
--- a/test/range/index-spec.js
+++ b/test/range/index-spec.js
@@ -137,32 +137,23 @@ describe('Range ', () => {
assert(wrapper.find('.next-range-scale-item').length === 4);
assert(wrapper.find('.next-range-scale-item.activated').length === 2);
- assert.deepEqual(
+ assert(
wrapper
.find('.next-range-scale-item')
.first()
- .props().style,
- {
- left: '3%',
- }
+ .props().style.left === '3%'
);
- assert.deepEqual(
+ assert(
wrapper
.find('.next-range-scale-item')
.at(1)
- .props().style,
- {
- left: '26%',
- }
+ .props().style.left === '26%'
);
- assert.deepEqual(
+ assert(
wrapper
.find('.next-range-scale-item')
.at(2)
- .props().style,
- {
- left: '37%',
- }
+ .props().style.left === '37%'
);
assert(wrapper2.find('.next-range-scale-item').length === 11);
assert(wrapper3.find('.next-range-scale-item').length === 4);
@@ -472,4 +463,35 @@ describe('Range ', () => {
wrapper.find('.next-range-slider').simulate('keyDown', { keyCode: 39 });
assert(!aSpy.called);
});
+
+ it('rtl', () => {
+ const wrapperSingle = mount( );
+ const wrapperDouble = mount( );
+ assert.deepEqual(
+ wrapperSingle.find('.next-range-selected').props().style,
+ { width: '10%', left: '90%' }
+ );
+ assert.deepEqual(
+ wrapperDouble.find('.next-range-selected').props().style,
+ { width: '20%', left: '70%' }
+ );
+ });
+
+ it('rtl & reverse', () => {
+ const wrapperSingle = mount( );
+ const wrapperDouble = mount(
+
+ );
+ assert.deepEqual(
+ wrapperSingle.find('.next-range-selected').props().style,
+ { width: '90%', left: '0%' }
+ );
+ assert.deepEqual(
+ wrapperDouble
+ .find('.next-range-selected')
+ .at(0)
+ .props().style,
+ { width: '70%', left: 0 }
+ );
+ });
});
diff --git a/test/rating/index-spec.js b/test/rating/index-spec.js
index b8db55511f..d8bc0f966f 100644
--- a/test/rating/index-spec.js
+++ b/test/rating/index-spec.js
@@ -8,7 +8,6 @@ import { setTimeout } from 'timers';
import Rating from '../../src/rating/index';
import '../../src/rating/style.js';
import { KEYCODE } from '../../src/util';
-import Paragraph from '../../src/paragraph';
Enzyme.configure({ adapter: new Adapter() });
diff --git a/test/select/index-spec.js b/test/select/index-spec.js
index 467e12587f..50cf9f4cec 100644
--- a/test/select/index-spec.js
+++ b/test/select/index-spec.js
@@ -648,6 +648,50 @@ describe('Select', () => {
wrapper.find('input').simulate('change');
assert(/测试/.test(input.value));
});
+
+ it('should support select all and unselect all', () => {
+ const dataSource = [
+ { label: 'xxx', value: 123 },
+ { label: 'empty', value: false },
+ ];
+ wrapper.setProps({
+ dataSource,
+ visible: true,
+ mode: 'multiple',
+ hasSelectAll: true,
+ });
+
+ ReactTestUtils.Simulate.click(
+ document.querySelectorAll('.next-select-all')[0]
+ );
+ assert(
+ document.querySelectorAll('.next-menu-icon-selected').length === 3
+ );
+
+ ReactTestUtils.Simulate.click(
+ document.querySelectorAll('.next-select-menu-item')[0]
+ );
+
+ assert(
+ document.querySelectorAll('.next-menu-icon-selected').length === 1
+ );
+
+ ReactTestUtils.Simulate.click(
+ document.querySelectorAll('.next-select-all')[0]
+ );
+
+ assert(
+ document.querySelectorAll('.next-menu-icon-selected').length === 3
+ );
+
+ ReactTestUtils.Simulate.click(
+ document.querySelectorAll('.next-select-all')[0]
+ );
+
+ assert(
+ document.querySelectorAll('.next-menu-icon-selected').length === 0
+ );
+ });
});
describe('Select Controlled', () => {
diff --git a/test/step/index-spec.js b/test/step/index-spec.js
index f4eeaa1f12..7af1f60207 100644
--- a/test/step/index-spec.js
+++ b/test/step/index-spec.js
@@ -273,8 +273,23 @@ describe('Step', () => {
);
assert(wrapper.find('.next-step-label-vertical').length === 1);
- wrapper.setProps({ labelPlacement: 'horizontal' });
- assert(wrapper.find('.next-step-label-horizontal').length === 1);
+ wrapper.setProps({ labelPlacement: 'horizontal' }, () => {
+ assert(wrapper.find('.next-step-label-horizontal').length === 1);
+ // 横向模式下会调整 next-step-item-tail 的宽度值
+ const $tail = wrapper.find('.next-step-item-tail');
+ assert(
+ $tail.length === 3 &&
+ $tail.at(0).instance().style.width !== "" &&
+ $tail.at(2).instance().style.width === ""
+ );
+ // 重新设置为垂直居中 应该去掉 next-step-item-tail 的宽度值
+ wrapper.setProps({labelPlacement: 'ver'}, () => {
+ assert(
+ $tail.length === 3 &&
+ $tail.at(0).instance().style.width === ""
+ );
+ });
+ });
});
it('should trigger click event', () => {
diff --git a/test/tab/index-spec.js b/test/tab/index-spec.js
index 4d7b7e54c8..09c6b73517 100644
--- a/test/tab/index-spec.js
+++ b/test/tab/index-spec.js
@@ -342,7 +342,11 @@ describe('Tab', () => {
it('should resize', () => {
const render = sinon.spy();
- const ele = ( );
+ const ele = (
+
+
+
+ );
wrapper = mount(ele);
window.dispatchEvent(new Event('resize'));
assert(render.calledOnce);
@@ -418,9 +422,14 @@ describe('Tab', () => {
});
it('should not render dropdown if not excessed', () => {
- wrapper = mount(
-
-
, { attachTo: target });
+ wrapper = mount(
+
+
+
+
+
,
+ { attachTo: target }
+ );
assert(wrapper.find('.next-tabs-btn-down').length === 0);
});
@@ -443,4 +452,72 @@ describe('Tab', () => {
);
});
});
+ describe('rtl mode', () => {
+ let wrapper, target;
+ const panes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((item, index) => (
+
+ ));
+ const boxStyle = { width: '200px' };
+
+ beforeEach(() => {
+ target = document.createElement('div');
+ document.body.appendChild(target);
+ });
+
+ afterEach(() => {
+ document.body.removeChild(target);
+ wrapper.unmount();
+ wrapper = null;
+ target = null;
+ });
+ it('should render extra content in left', () => {
+ wrapper = mount(
+ ,
+ { attachTo: target }
+ );
+ const el = wrapper.find('#test-extra').getDOMNode().parentElement;
+ assert(el.style.getPropertyValue('float') === 'left');
+ });
+ it('should slide', () => {
+ const boxStyle = { width: '200px' };
+ wrapper = mount(
+
+
+ {panes}
+
+
,
+ { attachTo: target }
+ );
+ assert(wrapper.find('.next-tabs-btn-prev').hasClass('disabled'));
+ assert(wrapper.find('.next-tabs-btn-next').length === 1);
+ });
+ it('should slide', (done) => {
+ const boxStyle = { width: '200px' };
+ wrapper = mount(
+
+
+ {panes}
+
+
,
+ { attachTo: target }
+ );
+ const prev = wrapper.find(".next-tabs-nav").at(0).getDOMNode().getBoundingClientRect().left;
+ wrapper.find('.next-tabs-btn-next').simulate('click');
+ setTimeout(()=>{
+ const newpos = wrapper.find(".next-tabs-nav").at(0).getDOMNode().getBoundingClientRect().left;
+ assert(newpos>prev);
+ done();
+ }, 500);
+ });
+ });
});
diff --git a/test/table/index-spec.js b/test/table/index-spec.js
index fafb19060b..00a73a9d3b 100644
--- a/test/table/index-spec.js
+++ b/test/table/index-spec.js
@@ -731,7 +731,7 @@ describe('Table', () => {
);
});
- it('should support rtl', () => {
+ it('should support rtl', done => {
timeout(
{
children: [
@@ -742,6 +742,7 @@ describe('Table', () => {
},
() => {
assert(wrapper.find('.next-table[dir="rtl"]').length === 3);
+ done();
}
);
});
diff --git a/test/table/issue-spec.js b/test/table/issue-spec.js
index 0f42bf25ad..9f4c5537de 100644
--- a/test/table/issue-spec.js
+++ b/test/table/issue-spec.js
@@ -487,4 +487,35 @@ describe('Issue', () => {
ReactDOM.unmountComponentAtNode(div);
document.body.removeChild(div);
});
+
+ it('fix #466, stickHeader + lock with enough space', () => {
+ class App extends React.Component {
+ render() {
+ return (
+
+ );
+ }
+ }
+
+ const div = document.createElement('div');
+ document.body.appendChild(div);
+ ReactDOM.render( , div);
+
+ assert(document.querySelectorAll('div.next-table-empty').length === 1);
+ ReactDOM.unmountComponentAtNode(div);
+ document.body.removeChild(div);
+ });
});
diff --git a/test/util/a11y/validate.js b/test/util/a11y/validate.js
index 18722bf7d5..20bd3f7d04 100644
--- a/test/util/a11y/validate.js
+++ b/test/util/a11y/validate.js
@@ -26,6 +26,13 @@ function formatViolations(violations, verbose = false) {
return JSON.stringify(violations, null, 2);
}
+
+function delay(duration) {
+ return new Promise((res) => {
+ setTimeout(res, duration)
+ });
+}
+
/**
* Run Axe-core tests on a dom node
*
@@ -110,7 +117,9 @@ export const mountReact = async function(node, id = A11Y_ROOT_ID) {
*/
// TODO: resolve issue where failing tests do not pass wrapper and so cannot be cleaned up correctly
export const testReact = async function(node, options = {}) {
- const wrapper = mountReact(node, A11Y_ROOT_ID);
+ const wrapper = await mountReact(node, A11Y_ROOT_ID);
+
+ await delay(options.delay || 200);
await test(`#${A11Y_ROOT_ID}`, options);
return wrapper;
};