Skip to content

Commit

Permalink
Merge c138a4c into dd944ec
Browse files Browse the repository at this point in the history
  • Loading branch information
aljesusg committed Feb 13, 2018
2 parents dd944ec + c138a4c commit b7b040d
Show file tree
Hide file tree
Showing 9 changed files with 729 additions and 0 deletions.
80 changes: 80 additions & 0 deletions src/components/InfoTip/InfoTip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Dropdown } from '../Dropdown';

class InfoTip extends React.Component {
constructor(props) {
super(props);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleBackFocus = this.handleBackFocus.bind(this);
this.state = { open: false, footerFocused: false };
}

handleEnterKeyDown(event) {
this.setState({ open: !this.state.open });
event.preventDefault();
}

handleTabKeyDown(event) {
if (this.state.footerFocused) {
this.setState({ open: false, footerFocused: false });
} else {
this.setState({ footerFocused: true });
}
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
}

handleKeyDown(event) {
console.log(event.keyCode);
if (event.shiftKey && event.keyCode) {
return this.handleBackFocus();
}
switch (event.key) {
case 'Enter':
return this.handleEnterKeyDown(event);
case 'Tab':
return this.handleTabKeyDown(event);
case 'Escape':
return this.setState({ open: false });
default:
}
}

handleBackFocus() {
if (this.state.open) {
this.setState({ open: false });
}
}

handleClick(event) {
event.preventDefault();
this.setState({ open: !this.state.open });
}

render() {
const { children, onToggle, ...props } = this.props;

return (
<Dropdown
componentClass="li"
onClick={this.handleClick}
onKeyDown={this.handleKeyDown}
onToggle={this.handleKeyDown}
open={this.state.open}
{...props}
>
{children}
</Dropdown>
);
}
}

InfoTip.propTypes = {
...Dropdown.propTypes,
children: PropTypes.node.isRequired,
id: PropTypes.string.isRequired
};

export default InfoTip;
67 changes: 67 additions & 0 deletions src/components/InfoTip/InfoTip.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import { defaultTemplate } from '../../../storybook/decorators/storyTemplates';
import { DOCUMENTATION_URL } from '../../../storybook/constants';
import { ListGroup, ListGroupItem } from '../ListGroup';

import { InfoTip } from './index';

const stories = storiesOf('InfoTip', module);

stories.addDecorator(
defaultTemplate({
title: 'InfoTip',
documentationLink: DOCUMENTATION_URL.PATTERNFLY_ORG_WIDGETS + '#info-tip'
})
);

stories.addWithInfo('InfoTip', '', () => (
<nav className="navbar navbar-default navbar-pf" role="navigation">
<div className="navbar-header">
<button
type="button"
className="navbar-toggle"
data-toggle="collapse"
data-target=".navbar-collapse-1"
>
<span className="sr-only">Toggle navigation</span>
<span className="icon-bar" />
<span className="icon-bar" />
<span className="icon-bar" />
</button>
<a className="navbar-brand" href="/">
<img
src="http://www.patternfly.org/assets/img/brand.svg"
alt="PatternFly Enterprise Application"
/>
</a>
</div>
<div className="collapse navbar-collapse navbar-collapse-1">
<ul className="nav navbar-nav navbar-utility">
<InfoTip id="infotip-widget">
<InfoTip.Toggle>Messages: 2</InfoTip.Toggle>
<InfoTip.Menu>
<ListGroup>
<ListGroupItem>
<InfoTip.MenuItemIcon type="pf" name="info" /> Added Datasources
TestDS
</ListGroupItem>
<ListGroupItem>
<InfoTip.MenuItemIcon type="pf" name="info" /> Modified
Datasources ExampleDS
</ListGroupItem>
</ListGroup>
<InfoTip.MenuFooter>
<a href="#">Clear Messages</a>
</InfoTip.MenuFooter>
</InfoTip.Menu>
</InfoTip>
</ul>
<ul className="nav navbar-nav navbar-primary">
<li>
<a href="#">First Link</a>
</li>
</ul>
</div>
</nav>
));
217 changes: 217 additions & 0 deletions src/components/InfoTip/InfoTip.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/* eslint-env jest */

import React from 'react';
import renderer from 'react-test-renderer';
import { InfoTip } from './index';
import { ListGroup, ListGroupItem } from '../ListGroup';

test('InfoTip renders properly with item children', () => {
const component = renderer.create(
<InfoTip id="infotip-widget">
<InfoTip.Toggle>Messages: 2</InfoTip.Toggle>
<InfoTip.Menu>
<ListGroup>
<ListGroupItem>
<InfoTip.MenuItemIcon type="pf" name="info" /> Added Datasources
TestDS
</ListGroupItem>
<ListGroupItem>
<InfoTip.MenuItemIcon type="pf" name="info" /> Modified Datasources
ExampleDS
</ListGroupItem>
</ListGroup>
<InfoTip.MenuFooter>
<a href="#">Clear Messages</a>
</InfoTip.MenuFooter>
</InfoTip.Menu>
</InfoTip>
);

const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

test('InfoTip renders properly with a default MenuItemIcon', () => {
const component = renderer.create(
<InfoTip id="infotip-widget">
<InfoTip.Toggle>Messages: 2</InfoTip.Toggle>
<InfoTip.Menu>
<ListGroup>
<ListGroupItem>
<InfoTip.MenuItemIcon /> Added Datasources TestDS
</ListGroupItem>
<ListGroupItem>
<InfoTip.MenuItemIcon /> Modified Datasources ExampleDS
</ListGroupItem>
</ListGroup>
<InfoTip.MenuFooter>
<a href="#">Clear Messages</a>
</InfoTip.MenuFooter>
</InfoTip.Menu>
</InfoTip>
);

const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

test('InfoTip renders properly with another MenuItemIcon', () => {
const component = renderer.create(
<InfoTip id="infotip-widget">
<InfoTip.Toggle bsRole="toggle">Messages: 2</InfoTip.Toggle>
<InfoTip.Menu bsRole="menu">
<ListGroup>
<ListGroupItem>
<InfoTip.MenuItemIcon type="pf" name="cube" /> Added Datasources
TestDS
</ListGroupItem>
<ListGroupItem>
<InfoTip.MenuItemIcon type="pf" name="check" /> Modified Datasources
ExampleDS
</ListGroupItem>
</ListGroup>
<InfoTip.MenuFooter>
<a href="#">Clear Messages</a>
</InfoTip.MenuFooter>
</InfoTip.Menu>
</InfoTip>
);

const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

const component = renderer.create(
<InfoTip id="infotip-widget">
<InfoTip.Toggle>Messages: 2</InfoTip.Toggle>
<InfoTip.Menu>
<ListGroup>
<ListGroupItem>
<InfoTip.MenuItemIcon type="pf" name="info" /> Added Datasources
TestDS
</ListGroupItem>
<ListGroupItem>
<InfoTip.MenuItemIcon type="pf" name="info" /> Modified Datasources
ExampleDS
</ListGroupItem>
</ListGroup>
<InfoTip.MenuFooter>
<a href="#">Clear Messages</a>
</InfoTip.MenuFooter>
</InfoTip.Menu>
</InfoTip>
);

test('InfoTip is a instance', () => {
var instance = component.getInstance();
expect(instance).toBeTruthy();
});

test('InfoTip handleEnterKeyDown', () => {
var instance = component.getInstance();
var event = {
preventDefault() {},
key: 'Enter',
keyCode: 13,
which: 13
};
expect(instance.state.wasEnabled).toBeFalsy();
expect(instance.state.open).toBeFalsy();
instance.handleEnterKeyDown(event);
expect(instance.state.open).toBeTruthy();
instance.handleEnterKeyDown(event);
expect(instance.state.open).toBeFalsy();
});

test('InfoTip handleTabKeyDown', () => {
var instance = component.getInstance();
var event = {
stopPropagation() {},
nativeEvent: {
stopImmediatePropagation() {}
},
key: 'Tab',
keyCode: 9,
which: 9
};
expect(instance.state.footerFocused).toBeFalsy();
// Should focus the Footer
instance.handleTabKeyDown(event);
expect(instance.state.footerFocused).toBeTruthy();
instance.state.open = true;
// Should close the menu
instance.handleTabKeyDown(event);
expect(instance.state.footerFocused).toBeFalsy();
expect(instance.state.open).toBeFalsy();
});

test('InfoTip handleClick', () => {
var instance = component.getInstance();
var event = {
preventDefault() {}
};
instance.state.open = false;

// Should open the menu
instance.handleClick(event);
expect(instance.state.open).toBeTruthy();

// Should close the menu
instance.handleClick(event);
expect(instance.state.open).toBeFalsy();
});

test('InfoTip handleBackFocus', () => {
var instance = component.getInstance();
instance.state.open = true;

// Should close the menu
instance.handleBackFocus();
expect(instance.state.open).toBeFalsy();

// Should do nothing if the menus is not open
instance.handleBackFocus();
expect(instance.state.open).toBeFalsy();
});

test('InfoTip handleKeyDown', () => {
var instance = component.getInstance();
var eventEnterKey = {
preventDefault() {},
key: 'Enter',
keyCode: 13,
which: 13
};
instance.state.open = true;
instance.handleKeyDown(eventEnterKey);
expect(instance.state.open).toBeFalsy();

var eventTabKey = {
stopPropagation() {},
nativeEvent: {
stopImmediatePropagation() {}
},
key: 'Tab',
keyCode: 9,
which: 9
};
instance.state.footerFocused = false;
instance.handleKeyDown(eventTabKey);
expect(instance.state.footerFocused).toBeTruthy();
instance.handleKeyDown(eventTabKey);
expect(instance.state.open).toBeFalsy();
expect(instance.state.footerFocused).toBeFalsy();

var eventEscKey = {
stopPropagation() {},
nativeEvent: {
stopImmediatePropagation() {}
},
key: 'Escape',
keyCode: 27,
which: 27
};
instance.state.open = true;
instance.handleKeyDown(eventEscKey);
expect(instance.state.open).toBeFalsy();
});
Loading

0 comments on commit b7b040d

Please sign in to comment.