benivo-ui-library 1.9.77 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/accordion.less +6 -5
- package/asideSummaryCard.less +68 -5
- package/asideSummaryCardSection.less +95 -16
- package/avatar.less +6 -5
- package/benivo-ui-lib.less +16 -0
- package/button.less +8 -2
- package/buttonGroup.less +236 -0
- package/cardHeader.less +230 -0
- package/charts.less +182 -0
- package/checkbox.less +192 -41
- package/checklistCard.less +119 -0
- package/contentDivider.less +68 -0
- package/currencyInput.less +6 -0
- package/dataGrid.less +690 -0
- package/detailCard.less +80 -0
- package/fileCard.less +8 -6
- package/filePreview.less +380 -0
- package/fileUpload.less +9 -6
- package/footer.less +123 -0
- package/heroInput.less +20 -4
- package/index.js +1 -1
- package/input.less +17 -1
- package/metric.less +241 -0
- package/package.json +1 -1
- package/pageHeader.less +266 -0
- package/pageIndicator.less +4 -2
- package/pagination.less +6 -1
- package/phoneNumber.less +6 -0
- package/progressSteps.less +398 -0
- package/radiobutton.less +21 -7
- package/sectionHeader.less +244 -0
- package/select.less +14 -1
- package/slider.less +8 -1
- package/tabGroup.less +2 -1
- package/tabs.less +2 -1
- package/tag.less +16 -6
- package/tagsSelect.less +9 -0
- package/textarea.less +4 -0
- package/variables.less +52 -9
- package/verificationCode.less +4 -1
- package/workspaceModal.less +607 -0
package/accordion.less
CHANGED
|
@@ -64,12 +64,13 @@
|
|
|
64
64
|
text-align: left;
|
|
65
65
|
font-family: @font-family;
|
|
66
66
|
|
|
67
|
-
// Keyboard only, so clicking a row does not leave a ring behind.
|
|
68
|
-
//
|
|
69
|
-
//
|
|
67
|
+
// Keyboard only, so clicking a row does not leave a ring behind. This used to
|
|
68
|
+
// write the values out because the shared focus variables were not on main yet;
|
|
69
|
+
// BPO-14843 is the branch that comment was waiting for, so it is folded on now
|
|
70
|
+
// and a change to the indicator colour reaches this rule too.
|
|
70
71
|
&:focus-visible {
|
|
71
|
-
outline:
|
|
72
|
-
outline-offset:
|
|
72
|
+
outline: @focus-outline;
|
|
73
|
+
outline-offset: @focus-outline-offset;
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
|
package/asideSummaryCard.less
CHANGED
|
@@ -1,12 +1,30 @@
|
|
|
1
|
+
//
|
|
2
|
+
// AsideSummaryCard — new Figma "Summary card". BPO-15015. Node 10995:49133.
|
|
3
|
+
//
|
|
4
|
+
// Contract-preserving restyle: the card stays fluid (a sidebar sizes it, not the
|
|
5
|
+
// Figma fixed 376px) and keeps its `.summary-card*` classes. The card itself
|
|
6
|
+
// carries NO horizontal padding — each block (title, header, section) is inset
|
|
7
|
+
// 32px, so a section's divider can run full width while its text sits inset,
|
|
8
|
+
// exactly as Figma draws it. Blocks are spaced by a 20px column gap.
|
|
9
|
+
//
|
|
1
10
|
.summary-card {
|
|
2
11
|
background: var(--white);
|
|
3
|
-
padding: 24px;
|
|
4
12
|
border: 1px solid var(--border-200);
|
|
5
|
-
.border-radius(
|
|
13
|
+
.border-radius(16px);
|
|
14
|
+
padding: 26px 0;
|
|
15
|
+
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
align-items: center;
|
|
19
|
+
gap: 20px;
|
|
6
20
|
|
|
7
21
|
&__title {
|
|
8
|
-
|
|
9
|
-
|
|
22
|
+
width: 100%;
|
|
23
|
+
box-sizing: border-box;
|
|
24
|
+
padding: 0 32px;
|
|
25
|
+
font-size: @font-size; // 16
|
|
26
|
+
line-height: 1.5rem; // 24
|
|
27
|
+
color: var(--black);
|
|
10
28
|
font-weight: @font-weight-semibold;
|
|
11
29
|
}
|
|
12
30
|
|
|
@@ -16,4 +34,49 @@
|
|
|
16
34
|
padding-left: 15px;
|
|
17
35
|
}
|
|
18
36
|
}
|
|
19
|
-
|
|
37
|
+
|
|
38
|
+
// ---- Opt-in: summary header (Figma "Summary header") -----------------
|
|
39
|
+
// Type=Assignment composes FlagFeatureIcon; Type=Feature icon composes
|
|
40
|
+
// FeaturedIcon; Type=Text passes no icon. The icon is a node either way.
|
|
41
|
+
&__header {
|
|
42
|
+
width: 100%;
|
|
43
|
+
box-sizing: border-box;
|
|
44
|
+
padding: 0 32px;
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
gap: 16px;
|
|
48
|
+
|
|
49
|
+
&-icon {
|
|
50
|
+
flex-shrink: 0;
|
|
51
|
+
display: inline-flex;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&-text {
|
|
55
|
+
display: flex;
|
|
56
|
+
flex-direction: column;
|
|
57
|
+
min-width: 0; // let long titles/meta ellipsis rather than push width
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
&-title {
|
|
61
|
+
font-size: @h4-font-size; // 18 — DS has no dedicated 18px text token; h4 carries 18/28
|
|
62
|
+
line-height: @h4-line-height; // 28
|
|
63
|
+
color: var(--black);
|
|
64
|
+
font-weight: @font-weight-semibold;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
&-meta {
|
|
68
|
+
font-size: @font-size; // 16
|
|
69
|
+
line-height: 1.5rem; // 24
|
|
70
|
+
color: var(--text-600);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ---- Opt-in: empty state ---------------------------------------------
|
|
75
|
+
&__empty {
|
|
76
|
+
width: 100%;
|
|
77
|
+
box-sizing: border-box;
|
|
78
|
+
padding: 6px 32px;
|
|
79
|
+
display: flex;
|
|
80
|
+
justify-content: center;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -1,33 +1,66 @@
|
|
|
1
|
+
//
|
|
2
|
+
// AsideSummaryCardSection — new Figma "Summary card" section + rows.
|
|
3
|
+
// BPO-15015. Nodes 10995:49049 (section) / 10995:49013 (input).
|
|
4
|
+
//
|
|
5
|
+
// Contract-preserving restyle: every `.summary-card-section*` class is kept, so
|
|
6
|
+
// consumers inherit the new look with no code change. Content is inset 32px; the
|
|
7
|
+
// section title's divider runs full width. Rows STACK (label 16/24 Text/600 over
|
|
8
|
+
// value 16/24 black, 4px apart) — the only layout. Blocks are spaced by a 20px
|
|
9
|
+
// column gap.
|
|
10
|
+
//
|
|
1
11
|
.summary-card-section {
|
|
2
|
-
|
|
3
|
-
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
gap: 20px;
|
|
15
|
+
width: 100%;
|
|
16
|
+
font-size: @font-size; // 16
|
|
17
|
+
line-height: 1.5rem; // 24
|
|
4
18
|
|
|
5
19
|
&__title {
|
|
6
|
-
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
padding: 0 32px 12px;
|
|
7
22
|
border-bottom: 1px solid var(--border-200);
|
|
8
|
-
|
|
9
|
-
|
|
23
|
+
font-size: @font-size; // 16
|
|
24
|
+
line-height: 1.5rem; // 24
|
|
25
|
+
color: var(--black);
|
|
10
26
|
font-weight: @font-weight-semibold;
|
|
11
27
|
}
|
|
12
28
|
|
|
29
|
+
&__content {
|
|
30
|
+
box-sizing: border-box;
|
|
31
|
+
padding: 0 32px;
|
|
32
|
+
display: flex;
|
|
33
|
+
flex-direction: column;
|
|
34
|
+
gap: 20px;
|
|
35
|
+
|
|
36
|
+
// Intro copy and step lists are supporting text — Text/600, not black.
|
|
37
|
+
p,
|
|
38
|
+
ol,
|
|
39
|
+
ul {
|
|
40
|
+
color: var(--text-600);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Full-width "View more" toggle (DS Button carries no fullWidth prop).
|
|
45
|
+
&__more {
|
|
46
|
+
width: 100%;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Stacked rows — the new default. Label above value, 4px apart.
|
|
50
|
+
// `!important` intentionally overrides the legacy inline `display` some
|
|
51
|
+
// consumers set on hand-written `__detail` rows, so the new stacked layout
|
|
52
|
+
// wins without touching their markup.
|
|
13
53
|
&__detail {
|
|
14
54
|
display: flex !important;
|
|
15
|
-
|
|
16
|
-
|
|
55
|
+
flex-direction: column;
|
|
56
|
+
gap: 4px;
|
|
17
57
|
|
|
18
58
|
&__label {
|
|
19
|
-
display: inline-block;
|
|
20
59
|
color: var(--text-600);
|
|
21
|
-
flex-basis: 50%;
|
|
22
|
-
padding-right: 10px;
|
|
23
60
|
}
|
|
24
61
|
|
|
25
62
|
&__value {
|
|
26
|
-
|
|
27
|
-
text-align: right;
|
|
28
|
-
overflow: hidden;
|
|
29
|
-
text-overflow: ellipsis;
|
|
30
|
-
white-space: nowrap;
|
|
63
|
+
color: var(--black);
|
|
31
64
|
|
|
32
65
|
i {
|
|
33
66
|
font-size: @font-size-xs;
|
|
@@ -35,4 +68,50 @@
|
|
|
35
68
|
}
|
|
36
69
|
}
|
|
37
70
|
}
|
|
38
|
-
|
|
71
|
+
|
|
72
|
+
// ---- Opt-in: avatar / user row (Figma "Summary input" Type=User) -----
|
|
73
|
+
&__user {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
gap: 8px;
|
|
77
|
+
|
|
78
|
+
&-label {
|
|
79
|
+
color: var(--text-600);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
&-row {
|
|
83
|
+
display: flex;
|
|
84
|
+
align-items: center;
|
|
85
|
+
gap: 10px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&-info {
|
|
89
|
+
display: flex;
|
|
90
|
+
flex-direction: column;
|
|
91
|
+
min-width: 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
&-name {
|
|
95
|
+
font-size: @font-size-sm; // 14
|
|
96
|
+
line-height: 1.25rem; // 20
|
|
97
|
+
color: var(--black);
|
|
98
|
+
font-weight: @font-weight-semibold;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
&-email {
|
|
102
|
+
font-size: @font-size-sm; // 14
|
|
103
|
+
line-height: 1.25rem; // 20
|
|
104
|
+
color: var(--text-600);
|
|
105
|
+
overflow: hidden;
|
|
106
|
+
text-overflow: ellipsis;
|
|
107
|
+
white-space: nowrap;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ---- Opt-in: tag chips (Figma "Summary tags") ------------------------
|
|
112
|
+
&__tags {
|
|
113
|
+
display: flex;
|
|
114
|
+
flex-wrap: wrap;
|
|
115
|
+
gap: 8px;
|
|
116
|
+
}
|
|
117
|
+
}
|
package/avatar.less
CHANGED
|
@@ -144,11 +144,12 @@
|
|
|
144
144
|
}
|
|
145
145
|
&:focus-visible {
|
|
146
146
|
// Figma spec used a faint grey ring (rgba(152,162,179,0.14)) that fails
|
|
147
|
-
// WCAG 1.4.11/2.4.7 (~1.1:1) and diverges from DS focus rule.
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
outline
|
|
147
|
+
// WCAG 1.4.11/2.4.7 (~1.1:1) and diverges from DS focus rule. The DS halo
|
|
148
|
+
// is no better on its own at 1.37:1, so @focus-outline (--brand-500,
|
|
149
|
+
// 3.23:1) is the indicator; it also survives Windows High-Contrast /
|
|
150
|
+
// forced-colors mode, where the box-shadow is dropped.
|
|
151
|
+
outline: @focus-outline;
|
|
152
|
+
outline-offset: @focus-outline-offset;
|
|
152
153
|
box-shadow: @form-focus-box-shadow;
|
|
153
154
|
}
|
|
154
155
|
&:disabled {
|
package/benivo-ui-lib.less
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
@import '../components/checkbox/checkbox.less';
|
|
9
9
|
@import '../components/radiobutton/radiobutton.less';
|
|
10
10
|
@import '../components/checkboxGroup/checkboxGroup.less';
|
|
11
|
+
@import '../components/buttonGroup/buttonGroup.less';
|
|
11
12
|
@import '../components/slider/slider.less';
|
|
12
13
|
@import '../components/progress/progress.less';
|
|
13
14
|
@import '../icons/featuredIcon/featuredIcon.less';
|
|
@@ -21,12 +22,15 @@
|
|
|
21
22
|
@import '../components/badge/badge.less';
|
|
22
23
|
@import '../components/activityFeed/activityFeed.less';
|
|
23
24
|
@import '../components/notificationCard/notificationCard.less';
|
|
25
|
+
@import '../components/cardHeader/cardHeader.less';
|
|
24
26
|
@import '../components/alertBanner/alertBanner.less';
|
|
25
27
|
@import '../components/alert/alert.less';
|
|
26
28
|
@import '../icons/pageHeaderIcon/pageHeaderIcon.less';
|
|
27
29
|
@import '../components/breadcrumbs/breadcrumbs.less';
|
|
30
|
+
@import '../components/pageHeader/pageHeader.less';
|
|
28
31
|
@import '../components/pageIndicator/pageIndicator.less';
|
|
29
32
|
@import '../components/fileUpload/fileUpload.less';
|
|
33
|
+
@import '../components/contentDivider/contentDivider.less';
|
|
30
34
|
@import '../components/pagination/pagination.less';
|
|
31
35
|
@import '../components/shared/optionList.less';
|
|
32
36
|
@import '../components/select/select.less';
|
|
@@ -34,17 +38,22 @@
|
|
|
34
38
|
@import '../components/navigation/navigation.less';
|
|
35
39
|
@import '../components/swiperSlider/swiper/swiper.less';
|
|
36
40
|
@import '../components/select/TagsSelect/tagsSelect.less';
|
|
41
|
+
@import '../components/dataGrid/dataGrid.less';
|
|
37
42
|
@import '../components/copyInput/copyInput.less';
|
|
38
43
|
@import '../components/currencyInput/currencyInput.less';
|
|
39
44
|
@import '../components/phoneNumber/phoneNumber.less';
|
|
40
45
|
@import '../components/emptyState/emptyState.less';
|
|
41
46
|
@import '../components/emptyState/illustration/illustration.less';
|
|
42
47
|
@import '../components/menu/menu.less';
|
|
48
|
+
@import '../components/metric/metric.less';
|
|
43
49
|
@import '../components/heroInput/heroInput.less';
|
|
44
50
|
@import '../components/formSection/formSection.less';
|
|
51
|
+
@import '../components/sectionHeader/sectionHeader.less';
|
|
45
52
|
@import '../components/verificationCode/verificationCode.less';
|
|
46
53
|
@import '../components/avatar/avatar.less';
|
|
47
54
|
@import '../components/tag/tag.less';
|
|
55
|
+
@import '../components/asideSummaryCard/asideSummaryCard.less';
|
|
56
|
+
@import '../components/asideSummaryCardSection/asideSummaryCardSection.less';
|
|
48
57
|
@import '../components/tab/tabs/tabs.less';
|
|
49
58
|
@import '../components/tab/tabGroup/tabGroup.less';
|
|
50
59
|
@import '../components/accordion/accordion.less';
|
|
@@ -52,7 +61,14 @@
|
|
|
52
61
|
@import '../components/flag/flag.less';
|
|
53
62
|
@import '../components/textarea/textarea.less';
|
|
54
63
|
@import '../components/modal/modal.less';
|
|
64
|
+
@import '../components/workspaceModal/workspaceModal.less';
|
|
55
65
|
@import '../components/fileCard/fileCard.less';
|
|
66
|
+
@import '../components/detailCard/detailCard.less';
|
|
67
|
+
@import '../components/checklistCard/checklistCard.less';
|
|
68
|
+
@import '../components/progressSteps/progressSteps.less';
|
|
69
|
+
@import '../components/footer/footer.less';
|
|
70
|
+
@import '../components/filePreview/filePreview.less';
|
|
71
|
+
@import '../components/charts/charts.less';
|
|
56
72
|
@import './forms.less';
|
|
57
73
|
@import './spacing.less';
|
|
58
74
|
@import './typography.less';
|
package/button.less
CHANGED
|
@@ -511,10 +511,16 @@
|
|
|
511
511
|
// question rather than reproduced.
|
|
512
512
|
|
|
513
513
|
// --- Destructive primary ---------------------------------------------
|
|
514
|
+
// BPO-14879 / BPO-14810 row 110161 (WCAG 1.4.3): white text on --error-main is 3.76:1, measured
|
|
515
|
+
// in a running app, and 16px/400 is normal-size text so it needs 4.5:1. The resting state was
|
|
516
|
+
// therefore non-conformant while :hover, already a step darker at 6.16:1, passed — the button was
|
|
517
|
+
// only accessible while the pointer was on it. --error-700 is 6.57:1 and is the closer hue match
|
|
518
|
+
// to --error-main than the more magenta --rose-* steps. Only the CONTAINED variant changes: the
|
|
519
|
+
// outlined and text danger variants put the colour on white as text and were fixed separately.
|
|
514
520
|
&.btn-variant-contained.btn-color-danger {
|
|
515
521
|
color: var(--white);
|
|
516
|
-
background: var(--error-
|
|
517
|
-
border-color: var(--error-
|
|
522
|
+
background: var(--error-700);
|
|
523
|
+
border-color: var(--error-700);
|
|
518
524
|
box-shadow: @btn-shadow;
|
|
519
525
|
|
|
520
526
|
&:hover {
|
package/buttonGroup.less
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Button group — segmented control (single-select)
|
|
3
|
+
//
|
|
4
|
+
// Joined buttons that share borders, exactly one Current (selected). Each
|
|
5
|
+
// segment is a real radio (see ButtonGroupItem.jsx); everything here is the
|
|
6
|
+
// button skin laid over it. The visual language is the DS Button's
|
|
7
|
+
// "Secondary grey" hierarchy — white fill, Text/300 border, the shared
|
|
8
|
+
// @focus-ring — reused through the @btn-* / @focus-* tokens rather than
|
|
9
|
+
// re-derived, so the group and a standalone Button stay in step.
|
|
10
|
+
//
|
|
11
|
+
// Figma: `_Button group base` 1046-9312 / `Button group` 1046-10171 (node 16-399).
|
|
12
|
+
// segment white bg · Text/300 border · Text/600 label · Semibold
|
|
13
|
+
// current Grey/100 fill · black label (the selected segment)
|
|
14
|
+
// hover Grey/50 fill (unselected only)
|
|
15
|
+
// focus the DS 2px outline + grey halo, raised above the shared borders
|
|
16
|
+
// disabled Text/400 label, no hover/pointer
|
|
17
|
+
// joined borders collapse (-1px) so adjacent segments share one line;
|
|
18
|
+
// only the two ends are rounded.
|
|
19
|
+
|
|
20
|
+
// The field wrapper (present only when a visible group label is passed).
|
|
21
|
+
.bnv-button-group-field {
|
|
22
|
+
display: inline-flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
gap: 0.375rem; // label -> control
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.bnv-button-group__group-label {
|
|
28
|
+
font-size: 14px;
|
|
29
|
+
line-height: 20px;
|
|
30
|
+
font-weight: @font-weight-semibold;
|
|
31
|
+
color: var(--black);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.bnv-button-group {
|
|
35
|
+
display: inline-flex;
|
|
36
|
+
align-items: stretch;
|
|
37
|
+
// The subtle DS button elevation, on the group as a whole.
|
|
38
|
+
box-shadow: @btn-shadow;
|
|
39
|
+
.border-radius(@btn-brd-radius);
|
|
40
|
+
// A new stacking context so a focused segment's z-index stays local.
|
|
41
|
+
isolation: isolate;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.bnv-button-group__segment {
|
|
45
|
+
position: relative;
|
|
46
|
+
display: inline-flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: center;
|
|
49
|
+
box-sizing: border-box;
|
|
50
|
+
cursor: pointer;
|
|
51
|
+
background: var(--white);
|
|
52
|
+
// Figma strokes the segments with Text/300 (as the DS Secondary-grey
|
|
53
|
+
// button does); there is no border token at that step.
|
|
54
|
+
border: @btn-brd solid var(--text-300);
|
|
55
|
+
color: var(--text-600);
|
|
56
|
+
font-family: @btn-font-family;
|
|
57
|
+
font-weight: @btn-font-weight;
|
|
58
|
+
font-size: @btn-md-font-size;
|
|
59
|
+
line-height: @btn-md-line-height;
|
|
60
|
+
text-align: center;
|
|
61
|
+
white-space: nowrap;
|
|
62
|
+
.user-select(none);
|
|
63
|
+
.transition(@btn-transition);
|
|
64
|
+
|
|
65
|
+
// Collapse the shared border so neighbours draw one line, not two.
|
|
66
|
+
&:not(:first-child) {
|
|
67
|
+
margin-left: calc(-1 * @btn-brd);
|
|
68
|
+
}
|
|
69
|
+
&:first-child {
|
|
70
|
+
.border-radius(@btn-brd-radius 0 0 @btn-brd-radius);
|
|
71
|
+
}
|
|
72
|
+
&:last-child {
|
|
73
|
+
.border-radius(0 @btn-brd-radius @btn-brd-radius 0);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// --- segment contents (elements of the block, siblings of __segment) -----
|
|
78
|
+
.bnv-button-group__content {
|
|
79
|
+
display: inline-flex;
|
|
80
|
+
align-items: center;
|
|
81
|
+
gap: @btn-md-gap;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.bnv-button-group__icon {
|
|
85
|
+
display: inline-flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
font-size: @btn-icon-size;
|
|
88
|
+
|
|
89
|
+
svg {
|
|
90
|
+
width: @btn-icon-size;
|
|
91
|
+
height: @btn-icon-size;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Leading status dot; inherits the label colour unless dotColor is set.
|
|
96
|
+
.bnv-button-group__dot {
|
|
97
|
+
display: inline-block;
|
|
98
|
+
width: 8px;
|
|
99
|
+
height: 8px;
|
|
100
|
+
border-radius: 50%;
|
|
101
|
+
background: currentColor;
|
|
102
|
+
flex: 0 0 auto;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.bnv-button-group__label {
|
|
106
|
+
display: inline-block;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// --- sizes ---------------------------------------------------------------
|
|
110
|
+
// Heights track the DS Button scale (sm 40 / md 44 / lg 48); horizontal
|
|
111
|
+
// padding tracks @btn-*-padding. Font stays 1rem across sizes, as the DS
|
|
112
|
+
// Button does for sm/md/lg.
|
|
113
|
+
.bnv-button-group__segment {
|
|
114
|
+
&--sm {
|
|
115
|
+
height: 40px;
|
|
116
|
+
padding: 0 0.875rem;
|
|
117
|
+
}
|
|
118
|
+
&--md {
|
|
119
|
+
height: 44px;
|
|
120
|
+
padding: 0 1rem;
|
|
121
|
+
}
|
|
122
|
+
&--lg {
|
|
123
|
+
height: 48px;
|
|
124
|
+
padding: 0 1.125rem;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Icon-only segments are square, so the group reads as even tiles.
|
|
128
|
+
&--icon-only {
|
|
129
|
+
&.bnv-button-group__segment--sm {
|
|
130
|
+
width: 40px;
|
|
131
|
+
padding: 0;
|
|
132
|
+
}
|
|
133
|
+
&.bnv-button-group__segment--md {
|
|
134
|
+
width: 44px;
|
|
135
|
+
padding: 0;
|
|
136
|
+
}
|
|
137
|
+
&.bnv-button-group__segment--lg {
|
|
138
|
+
width: 48px;
|
|
139
|
+
padding: 0;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// --- the native radio, visually hidden but still focusable ---------------
|
|
145
|
+
// display:none would drop it out of the tab order and kill the browser's
|
|
146
|
+
// arrow-key radio-group behaviour, so it is clipped instead. Clicks land on
|
|
147
|
+
// the wrapping label, which toggles it natively.
|
|
148
|
+
.bnv-button-group__input {
|
|
149
|
+
position: absolute;
|
|
150
|
+
width: 1px;
|
|
151
|
+
height: 1px;
|
|
152
|
+
margin: 0;
|
|
153
|
+
padding: 0;
|
|
154
|
+
border: 0;
|
|
155
|
+
opacity: 0;
|
|
156
|
+
pointer-events: none;
|
|
157
|
+
clip: rect(0 0 0 0);
|
|
158
|
+
clip-path: inset(50%);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// --- states --------------------------------------------------------------
|
|
162
|
+
// Hover: unselected segments fill Grey/50 (the DS Secondary-grey hover).
|
|
163
|
+
.bnv-button-group__segment:hover:not([data-disabled='true']):not([data-selected='true']) {
|
|
164
|
+
background: var(--bg-50);
|
|
165
|
+
color: var(--black);
|
|
166
|
+
z-index: 1; // lift the hovered border above its neighbours
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Current: the one selected segment. A darker fill than hover (Grey/100 vs
|
|
170
|
+
// Grey/50) so "selected" reads distinctly from "hovered", plus a black label.
|
|
171
|
+
.bnv-button-group__segment[data-selected='true'] {
|
|
172
|
+
background: var(--bg-100);
|
|
173
|
+
color: var(--black);
|
|
174
|
+
z-index: 1;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Focus: the DS focus treatment (2px outline for the 3:1 WCAG indicator plus
|
|
178
|
+
// the grey halo) painted on an overlay so it clears the shared borders. Keyed
|
|
179
|
+
// off :focus-visible on the input, so a mouse click leaves no ring behind.
|
|
180
|
+
.bnv-button-group__focus {
|
|
181
|
+
position: absolute;
|
|
182
|
+
inset: 0;
|
|
183
|
+
border-radius: inherit;
|
|
184
|
+
pointer-events: none;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.bnv-button-group__input:focus-visible ~ .bnv-button-group__focus {
|
|
188
|
+
outline: @focus-outline;
|
|
189
|
+
outline-offset: @focus-outline-offset;
|
|
190
|
+
box-shadow: @focus-ring-grey;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Raise the whole segment while focused so the ring is never clipped by the
|
|
194
|
+
// neighbouring segment's border.
|
|
195
|
+
.bnv-button-group__segment:has(.bnv-button-group__input:focus-visible) {
|
|
196
|
+
z-index: 2;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Disabled: greyed label, no hover, no pointer. A disabled radio is already
|
|
200
|
+
// skipped by the browser's arrow-key navigation. The label uses --text-500,
|
|
201
|
+
// not --text-400: --text-400 measures 2.575:1 and fails WCAG 1.4.3, which is
|
|
202
|
+
// exactly why DS Button's disabled labels moved to --text-500 (BPO-14588).
|
|
203
|
+
.bnv-button-group__segment[data-disabled='true'] {
|
|
204
|
+
color: var(--text-500);
|
|
205
|
+
cursor: not-allowed;
|
|
206
|
+
background: var(--white);
|
|
207
|
+
|
|
208
|
+
.bnv-button-group__input {
|
|
209
|
+
cursor: not-allowed;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Disabled + Current: keep the selection fill (greyed via the disabled label
|
|
214
|
+
// colour) so the current segment is still identifiable — matching CheckboxGroup,
|
|
215
|
+
// where a disabled+selected item keeps its indicator rather than losing it. The
|
|
216
|
+
// disabled rule above resets the background, so re-assert the fill here (it has
|
|
217
|
+
// higher specificity, and comes later, so it wins).
|
|
218
|
+
.bnv-button-group__segment[data-disabled='true'][data-selected='true'] {
|
|
219
|
+
background: var(--bg-100);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Windows High Contrast / forced-colors forces every background-color to the
|
|
223
|
+
// theme's Canvas, so the Current segment's Grey/100 fill vanishes and it becomes
|
|
224
|
+
// indistinguishable from the unselected ones (the radio is opacity:0, so it is
|
|
225
|
+
// no fallback). Rebuild the state from the platform's own selection pair
|
|
226
|
+
// Highlight / HighlightText — the same fix radiobutton.less carries (BPO-14588).
|
|
227
|
+
@media (forced-colors: active) {
|
|
228
|
+
.bnv-button-group__segment[data-selected='true'] {
|
|
229
|
+
background: Highlight;
|
|
230
|
+
color: HighlightText;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.bnv-button-group__segment[data-disabled='true'] {
|
|
234
|
+
color: GrayText;
|
|
235
|
+
}
|
|
236
|
+
}
|