Skip to content

Lookups refactor #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 5, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions components/SLDSLookup/Menu/Item/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class Item extends React.Component {
}

componentWillReceiveProps(nextProps){
if(nextProps.isActive !== this.props.isActive){
this.props.setActiveDescendant(nextProps.id);
if(nextProps.isActive !== this.props.isActive && (nextProps.isActive === true)){
this.props.setFocus(this.props.id);
}
}

Expand All @@ -42,17 +42,13 @@ class Item extends React.Component {

render(){
let className = 'slds-lookup__item';

//TODO: make isActive styles into a class??
let id = this.props.id;
let styles = {};
if(this.props.isActive) className += ' slds-theme--shade';

return (
//IMPORTANT: id is used to set lookup's input's aria-activedescendant
//IMPORTANT: anchor id is used to set lookup's input's aria-activedescendant
<li
className={className}
style={styles}
role="presentaion">
<a
href={this.props.href}
Expand All @@ -68,7 +64,17 @@ class Item extends React.Component {
</li>
)
}

}

Item.propTypes = {
id: React.PropTypes.string,
setFocus: React.PropTypes.func,
isActive: React.PropTypes.bool,
onSelect: React.PropTypes.func,
searchTerm: React.PropTypes.string,
};

Item.defaultProps = {
};

module.exports = Item;
25 changes: 23 additions & 2 deletions components/SLDSLookup/Menu/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,20 @@ class Menu extends React.Component {
this.state = {};
}

componentDidUpdate(){
let list = React.findDOMNode(this.refs.list).children.length;
this.props.getListLength(list);
}

filter(item){
return this.props.filterWith(this.props.searchTerm, item);
}

renderItems(){
return this.props.items.filter(this.filter, this).map((c, i) => {
//isActive means it is aria-activedescendant
const isActive = this.props.activeIndex === i ? true : false;
return <Item key={c.id} id={c.id} setActiveDescendant={this.props.setActiveDescendant} isActive={isActive} onSelect={this.props.onSelect} searchTerm={this.props.searchTerm}>{c}</Item>
const isActive = this.props.focusIndex === i ? true : false;
return <Item key={c.id} id={c.id} setFocus={this.props.setFocus} isActive={isActive} onSelect={this.props.onSelect} searchTerm={this.props.searchTerm}>{c}</Item>
});
}

Expand All @@ -42,4 +47,20 @@ class Menu extends React.Component {
)
}
}

Menu.propTypes = {
searchTerm: React.PropTypes.string,
filterWith: React.PropTypes.func,
onSelect: React.PropTypes.func,
label: React.PropTypes.string,
items: React.PropTypes.array,
setFocus: React.PropTypes.func,
getListLength: React.PropTypes.func,
listLength: React.PropTypes.number,
focusIndex: React.PropTypes.number,
};

Menu.defaultProps = {
};

module.exports = Menu;
70 changes: 42 additions & 28 deletions components/SLDSLookup/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,41 +22,46 @@ const defaultFilter = (term, item) => {
class SLDSLookup extends React.Component {
constructor(props) {
super(props);
this.props.items.map((item, index) => {
return item.id = 'item-' + index;
})

//Dynamically assign ids to list items to reference for focusing and selecting items
this.props.items.map((item, index) => { return item.id = 'item-' + index; })

this.state = {
searchTerm: '',
isOpen:false,
activeItem:null,
currentFocus:null,
focusIndex:null,
selectedIndex: null,
activeIndex:null,
listLength:this.props.items.length
};
}

//=================================================
// Set Active Descendant (on key down/up, set currently focused/hovered item in list)
// Using down/up keys, set Focus on list item and assign it to aria-activedescendant attribute in input.
// Need to keep track of filtered list length to be able to increment/decrement the focus index so it's contained to the number of available list items.
increaseIndex(){
this.setState({
activeIndex: this.state.activeIndex <= this.props.items.length ? this.state.activeIndex + 1 : 0
})
let items = this.state.listLength - 1;
this.setState({ focusIndex: this.state.focusIndex < items ? this.state.focusIndex + 1 : 0 })
}

decreaseIndex(){
this.setState({
activeIndex: this.state.activeIndex > 0 ? this.state.activeIndex - 1 : this.props.items.length
})
let items = this.state.listLength - 1;
this.setState({ focusIndex: this.state.focusIndex > 0 ? this.state.focusIndex - 1 : items })
}

setActiveDescendant(id){
this.setState({activeItem:id});
setFocus(id){
this.setState({currentFocus:id});
}

getListLength(qty){
if(qty !== this.state.listLength){
this.setState({listLength:qty});
}
}

//=================================================
// Select menu item (onClick or on key enter/space)
selectItem(itemId){
//console.log('selectItem fired');
let index = itemId.replace('item-', '');
this.setState({
selectedIndex: index,
Expand All @@ -76,7 +81,7 @@ class SLDSLookup extends React.Component {
handleClose() {
this.setState({
isOpen:false,
activeIndex:null
focusIndex:null
})
}

Expand All @@ -103,25 +108,25 @@ class SLDSLookup extends React.Component {
event.keyCode === KEYS.ESCAPE ? this.handleClose() : this.handleClick();

//If user hits tab key, move aria activedescendant to first menu item
if(event.keyCode === KEYS.TAB && this.state.activeIndex === null){
this.setState({activeIndex: 0});
if(event.keyCode === KEYS.TAB && this.state.focusIndex === null){
this.setState({focusIndex: 0});
EventUtil.trapImmediate(event);
}
//If user hits down key, advance aria activedescendant to next item
else if(event.keyCode === KEYS.DOWN && this.state.activeIndex !== null){
else if(event.keyCode === KEYS.DOWN && this.state.focusIndex !== null){
EventUtil.trapImmediate(event);
this.increaseIndex();
}
//If user hits up key, advance aria activedescendant to previous item
else if(event.keyCode === KEYS.UP && this.state.activeIndex !== null){
else if(event.keyCode === KEYS.UP && this.state.focusIndex !== null){
EventUtil.trapImmediate(event);
this.decreaseIndex();
}

//If user hits enter/space key, select current activedescendant item
else if((event.keyCode === KEYS.ENTER || event.keyCode === KEYS.SPACE) && this.state.activeIndex !== null){
else if((event.keyCode === KEYS.ENTER || event.keyCode === KEYS.SPACE) && this.state.focusIndex !== null){
EventUtil.trapImmediate(event);
this.selectItem(this.state.activeItem);
this.selectItem(this.state.currentFocus);
}
}
}
Expand All @@ -136,8 +141,10 @@ class SLDSLookup extends React.Component {
onSelect={this.selectItem.bind(this)}
label={this.props.label}
items={this.props.items}
setActiveDescendant={this.setActiveDescendant.bind(this)}
activeIndex={this.state.activeIndex}/>;
setFocus={this.setFocus.bind(this)}
getListLength={this.getListLength.bind(this)}
listLength={this.state.listLength}
focusIndex={this.state.focusIndex}/>;
}else{
return null;
}
Expand All @@ -162,10 +169,10 @@ class SLDSLookup extends React.Component {

render(){
let inputClasses = this.state.selectedIndex === null ? 'slds-input':'slds-input slds-hide';
let compClasses = this.state.selectedIndex === null ? "slds-lookup ignore-react-onclickoutside":"slds-lookup ignore-react-onclickoutside slds-has-selection";
let componentClasses = this.state.selectedIndex === null ? "slds-lookup ignore-react-onclickoutside":"slds-lookup ignore-react-onclickoutside slds-has-selection";

return (
<div className={compClasses} data-select="single" data-scope="single" data-typeahead="true">
<div className={componentClasses} data-select="single" data-scope="single" data-typeahead="true">
<section className="slds-form-element">
<label className="slds-form-element__label" forHTML="lookup">{this.props.label}</label>

Expand All @@ -179,7 +186,7 @@ class SLDSLookup extends React.Component {
aria-label="lookup"
aria-haspopup="true"
aria-autocomplete="list"
aria-activedescendant={this.state.activeItem ? this.state.activeItem:""}
aria-activedescendant={this.state.currentFocus ? this.state.currentFocus:""}
aria-expanded={this.state.isOpen}
role="combobox"
onChange={this.handleChange.bind(this)}
Expand All @@ -197,11 +204,18 @@ class SLDSLookup extends React.Component {
}
}


SLDSLookup.propTypes = {
items: React.PropTypes.array,
label: React.PropTypes.string,
};

SLDSLookup.defaultProps = {
filterWith: defaultFilter,
onItemSelect: function(item){
//console.log('onItemSelect should be defined');
//console.log('onItemSelect should be defined');
}
};

module.exports = SLDSLookup;

12 changes: 6 additions & 6 deletions components/SLDSModal/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ module.exports = React.createClass( {

componentDidMount () {
Modal.setAppElement(SLDSSettings.getAppElement());
console.log('!!! window.activeElement !!! ',document.activeElement);
//console.log('!!! window.activeElement !!! ',document.activeElement);
this.setState({returnFocusTo:document.activeElement})
if(!this.state.revealed){
setTimeout(()=>{
Expand Down Expand Up @@ -101,14 +101,14 @@ module.exports = React.createClass( {
},

getModal() {
return <div
className={'slds-modal' +(this.state.revealed?' slds-fade-in-open':'')}
return <div
className={'slds-modal' +(this.state.revealed?' slds-fade-in-open':'')}
style={{pointerEvents:'inherit'}}
onClick={this.closeModal}
>
<div
<div
role='dialog'
className='slds-modal__container'
className='slds-modal__container'
onClick={this.handleModalClick}
>
<div className='slds-modal__header'>
Expand Down Expand Up @@ -157,7 +157,7 @@ module.exports = React.createClass( {


if(this.state.isClosing){
console.log('CLOSING: ');
//console.log('CLOSING: ');

if(this.isMounted()){
const el = this.getDOMNode().parentNode;
Expand Down
2 changes: 1 addition & 1 deletion demo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const { Route, DefaultRoute, RouteHandler, Link } = Router;
import { SLDSSettings } from '../components/';
SLDSSettings.setAssetsPath('demo/assets/');
SLDSSettings.setAppElement('#root');
console.log('SLDSSettings.getAssetsPath: '+SLDSSettings.getAssetsPath());
//console.log('SLDSSettings.getAssetsPath: '+SLDSSettings.getAssetsPath());

import App from './App';
import HomePage from './pages/HomePage';
Expand Down