Dropdown with dropdown_v2 branch
This commit is contained in:
parent
8a32f61f2f
commit
47f1447bc4
@ -1,82 +1,86 @@
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import classNames from 'classnames';
|
||||
import Icon from '/imports/ui/components/icon/component';
|
||||
import cx from 'classnames';
|
||||
import styles from './styles';
|
||||
import DropdownContent from './DropdownContent';
|
||||
import DropdownTrigger from './DropdownTrigger';
|
||||
|
||||
export default class Dropdown extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { isMenuOpen: false, };
|
||||
this.showMenu = this.showMenu.bind(this);
|
||||
this.hideMenu = this.hideMenu.bind(this);
|
||||
}
|
||||
|
||||
showMenu() {
|
||||
this.setState({ isMenuOpen: !this.state.isMenuOpen, });
|
||||
|
||||
}
|
||||
|
||||
hideMenu() {
|
||||
this.setState({ isMenuOpen: false, });
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { addEventListener } = window;
|
||||
addEventListener( 'click', this.onWindowClick.bind(this), false );
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
const { removeEventListener } = window;
|
||||
removeEventListener( 'click', this.onWindowClick.bind(this), false );
|
||||
}
|
||||
|
||||
onWindowClick(event) {
|
||||
const dropdown_element = findDOMNode(this);
|
||||
const shouldUpdateState = event.target !== dropdown_element &&
|
||||
!dropdown_element.contains(event.target) &&
|
||||
this.state.isMenuOpen;
|
||||
|
||||
if(shouldUpdateState) {
|
||||
this.hideMenu();
|
||||
}
|
||||
}
|
||||
|
||||
toggle() {
|
||||
if(this.state.isMenuOpen) {
|
||||
this.hideMenu();
|
||||
} else {
|
||||
this.showMenu();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const toggleMenu = this.toggle.bind(this);
|
||||
|
||||
// // stick callback on trigger element
|
||||
const boundChildren = React.Children.map( this.props.children, (child) => {
|
||||
if( child.type === DropdownTrigger ){
|
||||
child = React.cloneElement( child, {
|
||||
toggleMenu: toggleMenu,
|
||||
});
|
||||
}
|
||||
return child;
|
||||
});
|
||||
|
||||
let trigger = boundChildren[0];
|
||||
let content = boundChildren[1];
|
||||
|
||||
return (
|
||||
<div className={styles.dropdown}>
|
||||
{trigger}
|
||||
{ this.state.isMenuOpen ?
|
||||
content : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import Icon from '/imports/ui/components/icon/component';
|
||||
import classNames from 'classnames';
|
||||
import styles from './styles';
|
||||
import DropdownTrigger from './DropdownTrigger';
|
||||
import DropdownContent from './DropdownContent';
|
||||
|
||||
export default class Dropdown extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { isMenuOpen: false, };
|
||||
this.showMenu = this.showMenu.bind(this);
|
||||
this.hideMenu = this.hideMenu.bind(this);
|
||||
}
|
||||
|
||||
showMenu(event) {
|
||||
this.setState({ isMenuOpen: true, });
|
||||
let pressedKey = event.keyCode;
|
||||
|
||||
if (pressedKey === 9 || pressedKey == 40) {
|
||||
this.props.menuFocus(event);
|
||||
}
|
||||
}
|
||||
|
||||
hideMenu() {
|
||||
this.setState({ isMenuOpen: false, });
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { addEventListener } = window;
|
||||
addEventListener('click', this.onWindowClick.bind(this), false);
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
const { removeEventListener } = window;
|
||||
removeEventListener('click', this.onWindowClick.bind(this), false);
|
||||
}
|
||||
|
||||
onWindowClick(event) {
|
||||
const dropdownElement = findDOMNode(this);
|
||||
const shouldUpdateState = event.target !== dropdownElement &&
|
||||
!dropdownElement.contains(event.target) &&
|
||||
this.state.isMenuOpen;
|
||||
|
||||
if (shouldUpdateState) {
|
||||
this.hideMenu();
|
||||
}
|
||||
}
|
||||
|
||||
toggle(event) {
|
||||
if (this.state.isMenuOpen) {
|
||||
this.hideMenu();
|
||||
} else {
|
||||
this.showMenu(event);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const toggleMenu = this.toggle.bind(this);
|
||||
|
||||
// stick callback on trigger element
|
||||
const boundChildren = React.Children.map(this.props.children, (child) => {
|
||||
if (child.type === DropdownTrigger) {
|
||||
child = React.cloneElement(child, {
|
||||
toggleMenu: toggleMenu,
|
||||
});
|
||||
}
|
||||
|
||||
return child;
|
||||
});
|
||||
|
||||
let trigger = boundChildren[0];
|
||||
let content = boundChildren[1];
|
||||
|
||||
return (
|
||||
<div className={styles.dropdown}>
|
||||
{trigger}
|
||||
{ this.state.isMenuOpen ?
|
||||
content : null }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import styles from './styles';
|
||||
|
||||
export default class DropdownContent extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div>{this.props.children}</div>;
|
||||
}
|
||||
}
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import styles from './styles';
|
||||
|
||||
export default class DropdownContent extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div>{this.props.children}</div>;
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,26 @@
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import styles from './styles';
|
||||
|
||||
const propTypes = {
|
||||
labelBtn: PropTypes.string.isRequired,
|
||||
iconBtn: PropTypes.string.isRequired,
|
||||
toggleMenu: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default class DropdownTrigger extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { labelBtn, iconBtn, refBtn } = this.props;
|
||||
const toggle = this.props.toggleMenu.bind(this);
|
||||
return (
|
||||
<Button className={styles.settingBtn}
|
||||
role='button'
|
||||
label='setting'
|
||||
icon='more'
|
||||
ghost={true}
|
||||
circle={true}
|
||||
hideLabel={true}
|
||||
onClick={toggle}
|
||||
ref='settingBtn'/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DropdownTrigger.propTypes = propTypes;
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import styles from './styles';
|
||||
|
||||
export default class DropdownTrigger extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { labelBtn, iconBtn } = this.props;
|
||||
const toggle = this.props.toggleMenu.bind(this);
|
||||
return (
|
||||
<Button className={styles.settingBtn}
|
||||
role='button'
|
||||
label={labelBtn}
|
||||
icon={iconBtn}
|
||||
ghost={true}
|
||||
circle={true}
|
||||
hideLabel={true}
|
||||
onClick={toggle}
|
||||
onKeyDown={toggle}
|
||||
aria-haspopup={'true'}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,173 +1,184 @@
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Modal from 'react-modal';
|
||||
import Icon from '/imports/ui/components/icon/component';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import classNames from 'classnames';
|
||||
import styles from './styles';
|
||||
import SettingsModal from '../settings/SettingsModal';
|
||||
import SessionMenu from '../settings/submenus/SessionMenu';
|
||||
import Dropdown from './Dropdown';
|
||||
import DropdownContent from './DropdownContent';
|
||||
import DropdownTrigger from './DropdownTrigger';
|
||||
|
||||
export default class SettingsDropdown extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.menus = [];
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.setState({ activeMenu: -1, focusMenu: 0, });
|
||||
this.menus.push({ className: '',
|
||||
props: { title: 'Fullscreen', prependIconName: 'icon-',
|
||||
icon: 'bbb-full-screen', }, tabIndex: 1, });
|
||||
this.menus.push({ className: SettingsModal,
|
||||
props: { title: 'Settings/Options', prependIconName: 'icon-',
|
||||
icon: 'bbb-more', }, tabIndex: 2, });
|
||||
this.menus.push({ className: SessionMenu,
|
||||
props: { title: 'Leave Session', prependIconName: 'icon-',
|
||||
icon: 'bbb-logout', }, tabIndex: 3, });
|
||||
}
|
||||
|
||||
componentWillUpdate() {
|
||||
if (this.refs.dropdown.state.isMenuOpen && this.state.activeMenu > 0) {
|
||||
this.setState({ activeMenu: -1, focusMenu: 0, });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
handleListKeyDown(event) {
|
||||
const pressedKey = event.keyCode;
|
||||
let menusLength = this.menus.length - 1;
|
||||
|
||||
// tab
|
||||
if (pressedKey === 9) {
|
||||
let newIndex = 0;
|
||||
if (this.state.focusMenu >= menusLength) {
|
||||
newIndex = 0;
|
||||
} else {
|
||||
newIndex = this.state.focusMenu + 1;
|
||||
}
|
||||
|
||||
this.setState({ focusMenu: newIndex });
|
||||
return;
|
||||
}
|
||||
|
||||
// shift + tab
|
||||
if (event.shiftKey && pressedKey === 9) {
|
||||
let newIndex = 0;
|
||||
if (this.state.focusMenu <= 0) {
|
||||
newIndex = menusLength;
|
||||
} else {
|
||||
newIndex = this.state.focusMenu - 1;
|
||||
}
|
||||
|
||||
this.setState({ focusMenu: newIndex });
|
||||
return;
|
||||
}
|
||||
|
||||
// Up key
|
||||
if (pressedKey === 38) {
|
||||
if (this.state.focusMenu <= 0) { // checks if at end of menu
|
||||
this.setState({ focusMenu: menusLength },
|
||||
function () { ReactDOM.findDOMNode(this.refs[`menu${this.state.focusMenu}`]).focus();
|
||||
});
|
||||
} else {
|
||||
this.setState({ focusMenu: this.state.focusMenu - 1 },
|
||||
function () { ReactDOM.findDOMNode(this.refs[`menu${this.state.focusMenu}`]).focus(); });
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Down key
|
||||
if (pressedKey === 40) {
|
||||
if (this.state.focusMenu >= menusLength) { // checks if at end of menu
|
||||
this.setState({ focusMenu: 0 },
|
||||
function () { ReactDOM.findDOMNode(this.refs[`menu${this.state.focusMenu}`]).focus();
|
||||
});
|
||||
} else {
|
||||
this.setState({ focusMenu: this.state.focusMenu + 1 },
|
||||
function () { ReactDOM.findDOMNode(this.refs[`menu${this.state.focusMenu}`]).focus(); });
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Enter and SpaceBar
|
||||
if (pressedKey === 13 || pressedKey === 32) {
|
||||
this.clickMenu(this.state.focusMenu);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
handleFocus(index) {
|
||||
this.setState({ focusMenu: index });
|
||||
}
|
||||
|
||||
clickMenu(i) {
|
||||
|
||||
if (i < 0) {
|
||||
this.setState({ activeMenu: -1, focusMenu: 0, });
|
||||
}
|
||||
|
||||
if (i >= this.menus.length) {
|
||||
this.setState({ activeMenu: this.menus.length - 1,
|
||||
focusMenu: this.menus.length - 1, });
|
||||
} else {
|
||||
this.setState({ activeMenu: i, focusMenu: i, });
|
||||
}
|
||||
|
||||
this.refs.dropdown.hideMenu();
|
||||
}
|
||||
|
||||
createMenu() {
|
||||
const curr = this.state.activeMenu;
|
||||
if(curr === 0) {
|
||||
return console.log('full screen trigger');
|
||||
}
|
||||
|
||||
if(curr === 1) {
|
||||
return <SettingsModal />;
|
||||
}
|
||||
|
||||
if (curr == 2) {
|
||||
return <SessionMenu />;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Dropdown ref='dropdown' menuFocus={this.state.focusMenu}>
|
||||
<DropdownTrigger labelBtn='setting' iconBtn='more' />
|
||||
<DropdownContent>
|
||||
<div className={styles.triangleOnDropdown}></div>
|
||||
<div className={styles.dropdown_active_content}>
|
||||
<p id="dropdownModal" className={styles.descModal}>Settings dropdown</p>
|
||||
<ul className={styles.menuList} role="menu">
|
||||
{this.menus.map((value, index) => (
|
||||
<li key={index} role='menuitem'
|
||||
tabIndex={value.tabIndex}
|
||||
onClick={this.clickMenu.bind(this, index)}
|
||||
onKeyDown={this.handleListKeyDown.bind(this)}
|
||||
onFocus={this.handleFocus.bind(this, index)}
|
||||
ref={'menu' + index}
|
||||
className={styles.settingsMenuItem}>
|
||||
<Icon key={index} prependIconName={value.props.prependIconName}
|
||||
iconName={value.props.icon} title={value.props.title}/>
|
||||
<span className={styles.settingsMenuItemText}>{value.props.title}</span>
|
||||
{index == '0' ? <hr /> : null}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</DropdownContent>
|
||||
</Dropdown>
|
||||
<div>{this.createMenu()}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
import React, { Component, PropTyes } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Icon from '/imports/ui/components/icon/component';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import classNames from 'classnames';
|
||||
import styles from './styles';
|
||||
import SettingsModal from '../settings/SettingsModal';
|
||||
import SessionMenu from '../settings/submenus/SessionMenu';
|
||||
import Dropdown from './Dropdown';
|
||||
import DropdownContent from './DropdownContent';
|
||||
import DropdownTrigger from './DropdownTrigger';
|
||||
|
||||
export default class SettingsDropdown extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.menus = [];
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.setState({ activeMenu: -1, focusMenu: 0, });
|
||||
this.menus.push({ className: '',
|
||||
props: { title: 'Fullscreen', prependIconName: 'icon-',
|
||||
icon: 'bbb-full-screen', }, tabIndex: 1, });
|
||||
this.menus.push({ className: SettingsModal,
|
||||
props: { title: 'Settings/Options', prependIconName: 'icon-',
|
||||
icon: 'bbb-more', }, tabIndex: 2, });
|
||||
this.menus.push({ className: SessionMenu,
|
||||
props: { title: 'Leave Session', prependIconName: 'icon-',
|
||||
icon: 'bbb-logout', }, tabIndex: 3, });
|
||||
}
|
||||
|
||||
componentWillUpdate() {
|
||||
if (!this.refs.dropdown.state.isMenuOpen && this.state.activeMenu > 0) {
|
||||
this.setState({ activeMenu: -1, focusMenu: 0, });
|
||||
}
|
||||
}
|
||||
|
||||
// call focus
|
||||
setFocus() {
|
||||
ReactDOM.findDOMNode(this.refs[`menu${this.state.focusMenu}`]).focus();
|
||||
}
|
||||
|
||||
handleListKeyDown(event) {
|
||||
const pressedKey = event.keyCode;
|
||||
let menusLength = this.menus.length - 1;
|
||||
|
||||
// tab
|
||||
if (pressedKey === 9) {
|
||||
let newIndex = 0;
|
||||
if (this.state.focusMenu >= menusLength) {
|
||||
newIndex = 0;
|
||||
this.refs.dropdown.hideMenu();
|
||||
} else {
|
||||
newIndex = this.state.focusMenu;
|
||||
}
|
||||
|
||||
this.setState({ focusMenu: newIndex });
|
||||
return;
|
||||
}
|
||||
|
||||
// Down key
|
||||
if (pressedKey === 40) {
|
||||
if (this.state.focusMenu >= menusLength) { // checks if at end of menu
|
||||
this.setState({ focusMenu: 0 },
|
||||
() => { this.setFocus(); });
|
||||
} else {
|
||||
this.setState({ focusMenu: this.state.focusMenu + 1 },
|
||||
() => { this.setFocus(); });
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// shift + tab
|
||||
if (event.shiftKey && pressedKey === 9) {
|
||||
let newIndex = 0;
|
||||
if (this.state.focusMenu <= 0) {
|
||||
newIndex = menusLength;
|
||||
} else {
|
||||
newIndex = this.state.focusMenu - 1;
|
||||
}
|
||||
|
||||
this.setState({ focusMenu: newIndex });
|
||||
return;
|
||||
}
|
||||
|
||||
// Up key
|
||||
if (pressedKey === 38) {
|
||||
if (this.state.focusMenu <= 0) { // checks if at end of menu
|
||||
this.setState({ focusMenu: menusLength },
|
||||
() => { this.setFocus(); });
|
||||
} else {
|
||||
this.setState({ focusMenu: this.state.focusMenu - 1 },
|
||||
() => { this.setFocus(); });
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Enter and SpaceBar
|
||||
if (pressedKey === 13 || pressedKey === 32) {
|
||||
this.clickMenu(this.state.focusMenu);
|
||||
return;
|
||||
}
|
||||
|
||||
//ESC
|
||||
if (pressedKey == 27) {
|
||||
this.setState({ activeMenu: -1, focusMenu: 0 });
|
||||
this.refs.dropdown.hideMenu();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
handleFocus(index) {
|
||||
this.setState({ focusMenu: index },
|
||||
() => { this.setFocus(); });
|
||||
}
|
||||
|
||||
clickMenu(i) {
|
||||
this.setState({ activeMenu: i });
|
||||
this.refs.dropdown.hideMenu();
|
||||
}
|
||||
|
||||
createMenu() {
|
||||
const curr = this.state.activeMenu;
|
||||
if (curr === 0) {
|
||||
console.log(this.menus[curr].props.title);
|
||||
}
|
||||
|
||||
if (curr === 1) {
|
||||
return <SettingsModal />;
|
||||
}
|
||||
|
||||
if (curr === 2) {
|
||||
return <SessionMenu />;
|
||||
}
|
||||
}
|
||||
|
||||
openWithKey(event) {
|
||||
|
||||
// keep focus is located at the first menu
|
||||
if (event.keyCode === 9) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
this.setState({ focusMenu: 0 }, () => { this.setFocus(); });
|
||||
}
|
||||
|
||||
render() {
|
||||
const keyChange = this.openWithKey.bind(this);
|
||||
return (
|
||||
<div>
|
||||
<Dropdown ref='dropdown' menuFocus={keyChange}>
|
||||
<DropdownTrigger labelBtn='setting' iconBtn='more' />
|
||||
<DropdownContent ref='content'>
|
||||
<div className={styles.triangleOnDropdown}></div>
|
||||
<div className={styles.dropdown_active_content}>
|
||||
<p id="dropdownModal" className={styles.descModal}>Settings dropdown</p>
|
||||
<ul className={styles.menuList} role="menu">
|
||||
{this.menus.map((value, index) => (
|
||||
<li key={index} role='menuitem'
|
||||
tabIndex={value.tabIndex}
|
||||
onClick={this.clickMenu.bind(this, index)}
|
||||
onKeyDown={this.handleListKeyDown.bind(this)}
|
||||
onFocus={this.handleFocus.bind(this, index)}
|
||||
ref={'menu' + index}
|
||||
className={styles.settingsMenuItem}>
|
||||
<Icon key={index} prependIconName={value.props.prependIconName}
|
||||
iconName={value.props.icon} title={value.props.title}/>
|
||||
<span className={styles.settingsMenuItemText}>{value.props.title}</span>
|
||||
{index == '0' ? <hr /> : null}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</DropdownContent>
|
||||
</Dropdown>
|
||||
<div>{this.createMenu()}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user