Skip to content

Commit 5bf6733

Browse files
authored
feat(refactor): code enhancements for easier Vue 3 migration (closes #6124, #6139) (#6141)
* feat(refactor): code improvements for easier Vue 3 migration * chore(deps): regenerate lockfile * fix(build): add missing `package.json` files for private components * chore: bump BundleWatch values * Update progress-bar.js * Update tab.js * Update bv-tooltip-template.js * Update props.js * Update props.spec.js * Update tabs.js * Update tab.js * Update progress-bar.js * Update tbody.js * Update td.js * Update tfoot.js * Update thead.js * Update tr.js * Update time.js * Update bv-tooltip-template.js * Update form-radio-check.js * Update collapse.js * Update collapse.js * Update form-radio-check.js * Update form-radio.js * Update safe-types.js * Update common-props.json * Update package.json * Update package.json * chore: alphabetically sort component meta information * chore(refactor): add `slots` constants for all slot names * Update safe-types.js * Update README.md * Update avatar.js * Update alert.js * Update form-radio-check.js * chore(docs): add `ariaControls` to common props * Update form-datepicker.js * Update form-timepicker.js * Update componentdoc.vue * chore(refactor): move all custom event names to `events` constants * Update dropdown.js * Update slots.js * Update form-spinbutton.js * Update form-rating.js * Update modal.js * Update sidebar.js * Update slots.js * Update pagination.js * Update pagination.js * chore(docs): add missing documentation for slots * Update package.json * Update componentdoc.vue * feat(popover/tooltip): use `normalizeSlotMixin` * Update card-img-lazy.js * Update package.json * Update package.json * chore(docs): improve prop XSS warnings * Update package.json * Update bv-tooltip-template.js * Update bv-popover-template.js * Update bv-tooltip-template.js * Update bv-popper.js * fix: `required` prop handling * Update tooltip.js * Update form-text.js * Update form-file.js * Update form-input.js * Update form-text.js * Update index.js
1 parent d2083e6 commit 5bf6733

File tree

408 files changed

+12767
-13012
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

408 files changed

+12767
-13012
lines changed

.bundlewatch.config.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
"files": [
33
{
44
"path": "./dist/bootstrap-vue-icons.js",
5-
"maxSize": "115 kB"
5+
"maxSize": "120 kB"
66
},
77
{
88
"path": "./dist/bootstrap-vue-icons.min.js",
9-
"maxSize": "105 kB"
9+
"maxSize": "110 kB"
1010
},
1111
{
1212
"path": "./dist/bootstrap-vue-icons.common.js",
@@ -18,7 +18,7 @@
1818
},
1919
{
2020
"path": "./dist/bootstrap-vue-icons.esm.js",
21-
"maxSize": "115 kB"
21+
"maxSize": "120 kB"
2222
},
2323
{
2424
"path": "./dist/bootstrap-vue-icons.esm.min.js",

docs/common-props.json

+159-152
Large diffs are not rendered by default.

docs/components/componentdoc.vue

+53-47
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ import commonProps from '../common-props.json'
305305
import { getComponentName, getCleanComponentName, kebabCase } from '../utils'
306306
import AnchoredHeading from './anchored-heading'
307307
308+
const SORT_THRESHOLD = 10
309+
308310
export default {
309311
name: 'BVComponentdoc',
310312
components: { AnchoredHeading },
@@ -393,34 +395,36 @@ export default {
393395
}, {})
394396
},
395397
propsFields() {
396-
const sortable = this.propsItems.length >= 10
398+
const sortable = this.propsItems.length >= SORT_THRESHOLD
397399
const hasDescriptions = this.propsItems.some(p => p.description)
398400
return [
399401
{ key: 'prop', label: 'Property', sortable },
400-
{ key: 'type', label: 'Type' },
402+
{ key: 'type', label: 'Type', sortable },
401403
{ key: 'defaultValue', label: 'Default' },
402404
...(hasDescriptions ? [{ key: 'description', label: 'Description' }] : [])
403405
]
404406
},
405407
eventsFields() {
408+
const sortable = this.events.length >= SORT_THRESHOLD
406409
return [
407-
{ key: 'event', label: 'Event' },
410+
{ key: 'event', label: 'Event', sortable },
408411
{ key: 'args', label: 'Arguments' },
409412
{ key: 'description', label: 'Description' }
410413
]
411414
},
412415
rootEventListenersFields() {
416+
const sortable = this.rootEventListeners.length >= SORT_THRESHOLD
413417
return [
414-
{ key: 'event', label: 'Event' },
418+
{ key: 'event', label: 'Event', sortable },
415419
{ key: 'args', label: 'Arguments' },
416420
{ key: 'description', label: 'Description' }
417421
]
418422
},
419423
slotsFields() {
420-
const sortable = this.slotsItems.length >= 10
424+
const sortable = this.slots.length >= SORT_THRESHOLD
421425
const hasScopedSlots = this.slots.some(s => s.scope)
422426
return [
423-
{ key: 'name', label: 'Slot Name', sortable },
427+
{ key: 'name', label: 'Name', sortable },
424428
...(hasScopedSlots ? [{ key: 'scope', label: 'Scoped' }] : []),
425429
{ key: 'description', label: 'Description' }
426430
]
@@ -429,50 +433,52 @@ export default {
429433
const props = this.componentProps
430434
const propsMetaObj = this.componentPropsMetaObj
431435
432-
return Object.keys(props).map(prop => {
433-
const p = props[prop]
434-
const meta = {
435-
// Fallback descriptions for common props
436-
...(commonProps[prop] || {}),
437-
...(propsMetaObj[prop] || {})
438-
}
436+
return Object.keys(props)
437+
.sort()
438+
.map(prop => {
439+
const p = props[prop]
440+
const meta = {
441+
// Fallback descriptions for common props
442+
...(commonProps[prop] || {}),
443+
...(propsMetaObj[prop] || {})
444+
}
439445
440-
// Describe type
441-
let type = p.type
442-
let types = []
443-
if (Array.isArray(type)) {
444-
types = type.map(type => type.name)
445-
} else {
446-
types = type && type.name ? [type.name] : ['Any']
447-
}
448-
type = types
449-
.map(type => `<code class="notranslate" translate="no">${type}</code>`)
450-
.join(' or ')
446+
// Describe type
447+
let type = p.type
448+
let types = []
449+
if (Array.isArray(type)) {
450+
types = type.map(type => type.name)
451+
} else {
452+
types = type && type.name ? [type.name] : ['Any']
453+
}
454+
type = types
455+
.map(type => `<code class="notranslate" translate="no">${type}</code>`)
456+
.join(' or ')
451457
452-
// Default value
453-
let defaultValue = p.default
454-
if (defaultValue instanceof Function && !Array.isArray(defaultValue)) {
455-
defaultValue = defaultValue()
456-
}
457-
defaultValue =
458-
typeof defaultValue === 'undefined'
459-
? ''
460-
: String(JSON.stringify(defaultValue, undefined, 1)).replace(/"/g, "'")
458+
// Default value
459+
let defaultValue = p.default
460+
if (defaultValue instanceof Function && !Array.isArray(defaultValue)) {
461+
defaultValue = defaultValue()
462+
}
463+
defaultValue =
464+
typeof defaultValue === 'undefined'
465+
? ''
466+
: String(JSON.stringify(defaultValue, undefined, 1)).replace(/"/g, "'")
461467
462-
return {
463-
prop: kebabCase(prop),
464-
type,
465-
defaultValue,
466-
required: p.required || false,
467-
description: meta.description || '',
468-
version: meta.version || '',
469-
xss: /[a-z]Html$/.test(prop),
470-
isVModel: this.componentVModel && this.componentVModel.prop === prop,
471-
deprecated: p.deprecated || false,
472-
deprecation: p.deprecation || false,
473-
_showDetails: typeof p.deprecated === 'string' || typeof p.deprecation === 'string'
474-
}
475-
})
468+
return {
469+
prop: kebabCase(prop),
470+
type,
471+
defaultValue,
472+
required: p.required || false,
473+
description: meta.description || '',
474+
version: meta.version || '',
475+
xss: meta.xss || false,
476+
isVModel: this.componentVModel && this.componentVModel.prop === prop,
477+
deprecated: p.deprecated || false,
478+
deprecation: p.deprecation || false,
479+
_showDetails: typeof p.deprecated === 'string' || typeof p.deprecation === 'string'
480+
}
481+
})
476482
},
477483
slotsItems() {
478484
// We use object spread here so that `_showDetails` doesn't

docs/utils/index.js

+30-30
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,23 @@ export const getComponentName = component => kebabCase(component).replace(/{/g,
1919
export const getCleanComponentName = component => getComponentName(component).replace(/({|})/g, '')
2020

2121
export const parseUrl = value => {
22-
const anchor = document.createElement('a')
23-
anchor.href = value
22+
const $anchor = document.createElement('a')
23+
$anchor.href = value
2424

2525
// We need to add the anchor to the document to make sure the
2626
// `pathname` is correctly detected in any browser
27-
document.body.appendChild(anchor)
27+
document.body.appendChild($anchor)
2828

2929
const result = ['hash', 'host', 'hostname', 'pathname', 'port', 'protocol', 'search'].reduce(
3030
(result, prop) => {
31-
result[prop] = anchor[prop] || null
31+
result[prop] = $anchor[prop] || null
3232
return result
3333
},
3434
{}
3535
)
3636

3737
// Make sure to remove the anchor from document as soon as possible
38-
document.body.removeChild(anchor)
38+
document.body.removeChild($anchor)
3939

4040
// Normalize port
4141
if (!result.port && result.protocol) {
@@ -146,31 +146,31 @@ export const updateMetaTOC = (tocData = {}, meta = null) => {
146146
return tocData
147147
}
148148

149-
export const importAll = r => {
150-
const obj = {}
151-
152-
r.keys()
153-
.map(r)
154-
.map(m => m.meta || m)
155-
.map(m => ({
156-
slug:
157-
typeof m.slug === 'undefined' ? (m.title || '').replace(' ', '-').toLowerCase() : m.slug,
158-
...m
159-
}))
160-
.sort((a, b) => {
161-
if (a.slug < b.slug) return -1
162-
else if (a.slug > b.slug) return 1
163-
return 0
164-
})
165-
.forEach(m => {
166-
if (m.components) {
167-
// Normalize `meta.components` to array of objects form
168-
m.components = m.components.map(c => (typeof c === 'string' ? { component: c } : c))
169-
}
170-
obj[m.slug] = m
171-
})
172-
173-
return obj
149+
export const importAll = context => {
150+
// Get array of datas by keys from context
151+
const datas = context.keys().map(context)
152+
153+
return (
154+
datas
155+
// Filter out private datas
156+
.filter(data => !data.private)
157+
// Map meta information
158+
.map(data => data.meta || data)
159+
// Normalize meta information
160+
.map(meta => ({
161+
...meta,
162+
slug:
163+
meta.slug === undefined ? (meta.title || '').replace(' ', '-').toLowerCase() : meta.slug
164+
}))
165+
// Sort by slug
166+
.sort((a, b) => {
167+
if (a.slug < b.slug) return -1
168+
else if (a.slug > b.slug) return 1
169+
return 0
170+
})
171+
// Build one object keyed by slug
172+
.reduce((result, meta) => ({ ...result, [meta.slug]: meta }), {})
173+
)
174174
}
175175

176176
// Smooth Scroll handler methods

scripts/check-plugin-meta.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ const checkPluginMeta = async plugin => {
4444
return file.replace(/\.js/, '')
4545
})
4646

47-
const { meta } = await import(`${pluginDir}/package.json`)
48-
if (!meta) {
47+
const { private: isPrivate, meta } = await import(`${pluginDir}/package.json`)
48+
if (isPrivate || !meta) {
4949
return
5050
}
5151

src/_custom-controls.scss

-112
Original file line numberDiff line numberDiff line change
@@ -28,115 +28,3 @@
2828
}
2929
}
3030
}
31-
32-
// Shared BVFormBtnLabelControl styling
33-
// Currently used by BFormTimepicker and BFormDatepicker
34-
// Does not apply to button-only styling
35-
.b-form-btn-label-control.form-control {
36-
// Remove background validation images and padding from
37-
// main wrapper as they will be present in the inner label element
38-
background-image: none;
39-
padding: 0;
40-
41-
@at-root {
42-
// Handle input-group padding overrides
43-
.input-group & {
44-
padding: 0;
45-
}
46-
}
47-
48-
@at-root {
49-
// Prevent the button/label from reversing order on in horizontal RTL mode
50-
[dir="rtl"] &,
51-
&[dir="rtl"] {
52-
flex-direction: row-reverse;
53-
54-
> label {
55-
text-align: right;
56-
}
57-
}
58-
}
59-
60-
> .btn {
61-
line-height: 1;
62-
font-size: inherit;
63-
box-shadow: none !important;
64-
border: 0;
65-
66-
&:disabled {
67-
pointer-events: none;
68-
}
69-
}
70-
71-
&.is-valid > .btn {
72-
color: $form-feedback-valid-color;
73-
}
74-
75-
&.is-invalid > .btn {
76-
color: $form-feedback-invalid-color;
77-
}
78-
79-
> .dropdown-menu {
80-
padding: 0.5rem;
81-
}
82-
83-
> label {
84-
outline: 0;
85-
padding-left: 0.25rem;
86-
margin: 0;
87-
border: 0;
88-
font-size: inherit;
89-
@if $enable-pointer-cursor-for-buttons {
90-
cursor: pointer;
91-
}
92-
// Set a minimum height, as we have height set to auto
93-
// (to allow the content to wrap if needed)
94-
// We subtract off the border, as we have border set to 0
95-
min-height: calc(#{$input-height} - #{$input-height-border});
96-
97-
&.form-control-sm {
98-
min-height: calc(#{$input-height-sm} - #{$input-height-border});
99-
}
100-
101-
&.form-control-lg {
102-
min-height: calc(#{$input-height-lg} - #{$input-height-border});
103-
}
104-
105-
@at-root {
106-
// Handle input group sizing
107-
.input-group.input-group-sm & {
108-
min-height: calc(#{$input-height-sm} - #{$input-height-border});
109-
padding-top: $input-padding-y-sm;
110-
padding-bottom: $input-padding-y-sm;
111-
}
112-
113-
.input-group.input-group-lg & {
114-
min-height: calc(#{$input-height-lg} - #{$input-height-border});
115-
padding-top: $input-padding-y-lg;
116-
padding-bottom: $input-padding-y-lg;
117-
}
118-
}
119-
}
120-
121-
// Disabled and read-only styling
122-
&[aria-disabled="true"],
123-
&[aria-readonly="true"] {
124-
background-color: $input-disabled-bg;
125-
opacity: 1;
126-
}
127-
128-
&[aria-disabled="true"] {
129-
pointer-events: none;
130-
131-
> label {
132-
cursor: default;
133-
}
134-
}
135-
}
136-
137-
// Button only mode menu padding overrides
138-
.b-form-btn-label-control.btn-group {
139-
> .dropdown-menu {
140-
padding: 0.5rem;
141-
}
142-
}

0 commit comments

Comments
 (0)