DatePicker With Time
@@ -39,5 +40,7 @@ ReactDOM.render(
RangePicker with Time, with default time value, hide seconds
+
RangePicker with Time, with default start & end time value, hide seconds
+
, mountNode);
````
diff --git a/docs/dialog/adaptor/index.jsx b/docs/dialog/adaptor/index.jsx
new file mode 100644
index 0000000000..bce05c90b5
--- /dev/null
+++ b/docs/dialog/adaptor/index.jsx
@@ -0,0 +1,141 @@
+import React from 'react';
+import { Types } from '@alifd/adaptor-helper';
+import { Dialog, Message } from '@alifd/next';
+import locale from '../../../src/locale/en-us';
+
+
+export default {
+ name: 'Dialog',
+ editor: () => ({
+ props: [{
+ name: 'level',
+ type: Types.enum,
+ options: ['normal', 'alert', 'confirm'],
+ default: 'normal'
+ }, {
+ name: 'footerAlign',
+ label: 'Button Position',
+ type: Types.enum,
+ options: ['left', 'right', 'center'],
+ default: 'right'
+ }, {
+ name: 'okButtonPosition',
+ label: 'Button Order',
+ type: Types.enum,
+ options: ['left', 'right'],
+ default: 'left'
+ }, {
+ name: 'mask',
+ type: Types.bool,
+ default: false
+ }, {
+ name: 'width',
+ type: Types.number,
+ default: 400
+ }, {
+ name: 'height',
+ type: Types.number,
+ default: 160
+ }, {
+ name: 'title',
+ type: Types.string,
+ default: 'Welcome to Alibaba.com'
+ }],
+ data: {
+ default: 'Start your business here by searching a popular product'
+ }
+ }),
+ adaptor: ({ level, footerAlign, okButtonPosition, mask, width, height, title, style, className, data, ...others}) => {
+ const dialogStyle = {
+ position: mask ? 'absolute' : 'relative',
+ width: width,
+ zIndex: 1,
+ ...(mask ? {
+ left: 20,
+ top: 20,
+ } : style),
+ };
+
+ const props = {
+ ...(mask ? {} : {...others }),
+ className: level === 'normal' ? className : `${className || ''} next-dialog-quick`,
+ style: dialogStyle,
+ footerAlign: footerAlign,
+ footerActions: okButtonPosition === 'left' ? ['ok', 'cancel'] : ['cancel', 'ok'],
+ locale: locale.Dialog,
+ height: `${height}px`
+ };
+
+ let dialog;
+ switch(level) {
+ case 'alert':
+ dialog = (
+
+
+ {data}
+
+
+ );
+ break;
+ case 'confirm':
+ dialog = (
+
+
+ {data}
+
+
+ );
+ break;
+ default:
+ dialog =
{data}
+ break;
+ }
+
+ return mask ? (
+
+ ) : dialog;
+ },
+ content: () => ({
+ options: [{
+ name: 'title',
+ options: ['show', 'hide'],
+ default: 'show',
+ }, {
+ name: 'overlay',
+ options: ['show', 'hide'],
+ default: 'hide',
+ }, {
+ name: 'footerAlign',
+ options: ['left', 'center', 'right'],
+ default: 'right'
+ }, {
+ name: 'okButtonPosition',
+ options: ['left', 'right'],
+ default: 'right'
+ }],
+ transform: (props, { title, overlay, footerAlign, okButtonPosition }) => {
+ return {
+ ...props,
+ title: title === 'hide' ? '' : title,
+ mask: overlay === 'show',
+ footerAlign,
+ okButtonPosition,
+ };
+ }
+ })
+};
diff --git a/docs/drawer/demo/basic.md b/docs/drawer/demo/basic.md
new file mode 100644
index 0000000000..c5cf4f7a2c
--- /dev/null
+++ b/docs/drawer/demo/basic.md
@@ -0,0 +1,55 @@
+# 基本
+
+- order: 0
+
+第一个抽屉
+
+:::lang=en-us
+# Basic
+
+- order: 0
+
+First drawer
+:::
+---
+
+````jsx
+import { Radio, Button, Drawer } from '@alifd/next';
+
+class Demo extends React.Component {
+ state = {
+ visible: false,
+ };
+
+ onOpen = () => {
+ this.setState({
+ visible: true
+ });
+ };
+
+ onClose = (reason, e) => {
+ console.log(reason, e);
+ this.setState({
+ visible: false
+ });
+ }
+
+ render() {
+ return (
+
+
+
+ Start your business here by searching a popular product
+
+
+ );
+ }
+}
+
+ReactDOM.render(
, mountNode);
+````
diff --git a/docs/drawer/demo/double.md b/docs/drawer/demo/double.md
new file mode 100644
index 0000000000..461b0fb0f2
--- /dev/null
+++ b/docs/drawer/demo/double.md
@@ -0,0 +1,103 @@
+# 双层抽屉
+
+- order: 2
+
+双层抽屉,抽屉内打开新的抽屉
+
+:::lang=en-us
+# Basic
+
+- order: 2
+
+Double drawer
+:::
+---
+
+````jsx
+import { Button, Drawer } from '@alifd/next';
+
+class App extends React.Component {
+ state = { visible: false, childrenDrawer: false };
+
+ showDrawer = () => {
+ this.setState({
+ visible: true,
+ });
+ };
+
+ onClose = () => {
+ this.setState({
+ visible: false,
+ });
+ };
+
+ showChildrenDrawer = () => {
+ this.setState({
+ childrenDrawer: true,
+ });
+ };
+
+ onChildrenDrawerClose = () => {
+ this.setState({
+ childrenDrawer: false,
+ });
+ };
+
+ render() {
+ return (
+
+
+
+
+
+ This is two-level drawer
+
+
+
+
+
+
+
+ );
+ }
+}
+
+ReactDOM.render(
, mountNode);
+````
diff --git a/docs/drawer/demo/placement.md b/docs/drawer/demo/placement.md
new file mode 100644
index 0000000000..c9d5b70ace
--- /dev/null
+++ b/docs/drawer/demo/placement.md
@@ -0,0 +1,66 @@
+# 自定义弹出方向
+
+- order: 1
+
+自定义弹出方向
+
+:::lang=en-us
+# Basic
+
+- order: 1
+
+Diffrent placement
+:::
+---
+
+````jsx
+import { Radio, Button, Drawer } from '@alifd/next';
+
+class Demo extends React.Component {
+ state = {
+ visible: false,
+ placement: 'right'
+ };
+
+ onOpen = () => {
+ this.setState({
+ visible: true
+ });
+ };
+
+ onClose = (reason) => {
+
+ this.setState({
+ visible: false
+ });
+ };
+
+ onPlacementChange = dir => {
+ this.setState({
+ placement: dir
+ });
+ }
+
+ render() {
+ return (
+
+
+
+
+ Start your business here by searching a popular product
+
+
+ );
+ }
+}
+
+ReactDOM.render(
, mountNode);
+````
diff --git a/docs/drawer/demo/select.md b/docs/drawer/demo/select.md
new file mode 100644
index 0000000000..3012da3681
--- /dev/null
+++ b/docs/drawer/demo/select.md
@@ -0,0 +1,68 @@
+# 抽屉式选择
+
+- order: 1
+
+将 Select 的弹出模式换成 Drawer
+
+:::lang=en-us
+# Drawer Select
+
+- order: 1
+
+Select width drawer
+:::
+---
+
+````jsx
+import { Radio, Drawer, Select } from '@alifd/next';
+
+const Option = Select.Option;
+
+const onChange = function (value) {
+ console.log(value);
+};
+const onBlur = function (e) {
+ console.log(/onblur/,e);
+};
+
+const onToggleHighlightItem = function (item, type) {
+ console.log(item, type);
+};
+
+class Demo extends React.Component {
+ state = {
+ placement: 'right'
+ };
+
+ onPlacementChange = dir => {
+ this.setState({
+ placement: dir
+ });
+ }
+
+ render() {
+ const drawerProps = {
+ placement: this.state.placement,
+ closeable: 'mask',
+ bodyStyle: {padding: 0}
+ };
+ return (
+
+
+
+
+
+ );
+ }
+}
+
+ReactDOM.render(
, mountNode);
+````
diff --git a/docs/drawer/index.en-us.md b/docs/drawer/index.en-us.md
new file mode 100644
index 0000000000..142fa0c67c
--- /dev/null
+++ b/docs/drawer/index.en-us.md
@@ -0,0 +1,37 @@
+# Drawer
+
+- chinese: 抽屉
+- family: Feedback
+- category: Components
+- type: 弹层
+
+---
+
+## Guide
+
+## When To Use
+
+The Drawer is used to provide the user with an auxiliary window for quickly performing a simple operation, confirming user information, or providing a feedback prompt without leaving the main path.
+
+## API
+
+### Drawer
+
+| Param | Descripiton | Type | Default Value |
+| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- | --------------------------------------------------------------------------------- |
+| trigger | trigger the overlay to show or hide elements | ReactElement | - |
+| triggerType | trigger the overlay to show or hide operations, either 'click', 'hover', 'focus', or an array of them, such as ['hover', 'focus'] | String/Array | 'hover' |
+| visible | whether the overlay is visiible currently | Boolean | - |
+| animation | configure animation, support the {in: 'enter-class', out: 'leave-class' } object parameters, if set to false, do not play the animation. Refer to `Animate` component documentation for available animations. | Object/Boolean | { in: 'expandInDown', out: 'expandOutUp' } |
+| hasMask | whether to show the mask | Boolean | false |
+| closeable | controls how the dialog is closed. The value can be either a String or Boolean, where the string consists of the following values:
**close** clicking the close button can close the dialog
**mask** clicking the mask can close the dialog
**esc** pressing the esc key can close the dialog
such as 'close' or 'close,esc,mask'
If set to true, all of the above close methods take effect
If set to false, all of the above close methods will fail | String/Boolean | 'esc,close' |
+| onVisibleChange | callback function triggered when the ovlery is visible or hidden
**signatures**:
Function(visible: Boolean, type: String, e: Object) => void
**params**:
_visible_: {Boolean} whether the overlay is visible
_type_: {String} the reason that triggers the overlay to show or hide
_e_: {Object} DOM event | Function | func.noop |
+| placement | placement of the drawer
**options**:
'top', 'right', 'bottom', 'left' | Enum | 'right' |
+
+## ARIA and Keyboard
+
+| Keyboard | Descripiton |
+| :-------- | :--------------------------------------- |
+| esc | pressing ESC will close dialog |
+| tab | focus on any element that can be focused, the focus remains in the dialog when the dialog is displayed |
+| shift+tab | back focus on any element that can be focused, the focus remains in the dialog when the dialog is displayed |
diff --git a/docs/drawer/index.md b/docs/drawer/index.md
new file mode 100644
index 0000000000..b3a1a21356
--- /dev/null
+++ b/docs/drawer/index.md
@@ -0,0 +1,42 @@
+# Drawer
+
+- chinese: 抽屉
+- family: Feedback
+- category: Components
+- type: 弹层
+
+---
+
+## 使用指南
+
+抽屉
+
+### 何时使用
+
+抽屉是用于在不离开主路径的情况下,提供用户快速执行简单的操作、确认用户信息或反馈提示的辅助窗口。
+
+## API
+
+### Drawer
+
+| 参数 | 说明 | 类型 | 默认值 |
+| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -------- |
+| width | 宽度,仅在 placement是 left right 的时候生效 | Number/String | - |
+| height | 高度,仅在 placement是 top bottom 的时候生效 | Number/String | - |
+| visible | 是否显示 | Boolean | - |
+| hasMask | 是否显示遮罩 | Boolean | true |
+| closeable | 控制对话框关闭的方式,值可以为字符串或者布尔值,其中字符串是由以下值组成:
**close** 表示点击关闭按钮可以关闭对话框
**mask** 表示点击遮罩区域可以关闭对话框
**esc** 表示按下 esc 键可以关闭对话框
如 'close' 或 'close,esc,mask'
如果设置为 true,则以上关闭方式全部生效
如果设置为 false,则以上关闭方式全部失效 | String/Boolean | true |
+| onClose | 对话框关闭时触发的回调函数
**签名**:
Function(trigger: String, event: Object) => void
**参数**:
_trigger_: {String} 关闭触发行为的描述字符串
_event_: {Object} 关闭时事件对象 | Function | () => {} |
+| placement | 位于页面的位置
**可选值**:
'top', 'right', 'bottom', 'left' | Enum | 'right' |
+| title | 标题 | ReactNode | - |
+| onVisibleChange | 弹层显示或隐藏时触发的回调
**签名**:
Function(visible: Boolean, type: String) => void
**参数**:
_visible_: {Boolean} 弹层是否显示
_type_: {String} 触发弹层显示或隐藏的来源 fromContent 表示由Dropdown内容触发; fromTrigger 表示由trigger的点击触发; docClick 表示由document的点击触发 | Function | - |
+| animation | 显示隐藏时动画的播放方式 | Object/Boolean | - |
+| bodyStyle | body上的样式 | Object | - |
+
+## ARIA and Keyboard
+
+| 键盘 | 说明 |
+| :-------- | :--------------------------------------- |
+| esc | 按下ESC键将会关闭dialog而不触发任何的动作 |
+| tab | 正向聚焦到任何可以被聚焦的元素, 在Dialog显示的时候,焦点始终保持在框体内 |
+| shift+tab | 反向聚焦到任何可以被聚焦的元素,在Dialog显示的时候,焦点始终保持在框体内 |
diff --git a/docs/drawer/theme/index.jsx b/docs/drawer/theme/index.jsx
new file mode 100644
index 0000000000..f43a11f061
--- /dev/null
+++ b/docs/drawer/theme/index.jsx
@@ -0,0 +1,129 @@
+import React, { Component } from 'react';
+import ReactDOM from 'react-dom';
+import '../../../src/demo-helper/style.js';
+import '../../../src/drawer/style.js';
+import { Demo, DemoGroup, initDemo } from '../../../src/demo-helper';
+import Drawer from '../../../src/drawer';
+
+import zhCN from '../../../src/locale/zh-cn';
+import enUS from '../../../src/locale/en-us';
+
+const i18nMaps = {
+ 'en-us': {
+ title: 'Title Here',
+ content: 'Start your business here by searching a popular product',
+ },
+
+ 'zh-cn': {
+ title: '这里是标题',
+ content: '开启您的贸易生活从 Alibaba.com 开始',
+ }
+};
+
+class FunctionDemo extends Component {
+ state = {
+ demoFunction: {
+ hasTitle: {
+ label: '标题',
+ value: 'true',
+ enum: [{
+ label: '显示',
+ value: 'true'
+ }, {
+ label: '隐藏',
+ value: 'false'
+ }]
+ },
+ hasCloseIcon: {
+ label: '有无关闭按钮',
+ value: 'true',
+ enum: [{
+ label: '有',
+ value: 'true'
+ }, {
+ label: '无',
+ value: 'false'
+ }]
+ },
+ placement: {
+ label: '方向',
+ value: 'right',
+ enum: [{
+ label: '上',
+ value: 'top'
+ }, {
+ label: '下',
+ value: 'bottom'
+ }, {
+ label: '左',
+ value: 'left'
+ }, {
+ label: '右',
+ value: 'right'
+ }]
+ },
+ }
+ }
+ onFunctionChange = demoFunction => {
+ this.setState({
+ demoFunction
+ });
+ }
+
+ renderMask(hasMask, content) {
+ return hasMask ? (
+
+ ) : content;
+ }
+
+ render() {
+ // eslint-disable-next-line
+ const { lang, i18n } = this.props;
+ const locale = (lang === 'en-us' ? enUS : zhCN).Drawer;
+ const hasTitle = this.state.demoFunction.hasTitle.value === 'true';
+ const hasCloseIcon = this.state.demoFunction.hasCloseIcon.value === 'true';
+
+ const placement = this.state.demoFunction.placement.value;
+ const style = {
+ position: 'absolute',
+ top: placement === 'bottom' ? 'auto' : 0,
+ [placement]: 0,
+ };
+
+ const normalContent = (
+
+ {i18n.content}
+
+ );
+
+ return (
+
+
+
+
+ {this.renderMask(true, normalContent)}
+
+
+
+
+ );
+ }
+}
+
+
+const render = (lang = 'en-us') => {
+ const i18n = i18nMaps[lang];
+ ReactDOM.render(
, document.getElementById('container'));
+};
+
+window.renderDemo = render;
+window.renderDemo('en-us');
+initDemo('drawer');
diff --git a/docs/field/index.en-us.md b/docs/field/index.en-us.md
index cd2d8c0c7c..8d69278451 100644
--- a/docs/field/index.en-us.md
+++ b/docs/field/index.en-us.md
@@ -201,7 +201,7 @@ The api interface provided by the object after `new` (eg `myfield.getValues()`)
| getValue | get the value of a single input control | Function(name: String) |
| setValues | Sets the value of a set of input controls (triggers render, follow the use of react time) | Function(obj: Object) |
| setValue | Sets the value of a single input control (triggers render, follow the use of react time) | Function(name: String, value) |
-| Validate | Validate and retrieve the values of a set of input fields and Error | Function([names: String[]], [options: Object], callback: Function(errors, values)) | | |
+| Validate | Validate and retrieve the values of a set of input fields and Error | Function([names: String[]], callback: Function(errors, values)) | | |
|getError | Get Error of a Single Input Control | Function(name: String) | | |
|getErrors | Get Errors of a Group of Input Controls | Function([name: String]) | | |
|setError | Set Error for a Single Input Control | Function(name: String, errors:String/Array[String]) | | |
diff --git a/docs/field/index.md b/docs/field/index.md
index 9f7add8150..87871f3797 100644
--- a/docs/field/index.md
+++ b/docs/field/index.md
@@ -205,7 +205,7 @@ let myfield = new Field(this [,options]);
| getValue | 获取单个输入控件的值 | Function(name: String) | | |
| setValues | 设置一组输入控件的值(会触发render,请遵循react时机使用) | Function(obj: Object) | | |
| setValue | 设置单个输入控件的值 (会触发render,请遵循react时机使用)| Function(name: String, value) | | |
-| validate | 校验并获取一组输入域的值与 Error | Function([names: String[]], [options: Object], callback: Function(errors, values)) | | |
+| validate | 校验并获取一组输入域的值与 Error | Function([names: String[]], callback: Function(errors, values)) | | |
| getError | 获取单个输入控件的 Error | Function(name: String) | | |
| getErrors | 获取一组输入控件的 Error | Function([name: String]) | | |
| setError | 设置单个输入控件的 Error | Function(name: String, errors:String/Array[String]) | | |
diff --git a/docs/form/demo/mobile.md b/docs/form/demo/mobile.md
new file mode 100644
index 0000000000..8fc98eafec
--- /dev/null
+++ b/docs/form/demo/mobile.md
@@ -0,0 +1,78 @@
+# 移动端
+
+- order: 17
+
+device=phone 下会强制设置 labelAlign=top
+
+:::lang=en-us
+# Basic Usage
+
+- order: 17
+
+force set labelAlign=top while device=phone
+
+:::
+---
+
+````jsx
+import { Form, Input, Checkbox, Switch, Radio } from '@alifd/next';
+
+
+const FormItem = Form.Item;
+
+const formItemLayout = {
+ labelCol: {
+ fixedSpan: 10
+ },
+ wrapperCol: {
+ span: 14
+ }
+};
+
+class Demo extends React.Component {
+ state = {
+ device: 'desktop'
+ }
+
+ handleDeviceChange = (device) => {
+ this.setState({
+ device
+ });
+ };
+
+ render() {
+ return (
+
+
+ desktop
+ phone
+
+
+
+
+ );
+ }
+}
+
+ReactDOM.render(
, mountNode);
+````
diff --git a/docs/form/index.md b/docs/form/index.md
index 99a6d2229d..eece66b426 100644
--- a/docs/form/index.md
+++ b/docs/form/index.md
@@ -40,6 +40,7 @@
| value | 表单数值 | Object | - |
| onChange | 表单变化回调
**签名**:
Function(values: Object, item: Object) => void
**参数**:
_values_: {Object} 表单数据
_item_: {Object} 详细
_item.name_: {String} 变化的组件名
_item.value_: {String} 变化的数据
_item.field_: {Object} field 实例 | Function | func.noop |
| component | 设置标签类型 | String/Function | 'form' |
+| device | 预设屏幕宽度
**可选值**:
'phone', 'tablet', 'desktop' | Enum | 'desktop' |
### Form.Item
@@ -82,6 +83,7 @@
| validator | [表单校验] 自定义校验函数
**签名**:
Function() => void | Function | - |
| validatorTrigger | validator 自定义触发方式 | String/Array | - |
| autoValidate | 是否修改数据时自动触发校验 | Boolean | - |
+| device | 预设屏幕宽度
**可选值**:
'phone', 'tablet', 'desktop' | Enum | - |
### Form.Submit
diff --git a/docs/input/adaptor/index.jsx b/docs/input/adaptor/index.jsx
new file mode 100644
index 0000000000..20ef0f2969
--- /dev/null
+++ b/docs/input/adaptor/index.jsx
@@ -0,0 +1,172 @@
+import React from 'react';
+import { Types } from '@alifd/adaptor-helper';
+import { Input } from '@alifd/next';
+
+export default {
+ name: 'Input',
+ shape: [{
+ label: 'Textfield',
+ value: 'textfield'
+ }, {
+ label: 'Textarea',
+ value: 'textarea'
+ }, {
+ label: 'Addon',
+ value: 'addon'
+ }],
+ editor: (shape = 'textfield') => {
+ return {
+ props: [...(
+ shape === 'textarea' ? [] : [{
+ name: 'size',
+ type: Types.enum,
+ options: ['large', 'medium', 'small'],
+ default: 'medium'
+ }]
+ ), ...(
+ shape === 'addon' ? [] : [{
+ name: 'state',
+ label: 'Status',
+ type: Types.enum,
+ options: ['normal', 'focused', 'disabled', 'error', ...(shape === 'textfield' ? ['success', 'loading'] : [])],
+ default: 'normal'
+ }]
+ ), {
+ name: 'widget',
+ type: Types.enum,
+ options: shape === 'textarea' ? ['none', 'length'] : ['none', 'length', 'clear'],
+ default: 'none'
+ }, {
+ name: 'width',
+ type: Types.number,
+ default: 200
+ },
+ ...(shape === 'textarea' ? [{
+ name: 'rows',
+ type: Types.number,
+ default: 4,
+ }] : []),
+ ...(shape !== 'addon' ? [{
+ name: 'border',
+ type: Types.bool,
+ default: true,
+ }] : []),
+ {
+ name: 'label',
+ type: Types.string,
+ default: ''
+ }, {
+ name: 'placeholder',
+ type: Types.string,
+ default: 'Please Input'
+ },
+ ...(shape === 'addon' ? [{
+ name: 'prefix',
+ type: Types.string,
+ default: 'https://'
+ }, {
+ name: 'suffix',
+ type: Types.string,
+ default: '.com'
+ }] : [])],
+ data: {
+ default: shape === 'textarea' ? 'multiple line' : shape === 'addon' ? 'alibaba' : ''
+ }
+ };
+ },
+ adaptor: ({
+ shape,
+ size,
+ state,
+ widget,
+ width,
+ rows,
+ border,
+ label,
+ placeholder,
+ prefix = '',
+ suffix = '',
+ style = {},
+ className = '',
+ data,
+ ...others
+ }) => {
+ const props = {
+ ...others,
+ label,
+ hasBorder: border,
+ placeholder,
+ className,
+ style: {
+ width,
+ ...style
+ },
+ value: data
+ };
+
+ if (widget === 'length') {
+ props.hasLimitHint = true;
+ props.maxLength = 15;
+ } else if (widget === 'clear') {
+ props.hasClear = true;
+ }
+
+ if (size) {
+ props.size = size;
+ }
+
+ switch(state) {
+ case 'focused':
+ props.className = `${className} next-focus`;
+ break;
+ case 'disabled':
+ props.disabled = true;
+ break;
+ case 'error':
+ case 'loading':
+ case 'success':
+ props.state = state;
+ break;
+ default: break;
+ }
+
+
+ if (rows && rows > 0) {
+ props.rows = rows;
+ }
+
+ if (shape === 'addon') {
+ props.addonTextAfter = suffix;
+ props.addonTextBefore = prefix;
+ }
+
+ if (shape === 'textarea') {
+ return
;
+ }
+
+ return
;
+ },
+ content: (shape) => {
+ if (shape === 'textfield') {
+ return {
+ options: [{
+ name: 'clear',
+ options: ['show', 'hide'],
+ default: 'hide',
+ }],
+ transform: (props, { clear }) => {
+ return {
+ ...props,
+ widget: clear === 'show' ? 'clear' : 'none',
+ data: clear === 'show' ? 'Input ...' : props.value,
+ };
+ }
+ };
+ }
+
+ return {
+ options: [],
+ transform: p => p
+ };
+ }
+};
diff --git a/docs/loading/adaptor/index.jsx b/docs/loading/adaptor/index.jsx
new file mode 100644
index 0000000000..f81f8b148d
--- /dev/null
+++ b/docs/loading/adaptor/index.jsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import { Loading } from '@alifd/next';
+
+export default {
+ name: 'Loading',
+ editor: () => ({
+ props: [{
+ name: 'size',
+ type: 'enum',
+ options: ['large', 'medium'],
+ default: 'medium'
+ }],
+ }),
+ adaptor: ({ size, ...others }) => {
+ return
;
+ }
+};
diff --git a/docs/menu-button/adaptor/index.jsx b/docs/menu-button/adaptor/index.jsx
new file mode 100644
index 0000000000..1c67e72b5d
--- /dev/null
+++ b/docs/menu-button/adaptor/index.jsx
@@ -0,0 +1,195 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import { MenuButton, Menu, Icon } from '@alifd/next';
+import { Types, parseData, ContentType } from '@alifd/adaptor-helper';
+
+const createDataSouce = (list, keys = { selected: [], expanded: {} }, level = 0, prefix='') => {
+ const array = [];
+ let group = [];
+ let grouping = false;
+ let index = 0;
+
+ list.forEach((item) => {
+ switch(item.type) {
+ // eslint-disable-next-line no-case-declarations
+ case 'node':
+ const key = `${prefix || level }-${index++}`;
+
+ if (item.children && item.children.length > 0) {
+ item.children = createDataSouce(item.children, keys, level + 1, key);
+ }
+
+ if (grouping) {
+ group.push({
+ ...item,
+ key,
+ });
+ } else {
+ array.push({
+ ...item,
+ key
+ });
+ }
+
+ if (item.state === 'active') {
+ if (item.children && item.children.length > 0) {
+ keys.expanded.push(key);
+ } else {
+ keys.selected.push(key);
+ }
+ }
+
+ return;
+ case 'comment':
+ if (group.length > 0) {
+ array.push({
+ type: 'group',
+ value: grouping,
+ children: group,
+ key: `${prefix || level }-${index++}`
+ });
+ group = [];
+ }
+ grouping = item.value;
+ return;
+ case 'divider':
+ if (group.length > 0) {
+ array.push({
+ type: 'group',
+ value: grouping,
+ children: group,
+ key: `${prefix || level }-${index++}`
+ });
+ group = [];
+ }
+ grouping = false;
+ array.push({
+ type: 'divider',
+ key: `${prefix || level }-${index++}`,
+ });
+ return;
+ default: return;
+ }
+ });
+
+ if (group.length > 0) {
+ array.push({
+ type: 'group',
+ value: grouping,
+ children: group,
+ key: `${prefix || level }-${index++}`
+ });
+ group = [];
+ }
+
+ return array;
+};
+
+const createMenuItem = (item) => {
+ if (item.children.length > 0) {
+ return (
+
type === ContentType.text).map(({ value }) => value).join('') : ''}>
+ {createContents(item.children)}
+
+ );
+ }
+
+ return
type === 'icon' ? : value)} />;
+};
+
+const createContents = (array = []) => {
+
+ return array.map((item) => {
+ if (item.type === 'group' && item.children.length > 0) {
+ return {item.children.map(it => createMenuItem(it))};
+ }
+
+ if (item.type === 'divider') {
+ return ;
+ }
+
+ return createMenuItem(item);
+ });
+};
+
+export default {
+ name: 'MenuButton',
+ shape: ['normal', 'text', 'ghost'],
+ editor: (shape = 'normal') => ({
+ props: [{
+ name: 'level',
+ type: Types.enum,
+ options: shape === 'text' ? ['normal', 'primary'] : shape === 'ghost' ? ['light', 'dark'] : ['normal', 'primary', 'secondary'],
+ default: shape === 'ghost' ? 'light' : 'normal',
+ }, {
+ name: 'size',
+ type: Types.enum,
+ options: ['large', 'medium', 'small'],
+ default: 'medium'
+ }],
+ data: {
+ icon: true,
+ active: true,
+ disable: true,
+ default: 'Edit Document\n\tUndo\n\t*Redo\n\tCut\n\tCopy\n\tPaste'
+ }
+ }),
+ adaptor: ({ shape, level, size, data, ...others}) => {
+ const list = parseData(data, { parseContent: true });
+ const buttonItem = list[0] ? list[0] : { value: []};
+
+ if (buttonItem.type !== 'node') return null;
+
+ const keys = { selected: [], expanded: [] };
+ const dataSouce = createDataSouce(list[0] ? list[0].children : [], keys);
+
+ const label = buttonItem.value.map(({ type, value}) => {
+ if (type === 'icon') return ;
+ return value;
+ });
+
+ return (
+ node}
+ ghost={shape === 'ghost' ? level : false}
+ selectMode="multiple"
+ text={shape === 'text'}
+ menuProps={{ openKeys: keys.expanded, style: { textAlign: 'left' } }}
+ selectedKeys={keys.selected}
+ label={label}
+ >
+ {createContents(dataSouce)}
+
+ );
+ },
+ demoOptions: (demo) => {
+ const { node = { props: {} } } = demo;
+ const { level, data } = node.props;
+ if (data.indexOf('*') === 0) {
+ demo = {
+ ...demo,
+ height: 250
+ };
+ }
+
+ if (level === 'dark') {
+ demo = {
+ ...demo,
+ background: '#333'
+ };
+ } else if(level === 'light') {
+ demo = {
+ ...demo,
+ background: 'rgb(235, 236, 240)',
+ };
+ }
+
+ return demo;
+ }
+};
diff --git a/docs/menu/adaptor/index.jsx b/docs/menu/adaptor/index.jsx
new file mode 100644
index 0000000000..df98fc1551
--- /dev/null
+++ b/docs/menu/adaptor/index.jsx
@@ -0,0 +1,192 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import { Types, parseData, ContentType } from '@alifd/adaptor-helper';
+import { Menu, Icon } from '@alifd/next';
+
+const createDataSouce = (list, keys = { selected: [], expanded: [] }, level = 0, prefix='') => {
+ const array = [];
+ let group = [];
+ let grouping = false;
+ let index = 0;
+
+ list.forEach((item) => {
+ switch(item.type) {
+ // eslint-disable-next-line no-case-declarations
+ case 'node':
+ const key = `${prefix || level }-${index++}`;
+
+ if (item.children && item.children.length > 0) {
+ item.children = createDataSouce(item.children, keys, level + 1, key);
+ }
+
+ if (grouping) {
+ group.push({
+ ...item,
+ key,
+ });
+ } else {
+ array.push({
+ ...item,
+ key
+ });
+ }
+
+ if (item.state === 'active') {
+ if (item.children && item.children.length > 0) {
+ keys.expanded.push(key);
+ } else {
+ keys.selected.push(key);
+ }
+ }
+
+ return;
+ case 'comment':
+ if (group.length > 0) {
+ array.push({
+ type: 'group',
+ value: grouping,
+ children: group,
+ key: `${prefix || level }-${index++}`
+ });
+ group = [];
+ }
+ grouping = item.value;
+ return;
+ case 'divider':
+ if (group.length > 0) {
+ array.push({
+ type: 'group',
+ value: grouping,
+ children: group,
+ key: `${prefix || level }-${index++}`
+ });
+ group = [];
+ }
+ grouping = false;
+ array.push({
+ type: 'divider',
+ key: `${prefix || level }-${index++}`,
+ });
+ return;
+ default: return;
+ }
+ });
+
+ if (group.length > 0) {
+ array.push({
+ type: 'group',
+ value: grouping,
+ children: group,
+ key: `${prefix || level }-${index++}`
+ });
+ group = [];
+ }
+
+ return array;
+};
+
+const createMenuItem = (item, selectType) => {
+ if (item.children.length > 0) {
+ return (
+ type === ContentType.text).map(({ value }) => value).join('') : ''}>
+ {createContents(item.children, selectType)}
+
+ );
+ }
+
+ let Item = Menu.Item;
+
+ if (selectType === 'checkbox') {
+ Item = Menu.CheckboxItem;
+ } else if (selectType === 'radio') {
+ Item = Menu.RadioItem;
+ }
+
+ return - type === 'icon' ? : value)} />;
+};
+
+const createContents = (array = [], selectType) => {
+
+ return array.map((item) => {
+ if (item.type === 'group' && item.children.length > 0) {
+ return {item.children.map(it => createMenuItem(it, selectType))};
+ }
+
+ if (item.type === 'divider') {
+ return ;
+ }
+
+ return createMenuItem(item, selectType);
+ });
+};
+
+export default {
+ name: "Menu",
+ editor: () => ({
+ props: [{
+ name: 'selectType',
+ label: 'Selection Mode',
+ type: Types.enum,
+ options: ['checkbox', 'radio', 'checkLeft', 'checkRight'],
+ default: 'checkLeft'
+ }, {
+ name: 'nestMode',
+ label: 'Subset Structure',
+ type: Types.enum,
+ options: ['inline', 'popup'],
+ default: 'inline',
+ }, {
+ name: 'width',
+ type: Types.number,
+ default: 150
+ }],
+ data: {
+ active: true,
+ disable: true,
+ group: true,
+ icon: true,
+ default: '#Group1\noption1\n*option2\n\tsub option3\n\t-sub option4\n\tsub option5\n---\n#Group2\noption1\n*option2'
+ }
+ }),
+ adaptor: ({ selectType, nestMode, width, style, data, ...others }) => {
+ const list = parseData(data, { parseContent: true });
+ const keys = { selected: [], expanded: [] };
+ const array = createDataSouce(list, keys);
+
+ return (
+
+ );
+ },
+ content: () => ({
+ options: [{
+ name: 'group',
+ options: ['yes', 'no'],
+ default: 'no'
+ }, {
+ name: 'icon',
+ options: ['yes', 'no'],
+ default: 'no'
+ }, {
+ name: 'selectType',
+ options: ['checkbox', 'radio', 'checkLeft', 'checkRight'],
+ default: 'checkLeft',
+ }],
+ transform: (props, { group, icon, selectType }) => {
+ const iconStr = icon === 'yes' ? '[picture]' : '';
+ const prefix = (props.data || '').indexOf('*') !== -1 ? '*' : (props.data || '').indexOf('-') !== -1 ? '-' : '';
+ if (group === 'yes') {
+ props.data = `#group1\n${prefix}${iconStr}option1\n${iconStr}option2\n---\n#group2\n${iconStr}option3\n${iconStr}option4`;
+ } else if (icon === 'yes') {
+ props.data = `${iconStr}option1\n${iconStr}option2\n${iconStr}option3\n${iconStr}option4`;
+ }
+ return {
+ ...props,
+ selectType,
+ };
+ }
+ })
+};
diff --git a/docs/message/adaptor/index.jsx b/docs/message/adaptor/index.jsx
new file mode 100644
index 0000000000..4ddb0487e7
--- /dev/null
+++ b/docs/message/adaptor/index.jsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import { Message } from '@alifd/next';
+import { Types } from '@alifd/adaptor-helper';
+
+export default {
+ name: 'Message',
+ editor: () => ({
+ props: [{
+ name: 'level',
+ label: 'Shape',
+ type: Types.enum,
+ options: ['inline', 'toast', 'addon'],
+ default: 'inline'
+ }, {
+ name: 'size',
+ type: Types.enum,
+ options: ['large', 'medium'],
+ default: 'medium'
+ }, {
+ name: 'state',
+ label: 'Status',
+ type: Types.enum,
+ options: ['success', 'warning', 'error', 'notice', 'help', 'loading'],
+ default: 'success',
+ }, {
+ name: 'closable',
+ label: 'Close Included',
+ type: Types.bool,
+ default: false
+ }, {
+ name: 'width',
+ type: Types.number,
+ default: 400
+ }, {
+ name: 'title',
+ type: Types.string,
+ default: 'Title'
+ }],
+ data: {
+ default: 'This item already has the label "travel", you can add a new label.'
+ }
+ }),
+ adaptor: ({ level, size, state, closable, width, title, data, style, ...others}) => {
+ return (
+ {data}
+ );
+ }
+};
diff --git a/docs/nav/adaptor/index.jsx b/docs/nav/adaptor/index.jsx
new file mode 100644
index 0000000000..80873840fb
--- /dev/null
+++ b/docs/nav/adaptor/index.jsx
@@ -0,0 +1,188 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import { Types, parseData, ContentType } from '@alifd/adaptor-helper';
+import { Nav } from '@alifd/next';
+
+const createDataSouce = (list, keys = { selected: [], expanded: {} }, level = 0, prefix='') => {
+ const array = [];
+ let group = [];
+ let grouping = false;
+ let index = 0;
+
+ list.forEach((item) => {
+ switch(item.type) {
+ // eslint-disable-next-line no-case-declarations
+ case 'node':
+ const key = `${prefix || level }-${index++}`;
+
+ if (item.children && item.children.length > 0) {
+ item.children = createDataSouce(item.children, keys, level + 1, key);
+ }
+
+ if (grouping) {
+ group.push({
+ ...item,
+ key,
+ });
+ } else {
+ array.push({
+ ...item,
+ key
+ });
+ }
+
+ if (item.state === 'active') {
+ if (item.children && item.children.length > 0) {
+ keys.expanded.push(key);
+ } else {
+ keys.selected.push(key);
+ }
+ }
+
+ return;
+ case 'comment':
+ if (group.length > 0) {
+ array.push({
+ type: 'group',
+ value: grouping,
+ children: group,
+ key: `${prefix || level }-${index++}`
+ });
+ group = [];
+ }
+ grouping = item.value;
+ return;
+ case 'divider':
+ if (group.length > 0) {
+ array.push({
+ type: 'group',
+ value: grouping,
+ children: group,
+ key: `${prefix || level }-${index++}`
+ });
+ group = [];
+ }
+ grouping = false;
+ array.push({
+ type: 'divider',
+ key: `${prefix || level }-${index++}`,
+ });
+ return;
+ default: return;
+ }
+ });
+
+ if (group.length > 0) {
+ array.push({
+ type: 'group',
+ value: grouping,
+ children: group,
+ key: `${prefix || level }-${index++}`
+ });
+ group = [];
+ }
+
+ return array;
+};
+
+const createMenuItem = (item) => {
+ const { value } = (item.value || []).find(item => item.type === ContentType.icon) || {};
+ if (item.children.length > 0) {
+ return (
+ type === ContentType.text).map(({ value }) => value).join('') : ''}>
+ {createContents(item.children)}
+
+ );
+ }
+
+ return type === 'icon' ? null : value)} />;
+};
+
+const createContents = (array = []) => {
+
+ return array.map((item) => {
+ if (item.type === 'group' && item.children.length > 0) {
+ return {item.children.map(it => createMenuItem(it))};
+ }
+
+ if (item.type === 'divider') {
+ return ;
+ }
+
+ return createMenuItem(item);
+ });
+};
+
+
+export default {
+ name: 'Nav',
+ shape: [{
+ label: 'Horizontal',
+ value: 'hoz'
+ }, {
+ label: 'Vertical',
+ value: 'ver'
+ }],
+ editor: (shape = 'hoz') => ({
+ props: [{
+ name: 'level',
+ type: Types.enum,
+ options: ['normal', 'primary', 'secondary', 'line'],
+ default: 'normal'
+ }, {
+ name: 'selectLinePosition',
+ label: 'Label Position',
+ type: Types.enum,
+ options: shape === 'hoz' ? ['top', 'bottom', 'none'] : ['left', 'right', 'none'],
+ default: shape === 'hoz' ? 'bottom' : 'right'
+ }, {
+ name: 'width',
+ type: Types.number,
+ default: shape === 'hoz' ? 640 : 200
+ },
+ ...(shape === 'ver' ? [{
+ name: 'height',
+ type: Types.number,
+ default: shape === 'hoz' ? '' : 600
+ }, {
+ name: 'iconOnly',
+ type: Types.bool,
+ default: false,
+ }] : [])],
+ data: {
+ active: true,
+ hover: true,
+ group: true,
+ icon: true,
+ default: `[account]Nav Item 1\n[account]Nav Item 2\n[account]Nav Item 3\n${shape === 'ver' ? '*' : ''}[account]Nav Item 4\n\t[account]Option 1\n\t[account]Option 2\n\t[account]Option 3\n\t[account]Option 4`
+ }
+ }),
+ adaptor: ({ shape, level, selectLinePosition, width, height, data, style, iconOnly = false, ...others}) => {
+ const list = parseData(data, { parseContent: true });
+ const keys = { selected: [], expanded: [] };
+ const dataSouce = createDataSouce(list, keys);
+
+ return (
+
+ );
+ }
+};
diff --git a/docs/number-picker/adaptor/index.jsx b/docs/number-picker/adaptor/index.jsx
new file mode 100644
index 0000000000..64d541d2b9
--- /dev/null
+++ b/docs/number-picker/adaptor/index.jsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { NumberPicker } from '@alifd/next';
+import { Types } from '@alifd/adaptor-helper';
+
+export default {
+ name: 'NumberPicker',
+ editor: () => ({
+ props: [{
+ name: 'level',
+ type: Types.enum,
+ options: ['normal', 'inline'],
+ default: 'normal'
+ }, {
+ name: 'size',
+ type: Types.enum,
+ options: ['large', 'medium'],
+ default: 'medium'
+ }, {
+ name: 'state',
+ label: 'Status',
+ type: Types.enum,
+ options: ['normal', 'disabled'],
+ default: 'normal'
+ }, {
+ name: 'width',
+ type: Types.number,
+ default: 80
+ }, {
+ name: 'value',
+ type: Types.number,
+ default: 1
+ }]
+ }),
+ adaptor: ({ level, size, state, width, value, style, ...others }) => {
+ return
+ }
+};
diff --git a/docs/number-picker/demo/mobile.md b/docs/number-picker/demo/mobile.md
new file mode 100644
index 0000000000..ac340269c8
--- /dev/null
+++ b/docs/number-picker/demo/mobile.md
@@ -0,0 +1,50 @@
+# 移动端
+
+- order: 9
+
+device=phone 下会强制设置 type=normal
+
+:::lang=en-us
+# Basic Usage
+
+- order: 9
+
+force set type=normal while device=phone
+
+:::
+---
+
+````jsx
+import { NumberPicker, Radio } from '@alifd/next';
+
+class Demo extends React.Component {
+ state = {
+ device: 'desktop'
+ }
+
+ handleDeviceChange = (device) => {
+ this.setState({
+ device
+ });
+ };
+
+ render() {
+ return (
+
+
+ desktop
+ phone
+
+
+
+
+ );
+ }
+}
+
+ReactDOM.render(, mountNode);
+````
diff --git a/docs/number-picker/index.md b/docs/number-picker/index.md
index 9bb68d982e..02031ac686 100644
--- a/docs/number-picker/index.md
+++ b/docs/number-picker/index.md
@@ -51,6 +51,7 @@
| downBtnProps | 减少按钮的props | Object | - |
| label | 内联 label | ReactNode | - |
| innerAfter | inner after | ReactNode | - |
+| device | 预设屏幕宽度
**可选值**:
'phone', 'tablet', 'desktop' | Enum | - |
## ARIA and KeyBoard
diff --git a/docs/pagination/adaptor/index.jsx b/docs/pagination/adaptor/index.jsx
new file mode 100644
index 0000000000..70e73d631a
--- /dev/null
+++ b/docs/pagination/adaptor/index.jsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import { Pagination } from '@alifd/next';
+import { Types } from '@alifd/adaptor-helper';
+import enUS from '../../../src/locale/en-us';
+
+export default {
+ name: 'Pagination',
+ shape: ['normal', 'simple', 'mini'],
+ editor: () => ({
+ props: [{
+ name: 'size',
+ type: Types.enum,
+ options: ['large', 'medium', 'small'],
+ default: 'medium'
+ }, {
+ name: 'sizeSelector',
+ label: 'Widget',
+ type: Types.enum,
+ options: ['none', 'filter', 'dropdown'],
+ default: 'none'
+ }, {
+ name: 'control',
+ label: 'Arrow Style',
+ type: Types.enum,
+ options: ['textAndIcon', 'onlyIcon', 'noBorder'],
+ default: 'textAndIcon'
+ }]
+ }),
+ adaptor: ({ shape, size, sizeSelector, control, ...others}) => {
+ return (
+
+ );
+ },
+ content: () => ({
+ options: [{
+ name: 'control',
+ options: ['textAndIcon', 'onlyIcon', 'noBorder'],
+ default: 'textAndIcon'
+ }],
+ transform: (props, { control }) => {
+ return {
+ ...props,
+ control
+ };
+ }
+ })
+};
diff --git a/docs/paragraph/adaptor/index.jsx b/docs/paragraph/adaptor/index.jsx
new file mode 100644
index 0000000000..2c4ade5c32
--- /dev/null
+++ b/docs/paragraph/adaptor/index.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import { Paragraph } from '@alifd/next';
+import { Types } from '@alifd/adaptor-helper';
+
+export default {
+ name: 'Paragraph',
+ editor: () => ({
+ props: [{
+ name: 'size',
+ type: Types.enum,
+ options: ['medium', 'small'],
+ default: 'medium'
+ }, {
+ name: 'width',
+ type: Types.number,
+ default: 400
+ }],
+ data: {
+ default: `Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`
+ }
+ }),
+ adaptor: ({ size, width, style, data, ...others }) => {
+ return ({data});
+ }
+};
diff --git a/docs/progress/adaptor/index.jsx b/docs/progress/adaptor/index.jsx
new file mode 100644
index 0000000000..4fc510f8f3
--- /dev/null
+++ b/docs/progress/adaptor/index.jsx
@@ -0,0 +1,108 @@
+import React from 'react';
+import { Types } from '@alifd/adaptor-helper';
+import { Progress } from '@alifd/next';
+
+export default {
+ name: 'Progress',
+ shape: ['line', 'circle'],
+ editor: (shape = 'line') => {
+ return {
+ props: [{
+ name: 'mode',
+ label: 'Type',
+ type: Types.enum,
+ options: ['basic', 'staging'],
+ default: 'basic'
+ }, {
+ name: 'level',
+ type: Types.enum,
+ options: ['normal', 'success', 'error'],
+ default: 'normal'
+ }, {
+ name: 'size',
+ type: Types.enum,
+ options: ['large', 'medium', 'small'],
+ default: 'medium'
+ }, {
+ name: 'text',
+ label: 'Data Included',
+ type: Types.bool,
+ default: false
+ },
+ ...(
+ shape === 'line' ?
+ [{
+ name: 'border',
+ type: Types.bool,
+ default: false
+ }, {
+ name: 'width',
+ type: Types.number,
+ default: 200
+ }] :
+ []
+ ),
+ {
+ name: 'percent',
+ type: Types.number,
+ default: 25
+ }]
+ };
+ },
+ adaptor: ({ shape, level, size, mode, text, border, width, percent, style, ...others }) => {
+ return (
+
);
diff --git a/src/time-picker/panel.jsx b/src/time-picker/panel.jsx
index c8b0aea993..e21d153447 100644
--- a/src/time-picker/panel.jsx
+++ b/src/time-picker/panel.jsx
@@ -54,6 +54,18 @@ class TimePickerPanel extends Component {
* @return {Boolean} 是否禁用
*/
disabledSeconds: PropTypes.func,
+ /**
+ * 渲染的可选择时间列表
+ * [{
+ * label: '01',
+ * value: 1
+ * }]
+ * @param {Array} list 默认渲染的列表
+ * @param {String} mode 渲染的菜单 hour, minute, second
+ * @param {moment} value 当前时间,可能为 null
+ * @return {Array} 返回需要渲染的数据
+ */
+ renderTimeMenuItems: PropTypes.func,
/**
* 选择某个日期值时的回调
* @param {Object} 选中后的日期值
@@ -110,6 +122,7 @@ class TimePickerPanel extends Component {
disabledHours,
disabledMinutes,
disabledSeconds,
+ renderTimeMenuItems,
...others
} = this.props;
@@ -126,6 +139,8 @@ class TimePickerPanel extends Component {
prefix,
disabled,
onSelect: this.onSelectMenuItem,
+ renderTimeMenuItems,
+ value,
};
let activeHour;
diff --git a/src/time-picker/scss/menu.scss b/src/time-picker/scss/menu.scss
index ab8587a210..41a7ef92c3 100644
--- a/src/time-picker/scss/menu.scss
+++ b/src/time-picker/scss/menu.scss
@@ -30,7 +30,7 @@
cursor: pointer;
height: $time-picker-menu-item-height;
line-height: $time-picker-menu-item-height;
- transition: background .3s ease-out;
+ transition: background $motion-duration-immediately $motion-linear;
color: $time-picker-menu-item-color;
background: $time-picker-menu-item-background;
outline: none;
diff --git a/src/time-picker/time-picker.jsx b/src/time-picker/time-picker.jsx
index 48dc736867..a1f7632c50 100644
--- a/src/time-picker/time-picker.jsx
+++ b/src/time-picker/time-picker.jsx
@@ -84,6 +84,18 @@ export default class TimePicker extends Component {
* @return {Boolean} 是否禁用
*/
disabledSeconds: PropTypes.func,
+ /**
+ * 渲染的可选择时间列表
+ * [{
+ * label: '01',
+ * value: 1
+ * }]
+ * @param {Array} list 默认渲染的列表
+ * @param {String} mode 渲染的菜单 hour, minute, second
+ * @param {moment} value 当前时间,可能为 null
+ * @return {Array} 返回需要渲染的数据
+ */
+ renderTimeMenuItems: PropTypes.func,
/**
* 弹层是否显示(受控)
*/
@@ -138,6 +150,7 @@ export default class TimePicker extends Component {
*/
onChange: PropTypes.func,
className: PropTypes.string,
+ name: PropTypes.string,
};
static defaultProps = {
@@ -316,6 +329,7 @@ export default class TimePicker extends Component {
disabledHours,
disabledMinutes,
disabledSeconds,
+ renderTimeMenuItems,
popupAlign,
popupTriggerType,
popupContainer,
@@ -380,6 +394,7 @@ export default class TimePicker extends Component {
disabledHours,
disabledMinutes,
disabledSeconds,
+ renderTimeMenuItems,
onSelect: this.onTimePanelSelect,
};
@@ -398,9 +413,9 @@ export default class TimePicker extends Component {
className={classNames}
>