diff --git a/CHANGELOG.md b/CHANGELOG.md index caf65dd7..95be6422 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,34 @@ ### [@coreui/vue](https://coreui.io/) changelog +##### v2.1.0 +- feat(SidebarNavLink): attributes +- refactor(SidebarNav*): classes type [String, Array, Object] +- test: update SidebarNavLabel, SidebarNavLink, SidebarNavDivider +- refactor: rollup.config.js uglify() +- chore: update jest.config.js +- update `@vue/test-utils` to `^1.0.0-beta.27` +- update `babel-plugin-dynamic-import-node` to `^2.2.0` +- update `eslint` to `^5.10.0` +- update `eslint-config-prettier` to `^3.3.0` +- update `eslint-plugin-html` to `^5.0.0` +- update `eslint-plugin-jest` to `^22.1.2` +- update `eslint-plugin-vue` to `^5.0.0` +- update `husky` to `^1.2.0` +- update `lint-staged` to `^8.1.0` +- update `node-sass` to `^4.11.0` +- update `prettier` to `^1.15.3` +- update `rollup` to `^0.67.4` +- update `rollup-plugin-commonjs` to `^9.2.0` +- update `rollup-plugin-filesize` to `^5.0.1` +- update `rollup-plugin-replace` to `^2.1.0` +- update `rollup-plugin-uglify` to `^6.0.0` +- update `vue` to `^2.5.19` +- update `vue-server-renderer` to `^2.5.19` +- update `vue-template-compiler` to `^2.5.19` +- update `vue-jest` to `^3.0.1` +- update `vue-router` to `^3.0.2` +- update `@coreui/coreui` to `^2.1.4` + ##### v2.0.2 - fix(AsideToggler): add missing `display { default:'lg' }` prop value - fix(AsideToggler): add missing `defaultOpen` prop value handling diff --git a/README.md b/README.md index 25f3b59c..8f282cbb 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ [][npm] [![NPM downloads][npm-download]][npm] - +  - + [npm]: https://www.npmjs.com/package/@coreui/vue [npm-download]: https://img.shields.io/npm/dm/@coreui/vue.svg?style=flat-square diff --git a/jest.config.js b/jest.config.js index 4aee5bf7..393fedfc 100644 --- a/jest.config.js +++ b/jest.config.js @@ -12,6 +12,7 @@ module.exports = { coverageDirectory: "<rootDir>/coverage", collectCoverageFrom: [ "src/**/*.{js,vue}", + "!src/components/index.js", "!src/index.umd.js", "!**/node_modules/**" ] diff --git a/package.json b/package.json index c30bd55d..2848e2ca 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@coreui/vue", "description": "CoreUI Vue Bootstrap 4 layout components", - "version": "2.0.2", + "version": "2.1.0", "license": "MIT", "main": "dist/coreui-vue.common.js", "module": "dist/coreui-vue.esm.js", @@ -63,51 +63,51 @@ "vue-perfect-scrollbar": "^0.1.0" }, "devDependencies": { - "@vue/test-utils": "^1.0.0-beta.25", + "@vue/test-utils": "^1.0.0-beta.27", "babel-core": "^6.26.3", "babel-eslint": "^10.0.1", "babel-jest": "^23.6.0", - "babel-plugin-dynamic-import-node": "^2.1.0", + "babel-plugin-dynamic-import-node": "^2.2.0", "babel-plugin-module-resolver": "^3.1.1", "babel-preset-vue-app": "^2.0.0", - "eslint": "^5.6.1", - "eslint-config-prettier": "^3.1.0", + "eslint": "^5.10.0", + "eslint-config-prettier": "^3.3.0", "eslint-import-resolver-babel-module": "^4.0.0", - "eslint-plugin-html": "^4.0.6", + "eslint-plugin-html": "^5.0.0", "eslint-plugin-import": "^2.14.0", - "eslint-plugin-jest": "^21.24.1", + "eslint-plugin-jest": "^22.1.2", "eslint-plugin-prettier": "^3.0.0", - "eslint-plugin-vue": "^5.0.0-beta.3", - "husky": "^1.1.0", + "eslint-plugin-vue": "^5.0.0", + "husky": "^1.2.0", "jest": "^23.6.0", "jest-serializer-html": "^5.0.0", "jest-serializer-vue": "^2.0.2", "jest-vue-preprocessor": "^1.4.0", - "lint-staged": "^7.3.0", + "lint-staged": "^8.1.0", "lodash": "^4.17.11", - "node-sass": "^4.9.3", - "prettier": "^1.14.3", - "rollup": "^0.59.4", + "node-sass": "^4.11.0", + "prettier": "^1.15.3", + "rollup": "^0.67.4", "rollup-plugin-babel": "^3.0.7", - "rollup-plugin-commonjs": "^9.1.8", - "rollup-plugin-filesize": "^4.0.1", + "rollup-plugin-commonjs": "^9.2.0", + "rollup-plugin-filesize": "^5.0.1", "rollup-plugin-json": "^3.1.0", "rollup-plugin-license": "^0.7.0", "rollup-plugin-node-resolve": "^3.4.0", - "rollup-plugin-replace": "^2.0.0", - "rollup-plugin-uglify": "^3.0.0", + "rollup-plugin-replace": "^2.1.0", + "rollup-plugin-uglify": "^6.0.0", "rollup-plugin-vue": "^4.3.2", "sass-loader": "^7.1.0", "uglify-es": "^3.3.9", - "vue": "^2.5.17", - "vue-jest": "^2.6.0", + "vue": "^2.5.19", + "vue-jest": "^3.0.1", "vue-loader": "^15.4.2", - "vue-router": "^3.0.1", - "vue-server-renderer": "^2.5.17", - "vue-template-compiler": "^2.5.17" + "vue-router": "^3.0.2", + "vue-server-renderer": "^2.5.19", + "vue-template-compiler": "^2.5.19" }, "peerDependencies": { - "@coreui/coreui": "^2.0.14" + "@coreui/coreui": "^2.1.4" }, "lint-staged": { "*.{js,vue}": [ diff --git a/rollup.config.js b/rollup.config.js index d4f43d60..3702d43e 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -7,7 +7,7 @@ import json from "rollup-plugin-json"; import license from "rollup-plugin-license"; import resolve from "rollup-plugin-node-resolve"; import replace from "rollup-plugin-replace"; -import uglify from "rollup-plugin-uglify"; +import { uglify } from "rollup-plugin-uglify"; import vue from "rollup-plugin-vue"; import { minify } from "uglify-es"; diff --git a/src/components/Breadcrumb/Breadcrumb.vue b/src/components/Breadcrumb/Breadcrumb.vue index b751c286..0260fdc4 100644 --- a/src/components/Breadcrumb/Breadcrumb.vue +++ b/src/components/Breadcrumb/Breadcrumb.vue @@ -16,6 +16,11 @@ export default { default: () => [] } }, + computed: { + routeRecords: function () { + return this.list.filter((route) => route.name || route.meta.label) + } + }, methods: { getName (item) { return item.meta && item.meta.label ? item.meta.label : item.name || null @@ -23,11 +28,6 @@ export default { isLast (index) { return index === this.list.length - 1 } - }, - computed: { - routeRecords: function () { - return this.list.filter((route) => route.name || route.meta.label) - } } } </script> diff --git a/src/components/Footer/Footer.vue b/src/components/Footer/Footer.vue index d80989aa..7d1b0167 100644 --- a/src/components/Footer/Footer.vue +++ b/src/components/Footer/Footer.vue @@ -13,9 +13,6 @@ export default { default: false } }, - mounted: function () { - this.isFixed() - }, computed: { classList () { return [ @@ -23,6 +20,9 @@ export default { ] } }, + mounted: function () { + this.isFixed() + }, methods: { isFixed () { this.fixed ? document.body.classList.add('footer-fixed') : document.body.classList.remove('footer-fixed') diff --git a/src/components/Sidebar/SidebarNav.vue b/src/components/Sidebar/SidebarNav.vue index dd65ac10..2a139398 100644 --- a/src/components/Sidebar/SidebarNav.vue +++ b/src/components/Sidebar/SidebarNav.vue @@ -21,13 +21,13 @@ <!-- Second level dropdown --> <SidebarNavDropdown :key="index1" :name="childL1.name" :url="childL1.url" :icon="childL1.icon"> <li :key="index2" class="nav-item" v-for="(childL2, index2) in childL1.children"> - <SidebarNavLink :name="childL2.name" :url="childL2.url" :icon="childL2.icon" :badge="childL2.badge" :variant="item.variant"/> + <SidebarNavLink :name="childL2.name" :url="childL2.url" :icon="childL2.icon" :badge="childL2.badge" :variant="childL2.variant" :attributes="childL2.attributes" /> </li> </SidebarNavDropdown> </template> <template v-else> <SidebarNavItem :key="index1" :classes="item.class"> - <SidebarNavLink :name="childL1.name" :url="childL1.url" :icon="childL1.icon" :badge="childL1.badge" :variant="item.variant"/> + <SidebarNavLink :name="childL1.name" :url="childL1.url" :icon="childL1.icon" :badge="childL1.badge" :variant="childL1.variant" :attributes="childL1.attributes"/> </SidebarNavItem> </template> </template> @@ -35,7 +35,7 @@ </template> <template v-else> <SidebarNavItem :key="index" :classes="item.class"> - <SidebarNavLink :name="item.name" :url="item.url" :icon="item.icon" :badge="item.badge" :variant="item.variant"/> + <SidebarNavLink :name="item.name" :url="item.url" :icon="item.icon" :badge="item.badge" :variant="item.variant" :attributes="item.attributes"/> </SidebarNavItem> </template> </template> @@ -57,13 +57,6 @@ import VuePerfectScrollbar from 'vue-perfect-scrollbar' export default { name: 'SidebarNav', - props: { - navItems: { - type: Array, - required: true, - default: () => [] - } - }, components: { SidebarNavDivider, SidebarNavDropdown, @@ -73,6 +66,13 @@ export default { SidebarNavLabel, VuePerfectScrollbar }, + props: { + navItems: { + type: Array, + required: true, + default: () => [] + } + }, data () { return {} }, diff --git a/src/components/Sidebar/SidebarNavDivider.vue b/src/components/Sidebar/SidebarNavDivider.vue index ac124f8f..bd13b438 100644 --- a/src/components/Sidebar/SidebarNavDivider.vue +++ b/src/components/Sidebar/SidebarNavDivider.vue @@ -1,25 +1,26 @@ <template> - <li :class="classList"></li> + <li :class="classList" /> </template> <script> export default { - name: 'sidebar-nav-divider', + name: 'SidebarNavDivider', props: { classes: { - type: String, + type: [String, Array, Object], default: '' } }, computed: { classList () { return [ - 'divider', + 'nav-divider', ...this.itemClasses ] }, itemClasses () { - return this.classes ? this.classes.split(' ') : '' + const classes = this.classes + return !classes ? [] : typeof classes === 'string' || classes instanceof String ? classes.split(' ') : Array.isArray(classes) ? classes : Object.keys(classes).filter(i=>classes[i]) } } } diff --git a/src/components/Sidebar/SidebarNavItem.vue b/src/components/Sidebar/SidebarNavItem.vue index 284d1ce0..55d6717e 100644 --- a/src/components/Sidebar/SidebarNavItem.vue +++ b/src/components/Sidebar/SidebarNavItem.vue @@ -9,10 +9,10 @@ import { hideMobile } from '../../mixins/hideMobile' export default { name: 'sidebar-nav-item', - mixins: [ hideMobile ], - props: { + mixins: [ hideMobile ], + props: { classes: { - type: String, + type: [String, Array, Object], default: '' } }, @@ -24,7 +24,8 @@ export default { ] }, itemClasses () { - return this.classes ? this.classes.split(' ') : '' + const classes = this.classes + return !classes ? [] : typeof classes === 'string' || classes instanceof String ? classes.split(' ') : Array.isArray(classes) ? classes : Object.keys(classes).filter(i=>classes[i]) } } } diff --git a/src/components/Sidebar/SidebarNavLabel.vue b/src/components/Sidebar/SidebarNavLabel.vue index 480f1a16..30c456de 100644 --- a/src/components/Sidebar/SidebarNavLabel.vue +++ b/src/components/Sidebar/SidebarNavLabel.vue @@ -27,7 +27,7 @@ export default { default: 'fa fa-circle' }, classes: { - type: String, + type: [String, Array, Object], default: '' }, label: { @@ -39,7 +39,7 @@ export default { computed: { classList () { const classes = { - navItem: ['hidden-cn', ...this.getClasses(this.classes)].join(' '), + navItem: ['hidden-cn', ...this.itemClasses], navLink: 'nav-label', icon: [ this.icon ? this.icon : 'fa fa-circle', @@ -48,12 +48,11 @@ export default { ].join(' ') } return classes + }, + itemClasses () { + const classes = this.classes + return !classes ? [] : typeof classes === 'string' || classes instanceof String ? classes.split(' ') : Array.isArray(classes) ? classes : Object.keys(classes).filter(i=>classes[i]) } }, - methods: { - getClasses (classes) { - return classes ? classes.split(' ') : [] - } - } } </script> diff --git a/src/components/Sidebar/SidebarNavLink.vue b/src/components/Sidebar/SidebarNavLink.vue index 94c1d369..e7a27379 100644 --- a/src/components/Sidebar/SidebarNavLink.vue +++ b/src/components/Sidebar/SidebarNavLink.vue @@ -1,16 +1,16 @@ <template> - <div v-if="isExternalLink"> - <a :href="url" :class="classList"> - <i :class="classIcon"></i> {{name}} - <b-badge v-if="badge && badge.text" :variant="badge.variant">{{badge.text}}</b-badge> - </a> - </div> - <div v-else> - <router-link :to="url" :class="classList"> - <i :class="classIcon"></i> {{name}} - <b-badge v-if="badge && badge.text" :variant="badge.variant">{{badge.text}}</b-badge> - </router-link> - </div> + <a :class="classList" v-bind="attributes" tabindex="-1" v-on:click.stop.prevent v-if="isDisabled"> + <i :class="classIcon"></i> <span>{{name}}</span> + <b-badge v-if="badge && badge.text" :variant="badge.variant">{{badge.text}}</b-badge> + </a> + <a :href="url" :class="classList" v-bind="attributes" v-else-if="isExternalLink"> + <i :class="classIcon"></i> {{name}} + <b-badge v-if="badge && badge.text" :variant="badge.variant">{{badge.text}}</b-badge> + </a> + <router-link :to="url" :class="classList" v-bind="attributes" v-else> + <i :class="classIcon"></i> {{name}} + <b-badge v-if="badge && badge.text" :variant="badge.variant">{{badge.text}}</b-badge> + </router-link> </template> <script> @@ -38,8 +38,12 @@ export default { default: '' }, classes: { - type: String, + type: [String, Array, Object], default: '' + }, + attributes: { + type: Object, + default: () => { return Object.create(null) } } }, computed: { @@ -47,6 +51,8 @@ export default { return [ 'nav-link', this.linkVariant, + ...this.disabledClasses, + ...this.attrClasses, ...this.itemClasses ] }, @@ -60,14 +66,24 @@ export default { return this.variant ? `nav-link-${this.variant}` : '' }, itemClasses () { - return this.classes ? this.classes.split(' ') : [] + return this.getClassArray(this.classes) + }, + attrClasses () { + return this.getClassArray(this.attributes.class) + }, + disabledClasses () { + return this.isDisabled ? 'disabled'.split(' ') : [] + }, + isDisabled () { + return Boolean(this.attributes.disabled) }, isExternalLink () { - if (this.url.substring(0, 4) === 'http') { - return true - } else { - return false - } + return Boolean(this.url.substring(0, 4) === 'http') + } + }, + methods: { + getClassArray(classes) { + return !classes ? [] : typeof classes === 'string' || classes instanceof String ? classes.split(' ') : Array.isArray(classes) ? classes : Object.keys(classes).filter(i=>classes[i]) } } } diff --git a/src/components/Sidebar/SidebarNavTitle.vue b/src/components/Sidebar/SidebarNavTitle.vue index 6bac6f56..6340a2d9 100644 --- a/src/components/Sidebar/SidebarNavTitle.vue +++ b/src/components/Sidebar/SidebarNavTitle.vue @@ -19,7 +19,7 @@ export default { default: '' }, classes: { - type: String, + type: [String, Array, Object], default: '' }, wrapper: { @@ -35,7 +35,8 @@ export default { ] }, itemClasses () { - return this.classes ? this.classes.split(' ') : '' + const classes = this.classes + return !classes ? [] : typeof classes === 'string' || classes instanceof String ? classes.split(' ') : Array.isArray(classes) ? classes : Object.keys(classes).filter(i=>classes[i]) } } } diff --git a/src/components/Switch/Switch.vue b/src/components/Switch/Switch.vue index 7e14bd71..05692f4f 100644 --- a/src/components/Switch/Switch.vue +++ b/src/components/Switch/Switch.vue @@ -7,11 +7,11 @@ :required="required" :name="name" :value="value" - @change="handleChange" class="switch-input form-check-input" type="checkbox" true-value="value" false-value="uncheckedValue" + @change="handleChange" > <template v-if="label"> <span @@ -32,11 +32,6 @@ export default { prop: 'modelChecked', event: 'change' }, - data: function () { - return { - checkedData: this.isChecked ? this.value : this.uncheckedValue - } - }, props: { id: { type: String, @@ -108,6 +103,11 @@ export default { default: 'Off' } }, + data: function () { + return { + checkedData: this.isChecked ? this.value : this.uncheckedValue + } + }, computed: { classList () { return [ @@ -126,6 +126,9 @@ export default { return this.modelChecked === this.value } }, + mounted() { + this.toggle(this.defaultChecked || this.checked || this.isChecked); + }, methods: { handleChange (event) { this.toggle(event.target.checked); @@ -135,8 +138,5 @@ export default { this.$emit('change', this.checkedData); } }, - mounted() { - this.toggle(this.defaultChecked || this.checked || this.isChecked); - }, } </script> diff --git a/src/components/__tests__/SidebarNavDivider.js b/src/components/__tests__/SidebarNavDivider.js index 7ab2bebe..357343dd 100644 --- a/src/components/__tests__/SidebarNavDivider.js +++ b/src/components/__tests__/SidebarNavDivider.js @@ -10,6 +10,6 @@ describe("SidebarNavDivider.vue", () => { it('renders correctly', () => { const wrapper = mount(SidebarNavDivider) expect(wrapper.element).toMatchSnapshot() - expect(wrapper.classes()).toContain('divider') + expect(wrapper.classes()).toContain('nav-divider') }) }); diff --git a/src/components/__tests__/SidebarNavLabel.js b/src/components/__tests__/SidebarNavLabel.js index 511d1535..11045ad8 100644 --- a/src/components/__tests__/SidebarNavLabel.js +++ b/src/components/__tests__/SidebarNavLabel.js @@ -19,9 +19,7 @@ describe("SidebarNavLabel.vue", () => { }); it('has hasSlotDefault computed property', () => { expect(typeof SidebarNavLabel.computed.classList).toBe('function') - }) - it('has getClasses method', () => { - expect(typeof SidebarNavLabel.methods.getClasses).toBe('function') + expect(typeof SidebarNavLabel.computed.itemClasses).toBe('function') }) it('renders correctly', () => { const wrapper = mount(SidebarNavLabel, { diff --git a/src/components/__tests__/SidebarNavLink.js b/src/components/__tests__/SidebarNavLink.js index 2f9f512f..6d0b63bb 100644 --- a/src/components/__tests__/SidebarNavLink.js +++ b/src/components/__tests__/SidebarNavLink.js @@ -29,12 +29,18 @@ describe("SidebarNavLink.vue", () => { expect(typeof SidebarNavLink.computed.classList).toBe('function') expect(typeof SidebarNavLink.computed.classIcon).toBe('function') expect(typeof SidebarNavLink.computed.linkVariant).toBe('function') + expect(typeof SidebarNavLink.computed.attrClasses).toBe('function') expect(typeof SidebarNavLink.computed.itemClasses).toBe('function') + expect(typeof SidebarNavLink.computed.disabledClasses).toBe('function') + expect(typeof SidebarNavLink.computed.isDisabled).toBe('function') expect(typeof SidebarNavLink.computed.isExternalLink).toBe('function') }) + it('has getClassArray method', () => { + expect(typeof SidebarNavLink.methods.getClassArray).toBe('function') + }) it('renders correctly', () => { const wrapper = shallowMount(SidebarNavLink, { localVue, router }) expect(wrapper.element).toMatchSnapshot() - expect(wrapper.is('div')).toBe(true) + expect(wrapper.is('router-link-stub')).toBe(true) }) }); diff --git a/src/components/__tests__/__snapshots__/SidebarNavDivider.js.snap b/src/components/__tests__/__snapshots__/SidebarNavDivider.js.snap index 39f46f71..9b931e72 100644 --- a/src/components/__tests__/__snapshots__/SidebarNavDivider.js.snap +++ b/src/components/__tests__/__snapshots__/SidebarNavDivider.js.snap @@ -2,6 +2,6 @@ exports[`SidebarNavDivider.vue renders correctly 1`] = ` <li - class="divider" + class="nav-divider" /> `; diff --git a/src/components/__tests__/__snapshots__/SidebarNavLink.js.snap b/src/components/__tests__/__snapshots__/SidebarNavLink.js.snap index 8f051816..67242f4c 100644 --- a/src/components/__tests__/__snapshots__/SidebarNavLink.js.snap +++ b/src/components/__tests__/__snapshots__/SidebarNavLink.js.snap @@ -1,19 +1,17 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`SidebarNavLink.vue renders correctly 1`] = ` -<div> - <router-link-stub - class="nav-link" - event="click" - tag="a" - to="" - > - <i - class="nav-icon" - /> - - - <!----> - </router-link-stub> -</div> +<router-link-stub + class="nav-link" + event="click" + tag="a" + to="" +> + <i + class="nav-icon" + /> + + + <!----> +</router-link-stub> `;