diff --git a/.bundlewatch.config.json b/.bundlewatch.config.json index bb6383bcf9a..810e7c16e9a 100644 --- a/.bundlewatch.config.json +++ b/.bundlewatch.config.json @@ -2,27 +2,27 @@ "files": [ { "path": "./dist/bootstrap-vue-icons.js", - "maxSize": "105 kB" + "maxSize": "110 kB" }, { "path": "./dist/bootstrap-vue-icons.min.js", - "maxSize": "100 kB" + "maxSize": "105 kB" }, { "path": "./dist/bootstrap-vue-icons.common.js", - "maxSize": "110 kB" + "maxSize": "120 kB" }, { "path": "./dist/bootstrap-vue-icons.common.min.js", - "maxSize": "105 kB" + "maxSize": "110 kB" }, { "path": "./dist/bootstrap-vue-icons.esm.js", - "maxSize": "110 kB" + "maxSize": "115 kB" }, { "path": "./dist/bootstrap-vue-icons.esm.min.js", - "maxSize": "105 kB" + "maxSize": "110 kB" }, { "path": "./dist/bootstrap-vue-icons.css", @@ -34,27 +34,27 @@ }, { "path": "./dist/bootstrap-vue.js", - "maxSize": "230 kB" + "maxSize": "235 kB" }, { "path": "./dist/bootstrap-vue.min.js", - "maxSize": "100 kB" + "maxSize": "105 kB" }, { "path": "./dist/bootstrap-vue.common.js", - "maxSize": "305 kB" + "maxSize": "320 kB" }, { "path": "./dist/bootstrap-vue.common.min.js", - "maxSize": "190 kB" + "maxSize": "200 kB" }, { "path": "./dist/bootstrap-vue.esm.js", - "maxSize": "300 kB" + "maxSize": "320 kB" }, { "path": "./dist/bootstrap-vue.esm.min.js", - "maxSize": "190 kB" + "maxSize": "200 kB" }, { "path": "./dist/bootstrap-vue.css", diff --git a/.eslintrc.js b/.eslintrc.js index 8116ec010d8..57ae0371404 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -22,6 +22,7 @@ module.exports = { ignoreRestSiblings: false } ], + 'object-shorthand': ['error', 'properties'], 'spaced-comment': 'off', // needed to ignore `/*#__PURE__*/` comments 'vue/html-self-closing': [ 'error', diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b07f6a1582b..af29b8818b5 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`, `chore(docs): fix typo in README`, etc). **This is very important, as the `CHANGELOG` is generated from these messages, and determines the next version type (patch or minor).** +- [ ] 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, and determines the next version type (patch or minor).** **If new features/enhancement/fixes are added or changed:** diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fbe23e4d0c..aa53872153f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,167 @@ # Changelog -> All notable changes to this project will be documented in this file. +All notable changes to this project will be documented in this file. See +[standard-version](https://github.com/conventional-changelog/standard-version) for commit +guidelines. + + + +## [v2.17.0](https://github.com/bootstrap-vue/bootstrap-vue/compare/v2.16.0...v2.17.0) (2020-09-13) + +Released: 2020-09-13 + +### Features v2.17.0 + +- **b-avatar:** add size classes for `sm` and `lg` sizes (closes + [#5592](https://github.com/bootstrap-vue/bootstrap-vue/issues/5592)) + ([#5768](https://github.com/bootstrap-vue/bootstrap-vue/issues/5768)) + ([942bf31](https://github.com/bootstrap-vue/bootstrap-vue/commit/942bf31546179abce8f0bb8252f8716c85c6de86)) +- **b-calendar:** add `nav-button-variant` prop (closes + [#5702](https://github.com/bootstrap-vue/bootstrap-vue/issues/5702)) + ([#5705](https://github.com/bootstrap-vue/bootstrap-vue/issues/5705)) + ([aa291fc](https://github.com/bootstrap-vue/bootstrap-vue/commit/aa291fce6df52df4d2396b9499c964ce0ac5962b)) +- **b-form-file:** improved drag and drop handling (closes + [#3673](https://github.com/bootstrap-vue/bootstrap-vue/issues/3673)) + ([#5727](https://github.com/bootstrap-vue/bootstrap-vue/issues/5727)) + ([3b12a73](https://github.com/bootstrap-vue/bootstrap-vue/commit/3b12a73d3856a0b14f630d45d236570698b75e50)) +- **b-icon:** add proper `title` support (closes + [#5711](https://github.com/bootstrap-vue/bootstrap-vue/issues/5711)) + ([#5724](https://github.com/bootstrap-vue/bootstrap-vue/issues/5724)) + ([3756b2c](https://github.com/bootstrap-vue/bootstrap-vue/commit/3756b2c0e07fc85f73769ea312ede8917d1e1de5)) +- **b-pagination/b-pagination-nav:** allow page change to be prevented (closes + [#5679](https://github.com/bootstrap-vue/bootstrap-vue/issues/5679)) + ([#5755](https://github.com/bootstrap-vue/bootstrap-vue/issues/5755)) + ([7e18c61](https://github.com/bootstrap-vue/bootstrap-vue/commit/7e18c615fec871fb99a947ca5e247bcef04b7c6f)) +- **b-sidebar:** add `noEnforceFocus` prop (closes + [#5707](https://github.com/bootstrap-vue/bootstrap-vue/issues/5707)) + ([#5734](https://github.com/bootstrap-vue/bootstrap-vue/issues/5734)) + ([c11c237](https://github.com/bootstrap-vue/bootstrap-vue/commit/c11c237143230f533404af75933d86a2de7bfb56)) +- **b-skeleton:** add skeleton components (closes + [#5413](https://github.com/bootstrap-vue/bootstrap-vue/issues/5413)) + ([#5575](https://github.com/bootstrap-vue/bootstrap-vue/issues/5575)) + ([31c06b5](https://github.com/bootstrap-vue/bootstrap-vue/commit/31c06b5fa697b5f13cc888a1d72effae21eb5e73)) +- **b-table:** add `sortKey` option for `no-local-sorting` events + ([#5746](https://github.com/bootstrap-vue/bootstrap-vue/issues/5746)) + ([f847dae](https://github.com/bootstrap-vue/bootstrap-vue/commit/f847daeb797b84ed80b49a31294a5088fc32b59d)) +- **b-tags:** add `limit` prop ([#5543](https://github.com/bootstrap-vue/bootstrap-vue/issues/5543)) + ([caa0f1a](https://github.com/bootstrap-vue/bootstrap-vue/commit/caa0f1a2e6d96637c216eb306c77a67254af1caf)) +- **docs:** auto-detect settings props in component reference + ([#5761](https://github.com/bootstrap-vue/bootstrap-vue/issues/5761)) + ([0ddb2e0](https://github.com/bootstrap-vue/bootstrap-vue/commit/0ddb2e051c0ce42bdd599415ba93e82e1a6584f1)) + +### Bug Fixes v2.17.0 + +- **b-avatar:** image fit and scale (closes + [#5610](https://github.com/bootstrap-vue/bootstrap-vue/issues/5610), + [#5655](https://github.com/bootstrap-vue/bootstrap-vue/issues/5655)) + ([#5675](https://github.com/bootstrap-vue/bootstrap-vue/issues/5675)) + ([9812248](https://github.com/bootstrap-vue/bootstrap-vue/commit/9812248ea686e339f32604c0020a1714bb228d75)) +- **b-button-toolbar:** allow focus to leave toolbar by keyboard + ([#5737](https://github.com/bootstrap-vue/bootstrap-vue/issues/5737)) + ([f54e427](https://github.com/bootstrap-vue/bootstrap-vue/commit/f54e4275881947cfb504235aa9330c03444e08bb)) +- **b-form-checkbox:** `change` event value when in multiple mode + ([#5716](https://github.com/bootstrap-vue/bootstrap-vue/issues/5716)) + ([5150b94](https://github.com/bootstrap-vue/bootstrap-vue/commit/5150b943f25ff6b2f331aaef64321973bd60dd0e)) +- **b-form-checkbox/b-form-radio:** remove `autocomplete="off"` attribute + ([#5764](https://github.com/bootstrap-vue/bootstrap-vue/issues/5764)) + ([443aaf1](https://github.com/bootstrap-vue/bootstrap-vue/commit/443aaf1afc38dc029e0b142c11a39d360bbc98d2)) +- **b-form-datepicker/b-form-timepicker/b-nav-item-dropdown:** dropdown positioning handling (closes + [#5700](https://github.com/bootstrap-vue/bootstrap-vue/issues/5700), + [#5630](https://github.com/bootstrap-vue/bootstrap-vue/issues/5630)) + ([#5765](https://github.com/bootstrap-vue/bootstrap-vue/issues/5765)) + ([7ec2205](https://github.com/bootstrap-vue/bootstrap-vue/commit/7ec2205a96e0d14772f1ed6c047a9808a32fbf82)) +- **b-form-file:** drop handling for huge amounts of files (closes + [#5615](https://github.com/bootstrap-vue/bootstrap-vue/issues/5615)) + ([#5685](https://github.com/bootstrap-vue/bootstrap-vue/issues/5685)) + ([d54b240](https://github.com/bootstrap-vue/bootstrap-vue/commit/d54b240adeb6eadfe8736f4926384a5c4d351bde)) +- **b-form-input:** fix debounce when value does not change + ([#5632](https://github.com/bootstrap-vue/bootstrap-vue/issues/5632)) + ([111ca65](https://github.com/bootstrap-vue/bootstrap-vue/commit/111ca65240ab6941e2173ca44806aa0a75691c95)) +- **b-form-tags:** ensure same height with or without tags + ([#5752](https://github.com/bootstrap-vue/bootstrap-vue/issues/5752)) + ([07102f9](https://github.com/bootstrap-vue/bootstrap-vue/commit/07102f988cfe8e8290189e73f50790f70bbb4639)) +- **b-form-textarea:** `setStyle()` util usage + ([bf7a65f](https://github.com/bootstrap-vue/bootstrap-vue/commit/bf7a65f87caf0d725033c35ee85c1e32ced82adc)) +- **b-pagination:** properly calculate number of links with `hide-ellipsis` option (closes + [#5514](https://github.com/bootstrap-vue/bootstrap-vue/issues/5514)) + ([#5678](https://github.com/bootstrap-vue/bootstrap-vue/issues/5678)) + ([98e17ca](https://github.com/bootstrap-vue/bootstrap-vue/commit/98e17ca85588b858f5d74e217c48fa82f11f487f)) +- **bv-tooltip:** hide the tooltip when the title is set to empty (closes + [#5648](https://github.com/bootstrap-vue/bootstrap-vue/issues/5648)) + ([#5677](https://github.com/bootstrap-vue/bootstrap-vue/issues/5677)) + ([5363a31](https://github.com/bootstrap-vue/bootstrap-vue/commit/5363a3132df898cb5f0cac172c0510aead62d66e)) +- **perf:** reactivity issues with `bvAttrs` and `bvListeners` (closes + [#5520](https://github.com/bootstrap-vue/bootstrap-vue/issues/5520)) + ([#5753](https://github.com/bootstrap-vue/bootstrap-vue/issues/5753)) + ([d83a2b1](https://github.com/bootstrap-vue/bootstrap-vue/commit/d83a2b179cac2f7449a7138fce71e07139e18c94)) +- **v-b-toggle:** prevent scroll anchoring behavior (closes + [#5715](https://github.com/bootstrap-vue/bootstrap-vue/issues/5715)) + ([#5769](https://github.com/bootstrap-vue/bootstrap-vue/issues/5769)) + ([390a5c7](https://github.com/bootstrap-vue/bootstrap-vue/commit/390a5c7045432c98999ae8bf9259fb9ae03bcb19)) +- component destroy handling on parent destroy + ([#5749](https://github.com/bootstrap-vue/bootstrap-vue/issues/5749)) + ([e67d341](https://github.com/bootstrap-vue/bootstrap-vue/commit/e67d34190358cb5e9d3e6d45ec74f045bf20caef)) +- don't display BootstrapVue warning messages when in production + ([bf8966f](https://github.com/bootstrap-vue/bootstrap-vue/commit/bf8966f6de725bf2828ca4609056c27dd4a96399)) +- don't display warning messages when in production (closes + [#5598](https://github.com/bootstrap-vue/bootstrap-vue/issues/5598)) + ([#5763](https://github.com/bootstrap-vue/bootstrap-vue/issues/5763)) + ([4b5d916](https://github.com/bootstrap-vue/bootstrap-vue/commit/4b5d9162b8a6531c0ada66f646498b0ba40a0e9b)) +- **b-table:** make sure to apply all formatters of field configuration (closes + [#5672](https://github.com/bootstrap-vue/bootstrap-vue/issues/5672)) + ([#5674](https://github.com/bootstrap-vue/bootstrap-vue/issues/5674)) + ([c7c14ea](https://github.com/bootstrap-vue/bootstrap-vue/commit/c7c14ea1d023b26af8a12c12dbc2c3d8220b7f67)) +- **ssr:** avoid tree missmatches by either using `domProps` or `children` (closes + [#5453](https://github.com/bootstrap-vue/bootstrap-vue/issues/5453), + [#5557](https://github.com/bootstrap-vue/bootstrap-vue/issues/5557)) + ([#5723](https://github.com/bootstrap-vue/bootstrap-vue/issues/5723)) + ([5e8dad8](https://github.com/bootstrap-vue/bootstrap-vue/commit/5e8dad84c094ff1f7810f69293418b81e676af26)) +- **v-b-toggle:** handle component updates on click listeners + ([#5690](https://github.com/bootstrap-vue/bootstrap-vue/issues/5690)) + ([156b1d6](https://github.com/bootstrap-vue/bootstrap-vue/commit/156b1d6a3a1ebb6548ea0dbfac346d61a92f6ed9)) + + + +## [v2.16.0](https://github.com/bootstrap-vue/bootstrap-vue/compare/v2.15.0...v2.16.0) (2020-07-27) + +Released: 2020-07-27 + +### Features v2.16.0 + +- **b-form-tags:** add `ignoreInputFocusSelector` prop to make input focus behavior configurable + (closes [#5425](https://github.com/bootstrap-vue/bootstrap-vue/issues/5425)) + ([#5429](https://github.com/bootstrap-vue/bootstrap-vue/issues/5429)) + ([26d5953](https://github.com/bootstrap-vue/bootstrap-vue/commit/26d5953f834684d36b0af99da912dba08fd37bd8)) +- **docs:** launch themes page with first BootstrapVue theme + ([#5549](https://github.com/bootstrap-vue/bootstrap-vue/issues/5549)) + ([ec51ef0](https://github.com/bootstrap-vue/bootstrap-vue/commit/ec51ef062f7ed39339cde59b2d9d4cee40347dcc)) + +### Bug Fixes v2.16.0 + +- properly handle special characters in user-provided IDs (closes + [#4927](https://github.com/bootstrap-vue/bootstrap-vue/issues/4927), + [#5561](https://github.com/bootstrap-vue/bootstrap-vue/issues/5561)) + ([#5564](https://github.com/bootstrap-vue/bootstrap-vue/issues/5564)) + ([1fabd68](https://github.com/bootstrap-vue/bootstrap-vue/commit/1fabd68bb44b28a9127810f35bd07e1fdf3d12ec)) +- **b-form-checkbox-group:** only emit `input` when value loosely changes + ([#5432](https://github.com/bootstrap-vue/bootstrap-vue/issues/5432)) + ([e76d408](https://github.com/bootstrap-vue/bootstrap-vue/commit/e76d40874bd2a42126162101e94bb18e9042840b)) +- **b-form-tags:** unit test ([#5586](https://github.com/bootstrap-vue/bootstrap-vue/issues/5586)) + ([f4d509a](https://github.com/bootstrap-vue/bootstrap-vue/commit/f4d509af647eaf87e2b635d08ff9431b25150650)) +- **b-icon:** use `aria-label` attribute instead of `alt` + ([#5581](https://github.com/bootstrap-vue/bootstrap-vue/issues/5581)) + ([72a1363](https://github.com/bootstrap-vue/bootstrap-vue/commit/72a13635b94aedfab1fb6800f2a297fa306f63ef)) +- **b-img:** Allow empty `alt` prop (fixes + [#5524](https://github.com/bootstrap-vue/bootstrap-vue/issues/5524)) + ([#5545](https://github.com/bootstrap-vue/bootstrap-vue/issues/5545)) + ([b22829d](https://github.com/bootstrap-vue/bootstrap-vue/commit/b22829d064b6e3820ef66168ec766a57520f31eb)) +- **b-table:** prevent endless reevaluation when using v-model and object/array literal prop values + ([#5554](https://github.com/bootstrap-vue/bootstrap-vue/issues/5554)) + ([f127d91](https://github.com/bootstrap-vue/bootstrap-vue/commit/f127d916d1ddd3a3da37bcb081150f86b356a7a4)) +- **b-tags:** replace spacing utility with static CSS (fixes + [#5523](https://github.com/bootstrap-vue/bootstrap-vue/issues/5523)) + ([#5544](https://github.com/bootstrap-vue/bootstrap-vue/issues/5544)) + ([e0de687](https://github.com/bootstrap-vue/bootstrap-vue/commit/e0de6871640db405e7b0bfa23f3c33f348894cea)) @@ -1153,7 +1314,7 @@ Read the following migration guide for more details. - `b-table`: the `filter` prop will no longer accept a function reference (previously deprecated). Instead, pass a function to the `filter-function` prop when using a custom filter function. The prop `filter` is only to be used for the filter's _criteria_ (i.e. the search value, search - `RegExpr`, etc). + `RegExpr`, etc.). - `b-table`: passing an object as a `fields` definition will no longer work. Use the _array of strings_ or _array of objects_ (or a combination of the two) fields definition format instead. - `b-table`: sorting icon SASS variables have been changed to handle the new SVG backgrounds. If you diff --git a/docs/assets/scss/styles.scss b/docs/assets/scss/styles.scss index 127fbfa05fe..b0e31576cc5 100644 --- a/docs/assets/scss/styles.scss +++ b/docs/assets/scss/styles.scss @@ -36,7 +36,7 @@ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - &:after { + &::after { content: "#"; } } diff --git a/docs/common-props.json b/docs/common-props.json index 25cb814ad55..6267ab2c657 100644 --- a/docs/common-props.json +++ b/docs/common-props.json @@ -1,6 +1,6 @@ { "id": { - "description": "Used to set the 'id' attribute on the rendered content, and used as the base to generate any additional element IDs as needed" + "description": "Used to set the `id` attribute on the rendered content, and used as the base to generate any additional element IDs as needed" }, "variant": { "description": "Applies one of the Bootstrap theme color variants to the component" @@ -114,22 +114,22 @@ "description": "Set the size of the component's appearance. 'sm', 'md' (default), or 'lg'" }, "required": { - "description": "Adds the 'required' attribute to the form control" + "description": "Adds the `required` attribute to the form control" }, "form": { - "description": "ID of the form that the form control belongs to. Sets the 'form' attribute on the control" + "description": "ID of the form that the form control belongs to. Sets the `form` attribute on the control" }, "name": { - "description": "Sets the value of the 'name' attribute on the form control" + "description": "Sets the value of the `name` attribute on the form control" }, "placeholder": { - "description": "Sets the 'placeholder' attribute value on the form control" + "description": "Sets the `placeholder` attribute value on the form control" }, "disabled": { "description": "When set to 'true', disables the component's functionality and places it in a disabled state" }, "readonly": { - "description": "Sets the 'readonly' attribute on the form control" + "description": "Sets the `readonly` attribute on the form control" }, "plaintext": { "description": "Set the form control as readonly and renders the control to look like plain text (no borders)" @@ -138,25 +138,25 @@ "description": "Sets the 'autocomplete' attribute value on the form control" }, "autofocus": { - "description": "When set to 'true', attempts to auto-focus the control when it is mounted, or re-activated when in a keep-alive. Does not set the 'autofocus' attribute on the control" + "description": "When set to `true`, attempts to auto-focus the control when it is mounted, or re-activated when in a keep-alive. Does not set the `autofocus` attribute on the control" }, "state": { - "description": "Controls the validation state appearance of the component. 'true' for valid, 'false' for invalid', or 'null' for no validation state" + "description": "Controls the validation state appearance of the component. `true` for valid, `false` for invalid, or `null` for no validation state" }, "options": { "description": "Array of items to render in the component" }, "valueField": { - "description": "Field name in the 'options' array that should be used for the value" + "description": "Field name in the `options` array that should be used for the value" }, "textField": { - "description": "Field name in the 'options' array that should be used for the text label" + "description": "Field name in the `options` array that should be used for the text label" }, "htmlField": { - "description": "Field name in the 'options' array that should be used for the html label instead of text field. Use with caution." + "description": "Field name in the `options` array that should be used for the html label instead of text field. Use with caution" }, "disabledField": { - "description": "Field name in the 'options' array that should be used for the disabled state" + "description": "Field name in the `options` array that should be used for the disabled state" }, "plain": { "description": "Render the form control in plain mode, rather than custom styled mode" @@ -165,52 +165,52 @@ "description": "Renders the content of the component in-place in the DOM, rather than portalling it to be appended to the body element" }, "src": { - "description": "URL to set for the 'src' attribute" + "description": "URL to set for the `src` attribute" }, "alt": { - "description": "Value to set for the 'alt' attribute" + "description": "Value to set for the `alt` attribute" }, "role": { - "description": "Sets the ARIA attribute 'role' to a specific value" + "description": "Sets the ARIA attribute `role` to a specific value" }, "ariaRole": { - "description": "Sets the ARIA attribute 'role' to a specific value" + "description": "Sets the ARIA attribute `role` to a specific value" }, "ariaLabel": { - "description": "Sets the value of 'aria-label' attribute on the rendered element" + "description": "Sets the value of `aria-label` attribute on the rendered element" }, "ariaLabelledby": { - "description": "The ID of the element that provides a label for this component. Used as the value for the 'aria-labelledby' attribute" + "description": "The ID of the element that provides a label for this component. Used as the value for the `aria-labelledby` attribute" }, "ariaDescribedby": { - "description": "The ID of the element that provides additional context for this component. Used as the value for the 'aria-describedby' attribute" + "description": "The ID of the element that provides additional context for this component. Used as the value for the `aria-describedby` attribute" }, "ariaLive": { - "description": "When the rendered element is an aria-live region (for screen reader users), set to either 'polite' or 'assertive'" + "description": "When the rendered element is an `aria-live` region (for screen reader users), set to either 'polite' or 'assertive'" }, "fade": { - "description": "When set to 'true', enables the fade animation/transition on the component" + "description": "When set to `true`, enables the fade animation/transition on the component" }, "noFade": { - "description": "When set to 'true', disables the fade animation/transition on the component" + "description": "When set to `true`, disables the fade animation/transition on the component" }, "active": { - "description": "When set to 'true', places the component in the active state with active styling" + "description": "When set to `true`, places the component in the active state with active styling" }, "href": { "description": " prop: Denotes the target URL of the link for standard a links" }, "rel": { - "description": " prop: Sets the 'rel' attribute on the rendered link" + "description": " prop: Sets the `rel` attribute on the rendered link" }, "target": { - "description": " prop: Sets the 'target' attribute on the rendered link" + "description": " prop: Sets the `target` attribute on the rendered link" }, "to": { - "description": " prop: Denotes the target route of the link. When clicked, the value of the to prop will be passed to router.push() internally, so the value can be either a string or a Location descriptor object" + "description": " prop: Denotes the target route of the link. When clicked, the value of the to prop will be passed to `router.push()` internally, so the value can be either a string or a Location descriptor object" }, "replace": { - "description": " prop: Setting the replace prop will call 'router.replace()' instead of 'router.push()' when clicked, so the navigation will not leave a history record" + "description": " prop: Setting the replace prop will call `router.replace()` instead of `router.push()` when clicked, so the navigation will not leave a history record" }, "append": { "description": " prop: Setting append prop always appends the relative path to the current path" @@ -225,21 +225,20 @@ "description": " prop: Configure the active CSS class applied when the link is active with exact match. Typically you will want to set this to class name 'active'" }, "routerTag": { - "description": " prop: Specify which tag to render, and it will still listen to click events for navigation. 'router-tag' translates to the tag prop on the final rendered router-link. Typically you should use the default value" + "description": " prop: Specify which tag to render, and it will still listen to click events for navigation. `router-tag` translates to the tag prop on the final rendered ``. Typically you should use the default value" }, "event": { "description": " prop: Specify the event that triggers the link. In most cases you should leave this as the default" }, "prefetch": { - "description": " 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": " 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": " 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" + "description": " 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" }, "routerComponentName": { "description": " prop: BootstrapVue auto detects between `` and ``. In cases where you want to use a 3rd party link component based on ``, set this prop to the component name. e.g. set it to 'g-link' if you are using Gridsome (note only `` specific props are passed to the component)", - "version": "2.15.0", - "settings": true + "version": "2.15.0" } } diff --git a/docs/components/componentdoc.vue b/docs/components/componentdoc.vue index db5b0f13544..c415abe3da1 100644 --- a/docs/components/componentdoc.vue +++ b/docs/components/componentdoc.vue @@ -320,8 +320,8 @@ ul.component-ref-mini-toc:empty { + + +``` + ## Custom rendering with default scoped slot If you fancy a different look and feel for the tags control, you can provide your own custom @@ -344,17 +376,23 @@ The default slot scope properties are as follows: | `invalidTags` | Array | Array of the invalid tag(s) the user has entered | | `isDuplicate` | Boolean | `true` if the user input contains duplicate tag(s) | | `duplicateTags` | Array | Array of the duplicate tag(s) the user has entered | +| `isLimitReached` | Boolean | v2.17.0+ `true` if a `limit` is configured and the amount of tags has reached the limit | | `disableAddButton` | Boolean | Will be `true` if the tag(s) in the input cannot be added (all invalid and/or duplicates) | | `disabled` | Boolean | `true` if the component is in the disabled state. Value of the `disabled` prop | | `state` | Boolean | The contextual state of the component. Value of the `state` prop. Possible values are `true`, `false` or `null` | | `size` | String | The value of the `size` prop | +| `limit` | String | v2.17.0+ The value of the `limit` prop | | `separator` | String | The value of the `separator` prop | | `placeholder` | String | The value of the `placeholder` prop | | `tagRemoveLabel` | String | Value of the `tag-remove-label` prop. Used as the `aria-label` attribute on the remove button of tags | | `tagVariant` | String | The value of the `tag-variant` prop | +| `tagPills` | Boolean | The value of the `tag-pills` prop | | `tagClass` | String, Array, or Object | The value of the `tag-variant` prop. Class (or classes) to apply to the tag elements | | `addButtonText` | String | The value of the `add-button-text` prop | | `addButtonVariant` | String | The value of the `add-button-variant` prop | +| `invalidTagText` | String | The value of the `invalid-tag-text` prop | +| `duplicateTagText` | String | The value of the `duplicate-tag-text` prop | +| `limitTagsText` | String | v2.17.0+ The value of the `limit-tags-text` prop | #### `inputAttrs` object properties diff --git a/src/components/form-tags/_form-tags.scss b/src/components/form-tags/_form-tags.scss index dcf5382b441..6e76e3747e9 100644 --- a/src/components/form-tags/_form-tags.scss +++ b/src/components/form-tags/_form-tags.scss @@ -2,6 +2,7 @@ .b-form-tags-list { margin-top: -0.25rem; + .b-from-tags-field, .b-form-tag { margin-top: 0.25rem; } diff --git a/src/components/form-tags/form-tags.js b/src/components/form-tags/form-tags.js index 725633299fe..3fccb641c48 100644 --- a/src/components/form-tags/form-tags.js +++ b/src/components/form-tags/form-tags.js @@ -16,7 +16,8 @@ import { requestAF, select } from '../../utils/dom' -import { isEvent, isFunction, isString } from '../../utils/inspect' +import { stopEvent } from '../../utils/events' +import { isEvent, isFunction, isNumber, isString } from '../../utils/inspect' import { escapeRegExp, toString, trim, trimLeft } from '../../utils/string' import idMixin from '../../mixins/id' import normalizeSlotMixin from '../../mixins/normalize-slot' @@ -160,6 +161,14 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({ type: String, default: () => getComponentConfig(NAME, 'invalidTagText') }, + limitTagsText: { + type: String, + default: () => getComponentConfig(NAME, 'limitTagsText') + }, + limit: { + type: Number + // default: null + }, separator: { // Character (or characters) that trigger adding tags type: [String, Array] @@ -288,6 +297,10 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({ }, hasInvalidTags() { return this.invalidTags.length > 0 + }, + isLimitReached() { + const { limit } = this + return isNumber(limit) && limit >= 0 && this.tags.length >= limit } }, watch: { @@ -328,7 +341,7 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({ addTag(newTag) { newTag = isString(newTag) ? newTag : this.newTag /* istanbul ignore next */ - if (this.disabled || trim(newTag) === '') { + if (this.disabled || trim(newTag) === '' || this.isLimitReached) { // Early exit return } @@ -424,7 +437,7 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({ /* istanbul ignore else: testing to be added later */ if (!this.noAddOnEnter && keyCode === ENTER) { // Attempt to add the tag when user presses enter - evt.preventDefault() + stopEvent(evt, { propagation: false }) this.addTag() } else if ( this.removeOnDelete && @@ -432,7 +445,7 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({ value === '' ) { // Remove the last tag if the user pressed backspace/delete and the input is empty - evt.preventDefault() + stopEvent(evt, { propagation: false }) this.tags = this.tags.slice(0, -1) } }, @@ -530,25 +543,27 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({ // Default User Interface render defaultRender({ tags, - addTag, - removeTag, - inputType, inputAttrs, + inputType, inputHandlers, - inputClass, - tagClass, - tagVariant, - tagPills, - tagRemoveLabel, - invalidTagText, - duplicateTagText, + removeTag, + addTag, isInvalid, isDuplicate, + isLimitReached, + disableAddButton, disabled, placeholder, + inputClass, + tagRemoveLabel, + tagVariant, + tagPills, + tagClass, addButtonText, addButtonVariant, - disableAddButton + invalidTagText, + duplicateTagText, + limitTagsText }) { const h = this.$createElement @@ -558,19 +573,19 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({ return h( BFormTag, { - key: `li-tag__${tag}`, class: tagClass, props: { // `BFormTag` will auto generate an ID // so we do not need to set the ID prop tag: 'li', title: tag, - disabled: disabled, + disabled, variant: tagVariant, pill: tagPills, removeLabel: tagRemoveLabel }, - on: { remove: () => removeTag(tag) } + on: { remove: () => removeTag(tag) }, + key: `tags_${tag}` }, tag ) @@ -581,12 +596,15 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({ invalidTagText && isInvalid ? this.safeId('__invalid_feedback__') : null const duplicateFeedbackId = duplicateTagText && isDuplicate ? this.safeId('__duplicate_feedback__') : null + const limitFeedbackId = + limitTagsText && isLimitReached ? this.safeId('__limit_feedback__') : null // Compute the `aria-describedby` attribute value const ariaDescribedby = [ inputAttrs['aria-describedby'], invalidFeedbackId, - duplicateFeedbackId + duplicateFeedbackId, + limitFeedbackId ] .filter(identity) .join(' ') @@ -623,47 +641,59 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({ invisible: disableAddButton }, style: { fontSize: '90%' }, - props: { variant: addButtonVariant, disabled: disableAddButton }, + props: { + variant: addButtonVariant, + disabled: disableAddButton || isLimitReached + }, on: { click: () => addTag() } }, [this.normalizeSlot('add-button-text') || addButtonText] ) - // ID of the tags+input `