@hashicorp/design-system-components 2.1.0 → 2.2.0
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/CHANGELOG.md +27 -0
- package/HOW-TO-TEST-A-COMPONENT-IN-CLOUD-UI.md +28 -3
- package/addon/components/hds/app-frame/index.hbs +24 -0
- package/addon/components/hds/app-frame/index.js +52 -0
- package/addon/components/hds/app-frame/parts/footer.hbs +7 -0
- package/addon/components/hds/app-frame/parts/header.hbs +7 -0
- package/addon/components/hds/app-frame/parts/main.hbs +7 -0
- package/addon/components/hds/app-frame/parts/modals.hbs +6 -0
- package/addon/components/hds/app-frame/parts/sidebar.hbs +7 -0
- package/addon/components/hds/application-state/footer.js +5 -0
- package/addon/components/hds/dropdown/index.hbs +2 -2
- package/addon/components/hds/dropdown/index.js +18 -2
- package/addon/components/hds/flyout/footer.hbs +7 -0
- package/addon/components/hds/flyout/index.hbs +1 -0
- package/addon/components/hds/side-nav/base.hbs +14 -0
- package/addon/components/hds/side-nav/{home-link.js → header/home-link.js} +2 -2
- package/addon/components/hds/side-nav/{icon-button.js → header/icon-button.js} +2 -2
- package/addon/components/hds/side-nav/{header.hbs → header/index.hbs} +2 -2
- package/addon/components/hds/side-nav/index.hbs +40 -0
- package/addon/components/hds/side-nav/index.js +107 -0
- package/addon/components/hds/side-nav/list/index.hbs +2 -0
- package/addon/components/hds/side-nav/portal/index.hbs +12 -0
- package/addon/components/hds/side-nav/portal/target.hbs +14 -0
- package/addon/components/hds/side-nav/portal/target.js +156 -0
- package/app/components/hds/{side-nav/wrapper.js → app-frame/index.js} +1 -1
- package/app/components/hds/app-frame/parts/footer.js +6 -0
- package/app/components/hds/app-frame/parts/header.js +6 -0
- package/app/components/hds/{side-nav/icon-button.js → app-frame/parts/main.js} +1 -1
- package/app/components/hds/app-frame/parts/modals.js +6 -0
- package/app/components/hds/app-frame/parts/sidebar.js +6 -0
- package/app/components/hds/{side-nav/home-link.js → flyout/footer.js} +1 -1
- package/app/components/hds/side-nav/base.js +6 -0
- package/app/components/hds/side-nav/header/home-link.js +6 -0
- package/app/components/hds/side-nav/header/icon-button.js +6 -0
- package/app/components/hds/side-nav/index.js +6 -0
- package/app/components/hds/side-nav/portal/index.js +6 -0
- package/app/components/hds/side-nav/portal/target.js +6 -0
- package/app/styles/@hashicorp/design-system-components.scss +1 -0
- package/app/styles/@hashicorp/design-system-power-select-overrides.scss +32 -2
- package/app/styles/components/app-frame.scss +60 -0
- package/app/styles/components/dropdown.scss +11 -0
- package/app/styles/components/flyout.scss +15 -1
- package/app/styles/components/form/textarea.scss +1 -0
- package/app/styles/components/side-nav/a11y-refocus.scss +30 -0
- package/app/styles/components/side-nav/content.scss +156 -0
- package/app/styles/components/side-nav/header.scss +102 -0
- package/app/styles/components/side-nav/index.scss +10 -0
- package/app/styles/components/side-nav/main.scss +202 -0
- package/app/styles/components/side-nav/vars.scss +36 -0
- package/package.json +5 -3
- package/addon/components/hds/side-nav/wrapper.hbs +0 -18
- package/app/styles/components/side-nav.scss +0 -275
- /package/addon/components/hds/side-nav/{home-link.hbs → header/home-link.hbs} +0 -0
- /package/addon/components/hds/side-nav/{icon-button.hbs → header/icon-button.hbs} +0 -0
- /package/app/components/hds/side-nav/{header.js → header/index.js} +0 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) HashiCorp, Inc.
|
|
3
|
+
* SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import Component from '@glimmer/component';
|
|
7
|
+
import { inject as service } from '@ember/service';
|
|
8
|
+
import { tracked } from '@glimmer/tracking';
|
|
9
|
+
import { action } from '@ember/object';
|
|
10
|
+
import { DEBUG } from '@glimmer/env';
|
|
11
|
+
import Ember from 'ember';
|
|
12
|
+
import { debounce } from '@ember/runloop';
|
|
13
|
+
|
|
14
|
+
export default class SidenavPortalTarget extends Component {
|
|
15
|
+
@service router;
|
|
16
|
+
|
|
17
|
+
@tracked numSubnavs = 0;
|
|
18
|
+
|
|
19
|
+
static get prefersReducedMotionOverride() {
|
|
20
|
+
return Ember.testing;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
prefersReducedMotionMQ = window.matchMedia(
|
|
24
|
+
'(prefers-reduced-motion: reduce)'
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
get prefersReducedMotion() {
|
|
28
|
+
return (
|
|
29
|
+
this.constructor.prefersReducedMotionOverride ||
|
|
30
|
+
(this.prefersReducedMotionMQ && this.prefersReducedMotionMQ.matches)
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@action
|
|
35
|
+
panelsChanged(portalCount) {
|
|
36
|
+
this.numSubnavs = portalCount;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@action
|
|
40
|
+
didUpdateSubnav(element, [count]) {
|
|
41
|
+
debounce(this, 'animateSubnav', element, [count], 100);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@action
|
|
45
|
+
animateSubnav(element, [count]) {
|
|
46
|
+
/*
|
|
47
|
+
* Here is what the layout looks like for this setup
|
|
48
|
+
*
|
|
49
|
+
|
|
50
|
+
SideNav
|
|
51
|
+
+----------------------+
|
|
52
|
+
| +------------------+ |
|
|
53
|
+
| | ("header") | |
|
|
54
|
+
| +------------------+ |
|
|
55
|
+
| |
|
|
56
|
+
| +------------------+ |
|
|
57
|
+
| | ("body") | |
|
|
58
|
+
(PortalTarget) | | | |
|
|
59
|
+
+----------------------------------------------+ | |
|
|
60
|
+
| +----------+ +----------+ | +----------+ | | |
|
|
61
|
+
| | (Portal) | | (Portal) | | (Portal) | | | |
|
|
62
|
+
| | | | | | | | | | |
|
|
63
|
+
| | hidden | | hidden | | *active* | | | |
|
|
64
|
+
| | panel | | panel | | | panel | | | |
|
|
65
|
+
| | | | | | | | | |
|
|
66
|
+
| | | | | | | | | | |
|
|
67
|
+
| | | | | | | | | |
|
|
68
|
+
| | | | | | | | | | |
|
|
69
|
+
| | | | | | | | | |
|
|
70
|
+
| | | | | | | | | | |
|
|
71
|
+
| | | | | | | | | |
|
|
72
|
+
| +----------+ +----------+ | +----------+ | | |
|
|
73
|
+
+----------------------------------------------+ | |
|
|
74
|
+
| | | |
|
|
75
|
+
| +------------------+ |
|
|
76
|
+
| |
|
|
77
|
+
| +------------------+ |
|
|
78
|
+
| | ("footer") | |
|
|
79
|
+
| +------------------+ |
|
|
80
|
+
+----------------------+
|
|
81
|
+
|
|
82
|
+
*
|
|
83
|
+
* every time `HcAppFrame::SideNav::Portal` renders, it contains a portaled "panel"
|
|
84
|
+
* that is rendered into the `hds-side-nav__content-panels` (inside the PortalTarget).
|
|
85
|
+
*
|
|
86
|
+
* Rendering or unrendering other `HcAppFrame::SideNav::Portal`s triggers the number of
|
|
87
|
+
* subnavs to change (via `numSubnavs`), so this function runs and slides
|
|
88
|
+
* `hds-side-nav__content-panels` left or right using the `element.animate` api.
|
|
89
|
+
*
|
|
90
|
+
* */
|
|
91
|
+
|
|
92
|
+
let activeIndex = count - 1;
|
|
93
|
+
let targetElement = element;
|
|
94
|
+
let { prefersReducedMotion } = this;
|
|
95
|
+
|
|
96
|
+
let styles = getComputedStyle(targetElement);
|
|
97
|
+
let columnWidth = styles.getPropertyValue(
|
|
98
|
+
'--hds-app-sidenav-width-expanded'
|
|
99
|
+
);
|
|
100
|
+
let slideDuration = prefersReducedMotion ? 0 : 150;
|
|
101
|
+
let fadeDuration = prefersReducedMotion ? 0 : 175;
|
|
102
|
+
let fadeDelay = prefersReducedMotion ? 0 : 50;
|
|
103
|
+
|
|
104
|
+
// slide entire parent panel
|
|
105
|
+
let start = styles.transform;
|
|
106
|
+
let end = `translateX(-${activeIndex * parseInt(columnWidth, 10)}px)`;
|
|
107
|
+
let anim = targetElement.animate(
|
|
108
|
+
[{ transform: start }, { transform: end }],
|
|
109
|
+
{
|
|
110
|
+
duration: slideDuration,
|
|
111
|
+
easing: 'cubic-bezier(0.65, 0, 0.35, 1)',
|
|
112
|
+
fill: 'forwards',
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
// Notice: we don't add the styles by default because it writes a `style` attribute to the element and it causes an additional re-render
|
|
116
|
+
if (DEBUG) {
|
|
117
|
+
anim.commitStyles();
|
|
118
|
+
}
|
|
119
|
+
anim.finished.then(() => {
|
|
120
|
+
// uncomment this if we need/want to scroll the element to the top
|
|
121
|
+
// targetElement.scrollIntoView(true);
|
|
122
|
+
if (activeIndex > 0) {
|
|
123
|
+
let allPrev = Array.from(targetElement.children).slice(0, activeIndex);
|
|
124
|
+
for (let ele of allPrev) {
|
|
125
|
+
ele.ariaHidden = 'true';
|
|
126
|
+
ele.style.setProperty('visibility', 'hidden');
|
|
127
|
+
ele.style.setProperty('opacity', '0');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Notice: we don't add the styles by default because it writes a `style` attribute to the element and it causes an additional re-render
|
|
131
|
+
if (DEBUG) {
|
|
132
|
+
// Check the visibility of the element before attempting to commitStyles.
|
|
133
|
+
if (targetElement.offsetParent !== null) {
|
|
134
|
+
anim.commitStyles();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// fade in next panel
|
|
140
|
+
let nextPanelEl = targetElement.children[activeIndex];
|
|
141
|
+
if (nextPanelEl) {
|
|
142
|
+
nextPanelEl.ariaHidden = 'false';
|
|
143
|
+
nextPanelEl.style.setProperty('visibility', 'visible');
|
|
144
|
+
// this eliminates a flicker if there's only 1 subnav rendering
|
|
145
|
+
if (activeIndex === 0) {
|
|
146
|
+
fadeDelay = 0;
|
|
147
|
+
fadeDuration = 0;
|
|
148
|
+
}
|
|
149
|
+
nextPanelEl.animate([{ opacity: '0' }, { opacity: '1' }], {
|
|
150
|
+
delay: fadeDelay,
|
|
151
|
+
duration: fadeDuration,
|
|
152
|
+
fill: 'forwards',
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
// Notice: this list can be automatically edited by the Ember blueprint, please don't remove the start/end comments
|
|
14
14
|
// START COMPONENTS CSS FILES IMPORTS
|
|
15
15
|
@use "../components/alert";
|
|
16
|
+
@use "../components/app-frame";
|
|
16
17
|
@use "../components/application-state";
|
|
17
18
|
@use "../components/avatar";
|
|
18
19
|
@use "../components/badge";
|
|
@@ -193,6 +193,17 @@
|
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
.ember-power-select-option--no-matches-message {
|
|
197
|
+
padding: 8px;
|
|
198
|
+
|
|
199
|
+
&:hover {
|
|
200
|
+
color: inherit;
|
|
201
|
+
background-color: inherit;
|
|
202
|
+
border-color: transparent;
|
|
203
|
+
cursor: default;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
196
207
|
.ember-power-select-multiple-trigger {
|
|
197
208
|
padding-top: calc(var(--token-form-control-padding) - 3px);
|
|
198
209
|
padding-bottom: calc(var(--token-form-control-padding) - 3px);
|
|
@@ -203,7 +214,6 @@
|
|
|
203
214
|
.ember-power-select-multiple-option {
|
|
204
215
|
display: inline-flex;
|
|
205
216
|
align-items: stretch;
|
|
206
|
-
float: none;
|
|
207
217
|
margin: 4px 4px 4px 0;
|
|
208
218
|
padding: 3px 10px 5px 10px;
|
|
209
219
|
color: var(--token-color-foreground-primary);
|
|
@@ -212,7 +222,7 @@
|
|
|
212
222
|
font-family: var(--token-typography-font-stack-text);
|
|
213
223
|
line-height: 1rem; // 16px
|
|
214
224
|
vertical-align: middle;
|
|
215
|
-
background-color:
|
|
225
|
+
background-color: inherit;
|
|
216
226
|
border: 1px solid var(--token-color-border-strong);
|
|
217
227
|
border-radius: 50px;
|
|
218
228
|
}
|
|
@@ -232,6 +242,26 @@
|
|
|
232
242
|
}
|
|
233
243
|
}
|
|
234
244
|
|
|
245
|
+
.ember-power-select-trigger-multiple-input {
|
|
246
|
+
margin: 4px 4px 4px 0;
|
|
247
|
+
|
|
248
|
+
&:disabled {
|
|
249
|
+
display: none;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
&::-webkit-search-cancel-button {
|
|
253
|
+
width: var(--token-form-text-input-background-image-size);
|
|
254
|
+
height: var(--token-form-text-input-background-image-size);
|
|
255
|
+
background-image: var(--token-form-text-input-background-image-data-url-search-cancel);
|
|
256
|
+
background-position: center center;
|
|
257
|
+
background-size: var(--token-form-text-input-background-image-size);
|
|
258
|
+
cursor: pointer;
|
|
259
|
+
// stylelint-disable-next-line property-no-vendor-prefix
|
|
260
|
+
-webkit-appearance: none;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
|
|
235
265
|
.hds-power-select__after-options {
|
|
236
266
|
padding: 8px;
|
|
237
267
|
color: var(--token-color-foreground-primary);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) HashiCorp, Inc.
|
|
3
|
+
* SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
//
|
|
7
|
+
// APP-FRAME
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
.hds-app-frame {
|
|
11
|
+
display: grid;
|
|
12
|
+
grid-template-areas:
|
|
13
|
+
"header header"
|
|
14
|
+
"sidebar main"
|
|
15
|
+
"sidebar footer";
|
|
16
|
+
grid-template-rows: auto 1fr auto;
|
|
17
|
+
grid-template-columns: auto 1fr;
|
|
18
|
+
min-height: 100vh;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
// FRAME'S CONTAINERS
|
|
23
|
+
|
|
24
|
+
.hds-app-frame__header {
|
|
25
|
+
z-index: 7;
|
|
26
|
+
grid-area: header;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.hds-app-frame__sidebar {
|
|
30
|
+
z-index: 6;
|
|
31
|
+
grid-area: sidebar;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.hds-app-frame__main {
|
|
35
|
+
grid-area: main;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.hds-app-frame__footer {
|
|
39
|
+
z-index: 5;
|
|
40
|
+
grid-area: footer;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
// MODALS "CONTAINER"
|
|
45
|
+
|
|
46
|
+
.hds-app-frame__modals {
|
|
47
|
+
position: fixed;
|
|
48
|
+
top: 0;
|
|
49
|
+
left: 0;
|
|
50
|
+
z-index: 100;
|
|
51
|
+
width: 100vw;
|
|
52
|
+
height: 100vh;
|
|
53
|
+
pointer-events: none;
|
|
54
|
+
|
|
55
|
+
// since the content is injected via DOM manipulation, there's no issues of whitespace generated by Ember
|
|
56
|
+
// that make this approach unreliable (in some cases), so we can safely use it to controls its display
|
|
57
|
+
&:empty {
|
|
58
|
+
display: none;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -14,6 +14,17 @@
|
|
|
14
14
|
|
|
15
15
|
$hds-dropdown-toggle-border-radius: $hds-button-border-radius;
|
|
16
16
|
|
|
17
|
+
// DROPDOWN
|
|
18
|
+
|
|
19
|
+
.hds-dropdown--is-inline {
|
|
20
|
+
display: inline-block;
|
|
21
|
+
|
|
22
|
+
.hds-dropdown-toggle-icon,
|
|
23
|
+
.hds-dropdown-toggle-button {
|
|
24
|
+
display: inline-flex;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
17
28
|
// TOGGLE/ICON
|
|
18
29
|
|
|
19
30
|
.hds-dropdown-toggle-icon {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
right: 0;
|
|
46
46
|
bottom: 0;
|
|
47
47
|
left: 0;
|
|
48
|
-
z-index:
|
|
48
|
+
z-index: 49;
|
|
49
49
|
background: var(--token-color-palette-neutral-700);
|
|
50
50
|
opacity: 0.5;
|
|
51
51
|
}
|
|
@@ -91,6 +91,20 @@
|
|
|
91
91
|
border-top: 1px solid var(--token-color-border-primary);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
.hds-flyout__footer {
|
|
95
|
+
flex: none;
|
|
96
|
+
padding: 16px 24px;
|
|
97
|
+
background: var(--token-color-surface-faint);
|
|
98
|
+
border-top: 1px solid var(--token-color-border-primary);
|
|
99
|
+
|
|
100
|
+
// Tertiary buttons must always be placed/aligned at the end of the row
|
|
101
|
+
.hds-button-set {
|
|
102
|
+
.hds-button--color-tertiary {
|
|
103
|
+
margin-left: auto;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
94
108
|
.hds-flyout--size-medium {
|
|
95
109
|
@include hds-flyout-position(480px);
|
|
96
110
|
}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
.hds-form-textarea {
|
|
14
14
|
width: 100%;
|
|
15
15
|
max-width: 100%;
|
|
16
|
+
min-height: 36px;
|
|
16
17
|
padding: var(--token-form-control-padding);
|
|
17
18
|
color: var(--token-form-control-base-foreground-value-color);
|
|
18
19
|
background-color: var(--token-form-control-base-surface-color-default);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) HashiCorp, Inc.
|
|
3
|
+
* SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
//
|
|
7
|
+
// SIDE-NAV > A11Y-REFOCUS "SKIP LINK"
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
.hds-side-nav { // this extra qualifier is needed to increase specificity of the selector, please don't remove it
|
|
11
|
+
.ember-a11y-refocus-skip-link {
|
|
12
|
+
top: 10px;
|
|
13
|
+
left: 10px;
|
|
14
|
+
z-index: 20;
|
|
15
|
+
width: max-content;
|
|
16
|
+
padding: 2px 10px 4px;
|
|
17
|
+
color: var(--token-color-foreground-action);
|
|
18
|
+
font-size: var(--token-typography-display-200-font-size);
|
|
19
|
+
font-family: var(--token-typography-display-200-font-family);
|
|
20
|
+
line-height: var(--token-typography-display-200-line-height);
|
|
21
|
+
background-color: var(--token-color-surface-faint);
|
|
22
|
+
border-radius: 3px;
|
|
23
|
+
transform: translateY(-200%);
|
|
24
|
+
transition: 0.6s ease-in-out;
|
|
25
|
+
|
|
26
|
+
&:focus {
|
|
27
|
+
transform: translateY(0);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) HashiCorp, Inc.
|
|
3
|
+
* SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
//
|
|
7
|
+
// SIDE-NAV > CONTENT (PORTALS + LISTS OF ITEMS/LINKS)
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
@use "../../mixins/focus-ring" as *;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
// PANELS (wrappers used in conjunction with the portal elements)
|
|
14
|
+
|
|
15
|
+
.hds-side-nav__content {
|
|
16
|
+
// we use this trick (increasing the container size here, and reducing it at single panel level)
|
|
17
|
+
// to have the panels width match the sidebar extended width (it's used in the animated sliding of the panels)
|
|
18
|
+
margin: 0 calc(var(--token-side-nav-wrapper-padding-horizontal) * -1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.hds-side-nav__content-panels {
|
|
22
|
+
// see https://codepen.io/didoo/pen/YzOeRPr
|
|
23
|
+
display: grid;
|
|
24
|
+
grid-template-columns: repeat(5, 100%);
|
|
25
|
+
width: 100%;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.hds-side-nav__content-panel {
|
|
29
|
+
padding: 0 var(--token-side-nav-wrapper-padding-horizontal);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// (LIST) TITLE
|
|
33
|
+
|
|
34
|
+
.hds-side-nav__list-title {
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
min-height: 34px;
|
|
38
|
+
margin-top: var(--token-side-nav-body-list-margin-vertical);
|
|
39
|
+
padding: 0 var(--token-side-nav-body-list-item-padding-horizontal);
|
|
40
|
+
color: var(--token-side-nav-color-foreground-faint);
|
|
41
|
+
|
|
42
|
+
// Remove margin from title at top of all list-items & lists
|
|
43
|
+
.hds-side-nav__list-wrapper:first-child .hds-side-nav__list-item:first-child > & {
|
|
44
|
+
margin-top: 0;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
// LIST (root elements)
|
|
50
|
+
|
|
51
|
+
.hds-side-nav__list-wrapper, // <nav> element
|
|
52
|
+
.hds-side-nav__list { // <ul> element
|
|
53
|
+
margin: 0;
|
|
54
|
+
padding: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
// ITEM (generic container)
|
|
59
|
+
|
|
60
|
+
.hds-side-nav__list-item { // <li> element
|
|
61
|
+
list-style-type: none;
|
|
62
|
+
|
|
63
|
+
& + & {
|
|
64
|
+
margin-top: var(--token-side-nav-body-list-item-spacing-vertical);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.hds-side-nav__list-item-link { // <a>/<button> element (via Hds::Interactive)
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
width: 100%;
|
|
72
|
+
min-height: var(--token-side-nav-body-list-item-height);
|
|
73
|
+
padding: var(--token-side-nav-body-list-item-padding-vertical) var(--token-side-nav-body-list-item-padding-horizontal);
|
|
74
|
+
color: var(--token-side-nav-color-foreground-primary);
|
|
75
|
+
text-decoration: none;
|
|
76
|
+
background: var(--token-side-nav-color-surface-primary);
|
|
77
|
+
// "Link" could render as an HTML button element so this overrides the default border style in that case:
|
|
78
|
+
border-color: transparent;
|
|
79
|
+
border-radius: var(--token-side-nav-body-list-item-border-radius);
|
|
80
|
+
|
|
81
|
+
&:focus,
|
|
82
|
+
&.mock-focus {
|
|
83
|
+
@include hds-focus-ring-with-pseudo-element();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&:hover,
|
|
87
|
+
&.mock-hover {
|
|
88
|
+
background: var(--token-side-nav-color-surface-interactive-hover);
|
|
89
|
+
border-color: transparent;
|
|
90
|
+
|
|
91
|
+
.hds-side-nav__list-item-text,
|
|
92
|
+
.hds-side-nav__list-item-icon-leading,
|
|
93
|
+
.hds-side-nav__list-item-icon-trailing {
|
|
94
|
+
color: var(--token-side-nav-color-foreground-strong);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// notice: this ".active" extra class is used to match the corresponding `active` class assigned automatically
|
|
99
|
+
// by the `<LinkTo>` Ember component (when the link is "current), so that consumers get it for free if they want
|
|
100
|
+
// otherwise they can use the `@isActive` argument to set this visual state directly
|
|
101
|
+
&.active,
|
|
102
|
+
&:active,
|
|
103
|
+
&.mock-active {
|
|
104
|
+
background: var(--token-side-nav-color-surface-interactive-active);
|
|
105
|
+
|
|
106
|
+
.hds-side-nav__list-item-text,
|
|
107
|
+
.hds-side-nav__list-item-icon-leading,
|
|
108
|
+
.hds-side-nav__list-item-icon-trailing {
|
|
109
|
+
color: var(--token-side-nav-color-foreground-strong);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.hds-badge,
|
|
113
|
+
.hds-badge-count {
|
|
114
|
+
color: var(--token-color-foreground-primary);
|
|
115
|
+
background: var(--token-color-surface-strong);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.hds-badge,
|
|
120
|
+
.hds-badge-count {
|
|
121
|
+
margin-left: var(--token-side-nav-body-list-item-content-spacing-horizontal);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// special override for the "back-link" element (no visible active state, by design)
|
|
126
|
+
.hds-side-nav__list-item-link--back-link {
|
|
127
|
+
&:active,
|
|
128
|
+
&.mock-active {
|
|
129
|
+
background: var(--token-side-nav-color-surface-primary);
|
|
130
|
+
|
|
131
|
+
.hds-side-nav__list-item-text,
|
|
132
|
+
.hds-side-nav__list-item-icon-leading,
|
|
133
|
+
.hds-side-nav__list-item-icon-trailing {
|
|
134
|
+
color: var(--token-side-nav-color-foreground-primary);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
// LIST ITEM > INNER ELEMENTS
|
|
141
|
+
|
|
142
|
+
.hds-side-nav__list-item-text {
|
|
143
|
+
color: var(--token-side-nav-color-foreground-primary);
|
|
144
|
+
text-align: left;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.hds-side-nav__list-item-icon-leading {
|
|
148
|
+
flex: none;
|
|
149
|
+
margin-right: var(--token-side-nav-body-list-item-content-spacing-horizontal);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.hds-side-nav__list-item-icon-trailing {
|
|
153
|
+
flex: none;
|
|
154
|
+
margin-left: auto;
|
|
155
|
+
padding-left: var(--token-side-nav-body-list-item-content-spacing-horizontal);
|
|
156
|
+
}
|