diff --git a/docs/common-props.json b/docs/common-props.json index d728326c297..78ccfa2bf83 100644 --- a/docs/common-props.json +++ b/docs/common-props.json @@ -231,7 +231,8 @@ "description": "router-link prop: Specify the event that triggers the link. In most cases you should leave this as the default" }, "prefetch": { - "description": "nuxt-link prop: To improve the responsiveness of your Nuxt.js applications, when the link will be displayed within the viewport, Nuxt.js will automatically prefetch the code splitted page. Setting 'prefetch' to 'true' or 'false' will overwrite the default value of 'router.prefetchLinks'" + "description": "nuxt-link prop: To improve the responsiveness of your Nuxt.js applications, when the link will be displayed within the viewport, Nuxt.js will automatically prefetch the code splitted page. Setting 'prefetch' to 'true' or 'false' will overwrite the default value of 'router.prefetchLinks'", + "version": "2.15.0" }, "noPrefetch": { "description": "nuxt-link prop: To improve the responsiveness of your Nuxt.js applications, when the link will be displayed within the viewport, Nuxt.js will automatically prefetch the code splitted page. Setting 'no-prefetch' will disabled this feature for the specific link" diff --git a/docs/markdown/reference/router-links/README.md b/docs/markdown/reference/router-links/README.md index bc93b575ee1..796cd12ee93 100644 --- a/docs/markdown/reference/router-links/README.md +++ b/docs/markdown/reference/router-links/README.md @@ -158,15 +158,18 @@ additional Nuxt.js specific props. ### `prefetch` - type: `boolean` -- default: `undefined` -- availability: Nuxt.js 2.10.0+ +- default: `null` +- availability: Nuxt.js 2.10.0+ and BootstrapVue 2.15.0+ To improve the responsiveness of your Nuxt.js applications, when the link will be displayed within the viewport, Nuxt.js will automatically prefetch the code splitted page. Setting `prefetch` to `true` or `false` will overwrite the default value of `router.prefetchLinks` configured in the `nuxt.config.js` configuration file. -**Note:** If you have are using a version of Nuxt.js `< 2.10.0`, then this prop will have no effect. +**Notes:** + +- If you have are using a version of Nuxt.js `< 2.10.0`, then this prop will have no effect. +- Remember to `v-bind` the prop value (e.g. `:prefetch="true"` or `:prefetch="false"`). Prefetching support requires [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) diff --git a/src/components/badge/badge.js b/src/components/badge/badge.js index 9094a2d6356..ab2399e16fe 100644 --- a/src/components/badge/badge.js +++ b/src/components/badge/badge.js @@ -1,17 +1,17 @@ import Vue from '../../utils/vue' +import pluckProps from '../../utils/pluck-props' import { mergeData } from 'vue-functional-data-merge' import { getComponentConfig } from '../../utils/config' -import pluckProps from '../../utils/pluck-props' -import { BLink, propsFactory as linkPropsFactory } from '../link/link' +import { clone } from '../../utils/object' +import { BLink, props as BLinkProps } from '../link/link' const NAME = 'BBadge' -const linkProps = linkPropsFactory() +const linkProps = clone(BLinkProps) delete linkProps.href.default delete linkProps.to.default export const props = { - ...linkProps, tag: { type: String, default: 'span' @@ -23,7 +23,8 @@ export const props = { pill: { type: Boolean, default: false - } + }, + ...linkProps } // @vue/component diff --git a/src/components/breadcrumb/breadcrumb-link.js b/src/components/breadcrumb/breadcrumb-link.js index 038e6a379f2..a2cc8b1961e 100644 --- a/src/components/breadcrumb/breadcrumb-link.js +++ b/src/components/breadcrumb/breadcrumb-link.js @@ -2,10 +2,9 @@ import Vue from '../../utils/vue' import { mergeData } from 'vue-functional-data-merge' import pluckProps from '../../utils/pluck-props' import { htmlOrText } from '../../utils/html' -import { BLink, propsFactory as linkPropsFactory } from '../link/link' +import { BLink, props as BLinkProps } from '../link/link' export const props = { - ...linkPropsFactory(), text: { type: String, default: null @@ -17,7 +16,8 @@ export const props = { ariaCurrent: { type: String, default: 'location' - } + }, + ...BLinkProps } // @vue/component diff --git a/src/components/button/button.js b/src/components/button/button.js index 730eeb94903..e7c9382c556 100644 --- a/src/components/button/button.js +++ b/src/components/button/button.js @@ -6,14 +6,20 @@ import { concat } from '../../utils/array' import { getComponentConfig } from '../../utils/config' import { addClass, removeClass } from '../../utils/dom' import { isBoolean, isEvent, isFunction } from '../../utils/inspect' -import { keys } from '../../utils/object' +import { clone } from '../../utils/object' import { toString } from '../../utils/string' -import { BLink, propsFactory as linkPropsFactory } from '../link/link' +import { BLink, props as BLinkProps } from '../link/link' -// --- Constants -- +// --- Constants --- const NAME = 'BButton' +// --- Props --- + +const linkProps = clone(BLinkProps) +delete linkProps.href.default +delete linkProps.to.default + const btnProps = { block: { type: Boolean, @@ -55,12 +61,7 @@ const btnProps = { } } -const linkProps = linkPropsFactory() -delete linkProps.href.default -delete linkProps.to.default -const linkPropKeys = keys(linkProps) - -export const props = { ...linkProps, ...btnProps } +export const props = { ...btnProps, ...linkProps } // --- Helper methods --- @@ -104,7 +105,7 @@ const computeClass = props => [ ] // Compute the link props to pass to b-link (if required) -const computeLinkProps = props => (isLink(props) ? pluckProps(linkPropKeys, props) : null) +const computeLinkProps = props => (isLink(props) ? pluckProps(linkProps, props) : null) // Compute the attributes for a button const computeAttrs = (props, data) => { @@ -142,6 +143,7 @@ const computeAttrs = (props, data) => { } } +// --- Main component --- // @vue/component export const BButton = /*#__PURE__*/ Vue.extend({ name: NAME, diff --git a/src/components/dropdown/dropdown-item.js b/src/components/dropdown/dropdown-item.js index 992984e4d0a..01af4fe1478 100644 --- a/src/components/dropdown/dropdown-item.js +++ b/src/components/dropdown/dropdown-item.js @@ -1,10 +1,11 @@ import Vue from '../../utils/vue' import { requestAF } from '../../utils/dom' +import { clone } from '../../utils/object' import attrsMixin from '../../mixins/attrs' import normalizeSlotMixin from '../../mixins/normalize-slot' -import { BLink, propsFactory as linkPropsFactory } from '../link/link' +import { BLink, props as BLinkProps } from '../link/link' -export const props = linkPropsFactory() +export const props = clone(BLinkProps) // @vue/component export const BDropdownItem = /*#__PURE__*/ Vue.extend({ diff --git a/src/components/link/link.js b/src/components/link/link.js index 05b622ee40e..539af3514c6 100644 --- a/src/components/link/link.js +++ b/src/components/link/link.js @@ -1,45 +1,17 @@ import Vue from '../../utils/vue' +import pluckProps from '../../utils/pluck-props' import { concat } from '../../utils/array' import { attemptBlur, attemptFocus } from '../../utils/dom' -import { isEvent, isFunction, isUndefined } from '../../utils/inspect' +import { isBoolean, isEvent, isFunction, isUndefined } from '../../utils/inspect' import { computeHref, computeRel, computeTag, isRouterLink } from '../../utils/router' -import { omit } from '../../utils/object' import attrsMixin from '../../mixins/attrs' import listenersMixin from '../../mixins/listeners' import normalizeSlotMixin from '../../mixins/normalize-slot' -/** - * The Link component is used in many other BV components - * As such, sharing its props makes supporting all its features easier - * However, some components need to modify the defaults for their own purpose - * Prefer sharing a fresh copy of the props to ensure mutations - * do not affect other component references to the props - * - * See: https://github.com/vuejs/vue-router/blob/dev/src/components/link.js - */ -export const propsFactory = () => ({ - href: { - type: String, - default: null - }, - rel: { - type: String, - // Must be `null` if no value provided - default: null - }, - target: { - type: String, - default: '_self' - }, - active: { - type: Boolean, - default: false - }, - disabled: { - type: Boolean, - default: false - }, - // specific props +// --- Props --- + +// specific props +export const routerLinkProps = { to: { type: [String, Object], default: null @@ -71,29 +43,61 @@ export const propsFactory = () => ({ routerTag: { type: String, default: 'a' - }, - // specific prop(s) + } +} + +// specific props +export const nuxtLinkProps = { prefetch: { - type: Boolean - // Must be `undefined` to fall back to the value defined in the + type: Boolean, + // Must be `null` to fall back to the value defined in the // `nuxt.config.js` configuration file for `router.prefetchLinks` - // default: undefined + // We convert `null` to `undefined`, so that Nuxt.js will use the + // compiled default. Vue treats `undefined` as default of `false` + // for Boolean props, so we must set it as `null` here to be a + // true tri-state prop + default: null }, noPrefetch: { type: Boolean, default: false } -}) +} -export const props = propsFactory() +export const props = { + href: { + type: String, + default: null + }, + rel: { + type: String, + // Must be `null` if no value provided + default: null + }, + target: { + type: String, + default: '_self' + }, + active: { + type: Boolean, + default: false + }, + disabled: { + type: Boolean, + default: false + }, + ...routerLinkProps, + ...nuxtLinkProps +} +// --- Main component --- // @vue/component export const BLink = /*#__PURE__*/ Vue.extend({ name: 'BLink', // Mixin order is important! mixins: [attrsMixin, listenersMixin, normalizeSlotMixin], inheritAttrs: false, - props: propsFactory(), + props, computed: { computedTag() { // We don't pass `this` as the first arg as we need reactivity of the props @@ -111,9 +115,16 @@ export const BLink = /*#__PURE__*/ Vue.extend({ return computeHref({ to: this.to, href: this.href }, this.computedTag) }, computedProps() { - const props = this.isRouterLink ? { ...this.$props, tag: this.routerTag } : {} - // Ensure the `href` prop does not exist for router links - return this.computedHref ? props : omit(props, ['href']) + const prefetch = this.prefetch + return this.isRouterLink + ? { + ...pluckProps({ ...routerLinkProps, ...nuxtLinkProps }, this.$props), + // Coerce `prefetch` value `null` to be `undefined` + prefetch: isBoolean(prefetch) ? prefetch : undefined, + // Pass `router-tag` as `tag` prop + tag: this.routerTag + } + : {} }, computedAttrs() { const { diff --git a/src/components/list-group/list-group-item.js b/src/components/list-group/list-group-item.js index 3571fbea452..f41bf0c3e77 100644 --- a/src/components/list-group/list-group-item.js +++ b/src/components/list-group/list-group-item.js @@ -1,14 +1,20 @@ -import Vue from '../../utils/vue' import { mergeData } from 'vue-functional-data-merge' +import Vue from '../../utils/vue' import pluckProps from '../../utils/pluck-props' import { arrayIncludes } from '../../utils/array' import { getComponentConfig } from '../../utils/config' -import { BLink, propsFactory as linkPropsFactory } from '../link/link' +import { clone } from '../../utils/object' +import { BLink, props as BLinkProps } from '../link/link' + +// --- Constants --- const NAME = 'BListGroupItem' const actionTags = ['a', 'router-link', 'button', 'b-link'] -const linkProps = linkPropsFactory() + +// --- Props --- + +const linkProps = clone(BLinkProps) delete linkProps.href.default delete linkProps.to.default @@ -31,6 +37,8 @@ export const props = { }, ...linkProps } + +// --- Main component --- // @vue/component export const BListGroupItem = /*#__PURE__*/ Vue.extend({ name: NAME, diff --git a/src/components/nav/nav-item.js b/src/components/nav/nav-item.js index 64b9bce9311..a5796140354 100644 --- a/src/components/nav/nav-item.js +++ b/src/components/nav/nav-item.js @@ -1,9 +1,13 @@ -import Vue from '../../utils/vue' import { mergeData } from 'vue-functional-data-merge' -import { BLink, propsFactory as linkPropsFactory } from '../link/link' +import Vue from '../../utils/vue' +import { clone } from '../../utils/object' +import { BLink, props as BLinkProps } from '../link/link' + +// --- Props --- -export const props = linkPropsFactory() +export const props = clone(BLinkProps) +// --- Main component --- // @vue/component export const BNavItem = /*#__PURE__*/ Vue.extend({ name: 'BNavItem', diff --git a/src/components/navbar/navbar-brand.js b/src/components/navbar/navbar-brand.js index d1b71461b80..144f8e2e0ef 100644 --- a/src/components/navbar/navbar-brand.js +++ b/src/components/navbar/navbar-brand.js @@ -1,9 +1,10 @@ -import Vue from '../../utils/vue' import { mergeData } from 'vue-functional-data-merge' +import Vue from '../../utils/vue' import pluckProps from '../../utils/pluck-props' -import { BLink, propsFactory } from '../link/link' +import { clone } from '../../utils/object' +import { BLink, props as BLinkProps } from '../link/link' -const linkProps = propsFactory() +const linkProps = clone(BLinkProps) linkProps.href.default = undefined linkProps.to.default = undefined