Skip to content

a few more tweaks to the lookup #47

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 9 commits into from
Nov 2, 2015
3 changes: 2 additions & 1 deletion components/SLDSLookup/Menu/Item/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class Item extends React.Component {
role="option"
onClick={this.handleClick.bind(this)}
onMouseDown={this.handleMouseDown.bind(this)}>
<Icon name={this.props.type} />
<Icon name={this.props.type} category={this.props.iconCategory}/>
{ this.boldSearchText(this.props.children.label) }
</a>
</li>
Expand All @@ -80,6 +80,7 @@ Item.propTypes = {
id: React.PropTypes.string,
href: React.PropTypes.string,
type: React.PropTypes.string,
iconCategory: React.PropTypes.string,
searchTerm: React.PropTypes.string,
index: React.PropTypes.number,
isActive: React.PropTypes.bool,
Expand Down
65 changes: 42 additions & 23 deletions components/SLDSLookup/Menu/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ class Menu extends React.Component {

//Set filtered list length in parent to determine active indexes for aria-activedescendent
componentDidUpdate(prevProps, prevState){
let list = React.findDOMNode(this.refs.list).children.length;
// make an array of the children of the list
// but only count the actual items (ignore errors/messages)
let list = [].slice.call(React.findDOMNode(this.refs.list).children)
.filter((child) => child.className.indexOf("slds-lookup__item") > -1).length;
this.props.getListLength(list);
}

Expand All @@ -28,8 +31,8 @@ class Menu extends React.Component {
}

//Scroll menu up/down when using mouse keys
handleItemFocus (itemIndex, itemHeight) {
if(this.refs.list){
handleItemFocus(itemIndex, itemHeight){
if (this.refs.list) {
React.findDOMNode(this.refs.list).scrollTop = itemIndex * itemHeight;
}
}
Expand All @@ -39,10 +42,10 @@ class Menu extends React.Component {
}

renderFooter(){
if(this.props.footer){
if (this.props.footer) {
let footerActive = false;
let isActiveClass = null;
if(this.props.focusIndex === this.props.listLength+1){
if (this.props.focusIndex === this.props.listLength+1) {
footerActive = true;
isActiveClass = 'slds-theme--shade';
}else{
Expand All @@ -53,15 +56,14 @@ class Menu extends React.Component {
return <div className={isActiveClass}>{this.props.footer}</div>;
}
}
renderMessages(){
return this.props.messages.map((message) => {
return <li className="slds-lookup__message" aria-live="polite">{message}</li>;
});
}

renderErrors(){
return this.props.errors.map((error) => {
return <li className="slds-lookup__error" aria-live="polite">{error}</li>;
return (
<li className="slds-lookup__error" aria-live="polite">
<span>{error}</span>
</li>
);
});
}

Expand All @@ -70,7 +72,7 @@ class Menu extends React.Component {
//isActive means it is aria-activedescendant
const id = c.id;
let isActive = false;
if(this.props.header){
if (this.props.header) {
isActive = this.props.focusIndex === i + 1 ? true : false;
}else{
isActive = this.props.focusIndex === i ? true : false;
Expand All @@ -79,6 +81,7 @@ class Menu extends React.Component {
key={id}
id={id}
type={this.props.type}
iconCategory={this.props.iconCategory}
searchTerm={this.props.searchTerm}
index={i}
isActive={isActive}
Expand All @@ -93,18 +96,31 @@ class Menu extends React.Component {
});
}

renderContent() {
if (this.props.errors.length)
return this.renderErrors
renderMessages(){
return this.props.messages.map((message) => {
return (
<li className="slds-lookup__message" aria-live="polite">
<span>{message}</span>
</li>
);
});
}

renderContent(){
if (this.props.errors.length > 0)
return this.renderErrors()
else if (this.props.items.length === 0)
return <li className="slds-lookup__message" aria-live="polite">{this.props.emptyMessage}</li>;

elements = this.renderItems()
if (this.props.messages.length){
return elements.concat(this.renderMessages());
return (
<li className="slds-lookup__message" aria-live="polite">
<span>{this.props.emptyMessage}</span>
</li>
);

let elements = this.renderItems();
if (this.props.messages.length > 0) {
elements.concat(this.renderMessages());
}
return elements;

}

render(){
Expand All @@ -116,19 +132,19 @@ class Menu extends React.Component {
</ul>
{this.renderFooter()}
</section>
)
);
}
}

Menu.propTypes = {
searchTerm: React.PropTypes.string,
label: React.PropTypes.string,
type: React.PropTypes.string,
iconCategory: React.PropTypes.string,
focusIndex: React.PropTypes.number,
listLength: React.PropTypes.number,
items: React.PropTypes.array,
emptyMessage: React.PropTypes.string,
messages: React.PropTypes.arrayOf(React.PropTypes.string),
errors: React.PropTypes.arrayOf(React.PropTypes.string),
filterWith: React.PropTypes.func,
getListLength: React.PropTypes.func,
Expand All @@ -137,6 +153,9 @@ Menu.propTypes = {
};

Menu.defaultProps = {
emptyMessage: "No matches found.",
messages: [],
errors: [],
};

module.exports = Menu;
61 changes: 35 additions & 26 deletions components/SLDSLookup/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ class SLDSLookup extends React.Component {
focusIndex:null,
selectedIndex: null,
listLength:this.props.items.length,
items:[],
errors:[],
messages:[],
items:[]
};
}

Expand All @@ -63,13 +61,13 @@ class SLDSLookup extends React.Component {
// 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.
// Adding/subtracting 1 from focusIndex to account for fixed action items (searchRecords and addNewItem buttons)
increaseIndex(){
let items = this.state.listLength;
this.setState({ focusIndex: this.state.focusIndex <= items ? this.state.focusIndex + 1 : 0 })
let numFocusable = this.getNumFocusableItems();
this.setState({ focusIndex: this.state.focusIndex < numFocusable - 1 ? this.state.focusIndex + 1 : 0 })
}

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

setFocus(id){
Expand All @@ -80,16 +78,33 @@ class SLDSLookup extends React.Component {
if(qty !== this.state.listLength) this.setState({listLength:qty});
}

getNumFocusableItems(){
let offset = 0
if (this.refs.footer)
offset += 1
if (this.refs.header)
offset += 1
return this.state.listLength + offset
}

//=================================================
// Select menu item (onClick or on key enter/space)
selectItem(itemId){
const index = itemId.replace('item-', '');
this.setState({
selectedIndex: index,
searchTerm: null
});
const data = this.state.items[index].data;
if(this.props.onItemSelect) this.props.onItemSelect(data);
if (itemId) {
const index = itemId.replace('item-', '');
this.selectItemByIndex(index);
}
}

selectItemByIndex(index){
if (index >= 0 && index < this.state.items.length) {
this.setState({
selectedIndex: index,
searchTerm: null
});
const data = this.state.items[index].data;
if(this.props.onItemSelect) this.props.onItemSelect(data);
}
}

handleDeleteSelected() {
Expand Down Expand Up @@ -149,20 +164,19 @@ class SLDSLookup extends React.Component {
//If user hits up key, advance aria activedescendant to previous item
else if(event.keyCode === KEYS.UP){
EventUtil.trapImmediate(event);
this.state.focusIndex === null ? this.setState({focusIndex: this.state.listLength + 1}) : this.decreaseIndex();
let numFocusable = this.getNumFocusableItems()
this.state.focusIndex === null ? this.setState({focusIndex: numFocusable - 1}) : this.decreaseIndex();
}
//If user hits enter/space key, select current activedescendant item
else if((event.keyCode === KEYS.ENTER || event.keyCode === KEYS.SPACE) && this.state.focusIndex !== null){
EventUtil.trapImmediate(event);
//If the focus is on the first fixed Action Item in Menu, click it
if(this.refs.header && this.state.focusIndex === 0){
// document.getElementById('menuContainer').firstChild.children[0].click();
React.findDOMNode(this.refs.header).click();
}
//If the focus is on the last fixed Action Item in Menu, click it
else if(this.refs.footer && this.state.focusIndex === (this.state.listLength + 1)){
React.findDOMNode(this.refs.footer).click();
// document.getElementById('menuContainer').lastChild.children[0].click();
}
//If not, then select menu item
else{
Expand Down Expand Up @@ -223,12 +237,13 @@ class SLDSLookup extends React.Component {
searchTerm={this.state.searchTerm}
label={this.props.label}
type={this.props.type}
iconCategory={this.props.iconCategory}
focusIndex={this.state.focusIndex}
listLength={this.state.listLength}
items={this.state.items}
emptyMessage={this.props.emptyMessage}
messages={this.state.messages}
errors={this.state.errors}
messages={this.props.messages}
errors={this.props.errors}
filterWith={this.props.filterWith}
getListLength={this.getListLength.bind(this)}
setFocus={this.setFocus.bind(this)}
Expand Down Expand Up @@ -298,12 +313,6 @@ class SLDSLookup extends React.Component {
if(newProps.items){
this.modifyItems(newProps.items);
}
if (newProps.message){
this.setState({message: newProps.message});
}
if (newProps.error){
this.setState({errors: newProps.error});
}
}

render(){
Expand Down Expand Up @@ -349,12 +358,12 @@ class SLDSLookup extends React.Component {

SLDSLookup.propTypes = {
items: React.PropTypes.array,
errors: React.PropTypes.arrayOf(React.PropTypes.string),
emptyMessage: React.PropTypes.string,
messages: React.PropTypes.arrayOf(React.PropTypes.string),
errors: React.PropTypes.arrayOf(React.PropTypes.string),
label: React.PropTypes.string,
type: React.PropTypes.string,
iconCategory: React.PropTypes.string,
filterWith: React.PropTypes.func,
onItemSelect: React.PropTypes.func,
onItemUnselect: React.PropTypes.func,
Expand Down