@brightspace-ui/core 3.137.2 → 3.137.4

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.
@@ -121,6 +121,18 @@ export const ButtonMixin = superclass => class extends FocusMixin(superclass) {
121
121
  this.removeEventListener('click', this._handleClick, true);
122
122
  }
123
123
 
124
+ firstUpdated(changedProperties) {
125
+ super.firstUpdated(changedProperties);
126
+ const button = this.shadowRoot.querySelector(this.constructor.focusElementSelector);
127
+ if (!button) return;
128
+ button.addEventListener('focus', () => {
129
+ if (this.shadowRoot.querySelector(':focus-visible')) {
130
+ /** @ignore */
131
+ this.dispatchEvent(new CustomEvent('focus-visible'));
132
+ }
133
+ });
134
+ }
135
+
124
136
  willUpdate(changedProperties) {
125
137
  super.willUpdate(changedProperties);
126
138
  if (changedProperties.has('ariaExpanded') && this.ariaExpanded !== undefined) {
@@ -5,6 +5,7 @@ import '../dropdown/dropdown-menu.js';
5
5
  import '../icons/icon.js';
6
6
  import '../menu/menu.js';
7
7
  import { css, html, LitElement } from 'lit';
8
+ import { classMap } from 'lit/directives/class-map.js';
8
9
  import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
9
10
  import { ifDefined } from 'lit/directives/if-defined.js';
10
11
  import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
@@ -46,7 +47,8 @@ class ButtonSplit extends FocusMixin(PropertyRequiredMixin(LocalizeCoreElement(L
46
47
  * ACCESSIBILITY: REQUIRED: Accessible text for the main action button
47
48
  * @type {string}
48
49
  */
49
- text: { type: String, reflect: true, required: true }
50
+ text: { type: String, reflect: true, required: true },
51
+ _focusVisibleElem: { state: true }
50
52
  };
51
53
  }
52
54
 
@@ -60,7 +62,7 @@ class ButtonSplit extends FocusMixin(PropertyRequiredMixin(LocalizeCoreElement(L
60
62
  }
61
63
  .container {
62
64
  display: flex;
63
- gap: 6px;
65
+ gap: 2px;
64
66
  }
65
67
  .main-action {
66
68
  --d2l-button-start-end-radius: 0;
@@ -78,6 +80,14 @@ class ButtonSplit extends FocusMixin(PropertyRequiredMixin(LocalizeCoreElement(L
78
80
  ::slotted(:not(d2l-button-split-item)) {
79
81
  display: none;
80
82
  }
83
+ .main-action-focus-visible .d2l-dropdown-opener {
84
+ --d2l-button-padding-inline-start: calc(0.6rem - 4px);
85
+ margin-inline-start: 4px;
86
+ }
87
+ .menu-opener-focus-visible .main-action {
88
+ --d2l-button-padding-inline-end: calc(1.5rem - 4px);
89
+ margin-inline-end: 4px;
90
+ }
81
91
  `;
82
92
  }
83
93
 
@@ -85,6 +95,7 @@ class ButtonSplit extends FocusMixin(PropertyRequiredMixin(LocalizeCoreElement(L
85
95
  super();
86
96
  this.disabled = false;
87
97
  this.primary = false;
98
+ this._focusVisibleElem = null;
88
99
  }
89
100
 
90
101
  static get focusElementSelector() {
@@ -92,22 +103,32 @@ class ButtonSplit extends FocusMixin(PropertyRequiredMixin(LocalizeCoreElement(L
92
103
  }
93
104
 
94
105
  render() {
106
+ const classes = {
107
+ 'container': true,
108
+ 'main-action-focus-visible': (this._focusVisibleElem === 'main-action'),
109
+ 'menu-opener-focus-visible': (this._focusVisibleElem === 'menu-opener'),
110
+ };
111
+
95
112
  return html`
96
- <div class="container" @click="${this.#suppressClick}">
113
+ <div class="${classMap(classes)}" @click="${this.#suppressClick}">
97
114
  <d2l-button
115
+ @blur="${this.#handleMainActionBlur}"
98
116
  class="main-action"
99
117
  @click="${this.#handleMainActionClick}"
100
118
  description="${ifDefined(this.description)}"
101
119
  ?disabled="${this.disabled}"
102
120
  disabled-tooltip="${ifDefined(this.disabledTooltip)}"
121
+ @focus-visible="${this.#handleMainActionFocusVisible}"
103
122
  ?primary="${this.primary}">
104
123
  ${this.text}
105
124
  </d2l-button>
106
125
  <d2l-dropdown>
107
126
  <d2l-button
108
127
  aria-label="${this.localize('components.button-split.otherOptions')}"
128
+ @blur="${this.#handleMenuOpenerBlur}"
109
129
  class="d2l-dropdown-opener"
110
130
  ?disabled="${this.disabled}"
131
+ @focus-visible="${this.#handleMenuOpenerFocusVisible}"
111
132
  ?primary="${this.primary}">
112
133
  <d2l-icon icon="tier1:chevron-down"></d2l-icon>
113
134
  </d2l-button>
@@ -126,14 +147,30 @@ class ButtonSplit extends FocusMixin(PropertyRequiredMixin(LocalizeCoreElement(L
126
147
  this.dispatchEvent(new CustomEvent('click', { detail: { key } }));
127
148
  }
128
149
 
150
+ #handleMainActionBlur() {
151
+ this._focusVisibleElem = null;
152
+ }
153
+
129
154
  #handleMainActionClick() {
130
155
  this.#dispatchClick(this.key);
131
156
  }
132
157
 
158
+ #handleMainActionFocusVisible() {
159
+ this._focusVisibleElem = 'main-action';
160
+ }
161
+
133
162
  #handleMenuItemSelect(e) {
134
163
  this.#dispatchClick(e.target.key);
135
164
  }
136
165
 
166
+ #handleMenuOpenerBlur() {
167
+ this._focusVisibleElem = null;
168
+ }
169
+
170
+ #handleMenuOpenerFocusVisible() {
171
+ this._focusVisibleElem = 'menu-opener';
172
+ }
173
+
137
174
  #suppressClick(e) {
138
175
  e.stopPropagation();
139
176
  }
@@ -1,11 +1,9 @@
1
1
  import '../colors/colors.js';
2
2
  import { css, html, LitElement, nothing } from 'lit';
3
3
  import { classMap } from 'lit/directives/class-map.js';
4
- import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
5
4
  import { ifDefined } from 'lit/directives/if-defined.js';
6
5
  import { offscreenStyles } from '../offscreen/offscreen.js';
7
6
  import ResizeObserver from 'resize-observer-polyfill/dist/ResizeObserver.es.js';
8
- import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
9
7
  import { styleMap } from 'lit/directives/style-map.js';
10
8
 
11
9
  /**
@@ -16,7 +14,7 @@ import { styleMap } from 'lit/directives/style-map.js';
16
14
  * @slot footer - Slot for footer content, such secondary actions
17
15
  * @slot header - Slot for header content, such as course image (no actionable elements)
18
16
  */
19
- class Card extends FocusMixin(RtlMixin(LitElement)) {
17
+ class Card extends LitElement {
20
18
 
21
19
  static get properties() {
22
20
  return {
@@ -142,22 +140,14 @@ class Card extends FocusMixin(RtlMixin(LitElement)) {
142
140
  padding-bottom: 1.2rem;
143
141
  }
144
142
  .d2l-card-actions {
143
+ inset-inline-end: 0.6rem;
145
144
  position: absolute;
146
- right: 0.6rem;
147
145
  top: 0.6rem;
148
146
  /* this must be higher than footer z-index so dropdowns will be on top */
149
147
  z-index: 3;
150
148
  }
151
- :host([dir="rtl"]) .d2l-card-actions {
152
- left: 0.6rem;
153
- right: auto;
154
- }
155
149
  .d2l-card-actions ::slotted(*) {
156
- margin-left: 0.3rem;
157
- }
158
- :host([dir="rtl"]) .d2l-card-actions ::slotted(*) {
159
- margin-left: 0;
160
- margin-right: 0.3rem;
150
+ margin-inline-start: 0.3rem;
161
151
  }
162
152
  .d2l-card-badge {
163
153
  line-height: 0;
@@ -237,6 +227,7 @@ class Card extends FocusMixin(RtlMixin(LitElement)) {
237
227
  this.subtle = false;
238
228
  this._active = false;
239
229
  this._dropdownActionOpen = false;
230
+ this._focusOnFirstRender = false;
240
231
  this._footerHidden = true;
241
232
  this._hover = false;
242
233
  this._tooltipShowing = false;
@@ -244,16 +235,17 @@ class Card extends FocusMixin(RtlMixin(LitElement)) {
244
235
  this._onFooterResize = this._onFooterResize.bind(this);
245
236
  }
246
237
 
247
- static get focusElementSelector() {
248
- return 'a';
249
- }
250
-
251
238
  firstUpdated(changedProperties) {
252
239
  super.firstUpdated(changedProperties);
253
240
  const badgeObserver = new ResizeObserver(this._onBadgeResize);
254
241
  badgeObserver.observe(this.shadowRoot.querySelector('.d2l-card-badge'));
255
242
  const footerObserver = new ResizeObserver(this._onFooterResize);
256
243
  footerObserver.observe(this.shadowRoot.querySelector('.d2l-card-footer'));
244
+
245
+ if (this._focusOnFirstRender) {
246
+ this._focusOnFirstRender = false;
247
+ this.focus();
248
+ }
257
249
  }
258
250
 
259
251
  render() {
@@ -308,6 +300,17 @@ class Card extends FocusMixin(RtlMixin(LitElement)) {
308
300
  `;
309
301
  }
310
302
 
303
+ focus() {
304
+ if (!this.hasUpdated) {
305
+ this._focusOnFirstRender = true;
306
+ return;
307
+ }
308
+
309
+ const elem = this.shadowRoot.querySelector('a[href]');
310
+ if (elem) elem.focus();
311
+ else super.focus();
312
+ }
313
+
311
314
  _onBadgeResize(entries) {
312
315
  if (!entries || entries.length === 0) return;
313
316
  const entry = entries[0];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.137.2",
3
+ "version": "3.137.4",
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",