@brightspace-ui/labs 2.8.0 → 2.9.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.
Files changed (42) hide show
  1. package/package.json +20 -1
  2. package/src/components/navigation/README.md +192 -0
  3. package/src/components/navigation/navigation-band.js +134 -0
  4. package/src/components/navigation/navigation-button-icon.js +120 -0
  5. package/src/components/navigation/navigation-dropdown-button-custom.js +35 -0
  6. package/src/components/navigation/navigation-dropdown-button-icon.js +86 -0
  7. package/src/components/navigation/navigation-immersive.js +265 -0
  8. package/src/components/navigation/navigation-iterator.js +97 -0
  9. package/src/components/navigation/navigation-link-back.js +39 -0
  10. package/src/components/navigation/navigation-link-icon.js +127 -0
  11. package/src/components/navigation/navigation-link-image.js +73 -0
  12. package/src/components/navigation/navigation-link.js +62 -0
  13. package/src/components/navigation/navigation-main-footer.js +27 -0
  14. package/src/components/navigation/navigation-main-header.js +67 -0
  15. package/src/components/navigation/navigation-notification-icon.js +54 -0
  16. package/src/components/navigation/navigation-separator.js +30 -0
  17. package/src/components/navigation/navigation-shared-styles.js +32 -0
  18. package/src/components/navigation/navigation-skip-main.js +31 -0
  19. package/src/components/navigation/navigation-skip.js +59 -0
  20. package/src/components/navigation/navigation-styles.js +107 -0
  21. package/src/components/navigation/navigation.js +60 -0
  22. package/src/lang/ar.js +4 -0
  23. package/src/lang/cy.js +4 -0
  24. package/src/lang/da.js +4 -0
  25. package/src/lang/de.js +4 -0
  26. package/src/lang/en-gb.js +4 -0
  27. package/src/lang/en.js +4 -0
  28. package/src/lang/es-es.js +4 -0
  29. package/src/lang/es.js +4 -0
  30. package/src/lang/fr-fr.js +4 -0
  31. package/src/lang/fr-on.js +4 -0
  32. package/src/lang/fr.js +4 -0
  33. package/src/lang/haw.js +4 -0
  34. package/src/lang/hi.js +4 -0
  35. package/src/lang/ja.js +4 -0
  36. package/src/lang/ko.js +4 -0
  37. package/src/lang/nl.js +4 -0
  38. package/src/lang/pt.js +4 -0
  39. package/src/lang/sv.js +4 -0
  40. package/src/lang/tr.js +4 -0
  41. package/src/lang/zh-cn.js +4 -0
  42. package/src/lang/zh-tw.js +4 -0
@@ -0,0 +1,265 @@
1
+ import '@brightspace-ui/core/components/colors/colors.js';
2
+ import './navigation.js';
3
+ import './navigation-link-back.js';
4
+ import { css, html, LitElement } from 'lit';
5
+ import { bodyCompactStyles } from '@brightspace-ui/core/components/typography/styles.js';
6
+ import { classMap } from 'lit/directives/class-map.js';
7
+ import { navigationSharedStyle } from './navigation-shared-styles.js';
8
+ import ResizeObserver from 'resize-observer-polyfill/dist/ResizeObserver.es.js';
9
+
10
+ const mediaQueryList = window.matchMedia('(max-width: 615px)');
11
+
12
+ class NavigationImmersive extends LitElement {
13
+
14
+ static get properties() {
15
+ return {
16
+ allowOverflow: {
17
+ attribute: 'allow-overflow',
18
+ type: Boolean,
19
+ reflect: true
20
+ },
21
+ backLinkHref: {
22
+ attribute: 'back-link-href',
23
+ type: String
24
+ },
25
+ backLinkText: {
26
+ attribute: 'back-link-text',
27
+ type: String
28
+ },
29
+ backLinkTextShort: {
30
+ attribute: 'back-link-text-short',
31
+ type: String
32
+ },
33
+ widthType: {
34
+ attribute: 'width-type',
35
+ type: String,
36
+ reflect: true
37
+ },
38
+ _middleHidden: { state: true },
39
+ _middleNoRightBorder: { state: true },
40
+ _smallWidth: { state: true }
41
+ };
42
+ }
43
+
44
+ static get styles() {
45
+ return [bodyCompactStyles, navigationSharedStyle, css`
46
+ :host {
47
+ --d2l-labs-navigation-immersive-height-main: 3.1rem;
48
+ --d2l-labs-navigation-immersive-height-responsive: 2.8rem;
49
+ }
50
+ .d2l-navigiation-immersive-fixed {
51
+ background-color: white;
52
+ left: 0;
53
+ position: fixed;
54
+ right: 0;
55
+ top: 0;
56
+ z-index: 2; /* higher than skeletons which could scroll behind immersive nav */
57
+ }
58
+ d2l-labs-navigation {
59
+ border-bottom: 1px solid var(--d2l-color-mica);
60
+ }
61
+ .d2l-labs-navigation-immersive-margin {
62
+ display: flex;
63
+ justify-content: center;
64
+ margin: 0 30px;
65
+ }
66
+
67
+ .d2l-labs-navigation-immersive-container {
68
+ display: flex;
69
+ height: var(--d2l-labs-navigation-immersive-height-main);
70
+ justify-content: space-between;
71
+ margin: 0 -7px;
72
+ max-width: 100%;
73
+ overflow: hidden;
74
+ width: 100%;
75
+ }
76
+
77
+ :host([width-type="normal"]) .d2l-labs-navigation-immersive-container {
78
+ max-width: 1230px;
79
+ }
80
+
81
+ :host([allow-overflow]) .d2l-labs-navigation-immersive-container {
82
+ overflow: visible;
83
+ }
84
+
85
+ .d2l-labs-navigation-immersive-left ::slotted(*),
86
+ .d2l-labs-navigation-immersive-middle ::slotted(*),
87
+ .d2l-labs-navigation-immersive-right ::slotted(*) {
88
+ height: var(--d2l-labs-navigation-immersive-height-main);
89
+ }
90
+
91
+ .d2l-labs-navigation-immersive-left {
92
+ color: var(--d2l-color-tungsten);
93
+ letter-spacing: 0.2px;
94
+ padding-left: 7px;
95
+ }
96
+
97
+ .d2l-labs-navigation-immersive-right {
98
+ padding-right: 7px;
99
+ }
100
+
101
+ .d2l-labs-navigation-immersive-left,
102
+ .d2l-labs-navigation-immersive-right {
103
+ flex: 0 0 auto;
104
+ }
105
+
106
+ .d2l-labs-navigation-immersive-middle {
107
+ border-inline-end: 1px solid var(--d2l-color-gypsum);
108
+ border-inline-start: 1px solid var(--d2l-color-gypsum);
109
+ flex: 0 1 auto;
110
+ margin: 0 24px;
111
+ min-width: 0;
112
+ padding: 0 24px;
113
+ width: 100%;
114
+ }
115
+
116
+ .d2l-labs-navigation-immersive-middle.d2l-labs-navigation-immersive-middle-no-right-border {
117
+ border-inline-end: none;
118
+ }
119
+
120
+ div.d2l-labs-navigation-immersive-middle-observer,
121
+ div.d2l-labs-navigation-immersive-right-observer {
122
+ height: auto;
123
+ }
124
+
125
+ .d2l-labs-navigation-immersive-middle-hidden {
126
+ visibility: hidden;
127
+ }
128
+
129
+ .d2l-labs-navigation-immersive-spacing {
130
+ height: calc(var(--d2l-labs-navigation-immersive-height-main) + 5px);
131
+ position: unset;
132
+ }
133
+
134
+ @media (max-width: 929px) {
135
+ .d2l-labs-navigation-immersive-margin {
136
+ margin: 0 24px;
137
+ }
138
+ }
139
+
140
+ @media (max-width: 767px) {
141
+ .d2l-labs-navigation-immersive-margin {
142
+ margin: 0 18px;
143
+ }
144
+ }
145
+
146
+ @media (max-width: 615px) {
147
+ .d2l-labs-navigation-immersive-container {
148
+ height: var(--d2l-labs-navigation-immersive-height-responsive);
149
+ }
150
+ .d2l-labs-navigation-immersive-left ::slotted(*),
151
+ .d2l-labs-navigation-immersive-middle ::slotted(*),
152
+ .d2l-labs-navigation-immersive-right ::slotted(*) {
153
+ height: var(--d2l-labs-navigation-immersive-height-responsive);
154
+ }
155
+ .d2l-labs-navigation-immersive-spacing {
156
+ height: calc(var(--d2l-labs-navigation-immersive-height-responsive) + 5px);
157
+ }
158
+ .d2l-labs-navigation-immersive-middle {
159
+ margin: 0 18px;
160
+ padding: 0 18px;
161
+ }
162
+ }
163
+ `];
164
+ }
165
+
166
+ constructor() {
167
+ super();
168
+ this._handlePageResize = this._handlePageResize.bind(this);
169
+ this._middleHidden = false;
170
+ this._middleNoRightBorder = true;
171
+ this._middleObserver = new ResizeObserver(this._onMiddleResize.bind(this));
172
+ this._rightObserver = new ResizeObserver(this._onRightResize.bind(this));
173
+ this._smallWidth = false;
174
+ }
175
+
176
+ connectedCallback() {
177
+ super.connectedCallback();
178
+ this._startObserving();
179
+ if (mediaQueryList.addEventListener) mediaQueryList.addEventListener('change', this._handlePageResize);
180
+ }
181
+
182
+ disconnectedCallback() {
183
+ super.disconnectedCallback();
184
+ if (this._middleObserver) this._middleObserver.disconnect();
185
+ if (this._rightObserver) this._rightObserver.disconnect();
186
+ if (mediaQueryList.removeEventListener) mediaQueryList.removeEventListener('change', this._handlePageResize);
187
+ }
188
+
189
+ firstUpdated(changedProperties) {
190
+ super.firstUpdated(changedProperties);
191
+ this._startObserving();
192
+ this._smallWidth = mediaQueryList.matches;
193
+ }
194
+
195
+ render() {
196
+ const middleContainerClasses = {
197
+ 'd2l-labs-navigation-immersive-middle': true,
198
+ 'd2l-labs-navigation-immersive-middle-hidden': this._middleHidden,
199
+ 'd2l-labs-navigation-immersive-middle-no-right-border': this._middleNoRightBorder
200
+ };
201
+ const backLinkText = this._smallWidth ? (this.backLinkTextShort || this.backLinkText) : this.backLinkText;
202
+ return html`
203
+ <div class="d2l-navigiation-immersive-fixed">
204
+ <d2l-labs-navigation>
205
+ <div class="d2l-labs-navigation-immersive-margin">
206
+ <div class="d2l-labs-navigation-immersive-container">
207
+ <div class="d2l-labs-navigation-immersive-left d2l-body-compact">
208
+ <slot name="left">
209
+ <d2l-labs-navigation-link-back text="${backLinkText}" href="${this.backLinkHref}" @click="${this._handleBackClick}"></d2l-labs-navigation-link-back>
210
+ </slot>
211
+ </div>
212
+ <div class="${classMap(middleContainerClasses)}">
213
+ <div class="d2l-labs-navigation-immersive-middle-observer">
214
+ <slot name="middle"></slot>
215
+ </div>
216
+ </div>
217
+ <div class="d2l-labs-navigation-immersive-right"><div class="d2l-labs-navigation-immersive-right-observer"><slot name="right"></slot></div></div>
218
+ </div>
219
+ </div>
220
+ </d2l-labs-navigation>
221
+ </div>
222
+ <div class="d2l-labs-navigation-immersive-spacing"></div>
223
+ `;
224
+ }
225
+
226
+ _handleBackClick() {
227
+ this.dispatchEvent(
228
+ new CustomEvent(
229
+ 'd2l-labs-navigation-immersive-back-click',
230
+ { bubbles: false, composed: false }
231
+ )
232
+ );
233
+ }
234
+
235
+ _handlePageResize(e) {
236
+ this._smallWidth = e.matches;
237
+ }
238
+
239
+ _onMiddleResize(entries) {
240
+ if (!entries || entries.length === 0) {
241
+ return;
242
+ }
243
+ this._middleHidden = (entries[0].contentRect.height < 1);
244
+ }
245
+
246
+ _onRightResize(entries) {
247
+ if (!entries || entries.length === 0) {
248
+ return;
249
+ }
250
+ this._middleNoRightBorder = (entries[0].contentRect.height < 1);
251
+ }
252
+
253
+ _startObserving() {
254
+ const middle = this.shadowRoot?.querySelector('.d2l-labs-navigation-immersive-middle-observer');
255
+ if (middle) {
256
+ this._middleObserver.observe(middle);
257
+ }
258
+ const right = this.shadowRoot?.querySelector('.d2l-labs-navigation-immersive-right-observer');
259
+ if (right) {
260
+ this._rightObserver.observe(right);
261
+ }
262
+ }
263
+
264
+ }
265
+ customElements.define('d2l-labs-navigation-immersive', NavigationImmersive);
@@ -0,0 +1,97 @@
1
+ import './navigation-button-icon.js';
2
+ import { css, html, LitElement } from 'lit';
3
+ import { bodyCompactStyles } from '@brightspace-ui/core/components/typography/styles.js';
4
+ import { LocalizeLabsElement } from '../localize-labs-element.js';
5
+
6
+ class NavigationIterator extends LocalizeLabsElement(LitElement) {
7
+
8
+ static get properties() {
9
+ return {
10
+ hideText: { attribute: 'hide-text', type: Boolean },
11
+ previousDisabled: { attribute: 'previous-disabled', type: Boolean },
12
+ previousText: { attribute: 'previous-text', type: String },
13
+ nextDisabled: { attribute: 'next-disabled', type: Boolean },
14
+ nextText: { attribute: 'next-text', type: String },
15
+ };
16
+ }
17
+
18
+ static get styles() {
19
+ return [bodyCompactStyles, css`
20
+ :host {
21
+ align-items: center;
22
+ display: flex;
23
+ gap: 1.2rem;
24
+ height: 3.3rem;
25
+ justify-content: space-between;
26
+ max-width: 20rem;
27
+ }
28
+ :host([hidden]) {
29
+ display: none;
30
+ }
31
+ `];
32
+ }
33
+
34
+ constructor() {
35
+ super();
36
+ this.hideText = false;
37
+ this.nextDisabled = false;
38
+ this.nextText = '';
39
+ this.previousDisabled = false;
40
+ this.previousText = '';
41
+ }
42
+
43
+ render() {
44
+ const previousText = this.previousText ? this.previousText : this.localize('components:navigation:previous');
45
+ const nextText = this.nextText ? this.nextText : this.localize('components:navigation:next');
46
+ return html`
47
+ <d2l-labs-navigation-button-icon
48
+ class="d2l-body-compact"
49
+ icon="tier3:chevron-left-circle"
50
+ icon-position="start"
51
+ text="${previousText}"
52
+ ?text-hidden="${this.hideText}"
53
+ ?disabled="${this.previousDisabled}"
54
+ @click="${this._dispatchPreviousClicked}"></d2l-labs-navigation-button-icon>
55
+ <slot class="d2l-body-compact"></slot>
56
+ <d2l-labs-navigation-button-icon
57
+ class="d2l-body-compact"
58
+ icon="tier3:chevron-right-circle"
59
+ icon-position="end"
60
+ text="${nextText}"
61
+ ?text-hidden="${this.hideText}"
62
+ ?disabled="${this.nextDisabled}"
63
+ @click="${this._dispatchNextClicked}"></d2l-labs-navigation-button-icon>
64
+ `;
65
+ }
66
+
67
+ _dispatchNextClicked(e) {
68
+ if (this.nextDisabled) {
69
+ return;
70
+ }
71
+
72
+ e.stopPropagation();
73
+
74
+ this.dispatchEvent(new CustomEvent('next-click', {
75
+ detail: {
76
+ type: e.currentTarget.type
77
+ }
78
+ }));
79
+ }
80
+
81
+ _dispatchPreviousClicked(e) {
82
+ if (this.previousDisabled) {
83
+ return;
84
+ }
85
+
86
+ e.stopPropagation();
87
+
88
+ this.dispatchEvent(new CustomEvent('previous-click', {
89
+ detail: {
90
+ type: e.currentTarget.type
91
+ }
92
+ }));
93
+ }
94
+
95
+ }
96
+
97
+ window.customElements.define('d2l-labs-navigation-iterator', NavigationIterator);
@@ -0,0 +1,39 @@
1
+ import './navigation-link-icon.js';
2
+ import { css, html, LitElement } from 'lit';
3
+ import { FocusMixin } from '@brightspace-ui/core/mixins/focus-mixin.js';
4
+ import { LocalizeLabsElement } from '../localize-labs-element.js';
5
+
6
+ class NavigationLinkBack extends LocalizeLabsElement(FocusMixin(LitElement)) {
7
+
8
+ static get properties() {
9
+ return {
10
+ text: { type: String },
11
+ href: { type: String }
12
+ };
13
+ }
14
+
15
+ static get styles() {
16
+ return css`
17
+ :host {
18
+ display: inline-block;
19
+ height: 100%;
20
+ }
21
+ :host([hidden]) {
22
+ display: none;
23
+ }
24
+ `;
25
+ }
26
+
27
+ static get focusElementSelector() {
28
+ return 'd2l-labs-navigation-link-icon';
29
+ }
30
+
31
+ render() {
32
+ const href = this.href ? this.href : 'javascript:void(0);'; // backwards-compatible for uses before missing "href" threw exception
33
+ const text = this.text ? this.text : this.localize('components:navigation:back');
34
+ return html`<d2l-labs-navigation-link-icon href="${href}" icon="tier1:chevron-left" text="${text}"></d2l-labs-navigation-link-icon>`;
35
+ }
36
+
37
+ }
38
+
39
+ customElements.define('d2l-labs-navigation-link-back', NavigationLinkBack);
@@ -0,0 +1,127 @@
1
+ import '@brightspace-ui/core/components/icons/icon.js';
2
+ import '@brightspace-ui/core/components/tooltip/tooltip.js';
3
+ import { css, html, LitElement, nothing } from 'lit';
4
+ import { highlightBorderStyles, highlightLinkStyles } from './navigation-styles.js';
5
+ import { FocusMixin } from '@brightspace-ui/core/mixins/focus-mixin.js';
6
+ import { getUniqueId } from '@brightspace-ui/core/helpers/uniqueId.js';
7
+ import { ifDefined } from 'lit/directives/if-defined.js';
8
+ import { offscreenStyles } from '@brightspace-ui/core/components/offscreen/offscreen.js';
9
+
10
+ /**
11
+ * Navigation link with an icon and text.
12
+ */
13
+ class NavigationLinkIcon extends FocusMixin(LitElement) {
14
+
15
+ static get properties() {
16
+ return {
17
+ /**
18
+ * REQUIRED: URL or URL fragment of the link
19
+ * @type {string}
20
+ */
21
+ href: { type: String },
22
+ /**
23
+ * REQUIRED: Preset icon key (e.g. "tier1:gear")
24
+ * @type {string}
25
+ */
26
+ icon: { type: String },
27
+ /**
28
+ * REQUIRED: Text for the link
29
+ * @type {string}
30
+ */
31
+ text: { type: String },
32
+ /**
33
+ * Visually hides the text but still accessible
34
+ * @type {boolean}
35
+ */
36
+ textHidden: { attribute: 'text-hidden', type: Boolean },
37
+ /**
38
+ * Offset of the tooltip
39
+ * @type {Number}
40
+ */
41
+ tooltipOffset: { attribute: 'tooltip-offset', type: Number }
42
+ };
43
+ }
44
+
45
+ static get styles() {
46
+ return [highlightBorderStyles, highlightLinkStyles, offscreenStyles, css`
47
+ :host {
48
+ display: inline-block;
49
+ height: 100%;
50
+ }
51
+ :host([hidden]) {
52
+ display: none;
53
+ }
54
+ `];
55
+ }
56
+
57
+ constructor() {
58
+ super();
59
+ this.textHidden = false;
60
+ this._linkId = getUniqueId();
61
+ this._missingHrefErrorHasBeenThrown = false;
62
+ this._validatingHrefTimeout = null;
63
+ }
64
+
65
+ static get focusElementSelector() {
66
+ return 'a';
67
+ }
68
+
69
+ firstUpdated(changedProperties) {
70
+ super.firstUpdated(changedProperties);
71
+ this._validateHref();
72
+ }
73
+
74
+ render() {
75
+ const { ariaLabel, id, text, tooltip } = this._getRenderSettings();
76
+ return html`
77
+ <a id="${ifDefined(id)}" href="${ifDefined(this.href)}" aria-label="${ifDefined(ariaLabel)}">
78
+ <span class="d2l-labs-navigation-highlight-border"></span>
79
+ <d2l-icon icon="${this.icon}"></d2l-icon>
80
+ ${text}
81
+ </a>
82
+ ${tooltip}
83
+ `;
84
+ }
85
+
86
+ updated(changedProperties) {
87
+
88
+ super.updated(changedProperties);
89
+
90
+ if (changedProperties.has('href')) this._validateHref();
91
+
92
+ }
93
+
94
+ _getRenderSettings() {
95
+ if (this.textHidden) {
96
+ return {
97
+ ariaLabel: this.text,
98
+ id: this._linkId,
99
+ text: nothing,
100
+ tooltip: html`<d2l-tooltip for="${this._linkId}" for-type="label" position="bottom" offset="${ifDefined(this.tooltipOffset)}" class="vdiff-target">${this.text}</d2l-tooltip>`
101
+ };
102
+ }
103
+ return {
104
+ ariaLabel: undefined,
105
+ id: undefined,
106
+ text: this.text,
107
+ tooltip: nothing
108
+ };
109
+ }
110
+
111
+ _validateHref() {
112
+ clearTimeout(this._validatingHrefTimeout);
113
+ // don't error immediately in case it doesn't get set immediately
114
+ this._validatingHrefTimeout = setTimeout(() => {
115
+ this._validatingHrefTimeout = null;
116
+ const hasHref = (typeof this.href === 'string') && this.href.length > 0;
117
+ if (!hasHref && !this._missingHrefErrorHasBeenThrown) {
118
+ this._missingHrefErrorHasBeenThrown = true;
119
+ // we don't want to prevent rendering
120
+ setTimeout(() => { throw new Error('<d2l-labs-navigation-link-icon>: missing required "href" attribute. If this component performs an action and not a navigation, consider using <d2l-labs-navigation-button-icon> instead.'); });
121
+ }
122
+ }, 3000);
123
+ }
124
+
125
+ }
126
+
127
+ customElements.define('d2l-labs-navigation-link-icon', NavigationLinkIcon);
@@ -0,0 +1,73 @@
1
+ import '@brightspace-ui/core/components/tooltip/tooltip.js';
2
+ import { css, html, LitElement, nothing } from 'lit';
3
+ import { highlightBorderStyles, highlightLinkStyles } from './navigation-styles.js';
4
+ import { FocusMixin } from '@brightspace-ui/core/mixins/focus-mixin.js';
5
+ import { getUniqueId } from '@brightspace-ui/core/helpers/uniqueId.js';
6
+ import { ifDefined } from 'lit/directives/if-defined.js';
7
+
8
+ class NavigationLinkImage extends FocusMixin(LitElement) {
9
+
10
+ static get properties() {
11
+ return {
12
+ href: { type: String },
13
+ slim: { reflect: true, type: Boolean },
14
+ src: { type: String },
15
+ text: { type: String },
16
+ tooltipOffset: { attribute: 'tooltip-offset', type: Number }
17
+ };
18
+ }
19
+
20
+ static get styles() {
21
+ return [highlightBorderStyles, highlightLinkStyles, css`
22
+ :host {
23
+ display: inline-block;
24
+ height: 100%;
25
+ }
26
+ :host([hidden]) {
27
+ display: none;
28
+ }
29
+ img {
30
+ max-height: 60px;
31
+ max-width: 260px;
32
+ vertical-align: middle;
33
+ }
34
+ :host([slim]) img {
35
+ max-height: 40px;
36
+ max-width: 173px;
37
+ }
38
+ .d2l-labs-navigation-link-image-container {
39
+ align-items: center;
40
+ display: inline-flex;
41
+ height: 100%;
42
+ vertical-align: middle;
43
+ }
44
+ `];
45
+ }
46
+
47
+ constructor() {
48
+ super();
49
+ this.slim = false;
50
+ this.text = '';
51
+ this._linkId = getUniqueId();
52
+ }
53
+
54
+ static get focusElementSelector() {
55
+ return 'a';
56
+ }
57
+
58
+ render() {
59
+ const image = html`<img src="${this.src}" alt="${this.text}">`;
60
+ if (this.href) {
61
+ return html`
62
+ <a href="${this.href}" id="${this._linkId}">
63
+ <span class="d2l-labs-navigation-highlight-border"></span>
64
+ <span class="d2l-labs-navigation-link-image-container">${image}</span>
65
+ </a>
66
+ ${this.text ? html`<d2l-tooltip for="${this._linkId}" for-type="label" position="bottom" offset="${ifDefined(this.tooltipOffset)}" class="vdiff-target">${this.text}</d2l-tooltip>` : nothing}
67
+ `;
68
+ }
69
+ return html`<span class="d2l-labs-navigation-link-image-container">${image}</span>`;
70
+ }
71
+ }
72
+
73
+ customElements.define('d2l-labs-navigation-link-image', NavigationLinkImage);
@@ -0,0 +1,62 @@
1
+ import '@brightspace-ui/core/components/colors/colors.js';
2
+ import { css, html, LitElement } from 'lit';
3
+ import { FocusMixin } from '@brightspace-ui/core/mixins/focus-mixin.js';
4
+ import { highlightBorderStyles } from './navigation-styles.js';
5
+
6
+ class D2LNavigationLink extends FocusMixin(LitElement) {
7
+
8
+ static get properties() {
9
+ return {
10
+ href: {
11
+ reflect: true,
12
+ type: String
13
+ },
14
+ text: {
15
+ type: String
16
+ }
17
+ };
18
+ }
19
+
20
+ static get styles() {
21
+ return [highlightBorderStyles, css`
22
+ :host {
23
+ display: inline-block;
24
+ height: 100%;
25
+ }
26
+ a {
27
+ align-items: center;
28
+ color: var(--d2l-color-ferrite);
29
+ display: inline-flex;
30
+ height: 100%;
31
+ min-height: 40px;
32
+ position: relative;
33
+ text-decoration: none;
34
+ vertical-align: middle;
35
+ }
36
+ a:hover,
37
+ a:focus {
38
+ --d2l-icon-fill-color: var(--d2l-color-celestine);
39
+ color: var(--d2l-color-celestine);
40
+ outline: none;
41
+ }
42
+ :host(:not([href])) .d2l-labs-navigation-highlight-border {
43
+ display: none;
44
+ }
45
+ `];
46
+ }
47
+
48
+ static get focusElementSelector() {
49
+ return 'a';
50
+ }
51
+
52
+ render() {
53
+ return html`
54
+ <a href="${this.href}" title="${this.text}">
55
+ <span class="d2l-labs-navigation-highlight-border"></span>
56
+ <slot></slot>
57
+ </a>
58
+ `;
59
+ }
60
+ }
61
+
62
+ customElements.define('d2l-labs-navigation-link', D2LNavigationLink);
@@ -0,0 +1,27 @@
1
+ import { css, html, LitElement } from 'lit';
2
+ import { navigationSharedStyle } from './navigation-shared-styles.js';
3
+
4
+ class NavigationMainFooter extends LitElement {
5
+
6
+ static get styles() {
7
+ return [navigationSharedStyle, css`
8
+ :host {
9
+ border-bottom: 1px solid rgba(124, 134, 149, 0.18);
10
+ border-top: 1px solid rgba(124, 134, 149, 0.18);
11
+ display: block;
12
+ }
13
+ `];
14
+ }
15
+
16
+ render() {
17
+ return html`
18
+ <div class="d2l-labs-navigation-centerer">
19
+ <div class="d2l-labs-navigation-gutters">
20
+ <slot name="main"></slot>
21
+ </div>
22
+ </div>
23
+ `;
24
+ }
25
+
26
+ }
27
+ customElements.define('d2l-labs-navigation-main-footer', NavigationMainFooter);