benivo-ui-library 1.9.74 → 1.9.76
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 +167 -0
- package/alert.less +278 -0
- package/alertBanner.less +145 -0
- package/avatar.less +280 -0
- package/{lib/badge.less → badge.less} +2 -2
- package/{lib/benivo-ui-lib.less → benivo-ui-lib.less} +20 -0
- package/breadcrumbs.less +92 -0
- package/button.less +635 -0
- package/checkIcon.less +47 -0
- package/checkItem.less +31 -0
- package/copyInput.less +98 -0
- package/{lib/datePicker.less → datePicker.less} +59 -33
- package/flag.less +44 -0
- package/formSection.less +162 -0
- package/{lib/forms.less → forms.less} +21 -23
- package/heroInput.less +322 -0
- package/index.js +2 -0
- package/{lib/index.js.LICENSE.txt → index.js.LICENSE.txt} +1 -1
- package/input.less +369 -0
- package/notificationCard.less +202 -0
- package/{lib/notifications.less → notifications.less} +13 -4
- package/package.json +4 -2
- package/{lib/phoneNumber.less → phoneNumber.less} +40 -16
- package/progress.less +242 -0
- package/select.less +358 -0
- package/slider.less +98 -0
- package/starIcon.less +25 -0
- package/{lib/tabGroup.less → tabGroup.less} +59 -12
- package/tabs.less +64 -0
- package/tag.less +204 -0
- package/tagsSelect.less +183 -0
- package/textarea.less +73 -0
- package/{lib/tooltip.less → tooltip.less} +45 -20
- package/{lib/variables.less → variables.less} +102 -10
- package/verificationCode.less +142 -0
- package/.design-sync/NOTES.md +0 -59
- package/.design-sync/config.json +0 -11
- package/.design-sync/conventions.md +0 -71
- package/.prettierrc.json +0 -8
- package/.storybook/main.js +0 -66
- package/.storybook/preview-head.html +0 -11
- package/.storybook/preview.js +0 -18
- package/.vscode/extensions.json +0 -5
- package/.vscode/mcp.json +0 -9
- package/.vscode/settings.json +0 -6
- package/Benivo.UI.lib.csproj +0 -21
- package/Benivo.UI.lib.sln +0 -33
- package/LICENSE +0 -21
- package/Properties/launchSettings.json +0 -27
- package/jest.config.js +0 -20
- package/lib/README.md +0 -38
- package/lib/button.less +0 -645
- package/lib/copyInput.less +0 -62
- package/lib/index.js +0 -2
- package/lib/input.less +0 -232
- package/lib/package.json +0 -138
- package/lib/select.less +0 -161
- package/lib/tabs.less +0 -26
- package/lib/tagsSelect.less +0 -114
- package/lib/textarea.less +0 -65
- package/mocking/fileMock.js +0 -7
- package/mocking/mock.worker.js +0 -25
- package/mocking/setup.js +0 -1
- package/mocking/styleMock.js +0 -1
- package/tsconfig.json +0 -18
- package/webpack.config.dev.js +0 -91
- /package/{lib/arrowButton.less → arrowButton.less} +0 -0
- /package/{lib/asideSummaryCard.less → asideSummaryCard.less} +0 -0
- /package/{lib/asideSummaryCardSection.less → asideSummaryCardSection.less} +0 -0
- /package/{lib/assignmentSelectBox.less → assignmentSelectBox.less} +0 -0
- /package/{lib/autoComplete.less → autoComplete.less} +0 -0
- /package/{lib/benivoLogo.less → benivoLogo.less} +0 -0
- /package/{lib/buttonOld.less → buttonOld.less} +0 -0
- /package/{lib/checkbox.less → checkbox.less} +0 -0
- /package/{lib/countryFlag.less → countryFlag.less} +0 -0
- /package/{lib/currencyInput.less → currencyInput.less} +0 -0
- /package/{lib/data-table.less → data-table.less} +0 -0
- /package/{lib/drawer.less → drawer.less} +0 -0
- /package/{lib/dropdownButton.less → dropdownButton.less} +0 -0
- /package/{lib/expander.less → expander.less} +0 -0
- /package/{lib/fantasyButton.less → fantasyButton.less} +0 -0
- /package/{lib/featuredIcon.less → featuredIcon.less} +0 -0
- /package/{lib/fileTypeIcon.less → fileTypeIcon.less} +0 -0
- /package/{lib/folderIcon.less → folderIcon.less} +0 -0
- /package/{lib/frame.less → frame.less} +0 -0
- /package/{lib/freshDeskChat.less → freshDeskChat.less} +0 -0
- /package/{lib/googleTranslate.less → googleTranslate.less} +0 -0
- /package/{lib/image.less → image.less} +0 -0
- /package/{lib/infoMessageBanner.less → infoMessageBanner.less} +0 -0
- /package/{lib/loader.less → loader.less} +0 -0
- /package/{lib/main.less → main.less} +0 -0
- /package/{lib/miIcon.less → miIcon.less} +0 -0
- /package/{lib/mixins.less → mixins.less} +0 -0
- /package/{lib/navigation.less → navigation.less} +0 -0
- /package/{lib/pageHeaderIcon.less → pageHeaderIcon.less} +0 -0
- /package/{lib/pop-up.less → pop-up.less} +0 -0
- /package/{lib/radiobutton.less → radiobutton.less} +0 -0
- /package/{lib/sidebarMenu.less → sidebarMenu.less} +0 -0
- /package/{lib/spacing.less → spacing.less} +0 -0
- /package/{lib/spinner.less → spinner.less} +0 -0
- /package/{lib/splashScreen.less → splashScreen.less} +0 -0
- /package/{lib/status.less → status.less} +0 -0
- /package/{lib/swiper-a11y.less → swiper-a11y.less} +0 -0
- /package/{lib/swiper-effect-cube.less → swiper-effect-cube.less} +0 -0
- /package/{lib/swiper-effect-fade.less → swiper-effect-fade.less} +0 -0
- /package/{lib/swiper-effect-flip.less → swiper-effect-flip.less} +0 -0
- /package/{lib/swiper-lazy.less → swiper-lazy.less} +0 -0
- /package/{lib/swiper-navigation.less → swiper-navigation.less} +0 -0
- /package/{lib/swiper-pagination.less → swiper-pagination.less} +0 -0
- /package/{lib/swiper-scrollbar.less → swiper-scrollbar.less} +0 -0
- /package/{lib/swiper-thumb.less → swiper-thumb.less} +0 -0
- /package/{lib/swiper-zoom.less → swiper-zoom.less} +0 -0
- /package/{lib/swiper.less → swiper.less} +0 -0
- /package/{lib/table-sort.less → table-sort.less} +0 -0
- /package/{lib/typography-helper.less → typography-helper.less} +0 -0
- /package/{lib/typography.less → typography.less} +0 -0
- /package/{lib/withPortal.less → withPortal.less} +0 -0
package/accordion.less
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Accordion
|
|
3
|
+
//
|
|
4
|
+
// One row: a chevron, a title, and a panel that opens under it.
|
|
5
|
+
//
|
|
6
|
+
// padding border radius
|
|
7
|
+
// none — — —
|
|
8
|
+
// stroke 24px top 1px top —
|
|
9
|
+
// card 16px all 1px all 12px
|
|
10
|
+
//
|
|
11
|
+
// Only those three lines differ between the looks. Everything else — the 24px
|
|
12
|
+
// gap, the 18/28 title, the 16/24 body, the 8px above the panel — is shared.
|
|
13
|
+
//
|
|
14
|
+
// Figma also carries a Breakpoint property, which is not a variant here: the
|
|
15
|
+
// mobile frames are identical to the desktop ones apart from being narrower, so
|
|
16
|
+
// this reflows rather than switching on a prop.
|
|
17
|
+
//
|
|
18
|
+
//
|
|
19
|
+
// The group holds a set of rows and does nothing else — no border, no padding,
|
|
20
|
+
// no background. It only decides how far apart they sit, and that depends on the
|
|
21
|
+
// divider: a stroke needs clear air either side of its rule, while cards carry
|
|
22
|
+
// their own edges and sit closer.
|
|
23
|
+
//
|
|
24
|
+
// none 24px
|
|
25
|
+
// stroke 24px
|
|
26
|
+
// card 10px
|
|
27
|
+
//
|
|
28
|
+
// `align-items` is left alone so the rows stretch to the group's width. Figma
|
|
29
|
+
// says items-start with w-full on each row, which comes to the same thing without
|
|
30
|
+
// reaching into the children.
|
|
31
|
+
//
|
|
32
|
+
.bnv-accordion-group {
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
gap: 1.5rem;
|
|
36
|
+
width: 100%;
|
|
37
|
+
|
|
38
|
+
&--card {
|
|
39
|
+
gap: .625rem;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.bnv-accordion {
|
|
44
|
+
box-sizing: border-box;
|
|
45
|
+
min-width: 320px;
|
|
46
|
+
|
|
47
|
+
// Structural only. The row needs to appear in a screen reader's heading list,
|
|
48
|
+
// but its size comes from __title, not from whichever level is used.
|
|
49
|
+
&__heading {
|
|
50
|
+
margin: 0;
|
|
51
|
+
font: inherit;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&__trigger {
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: flex-start;
|
|
57
|
+
gap: 1.5rem;
|
|
58
|
+
width: 100%;
|
|
59
|
+
margin: 0;
|
|
60
|
+
padding: 0;
|
|
61
|
+
border: 0;
|
|
62
|
+
background: none;
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
text-align: left;
|
|
65
|
+
font-family: @font-family;
|
|
66
|
+
|
|
67
|
+
// Keyboard only, so clicking a row does not leave a ring behind. Written
|
|
68
|
+
// out rather than sharing the button restyle's variables, which are not on
|
|
69
|
+
// main yet — worth folding together once that lands.
|
|
70
|
+
&:focus-visible {
|
|
71
|
+
outline: 2px solid var(--brand-400);
|
|
72
|
+
outline-offset: 2px;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
&__icon {
|
|
77
|
+
display: inline-flex;
|
|
78
|
+
flex-shrink: 0;
|
|
79
|
+
// Figma nudges the 24px chevron 2px down so it reads as centred against
|
|
80
|
+
// the 28px title line instead of sitting flush with its ascender.
|
|
81
|
+
padding-top: 2px;
|
|
82
|
+
color: var(--text-400);
|
|
83
|
+
|
|
84
|
+
svg {
|
|
85
|
+
display: block;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// --- hover -----------------------------------------------------------
|
|
90
|
+
//
|
|
91
|
+
// Guarded on a device that genuinely hovers: a touch device latches :hover
|
|
92
|
+
// after a tap, which would leave the last-tapped row looking permanently
|
|
93
|
+
// active.
|
|
94
|
+
//
|
|
95
|
+
// The hover belongs to the trigger, not the whole row — the panel is not
|
|
96
|
+
// clickable, so hovering the answer must not suggest that it is. For the card
|
|
97
|
+
// that means matching on the trigger but colouring the card, hence `:has()`
|
|
98
|
+
// rather than a plain `:hover` on the root.
|
|
99
|
+
@media (hover: hover) {
|
|
100
|
+
.bnv-accordion__trigger:hover .bnv-accordion__icon {
|
|
101
|
+
color: var(--text-600);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
&--card:has(.bnv-accordion__trigger:hover) {
|
|
105
|
+
background: var(--bg-50);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
&__title {
|
|
110
|
+
flex: 1 0 0;
|
|
111
|
+
min-width: 0;
|
|
112
|
+
color: var(--black);
|
|
113
|
+
font-size: 1.125rem;
|
|
114
|
+
line-height: 1.75rem;
|
|
115
|
+
font-weight: @font-weight-medium;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// No `display` here on purpose: the panel is hidden with the `hidden`
|
|
119
|
+
// attribute, and a display rule would override the browser's own
|
|
120
|
+
// `[hidden] { display: none }` and leave the answer on screen when closed.
|
|
121
|
+
&__panel {
|
|
122
|
+
margin-top: .5rem;
|
|
123
|
+
// 24px chevron + 24px gap, so the body lines up under the title rather
|
|
124
|
+
// than under the icon.
|
|
125
|
+
padding-left: 3rem;
|
|
126
|
+
color: var(--text-600);
|
|
127
|
+
font-size: 1rem;
|
|
128
|
+
line-height: 1.5rem;
|
|
129
|
+
font-weight: @font-weight-normal;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// --- icon position ---------------------------------------------------
|
|
133
|
+
// `order` rather than row-reverse: the chevron moves but the DOM does not,
|
|
134
|
+
// so the title stays first for anything reading the markup.
|
|
135
|
+
&--icon-right {
|
|
136
|
+
.bnv-accordion__icon { order: 1; }
|
|
137
|
+
|
|
138
|
+
.bnv-accordion__panel {
|
|
139
|
+
padding-left: 0;
|
|
140
|
+
padding-right: 3rem;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// --- dividers --------------------------------------------------------
|
|
145
|
+
//
|
|
146
|
+
// Both rules are drawn with an inset shadow rather than a border, because
|
|
147
|
+
// Figma puts its strokes *inside* the frame while a CSS border adds to it.
|
|
148
|
+
// With a border, stroke came out 1px taller than the design and card 2px
|
|
149
|
+
// taller AND 2px narrower — which moved where the body copy wraps, so it was
|
|
150
|
+
// not only a total-height rounding difference. An inset shadow occupies no
|
|
151
|
+
// space, which is exactly what Figma is doing.
|
|
152
|
+
//
|
|
153
|
+
// The rule sits on top of each row, so stacking rows draws the lines between
|
|
154
|
+
// them without needing a wrapper. The first row gets one too, which is
|
|
155
|
+
// Figma's.
|
|
156
|
+
&--stroke {
|
|
157
|
+
box-shadow: inset 0 1px 0 0 var(--border-200);
|
|
158
|
+
padding-top: 1.5rem;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
&--card {
|
|
162
|
+
background: var(--white);
|
|
163
|
+
box-shadow: inset 0 0 0 1px var(--border-200);
|
|
164
|
+
border-radius: 12px;
|
|
165
|
+
padding: 1rem;
|
|
166
|
+
}
|
|
167
|
+
}
|
package/alert.less
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Alert
|
|
3
|
+
//
|
|
4
|
+
// Two sizes:
|
|
5
|
+
// floating bordered card, icon + text stacked with actions beneath
|
|
6
|
+
// full-width spans the viewport with a single bottom rule; title and
|
|
7
|
+
// supporting text sit inline and the actions move to the right
|
|
8
|
+
//
|
|
9
|
+
// Six colours. Every colour but `default` uses a tinted FeaturedIcon; `default`
|
|
10
|
+
// is a white, bordered container instead.
|
|
11
|
+
//
|
|
12
|
+
@alert-radius: 0.75rem; // 12px
|
|
13
|
+
@alert-pad: 16px;
|
|
14
|
+
@alert-gap: 16px;
|
|
15
|
+
@alert-shadow: 0 1px 1px rgba(16, 24, 40, 0.05);
|
|
16
|
+
@alert-icon-plain: 40px;
|
|
17
|
+
@alert-full-max: 1280px;
|
|
18
|
+
|
|
19
|
+
.bnv-alert {
|
|
20
|
+
font-family: @font-family;
|
|
21
|
+
background-color: var(--white);
|
|
22
|
+
// --border-300 arrives with the Input PR; until then this falls back to the
|
|
23
|
+
// identical colour under its other name, so the border is right either way.
|
|
24
|
+
border: 1px solid var(--border-300, var(--text-300));
|
|
25
|
+
color: var(--black);
|
|
26
|
+
|
|
27
|
+
&__container {
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: flex-start;
|
|
30
|
+
gap: @alert-gap;
|
|
31
|
+
position: relative;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ---------- leading icon ----------
|
|
35
|
+
&__icon {
|
|
36
|
+
flex-shrink: 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// `default` has no tint: a white box with a border and the same shadow as
|
|
40
|
+
// the alert itself.
|
|
41
|
+
&__icon--plain {
|
|
42
|
+
display: inline-flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
justify-content: center;
|
|
45
|
+
box-sizing: border-box;
|
|
46
|
+
width: @alert-icon-plain;
|
|
47
|
+
height: @alert-icon-plain;
|
|
48
|
+
background-color: var(--white);
|
|
49
|
+
border: 1px solid var(--bg-200);
|
|
50
|
+
border-radius: 0.5rem;
|
|
51
|
+
box-shadow: @alert-shadow;
|
|
52
|
+
color: var(--text-600);
|
|
53
|
+
|
|
54
|
+
svg {
|
|
55
|
+
width: 20px;
|
|
56
|
+
height: 20px;
|
|
57
|
+
display: block;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ---------- text ----------
|
|
62
|
+
&__content {
|
|
63
|
+
display: flex;
|
|
64
|
+
flex: 1 0 0;
|
|
65
|
+
min-width: 0;
|
|
66
|
+
flex-direction: column;
|
|
67
|
+
gap: 12px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
&__text {
|
|
71
|
+
display: flex;
|
|
72
|
+
flex-direction: column;
|
|
73
|
+
gap: 4px;
|
|
74
|
+
min-width: 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
&__title,
|
|
78
|
+
&__supporting {
|
|
79
|
+
margin: 0;
|
|
80
|
+
font-size: @font-size;
|
|
81
|
+
line-height: 24px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
&__title {
|
|
85
|
+
font-weight: @font-weight-semibold;
|
|
86
|
+
color: var(--black);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
&__supporting {
|
|
90
|
+
font-weight: @font-weight-normal;
|
|
91
|
+
color: var(--text-600);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ---------- actions ----------
|
|
95
|
+
&__actions {
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
gap: 12px;
|
|
99
|
+
flex-shrink: 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
&__action {
|
|
103
|
+
font-family: inherit;
|
|
104
|
+
font-weight: @font-weight-semibold;
|
|
105
|
+
cursor: pointer;
|
|
106
|
+
border: 0;
|
|
107
|
+
background: none;
|
|
108
|
+
padding: 0;
|
|
109
|
+
|
|
110
|
+
&:focus-visible {
|
|
111
|
+
outline: 2px solid var(--primary);
|
|
112
|
+
outline-offset: 2px;
|
|
113
|
+
border-radius: 0.25rem;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ---------- close ----------
|
|
118
|
+
&__close {
|
|
119
|
+
display: inline-flex;
|
|
120
|
+
align-items: center;
|
|
121
|
+
justify-content: center;
|
|
122
|
+
flex-shrink: 0;
|
|
123
|
+
width: 36px;
|
|
124
|
+
height: 36px;
|
|
125
|
+
padding: 8px;
|
|
126
|
+
border: 0;
|
|
127
|
+
background: none;
|
|
128
|
+
border-radius: 0.5rem;
|
|
129
|
+
color: var(--text-400);
|
|
130
|
+
cursor: pointer;
|
|
131
|
+
|
|
132
|
+
svg {
|
|
133
|
+
width: 20px;
|
|
134
|
+
height: 20px;
|
|
135
|
+
display: block;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&:hover {
|
|
139
|
+
background-color: var(--bg-100);
|
|
140
|
+
color: var(--text-600);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
&:focus-visible {
|
|
144
|
+
outline: 2px solid var(--primary);
|
|
145
|
+
outline-offset: 2px;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ---------- floating ----------
|
|
150
|
+
&--floating {
|
|
151
|
+
position: relative;
|
|
152
|
+
padding: @alert-pad;
|
|
153
|
+
border-radius: @alert-radius;
|
|
154
|
+
box-shadow: @alert-shadow;
|
|
155
|
+
|
|
156
|
+
// the close X is placed against the card, not the padded content, so
|
|
157
|
+
// it can sit 7px from the alert's own edge as Figma draws it
|
|
158
|
+
.bnv-alert__container {
|
|
159
|
+
position: static;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// the title clears the absolutely-positioned close button
|
|
163
|
+
.bnv-alert__text {
|
|
164
|
+
padding-right: 32px;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.bnv-alert__action {
|
|
168
|
+
font-size: @font-size-sm;
|
|
169
|
+
line-height: 20px;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.bnv-alert__action--secondary {
|
|
173
|
+
color: var(--black);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.bnv-alert__action--primary {
|
|
177
|
+
color: var(--brand-700);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.bnv-alert__close {
|
|
181
|
+
position: absolute;
|
|
182
|
+
top: 7px;
|
|
183
|
+
right: 7px;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@media @md-max {
|
|
187
|
+
.bnv-alert__container {
|
|
188
|
+
gap: 12px;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ---------- full-width ----------
|
|
194
|
+
// A page-level bar: no radius, no shadow, a single rule underneath.
|
|
195
|
+
&--full-width {
|
|
196
|
+
border-width: 0 0 1px;
|
|
197
|
+
border-radius: 0;
|
|
198
|
+
box-shadow: none;
|
|
199
|
+
|
|
200
|
+
.bnv-alert__container {
|
|
201
|
+
align-items: center;
|
|
202
|
+
gap: 12px;
|
|
203
|
+
max-width: @alert-full-max;
|
|
204
|
+
margin: 0 auto;
|
|
205
|
+
padding: 12px 32px;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.bnv-alert__content {
|
|
209
|
+
flex-direction: row;
|
|
210
|
+
align-items: center;
|
|
211
|
+
gap: 16px;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// title and supporting text run inline here, wrapping as one block
|
|
215
|
+
.bnv-alert__text {
|
|
216
|
+
flex: 1 0 0;
|
|
217
|
+
flex-direction: row;
|
|
218
|
+
flex-wrap: wrap;
|
|
219
|
+
align-items: baseline;
|
|
220
|
+
gap: 2px 6px;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Link actions, not buttons — a page-level bar shouldn't carry a CTA
|
|
224
|
+
// that competes with the page's own primary action.
|
|
225
|
+
.bnv-alert__action {
|
|
226
|
+
font-size: @font-size-sm;
|
|
227
|
+
line-height: 20px;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.bnv-alert__action--secondary {
|
|
231
|
+
color: var(--black);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.bnv-alert__action--primary {
|
|
235
|
+
color: var(--brand-700);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
@media @md-max {
|
|
239
|
+
position: relative;
|
|
240
|
+
|
|
241
|
+
// everything stacks: the actions are a sibling of the content here,
|
|
242
|
+
// so it is the container that has to turn, not the content
|
|
243
|
+
.bnv-alert__container {
|
|
244
|
+
flex-direction: column;
|
|
245
|
+
align-items: stretch;
|
|
246
|
+
gap: 16px;
|
|
247
|
+
padding: 16px;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Figma drops the leading icon on mobile — the message carries itself
|
|
251
|
+
.bnv-alert__icon {
|
|
252
|
+
display: none;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.bnv-alert__content {
|
|
256
|
+
flex-direction: column;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// title and supporting text stop running inline
|
|
260
|
+
.bnv-alert__text {
|
|
261
|
+
flex-direction: column;
|
|
262
|
+
gap: 4px;
|
|
263
|
+
padding-right: 32px; // clears the close X
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// links stay inline on mobile too — there is no button to stack
|
|
267
|
+
.bnv-alert__actions {
|
|
268
|
+
gap: 12px;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.bnv-alert__close {
|
|
272
|
+
position: absolute;
|
|
273
|
+
top: 7px;
|
|
274
|
+
right: 7px;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
package/alertBanner.less
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Alert banner
|
|
3
|
+
//
|
|
4
|
+
// A short inline message in a tinted pill — smaller than Alert, with no title
|
|
5
|
+
// and no actions. Four colours, and the text sits centred or left.
|
|
6
|
+
//
|
|
7
|
+
// Namespaced `bnv-` deliberately: MPApp and VPApp both ship a local
|
|
8
|
+
// `.alert-banner` class, and this LESS is global.
|
|
9
|
+
//
|
|
10
|
+
@alert-banner-radius: 0.75rem; // 12px
|
|
11
|
+
@alert-banner-pad-y: 8px;
|
|
12
|
+
@alert-banner-pad-x: 12px;
|
|
13
|
+
@alert-banner-gap: 8px;
|
|
14
|
+
@alert-banner-icon: 20px;
|
|
15
|
+
|
|
16
|
+
.bnv-alert-banner {
|
|
17
|
+
display: flex;
|
|
18
|
+
align-items: center;
|
|
19
|
+
gap: @alert-banner-gap;
|
|
20
|
+
width: 100%;
|
|
21
|
+
box-sizing: border-box;
|
|
22
|
+
padding: @alert-banner-pad-y @alert-banner-pad-x;
|
|
23
|
+
border-radius: @alert-banner-radius;
|
|
24
|
+
font-family: @font-family;
|
|
25
|
+
|
|
26
|
+
&__slot {
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
justify-content: center;
|
|
30
|
+
flex-shrink: 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// An empty slot collapses by default, so it never indents left-aligned text.
|
|
34
|
+
&__slot:empty {
|
|
35
|
+
display: none;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&__icon {
|
|
39
|
+
display: inline-flex;
|
|
40
|
+
flex-shrink: 0;
|
|
41
|
+
|
|
42
|
+
svg {
|
|
43
|
+
width: @alert-banner-icon;
|
|
44
|
+
height: @alert-banner-icon;
|
|
45
|
+
display: block;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// The text takes the remaining width, so `align` decides where a short
|
|
50
|
+
// message sits rather than the flexbox packing.
|
|
51
|
+
&__text {
|
|
52
|
+
flex: 1 0 0;
|
|
53
|
+
min-width: 0;
|
|
54
|
+
margin: 0;
|
|
55
|
+
font-size: @font-size-sm;
|
|
56
|
+
line-height: 20px;
|
|
57
|
+
font-weight: @font-weight-semibold;
|
|
58
|
+
word-break: break-word;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Centred text only sits true if both sides reserve the same width, so here
|
|
62
|
+
// the slots hold their size even when empty. Without it a lone icon drags
|
|
63
|
+
// the text ~14px off centre. Left-aligned text needs no such balancing.
|
|
64
|
+
&--center &__slot,
|
|
65
|
+
&--center &__slot:empty {
|
|
66
|
+
display: flex;
|
|
67
|
+
width: @alert-banner-icon;
|
|
68
|
+
height: @alert-banner-icon;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
&--center &__text {
|
|
72
|
+
text-align: center;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
&--left &__text {
|
|
76
|
+
text-align: left;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// The same control as the Badge's dismiss — Figma calls it "_Badge close X"
|
|
80
|
+
// in both components, so the hover and focus treatment matches: a 16% tint
|
|
81
|
+
// of whatever colour the X is already carrying.
|
|
82
|
+
//
|
|
83
|
+
// Blending keeps the resting X sitting inside the banner tint; hover and
|
|
84
|
+
// focus turn it off so the fill renders predictably.
|
|
85
|
+
&__close {
|
|
86
|
+
display: inline-flex;
|
|
87
|
+
align-items: center;
|
|
88
|
+
justify-content: center;
|
|
89
|
+
flex-shrink: 0;
|
|
90
|
+
padding: 2px;
|
|
91
|
+
border: 0;
|
|
92
|
+
background-color: transparent;
|
|
93
|
+
border-radius: 3px;
|
|
94
|
+
cursor: pointer;
|
|
95
|
+
color: inherit;
|
|
96
|
+
mix-blend-mode: darken;
|
|
97
|
+
.transition(background-color .15s ease);
|
|
98
|
+
|
|
99
|
+
svg {
|
|
100
|
+
width: 12px;
|
|
101
|
+
height: 12px;
|
|
102
|
+
display: block;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
&:hover {
|
|
106
|
+
mix-blend-mode: normal;
|
|
107
|
+
background-color: color-mix(in srgb, currentColor 16%, transparent);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
&:focus-visible {
|
|
111
|
+
mix-blend-mode: normal;
|
|
112
|
+
background-color: color-mix(in srgb, currentColor 16%, transparent);
|
|
113
|
+
outline: 2px solid currentColor;
|
|
114
|
+
outline-offset: -1px;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ---------- colours ----------
|
|
119
|
+
// Tint carries the fill, and the text and icon share one colour.
|
|
120
|
+
&--grey {
|
|
121
|
+
background-color: var(--bg-100);
|
|
122
|
+
color: var(--text-600);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
&--success {
|
|
126
|
+
background-color: var(--success-light);
|
|
127
|
+
color: var(--success-main);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&--warning {
|
|
131
|
+
background-color: var(--warning-light);
|
|
132
|
+
color: var(--warning-main);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
&--error {
|
|
136
|
+
background-color: var(--error-light);
|
|
137
|
+
color: var(--error-main);
|
|
138
|
+
|
|
139
|
+
// The only colour whose X is not the text colour — Figma softens it to
|
|
140
|
+
// rose-400 so the dismiss control doesn't shout as loudly as the message.
|
|
141
|
+
.bnv-alert-banner__close {
|
|
142
|
+
color: var(--rose-400);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|