diff --git a/.changeset/tiny-bees-crash.md b/.changeset/tiny-bees-crash.md new file mode 100644 index 000000000..cb572d0b9 --- /dev/null +++ b/.changeset/tiny-bees-crash.md @@ -0,0 +1,9 @@ +--- +"druxt-breadcrumb": minor +--- + +feat(#433): Added path prop to DruxtBreadcrumb component. + +```vue + +``` diff --git a/packages/breadcrumb/src/components/DruxtBreadcrumb.vue b/packages/breadcrumb/src/components/DruxtBreadcrumb.vue index 414763c5b..8c7041bee 100644 --- a/packages/breadcrumb/src/components/DruxtBreadcrumb.vue +++ b/packages/breadcrumb/src/components/DruxtBreadcrumb.vue @@ -3,10 +3,14 @@ import DruxtModule from 'druxt/dist/components/DruxtModule.vue' import { mapActions, mapState } from 'vuex' /** - * Renders a list of breacrumbs based on the active route. + * The DruxtBreadcrumb component renders a list of breadcrumbs based on the + * active route. * * @example @lang vue * + * + * @example @lang vue + * */ export default { name: 'DruxtBreadcrumb', @@ -26,6 +30,21 @@ export default { home: { type: Boolean, default: true + }, + + /** + * The Decoupled router path. + * + * If not set, the Vue router value will be used instead. + * + * @type {string} + * + * @example @lang vue + * + */ + path: { + type: String, + default: '' } }, @@ -57,26 +76,34 @@ export default { * Fetch Crumbs */ async fetchCrumbs() { - // If there is no route, stop here. - if (!this.route || !Object.keys(this.route).length) return + const path = this.path || this.$route.path + let route = this.route + if (this.path && path !== this.$route.path) { + route = await this.getRoute(path) + } + + // If there is no route, throw an error. + if (!route || !Object.keys(route).length) { + throw new Error('No route data available.') + } // If we are at the root and don't want a home crumb, stop here. - if (this.$route.path === '/' && !this.home) return + if (path === '/' && !this.home) return // Current route crumb. const crumbs = [] - if (this.route.label) { - crumbs.push({ text: this.route.label }) + if (route.label) { + crumbs.push({ text: route.label }) } // If we are at the root of the site, stop here. - if (this.$route.path === '/') { + if (path === '/') { this.model = crumbs return } // Add crumbs for route parents. - const paths = this.$route.path.split('/').filter(String) + const paths = path.split('/').filter(String) paths.pop() while (paths.length > 0) { const to = '/' + paths.join('/') diff --git a/packages/breadcrumb/test/components/DruxtBreadcrumb.test.js b/packages/breadcrumb/test/components/DruxtBreadcrumb.test.js index d3fa6e900..846145171 100644 --- a/packages/breadcrumb/test/components/DruxtBreadcrumb.test.js +++ b/packages/breadcrumb/test/components/DruxtBreadcrumb.test.js @@ -4,6 +4,7 @@ import Vuex from 'vuex' import { DruxtRouterStore } from '../../../router/src' import DruxtBreadcrumb from '../../src/components/DruxtBreadcrumb.vue' +import DruxtDebug from '../../../druxt/src/components/DruxtDebug.vue' // Setup local vue instance. const localVue = createLocalVue() @@ -35,7 +36,9 @@ const mountComponent = ({ path, routes, propsData, options }) => { store.commit('druxtRouter/setRoute', path) } - return shallowMount(DruxtBreadcrumb, { store, localVue, mocks, propsData, ...options }) + const components = { DruxtDebug } + + return shallowMount(DruxtBreadcrumb, { components, store, localVue, mocks, propsData, ...options }) } describe('DruxtBreadcrumb', () => { @@ -86,7 +89,10 @@ describe('DruxtBreadcrumb', () => { }) test('level 2', async () => { - const wrapper = mountComponent({ path: '/level-1/level-2', routes: ['/', '/level-1', '/level-1/level-2'] }) + const wrapper = mountComponent({ + path: '/level-1/level-2', + routes: ['/', '/level-1', '/level-1/level-2'] + }) await wrapper.vm.$options.fetch.call(wrapper.vm) expect(wrapper.vm.route).toStrictEqual({ @@ -99,6 +105,24 @@ describe('DruxtBreadcrumb', () => { expect(wrapper.html()).toMatchSnapshot() }) + test('manual path', async () => { + const wrapper = mountComponent({ + path: undefined, + propsData: { + path: '/level-1/level-2', + }, + routes: ['/', '/level-1', '/level-1/level-2'] + }) + await wrapper.vm.$options.fetch.call(wrapper.vm) + + expect(wrapper.vm.route).toStrictEqual({}) + + expect(wrapper.vm.crumbs).toHaveLength(3) + expect(wrapper.vm.crumbs[0].to).toBe('/') + + expect(wrapper.html()).toMatchSnapshot() + }) + test('missing parent', async () => { const wrapper = mountComponent({ path: '/level-1/level-2', routes: ['/', '/level-1/level-2'] }) await wrapper.vm.$options.fetch.call(wrapper.vm) diff --git a/packages/breadcrumb/test/components/__snapshots__/DruxtBreadcrumb.test.js.snap b/packages/breadcrumb/test/components/__snapshots__/DruxtBreadcrumb.test.js.snap index 8bf28b87f..441dda19d 100644 --- a/packages/breadcrumb/test/components/__snapshots__/DruxtBreadcrumb.test.js.snap +++ b/packages/breadcrumb/test/components/__snapshots__/DruxtBreadcrumb.test.js.snap @@ -2,7 +2,7 @@ exports[`DruxtBreadcrumb 404 route 1`] = ` "
- +
" `; @@ -18,6 +18,12 @@ exports[`DruxtBreadcrumb level 2 1`] = ` " `; +exports[`DruxtBreadcrumb manual path 1`] = ` +"
+ +
" +`; + exports[`DruxtBreadcrumb missing parent 1`] = ` "