Skip to content

Commit

Permalink
Merge pull request #1523 from Hypnosphi/menu-hrefs
Browse files Browse the repository at this point in the history
Add hrefs to left menu links
  • Loading branch information
igor-dv authored Aug 4, 2017
2 parents 9b0dabe + c4bfa31 commit ab45a9b
Show file tree
Hide file tree
Showing 12 changed files with 414 additions and 113 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ module.exports = {
singleQuote: true,
},
],
quotes: [warn, 'single'],
quotes: [warn, 'single', { avoidEscape: true }],
'class-methods-use-this': ignore,
'arrow-parens': [warn, 'as-needed'],
'space-before-function-paren': ignore,
Expand Down
13 changes: 2 additions & 11 deletions lib/ui/src/modules/ui/components/left_panel/stories_tree/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ import PropTypes from 'prop-types';
import React from 'react';
import deepEqual from 'deep-equal';
import treeNodeTypes from './tree_node_type';
import createTreeDecorators from './tree_decorators';
import treeDecorators from './tree_decorators';
import treeStyle from './tree_style';

const namespaceSeparator = '@';
const keyCodeEnter = 13;

function createNodeKey({ namespaces, type }) {
return [...namespaces, [type]].join(namespaceSeparator);
Expand Down Expand Up @@ -39,14 +38,12 @@ class Stories extends React.Component {
constructor(...args) {
super(...args);
this.onToggle = this.onToggle.bind(this);
this.onKeyDown = this.onKeyDown.bind(this);

const { selectedHierarchy } = this.props;

this.state = {
nodes: getSelectedNodes(selectedHierarchy),
};
this.treeDecorators = createTreeDecorators(this);
}

componentWillReceiveProps(nextProps) {
Expand Down Expand Up @@ -84,12 +81,6 @@ class Stories extends React.Component {
}));
}

onKeyDown(event, node) {
if (event.keyCode === keyCodeEnter) {
this.onToggle(node, !node.toggled);
}
}

fireOnKind(kind) {
const { onSelectStory } = this.props;
if (onSelectStory) onSelectStory(kind, null);
Expand Down Expand Up @@ -152,7 +143,7 @@ class Stories extends React.Component {
style={treeStyle}
data={data}
onToggle={this.onToggle}
decorators={this.treeDecorators}
decorators={treeDecorators}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
import { shallow, mount } from 'enzyme';
import React from 'react';
import Stories from './index';
import { setContext } from '../../../../../compose';
import { createHierarchy } from '../../../libs/hierarchy';

const leftClick = { button: 0 };

describe('manager.ui.components.left_panel.stories', () => {
beforeEach(() =>
setContext({
clientStore: {
getAll() {
return { shortcutOptions: {} };
},
subscribe() {},
},
})
);

afterEach(() => setContext(null));

const data = createHierarchy([
{ kind: 'a', stories: ['a1', 'a2'] },
{ kind: 'b', stories: ['b1', 'b2'] },
Expand Down Expand Up @@ -65,7 +81,7 @@ describe('manager.ui.components.left_panel.stories', () => {
const output = wrap.html();

expect(output).toMatch(/some/);
expect(output).not.toMatch(/name/);
expect(output).not.toMatch(/>name</);
expect(output).not.toMatch(/item1/);
expect(output).not.toMatch(/a1/);
expect(output).not.toMatch(/a2/);
Expand Down Expand Up @@ -125,8 +141,8 @@ describe('manager.ui.components.left_panel.stories', () => {
/>
);

const kind = wrap.find('a').filterWhere(el => el.text() === 'some').last();
kind.simulate('click');
const kind = wrap.find('[data-name="some"]');
kind.simulate('click', leftClick);

const { nodes } = wrap.state();

Expand Down Expand Up @@ -216,8 +232,8 @@ describe('manager.ui.components.left_panel.stories', () => {
/>
);

const kind = wrap.find('a').filterWhere(el => el.text() === 'a').last();
kind.simulate('click');
const kind = wrap.find('[data-name="a"]');
kind.simulate('click', leftClick);

expect(onSelectStory).toHaveBeenCalledWith('a', null);
});
Expand All @@ -234,7 +250,7 @@ describe('manager.ui.components.left_panel.stories', () => {
/>
);

const kind = wrap.find('a').filterWhere(el => el.text() === 'a').last();
const kind = wrap.find('[data-name="a"]').filterWhere(el => el.text() === 'a').last();
kind.simulate('click');

onSelectStory.mockClear();
Expand All @@ -255,8 +271,8 @@ describe('manager.ui.components.left_panel.stories', () => {
/>
);

const kind = wrap.find('a').filterWhere(el => el.text() === 'b1').last();
kind.simulate('click');
const kind = wrap.find('[data-name="b1"]');
kind.simulate('click', leftClick);

expect(onSelectStory).toHaveBeenCalledWith('b', 'b1');
});
Expand All @@ -273,13 +289,13 @@ describe('manager.ui.components.left_panel.stories', () => {
/>
);

wrap.find('a').filterWhere(el => el.text() === 'another').last().simulate('click');
wrap.find('a').filterWhere(el => el.text() === 'space').last().simulate('click');
wrap.find('a').filterWhere(el => el.text() === '20').last().simulate('click');
wrap.find('[data-name="another"]').simulate('click', leftClick);
wrap.find('[data-name="space"]').simulate('click', leftClick);
wrap.find('[data-name="20"]').simulate('click', leftClick);

expect(onSelectStory).toHaveBeenCalledWith('another.space.20', null);

wrap.find('a').filterWhere(el => el.text() === 'b2').last().simulate('click');
wrap.find('[data-name="b2"]').simulate('click', leftClick);

expect(onSelectStory).toHaveBeenCalledWith('another.space.20', 'b2');
});
Expand All @@ -296,23 +312,12 @@ describe('manager.ui.components.left_panel.stories', () => {
/>
);

wrap
.find('a')
.filterWhere(el => el.text() === 'another')
.last()
.simulate('keyDown', { keyCode: 13 });

wrap
.find('a')
.filterWhere(el => el.text() === 'space')
.last()
.simulate('keyDown', { keyCode: 13 });

wrap
.find('a')
.filterWhere(el => el.text() === '20')
.last()
.simulate('keyDown', { keyCode: 13 });
wrap.find('[data-name="another"]').simulate('keyDown', { keyCode: 13 });

wrap.find('[data-name="space"]').simulate('keyDown', { keyCode: 13 });

// enter press on native link triggers click event
wrap.find('[data-name="20"]').simulate('click', leftClick);

expect(onSelectStory).toHaveBeenCalledWith('another.space.20', null);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import { decorators } from 'react-treebeard';
import { IoChevronRight } from 'react-icons/lib/io';
import React from 'react';
import PropTypes from 'prop-types';
import RoutedLink from '../../../containers/routed_link';
import MenuItem from '../../menu_item';
import treeNodeTypes from './tree_node_type';

function noop() {}

function ToggleDecorator({ style }) {
const { height, width, arrow } = style;
Expand All @@ -24,85 +29,92 @@ ToggleDecorator.propTypes = {
};

function ContainerDecorator(props) {
const { node } = props;
const { node, style, onClick } = props;
const { container, ...restStyles } = style;

if (node.root) {
return null;
}

return <decorators.Container {...props} />;
let containerStyle = container.reduce((acc, styles) => ({ ...acc, ...styles }), {});
const innerContainer = <decorators.Container {...props} style={restStyles} onClick={noop} />;

if (node.type !== treeNodeTypes.STORY) {
return (
<MenuItem style={containerStyle} onClick={onClick} data-name={node.name}>
{innerContainer}
</MenuItem>
);
}

const overrideParams = {
selectedKind: node.kind,
selectedStory: node.story,
};

containerStyle = {
...style.nativeLink,
...containerStyle,
};

return (
<RoutedLink
overrideParams={overrideParams}
style={containerStyle}
onClick={onClick}
data-name={node.name}
>
{innerContainer}
</RoutedLink>
);
}

ContainerDecorator.propTypes = {
style: PropTypes.shape({
container: PropTypes.array.isRequired,
}).isRequired,
node: PropTypes.shape({
root: PropTypes.bool,
type: PropTypes.oneOf([treeNodeTypes.NAMESPACE, treeNodeTypes.COMPONENT, treeNodeTypes.STORY])
.isRequired,
name: PropTypes.string.isRequired,
kind: PropTypes.string,
story: PropTypes.string,
}).isRequired,
onClick: PropTypes.func.isRequired,
};

function createHeaderDecoratorScope(parent) {
class HeaderDecorator extends React.Component {
constructor(...args) {
super(...args);
this.onKeyDown = this.onKeyDown.bind(this);
}

onKeyDown(event) {
const { onKeyDown } = parent;
const { node } = this.props;
function HeaderDecorator(props) {
const { style, node } = props;

onKeyDown(event, node);
}
let newStyle = style;

// Prevent focusing on mousedown
onMouseDown(event) {
event.preventDefault();
}

render() {
const { style, node } = this.props;

const newStyleTitle = {
if (node.type === treeNodeTypes.STORY) {
newStyle = {
...style,
title: {
...style.title,
};

if (!node.children || !node.children.length) {
newStyleTitle.fontSize = '13px';
}

return (
<div
style={style.base}
role="menuitem"
tabIndex="0"
onKeyDown={this.onKeyDown}
onMouseDown={this.onMouseDown}
>
<a style={newStyleTitle}>
{node.name}
</a>
</div>
);
}
...style.storyTitle,
},
};
}

HeaderDecorator.propTypes = {
style: PropTypes.shape({
title: PropTypes.object.isRequired,
base: PropTypes.object.isRequired,
}).isRequired,
node: PropTypes.shape({
name: PropTypes.string.isRequired,
}).isRequired,
};

return HeaderDecorator;
return <decorators.Header {...props} style={newStyle} />;
}

export default function(parent) {
return {
...decorators,
Header: createHeaderDecoratorScope(parent),
Container: ContainerDecorator,
Toggle: ToggleDecorator,
};
}
HeaderDecorator.propTypes = {
style: PropTypes.shape({
title: PropTypes.object.isRequired,
base: PropTypes.object.isRequired,
}).isRequired,
node: PropTypes.shape({
type: PropTypes.oneOf([treeNodeTypes.NAMESPACE, treeNodeTypes.COMPONENT, treeNodeTypes.STORY]),
}).isRequired,
};

export default {
...decorators,
Header: HeaderDecorator,
Container: ContainerDecorator,
Toggle: ToggleDecorator,
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default {
base: {
listStyle: 'none',
margin: 0,
padding: 0,
padding: '5px',
fontFamily: baseFonts.fontFamily,
fontSize: '15px',
minWidth: '200px',
Expand All @@ -20,12 +20,19 @@ export default {
link: {
cursor: 'pointer',
position: 'relative',
overflow: 'hidden',
padding: '0px 5px',
display: 'block',
zIndex: 1,
},
activeLink: {
fontWeight: 'bold',
backgroundColor: '#EEE',
zIndex: 0,
},
nativeLink: {
color: 'inherit',
textDecoration: 'none',
},
toggle: {
base: {
Expand Down Expand Up @@ -67,6 +74,9 @@ export default {
lineHeight: '24px',
verticalAlign: 'middle',
},
storyTitle: {
fontSize: '13px',
},
},
subtree: {
paddingLeft: '19px',
Expand Down
Loading

0 comments on commit ab45a9b

Please sign in to comment.