Skip to content

Commit

Permalink
feat(community-side-navigation): add accordion prop and remove id prop
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew-K-Lam authored and theetrain committed Jan 8, 2019
1 parent 74b66c4 commit 8983ae1
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 30 deletions.
39 changes: 33 additions & 6 deletions packages/SideNavigation/SideNavigation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ class SideNavigation extends Component {
constructor(props) {
super(props)
this.state = {
open: null,
open: [],
variant: 'top',
accordion: true,
}
this.adjustWidth = this.adjustWidth.bind(this)
this.removeEventListeners = this.removeEventListeners.bind(this)
}

componentDidMount() {
this.setState({ accordion: this.props.accordion })
this.checkOffset()
window.addEventListener('scroll', this.checkOffset)
window.addEventListener('click', this.checkOffset)
Expand All @@ -44,7 +46,18 @@ class SideNavigation extends Component {
}

toggleOpen = id => {
this.setState({ open: id !== this.state.open ? id : null })
if (this.checkAccordion(id, this.state.accordion)) {
const array = [...this.state.open]
const index = array.indexOf(id)
if (index !== -1) {
array.splice(index, 1)
this.setState({ open: array })
}
} else if (this.state.accordion) {
this.setState({ open: [id] })
} else {
this.setState({ open: [...this.state.open, id] })
}
}

removeEventListeners() {
Expand Down Expand Up @@ -78,9 +91,16 @@ class SideNavigation extends Component {
}
}

checkAccordion = id => {
return this.state.open.some(el => {
return el === id
})
}

render() {
const { children, verticalSpacing, ...rest } = this.props
const { open, variant } = this.state
const { children, verticalSpacing, accordion, ...rest } = this.props
const { variant } = this.state

let classes = joinClassNames(
verticalSpacing ? styles[`verticalPadding-${verticalSpacing}`] : undefined,
styles.topPosition
Expand All @@ -106,13 +126,15 @@ class SideNavigation extends Component {
className={classes}
>
<ul className={styles.spaced}>
{React.Children.map(children, child => {
{React.Children.map(children, (child, index) => {
let options = {}
const id = `TDS-SideNavigation-${index}`
if (child.type.name === 'SubMenu') {
options = {
onClick: this.toggleOpen,
isOpen: child.props.id === open,
isOpen: this.checkAccordion(id),
active: child.props.active,
id,
}
}
return <li className={styles.navLi}>{React.cloneElement(child, options)}</li>
Expand All @@ -133,10 +155,15 @@ SideNavigation.propTypes = {
* Indent content from the container's top edge by applying padding.
*/
verticalSpacing: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8]),
/**
* Identifies if only one `SideNavigation.SubMenu` should be open at a time.
*/
accordion: PropTypes.bool,
}

SideNavigation.defaultProps = {
verticalSpacing: undefined,
accordion: true,
}

SideNavigation.Link = Link
Expand Down
6 changes: 3 additions & 3 deletions packages/SideNavigation/SideNavigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ Displays multiple links on a page for easier navigation.
<FlexGrid limitWidth={false} gutter={false}>
<FlexGrid.Row>
<FlexGrid.Col xs={5}>
<SideNavigation verticalSpacing={3}>
<SideNavigation accordion={true} verticalSpacing={3}>
<SideNavigation.Link href="#">Top of the page</SideNavigation.Link>
<SideNavigation.SubMenu label="Overview" active id="introduction">
<SideNavigation.SubMenu label="Overview" active>
<SideNavigation.Link href="#introduction">Introduction</SideNavigation.Link>
</SideNavigation.SubMenu>
<SideNavigation.SubMenu label="Reference Architecture" id="reference-arch">
<SideNavigation.SubMenu label="Reference Architecture">
<SideNavigation.Link href="#reference">Overview</SideNavigation.Link>
</SideNavigation.SubMenu>
</SideNavigation>
Expand Down
4 changes: 3 additions & 1 deletion packages/SideNavigation/SubMenu/SubMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ SubMenu.propTypes = {
onClick: PropTypes.func,
/**
* ID of the SubMenu, must be unique when using multiple SubMenus within the same SideNavigation component.
* @ignore
*/
id: PropTypes.string.isRequired,
id: PropTypes.string,
/**
* Describes whether this SubMenu is open or not. Used in conjunction with ID so that only one SubMenu is open at a time.
*
Expand All @@ -84,6 +85,7 @@ SubMenu.defaultProps = {
isOpen: false,
active: false,
children: undefined,
id: undefined,
}

export default SubMenu
1 change: 0 additions & 1 deletion packages/SideNavigation/SubMenu/SubMenu.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@
### Usage Criteria

- Use `SideNavigation.SubMenu` with large pages that have multiple sections
- Each and every `SideNavigation.SubMenu` must have a unique id
84 changes: 68 additions & 16 deletions packages/SideNavigation/__tests__/SideNavigation.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,7 @@ describe('SideNavigation', () => {
<SideNavigation.Link href="#">Home</SideNavigation.Link>
<SideNavigation.Link href="#one">One</SideNavigation.Link>
<SideNavigation.Link href="#two">Two</SideNavigation.Link>
<SideNavigation.SubMenu
active
label="Threefdsfdsfds"
id="Three"
onClick={() => {}}
isOpen={false}
>
<SideNavigation.SubMenu active label="Threefdsfdsfds" onClick={() => {}} isOpen={false}>
<SideNavigation.Link href="#">Option 1</SideNavigation.Link>
<SideNavigation.Link href="#">Option 2</SideNavigation.Link>
<SideNavigation.Link href="#">Option 3</SideNavigation.Link>
Expand All @@ -34,13 +28,7 @@ describe('SideNavigation', () => {
const childrenNoSpacing = (
<SideNavigation>
<SideNavigation.Link href="#">Home</SideNavigation.Link>
<SideNavigation.SubMenu
active
label="Threefdsfdsfds"
id="Three"
onClick={() => {}}
isOpen={false}
>
<SideNavigation.SubMenu active label="Threefdsfdsfds" onClick={() => {}} isOpen={false}>
<SideNavigation.Link href="#">Option 1</SideNavigation.Link>
</SideNavigation.SubMenu>
</SideNavigation>
Expand All @@ -57,12 +45,76 @@ describe('SideNavigation', () => {
.find('SubMenu')
.find('button')
.simulate('click')
expect(sideNavigation.state('open')).toEqual('Three')
expect(sideNavigation.state('open')).toEqual(['TDS-SideNavigation-3'])
sideNavigation
.find('SubMenu')
.find('button')
.simulate('click')
expect(sideNavigation.state('open')).toEqual([])
})

it('toggles open multiple submenus', () => {
const childrenAccordionFalse = (
<SideNavigation accordion={false}>
<SideNavigation.SubMenu active label="Threefdsfdsfds" onClick={() => {}} isOpen={false}>
<SideNavigation.Link href="#">Option 1</SideNavigation.Link>
</SideNavigation.SubMenu>
<SideNavigation.SubMenu active label="Threefdsfdsfds" onClick={() => {}} isOpen={false}>
<SideNavigation.Link href="#">Option 1</SideNavigation.Link>
</SideNavigation.SubMenu>
</SideNavigation>
)
const sideNavigation = mount(childrenAccordionFalse)

sideNavigation
.find('SubMenu')
.find('button')
.at(0)
.simulate('click')
expect(sideNavigation.state('open')).toEqual(['TDS-SideNavigation-0'])
sideNavigation
.find('SubMenu')
.find('button')
.at(1)
.simulate('click')
expect(sideNavigation.state('open')).toEqual(['TDS-SideNavigation-0', 'TDS-SideNavigation-1'])
sideNavigation
.find('SubMenu')
.find('button')
.at(0)
.simulate('click')
expect(sideNavigation.state('open')).toEqual(['TDS-SideNavigation-1'])
sideNavigation
.find('SubMenu')
.find('button')
.at(1)
.simulate('click')
expect(sideNavigation.state('open')).toEqual([])
})

it('toggles does not allow custom props', () => {
const childrenAccordionFalse = (
<SideNavigation accordion={false}>
<SideNavigation.SubMenu
active
label="Threefdsfdsfds"
onClick={() => {}}
isOpen={false}
id="321321"
>
<SideNavigation.Link href="#">Option 1</SideNavigation.Link>
</SideNavigation.SubMenu>
<SideNavigation.Link href="#">Option 2</SideNavigation.Link>
</SideNavigation>
)
const sideNavigation = mount(childrenAccordionFalse)

sideNavigation
.find('SubMenu')
.find('button')
.at(0)
.simulate('click')
expect(sideNavigation.state('open')).toEqual(null)
expect(sideNavigation.state('open')).toEqual(['TDS-SideNavigation-0'])
})

it('does not allow custom CSS', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

exports[`SideNavigation renders 1`] = `
<SideNavigation
accordion={true}
verticalSpacing={3}
>
<div
Expand Down Expand Up @@ -172,7 +173,7 @@ exports[`SideNavigation renders 1`] = `
>
<SubMenu
active={true}
id="Three"
id="TDS-SideNavigation-3"
isOpen={false}
label="Threefdsfdsfds"
onClick={[Function]}
Expand Down Expand Up @@ -242,7 +243,9 @@ exports[`SideNavigation renders 1`] = `
`;

exports[`SideNavigation renders without vertical spacing 1`] = `
<SideNavigation>
<SideNavigation
accordion={true}
>
<div
className="container"
>
Expand Down Expand Up @@ -309,7 +312,7 @@ exports[`SideNavigation renders without vertical spacing 1`] = `
>
<SubMenu
active={true}
id="Three"
id="TDS-SideNavigation-1"
isOpen={false}
label="Threefdsfdsfds"
onClick={[Function]}
Expand Down

0 comments on commit 8983ae1

Please sign in to comment.