Skip to content

Commit 8c6cfe0

Browse files
authored
feat(custom components): avoid using padding/margin utility classes where possible (closes #5117) (#5121)
Co-authored-by: Jacob Müller
1 parent 6a5ff24 commit 8c6cfe0

15 files changed

+132
-86
lines changed

src/_custom-controls.scss

+11-2
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@
3131

3232
// Shared BVFormBtnLabelControl styling
3333
// Currently used by BFormTimepicker and BFormDatepicker
34+
// Does not apply to button-only styling
3435
.b-form-btn-label-control {
3536
// Remove background validation images from main wrapper
3637
background-image: none;
38+
padding: 0;
3739

3840
@at-root {
3941
// Prevent the button/label from reversing order on in horizontal RTL mode
@@ -51,6 +53,7 @@
5153
line-height: 1;
5254
font-size: inherit;
5355
box-shadow: none !important;
56+
border: 0;
5457

5558
&:disabled {
5659
pointer-events: none;
@@ -65,10 +68,15 @@
6568
color: $form-feedback-invalid-color;
6669
}
6770

71+
> .dropdown-menu {
72+
padding: 0.5rem;
73+
}
74+
6875
> label {
69-
// Unfortunately this is not supported by all browsers :(
70-
// text-align: end;
7176
outline: 0;
77+
padding-left: 0.25rem;
78+
margin: 0;
79+
border: 0;
7280
@if $enable-pointer-cursor-for-buttons {
7381
cursor: pointer;
7482
}
@@ -86,6 +94,7 @@
8694
}
8795
}
8896

97+
8998
// Disabled and read-only styling
9099
&[aria-disabled="true"],
91100
&[aria-readonly="true"] {

src/components/avatar/README.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77
88
## Overview
99

10-
Avatars are lightweight functional components, which render inline by default, so that they are
11-
vertically centered beside any adjoining plain text. They also can be used as children of other
12-
components.
10+
Avatars are lightweight components, which render inline by default, so that they are vertically
11+
centered beside any adjoining plain text. They also can be used as children of other components.
1312

1413
```html
1514
<template>

src/components/calendar/README.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -661,9 +661,8 @@ the best possible accessibility to _all_ users.
661661

662662
## Implementation notes
663663

664-
`<b-calendar>` uses Bootstrap's margin, padding, border, and flex utility classes, along with button
665-
(`btn-*`) classes and the `form-control` class. BootstrapVue's custom SCSS/CSS is also required for
666-
proper styling.
664+
`<b-calendar>` uses Bootstrap's border and flex utility classes, along with button (`btn-*`) classes
665+
and the `form-control` class. BootstrapVue's custom SCSS/CSS is also required for proper styling.
667666

668667
Accessibility-wise, we chose _not_ to use the ARIA role `grid` for the calendar to minimize
669668
verbosity and to provide consistency across various screen readers (NVDA, when encountering role

src/components/calendar/_calendar.scss

+30-4
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,48 @@
11
// BCalendar custom styles
22

33
.b-calendar {
4+
display: inline-flex;
5+
46
.b-calendar-inner {
57
// Prevent calendar from going below this width
68
min-width: 250px;
79
}
810

9-
output.readonly {
10-
background-color: $input-disabled-bg;
11-
opacity: 1;
11+
.b-calendar-header,
12+
.b-calendar-nav {
13+
margin-bottom: 0.25rem;
14+
}
15+
16+
.b-calendar-nav .btn {
17+
padding: 0.25rem;
1218
}
1319

14-
.form-control[role="application"] {
20+
output {
21+
padding: 0.25rem;
22+
font-size: 80%;
23+
24+
&.readonly {
25+
background-color: $input-disabled-bg;
26+
opacity: 1;
27+
}
28+
}
29+
30+
.b-calendar-footer {
31+
margin-top: 0.5rem;
32+
}
33+
34+
.b-calendar-grid {
35+
padding: 0;
36+
margin: 0;
1537
// Easy rounded corners on contained elements,
1638
// specifically the footer of the calendar grid
1739
overflow: hidden;
1840
}
1941

42+
.b-calendar-grid-caption {
43+
padding: 0.25rem;
44+
}
45+
2046
.b-calendar-grid-body {
2147
.col[data-date] {
2248
// We hard code the sizes in `px` to fit

src/components/calendar/calendar.js

+17-27
Original file line numberDiff line numberDiff line change
@@ -734,15 +734,10 @@ export const BCalendar = Vue.extend({
734734
return h()
735735
}
736736

737-
const isRTL = this.isRTL
737+
const { isLive, isRTL, activeYMD, selectedYMD, safeId } = this
738738
const hideDecadeNav = !this.showDecadeNav
739739
const todayYMD = formatYMD(this.getToday())
740-
const selectedYMD = this.selectedYMD
741-
const activeYMD = this.activeYMD
742740
const highlightToday = !this.noHighlightToday
743-
const safeId = this.safeId
744-
// Flag for making the `aria-live` regions live
745-
const isLive = this.isLive
746741
// Pre-compute some IDs
747742
// This should be computed props
748743
const idValue = safeId()
@@ -757,7 +752,7 @@ export const BCalendar = Vue.extend({
757752
let $header = h(
758753
'output',
759754
{
760-
staticClass: 'd-block text-center rounded border small p-1 mb-1',
755+
staticClass: 'form-control form-control-sm text-center',
761756
class: { 'text-muted': this.disabled, readonly: this.readonly || this.disabled },
762757
attrs: {
763758
id: idValue,
@@ -784,20 +779,22 @@ export const BCalendar = Vue.extend({
784779
// We use `bdi` elements here in case the label doesn't match the locale
785780
// Although IE 11 does not deal with <BDI> at all (equivalent to a span)
786781
h('bdi', { staticClass: 'sr-only' }, ` (${toString(this.labelSelected)}) `),
787-
h('bdi', {}, this.formatDateString(this.selectedDate))
782+
h('bdi', this.formatDateString(this.selectedDate))
788783
]
789784
: this.labelNoDateSelected || '\u00a0' // '&nbsp;'
790785
)
791786
$header = h(
792787
'header',
793788
{
794-
class: this.hideHeader ? 'sr-only' : 'mb-1',
789+
staticClass: 'b-calendar-header',
790+
class: { 'sr-only': this.hideHeader },
795791
attrs: { title: this.selectedDate ? this.labelSelectedDate || null : null }
796792
},
797793
[$header]
798794
)
799795

800796
// Content for the date navigation buttons
797+
// TODO: add slots for the nav button content
801798
const $prevDecadeIcon = h(BIconChevronBarLeft, { props: { shiftV: 0.5, flipH: isRTL } })
802799
const $prevYearIcon = h(BIconChevronDoubleLeft, { props: { shiftV: 0.5, flipH: isRTL } })
803800
const $prevMonthIcon = h(BIconChevronLeft, { props: { shiftV: 0.5, flipH: isRTL } })
@@ -811,7 +808,7 @@ export const BCalendar = Vue.extend({
811808
return h(
812809
'button',
813810
{
814-
staticClass: 'btn btn-sm btn-outline-secondary border-0 flex-fill p-1 mx-1',
811+
staticClass: 'btn btn-sm btn-outline-secondary border-0 flex-fill',
815812
class: { disabled: btnDisabled },
816813
attrs: {
817814
title: label || null,
@@ -830,7 +827,7 @@ export const BCalendar = Vue.extend({
830827
const $nav = h(
831828
'div',
832829
{
833-
staticClass: 'b-calendar-nav d-flex mx-n1 mb-1',
830+
staticClass: 'b-calendar-nav d-flex',
834831
attrs: {
835832
id: idNav,
836833
role: 'group',
@@ -901,7 +898,7 @@ export const BCalendar = Vue.extend({
901898
'header',
902899
{
903900
key: 'grid-caption',
904-
staticClass: 'text-center font-weight-bold p-1 m-0',
901+
staticClass: 'b-calendar-grid-caption text-center font-weight-bold',
905902
class: { 'text-muted': this.disabled },
906903
attrs: {
907904
id: idGridCaption,
@@ -915,7 +912,10 @@ export const BCalendar = Vue.extend({
915912
// Calendar weekday headings
916913
const $gridWeekDays = h(
917914
'div',
918-
{ staticClass: 'row no-gutters border-bottom', attrs: { 'aria-hidden': 'true' } },
915+
{
916+
staticClass: 'b-calendar-grid-weekdays row no-gutters border-bottom',
917+
attrs: { 'aria-hidden': 'true' }
918+
},
919919
this.calendarHeadings.map((d, idx) => {
920920
return h(
921921
'small',
@@ -1019,7 +1019,7 @@ export const BCalendar = Vue.extend({
10191019
const $gridHelp = h(
10201020
'footer',
10211021
{
1022-
staticClass: 'border-top small text-muted text-center bg-light',
1022+
staticClass: 'b-calendar-grid-help border-top small text-muted text-center bg-light',
10231023
attrs: {
10241024
id: idGridHelp
10251025
}
@@ -1031,7 +1031,7 @@ export const BCalendar = Vue.extend({
10311031
'div',
10321032
{
10331033
ref: 'grid',
1034-
staticClass: 'form-control h-auto text-center p-0 mb-0',
1034+
staticClass: 'b-calendar-grid form-control h-auto text-center',
10351035
attrs: {
10361036
id: idGrid,
10371037
role: 'application',
@@ -1057,13 +1057,12 @@ export const BCalendar = Vue.extend({
10571057

10581058
// Optional bottom slot
10591059
let $slot = this.normalizeSlot('default')
1060-
$slot = $slot ? h('footer', { staticClass: 'mt-2' }, $slot) : h()
1060+
$slot = $slot ? h('footer', { staticClass: 'b-calendar-footer' }, $slot) : h()
10611061

10621062
const $widget = h(
10631063
'div',
10641064
{
10651065
staticClass: 'b-calendar-inner',
1066-
class: this.block ? 'd-block' : 'd-inline-block',
10671066
style: this.block ? {} : { width: this.width },
10681067
attrs: {
10691068
id: idWidget,
@@ -1093,15 +1092,6 @@ export const BCalendar = Vue.extend({
10931092
)
10941093

10951094
// Wrap in an outer div that can be styled
1096-
return h(
1097-
'div',
1098-
{
1099-
staticClass: 'b-calendar',
1100-
// We use a style here rather than class `d-inline-block` so that users can
1101-
// override the display value (`d-*` classes use the `!important` flag)
1102-
style: this.block ? {} : { display: 'inline-block' }
1103-
},
1104-
[$widget]
1105-
)
1095+
return h('div', { staticClass: 'b-calendar', class: { 'd-block': this.block } }, [$widget])
11061096
}
11071097
})

src/components/form-datepicker/README.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -590,10 +590,8 @@ details.
590590
`<b-form-datepicker>` is based upon the components [`<b-calendar>`](/docs/components/calendar) and
591591
[`<b-dropdown>`](/docs/components/dropdown).
592592

593-
`<b-form-datepicker>` uses Bootstrap's margin, padding, border, and flex utility classes, along with
594-
button (`btn-*`) classes, dropdown (`dropdown*`) classes, and the `form-control*` (plus validation)
595-
classes.
596-
593+
`<b-form-datepicker>` uses Bootstrap's border and flex utility classes, along with button (`btn-*`)
594+
classes, dropdown (`dropdown*`) classes, and the `form-control*` (plus validation) classes.
597595
BootstrapVue's Custom SCSS/CSS is also required for proper styling of the date picker and calendar.
598596

599597
## See also

src/components/form-spinbutton/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ Note the the `repeat-delay`, `repeat-threshold` and `repeat-interval` only appli
403403

404404
## Implementation notes
405405

406-
`<b-form-spinbutton>` uses a mixture of Bootstrap v4 utility classes (margin, padding, and flex),
406+
`<b-form-spinbutton>` uses a mixture of Bootstrap v4 utility classes (border, alignment, flex),
407407
form-control and button classes, along with additional custom BootstrapVue SCSS/CSS.
408408

409409
## See also

src/components/form-spinbutton/_spinbutton.scss

+21-9
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
1-
.b-form-spinbutton.form-control {
1+
.b-form-spinbutton {
22
text-align: center;
33
// Quick way to get end buttons rounded on outside edges
44
overflow: hidden;
55
// Hide validation icon, as there is no room for it
66
background-image: none;
7-
8-
&.flex-column {
9-
height: auto;
10-
width: auto;
11-
}
7+
padding: 0;
128

139
@at-root {
1410
// Prevent the buttons from reversing order on in horizontal RTL mode
@@ -23,6 +19,9 @@
2319
outline: 0;
2420
border: 0;
2521
background-color: transparent;
22+
width: auto;
23+
margin: 0;
24+
padding: 0 0.25rem;
2625

2726
> div,
2827
> bdi {
@@ -33,13 +32,26 @@
3332
}
3433
}
3534

36-
&.d-inline-flex:not(.flex-column) {
37-
&,
35+
&.flex-column {
36+
height: auto;
37+
width: auto;
38+
3839
output {
39-
width: auto;
40+
margin: 0 0.25rem;
41+
padding: 0.25rem 0;
42+
}
43+
}
44+
45+
&:not(.d-inline-flex):not(.flex-column) {
46+
output: {
47+
width: 100%;
4048
}
4149
}
4250

51+
&.d-inline-flex:not(.flex-column) {
52+
width: auto;
53+
}
54+
4355
.btn {
4456
line-height: 1;
4557
box-shadow: none !important;

src/components/form-spinbutton/form-spinbutton.js

+3-7
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ export const BFormSpinbutton = /*#__PURE__*/ Vue.extend({
467467
touchstart: handler
468468
}
469469
},
470-
[h('div', {}, [this.normalizeSlot(slotName, scope) || $icon])]
470+
[h('div', [this.normalizeSlot(slotName, scope) || $icon])]
471471
)
472472
}
473473
// TODO: Add button disabled state when `wrap` is `false` and at value max/min
@@ -512,13 +512,9 @@ export const BFormSpinbutton = /*#__PURE__*/ Vue.extend({
512512
key: 'output',
513513
staticClass: 'flex-grow-1',
514514
class: {
515-
'w-100': !isVertical && !isInline,
516515
'd-flex': isVertical,
517516
'align-self-center': !isVertical,
518517
'align-items-center': isVertical,
519-
'py-1': isVertical,
520-
'px-1': !isVertical,
521-
'mx-1': isVertical,
522518
'border-top': isVertical,
523519
'border-bottom': isVertical,
524520
'border-left': !isVertical,
@@ -545,13 +541,13 @@ export const BFormSpinbutton = /*#__PURE__*/ Vue.extend({
545541
'aria-valuetext': hasValue ? formatter(value) : null
546542
}
547543
},
548-
[h('bdi', { staticClass: 'w-100' }, hasValue ? formatter(value) : this.placeholder || '')]
544+
[h('bdi', hasValue ? formatter(value) : this.placeholder || '')]
549545
)
550546

551547
return h(
552548
'div',
553549
{
554-
staticClass: 'b-form-spinbutton form-control p-0',
550+
staticClass: 'b-form-spinbutton form-control',
555551
class: {
556552
disabled: isDisabled,
557553
readonly: isReadonly,

src/components/form-timepicker/README.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -426,10 +426,8 @@ Refer to the [`<b-time>`](/docs/components/time#accessibility) documentation for
426426
`<b-form-timepicker>` is based upon the components [`<b-time>`](/docs/components/time) and
427427
[`<b-dropdown>`](/docs/components/dropdown).
428428
429-
`<b-form-timepicker>` uses Bootstrap's margin, padding, border, and flex utility classes, along with
430-
button (`btn-*`) classes, dropdown (`dropdown*`) classes, and the `form-control*` (plus validation)
431-
classes.
432-
429+
`<b-form-timepicker>` uses Bootstrap's border and flex utility classes, along with button (`btn-*`)
430+
classes, dropdown (`dropdown*`) classes, and the `form-control*` (plus validation) classes.
433431
BootstrapVue's Custom SCSS/CSS is also required for proper styling of the time picker and popup.
434432
435433
## See also

0 commit comments

Comments
 (0)