Skip to content

Commit

Permalink
feat(UsaSidenavItem): implement UsaSidenavItem component
Browse files Browse the repository at this point in the history
ISSUES CLOSED: #66
  • Loading branch information
patrickcate committed Jan 5, 2022
1 parent 5e0541b commit 804f4f4
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 0 deletions.
106 changes: 106 additions & 0 deletions src/components/UsaSidenavItem/UsaSidenavItem.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import UsaSidenavItem from './UsaSidenavItem.vue'

const defaultProps = {
item: {
to: '/test-page-1',
text: 'Test Page 1',
},
customClasses: {
item: [],
link: [],
sublist: [],
},
}

export default {
component: UsaSidenavItem,
title: 'Components/UsaSidenavItem',
argTypes: {
item: {
control: { type: 'object' },
},
customClasses: {
control: { type: 'object' },
},
defaultSlot: {
control: { type: 'text' },
},
},
args: {
item: defaultProps.item,
customClasses: defaultProps.customClasses,
defaultSlot: '',
},
decorators: [() => ({ template: '<ul class="usa-sidenav"><story /></ul>' })],
}

const DefaultTemplate = (args, { argTypes }) => ({
components: { UsaSidenavItem },
props: Object.keys(argTypes),
setup() {
return { ...args }
},
template: `<UsaSidenavItem :item="item" :custom-classes="customClasses"><template #default="{ item }">${args.defaultSlot}</template></UsaSidenavItem>`,
})

export const DefaultSidenavItem = DefaultTemplate.bind({})
DefaultSidenavItem.args = {
...defaultProps,
}
DefaultSidenavItem.storyName = 'Default'

export const CustomClassesSidenavItem = DefaultTemplate.bind({})
CustomClassesSidenavItem.args = {
...defaultProps,
item: {
to: '/test-page-1',
text: 'Test Page 1',
children: [
{
to: '/test-page-1-1',
text: 'Test Page 1.1',
},
{
to: '/test-page-1-2',
text: 'Test Page 1.2',
},
{
to: '/test-page-1-3',
text: 'Test Page 1.3',
},
],
},
customClasses: {
item: ['test-item-class'],
link: ['test-link-class'],
sublist: ['test-sublist-class'],
},
}
CustomClassesSidenavItem.storyName = 'Custom Classes'

export const SublistSidenavItem = DefaultTemplate.bind({})
SublistSidenavItem.args = {
...defaultProps,
item: {
to: '/parent-page',
text: 'Parent page',
children: [
{
to: '/parent-page/sublist',
text: 'Sublist',
},
],
},
}
SublistSidenavItem.storyName = 'With Sublist'

export const ScopedSlotSidenavItem = DefaultTemplate.bind({})
ScopedSlotSidenavItem.args = {
...defaultProps,
item: {
to: '/parent-page',
text: 'Parent page',
},
defaultSlot: `<strong>{{ item.to }} &rarr;</strong>`,
}
ScopedSlotSidenavItem.storyName = 'Scoped Slot'
77 changes: 77 additions & 0 deletions src/components/UsaSidenavItem/UsaSidenavItem.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import '@module/uswds/dist/css/uswds.min.css'
import { mount } from '@cypress/vue'
import { h } from 'vue'
import UsaSidenavItem from './UsaSidenavItem.vue'

const testItem = {
to: '/page-1',
text: 'Page 1',
children: [
{
href: '/page-1-1',
text: 'Page 1.1',
},
],
}

describe('UsaSidenavItem', () => {
beforeEach(() => {
// Set viewport large enough that all links show.
cy.viewport('ipad-mini')
})

it('renders the component', () => {
mount(UsaSidenavItem, {
props: {
item: testItem,
customClasses: {
item: ['test-item-class'],
link: ['test-link-class'],
sublist: ['test-sublist-class'],
},
},
})

cy.get('[data-v-app] > li.usa-sidenav__item')
.as('item')
.should('have.class', 'test-item-class')

cy.get('@item')
.find('> a')
.should('have.class', 'test-link-class')
.and('have.attr', 'to')
.and('contain', '/page-1')

cy.get('@item').find('> a').should('contain', 'Page 1')

cy.get('ul.usa-sidenav__sublist')
.as('sublist')
.should('have.class', 'test-sublist-class')

cy.get('@sublist').find('> li').should('have.class', 'usa-sidenav__item')

cy.get('@sublist')
.find('a')
.should('have.class', 'test-link-class')
.and('have.attr', 'href')
.and('contain', '/page-1-1')

cy.get('@sublist').find('a').should('contain', 'Page 1.1')
})

it('`item` prop is available in scoped slot', () => {
mount(UsaSidenavItem, {
props: {
item: testItem,
},
slots: {
default: props => h('span', {}, `path is: ${props.item.to}`),
},
})

cy.get('[data-v-app] > .usa-sidenav__item > a span').should(
'contain',
'path is: /page-1'
)
})
})
39 changes: 39 additions & 0 deletions src/components/UsaSidenavItem/UsaSidenavItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<script setup>
import BaseLink from '@/components/BaseLink'
import UsaSidenavSublist from '@/components/UsaSidenavSublist'
defineProps({
item: {
type: Object,
required: true,
},
customClasses: {
type: Object,
default: () => {
return {
item: [],
link: [],
sublist: [],
}
},
},
})
</script>

<template>
<li class="usa-sidenav__item" :class="customClasses?.item">
<BaseLink
:href="item?.href"
:to="item?.to"
:router-component-name="item?.routerComponentName"
:class="customClasses?.link"
v-bind="item?.attrs"
><slot :item="item">{{ item.text }}</slot></BaseLink
>
<UsaSidenavSublist
v-if="item?.children?.length"
:items="item.children"
:custom-classes="customClasses"
></UsaSidenavSublist>
</li>
</template>
4 changes: 4 additions & 0 deletions src/components/UsaSidenavItem/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import UsaSidenavItem from './UsaSidenavItem.vue'

export { UsaSidenavItem }
export default UsaSidenavItem

0 comments on commit 804f4f4

Please sign in to comment.