Skip to content

Commit

Permalink
deprecated(Dropdown): triggerType="focus" is deprecated
Browse files Browse the repository at this point in the history
  • Loading branch information
youluna committed Mar 29, 2019
1 parent e11f1df commit a07bb54
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 177 deletions.
9 changes: 6 additions & 3 deletions docs/dropdown/demo/basic.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ const menu = (
);

ReactDOM.render(
<Dropdown trigger={<a>Hello dropdown</a>} afterOpen={() => console.log('after open')}>
{menu}
</Dropdown>, mountNode);
<div>
<Dropdown trigger={<button>Hello dropdown</button>} triggerType={["click", "hover"]} afterOpen={() => console.log('after open')}>
{menu}
</Dropdown>
</div>
, mountNode);
````
6 changes: 5 additions & 1 deletion docs/dropdown/index.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

You can storage operation command with dropdown component when there are too much command. There will be a drop-down menu after you click or hover the trigger element. Then choose a command and run it.

### Note

- Dropdown is accessible when using like `<Dropdown triggerType={["click", "hover"]}>` (triggerType="focus" is deprecated). In our opinion, menu elements need to be confirmed by users before they are expanded when it comes to accessibility.

## API

### Dropdown
Expand All @@ -25,7 +29,7 @@ You can storage operation command with dropdown component when there are too muc
| defaultVisible | overlay display or not in default situation | Boolean | false |
| onVisibleChange | callback function when toggle visible of overlay<br><br>**signatures**:<br>Function(visible: Boolean, type: String, e: Object) => void<br>**params**:<br>_visible_: {Boolean} overlay display or not<br>_type_: {String} orign of trigger overlay toggle visible<br>_e_: {Object} DOM Event| Function | func.noop |
| trigger | trigger element | ReactNode | - |
| triggerType | operation type of trigger overlay toggle visible<br><br>**options**:<br>'hover', 'click', 'focus' | Enum | 'hover' |
| triggerType | operation type of trigger overlay toggle visible<br><br>**options**:<br>'hover', 'click' | Enum | 'hover' |
| disabled | overlay can not toggle visible if you set disabled attribute | Boolean | false |
| align | overlay position relative to trigger element, see details Overlay align | String | 'tl bl' |
| offset | overlay adjust position relative to trigger element | Array | [0, 0] |
Expand Down
6 changes: 5 additions & 1 deletion docs/dropdown/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

当页面上的操作命令过多时,用此组件可以收纳操作元素。点击或移入触点,会出现一个下拉菜单。可在列表中进行选择,并执行相应的命令。

### 使用注意

- 若要使用无障碍的Dropdown,推荐使用`<Dropdown triggerType={["click", "hover"]}>` (请勿使用triggerType="focus")。我们认为,菜单类元素需要由用户确认后再展开才是一种无障碍友好的实践。

## API

### Dropdown
Expand All @@ -26,7 +30,7 @@
| defaultVisible | 弹层默认是否显示 | Boolean | false |
| onVisibleChange | 弹层显示或隐藏时触发的回调函数<br><br>**签名**:<br>Function(visible: Boolean, type: String, e: Object) => void<br>**参数**:<br>_visible_: {Boolean} 弹层是否显示<br>_type_: {String} 触发弹层显示或隐藏的来源<br>_e_: {Object} DOM事件 | Function | func.noop |
| trigger | 触发弹层显示或者隐藏的元素 | ReactNode | - |
| triggerType | 触发弹层显示或隐藏的操作类型<br><br>**可选值**:<br>'hover', 'click', 'focus' | Enum | 'hover' |
| triggerType | 触发弹层显示或隐藏的操作类型,可以是 'click','hover',或者它们组成的数组,如 ['hover', 'click'] | String/Array | ['hover'] |
| disabled | 设置此属性,弹层无法显示或隐藏 | Boolean | false |
| align | 弹层相对于触发元素的定位, 详见 Overlay 的定位部分 | String | 'tl bl' |
| offset | 弹层相对于触发元素定位的微调 | Array | [0, 0] |
Expand Down
168 changes: 168 additions & 0 deletions src/dropdown/dropdown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import React, { Component, Children } from 'react';
import PropTypes from 'prop-types';
import Overlay from '../overlay';
import { func } from '../util';

const { noop, makeChain, bindCtx } = func;
const Popup = Overlay.Popup;

/**
* Dropdown
* @description 继承 Popup 的 API,除非特别说明
*/
export default class Dropdown extends Component {
static propTypes = {
prefix: PropTypes.string,
pure: PropTypes.bool,
rtl: PropTypes.bool,
className: PropTypes.string,
/**
* 弹层内容
*/
children: PropTypes.node,
/**
* 弹层当前是否显示
*/
visible: PropTypes.bool,
/**
* 弹层默认是否显示
*/
defaultVisible: PropTypes.bool,
/**
* 弹层显示或隐藏时触发的回调函数
* @param {Boolean} visible 弹层是否显示
* @param {String} type 触发弹层显示或隐藏的来源
* @param {Object} e DOM事件
*/
onVisibleChange: PropTypes.func,
/**
* 触发弹层显示或者隐藏的元素
*/
trigger: PropTypes.node,
/**
* 触发弹层显示或隐藏的操作类型,可以是 'click','hover',或者它们组成的数组,如 ['hover', 'click']
*/
triggerType: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
/**
* 设置此属性,弹层无法显示或隐藏
*/
disabled: PropTypes.bool,
/**
* 弹层相对于触发元素的定位, 详见 Overlay 的定位部分
*/
align: PropTypes.string,
/**
* 弹层相对于触发元素定位的微调
*/
offset: PropTypes.array,
/**
* 弹层显示或隐藏的延时时间(以毫秒为单位),在 triggerType 被设置为 hover 时生效
*/
delay: PropTypes.number,
/**
* 弹层打开时是否让其中的元素自动获取焦点
*/
autoFocus: PropTypes.bool,
/**
* 是否显示遮罩
*/
hasMask: PropTypes.bool,
/**
* 隐藏时是否保留子节点
*/
cache: PropTypes.bool,
/**
* 配置动画的播放方式,支持 { in: 'enter-class', out: 'leave-class' } 的对象参数,如果设置为 false,则不播放动画
* @default { in: 'expandInDown', out: 'expandOutUp' }
*/
animation: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
};
static defaultProps = {
prefix: 'next-',
pure: false,
defaultVisible: false,
onVisibleChange: noop,
triggerType: 'hover',
disabled: false,
align: 'tl bl',
offset: [0, 0],
delay: 200,
hasMask: false,
cache: false,
onPosition: noop,
};

constructor(props) {
super(props);

this.state = {
visible:
'visible' in props
? props.visible
: props.defaultVisible || false,
autoFocus: 'autoFocus' in props ? props.autoFocus : false,
};

bindCtx(this, ['onTriggerKeyDown', 'onMenuClick', 'onVisibleChange']);
}

getVisible(props = this.props) {
return 'visible' in props ? props.visible : this.state.visible;
}

onMenuClick() {
this.onVisibleChange(false, 'fromContent');
}

onVisibleChange(visible, from) {
this.setState({ visible });

this.props.onVisibleChange(visible, from);
}

onTriggerKeyDown() {
let autoFocus = true;

if ('autoFocus' in this.props) {
autoFocus = this.props.autoFocus;
}

this.setState({
autoFocus,
});
}

render() {
let child = Children.only(this.props.children);
if (typeof child.type === 'function' && child.type.isNextMenu) {
child = React.cloneElement(child, {
onItemClick: makeChain(
this.onMenuClick,
child.props.onItemClick
),
});
}

const { trigger, rtl } = this.props;
const newTrigger = React.cloneElement(trigger, {
onKeyDown: makeChain(
this.onTriggerKeyDown,
trigger.props.onKeyDown
),
});

return (
<Popup
{...this.props}
rtl={rtl}
autoFocus={this.state.autoFocus}
trigger={newTrigger}
visible={this.getVisible()}
onVisibleChange={this.onVisibleChange}
canCloseByOutSideClick
>
{child}
</Popup>
);
}
}
Loading

0 comments on commit a07bb54

Please sign in to comment.