diff --git a/__tests__/Vuent.test.js b/__tests__/Vuent.test.js index 7980531..d96a847 100644 --- a/__tests__/Vuent.test.js +++ b/__tests__/Vuent.test.js @@ -10,6 +10,7 @@ import { VntIcon, VntInput, VntLink, + VntNavView, VntRadio, VntRating, VntSelect, @@ -43,13 +44,14 @@ describe('Vuent', () => { expect(isInstalled(localVue, VntIcon)).toBe(true); expect(isInstalled(localVue, VntInput)).toBe(true); expect(isInstalled(localVue, VntLink)).toBe(true); + expect(isInstalled(localVue, VntNavView)).toBe(true); expect(isInstalled(localVue, VntRadio)).toBe(true); expect(isInstalled(localVue, VntRating)).toBe(true); expect(isInstalled(localVue, VntSelect)).toBe(true); expect(isInstalled(localVue, VntSlider)).toBe(true); expect(isInstalled(localVue, VntToggle)).toBe(true); expect(isInstalled(localVue, VntTabs)).toBe(true); - expect(countInstalledPlugins(localVue)).toBe(14); + expect(countInstalledPlugins(localVue)).toBe(15); }); test('has $vuent instance object', () => { diff --git a/__tests__/__snapshots__/navview.test.js.snap b/__tests__/__snapshots__/navview.test.js.snap new file mode 100644 index 0000000..13d3f1f --- /dev/null +++ b/__tests__/__snapshots__/navview.test.js.snap @@ -0,0 +1,113 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NavView by default renders correctly 1`] = ` +
+ +
+ +
+ Content goes here +
+
+
+`; + +exports[`NavView generates correct structure renders correctly 1`] = ` +
+ +
+
+
+

Header

+
+
+
+ Some content +
+
+
+`; + +exports[`NavView when using custom pane footer renders correctly 1`] = ` +
+ +
+ +
+ Some content +
+
+
+`; + +exports[`NavView when using custom pane header renders correctly 1`] = ` +
+ +
+ +
+ Some content +
+
+
+`; diff --git a/__tests__/__snapshots__/navviewItem.test.js.snap b/__tests__/__snapshots__/navviewItem.test.js.snap new file mode 100644 index 0000000..a0f6db1 --- /dev/null +++ b/__tests__/__snapshots__/navviewItem.test.js.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NavviewItem by default renders correctly 1`] = ` +
  • + +
  • +`; + +exports[`NavviewItem when icon is set renders correctly 1`] = ` +
  • + Settings +
  • +`; diff --git a/__tests__/navview.test.js b/__tests__/navview.test.js new file mode 100644 index 0000000..b059f71 --- /dev/null +++ b/__tests__/navview.test.js @@ -0,0 +1,128 @@ +import { createLocalVue, mount } from '@vue/test-utils'; +import { VntNavView } from '@/components'; +import { isInstalled } from './utils'; + +describe('NavView', () => { + let localVue, wrapper; + + beforeAll(() => { + localVue = createLocalVue(); + localVue.use(VntNavView); + }); + + test('can be installed separately', () => { + expect(isInstalled(localVue, VntNavView)).toBe(true); + }); + + describe('by default', () => { + + beforeAll(() => { + wrapper = mount(VntNavView, { + localVue + }); + }); + + test('pane is hidden', () => { + expect(wrapper.vm.isPaneOpened).toBe(false); + }); + + test('renders correctly', () => { + expect(wrapper).toMatchSnapshot(); + }); + + }); + + describe('generates correct structure', () => { + + beforeAll(() => { + wrapper = mount(VntNavView, { + localVue, + propsData: { + paneTitle: 'App name', + header: 'Header', + }, + slots: { + default: ` + + Nav item header + Link 1 + + Link 2 + + + Some content + + ` + } + }); + }); + + test('renders correctly', () => { + expect(wrapper).toMatchSnapshot(); + }); + + test('pane can be toggled', () => { + const menuButton = wrapper.find('.vnt-navview__pane-toggle'); + menuButton.trigger('click'); + + expect(wrapper.vm.isPaneOpened).toBe(true); + }); + + }); + + describe('when using custom pane header', () => { + + beforeAll(() => { + wrapper = mount(VntNavView, { + localVue, + propsData: { + paneTitle: 'App name' + }, + slots: { + default: ` + +
    App name with logo
    +
    + + Some content + + ` + } + }); + }); + + test('renders correctly', () => { + expect(wrapper).toMatchSnapshot(); + }); + + }); + + describe('when using custom pane footer', () => { + + beforeAll(() => { + wrapper = mount(VntNavView, { + localVue, + propsData: { + paneTitle: 'App name', + }, + slots: { + default: ` + + Account + Settings + + + Some content + + ` + } + }); + }); + + test('renders correctly', () => { + expect(wrapper).toMatchSnapshot(); + }); + + }); + +}); diff --git a/__tests__/navviewItem.test.js b/__tests__/navviewItem.test.js new file mode 100644 index 0000000..803cbff --- /dev/null +++ b/__tests__/navviewItem.test.js @@ -0,0 +1,76 @@ +import { mount } from '@vue/test-utils'; +import VntNavviewItem from '@/components/navview/MenuItem.vue'; + +describe('NavviewItem', () => { + let wrapper; + + describe('by default', () => { + + beforeAll(() => { + wrapper = mount(VntNavviewItem); + }); + + test('renders correctly', () => { + expect(wrapper).toMatchSnapshot(); + }); + + test('is not active', () => { + expect(wrapper.vm.active).toBe(false); + }); + + test('icon is null', () => { + expect(wrapper.vm.icon).toBeNull(); + }); + + test('click handler is undefined', () => { + expect(wrapper.vm.click).toBeUndefined(); + }); + + test('when clicked, no error is thrown', () => { + expect(() => { + wrapper.find('a').trigger('click'); + }).not.toThrow(); + }); + + }); + + describe('when icon is set', () => { + + beforeAll(() => { + wrapper = mount(VntNavviewItem, { + propsData: { + icon: 'settings' + }, + slots: { + default: 'Settings' + } + }); + }); + + test('renders correctly', () => { + expect(wrapper).toMatchSnapshot(); + }); + + }); + + describe('when click handler is given', () => { + let mockClick; + + beforeAll(() => { + mockClick = jest.fn(); + + wrapper = mount(VntNavviewItem, { + propsData: { + click: mockClick + } + }); + }); + + test('when clicked, click handler is invoked', () => { + wrapper.find('a').trigger('click'); + expect(mockClick).toHaveBeenCalled(); + }); + + }); + +}); diff --git a/commitlint.config.js b/commitlint.config.js index c0a8bf8..279fd24 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -11,6 +11,7 @@ module.exports = { 'icon', 'input', 'link', + 'navview', 'radio', 'rating', 'select', diff --git a/src/components/index.js b/src/components/index.js index 9fb94ee..7fd0270 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -7,6 +7,7 @@ export { default as VntHeader } from './header'; export { default as VntIcon } from './icon'; export { default as VntInput } from './input'; export { default as VntLink } from './link'; +export { default as VntNavView } from './navview'; export { default as VntRadio } from './radio'; export { default as VntRating } from './rating'; export { default as VntSelect } from './select'; diff --git a/src/components/navview/MenuButton.vue b/src/components/navview/MenuButton.vue new file mode 100644 index 0000000..b7bc5e5 --- /dev/null +++ b/src/components/navview/MenuButton.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/components/navview/MenuItem.vue b/src/components/navview/MenuItem.vue new file mode 100644 index 0000000..73f6af5 --- /dev/null +++ b/src/components/navview/MenuItem.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/src/components/navview/MenuItemHeader.vue b/src/components/navview/MenuItemHeader.vue new file mode 100644 index 0000000..0f28358 --- /dev/null +++ b/src/components/navview/MenuItemHeader.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/src/components/navview/MenuItemSeparator.vue b/src/components/navview/MenuItemSeparator.vue new file mode 100644 index 0000000..dd58f98 --- /dev/null +++ b/src/components/navview/MenuItemSeparator.vue @@ -0,0 +1,18 @@ + + + + + diff --git a/src/components/navview/NavView.vue b/src/components/navview/NavView.vue new file mode 100644 index 0000000..79dc04e --- /dev/null +++ b/src/components/navview/NavView.vue @@ -0,0 +1,239 @@ + + + + + diff --git a/src/components/navview/README.md b/src/components/navview/README.md new file mode 100644 index 0000000..0fe9c41 --- /dev/null +++ b/src/components/navview/README.md @@ -0,0 +1,25 @@ +# NavView + +## How to use + +```html + + + App name with logo + + + Nav item header + Link 1 + Link 2 + + Link 3 + + + Account + Settings + + +

    Content

    + +
    +``` diff --git a/src/components/navview/index.js b/src/components/navview/index.js new file mode 100644 index 0000000..c287d77 --- /dev/null +++ b/src/components/navview/index.js @@ -0,0 +1,13 @@ +import NavView from './NavView.vue'; +import NavViewMenuItem from './MenuItem.vue'; +import NavViewMenuItemHeader from './MenuItemHeader.vue'; +import NavViewMenuItemSeparator from './MenuItemSeparator.vue'; + +NavView.install = function (Vue) { + Vue.component(NavViewMenuItemHeader.name, NavViewMenuItemHeader); + Vue.component(NavViewMenuItem.name, NavViewMenuItem); + Vue.component(NavViewMenuItemSeparator.name, NavViewMenuItemSeparator); + Vue.component(NavView.name, NavView); +}; + +export default NavView; diff --git a/src/scss/mixins/_text.scss b/src/scss/mixins/_text.scss new file mode 100644 index 0000000..bc2e353 --- /dev/null +++ b/src/scss/mixins/_text.scss @@ -0,0 +1,5 @@ +@mixin text-overflow() { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +}