diff --git a/src/components/form-spinbutton/_spinbutton.scss b/src/components/form-spinbutton/_spinbutton.scss index 9a3161178d5..fad6b00a283 100644 --- a/src/components/form-spinbutton/_spinbutton.scss +++ b/src/components/form-spinbutton/_spinbutton.scss @@ -48,7 +48,7 @@ pointer-events: none; } - &:hover:not(:disabled) > div { + &:hover:not(:disabled) > div > .b-icon { transform: scale(1.25); } } diff --git a/src/components/form-spinbutton/form-spinbutton.js b/src/components/form-spinbutton/form-spinbutton.js index b92c29b4441..b1a36ccdc81 100644 --- a/src/components/form-spinbutton/form-spinbutton.js +++ b/src/components/form-spinbutton/form-spinbutton.js @@ -9,6 +9,7 @@ import { toString } from '../../utils/string' import identity from '../../utils/identity' import KeyCodes from '../../utils/key-codes' import idMixin from '../../mixins/id' +import normalizeSlotMixin from '../../mixins/normalize-slot' import { BIconPlus, BIconDash } from '../../icons/icons' // --- Constants --- @@ -47,7 +48,7 @@ const defaultInteger = (value, defaultValue = null) => { // @vue/component export const BFormSpinbutton = /*#__PURE__*/ Vue.extend({ name: NAME, - mixins: [idMixin], + mixins: [idMixin, normalizeSlotMixin], inheritAttrs: false, props: { value: { @@ -439,11 +440,12 @@ export const BFormSpinbutton = /*#__PURE__*/ Vue.extend({ const hasValue = !isNull(value) const formatter = isFunction(this.formatterFn) ? this.formatterFn : this.defaultFormatter - const makeButton = (stepper, label, IconCmp, keyRef, shortcut, btnDisabled) => { + const makeButton = (stepper, label, IconCmp, keyRef, shortcut, btnDisabled, slotName) => { const $icon = h(IconCmp, { props: { scale: this.hasFocus ? 1.5 : 1.25 }, attrs: { 'aria-hidden': 'true' } }) + const scope = { hasFocus: this.hasFocus } const handler = evt => { if (!isDisabled && !isReadonly) { evt.preventDefault() @@ -476,12 +478,28 @@ export const BFormSpinbutton = /*#__PURE__*/ Vue.extend({ touchstart: handler } }, - [h('div', {}, [$icon])] + [h('div', {}, [this.normalizeSlot(slotName, scope) || $icon])] ) } // TODO: Add button disabled state when `wrap` is `false` and at value max/min - const $increment = makeButton(this.stepUp, this.labelIncrement, BIconPlus, 'inc', 'ArrowUp') - const $decrement = makeButton(this.stepDown, this.labelDecrement, BIconDash, 'dec', 'ArrowDown') + const $increment = makeButton( + this.stepUp, + this.labelIncrement, + BIconPlus, + 'inc', + 'ArrowUp', + false, + 'increment' + ) + const $decrement = makeButton( + this.stepDown, + this.labelDecrement, + BIconDash, + 'dec', + 'ArrowDown', + false, + 'decrement' + ) let $hidden = h() if (this.name && !isDisabled) { diff --git a/src/components/form-spinbutton/package.json b/src/components/form-spinbutton/package.json index 83a80cfbaae..523f599eb94 100644 --- a/src/components/form-spinbutton/package.json +++ b/src/components/form-spinbutton/package.json @@ -99,6 +99,32 @@ "description": "Number of steps to jump by once the `repeat-threshold` has been reached. Must be a positive integer. This value is also used for the page up and down keys" } ], + "slots": [ + { + "name": "increment", + "version": "2.8.0", + "description": "Custom content to place in the increment button", + "scope": [ + { + "prop": "hasFocus", + "type": "Boolean", + "description": "`true` when the spinbutton has focus" + } + ] + }, + { + "name": "decrement", + "version": "2.8.0", + "description": "Custom content to place in the decrement button", + "scope": [ + { + "prop": "hasFocus", + "type": "Boolean", + "description": "`true` when the spinbutton has focus" + } + ] + } + ], "events": [ { "event": "input", diff --git a/src/components/form-timepicker/README.md b/src/components/form-timepicker/README.md index a389323f862..5480032e618 100644 --- a/src/components/form-timepicker/README.md +++ b/src/components/form-timepicker/README.md @@ -236,8 +236,7 @@ In the following simple example, we are placing the timepicker (button only mode button-only right show-seconds - :hour12="false" - locale="en-US" + locale="en" aria-controls="example-input" > diff --git a/src/components/time/time.js b/src/components/time/time.js index 411a329f9fc..1c1ab5aba21 100644 --- a/src/components/time/time.js +++ b/src/components/time/time.js @@ -17,7 +17,7 @@ import idMixin from '../../mixins/id' import normalizeSlotMixin from '../../mixins/normalize-slot' // Sub components used import { BFormSpinbutton } from '../form-spinbutton/form-spinbutton' -import { BIconCircleFill } from '../../icons/icons' +import { BIconCircleFill, BIconChevronUp } from '../../icons/icons' // --- Constants --- @@ -288,6 +288,21 @@ export const BTime = /*#__PURE__*/ Vue.extend({ return this.timeFormatter(createDate(Date.UTC(0, 0, 1, hours, minutes, seconds))) } return this.labelNoTimeSelected || ' ' + }, + spinScopedSlots() { + const h = this.$createElement + return { + increment: ({ hasFocus }) => + h(BIconChevronUp, { + props: { scale: hasFocus ? 1.5 : 1.25 }, + attrs: { 'aria-hidden': 'true' } + }), + decrement: ({ hasFocus }) => + h(BIconChevronUp, { + props: { flipV: true, scale: hasFocus ? 1.5 : 1.25 }, + attrs: { 'aria-hidden': 'true' } + }) + } } }, watch: { @@ -467,6 +482,7 @@ export const BTime = /*#__PURE__*/ Vue.extend({ min: 0, ...spinbuttonProps }, + scopedSlots: this.spinScopedSlots, on: { // We use `change` event to minimize SR verbosity // As the spinbutton will announce each value change