Skip to content
Permalink
Browse files
fix: properly handle HTML props render order (closes #5363) (#5365)
* fix(jumbatron): fix html props and ensure correct render order

* Update html.js

* Update visible.js

* Update dropdown.js

* Update modal.js

* Update modal.spec.js

* Update carousel-slide.js

* Update card.js

* Update carousel-slide.js

* Update jumbotron.js

* Update card-footer.js

* Update card-header.js

* Update input-group.js

* Update progress-bar.js

* Update mixin-caption.js

* Update mixin-empty.js

* Update mixin-thead.js

* Unify prop utils

* Update props.js

* Merge remote-tracking branch 'origin/dev' into fix-jumbatron-html-props

* Update dropdown.spec.js

* Update dropdown.spec.js

* Update dropdown.spec.js

* Update dropdown.spec.js

* Update modal.spec.js

* Update modal.spec.js

* Update breadcrumb-link.js

* Update card-footer.js

* Update card-header.js

* Update form-select-option-group.js

* Update form-datalist.js

* Update test.yml

* Merge remote-tracking branch 'origin/dev' into fix-jumbatron-html-props

* Update toast.js

* Update form-select.js

* Update form-radio-check-group.js

* Update mixin-thead.js

Co-authored-by: Troy Morehouse <troymore@nbnet.nb.ca>
  • Loading branch information
jacobmllr95 and tmorehouse committed May 15, 2020
1 parent a5df131 commit 844ecda654a2db50d9b84c193f1ab031e291d024
Showing 42 changed files with 776 additions and 595 deletions.
@@ -207,4 +207,3 @@ jobs:
run: yarn run bundlewatch
env:
BUNDLEWATCH_GITHUB_TOKEN: "${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }}"
CI_BRANCH_BASE: "${{ github.base_ref }}"
@@ -1,9 +1,9 @@
import Vue from '../../utils/vue'
import pluckProps from '../../utils/pluck-props'
import { getComponentConfig } from '../../utils/config'
import { isNumber, isString, isUndefinedOrNull } from '../../utils/inspect'
import { toFloat } from '../../utils/number'
import { omit } from '../../utils/object'
import { pluckProps } from '../../utils/props'
import { isLink } from '../../utils/router'
import { BButton } from '../button/button'
import { BLink, props as BLinkProps } from '../link/link'
@@ -1,8 +1,8 @@
import Vue from '../../utils/vue'
import pluckProps from '../../utils/pluck-props'
import { mergeData } from 'vue-functional-data-merge'
import Vue from '../../utils/vue'
import { getComponentConfig } from '../../utils/config'
import { omit } from '../../utils/object'
import { pluckProps } from '../../utils/props'
import { isLink } from '../../utils/router'
import { BLink, props as BLinkProps } from '../link/link'

@@ -1,10 +1,12 @@
import { mergeData } from 'vue-functional-data-merge'
import Vue from '../../utils/vue'
import pluckProps from '../../utils/pluck-props'
import { htmlOrText } from '../../utils/html'
import { omit } from '../../utils/object'
import { pluckProps } from '../../utils/props'
import { BLink, props as BLinkProps } from '../link/link'

// --- Props ---

export const props = {
text: {
type: String,
@@ -21,17 +23,19 @@ export const props = {
...omit(BLinkProps, ['event', 'routerTag'])
}

// --- Main component ---
// @vue/component
export const BBreadcrumbLink = /*#__PURE__*/ Vue.extend({
name: 'BBreadcrumbLink',
functional: true,
props,
render(h, { props: suppliedProps, data, children }) {
const tag = suppliedProps.active ? 'span' : BLink
const { active } = suppliedProps
const tag = active ? 'span' : BLink

const componentData = { props: pluckProps(props, suppliedProps) }
if (suppliedProps.active) {
componentData.attrs = { 'aria-current': suppliedProps.ariaCurrent }
const componentData = {
attrs: { 'aria-current': active ? suppliedProps.ariaCurrent : null },
props: pluckProps(props, suppliedProps)
}

if (!children) {
@@ -1,12 +1,12 @@
import Vue from '../../utils/vue'
import { mergeData } from 'vue-functional-data-merge'
import Vue from '../../utils/vue'
import KeyCodes from '../../utils/key-codes'
import pluckProps from '../../utils/pluck-props'
import { concat } from '../../utils/array'
import { getComponentConfig } from '../../utils/config'
import { addClass, isTag, removeClass } from '../../utils/dom'
import { isBoolean, isEvent, isFunction } from '../../utils/inspect'
import { omit } from '../../utils/object'
import { pluckProps } from '../../utils/props'
import { isLink as isLinkStrict } from '../../utils/router'
import { BLink, props as BLinkProps } from '../link/link'

@@ -1,8 +1,6 @@
import Vue from '../../utils/vue'
import { mergeData } from 'vue-functional-data-merge'
import prefixPropName from '../../utils/prefix-prop-name'
import copyProps from '../../utils/copy-props'
import pluckProps from '../../utils/pluck-props'
import Vue from '../../utils/vue'
import { copyProps, pluckProps, prefixPropName } from '../../utils/props'
import cardMixin from '../../mixins/card'
import { BCardTitle, props as titleProps } from './card-title'
import { BCardSubTitle, props as subTitleProps } from './card-sub-title'
@@ -1,11 +1,11 @@
import Vue from '../../utils/vue'
import { mergeData } from 'vue-functional-data-merge'

import prefixPropName from '../../utils/prefix-prop-name'
import copyProps from '../../utils/copy-props'
import Vue from '../../utils/vue'
import { htmlOrText } from '../../utils/html'
import { copyProps, prefixPropName } from '../../utils/props'
import cardMixin from '../../mixins/card'

// --- Props ---

export const props = {
...copyProps(cardMixin.props, prefixPropName.bind(null, 'footer')),
footer: {
@@ -22,26 +22,30 @@ export const props = {
}
}

// --- Main component ---
// @vue/component
export const BCardFooter = /*#__PURE__*/ Vue.extend({
name: 'BCardFooter',
functional: true,
props,
render(h, { props, data, children }) {
const { footerBgVariant, footerBorderVariant, footerTextVariant } = props

return h(
props.footerTag,
mergeData(data, {
staticClass: 'card-footer',
class: [
props.footerClass,
{
[`bg-${props.footerBgVariant}`]: props.footerBgVariant,
[`border-${props.footerBorderVariant}`]: props.footerBorderVariant,
[`text-${props.footerTextVariant}`]: props.footerTextVariant
[`bg-${footerBgVariant}`]: footerBgVariant,
[`border-${footerBorderVariant}`]: footerBorderVariant,
[`text-${footerTextVariant}`]: footerTextVariant
}
]
],
domProps: children ? {} : htmlOrText(props.footerHtml, props.footer)
}),
children || [h('div', { domProps: htmlOrText(props.footerHtml, props.footer) })]
children
)
}
})
@@ -1,10 +1,11 @@
import Vue from '../../utils/vue'
import { mergeData } from 'vue-functional-data-merge'
import prefixPropName from '../../utils/prefix-prop-name'
import copyProps from '../../utils/copy-props'
import Vue from '../../utils/vue'
import { htmlOrText } from '../../utils/html'
import { copyProps, prefixPropName } from '../../utils/props'
import cardMixin from '../../mixins/card'

// --- Props ---

export const props = {
...copyProps(cardMixin.props, prefixPropName.bind(null, 'header')),
header: {
@@ -21,26 +22,30 @@ export const props = {
}
}

// --- Main component ---
// @vue/component
export const BCardHeader = /*#__PURE__*/ Vue.extend({
name: 'BCardHeader',
functional: true,
props,
render(h, { props, data, children }) {
const { headerBgVariant, headerBorderVariant, headerTextVariant } = props

return h(
props.headerTag,
mergeData(data, {
staticClass: 'card-header',
class: [
props.headerClass,
{
[`bg-${props.headerBgVariant}`]: props.headerBgVariant,
[`border-${props.headerBorderVariant}`]: props.headerBorderVariant,
[`text-${props.headerTextVariant}`]: props.headerTextVariant
[`bg-${headerBgVariant}`]: headerBgVariant,
[`border-${headerBorderVariant}`]: headerBorderVariant,
[`text-${headerTextVariant}`]: headerTextVariant
}
]
],
domProps: children ? {} : htmlOrText(props.headerHtml, props.header)
}),
children || [h('div', { domProps: htmlOrText(props.headerHtml, props.header) })]
children
)
}
})
@@ -1,10 +1,8 @@
import Vue from '../../utils/vue'
import { mergeData } from 'vue-functional-data-merge'
import prefixPropName from '../../utils/prefix-prop-name'
import unPrefixPropName from '../../utils/unprefix-prop-name'
import copyProps from '../../utils/copy-props'
import pluckProps from '../../utils/pluck-props'
import Vue from '../../utils/vue'
import { htmlOrText } from '../../utils/html'
import { hasNormalizedSlot, normalizeSlot } from '../../utils/normalize-slot'
import { copyProps, pluckProps, prefixPropName, unprefixPropName } from '../../utils/props'
import cardMixin from '../../mixins/card'
import { BCardBody, props as bodyProps } from './card-body'
import { BCardHeader, props as headerProps } from './card-header'
@@ -36,49 +34,68 @@ export const BCard = /*#__PURE__*/ Vue.extend({
functional: true,
props,
render(h, { props, data, slots, scopedSlots }) {
const $slots = slots()
// Vue < 2.6.x may return undefined for scopedSlots
const {
imgLeft,
imgRight,
imgStart,
imgEnd,
header,
headerHtml,
footer,
footerHtml,
align,
textVariant,
bgVariant,
borderVariant
} = props
const $scopedSlots = scopedSlots || {}
const $slots = slots()
const slotScope = {}

// Create placeholder elements for each section
let imgFirst = h()
let header = h()
let content = h()
let footer = h()
let imgLast = h()

let $imgFirst = h()
let $imgLast = h()
if (props.imgSrc) {
const img = h(BCardImg, {
props: pluckProps(cardImgProps, props, unPrefixPropName.bind(null, 'img'))
const $img = h(BCardImg, {
props: pluckProps(cardImgProps, props, unprefixPropName.bind(null, 'img'))
})

if (props.imgBottom) {
imgLast = img
$imgLast = $img
} else {
imgFirst = img
$imgFirst = $img
}
}

if (props.header || props.headerHtml || hasNormalizedSlot('header', $scopedSlots, $slots)) {
header = h(
let $header = h()
const hasHeaderSlot = hasNormalizedSlot('header', $scopedSlots, $slots)
if (hasHeaderSlot || header || headerHtml) {
$header = h(
BCardHeader,
{ props: pluckProps(headerProps, props) },
normalizeSlot('header', {}, $scopedSlots, $slots)
{
props: pluckProps(headerProps, props),
domProps: hasHeaderSlot ? {} : htmlOrText(headerHtml, header)
},
normalizeSlot('header', slotScope, $scopedSlots, $slots)
)
}

content = normalizeSlot('default', {}, $scopedSlots, $slots) || []
let $content = normalizeSlot('default', slotScope, $scopedSlots, $slots)

// Wrap content in <card-body> when `noBody` prop set
if (!props.noBody) {
// Wrap content in card-body
content = [h(BCardBody, { props: pluckProps(bodyProps, props) }, [...content])]
$content = h(BCardBody, { props: pluckProps(bodyProps, props) }, $content)
}

if (props.footer || props.footerHtml || hasNormalizedSlot('footer', $scopedSlots, $slots)) {
footer = h(
let $footer = h()
const hasFooterSlot = hasNormalizedSlot('footer', $scopedSlots, $slots)
if (hasFooterSlot || footer || footerHtml) {
$footer = h(
BCardFooter,
{
props: pluckProps(footerProps, props)
props: pluckProps(footerProps, props),
domProps: hasHeaderSlot ? {} : htmlOrText(footerHtml, footer)
},
normalizeSlot('footer', {}, $scopedSlots, $slots)
normalizeSlot('footer', slotScope, $scopedSlots, $slots)
)
}

@@ -87,16 +104,15 @@ export const BCard = /*#__PURE__*/ Vue.extend({
mergeData(data, {
staticClass: 'card',
class: {
'flex-row': props.imgLeft || props.imgStart,
'flex-row-reverse':
(props.imgRight || props.imgEnd) && !(props.imgLeft || props.imgStart),
[`text-${props.align}`]: props.align,
[`bg-${props.bgVariant}`]: props.bgVariant,
[`border-${props.borderVariant}`]: props.borderVariant,
[`text-${props.textVariant}`]: props.textVariant
'flex-row': imgLeft || imgStart,
'flex-row-reverse': (imgRight || imgEnd) && !(imgLeft || imgStart),
[`text-${align}`]: align,
[`bg-${bgVariant}`]: bgVariant,
[`border-${borderVariant}`]: borderVariant,
[`text-${textVariant}`]: textVariant
}
}),
[imgFirst, header, ...content, footer, imgLast]
[$imgFirst, $header, $content, $footer, $imgLast]
)
}
})

0 comments on commit 844ecda

Please sign in to comment.