This repository has been archived by the owner on Dec 30, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 386
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Breadcrumb): add a new widget & connector (#228)
* feat(Breadcrumb): create a story * feat(Breadcrumb): retrieve items in Story * feat(Breadcrumb): modified the getProvidedProps method in the connector * feat(Breadcrumb): WIP * feat(Breadcrumb): WIP * feat(Breadcrumb): assembleBreadcrumb method * feat(Breadcrumb): improve assembleBreadcrumb method * feat(Breadcrumb): minor edits in connectBreadcrumb * feat(Breadcrumb): added render method * feat(Breadcrumb): Handled the separator prop * feat(Breadcrumb): separator prop can be a string or a React Component * feat(Breadcrumb): Added VirtualHierarchicalMenu + Refactored HierarchicalMenuLogic * feat(Breadcrumb): Make tests pass! * feat(Breadcrumb): Make component tests pass * feat(Breadcrumb): disable click on the last item * feat(Breadcrumb): added rootURL * feat(Breadcrumb): add tests for rootURL * feat(Breadcrumb): Added translation for rootURL + playground story * feat(Breadcrumb): Added translation test * feat(Breadcrumb): Added a story for the separator-custom element * feat(Breadcrumb): Add custom React Component test for separator * feat(Breadcrumb): Changed the translation name to "rootLabel" * feat(Breadcrumb): Minor change in PropTypes * feat(Breadcrumb): Add style * feat(Breadcrumb): Minor modification to the playground story * feat(Breadcrumb): Minor modifications to tests and style * feat(Breadcrumb): review WIP * feat(Breadcrumb): some cleanup * feat(Breadcrumb): review * feat(Breadcrumb): some fixes * feat(Breadcrumb): remove hierarchicalMenuLogic file * feat(Breadcrumb): modified the structure, putting the separator in between 2 elements * Update style.scss * feat(Breadcrumb): add snapshot * feat(Breadcrumb): minor edits to doc and story + update yarn lock * feat(Breadcrumb): changed div to span * feat(Breadcrumb): changed to root div * feat(Breadcrumb): update test * feat(Breadcrumb): modify documentation
- Loading branch information
1 parent
7157bd8
commit 7f8f3ae
Showing
13 changed files
with
9,117 additions
and
1,318 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
packages/react-instantsearch-theme-algolia/styles/_Breadcrumb.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
.ais-Breadcrumb__itemDisabled, | ||
.ais-Breadcrumb__itemLabel, | ||
.ais-Breadcrumb__separator, | ||
.ais-Breadcrumb__rootLabel { | ||
color: #3369e7; | ||
} | ||
|
||
.ais-Breadcrumb__itemLink { | ||
font-weight: bold; | ||
} | ||
|
||
.ais-Breadcrumb__itemDisabled, | ||
.ais-Breadcrumb__separator { | ||
font-weight: normal; | ||
} | ||
|
||
.ais-Breadcrumb__item, | ||
{ | ||
display: inline; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import PropTypes from 'prop-types'; | ||
import React, { Component } from 'react'; | ||
import Link from './Link'; | ||
import classNames from './classNames.js'; | ||
import translatable from '../core/translatable'; | ||
|
||
const cx = classNames('Breadcrumb'); | ||
|
||
const itemsPropType = PropTypes.arrayOf( | ||
PropTypes.shape({ | ||
label: PropTypes.string.isRequired, | ||
value: PropTypes.string.isRequired, | ||
}) | ||
); | ||
|
||
class Breadcrumb extends Component { | ||
static propTypes = { | ||
canRefine: PropTypes.bool.isRequired, | ||
createURL: PropTypes.func.isRequired, | ||
items: itemsPropType, | ||
refine: PropTypes.func.isRequired, | ||
rootURL: PropTypes.string, | ||
separator: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), | ||
translate: PropTypes.func.isRequired, | ||
}; | ||
|
||
static contextTypes = { | ||
canRefine: PropTypes.func, | ||
}; | ||
|
||
componentWillMount() { | ||
if (this.context.canRefine) this.context.canRefine(this.props.canRefine); | ||
} | ||
|
||
componentWillReceiveProps(props) { | ||
if (this.context.canRefine) this.context.canRefine(props.canRefine); | ||
} | ||
|
||
render() { | ||
const { canRefine, createURL, items, refine, translate } = this.props; | ||
const rootPath = canRefine | ||
? <span {...cx('item')}> | ||
<a | ||
{...cx('itemLink', 'itemLinkRoot')} | ||
onClick={() => (!this.props.rootURL ? refine() : null)} | ||
href={this.props.rootURL ? this.props.rootURL : createURL()} | ||
> | ||
<span {...cx('rootLabel')}> | ||
{translate('rootLabel')} | ||
</span> | ||
</a> | ||
<span {...cx('separator')}> | ||
{this.props.separator} | ||
</span> | ||
</span> | ||
: null; | ||
|
||
const breadcrumb = items.map((item, idx) => { | ||
const isLast = idx === items.length - 1; | ||
const separator = isLast ? '' : this.props.separator; | ||
return !isLast | ||
? <span {...cx('item')} key={idx}> | ||
<Link | ||
{...cx('itemLink')} | ||
onClick={() => refine(item.value)} | ||
href={createURL(item.value)} | ||
key={idx} | ||
> | ||
<span {...cx('itemLabel')}> | ||
{item.label} | ||
</span> | ||
</Link> | ||
<span {...cx('separator')}> | ||
{separator} | ||
</span> | ||
</span> | ||
: <span {...cx('itemLink', 'itemDisabled', 'item')} key={idx}> | ||
<span {...cx('itemLabel')}> | ||
{item.label} | ||
</span> | ||
</span>; | ||
}); | ||
|
||
return ( | ||
<div {...cx('root', !canRefine && 'noRefinement')}> | ||
{rootPath} | ||
{breadcrumb} | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
export default translatable({ | ||
rootLabel: 'Home', | ||
})(Breadcrumb); |
214 changes: 214 additions & 0 deletions
214
packages/react-instantsearch/src/components/Breadcrumb.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
import PropTypes from 'prop-types'; | ||
/* eslint-env jest, jasmine */ | ||
|
||
import React from 'react'; | ||
import renderer from 'react-test-renderer'; | ||
import { mount } from 'enzyme'; | ||
|
||
import Breadcrumb from './Breadcrumb'; | ||
|
||
describe('Breadcrumb', () => { | ||
it('outputs the default breadcrumb', () => { | ||
const tree = renderer | ||
.create( | ||
<Breadcrumb | ||
refine={() => null} | ||
createURL={() => '#'} | ||
items={[ | ||
{ | ||
value: 'white', | ||
label: 'white', | ||
}, | ||
{ | ||
value: 'white > white1', | ||
label: 'white1', | ||
}, | ||
{ | ||
value: 'white > white1 > white1.1', | ||
label: 'white1.1', | ||
}, | ||
]} | ||
canRefine={true} | ||
/> | ||
) | ||
.toJSON(); | ||
expect(tree).toMatchSnapshot(); | ||
}); | ||
|
||
it('refines its value on change', () => { | ||
const refine = jest.fn(); | ||
const wrapper = mount( | ||
<Breadcrumb | ||
refine={refine} | ||
createURL={() => '#'} | ||
items={[ | ||
{ | ||
value: 'white', | ||
label: 'white', | ||
}, | ||
{ | ||
value: 'white > white1', | ||
label: 'white1', | ||
}, | ||
{ | ||
value: 'white > white1 > white1.1', | ||
label: 'white1.1', | ||
}, | ||
]} | ||
canRefine={true} | ||
/> | ||
); | ||
|
||
const items = wrapper.find('.ais-Breadcrumb__itemLink'); | ||
expect(items.length).toBe(4); | ||
|
||
items.first().simulate('click'); | ||
expect(refine.mock.calls.length).toBe(1); | ||
expect(refine.mock.calls[0][0]).toEqual(); | ||
|
||
items.at(1).simulate('click'); | ||
expect(refine.mock.calls.length).toBe(2); | ||
expect(refine.mock.calls[1][0]).toEqual('white'); | ||
|
||
items.at(2).simulate('click'); | ||
expect(refine.mock.calls.length).toBe(3); | ||
expect(refine.mock.calls[2][0]).toEqual('white > white1'); | ||
|
||
items.at(3).simulate('click'); | ||
expect(refine.mock.calls.length).toBe(3); | ||
|
||
wrapper.unmount(); | ||
}); | ||
|
||
it('has a rootURL prop', () => { | ||
const refine = jest.fn(); | ||
const rootLink = 'www.algolia.com'; | ||
|
||
const wrapper = mount( | ||
<Breadcrumb | ||
refine={refine} | ||
createURL={() => '#'} | ||
rootURL={rootLink} | ||
items={[ | ||
{ | ||
value: 'white', | ||
label: 'white', | ||
}, | ||
{ | ||
value: 'white > white1', | ||
label: 'white1', | ||
}, | ||
{ | ||
value: 'white > white1 > white1.1', | ||
label: 'white1.1', | ||
}, | ||
]} | ||
canRefine={true} | ||
/> | ||
); | ||
|
||
const items = wrapper.find('.ais-Breadcrumb__itemLink'); | ||
expect(items.length).toBe(4); | ||
|
||
items.first().simulate('click'); | ||
expect(refine.mock.calls.length).toBe(0); | ||
expect(wrapper.find('a').first().prop('href')).toEqual('www.algolia.com'); | ||
|
||
wrapper.unmount(); | ||
}); | ||
|
||
it('has a separator prop that can be a custom component', () => { | ||
const tree = renderer | ||
.create( | ||
<Breadcrumb | ||
refine={() => null} | ||
createURL={() => '#'} | ||
separator={<span>🔍</span>} | ||
items={[ | ||
{ | ||
value: 'white', | ||
label: 'white', | ||
}, | ||
{ | ||
value: 'white > white1', | ||
label: 'white1', | ||
}, | ||
{ | ||
value: 'white > white1 > white1.1', | ||
label: 'white1.1', | ||
}, | ||
]} | ||
canRefine={true} | ||
/> | ||
) | ||
.toJSON(); | ||
expect(tree).toMatchSnapshot(); | ||
}); | ||
|
||
it('has customizable translations', () => { | ||
const tree = renderer | ||
.create( | ||
<Breadcrumb | ||
refine={() => null} | ||
createURL={() => '#'} | ||
translations={{ | ||
rootLabel: 'ROOT_LABEL', | ||
}} | ||
items={[ | ||
{ | ||
value: 'white', | ||
label: 'white', | ||
}, | ||
{ | ||
value: 'white > white1', | ||
label: 'white1', | ||
}, | ||
{ | ||
value: 'white > white1 > white1.1', | ||
label: 'white1.1', | ||
}, | ||
]} | ||
canRefine={true} | ||
/> | ||
) | ||
.toJSON(); | ||
expect(tree).toMatchSnapshot(); | ||
}); | ||
|
||
describe('Panel compatibility', () => { | ||
it('Should indicate when there is no more refinement', () => { | ||
const canRefine = jest.fn(); | ||
const wrapper = mount( | ||
<Breadcrumb | ||
refine={() => null} | ||
createURL={() => '#'} | ||
items={[ | ||
{ | ||
value: 'white', | ||
label: 'white', | ||
}, | ||
{ | ||
value: 'white > white1', | ||
label: 'white1', | ||
}, | ||
]} | ||
canRefine={true} | ||
/>, | ||
{ | ||
context: { canRefine }, | ||
childContextTypes: { canRefine: PropTypes.func }, | ||
} | ||
); | ||
|
||
expect(canRefine.mock.calls.length).toBe(1); | ||
expect(canRefine.mock.calls[0][0]).toEqual(true); | ||
expect(wrapper.find('.ais-Breadcrumb__noRefinement').length).toBe(0); | ||
|
||
wrapper.setProps({ canRefine: false }); | ||
|
||
expect(canRefine.mock.calls.length).toBe(2); | ||
expect(canRefine.mock.calls[1][0]).toEqual(false); | ||
expect(wrapper.find('.ais-Breadcrumb__noRefinement').length).toBe(1); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.