diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 1446f26b4b7..0cf04588611 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -25,7 +25,7 @@ A clear and concise description of what the pull request does.
- [ ] It's submitted to the `dev` branch, **not** the `master` branch
- [ ] When resolving a specific issue, it's referenced in the PR's title (i.e. `[...] (fixes #xxx[,#xxx])`, where "xxx" is the issue number)
- [ ] It should address only one issue or feature. If adding multiple features or fixing a bug and adding a new feature, break them into separate PRs if at all possible.
-- [ ] The title should follow the [**Conventional Commits**](https://www.conventionalcommits.org/) naming convention (i.e. `fix(alert): not alerting during SSR render`, `docs(badge): update pill examples, fix typos`, `chore: fix typo in README`, etc). **This is very important, as the `CHANGELOG` is generated from these messages.**
+- [ ] The title should follow the [**Conventional Commits**](https://www.conventionalcommits.org/) naming convention (i.e. `fix(alert): not alerting during SSR render`, `docs(badge): update pill examples`, `chore(docs): fix typo in README`, etc). **This is very important, as the `CHANGELOG` is generated from these messages.**
**If new features/enhancement/fixes are added or changed:**
@@ -33,6 +33,7 @@ A clear and concise description of what the pull request does.
- [ ] Includes any needed TypeScript declaration file updates
- [ ] New/updated tests are included and passing (if required)
- [ ] Existing test suites are passing
+- [ ] CodeCov for patch has met target
- [ ] The changes have not impacted the functionality of other components or directives
- [ ] ARIA Accessibility has been taken into consideration (Does it affect screen reader users or keyboard only users? Clickable items should be in the tab index, etc.)
diff --git a/.github/renovate.json b/.github/renovate.json
index bba6e15153b..9e03220db5a 100644
--- a/.github/renovate.json
+++ b/.github/renovate.json
@@ -13,6 +13,10 @@
{
"packageNames": ["prettier"],
"allowedVersions": "<=1.14.3"
+ },
+ {
+ "packageNames": ["@vue/test-utils"],
+ "allowedVersions": "<=1.0.0-beta.29"
}
]
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2f3f791f5c7..c1785cad9f7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,86 @@
> [standard-version](https://github.com/conventional-changelog/standard-version) for commit
> guidelines.
+
+
+## [v2.2.0](https://github.com/bootstrap-vue/bootstrap-vue/compare/v2.1.0...v2.2.0)
+
+Released: 2020-01-08
+
+### Overview v2.2.0
+
+- New optional icon components based on `BootstrapIcons v1.0.0-alpha2`
+- New tagged input component ``
+- Support for `Bootstrap v4.4.1` CSS/SCSS
+
+### Features v2.2.0
+
+- **icons:** new optional icon components
+ ([#4489](https://github.com/bootstrap-vue/bootstrap-vue/issues/4489))
+ ([d2bef17](https://github.com/bootstrap-vue/bootstrap-vue/commit/d2bef1715636fcb83de6d51808683e6feda671d0))
+- **b-collapse:** add new prop `appear` to animate an initially visible collapse
+ ([#4317](https://github.com/bootstrap-vue/bootstrap-vue/issues/4317))
+ ([136a72b](https://github.com/bootstrap-vue/bootstrap-vue/commit/136a72b0352d4bb1339ab31f791087cbcda42fa5))
+- **b-collapse:** add optional scoping to default slot
+ ([#4405](https://github.com/bootstrap-vue/bootstrap-vue/issues/4405))
+ ([8e95bac](https://github.com/bootstrap-vue/bootstrap-vue/commit/8e95bacf9d00562f2676689d067ae0db009cbbb6))
+- **b-container:** add support for bootstrap v4.4.x new responsive containers
+ ([0e318f4](https://github.com/bootstrap-vue/bootstrap-vue/commit/0e318f4755e65eb569dcc579938d0d72c02abd62))
+- **b-dropdown:** add splitClass property to dropdown component
+ ([#4394](https://github.com/bootstrap-vue/bootstrap-vue/issues/4394))
+ ([a5f342e](https://github.com/bootstrap-vue/bootstrap-vue/commit/a5f342e0e4de2186259e36e42cecda8c20e1c8ab))
+- **b-dropdown-form:** new `form-class` prop for adding classes to the form element (closes
+ [#4474](https://github.com/bootstrap-vue/bootstrap-vue/issues/4474))
+ ([#4475](https://github.com/bootstrap-vue/bootstrap-vue/issues/4475))
+ ([eef4200](https://github.com/bootstrap-vue/bootstrap-vue/commit/eef4200976f7921b1bb03f50c0ece8ee7c41ed0e))
+- **b-form-select:** add group/tree support and dedicated option and option-group components (closes
+ [#3222](https://github.com/bootstrap-vue/bootstrap-vue/issues/3222))
+ ([#4267](https://github.com/bootstrap-vue/bootstrap-vue/issues/4267))
+ ([f1ed017](https://github.com/bootstrap-vue/bootstrap-vue/commit/f1ed0177c20f9d7e7e340a8815d1b6bc66f7cb76))
+- **b-form-select:** support paths for `valueField`, `textField`, `htmlField` and `disabledField`
+ props ([#4386](https://github.com/bootstrap-vue/bootstrap-vue/issues/4386))
+ ([ed3b736](https://github.com/bootstrap-vue/bootstrap-vue/commit/ed3b7360af415dc3cc56f0b6662c9d48cc165781))
+- **b-form-tags:** new tagged input component
+ ([#4409](https://github.com/bootstrap-vue/bootstrap-vue/issues/4409))
+ ([00eb9d9](https://github.com/bootstrap-vue/bootstrap-vue/commit/00eb9d9fd460adca8227b3b344284b5cc49a734f))
+- **b-row:** add Bootstrap v4.4 row columns support
+ ([#4439](https://github.com/bootstrap-vue/bootstrap-vue/issues/4439))
+ ([833b028](https://github.com/bootstrap-vue/bootstrap-vue/commit/833b028a2d6101d01b7012a7378359db1c801695))
+- **b-table:** better sort labeling for screen readers (closes
+ [#4487](https://github.com/bootstrap-vue/bootstrap-vue/issues/4487))
+ ([#4488](https://github.com/bootstrap-vue/bootstrap-vue/issues/4488))
+ ([d4e66fa](https://github.com/bootstrap-vue/bootstrap-vue/commit/d4e66fa48fdd1cd7fd4b93907fe999de3fc577f8))
+- **b-table, b-table-lite:** new `tbody-tr-attr` prop for arbitrary row attributes (closes
+ [#1864](https://github.com/bootstrap-vue/bootstrap-vue/issues/1864))
+ ([#4481](https://github.com/bootstrap-vue/bootstrap-vue/issues/4481))
+ ([4acf6ed](https://github.com/bootstrap-vue/bootstrap-vue/commit/4acf6ed863dd5edd85897a01b099c42322097d1b))
+- **b-tooltip:** add `noninteractive` prop (closes
+ [#4556](https://github.com/bootstrap-vue/bootstrap-vue/issues/4556))
+ ([#4563](https://github.com/bootstrap-vue/bootstrap-vue/issues/4563))
+ ([b3ad726](https://github.com/bootstrap-vue/bootstrap-vue/commit/b3ad7264d9b10fb1b8dfba70c62eed11a56519d6))
+- **build:** configure pre-commit hook (closes
+ [#4532](https://github.com/bootstrap-vue/bootstrap-vue/issues/4532))
+ ([#4552](https://github.com/bootstrap-vue/bootstrap-vue/issues/4552))
+ ([1bf9e59](https://github.com/bootstrap-vue/bootstrap-vue/commit/1bf9e59e8888a7a2cd6f135665103419f603a32d))
+
+### Bug Fixes v2.2.0
+
+- **b-table, b-table-lite:** handle edge case with row events when table is removed from dom.
+ instantiate row event handlers only when listeners are registered (fixes
+ [#4384](https://github.com/bootstrap-vue/bootstrap-vue/issues/4384))
+ ([#4388](https://github.com/bootstrap-vue/bootstrap-vue/issues/4388))
+ ([9a81cd4](https://github.com/bootstrap-vue/bootstrap-vue/commit/9a81cd414a2c534b96de0d82c3d00d94651e5a7b))
+- **b-toast:** fix interal `ensureToaster` method call when toaster name changes
+ ([#4468](https://github.com/bootstrap-vue/bootstrap-vue/issues/4468))
+ ([744bb7a](https://github.com/bootstrap-vue/bootstrap-vue/commit/744bb7a77092a04184af31bf285e432110e1ab44))
+- **tooltips, popovers:** fix memory leak (closes
+ [#4400](https://github.com/bootstrap-vue/bootstrap-vue/issues/4400))
+ ([#4401](https://github.com/bootstrap-vue/bootstrap-vue/issues/4401))
+ ([c71352d](https://github.com/bootstrap-vue/bootstrap-vue/commit/c71352d674347e5e2d72fe8b82334fc87a4ffd8c))
+- **docs:** handle undocumented breaking changes in babel-standalone for IE11
+ ([#4484](https://github.com/bootstrap-vue/bootstrap-vue/issues/4484))
+ ([56f8bb5](https://github.com/bootstrap-vue/bootstrap-vue/commit/56f8bb5af7fb7188da035210e8be28d7ae1c7bc1))
+
## [v2.1.0](https://github.com/bootstrap-vue/bootstrap-vue/compare/v2.0.4...v2.1.0)
@@ -77,8 +157,8 @@ Released: 2019-11-12
([#4325](https://github.com/bootstrap-vue/bootstrap-vue/issues/4325))
([c686088](https://github.com/bootstrap-vue/bootstrap-vue/commit/c686088))
- **b-table, b-table-lite, b-table-simple:** fix issue with sticky columns when table is not
- responsive but has sticky headers
- (fixes [#4354](https://github.com/bootstrap-vue/bootstrap-vue/issues/4354))
+ responsive but has sticky headers (fixes
+ [#4354](https://github.com/bootstrap-vue/bootstrap-vue/issues/4354))
([#4356](https://github.com/bootstrap-vue/bootstrap-vue/issues/4356))
([56b3958](https://github.com/bootstrap-vue/bootstrap-vue/commit/56b3958))
- **b-table, b-table-lite, b-tbody:** fix delegated event handlers when transition + minor
diff --git a/LICENSE b/LICENSE
index 0afe512d48d..80d672f72fb 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2016-2019 - BootstrapVue
+Copyright (c) 2016-2020 - BootstrapVue
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/docs/components/anchored-heading.js b/docs/components/anchored-heading.js
index 71933ed108a..be467ae0348 100644
--- a/docs/components/anchored-heading.js
+++ b/docs/components/anchored-heading.js
@@ -26,6 +26,7 @@ export default {
return h(
`h${props.level}`,
mergeData(data, {
+ staticClass: 'bv-no-focus-ring',
attrs: {
id: props.id,
tabindex: '-1'
diff --git a/docs/components/componentdoc.vue b/docs/components/componentdoc.vue
index f528fc68bab..c797ddd24b9 100644
--- a/docs/components/componentdoc.vue
+++ b/docs/components/componentdoc.vue
@@ -2,9 +2,10 @@
-
+ {{ tag }}
+ v{{ version }}+
-
+
View source
@@ -120,7 +127,7 @@
Caution: Props that support HTML strings
- (*-html) can be vulerable to
+ (*-html) can be vulnerable to
Cross Site Scripting (XSS) attacks
@@ -310,18 +317,23 @@ ul.component-ref-mini-toc:empty {
diff --git a/docs/components/importdoc.vue b/docs/components/importdoc.vue
index c246369c47b..19f1185e03b 100644
--- a/docs/components/importdoc.vue
+++ b/docs/components/importdoc.vue
@@ -118,9 +118,9 @@
+
+
+
```
## Build variants
@@ -643,12 +702,29 @@ JavaScript files.
Choosing the best variant for your build environment / packager helps reduce bundle sizes. If your
bundler supports esm modules, it will automatically prefer it over commonjs.
-| Variant | Environments | Package path |
-| -------------- | ---------------------- | ---------------------------------------------------------------------- |
-| **ESM module** | webpack 2+ / rollup.js | `esm/index.js` |
-| ESM bundle | webpack 2+ / rollup.js | `dist/bootstrap-vue.esm.js` |
-| commonjs2 | webpack 1 / ... | `dist/bootstrap-vue.common.js` _or_ `dist/bootstrap-vue.common.min.js` |
-| UMD | Browser | `dist/bootstrap-vue.js` _or_ `dist/bootstrap-vue.min.js` |
+| Variant | Environments | Tree Shake | Package path |
+| -------------- | ---------------------- | ---------- | ---------------------------------------------------------------------- |
+| **ESM module** | webpack 2+ / rollup.js | Yes | `esm/index.js` |
+| ESM bundle | webpack 2+ / rollup.js | Yes | `dist/bootstrap-vue.esm.js` |
+| commonjs2 | webpack 1 / ... | No | `dist/bootstrap-vue.common.js` _or_ `dist/bootstrap-vue.common.min.js` |
+| UMD | Browser | No | `dist/bootstrap-vue.js` _or_ `dist/bootstrap-vue.min.js` |
+
+Note the UMD (browser) variant **does not** include BootstrapVue [icons](/docs/icons) support. All
+other variants listed above _do include_ the `BootstrapVueIcons` (`IconsPlugin`) plugin (note the
+icons plugin is not automatically installed, and must explicitly installed via `Vue.use()`. See the
+[Icons usage](/docs/icons#usage) section for more details.
+
+Icons only modules:
+
+| Variant | Environments | Tree Shake | Package path |
+| -------------- | ---------------------- | ---------- | ---------------------------------------------------------------------------------- |
+| **ESM bundle** | webpack 2+ / rollup.js | Yes | `dist/bootstrap-vue-icons.esm.js` |
+| commonjs2 | webpack 1 / ... | No | `dist/bootstrap-vue-icons.common.js` _or_ `dist/bootstrap-vue-icons.common.min.js` |
+| UMD | Browser | No | `dist/bootstrap-vue-icons.js` _or_ `dist/bootstrap-vue-icons.min.js` |
+
+The `ESM` module build and the `ESM` bundles (single file) are
+[tree-shakeable](#tree-shaking-with-module-bundlers), but you will experience smaller final bundle
+sizes when using the `ESM` module _vs._ the `ESM` bundle.
All of the build variants listed above have been pre-transpiled targeting the
[browsers](https://github.com/bootstrap-vue/bootstrap-vue/blob/master/.browserslistrc) supported by
@@ -659,21 +735,18 @@ reduce final project bundle sizes. See the
[Using BootstrapVue source code for smaller bundles](#using-bootstrapvue-source-code-for-smaller-bundles)
section above for more details.
-Both the `ESM` module and `ESM` bundle (single file) are
-[tree-shakeable](#tree-shaking-with-module-bundlers), but you will experience smaller final bundle
-sizes when using the `ESM` module _vs._ the `ESM` bundle.
-
### Dependencies
BootstrapVue relies on `Popper.js` (for Tooltip, Popover, and Dropdown positioning), `PortalVue`
(for toasts) and
[`vue-functional-data-merge`](https://github.com/alexsasharegan/vue-functional-data-merge) (used by
-our functional components). These three dependencies are included in the `UMD` bundle.
+our functional components). These three dependencies are included in the BootstrapVue `UMD` bundle,
+while the UMD (browser) icons only bundle includes `vue-functional-data-merge`.
## Migrating a project already using Bootstrap
-If you've already been using Bootstrap v4, there are a couple adjustments you may need to make to
-your project:
+If you've already been using Bootstrap vv{{bootstrapVersionMajor}}, there are a couple adjustments
+you may need to make to your project:
- Remove the `bootstrap.js` file from your page scripts or build pipeline
- If Bootstrap is the only thing relying on `jQuery`, you can safely remove it — BootstrapVue **does
@@ -685,9 +758,9 @@ your project:
### CSS
-BootstrapVue is to be used with Bootstrap v4.3 CSS/SCSS. Please see
-[Browsers and devices](https://getbootstrap.com/docs/4.3/getting-started/browsers-devices) for more
-information about browsers currently supported by Bootstrap v4.
+BootstrapVue is to be used with Bootstrap v{{bootstrapVersionMinor}} CSS/SCSS. Please see
+Browsers and devices for more
+information about browsers currently supported by Bootstrap v{{bootstrapVersionMajor}}.
### JS
diff --git a/docs/nuxt.config.js b/docs/nuxt.config.js
index 0892e5e1919..2e98febdeb2 100644
--- a/docs/nuxt.config.js
+++ b/docs/nuxt.config.js
@@ -88,8 +88,8 @@ renderer.heading = function(text, level, raw, slugger) {
ANCHOR_LINK_HEADING_LEVELS.indexOf(level) !== -1
? ``
: ''
-
- return `${getTextMarkup(text + anchor)}\n`
+ const attrs = `id="${link}" class="bv-no-focus-ring"`
+ return `${getTextMarkup(text + anchor)}\n`
}
// Convert lead-in blockquote paragraphs to true bootstrap docs leads
diff --git a/docs/pages/docs/components/_slug.js b/docs/pages/docs/components/_slug.js
index 3dd9b6cc125..36110b9dbc5 100644
--- a/docs/pages/docs/components/_slug.js
+++ b/docs/pages/docs/components/_slug.js
@@ -33,9 +33,9 @@ export default {
h(AnchoredHeading, { props: { id: 'component-reference' } }, 'Component reference'),
// Component reference information
...this.meta.components.map(
- ({ component, events, rootEventListeners, slots, aliases, props: propsMeta }) =>
+ ({ component, events, rootEventListeners, slots, aliases, props: propsMeta, version }) =>
h(Componentdoc, {
- props: { component, events, rootEventListeners, slots, aliases, propsMeta }
+ props: { component, events, rootEventListeners, slots, aliases, propsMeta, version }
})
),
// Component importing information
diff --git a/docs/pages/docs/icons/index.js b/docs/pages/docs/icons/index.js
new file mode 100644
index 00000000000..3f001e38091
--- /dev/null
+++ b/docs/pages/docs/icons/index.js
@@ -0,0 +1,75 @@
+import AnchoredHeading from '~/components/anchored-heading'
+import Componentdoc from '~/components/componentdoc'
+import IconsTable from '~/components/icons-table'
+import Importdoc from '~/components/importdoc'
+import Main from '~/components/main'
+import Section from '~/components/section'
+import docsMixin from '~/plugins/docs-mixin'
+import { icons as iconsMeta, bootstrapIconsVersion } from '~/content'
+import readme from '~/../src/icons/README.md'
+
+export default {
+ name: 'BDVIcons',
+ layout: 'docs',
+ // We use a string template here so that the docs README can do interpolation
+ template: `
+
+ ${readme}
+
+ Component reference
+
+
+
+
+
+ Individual icon components are not listed here due to the large number of components.
+
+
+
+
+ IconsPlugin is also exported as BootstrapVueIcons.
+
+
+ `,
+ components: {
+ AnchoredHeading,
+ Componentdoc,
+ IconsTable,
+ Importdoc,
+ Main,
+ Section
+ },
+ mixins: [docsMixin],
+ data() {
+ return {
+ readme: readme,
+ // Key for icons meta is '' (empty slug)
+ meta: iconsMeta[''],
+ bootstrapIconsVersion
+ }
+ },
+ computed: {
+ componentMeta() {
+ // `docs/content/index.js` massages the list of icon components
+ // to include only `BIcon` and an example component
+ const components = this.meta.components
+ // Add in a special property or grabbing the component props
+ // as `BIcon{IconName}` doesn't exist
+ components[1].srcComponent = 'BIconBlank'
+ return components
+ },
+ importMeta() {
+ return { ...this.meta, slug: 'icons', components: this.componentMeta }
+ }
+ }
+}
diff --git a/docs/pages/docs/index.js b/docs/pages/docs/index.js
index 92f5797a4bc..ace02436f32 100644
--- a/docs/pages/docs/index.js
+++ b/docs/pages/docs/index.js
@@ -46,6 +46,10 @@ export default {
}
},
computed: {
+ hrefBootstrapBrowserDevices() {
+ const minorVersion = this.bootstrapVersionMinor
+ return `//getbootstrap.com/docs/${minorVersion}/getting-started/browsers-devices`
+ },
// TODO: pull this from the meta.json file
meta() {
return {
diff --git a/docs/pages/index.vue b/docs/pages/index.vue
index 0903aa8c95a..3520d945c18 100644
--- a/docs/pages/index.vue
+++ b/docs/pages/index.vue
@@ -132,7 +132,7 @@
- With over 40 available plugins and more than 80 custom UI components,
+ With over 40 available plugins and more than 80 custom UI components, directives, and over 300 icons,
BootstrapVue provides one of the most
comprehensive implementations of the
Bootstrap v{{ bootstrapVersionMinor }} component and grid system
@@ -190,28 +190,9 @@
-
-
+ Responsive
-
Mobile first responsive layout
@@ -219,29 +200,9 @@
-
-
+ Modular
-
Import only the features that you need
@@ -249,27 +210,15 @@
-
-
+ >
Accessible
-
Automated WAI-ARIA accessibility markup
@@ -293,10 +242,8 @@
d="M356.9 64.3H280l-56 88.6-48-88.6H0L224 448 448 64.3h-91.1zm-301.2 32h53.8L224 294.5 338.4 96.3h53.8L224 384.5 55.7 96.3z"
/>
-
Modern
-
Built with Vue.js v{{ vueVersionMinor }} and
Bootstrap SCSS v{{ bootstrapVersionMinor }}
@@ -305,34 +252,9 @@
-
-
+ Configurable
-
Create themes with SCSS variables and global options
@@ -354,10 +276,8 @@
d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"
/>
-
Free
-
Open sourced on GitHub,
MIT License
diff --git a/docs/pages/play.vue b/docs/pages/play.vue
index 1530d043213..cde2f93273a 100644
--- a/docs/pages/play.vue
+++ b/docs/pages/play.vue
@@ -685,7 +685,6 @@ export default {
} else {
delete options.template
}
-
// Vue's `errorCapture` doesn't always handle errors in methods (although it
// does if the method is used as a `v-on`/`@` handler), so we wrap any methods
// with a try/catch handler so we can show the error in our GUI log console.
@@ -709,15 +708,15 @@ export default {
})
}
- // Try and buld the user app
+ // Try and build the user app
try {
const holder = document.createElement('div')
this.$refs.result.appendChild(holder)
this.playVM = new Vue({
...options,
el: holder,
- // Router needed for tooltips/popovers so they hide when
- // docs route changes
+ // Router needed for tooltips/popovers/toasts so
+ // that they hide when docs route changes
router: this.$router,
// We set a fake parent so we can capture most runtime and
// render errors (this is an error boundary component)
@@ -751,7 +750,7 @@ export default {
this.compiledJs = null
return
}
- const js = this.js.trim() || '{}'
+ const js = (this.js || '').trim() || '{}'
this.compiling = true
let compiled = null
this.$nextTick(() => {
@@ -759,7 +758,7 @@ export default {
try {
// The app build process expects the app options to
// be assigned to the `options` variable
- compiled = this.compiler(`;options = ${js};`)
+ compiled = this.compiler(';options = ' + js + ';')
} catch (err) {
this.errHandler(err, 'javascript')
window.console.error('Error in javascript', err)
diff --git a/docs/plugins/bootstrap-vue.js b/docs/plugins/bootstrap-vue.js
index 4b3ae0e1349..eccf73126ff 100644
--- a/docs/plugins/bootstrap-vue.js
+++ b/docs/plugins/bootstrap-vue.js
@@ -1,4 +1,5 @@
import Vue from 'vue'
-import BootstrapVue from '../../src'
+import { BootstrapVue, BootstrapVueIcons } from '../../src'
Vue.use(BootstrapVue)
+Vue.use(BootstrapVueIcons)
diff --git a/docs/utils/compile-js.js b/docs/utils/compile-js.js
index d5d13e86850..b7373381a4f 100644
--- a/docs/utils/compile-js.js
+++ b/docs/utils/compile-js.js
@@ -1,12 +1,61 @@
-// Utility for tranpiling ES6 code into ES5 for playground and v-play
+// Utility for transpiling ES6 code into ES5 for playground and `v-play`
+// Imported only on demand when needed
import { transform, disableScriptTags } from '@babel/standalone'
+// Babel broke the standalone version via PR https://github.com/babel/babel/pull/10420
+// Which assumes the browser supports String.prototype.trimLeft/Right
+// IE 11 does not support either, and polyfill.io does not polyfill them
+// So we do it here (as this file is only loaded if we need transpilation):
+if (typeof window !== 'undefined') {
+ const Proto = window.String.prototype
+
+ // Ensure we have a `trimStart` method
+ ;((obj, prop) => {
+ if (!(prop in obj && obj[prop])) {
+ const rx = /^\s+/
+ obj[prop] =
+ obj.trimLeft ||
+ function() {
+ return this.replace(rx, '')
+ }
+ }
+ })(Proto, 'trimStart')
+
+ // Ensure we have a `trimLeft` method
+ ;((obj, prop) => {
+ if (!(prop in obj && obj[prop])) {
+ obj[prop] = obj.trimStart
+ }
+ })(Proto, 'trimLeft')
+
+ // Ensure we have a `trimEnd` method
+ ;((obj, prop) => {
+ if (!(prop in obj && obj[prop])) {
+ const rx = /\s+$/
+ obj[prop] =
+ obj.trimRight ||
+ function() {
+ return this.replace(rx, '')
+ }
+ }
+ })(Proto, 'trimEnd')
+
+ // Ensure we have a `trimRight` method
+ ;((obj, prop) => {
+ if (!(prop in obj && obj[prop])) {
+ obj[prop] = obj.trimEnd
+ }
+ })(Proto, 'trimRight')
+}
+
+// Prevent Babel/Standalone from processing
+
+
+```
## Inline and stacked checkboxes
diff --git a/src/components/form-checkbox/_form-checkbox-group.scss b/src/components/form-checkbox/_form-checkbox-group.scss
index 95f35ac44ff..a65e471525b 100644
--- a/src/components/form-checkbox/_form-checkbox-group.scss
+++ b/src/components/form-checkbox/_form-checkbox-group.scss
@@ -1 +1,2 @@
+@import "../../utilities";
@import "../input-group/index";
diff --git a/src/components/form-checkbox/form-checkbox-group.spec.js b/src/components/form-checkbox/form-checkbox-group.spec.js
index 2c9e71a3500..17fe440aca7 100644
--- a/src/components/form-checkbox/form-checkbox-group.spec.js
+++ b/src/components/form-checkbox/form-checkbox-group.spec.js
@@ -17,9 +17,10 @@ describe('form-checkbox-group', () => {
wrapper.destroy()
})
- it('default has no classes on wrapper', async () => {
+ it('default has no classes on wrapper other than focus ring', async () => {
const wrapper = mount(BFormCheckboxGroup)
- expect(wrapper.classes().length).toEqual(0)
+ expect(wrapper.classes()).toContain('bv-no-focus-ring')
+ expect(wrapper.classes().length).toEqual(1)
wrapper.destroy()
})
@@ -177,9 +178,10 @@ describe('form-checkbox-group', () => {
}
})
expect(wrapper.classes()).toBeDefined()
- expect(wrapper.classes().length).toBe(2)
+ expect(wrapper.classes().length).toBe(3)
expect(wrapper.classes()).toContain('btn-group')
expect(wrapper.classes()).toContain('btn-group-toggle')
+ expect(wrapper.classes()).toContain('bv-no-focus-ring')
wrapper.destroy()
})
@@ -193,9 +195,10 @@ describe('form-checkbox-group', () => {
}
})
expect(wrapper.classes()).toBeDefined()
- expect(wrapper.classes().length).toBe(2)
+ expect(wrapper.classes().length).toBe(3)
expect(wrapper.classes()).toContain('btn-group-vertical')
expect(wrapper.classes()).toContain('btn-group-toggle')
+ expect(wrapper.classes()).toContain('bv-no-focus-ring')
wrapper.destroy()
})
@@ -209,10 +212,11 @@ describe('form-checkbox-group', () => {
}
})
expect(wrapper.classes()).toBeDefined()
- expect(wrapper.classes().length).toBe(3)
+ expect(wrapper.classes().length).toBe(4)
expect(wrapper.classes()).toContain('btn-group')
expect(wrapper.classes()).toContain('btn-group-toggle')
expect(wrapper.classes()).toContain('btn-group-lg')
+ expect(wrapper.classes()).toContain('bv-no-focus-ring')
wrapper.destroy()
})
@@ -227,10 +231,11 @@ describe('form-checkbox-group', () => {
}
})
expect(wrapper.classes()).toBeDefined()
- expect(wrapper.classes().length).toBe(3)
+ expect(wrapper.classes().length).toBe(4)
expect(wrapper.classes()).toContain('btn-group-vertical')
expect(wrapper.classes()).toContain('btn-group-toggle')
expect(wrapper.classes()).toContain('btn-group-lg')
+ expect(wrapper.classes()).toContain('bv-no-focus-ring')
wrapper.destroy()
})
diff --git a/src/components/form-file/form-file.js b/src/components/form-file/form-file.js
index 626e35eb104..367374b3a56 100644
--- a/src/components/form-file/form-file.js
+++ b/src/components/form-file/form-file.js
@@ -1,8 +1,10 @@
import Vue from '../../utils/vue'
+import identity from '../../utils/identity'
import { from as arrayFrom, isArray, concat } from '../../utils/array'
import { getComponentConfig } from '../../utils/config'
import { isFile, isFunction, isUndefinedOrNull } from '../../utils/inspect'
import { File } from '../../utils/safe-types'
+import { toString } from '../../utils/string'
import { warn } from '../../utils/warn'
import formCustomMixin from '../../mixins/form-custom'
import formMixin from '../../mixins/form'
@@ -12,6 +14,9 @@ import normalizeSlotMixin from '../../mixins/normalize-slot'
const NAME = 'BFormFile'
+const VALUE_EMPTY_DEPRECATED_MSG =
+ 'Setting "value"/"v-model" to an empty string for reset is deprecated. Set to "null" instead.'
+
// @vue/component
export const BFormFile = /*#__PURE__*/ Vue.extend({
name: NAME,
@@ -32,9 +37,7 @@ export const BFormFile = /*#__PURE__*/ Vue.extend({
validator: val => {
/* istanbul ignore next */
if (val === '') {
- warn(
- `${NAME} - setting value/v-model to an empty string for reset is deprecated. Set to 'null' instead`
- )
+ warn(VALUE_EMPTY_DEPRECATED_MSG, NAME)
return true
}
return (
@@ -106,7 +109,7 @@ export const BFormFile = /*#__PURE__*/ Vue.extend({
}
// Convert selectedFile to an array (if not already one)
- const files = concat(this.selectedFile).filter(Boolean)
+ const files = concat(this.selectedFile).filter(identity)
if (this.hasNormalizedSlot('file-name')) {
// There is a slot for formatting the files/names
@@ -119,7 +122,7 @@ export const BFormFile = /*#__PURE__*/ Vue.extend({
} else {
// Use the user supplied formatter, or the built in one.
return isFunction(this.fileNameFormatter)
- ? String(this.fileNameFormatter(files))
+ ? toString(this.fileNameFormatter(files))
: files.map(file => file.name).join(', ')
}
}
@@ -329,7 +332,7 @@ export const BFormFile = /*#__PURE__*/ Vue.extend({
class: [
this.stateClass,
{
- [`b-custom-control-${this.size}`]: Boolean(this.size)
+ [`b-custom-control-${this.size}`]: this.size
}
],
attrs: { id: this.safeId('_BV_file_outer_') },
diff --git a/src/components/form-file/package.json b/src/components/form-file/package.json
index c46d78e43be..82d7a02892c 100644
--- a/src/components/form-file/package.json
+++ b/src/components/form-file/package.json
@@ -60,7 +60,7 @@
{
"prop": "files",
"type": "Array",
- "description": "Array if File objects"
+ "description": "Array of File objects"
},
{
"prop": "names",
diff --git a/src/components/form-group/form-group.js b/src/components/form-group/form-group.js
index d2ec1d745fd..be2b47ee57c 100644
--- a/src/components/form-group/form-group.js
+++ b/src/components/form-group/form-group.js
@@ -1,12 +1,12 @@
// Utils
import memoize from '../../utils/memoize'
-import upperFirst from '../../utils/upper-first'
import { arrayIncludes } from '../../utils/array'
import { getBreakpointsUpCached } from '../../utils/config'
import { select, selectAll, isVisible, setAttr, removeAttr, getAttr } from '../../utils/dom'
import { isBrowser } from '../../utils/env'
import { isBoolean } from '../../utils/inspect'
import { keys, create } from '../../utils/object'
+import { upperFirst } from '../../utils/string'
// Mixins
import formStateMixin from '../../mixins/form-state'
import idMixin from '../../mixins/id'
@@ -126,6 +126,8 @@ const renderLabel = (h, ctx) => {
tabindex: isLegend ? '-1' : null
},
class: [
+ // Hide the focus ring on the legend
+ isLegend ? 'bv-no-focus-ring' : '',
// When horizontal or if a legend is rendered, add col-form-label
// for correct sizing as Bootstrap has inconsistent font styling
// for legend in non-horizontal form-groups.
@@ -362,7 +364,9 @@ export const BFormGroup = {
const inputs = selectAll(SELECTOR, this.$refs.content).filter(isVisible)
if (inputs && inputs.length === 1 && inputs[0].focus) {
// if only a single input, focus it, emulating label behaviour
- inputs[0].focus()
+ try {
+ inputs[0].focus()
+ } catch {}
}
},
setInputDescribedBy(add, remove) {
@@ -405,6 +409,8 @@ export const BFormGroup = {
isHorizontal ? BCol : 'div',
{
ref: 'content',
+ // Hide focus ring
+ staticClass: 'bv-no-focus-ring',
attrs: {
tabindex: isFieldset ? '-1' : null,
role: isFieldset ? 'group' : null
diff --git a/src/components/form-group/form-group.spec.js b/src/components/form-group/form-group.spec.js
index 1da10e729ec..2e4b04b1769 100644
--- a/src/components/form-group/form-group.spec.js
+++ b/src/components/form-group/form-group.spec.js
@@ -118,7 +118,8 @@ describe('form-group', () => {
expect(wrapper.find('label').attributes('for')).toBeDefined()
expect(wrapper.find('label').attributes('for')).toEqual('input-id')
expect(wrapper.find('div > div').exists()).toBe(true)
- expect(wrapper.find('div > div').classes().length).toBe(0)
+ expect(wrapper.find('div > div').classes()).toContain('bv-no-focus-ring')
+ expect(wrapper.find('div > div').classes().length).toBe(1)
expect(wrapper.find('div > div').attributes('role')).not.toBeDefined()
expect(wrapper.find('div > div').attributes('tabindex')).not.toBeDefined()
expect(wrapper.find('div > div > input').exists()).toBe(true)
@@ -169,7 +170,8 @@ describe('form-group', () => {
expect(wrapper.find('label').text()).toEqual('test')
expect(wrapper.find('div > div').exists()).toBe(true)
expect(wrapper.find('div > div').classes()).toContain('col')
- expect(wrapper.find('div > div').classes().length).toBe(1)
+ expect(wrapper.find('div > div').classes()).toContain('bv-no-focus-ring')
+ expect(wrapper.find('div > div').classes().length).toBe(2)
wrapper.destroy()
})
@@ -208,11 +210,13 @@ describe('form-group', () => {
expect(wrapper.find('legend').classes()).toContain('col-md-3')
expect(wrapper.find('legend').classes()).toContain('col-lg-4')
expect(wrapper.find('legend').classes()).toContain('col-xl-5')
- expect(wrapper.find('legend').classes().length).toBe(6)
+ expect(wrapper.find('legend').classes()).toContain('bv-no-focus-ring')
+ expect(wrapper.find('legend').classes().length).toBe(7)
expect(wrapper.find('legend').text()).toEqual('test')
expect(wrapper.find('fieldset > div > div').exists()).toBe(true)
expect(wrapper.find('fieldset > div > div').classes()).toContain('col')
- expect(wrapper.find('fieldset > div > div').classes().length).toBe(1)
+ expect(wrapper.find('fieldset > div > div').classes()).toContain('bv-no-focus-ring')
+ expect(wrapper.find('fieldset > div > div').classes().length).toBe(2)
expect(wrapper.find('fieldset > div > div').attributes('role')).toEqual('group')
expect(wrapper.find('fieldset > div > div').attributes('tabindex')).toEqual('-1')
diff --git a/src/components/form-input/README.md b/src/components/form-input/README.md
index 34ddf6c1807..aacf4505949 100644
--- a/src/components/form-input/README.md
+++ b/src/components/form-input/README.md
@@ -75,7 +75,7 @@ rendered and a console warning will be issued.
**Caveats with input types:**
- Not all browsers support all input types, nor do some types render in the same format across
- browser types/versions.
+ browser types/versions. Refer to [caniuse.com](https://caniuse.com/#search=input).
- Browsers that do not support a particular type will fall back to a `text` input type (even though
the rendered `type` attribute markup shows the requested type).
- No testing is performed to see if the requested input type is supported by the browser.
@@ -90,7 +90,7 @@ rendered and a console warning will be issued.
prop instead.
- `v-model` modifiers `.number` and `.trim` can cause unexpected cursor jumps when the user is
typing (this is a Vue issue with `v-model` on custom components). _Avoid using these modifiers_.
- Use the `number` or `trip` props instead.
+ Use the `number` or `trim` props instead.
- Older version of Firefox may not support `readonly` for `range` type inputs.
- Input types that do not support `min`, `max` and `step` (i.e. `text`, `password`, `tel`, `email`,
`url`, etc) will silently ignore these values (although they will still be rendered on the input
diff --git a/src/components/form-radio/README.md b/src/components/form-radio/README.md
index 4467e5d9d12..de1913d896f 100644
--- a/src/components/form-radio/README.md
+++ b/src/components/form-radio/README.md
@@ -130,8 +130,124 @@ To have them appear _above_ the inputs generated by `options`, place them in the
## Radio group options array
-Please see the [`` `options` prop](/docs/components/form-select#options-property)
-docs for details on the formats and helper props associated with `options`.
+`options` can be an array of strings or objects. Available fields:
+
+- **`value`** The selected value which will be set on `v-model`
+- **`disabled`** Disables item for selection
+- **`text`** Display text, or **`html`** Display basic inline html
+
+`value` can be a string, number, or simple object. Avoid using complex types in values.
+
+If both `html` and `text` are provided, `html` will take precedence. Only basic/native HTML is
+supported in the `html` field (components will not work). Note that not all browsers will render
+inline html (i.e. ``, ``, etc) inside `