Skip to content

Commit

Permalink
Merge pull request #1358 from Automattic/update/search-gridicon
Browse files Browse the repository at this point in the history
Framework: Update search component (and instances) to use gridicons
  • Loading branch information
kellychoffman committed Dec 11, 2015
2 parents 1bfa47b + 0e9155f commit 25d7ed6
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 120 deletions.
4 changes: 2 additions & 2 deletions assets/stylesheets/sections/_menus.scss
Original file line number Diff line number Diff line change
Expand Up @@ -839,10 +839,10 @@
.search-container {
position: relative;

.noticon-search {
.gridicon {
position: absolute;
left: 0;
padding: 9px 9px;
padding: 9px 8px;
}

.search-box {
Expand Down
4 changes: 0 additions & 4 deletions client/components/author-selector/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@
height: 43px;
margin-bottom: 0;

.is-open .noticon-search {
color: $gray;
}

.search__input[type="search"] {
border-radius: 5px;
font-size: 14px;
Expand Down
13 changes: 8 additions & 5 deletions client/components/search/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ var React = require( 'react' ),
* Internal dependencies
*/
var analytics = require( 'analytics' ),
Spinner = require( 'components/spinner' );
Spinner = require( 'components/spinner' ),
Gridicon = require( 'components/gridicon' );

/**
* Internal variables
Expand Down Expand Up @@ -246,15 +247,16 @@ module.exports = React.createClass( {
<Spinner />
<div
ref="openIcon"
className="noticon noticon-search"
onTouchTap={ enableOpenIcon ? this.openSearch : this.focus }
tabIndex={ enableOpenIcon ? '0' : null }
onKeyDown={ enableOpenIcon
? this._keyListener.bind( this, 'openSearch' )
: null
}
aria-controls={ 'search-component-' + this.id }
aria-label={ this.translate( 'Open Search', { context: 'button label' } ) }/>
aria-label={ this.translate( 'Open Search', { context: 'button label' } ) }>
<Gridicon icon="search" className="search-open__icon"/>
</div>
<input
type="search"
id={ 'search-component-' + this.id }
Expand All @@ -280,12 +282,13 @@ module.exports = React.createClass( {
closeButton: function() {
return (
<span
className="noticon noticon-close-alt"
onTouchTap={ this.closeSearch }
tabIndex="0"
onKeyDown={ this._keyListener.bind( this, 'closeSearch' ) }
aria-controls={ 'search-component-' + this.id }
aria-label={ this.translate( 'Close Search', { context: 'button label' } ) }/>
aria-label={ this.translate( 'Close Search', { context: 'button label' } ) }>
<Gridicon icon="cross" className="search-close__icon"/>
</span>
);
},

Expand Down
41 changes: 16 additions & 25 deletions client/components/search/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
width: 50px;
}

.noticon-search {
.search-open__icon {
position: absolute;
top: 0;
bottom: 0;
top: 50%;
margin-top: -12px;
width: 60px;
z-index: 20;
color: $blue-wordpress;
Expand All @@ -26,35 +26,26 @@
outline: dotted 1px $blue-wordpress;
}

&::before {
position: absolute;
left: 0;
right: 0;
top: 50%;
margin-top: -12px;
font-size: 24px;
text-align: center;
}

@include breakpoint( "<660px" ) {
width: 50px;
}

}

.noticon-search:hover {
color: $gray-dark;
.search-open__icon:hover {
color: darken( $gray, 30% );
}

.noticon-close-alt {
.search-close__icon {
position: absolute;
bottom: 0;
top: 0;
top: 50%;
right: 0;
margin-top: -12px;
width: 60px;
cursor: pointer;
z-index: 20;
color: $gray-dark;
color: darken( $gray, 30% );
display: none;
opacity: 0;
transition: opacity .2s ease-in;
Expand Down Expand Up @@ -96,7 +87,7 @@
// matching dropdown-selector
z-index: 170;

.noticon-search {
.search-open__icon {
right: 0;
}

Expand All @@ -112,7 +103,7 @@
top: 0;
padding: 0 50px 0 60px;
border: none;
background: #fff;
background: $white;
height: 51px;
appearance: none;
box-sizing: border-box;
Expand All @@ -139,17 +130,17 @@
margin-right: 0 !important;
width: 100%;

.noticon-search {
color: $gray-dark;
.search-open__icon {
color: darken( $gray, 30% );
left: 0;
}

.noticon-close-alt {
.search-close__icon {
display: inline-block;
}

.search__input,
.noticon-close-alt {
.search-close__icon{
opacity: 1;
}

Expand All @@ -170,7 +161,7 @@
}
}

.search.is-searching .noticon-search {
.search.is-searching .search-open__icon {
display: none;
}

Expand Down
7 changes: 7 additions & 0 deletions client/components/search/test/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@ import mockery from 'mockery';
const expect = chai.expect,
TestUtils = React.addons.TestUtils;

const EMPTY_COMPONENT = React.createClass( {
render: function() {
return <div />;
}
} );

describe( 'Search', function() {
beforeEach( function() {
mockery.registerMock( 'analytics', {} );
mockery.registerMock( 'components/gridicon', EMPTY_COMPONENT );
mockery.enable();
mockery.warnOnUnregistered( false );

Expand Down
137 changes: 78 additions & 59 deletions client/components/section-nav/test/index.jsx
Original file line number Diff line number Diff line change
@@ -1,89 +1,108 @@
var assert = require( 'chai' ).assert,
sinon = require( 'sinon' ),
React = require( 'react/addons' ),
mockery = require( 'mockery' ),
TestUtils = React.addons.TestUtils,
SectionNav;

var EMPTY_COMPONENT = React.createClass( {
render: function() {
return <div />;
}
} );

require( 'lib/react-test-env-setup' )( '<html><body><script></script><div id="container"></div></body></html>' );
require( 'react-tap-event-plugin' )();

SectionNav = require( '../' );

function createComponent( component, props, children ) {
var shallowRenderer = React.addons.TestUtils.createRenderer();
shallowRenderer.render(
React.createElement( component, props, children )
);
return shallowRenderer.getRenderOutput();
}

describe( 'Section-Nav rendering', function() {
describe( 'section-nav', function() {
before( function() {
var selectedText = 'test';
var children = ( <p>mmyellow</p> );
mockery.registerMock( 'components/gridicon', EMPTY_COMPONENT );
mockery.enable();
mockery.warnOnUnregistered( false );

this.sectionNav = createComponent( SectionNav, {
selectedText: selectedText
}, children );
SectionNav = require( '../' );
} ),

this.panelElem = this.sectionNav.props.children[ 1 ];
this.headerElem = this.sectionNav.props.children[ 0 ];
this.headerTextElem = this.headerElem.props.children;
this.text = this.headerTextElem.props.children;
} );
after( function() {
mockery.deregisterMock( 'components/gridicon' );
mockery.disable();
} ),

it( 'should render a header and a panel', function() {
assert.equal( this.headerElem.props.className, 'section-nav__mobile-header' );
assert.equal( this.panelElem.props.className, 'section-nav__panel' );
assert.equal( this.headerTextElem.props.className, 'section-nav__mobile-header-text' );
} );
describe( 'rendering', function() {
before( function() {
var selectedText = 'test';
var children = ( <p>mmyellow</p> );

it( 'should render selectedText within mobile header', function() {
assert.equal( this.text, 'test' );
} );
this.sectionNav = createComponent( SectionNav, {
selectedText: selectedText
}, children );

it( 'should render children', function( done ) {
//React.Children.only should work here but gives an error about not being the only child
React.Children.map( this.panelElem.props.children, function( obj ) {
if ( obj.type === 'p' ) {
assert.equal( obj.props.children, 'mmyellow' );
done();
}
this.panelElem = this.sectionNav.props.children[ 1 ];
this.headerElem = this.sectionNav.props.children[ 0 ];
this.headerTextElem = this.headerElem.props.children;
this.text = this.headerTextElem.props.children;
} );
} );
} );

describe( 'Section-Nav interaction', function() {
it( 'should call onMobileNavPanelOpen function passed as a prop when tapped', function( done ) {
var elem = React.createElement( SectionNav, {
selectedText: 'placeholder',
onMobileNavPanelOpen: function() {
done();
}
}, ( <p>placeholder</p> ) );
var tree = TestUtils.renderIntoDocument( elem );
assert( ! tree.state.mobileOpen );
TestUtils.Simulate.touchTap( React.findDOMNode( TestUtils.findRenderedDOMComponentWithClass( tree, 'section-nav__mobile-header' ) ) );
assert( tree.state.mobileOpen );
it( 'should render a header and a panel', function() {
assert.equal( this.headerElem.props.className, 'section-nav__mobile-header' );
assert.equal( this.panelElem.props.className, 'section-nav__panel' );
assert.equal( this.headerTextElem.props.className, 'section-nav__mobile-header-text' );
} );

it( 'should render selectedText within mobile header', function() {
assert.equal( this.text, 'test' );
} );

it( 'should render children', function( done ) {
//React.Children.only should work here but gives an error about not being the only child
React.Children.map( this.panelElem.props.children, function( obj ) {
if ( obj.type === 'p' ) {
assert.equal( obj.props.children, 'mmyellow' );
done();
}
} );
} );
} );

it( 'should call onMobileNavPanelOpen function passed as a prop twice when tapped three times', function( done ) {
var spy = sinon.spy();
var elem = React.createElement( SectionNav, {
selectedText: 'placeholder',
onMobileNavPanelOpen: spy
}, ( <p>placeholder</p> ) );
var tree = TestUtils.renderIntoDocument( elem );
describe( 'interaction', function() {
it( 'should call onMobileNavPanelOpen function passed as a prop when tapped', function( done ) {
var elem = React.createElement( SectionNav, {
selectedText: 'placeholder',
onMobileNavPanelOpen: function() {
done();
}
}, ( <p>placeholder</p> ) );
var tree = TestUtils.renderIntoDocument( elem );
assert( ! tree.state.mobileOpen );
TestUtils.Simulate.touchTap( React.findDOMNode( TestUtils.findRenderedDOMComponentWithClass( tree, 'section-nav__mobile-header' ) ) );
assert( tree.state.mobileOpen );
} );

it( 'should call onMobileNavPanelOpen function passed as a prop twice when tapped three times', function( done ) {
var spy = sinon.spy();
var elem = React.createElement( SectionNav, {
selectedText: 'placeholder',
onMobileNavPanelOpen: spy
}, ( <p>placeholder</p> ) );
var tree = TestUtils.renderIntoDocument( elem );

assert( ! tree.state.mobileOpen );
TestUtils.Simulate.touchTap( React.findDOMNode( TestUtils.findRenderedDOMComponentWithClass( tree, 'section-nav__mobile-header' ) ) );
assert( tree.state.mobileOpen );
TestUtils.Simulate.touchTap( React.findDOMNode( TestUtils.findRenderedDOMComponentWithClass( tree, 'section-nav__mobile-header' ) ) );
assert( ! tree.state.mobileOpen );
TestUtils.Simulate.touchTap( React.findDOMNode( TestUtils.findRenderedDOMComponentWithClass( tree, 'section-nav__mobile-header' ) ) );
assert( tree.state.mobileOpen );
assert( ! tree.state.mobileOpen );
TestUtils.Simulate.touchTap( React.findDOMNode( TestUtils.findRenderedDOMComponentWithClass( tree, 'section-nav__mobile-header' ) ) );
assert( tree.state.mobileOpen );
TestUtils.Simulate.touchTap( React.findDOMNode( TestUtils.findRenderedDOMComponentWithClass( tree, 'section-nav__mobile-header' ) ) );
assert( ! tree.state.mobileOpen );
TestUtils.Simulate.touchTap( React.findDOMNode( TestUtils.findRenderedDOMComponentWithClass( tree, 'section-nav__mobile-header' ) ) );
assert( tree.state.mobileOpen );

assert( spy.calledTwice );
done();
assert( spy.calledTwice );
done();
} );
} );
} );
Loading

0 comments on commit 25d7ed6

Please sign in to comment.