@brightspace-ui/core 3.139.0 → 3.140.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.
@@ -64,17 +64,17 @@ class ButtonIcon extends SlottedIconMixin(PropertyRequiredMixin(ThemeMixin(Butto
64
64
  :host([translucent]) {
65
65
  --d2l-button-icon-background-color: rgba(0, 0, 0, 0.5);
66
66
  --d2l-button-icon-background-color-hover: var(--d2l-color-celestine);
67
- --d2l-button-focus-color: white;
68
- --d2l-button-focus-offset: -4px;
67
+ --d2l-focus-ring-color: white;
68
+ --d2l-focus-ring-offset: -4px;
69
69
  --d2l-button-icon-fill-color: white;
70
70
  --d2l-button-icon-fill-color-hover: white;
71
71
  }
72
72
  :host([theme="dark"]) {
73
73
  --d2l-button-icon-background-color: transparent;
74
74
  --d2l-button-icon-background-color-hover: rgba(51, 53, 54, 0.9); /* tungsten @70% @90% */
75
- --d2l-button-focus-color: var(--d2l-color-celestine-plus-1);
76
75
  --d2l-button-icon-fill-color: var(--d2l-color-sylvite);
77
76
  --d2l-button-icon-fill-color-hover: var(--d2l-color-sylvite);
77
+ --d2l-focus-ring-color: var(--d2l-color-celestine-plus-1);
78
78
  }
79
79
 
80
80
  button {
@@ -102,8 +102,8 @@ class ButtonMove extends ThemeMixin(FocusMixin(RtlMixin(LitElement))) {
102
102
  :host([theme="dark"]) {
103
103
  --d2l-button-move-background-color-focus: #000000;
104
104
  --d2l-button-move-icon-background-color-hover: rgba(51, 53, 54, 0.9); /* tungsten @70% @90% */
105
- --d2l-button-focus-color: var(--d2l-color-celestine-plus-1);
106
105
  --d2l-icon-fill-color: var(--d2l-color-sylvite);
106
+ --d2l-focus-ring-color: var(--d2l-color-celestine-plus-1);
107
107
  }
108
108
  button {
109
109
  background-color: transparent;
@@ -1,6 +1,6 @@
1
1
  import '../colors/colors.js';
2
- import { css, unsafeCSS } from 'lit';
3
- import { getFocusPseudoClass } from '../../helpers/focus.js';
2
+ import { css } from 'lit';
3
+ import { getFocusRingStyles } from '../../helpers/focus.js';
4
4
 
5
5
  export const buttonStyles = css`
6
6
  button {
@@ -24,10 +24,7 @@ export const buttonStyles = css`
24
24
  white-space: nowrap;
25
25
  width: auto;
26
26
  }
27
- button:${unsafeCSS(getFocusPseudoClass())} {
28
- outline: 2px solid var(--d2l-button-focus-color, var(--d2l-color-celestine));
29
- outline-offset: var(--d2l-button-focus-offset, 2px);
30
- }
27
+ ${getFocusRingStyles('button')}
31
28
  @media (prefers-contrast: more) {
32
29
  button {
33
30
  border: 2px solid transparent;
@@ -1,5 +1,6 @@
1
1
  import '../colors/colors.js';
2
2
  import { css } from 'lit';
3
+ import { getFocusRingStyles } from '../../helpers/focus.js';
3
4
 
4
5
  export const dialogStyles = css`
5
6
 
@@ -131,13 +132,7 @@ export const dialogStyles = css`
131
132
  overflow: hidden; /* scrollbar is kept hidden while we update the scroll position to avoid scrollbar flash */
132
133
  padding: 0 30px;
133
134
  }
134
-
135
- .d2l-dialog-content:focus-visible {
136
- border-radius: 6px;
137
- outline: 2px solid var(--d2l-color-celestine);
138
- outline-offset: -2px;
139
- }
140
-
135
+ ${getFocusRingStyles('.d2l-dialog-content', { extraStyles: css`--d2l-focus-ring-offset: -2px; border-radius: 6px;` })}
141
136
  .d2l-dialog-content > div {
142
137
  position: relative; /* make this the positioned parent for absolute positioned elements like d2l-template-primary-secondary */
143
138
  }
@@ -1,6 +1,6 @@
1
1
  import '../colors/colors.js';
2
- import { css, unsafeCSS } from 'lit';
3
- import { getFocusPseudoClass } from '../../helpers/focus.js';
2
+ import { css } from 'lit';
3
+ import { getFocusRingStyles } from '../../helpers/focus.js';
4
4
 
5
5
  export const emptyStateStyles = css`
6
6
 
@@ -20,13 +20,11 @@ export const emptyStateStyles = css`
20
20
  .action-slot::slotted(d2l-empty-state-action-link:first-of-type) {
21
21
  display: inline;
22
22
  }
23
-
24
- .d2l-empty-state-description:${unsafeCSS(getFocusPseudoClass())} {
23
+ .d2l-empty-state-description {
24
+ --d2l-focus-ring-offset: 3px;
25
25
  border-radius: 0.3rem;
26
- outline: 2px solid var(--d2l-color-celestine);
27
- outline-offset: 3px;
28
26
  }
29
-
27
+ ${getFocusRingStyles('.d2l-empty-state-description')}
30
28
  `;
31
29
 
32
30
  export const emptyStateSimpleStyles = css`
@@ -1,9 +1,9 @@
1
1
  import '../colors/colors.js';
2
2
  import { codeStyles, createHtmlBlockRenderer as createCodeRenderer } from '../../helpers/prism.js';
3
- import { css, html, LitElement, unsafeCSS } from 'lit';
3
+ import { css, html, LitElement } from 'lit';
4
4
  import { classMap } from 'lit/directives/class-map.js';
5
5
  import { createHtmlBlockRenderer as createMathRenderer } from '../../helpers/mathjax.js';
6
- import { getFocusPseudoClass } from '../../helpers/focus.js';
6
+ import { getFocusRingStyles } from '../../helpers/focus.js';
7
7
  import { LoadingCompleteMixin } from '../../mixins/loading-complete/loading-complete-mixin.js';
8
8
  import { renderEmbeds } from '../../helpers/embeds.js';
9
9
  import { requestInstance } from '../../mixins/provider/provider-mixin.js';
@@ -108,12 +108,11 @@ export const htmlBlockContentStyles = css`
108
108
  color: var(--d2l-color-celestine-minus-1, #004489);
109
109
  text-decoration: underline;
110
110
  }
111
- a:${unsafeCSS(getFocusPseudoClass())} {
112
- border-radius: 2px;
113
- outline: 2px solid var(--d2l-color-celestine, #006fbf);
114
- outline-offset: 1px;
115
- text-decoration: underline;
111
+ a {
112
+ --d2l-focus-ring-offset: 1px;
113
+ --d2l-focus-ring-color: var(--d2l-color-celestine, #006fbf);
116
114
  }
115
+ ${getFocusRingStyles('a', { extraStyles: css`border-radius: 2px; text-decoration: underline;` })}
117
116
  @media print {
118
117
  a,
119
118
  a:visited,
@@ -1,12 +1,12 @@
1
1
  import '../dropdown/dropdown.js';
2
2
  import '../dropdown/dropdown-content.js';
3
3
  import '../tooltip/tooltip.js';
4
- import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
4
+ import { css, html, LitElement, nothing } from 'lit';
5
5
  import { buttonStyles } from '../button/button-styles.js';
6
6
  import { classMap } from 'lit/directives/class-map.js';
7
7
  import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
8
8
  import { FormElementMixin } from '../form/form-element-mixin.js';
9
- import { getFocusPseudoClass } from '../../helpers/focus.js';
9
+ import { getFocusRingStyles } from '../../helpers/focus.js';
10
10
  import { getUniqueId } from '../../helpers/uniqueId.js';
11
11
  import { getValidHexColor } from '../../helpers/color.js';
12
12
  import { ifDefined } from 'lit/directives/if-defined.js';
@@ -226,14 +226,7 @@ class InputColor extends InputInlineHelpMixin(PropertyRequiredMixin(FocusMixin(F
226
226
  outline: none;
227
227
  width: 1.2rem;
228
228
  }
229
- .readonly-wrapper:focus {
230
- outline: none;
231
- }
232
- .readonly-wrapper:${unsafeCSS(getFocusPseudoClass())} {
233
- outline: 2px solid var(--d2l-color-celestine);
234
- outline-offset: 2px;
235
- }
236
-
229
+ ${getFocusRingStyles('.readonly-wrapper')}
237
230
  @media (prefers-contrast: more) {
238
231
  .swatch {
239
232
  border: 1px solid FieldText;
@@ -80,7 +80,7 @@ class InputSearch extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement)))
80
80
  --d2l-button-icon-min-height: 1.5rem;
81
81
  --d2l-button-icon-min-width: 1.5rem;
82
82
  --d2l-button-icon-border-radius: 4px;
83
- --d2l-button-focus-offset: 1px;
83
+ --d2l-focus-ring-offset: 1px;
84
84
  margin-left: 0.3rem;
85
85
  margin-right: 0.3rem;
86
86
  }
@@ -1,9 +1,9 @@
1
1
  import '../colors/colors.js';
2
2
  import '../icons/icon.js';
3
- import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
3
+ import { css, html, LitElement, nothing } from 'lit';
4
4
  import { classMap } from 'lit/directives/class-map.js';
5
5
  import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
6
- import { getFocusPseudoClass } from '../../helpers/focus.js';
6
+ import { getFocusRingStyles } from '../../helpers/focus.js';
7
7
  import { ifDefined } from 'lit/directives/if-defined.js';
8
8
  import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
9
9
  import { offscreenStyles } from '../offscreen/offscreen.js';
@@ -11,6 +11,7 @@ import { styleMap } from 'lit/directives/style-map.js';
11
11
 
12
12
  export const linkStyles = css`
13
13
  .d2l-link, .d2l-link:visited, .d2l-link:active, .d2l-link:link {
14
+ --d2l-focus-ring-offset: 1px;
14
15
  color: var(--d2l-color-celestine);
15
16
  cursor: pointer;
16
17
  outline-style: none;
@@ -24,12 +25,7 @@ export const linkStyles = css`
24
25
  color: var(--d2l-color-celestine-minus-1);
25
26
  text-decoration: underline;
26
27
  }
27
- .d2l-link:${unsafeCSS(getFocusPseudoClass())} {
28
- border-radius: 2px;
29
- outline: 2px solid var(--d2l-color-celestine);
30
- outline-offset: 1px;
31
- text-decoration: underline;
32
- }
28
+ ${getFocusRingStyles('.d2l-link', { extraStyles: css`border-radius: 2px; text-decoration: underline;` })}
33
29
  .d2l-link.d2l-link-main {
34
30
  font-weight: 700;
35
31
  }
@@ -1,8 +1,8 @@
1
1
  import '../colors/colors.js';
2
- import { css, html, unsafeCSS } from 'lit';
2
+ import { css, html } from 'lit';
3
3
  import { classMap } from 'lit/directives/class-map.js';
4
4
  import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
5
- import { getFocusPseudoClass } from '../../helpers/focus.js';
5
+ import { getFocusRingStyles } from '../../helpers/focus.js';
6
6
  import { getUniqueId } from '../../helpers/uniqueId.js';
7
7
  import { ifDefined } from 'lit/directives/if-defined.js';
8
8
  import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
@@ -47,6 +47,7 @@ export const SwitchMixin = superclass => class extends FocusMixin(RtlMixin(super
47
47
  }
48
48
 
49
49
  .d2l-switch-container {
50
+ --d2l-focus-ring-offset: 0;
50
51
  background-color: var(--d2l-switch-container-background-color, #ffffff);
51
52
  border-radius: 1rem;
52
53
  box-sizing: border-box;
@@ -58,9 +59,7 @@ export const SwitchMixin = superclass => class extends FocusMixin(RtlMixin(super
58
59
  padding: 0.1rem;
59
60
  vertical-align: middle;
60
61
  }
61
- .d2l-switch-container:${unsafeCSS(getFocusPseudoClass())} {
62
- outline: 2px solid var(--d2l-color-celestine);
63
- }
62
+ ${getFocusRingStyles('.d2l-switch-container')}
64
63
  :host([disabled]) .d2l-switch-container {
65
64
  cursor: default;
66
65
  opacity: 0.5;
@@ -1,5 +1,5 @@
1
- import { css, html, LitElement, unsafeCSS } from 'lit';
2
- import { getFocusPseudoClass } from '../../../helpers/focus.js';
1
+ import { css, html, LitElement } from 'lit';
2
+ import { getFocusRingStyles } from '../../../helpers/focus.js';
3
3
  import { TabMixin } from '../tab-mixin.js';
4
4
 
5
5
  class TabCustom extends TabMixin(LitElement) {
@@ -7,6 +7,7 @@ class TabCustom extends TabMixin(LitElement) {
7
7
  static get styles() {
8
8
  const styles = [ css`
9
9
  .d2l-tab-custom-content {
10
+ --d2l-focus-ring-offset: 0;
10
11
  margin: 0.5rem;
11
12
  overflow: hidden;
12
13
  padding: 0.1rem;
@@ -15,11 +16,10 @@ class TabCustom extends TabMixin(LitElement) {
15
16
  :host(:first-child) .d2l-tab-custom-content {
16
17
  margin-inline-start: 0;
17
18
  }
18
- :host(:${unsafeCSS(getFocusPseudoClass())}) .d2l-tab-custom-content {
19
- border-radius: 0.3rem;
20
- color: var(--d2l-color-celestine);
21
- outline: 2px solid var(--d2l-color-celestine);
22
- }
19
+ ${getFocusRingStyles(
20
+ pseudoClass => `:host(:${pseudoClass}) .d2l-tab-custom-content`,
21
+ { extraStyles: 'border-radius: 0.3rem; color: var(--d2l-color-celestine);' }
22
+ )}
23
23
  `];
24
24
 
25
25
  super.styles && styles.unshift(super.styles);
@@ -1,8 +1,13 @@
1
1
  import { css, html, LitElement, unsafeCSS } from 'lit';
2
+ import { getFocusPseudoClass, getFocusRingStyles } from '../../helpers/focus.js';
2
3
  import { classMap } from 'lit/directives/class-map.js';
3
- import { getFocusPseudoClass } from '../../helpers/focus.js';
4
4
  import { TabMixin } from './tab-mixin.js';
5
5
 
6
+ const focusRingStyles = getFocusRingStyles(
7
+ pseudoClass => `:host(:${pseudoClass}) .d2l-tab-text-inner-content`,
8
+ { extraStyles: css`border-radius: 0.3rem; color: var(--d2l-color-celestine);` }
9
+ );
10
+
6
11
  /**
7
12
  * @attr {string} id - REQUIRED: Unique identifier for the tab
8
13
  * @fires d2l-tab-content-change - Dispatched when the text attribute is changed. Triggers virtual scrolling calculations in parent d2l-tabs.
@@ -24,14 +29,11 @@ class Tab extends TabMixin(LitElement) {
24
29
  static get styles() {
25
30
  const styles = [ css`
26
31
  .d2l-tab-text-inner-content {
32
+ --d2l-focus-ring-offset: 0;
27
33
  display: flex;
28
34
  padding: 0.1rem;
29
35
  }
30
- :host(:${unsafeCSS(getFocusPseudoClass())}) .d2l-tab-text-inner-content {
31
- border-radius: 0.3rem;
32
- color: var(--d2l-color-celestine);
33
- outline: 2px solid var(--d2l-color-celestine);
34
- }
36
+ ${focusRingStyles}
35
37
  :host(:${unsafeCSS(getFocusPseudoClass())}) ::slotted(d2l-icon) {
36
38
  color: var(--d2l-color-celestine);
37
39
  }
@@ -1,10 +1,10 @@
1
1
  import '../colors/colors.js';
2
2
  import '../tooltip/tooltip.js';
3
- import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
3
+ import { css, html, LitElement, nothing } from 'lit';
4
4
  import { bodySmallStyles } from '../typography/styles.js';
5
5
  import { classMap } from 'lit/directives/class-map.js';
6
6
  import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
7
- import { getFocusPseudoClass } from '../../helpers/focus.js';
7
+ import { getFocusRingStyles } from '../../helpers/focus.js';
8
8
  import { ifDefined } from 'lit/directives/if-defined.js';
9
9
  import { SkeletonMixin } from '../skeleton/skeleton-mixin.js';
10
10
  import { SlottedIconMixin } from '../icons/slotted-icon-mixin.js';
@@ -48,6 +48,7 @@ class TooltipHelp extends SlottedIconMixin(SkeletonMixin(FocusMixin(LitElement))
48
48
  display: none;
49
49
  }
50
50
  #d2l-tooltip-help-text {
51
+ --d2l-focus-ring-offset: 0.05rem;
51
52
  align-items: baseline;
52
53
  background: none;
53
54
  border: none;
@@ -66,15 +67,7 @@ class TooltipHelp extends SlottedIconMixin(SkeletonMixin(FocusMixin(LitElement))
66
67
  align-self: center;
67
68
  }
68
69
 
69
- #d2l-tooltip-help-text:focus {
70
- outline-style: none;
71
- }
72
- #d2l-tooltip-help-text:${unsafeCSS(getFocusPseudoClass())} {
73
- border-radius: 0.05rem;
74
- outline: 2px solid var(--d2l-color-celestine);
75
- outline-offset: 0.05rem;
76
- text-underline-offset: 0.1rem;
77
- }
70
+ ${getFocusRingStyles('#d2l-tooltip-help-text', { extraStyles: css`border-radius: 0.05rem; text-underline-offset: 0.1rem;` })}
78
71
  :host([inherit-font-style]) #d2l-tooltip-help-text {
79
72
  color: inherit;
80
73
  font-size: inherit;
package/helpers/focus.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { css, unsafeCSS } from 'lit';
1
2
  import { getComposedChildren, getComposedParent, getNextAncestorSibling, getPreviousAncestorSibling, isVisible } from './dom.js';
2
3
 
3
4
  const focusableElements = {
@@ -62,6 +63,20 @@ export function getFocusableDescendants(node, options) {
62
63
  export function getFocusPseudoClass() {
63
64
  return isFocusVisibleSupported() ? 'focus-visible' : 'focus';
64
65
  }
66
+ export function getFocusRingStyles(selector, { applyOnHover = false, extraStyles = null } = {}) {
67
+ const selectorDelegate = typeof selector === 'string' ? pseudoClass => `${selector}:${pseudoClass}` : selector;
68
+ const cssSelector = unsafeCSS(`${selectorDelegate(getFocusPseudoClass())}${applyOnHover ? `, ${selectorDelegate('hover')}` : ''}`);
69
+ return css`${cssSelector} {
70
+ ${extraStyles ?? css``}
71
+ outline: 2px solid var(--d2l-focus-ring-color, var(--d2l-color-celestine));
72
+ outline-offset: var(--d2l-focus-ring-offset, 2px);
73
+ }
74
+ @media (prefers-contrast: more) {
75
+ ${cssSelector} {
76
+ outline-color: var(--d2l-focus-ring-color, Highlight);
77
+ }
78
+ }`;
79
+ }
65
80
 
66
81
  export function getLastFocusableDescendant(node, includeHidden) {
67
82
  const composedChildren = getComposedChildren(node);
@@ -1,8 +1,8 @@
1
1
  import { clearDismissible, setDismissible } from '../../helpers/dismissible.js';
2
2
  import { css, html } from 'lit';
3
3
  import { findComposedAncestor, isComposedAncestor } from '../../helpers/dom.js';
4
+ import { getFocusRingStyles, getNextFocusable } from '../../helpers/focus.js';
4
5
  import { classMap } from 'lit/directives/class-map.js';
5
- import { getNextFocusable } from '../../helpers/focus.js';
6
6
  import { ifDefined } from 'lit/directives/if-defined.js';
7
7
  import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
8
8
  import { offscreenStyles } from '../../components/offscreen/offscreen.js';
@@ -26,13 +26,10 @@ export const InteractiveMixin = superclass => class extends LocalizeCoreElement(
26
26
  }
27
27
 
28
28
  static get styles() {
29
- return [offscreenStyles, css`
30
- .interactive-focusing-toggle {
31
- border-radius: 6px;
32
- outline: 2px solid var(--d2l-color-celestine);
33
- outline-offset: 2px;
34
- }
35
- `];
29
+ return [offscreenStyles, getFocusRingStyles(
30
+ () => '.interactive-focusing-toggle',
31
+ { extraStyles: css`border-radius: 6px;` }
32
+ )];
36
33
  }
37
34
 
38
35
  constructor() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.139.0",
3
+ "version": "3.140.0",
4
4
  "description": "A collection of accessible, free, open-source web components for building Brightspace applications",
5
5
  "type": "module",
6
6
  "repository": "https://github.com/BrightspaceUI/core.git",