From 8e5b3286c293e8e2f56f487bb7d42c5e45cc2c07 Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Mon, 9 Mar 2020 22:32:59 -0300 Subject: [PATCH 01/24] feat(b-form-datepicker, b-form-timepicker): add support for icon button only mode (closes #4888) --- src/utils/bv-form-btn-label-control.js | 40 +++++++++++++++++++++----- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/src/utils/bv-form-btn-label-control.js b/src/utils/bv-form-btn-label-control.js index a4da96620b8..b5ccd321ffc 100644 --- a/src/utils/bv-form-btn-label-control.js +++ b/src/utils/bv-form-btn-label-control.js @@ -83,6 +83,16 @@ export const BVFormBtnLabelControl = /*#__PURE__*/ Vue.extend({ // Vue coerces `undefined` into Boolean `false` default: null }, + buttonOnly: { + // When true, renders a btn-group wrapper and visually hides the label + type: Boolean, + default: false + }, + buttonVariant: { + // Applicable in button mode only + type: String, + default: 'secondary' + }, menuClass: { // Extra classes to apply to the `dropdown-menu` div type: [String, Array, Object] @@ -152,14 +162,22 @@ export const BVFormBtnLabelControl = /*#__PURE__*/ Vue.extend({ const size = this.size const value = toString(this.value) || '' const labelSelected = this.labelSelected + const buttonOnly = !!this.buttonOnly + const buttonVariant = this.buttonVariant const btnScope = { isHovered, hasFocus, state, opened: visible } const $button = h( 'button', { ref: 'toggle', - staticClass: 'btn border-0 h-auto py-0', - class: { [`btn-${size}`]: !!size }, + staticClass: 'btn', + class: { + [`btn-${buttonVariant}`]: buttonOnly, + [`btn-${size}`]: !!size, + 'border-0': !buttonOnly, + 'h-auto': !buttonOnly, + 'py-0': !buttonOnly + }, attrs: { id: idButton, type: 'button', @@ -231,6 +249,8 @@ export const BVFormBtnLabelControl = /*#__PURE__*/ Vue.extend({ { staticClass: 'form-control text-break text-wrap border-0 bg-transparent h-auto pl-1 m-0', class: { + // Hidden in button only mode + 'sr-only': buttonOnly, // Mute the text if showing the placeholder 'text-muted': !value, [`form-control-${size}`]: !!size, @@ -261,21 +281,27 @@ export const BVFormBtnLabelControl = /*#__PURE__*/ Vue.extend({ return h( 'div', { - staticClass: - 'b-form-btn-label-control form-control dropdown d-flex p-0 h-auto align-items-stretch', + staticClass: 'dropdown', class: [ this.directionClass, { + 'btn-group': buttonOnly, + 'b-form-btn-label-control': !buttonOnly, + 'form-control': !buttonOnly, + [`form-control-${size}`]: !!size && !buttonOnly, + 'd-flex': !buttonOnly, + 'p-0': !buttonOnly, + 'h-auto': !buttonOnly, + 'align-items-stretch': !buttonOnly, + focus: hasFocus && !buttonOnly, show: visible, - focus: hasFocus, - [`form-control-${size}`]: !!size, 'is-valid': state === true, 'is-invalid': state === false } ], attrs: { id: idWrapper, - role: 'group', + role: buttonOnly ? null : 'group', lang: this.lang || null, dir: this.computedDir, 'aria-disabled': disabled, From a45cc2cf3394fa7b1c14e268491d2d3d061fac99 Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Mon, 9 Mar 2020 22:43:49 -0300 Subject: [PATCH 02/24] Update form-datepicker.js --- src/components/form-datepicker/form-datepicker.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/components/form-datepicker/form-datepicker.js b/src/components/form-datepicker/form-datepicker.js index 7fb362790a9..a7f22715ac0 100644 --- a/src/components/form-datepicker/form-datepicker.js +++ b/src/components/form-datepicker/form-datepicker.js @@ -100,6 +100,15 @@ const propsMixin = { type: String, default: null }, + buttonOnly: { + type: Boolean, + default: false + }, + buttonVariant: { + // Applicable in button only mode + type: String, + default: 'secondary' + }, calendarWidth: { // Width of the calendar dropdown type: String, From 438ff8aa332685b985e00b316db4615c1ef4e2b7 Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Mon, 9 Mar 2020 22:44:32 -0300 Subject: [PATCH 03/24] Update form-timepicker.js --- src/components/form-timepicker/form-timepicker.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/components/form-timepicker/form-timepicker.js b/src/components/form-timepicker/form-timepicker.js index b15f8a12032..d71f9420adc 100644 --- a/src/components/form-timepicker/form-timepicker.js +++ b/src/components/form-timepicker/form-timepicker.js @@ -90,6 +90,15 @@ const propsMixin = { type: [Number, String], default: 1 }, + buttonOnly: { + type: Boolean, + default: false + }, + buttonVariant: { + // Applicable in button only mode + type: String, + default: 'secondary' + }, nowButton: { type: Boolean, default: false From 97ed821964e93e443c90198a4c60261977d16142 Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Mon, 9 Mar 2020 23:01:28 -0300 Subject: [PATCH 04/24] Update bv-form-btn-label-control.js --- src/utils/bv-form-btn-label-control.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/utils/bv-form-btn-label-control.js b/src/utils/bv-form-btn-label-control.js index b5ccd321ffc..7baf95bc875 100644 --- a/src/utils/bv-form-btn-label-control.js +++ b/src/utils/bv-form-btn-label-control.js @@ -176,7 +176,11 @@ export const BVFormBtnLabelControl = /*#__PURE__*/ Vue.extend({ [`btn-${size}`]: !!size, 'border-0': !buttonOnly, 'h-auto': !buttonOnly, - 'py-0': !buttonOnly + 'py-0': !buttonOnly, + // `dropdown-toggle` is needed for proper + // corner rounding in button only mode + 'dropdown-toggle': buttonOnly, + 'dropdown-toggle-no-caret': buttonOnly, }, attrs: { id: idButton, From 7b0ffd1b340b9dfabe672656f21dfe6c3ac9ce65 Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Mon, 9 Mar 2020 23:04:09 -0300 Subject: [PATCH 05/24] lint --- src/utils/bv-form-btn-label-control.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/bv-form-btn-label-control.js b/src/utils/bv-form-btn-label-control.js index 7baf95bc875..e44fe4cffca 100644 --- a/src/utils/bv-form-btn-label-control.js +++ b/src/utils/bv-form-btn-label-control.js @@ -180,7 +180,7 @@ export const BVFormBtnLabelControl = /*#__PURE__*/ Vue.extend({ // `dropdown-toggle` is needed for proper // corner rounding in button only mode 'dropdown-toggle': buttonOnly, - 'dropdown-toggle-no-caret': buttonOnly, + 'dropdown-toggle-no-caret': buttonOnly }, attrs: { id: idButton, From fa88dc3a74221c4bb33672920986aafa857af488 Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Tue, 10 Mar 2020 00:02:55 -0300 Subject: [PATCH 06/24] Update README.md --- src/components/form-datepicker/README.md | 47 ++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/components/form-datepicker/README.md b/src/components/form-datepicker/README.md index 322d1f77bca..bc06f158135 100644 --- a/src/components/form-datepicker/README.md +++ b/src/components/form-datepicker/README.md @@ -301,6 +301,53 @@ and usage of these props. Want a fancy popup with a dark background instead of a light background? Set the `dark` prop to `true` to enable the dark background. +### Button only mode + +Fancy just a button that launches the date picker dialog, or want to provide your own optional text +input field? Use the `button-mode` prop to render the datepicker as a dropdown button. The formatted +date label will be rendered with the class `sr-only` (available only to screen readers). + +```html + + + + + +``` + +Control the size of the button via the `size` prop, and the button variant via the `button-variant` +prop. + ### Date string format v2.6.0+ From 776a89bbad8c9618ab4540b80f264b5825668b97 Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Tue, 10 Mar 2020 00:08:01 -0300 Subject: [PATCH 07/24] Update README.md --- src/components/form-timepicker/README.md | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/components/form-timepicker/README.md b/src/components/form-timepicker/README.md index 300eda4d93e..97dcb758c51 100644 --- a/src/components/form-timepicker/README.md +++ b/src/components/form-timepicker/README.md @@ -208,6 +208,54 @@ control the positioning of the popup calendar. Refer to the [`` documentation](/docs/components/dropdown) for details on the effects and usage of these props. +### Button only mode + +Fancy just a button that launches the timepicker dialog, or want to provide your own optional text +input field? Use the `button-mode` prop to render the timepicker as a dropdown button. The formatted +time label will be rendered with the class `sr-only` (available only to screen readers). + +```html + + + + + +``` + +Control the size of the button via the `size` prop, and the button variant via the `button-variant` +prop. + ## Internationalization Internationalization of the time interface is provided via From 2846a8cb0d46b172eca100115a64dfe2289246c6 Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Tue, 10 Mar 2020 00:31:56 -0300 Subject: [PATCH 08/24] Update calendar.js --- src/components/calendar/calendar.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/calendar/calendar.js b/src/components/calendar/calendar.js index d9723e48a8d..d054afa515c 100644 --- a/src/components/calendar/calendar.js +++ b/src/components/calendar/calendar.js @@ -473,10 +473,7 @@ export const BCalendar = Vue.extend({ } }, selectedYMD(newYMD, oldYMD) { - // TODO: - // Should we compare to `formatYMD(this.value)` and emit - // only if they are different? - if (newYMD !== oldYMD) { + if (newYMD !== oldYMD && !datesEqual(newYMD, formatYMD(this.value)) { this.$emit('input', this.valueAsDate ? parseYMD(newYMD) || null : newYMD || '') } }, From 6cc2393e88ea0bcd4ec635f32ca6a21a5dbf8ad9 Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Tue, 10 Mar 2020 00:34:50 -0300 Subject: [PATCH 09/24] Update calendar.js --- src/components/calendar/calendar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/calendar/calendar.js b/src/components/calendar/calendar.js index d054afa515c..ad53f008600 100644 --- a/src/components/calendar/calendar.js +++ b/src/components/calendar/calendar.js @@ -473,7 +473,7 @@ export const BCalendar = Vue.extend({ } }, selectedYMD(newYMD, oldYMD) { - if (newYMD !== oldYMD && !datesEqual(newYMD, formatYMD(this.value)) { + if (newYMD !== oldYMD && !datesEqual(newYMD, formatYMD(this.value))) { this.$emit('input', this.valueAsDate ? parseYMD(newYMD) || null : newYMD || '') } }, From 068840089d1b5f1a07e932863d79207f90a47c8f Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Tue, 10 Mar 2020 00:42:15 -0300 Subject: [PATCH 10/24] Update package.json --- src/components/form-datepicker/package.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/components/form-datepicker/package.json b/src/components/form-datepicker/package.json index 036cd59b1d9..f36c827088d 100644 --- a/src/components/form-datepicker/package.json +++ b/src/components/form-datepicker/package.json @@ -64,6 +64,16 @@ "prop": "direction", "description": "Set to the string 'rtl' or 'ltr' to explicitly force the calendar to render in right-to-left or left-ro-right (respectively) mode. Defaults to the resolved locale's directionality" }, + { + "prop": "buttonOnly", + "version": "2.7.0", + "description": "Renders the datepicker as a dropdown button instead of a form-control" + }, + { + "prop": "buttonVariant", + "version": "2.7.0", + "description": "The button variant to use when in `button-only` mode. Has no effect if prop `button-only` is not set" + }, { "prop": "calendarWidth", "version": "2.6.0", From 60825c7a13646b4bab6e192613eefe185c7d9aef Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Tue, 10 Mar 2020 00:42:46 -0300 Subject: [PATCH 11/24] Update package.json --- src/components/form-timepicker/package.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/components/form-timepicker/package.json b/src/components/form-timepicker/package.json index 08ccf8316d4..96d3f77610c 100644 --- a/src/components/form-timepicker/package.json +++ b/src/components/form-timepicker/package.json @@ -62,6 +62,16 @@ "prop": "hideHeader", "description": "When set, visually hides the selected date header" }, + { + "prop": "buttonOnly", + "version": "2.7.0", + "description": "Renders the datepicker as a dropdown button instead of a form-control" + }, + { + "prop": "buttonVariant", + "version": "2.7.0", + "description": "The button variant to use when in `button-only` mode. Has no effect if prop `button-only` is not set" + }, { "prop": "menuClass", "description": "Class (or classes) to apply to to popup menu wrapper" From f0f8613f3ecd70dd6a4731ce647c5333718f3f59 Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Tue, 10 Mar 2020 00:53:02 -0300 Subject: [PATCH 12/24] Update form-datepicker.js --- src/components/form-datepicker/form-datepicker.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/form-datepicker/form-datepicker.js b/src/components/form-datepicker/form-datepicker.js index a7f22715ac0..bedb69a1a92 100644 --- a/src/components/form-datepicker/form-datepicker.js +++ b/src/components/form-datepicker/form-datepicker.js @@ -355,7 +355,9 @@ export const BFormDatepicker = /*#__PURE__*/ Vue.extend({ }) }, onInput(ymd) { - if (this.localYMD !== ymd) { + // We only update the v-model if the dialog is open + // to prevent cursor jumps in bound text inputs + if (this.localYMD !== ymd && this.isVisible) { this.localYMD = ymd } }, From ecde1a214c549e0840a16978fa48689a3e180283 Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Tue, 10 Mar 2020 01:07:58 -0300 Subject: [PATCH 13/24] Update form-datepicker.js --- src/components/form-datepicker/form-datepicker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/form-datepicker/form-datepicker.js b/src/components/form-datepicker/form-datepicker.js index bedb69a1a92..dcf74cf8b6e 100644 --- a/src/components/form-datepicker/form-datepicker.js +++ b/src/components/form-datepicker/form-datepicker.js @@ -366,7 +366,7 @@ export const BFormDatepicker = /*#__PURE__*/ Vue.extend({ this.isRTL = isRTL this.localLocale = locale this.formattedValue = selectedFormatted - this.localYMD = selectedYMD + this.localYMD = this.isVisible ? selectedYMD : this.localYMD this.activeYMD = activeYMD // Re-emit the context event this.$emit('context', ctx) From 31a30d56018ed7907798f0a5690fe32e55a94f03 Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Tue, 10 Mar 2020 01:20:06 -0300 Subject: [PATCH 14/24] Update form-datepicker.js --- src/components/form-datepicker/form-datepicker.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/form-datepicker/form-datepicker.js b/src/components/form-datepicker/form-datepicker.js index dcf74cf8b6e..9dbb6535aa4 100644 --- a/src/components/form-datepicker/form-datepicker.js +++ b/src/components/form-datepicker/form-datepicker.js @@ -310,7 +310,10 @@ export const BFormDatepicker = /*#__PURE__*/ Vue.extend({ this.localYMD = formatYMD(newVal) || '' }, localYMD(newVal) { - this.$emit('input', this.valueAsDate ? parseYMD(newVal) || null : newVal || '') + // We only update the v-model when the datepicker is open + if (this.isVisible) { + this.$emit('input', this.valueAsDate ? parseYMD(newVal) || null : newVal || '') + } }, calendarYM(newVal, oldVal) /* istanbul ignore next */ { // Displayed calendar month has changed @@ -355,9 +358,7 @@ export const BFormDatepicker = /*#__PURE__*/ Vue.extend({ }) }, onInput(ymd) { - // We only update the v-model if the dialog is open - // to prevent cursor jumps in bound text inputs - if (this.localYMD !== ymd && this.isVisible) { + if (this.localYMD !== ymd) { this.localYMD = ymd } }, @@ -366,7 +367,7 @@ export const BFormDatepicker = /*#__PURE__*/ Vue.extend({ this.isRTL = isRTL this.localLocale = locale this.formattedValue = selectedFormatted - this.localYMD = this.isVisible ? selectedYMD : this.localYMD + this.localYMD = selectedYMD this.activeYMD = activeYMD // Re-emit the context event this.$emit('context', ctx) From d1b44b4f83e9df3b37071342673744baa98941bc Mon Sep 17 00:00:00 2001 From: Troy Morehouse Date: Tue, 10 Mar 2020 01:29:22 -0300 Subject: [PATCH 15/24] Update README.md --- src/components/form-timepicker/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/form-timepicker/README.md b/src/components/form-timepicker/README.md index 97dcb758c51..c09efdf72ab 100644 --- a/src/components/form-timepicker/README.md +++ b/src/components/form-timepicker/README.md @@ -210,10 +210,15 @@ and usage of these props. ### Button only mode +v2.7.0+ + Fancy just a button that launches the timepicker dialog, or want to provide your own optional text input field? Use the `button-mode` prop to render the timepicker as a dropdown button. The formatted time label will be rendered with the class `sr-only` (available only to screen readers). +In the following simple example, we are placing the timepicker (buton only mode) as an append to a +``: + ```html