From e34cf1999e4e44232db4c6c051a1f9c4413c3077 Mon Sep 17 00:00:00 2001 From: igor Date: Fri, 7 Jul 2017 11:05:53 +0300 Subject: [PATCH 1/5] Add keyboard accessibility to stories tree --- .../left_panel/stories_tree/index.js | 13 ++- .../stories_tree/tree_decorators.js | 82 ++++++++++++------- 2 files changed, 62 insertions(+), 33 deletions(-) diff --git a/lib/ui/src/modules/ui/components/left_panel/stories_tree/index.js b/lib/ui/src/modules/ui/components/left_panel/stories_tree/index.js index 88b346947434..bf238de67b1e 100644 --- a/lib/ui/src/modules/ui/components/left_panel/stories_tree/index.js +++ b/lib/ui/src/modules/ui/components/left_panel/stories_tree/index.js @@ -3,10 +3,11 @@ import PropTypes from 'prop-types'; import React from 'react'; import deepEqual from 'deep-equal'; import treeNodeTypes from './tree_node_type'; -import treeDecorators from './tree_decorators'; +import createTreeDecorators from './tree_decorators'; import treeStyle from './tree_style'; const namespaceSeparator = '@'; +const keyCodeEnter = 13; function createNodeKey({ namespaces, type }) { return [...namespaces, [type]].join(namespaceSeparator); @@ -39,12 +40,14 @@ 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) { @@ -82,6 +85,12 @@ 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); @@ -144,7 +153,7 @@ class Stories extends React.Component { style={treeStyle} data={data} onToggle={this.onToggle} - decorators={treeDecorators} + decorators={this.treeDecorators} /> ); } diff --git a/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_decorators.js b/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_decorators.js index b228a7e5df7d..25d7901f9467 100644 --- a/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_decorators.js +++ b/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_decorators.js @@ -34,41 +34,61 @@ ContainerDecorator.propTypes = { }).isRequired, }; -function HeaderDecorator(props) { - const { style, node } = props; +function createHeaderDecoratorScope(parent) { + class HeaderDecorator extends React.Component { + constructor(...args) { + super(...args); + this.onKeyDown = this.onKeyDown.bind(this); + } - const newStyleTitle = { - ...style.title, - }; + onKeyDown(event) { + const { onKeyDown } = parent; + const { node } = this.props; + + onKeyDown(event, node); + } + + render() { + const { style, node } = this.props; + + const newStyleTitle = { + ...style.title, + }; - const Icon = iconsMap[node.type]; + const Icon = iconsMap[node.type]; - if (!node.children || !node.children.length) { - newStyleTitle.fontSize = '13px'; + if (!node.children || !node.children.length) { + newStyleTitle.fontSize = '13px'; + } + + return ( +
+ {Icon && } + + {node.name} + +
+ ); + } } - return ( -
- {Icon && } - - {node.name} - -
- ); -} + HeaderDecorator.propTypes = { + style: PropTypes.shape({ + title: PropTypes.object, + base: PropTypes.object, + }).isRequired, + node: PropTypes.shape({ + name: PropTypes.string, + }).isRequired, + }; -HeaderDecorator.propTypes = { - style: PropTypes.shape({ - title: PropTypes.object, - base: PropTypes.object, - }).isRequired, - node: PropTypes.shape({ - name: PropTypes.string, - }).isRequired, -}; + return HeaderDecorator; +} -export default { - ...decorators, - Header: HeaderDecorator, - Container: ContainerDecorator, -}; +export default function(parent) { + return { + ...decorators, + Header: createHeaderDecoratorScope(parent), + Container: ContainerDecorator, + }; +} From 760a75225628cda77e526b139d3d3f9668f01a89 Mon Sep 17 00:00:00 2001 From: igor Date: Fri, 7 Jul 2017 21:10:17 +0300 Subject: [PATCH 2/5] Fix long story name word-breaking --- .../ui/components/left_panel/stories_tree/tree_style.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_style.js b/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_style.js index e3698c4a1694..7c20af54ec16 100644 --- a/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_style.js +++ b/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_style.js @@ -1,5 +1,7 @@ import { baseFonts } from '../../theme'; +const toggleWidth = '24px'; + export default { tree: { base: { @@ -30,7 +32,7 @@ export default { verticalAlign: 'top', marginLeft: '-5px', height: '24px', - width: '24px', + width: toggleWidth, }, wrapper: { position: 'absolute', @@ -49,6 +51,7 @@ export default { base: { display: 'inline-block', verticalAlign: 'top', + maxWidth: `calc(100% - ${toggleWidth})`, }, connector: { width: '2px', From de858e58993120df60fc29d27d66afeb47e0505c Mon Sep 17 00:00:00 2001 From: igor Date: Sat, 8 Jul 2017 00:04:40 +0300 Subject: [PATCH 3/5] Add test for pressing enter on story --- .../left_panel/stories_tree/index.test.js | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/lib/ui/src/modules/ui/components/left_panel/stories_tree/index.test.js b/lib/ui/src/modules/ui/components/left_panel/stories_tree/index.test.js index 14aef3420471..ffcca452097c 100644 --- a/lib/ui/src/modules/ui/components/left_panel/stories_tree/index.test.js +++ b/lib/ui/src/modules/ui/components/left_panel/stories_tree/index.test.js @@ -313,5 +313,46 @@ describe('manager.ui.components.left_panel.stories', () => { expect(onSelectStory).toHaveBeenCalledWith('another.space.20', 'b2'); }); + + test('should call the onSelectStory prop when a story is selected with enter key', () => { + const data = createHierarchy( + [ + { kind: 'some.name.item1', stories: ['a1', 'a2'] }, + { kind: 'another.space.20', stories: ['b1', 'b2'] }, + ], + '\\.' + ); + + const onSelectStory = jest.fn(); + const wrap = mount( + + ); + + 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 }); + + expect(onSelectStory).toHaveBeenCalledWith('another.space.20', null); + }); }); }); From 64814491811836c5b7efb803f4e0ed6ef5bae2e7 Mon Sep 17 00:00:00 2001 From: igor Date: Tue, 11 Jul 2017 10:04:09 +0300 Subject: [PATCH 4/5] Fix the left panel width when narrowing --- lib/ui/src/modules/ui/components/layout/index.js | 2 +- lib/ui/src/modules/ui/components/left_panel/index.js | 2 +- .../modules/ui/components/left_panel/stories_tree/tree_style.js | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ui/src/modules/ui/components/layout/index.js b/lib/ui/src/modules/ui/components/layout/index.js index 7b07f8896764..62d7270a7666 100755 --- a/lib/ui/src/modules/ui/components/layout/index.js +++ b/lib/ui/src/modules/ui/components/layout/index.js @@ -204,7 +204,7 @@ class Layout extends React.Component { showLeftPanel, () =>
-
{leftPanel()}
+
{leftPanel()}
, () => diff --git a/lib/ui/src/modules/ui/components/left_panel/index.js b/lib/ui/src/modules/ui/components/left_panel/index.js index 1ac73afd74f3..4e23362ad5ba 100755 --- a/lib/ui/src/modules/ui/components/left_panel/index.js +++ b/lib/ui/src/modules/ui/components/left_panel/index.js @@ -8,7 +8,7 @@ import TextFilter from './text_filter'; const scrollStyle = { height: 'calc(100vh - 105px)', marginTop: 10, - overflowY: 'auto', + overflow: 'auto', }; const mainStyle = { diff --git a/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_style.js b/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_style.js index 7c20af54ec16..0cc5f691a85e 100644 --- a/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_style.js +++ b/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_style.js @@ -10,6 +10,7 @@ export default { padding: 0, fontFamily: baseFonts.fontFamily, fontSize: '15px', + minWidth: '200px', }, node: { base: { From cabfee0c240a0ebb17ea7435d184021ea11353dc Mon Sep 17 00:00:00 2001 From: igor Date: Thu, 13 Jul 2017 19:46:56 +0300 Subject: [PATCH 5/5] Mark the nested prop types with isRequired --- .../components/left_panel/stories_tree/tree_decorators.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_decorators.js b/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_decorators.js index 25d7901f9467..32f911d00483 100644 --- a/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_decorators.js +++ b/lib/ui/src/modules/ui/components/left_panel/stories_tree/tree_decorators.js @@ -74,11 +74,11 @@ function createHeaderDecoratorScope(parent) { HeaderDecorator.propTypes = { style: PropTypes.shape({ - title: PropTypes.object, - base: PropTypes.object, + title: PropTypes.object.isRequired, + base: PropTypes.object.isRequired, }).isRequired, node: PropTypes.shape({ - name: PropTypes.string, + name: PropTypes.string.isRequired, }).isRequired, };