@brightspace-ui/core 2.14.8 → 2.15.1

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.
@@ -14,7 +14,8 @@ import { tryGetIfrauBackdropService } from '../../helpers/ifrauBackdropService.j
14
14
  window.D2L = window.D2L || {};
15
15
  window.D2L.DialogMixin = window.D2L.DialogMixin || {};
16
16
 
17
- window.D2L.DialogMixin.hasNative = (window.HTMLDialogElement !== undefined);
17
+ window.D2L.DialogMixin.hasNative = (window.HTMLDialogElement !== undefined)
18
+ && (navigator.vendor && navigator.vendor.toLowerCase().indexOf('apple') === -1);
18
19
  if (window.D2L.DialogMixin.preferNative === undefined) {
19
20
  window.D2L.DialogMixin.preferNative = true;
20
21
  }
@@ -174,6 +174,18 @@
174
174
  </mfrac>
175
175
  </mrow>
176
176
  <mtext>.</mtext>
177
+ <mspace linebreak="newline"></mspace>
178
+ <msup>
179
+ <mi>e</mi>
180
+ <mrow>
181
+ <mi>i</mi>
182
+ <mi>π<!-- π --></mi>
183
+ </mrow>
184
+ </msup>
185
+ <mo>+</mo>
186
+ <mn>1</mn>
187
+ <mo>=</mo>
188
+ <mn>0</mn>
177
189
  </math>
178
190
  <math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
179
191
  <msup>
@@ -363,6 +363,7 @@ The `d2l-list-item` provides the appropriate `listitem` semantics for children w
363
363
  | `key` | String | Value to identify item if selectable or draggable |
364
364
  | `label` | String | Explicitly defined label for the element |
365
365
  | `labelled-by` | String | The id of element that provides the label for this element |
366
+ | `no-primary-action` | Boolean | Whether to disable rendering the entire item as the primary action. Required if slotted content is interactive. |
366
367
  | `padding-type` | String | List item whitespace (`normal` (default), `none`)|
367
368
  | `selectable` | Boolean | Indicates an input should be rendered for selecting the item |
368
369
  | `selected` | Boolean | Whether the item is selected |
@@ -20,12 +20,17 @@
20
20
  import '../list-item-content.js';
21
21
  import '../list-item.js';
22
22
  import '../list.js';
23
+ import '../../tag-list/tag-list.js';
24
+ import '../../tag-list/tag-list-item.js';
23
25
  </script>
24
26
  <style>
25
27
  img {
26
28
  height: 500px;
27
29
  object-fit: cover;
28
30
  }
31
+ d2l-tag-list {
32
+ margin-top: 0.3rem;
33
+ }
29
34
  </style>
30
35
  </head>
31
36
  <body unresolved>
@@ -237,6 +242,89 @@
237
242
  </template>
238
243
  </d2l-demo-snippet>
239
244
 
245
+ <h2>List with Interactive Content</h2>
246
+
247
+ <d2l-demo-snippet>
248
+ <template>
249
+ <d2l-list grid>
250
+ <d2l-list-item no-primary-action selectable key="1" label="Introductory Earth Sciences">
251
+ <img slot="illustration" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg"></img>
252
+ <div>
253
+ <d2l-list-item-content>
254
+ <div>Introductory Earth Sciences</div>
255
+ </d2l-list-item-content>
256
+ <d2l-tag-list description="Tags for this course">
257
+ <d2l-tag-list-item text="Science"></d2l-tag-list-item>
258
+ <d2l-tag-list-item text="Environment"></d2l-tag-list-item>
259
+ <d2l-tag-list-item text="Earth"></d2l-tag-list-item>
260
+ </d2l-tag-list>
261
+ </div>
262
+ <div slot="actions">
263
+ <d2l-button-icon id="tooltip-btn-1" text="My Button" icon="tier1:preview"></d2l-button-icon>
264
+ <d2l-tooltip for="tooltip-btn-1">Preview</d2l-tooltip>
265
+ <d2l-dropdown-more text="Open!">
266
+ <d2l-dropdown-menu>
267
+ <d2l-menu label="Astronomy">
268
+ <d2l-menu-item text="Introduction"></d2l-menu-item>
269
+ <d2l-menu-item text="Searching for the Heavens "></d2l-menu-item>
270
+ </d2l-menu>
271
+ </d2l-dropdown-menu>
272
+ </d2l-dropdown-more>
273
+ </div>
274
+ </d2l-list-item>
275
+ <d2l-list-item no-primary-action selectable key="2" selected label="Engineering Materials for Energy Systems">
276
+ <img slot="illustration" src="https://s.brightspace.com/course-images/images/e5fd575a-bc14-4a80-89e1-46f349a76178/tile-high-density-max-size.jpg"></img>
277
+ <div>
278
+ <d2l-list-item-content>
279
+ <div>Engineering Materials for Energy Systems</div>
280
+ </d2l-list-item-content>
281
+ <d2l-tag-list description="Tags for this course">
282
+ <d2l-tag-list-item text="Engineering"></d2l-tag-list-item>
283
+ <d2l-tag-list-item text="Energy Systems"></d2l-tag-list-item>
284
+ </d2l-tag-list>
285
+ </div>
286
+ <div slot="actions">
287
+ <d2l-button-icon id="tooltip-btn-1" text="My Button" icon="tier1:preview"></d2l-button-icon>
288
+ <d2l-tooltip for="tooltip-btn-1">Preview</d2l-tooltip>
289
+ <d2l-dropdown-more text="Open!">
290
+ <d2l-dropdown-menu>
291
+ <d2l-menu label="Astronomy">
292
+ <d2l-menu-item text="Introduction"></d2l-menu-item>
293
+ <d2l-menu-item text="Searching for the Heavens "></d2l-menu-item>
294
+ </d2l-menu>
295
+ </d2l-dropdown-menu>
296
+ </d2l-dropdown-more>
297
+ </div>
298
+ </d2l-list-item>
299
+ <d2l-list-item no-primary-action selectable key="3" label="Geomorphology and GIS">
300
+ <img slot="illustration" src="https://s.brightspace.com/course-images/images/63b162ab-b582-4bf9-8c1d-1dad04714121/tile-high-density-max-size.jpg"></img>
301
+ <div>
302
+ <d2l-list-item-content>
303
+ <div>Geomorphology and GIS</div>
304
+ </d2l-list-item-content>
305
+ <d2l-tag-list description="Tags for this course">
306
+ <d2l-tag-list-item text="Geology"></d2l-tag-list-item>
307
+ <d2l-tag-list-item text="GIS"></d2l-tag-list-item>
308
+ <d2l-tag-list-item text="Earth Sciences"></d2l-tag-list-item>
309
+ </d2l-tag-list>
310
+ </div>
311
+ <div slot="actions">
312
+ <d2l-button-icon id="tooltip-btn-1" text="My Button" icon="tier1:preview"></d2l-button-icon>
313
+ <d2l-tooltip for="tooltip-btn-1">Preview</d2l-tooltip>
314
+ <d2l-dropdown-more text="Open!">
315
+ <d2l-dropdown-menu>
316
+ <d2l-menu label="Astronomy">
317
+ <d2l-menu-item text="Introduction"></d2l-menu-item>
318
+ <d2l-menu-item text="Searching for the Heavens "></d2l-menu-item>
319
+ </d2l-menu>
320
+ </d2l-dropdown-menu>
321
+ </d2l-dropdown-more>
322
+ </div>
323
+ </d2l-list-item>
324
+ </d2l-list>
325
+ </template>
326
+ </d2l-demo-snippet>
327
+
240
328
  </d2l-demo-page>
241
329
 
242
330
  </body>
@@ -1,10 +1,7 @@
1
1
  import { css, html, LitElement } from 'lit';
2
2
  import { findComposedAncestor, getNextAncestorSibling, getPreviousAncestorSibling, isComposedAncestor } from '../../helpers/dom.js';
3
- import {
4
- getComposedActiveElement,
5
- getFirstFocusableDescendant,
6
- getLastFocusableDescendant,
7
- isFocusable } from '../../helpers/focus.js';
3
+ import { getComposedActiveElement, getFirstFocusableDescendant, getLastFocusableDescendant, isFocusable } from '../../helpers/focus.js';
4
+ import { isInteractiveDescendant } from '../../mixins/interactive-mixin.js';
8
5
  import { RtlMixin } from '../../mixins/rtl-mixin.js';
9
6
 
10
7
  const keyCodes = {
@@ -42,6 +39,11 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
42
39
  * @type {'content'|'control'}
43
40
  */
44
41
  alignNested: { type: String, reflect: true, attribute: 'align-nested' },
42
+ /**
43
+ * Whether to constrain actions so they do not fill the item. Required if slotted content is interactive.
44
+ * @type {boolean}
45
+ */
46
+ noPrimaryAction: { type: Boolean, attribute: 'no-primary-action', reflect: true },
45
47
  /**
46
48
  * @ignore
47
49
  */
@@ -127,16 +129,25 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
127
129
  grid-column: start / end;
128
130
  z-index: 1;
129
131
  }
132
+ :host([no-primary-action]) ::slotted([slot="outside-control-action"]) {
133
+ grid-column: start / outside-control-end;
134
+ }
130
135
  ::slotted([slot="control-action"]) {
131
136
  grid-column: control-start / end;
132
137
  height: 100%;
133
138
  width: 100%;
134
139
  z-index: 2;
135
140
  }
141
+ :host([no-primary-action]) ::slotted([slot="control-action"]) {
142
+ grid-column: control-start / control-end;
143
+ }
136
144
  ::slotted([slot="content-action"]) {
137
145
  grid-column: content-start / end;
138
146
  z-index: 3;
139
147
  }
148
+ :host([no-primary-action]) ::slotted([slot="content-action"]) {
149
+ display: none;
150
+ }
140
151
 
141
152
  ::slotted([slot="outside-control-container"]) {
142
153
  grid-column: start / end;
@@ -152,6 +163,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
152
163
  constructor() {
153
164
  super();
154
165
  this.alignNested = 'content';
166
+ this.noPrimaryAction = false;
155
167
  this._preventFocus = {
156
168
  handleEvent(event) {
157
169
  // target content slot only for now - can add others later
@@ -186,7 +198,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
186
198
  <slot name="control-action" class="d2l-cell" data-cell-num="3"></slot>
187
199
  <slot name="control" class="d2l-cell" data-cell-num="4"></slot>
188
200
  <slot name="actions" class="d2l-cell" data-cell-num="6"></slot>
189
- <slot name="content" @focus="${this._preventFocus}"></slot>
201
+ <slot name="content" class="d2l-cell" data-cell-num="7" @focus="${!this.noPrimaryAction ? this._preventFocus : null}"></slot>
190
202
  <slot name="nested"></slot>
191
203
  `;
192
204
  }
@@ -276,14 +288,18 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
276
288
  }
277
289
 
278
290
  _focusNextWithinCell(node, num = 1) {
291
+
279
292
  if (!node || (node.assignedSlot && node.assignedSlot === this._getThisCell())) return null;
280
293
  let focusable = null;
281
294
  let siblingNum = 1;
282
295
  while (!focusable || siblingNum < num) {
283
296
  node = this._getNextSiblingInCell(node);
297
+
284
298
  if (!node) break;
285
299
  ++siblingNum;
300
+
286
301
  focusable = isFocusable(node, true) ? node : getFirstFocusableDescendant(node);
302
+ if (isInteractiveDescendant(focusable)) focusable = null;
287
303
  }
288
304
 
289
305
  if (focusable) focusable.focus();
@@ -57,6 +57,11 @@ export const ListItemMixin = superclass => class extends LocalizeCoreElement(Lis
57
57
  * @type {boolean}
58
58
  */
59
59
  dragTargetHandleOnly: { type: Boolean, attribute: 'drag-target-handle-only' },
60
+ /**
61
+ * Whether to disable rendering the entire item as the primary action. Required if slotted content is interactive.
62
+ * @type {boolean}
63
+ */
64
+ noPrimaryAction: { type: Boolean, attribute: 'no-primary-action' },
60
65
  /**
61
66
  * How much padding to render list items with
62
67
  * @type {'normal'|'none'}
@@ -106,6 +111,7 @@ export const ListItemMixin = superclass => class extends LocalizeCoreElement(Lis
106
111
 
107
112
  [slot="control-container"] {
108
113
  position: relative;
114
+ z-index: -1; /* must allow for interactive content to be accessible with mouse */
109
115
  }
110
116
  :host(:first-of-type) [slot="control-container"]::before,
111
117
  [slot="control-container"]::after {
@@ -343,6 +349,7 @@ export const ListItemMixin = superclass => class extends LocalizeCoreElement(Lis
343
349
  constructor() {
344
350
  super();
345
351
  this.breakpoints = defaultBreakpoints;
352
+ this.noPrimaryAction = false;
346
353
  this.paddingType = 'normal';
347
354
  this._breakpoint = 0;
348
355
  this._contentId = getUniqueId();
@@ -531,7 +538,7 @@ export const ListItemMixin = superclass => class extends LocalizeCoreElement(Lis
531
538
  'd2l-dragging-over': this._draggingOver
532
539
  };
533
540
 
534
- const primaryAction = this._renderPrimaryAction ? this._renderPrimaryAction(this._contentId) : null;
541
+ const primaryAction = ((!this.noPrimaryAction && this._renderPrimaryAction) ? this._renderPrimaryAction(this._contentId) : null);
535
542
  const tooltipForId = (primaryAction ? this._primaryActionId : (this.selectable ? this._checkboxId : null));
536
543
 
537
544
  const innerView = html`
@@ -543,7 +550,8 @@ export const ListItemMixin = superclass => class extends LocalizeCoreElement(Lis
543
550
  class="${classMap(classes)}"
544
551
  data-breakpoint="${this._breakpoint}"
545
552
  data-separators="${ifDefined(this._separators)}"
546
- ?grid-active="${this.role === 'rowgroup'}">
553
+ ?grid-active="${this.role === 'rowgroup'}"
554
+ ?no-primary-action="${this.noPrimaryAction}">
547
555
  <div slot="outside-control-container"></div>
548
556
  ${this._renderDropTarget()}
549
557
  ${this._renderDragHandle(this._renderOutsideControl)}
@@ -6519,6 +6519,12 @@
6519
6519
  "type": "array",
6520
6520
  "default": "[842,636,580,0]"
6521
6521
  },
6522
+ {
6523
+ "name": "no-primary-action",
6524
+ "description": "Whether to disable rendering the entire item as the primary action. Required if slotted content is interactive.",
6525
+ "type": "boolean",
6526
+ "default": "false"
6527
+ },
6522
6528
  {
6523
6529
  "name": "padding-type",
6524
6530
  "description": "How much padding to render list items with",
@@ -6601,6 +6607,13 @@
6601
6607
  "type": "array",
6602
6608
  "default": "[842,636,580,0]"
6603
6609
  },
6610
+ {
6611
+ "name": "noPrimaryAction",
6612
+ "attribute": "no-primary-action",
6613
+ "description": "Whether to disable rendering the entire item as the primary action. Required if slotted content is interactive.",
6614
+ "type": "boolean",
6615
+ "default": "false"
6616
+ },
6604
6617
  {
6605
6618
  "name": "paddingType",
6606
6619
  "attribute": "padding-type",
@@ -6770,6 +6783,12 @@
6770
6783
  "type": "array",
6771
6784
  "default": "[842,636,580,0]"
6772
6785
  },
6786
+ {
6787
+ "name": "no-primary-action",
6788
+ "description": "Whether to disable rendering the entire item as the primary action. Required if slotted content is interactive.",
6789
+ "type": "boolean",
6790
+ "default": "false"
6791
+ },
6773
6792
  {
6774
6793
  "name": "padding-type",
6775
6794
  "description": "How much padding to render list items with",
@@ -6852,6 +6871,13 @@
6852
6871
  "type": "array",
6853
6872
  "default": "[842,636,580,0]"
6854
6873
  },
6874
+ {
6875
+ "name": "noPrimaryAction",
6876
+ "attribute": "no-primary-action",
6877
+ "description": "Whether to disable rendering the entire item as the primary action. Required if slotted content is interactive.",
6878
+ "type": "boolean",
6879
+ "default": "false"
6880
+ },
6855
6881
  {
6856
6882
  "name": "paddingType",
6857
6883
  "attribute": "padding-type",
@@ -7082,6 +7108,12 @@
7082
7108
  "description": "How to align content in the nested slot",
7083
7109
  "type": "'content'|'control'",
7084
7110
  "default": "\"content\""
7111
+ },
7112
+ {
7113
+ "name": "no-primary-action",
7114
+ "description": "Whether to constrain actions so they do not fill the item. Required if slotted content is interactive.",
7115
+ "type": "boolean",
7116
+ "default": "false"
7085
7117
  }
7086
7118
  ],
7087
7119
  "properties": [
@@ -7097,6 +7129,13 @@
7097
7129
  "description": "How to align content in the nested slot",
7098
7130
  "type": "'content'|'control'",
7099
7131
  "default": "\"content\""
7132
+ },
7133
+ {
7134
+ "name": "noPrimaryAction",
7135
+ "attribute": "no-primary-action",
7136
+ "description": "Whether to constrain actions so they do not fill the item. Required if slotted content is interactive.",
7137
+ "type": "boolean",
7138
+ "default": "false"
7100
7139
  }
7101
7140
  ],
7102
7141
  "slots": [
@@ -7164,6 +7203,12 @@
7164
7203
  "type": "array",
7165
7204
  "default": "[842,636,580,0]"
7166
7205
  },
7206
+ {
7207
+ "name": "no-primary-action",
7208
+ "description": "Whether to disable rendering the entire item as the primary action. Required if slotted content is interactive.",
7209
+ "type": "boolean",
7210
+ "default": "false"
7211
+ },
7167
7212
  {
7168
7213
  "name": "padding-type",
7169
7214
  "description": "How much padding to render list items with",
@@ -7258,6 +7303,13 @@
7258
7303
  "type": "array",
7259
7304
  "default": "[842,636,580,0]"
7260
7305
  },
7306
+ {
7307
+ "name": "noPrimaryAction",
7308
+ "attribute": "no-primary-action",
7309
+ "description": "Whether to disable rendering the entire item as the primary action. Required if slotted content is interactive.",
7310
+ "type": "boolean",
7311
+ "default": "false"
7312
+ },
7261
7313
  {
7262
7314
  "name": "paddingType",
7263
7315
  "attribute": "padding-type",
@@ -64,14 +64,21 @@ export class HtmlBlockMathRenderer {
64
64
  return elem;
65
65
  }
66
66
 
67
+ // MathJax 3 does not support newlines, but it does persist styles, so add custom styles to mimic a linebreak
68
+ // This work-around should be removed when linebreaks are natively supported.
69
+ // MathJax issue: https://github.com/mathjax/MathJax/issues/2312
70
+ // A duplicate that explains our exact issue: https://github.com/mathjax/MathJax/issues/2495
71
+ const inner = elem.innerHTML.replaceAll('<mspace linebreak="newline">', '<mspace linebreak="newline" style="display: block; height: 0.5rem;">');
72
+
67
73
  const temp = document.createElement('div');
68
74
  temp.style.display = 'none';
69
75
  temp.attachShadow({ mode: 'open' });
70
- temp.shadowRoot.innerHTML = `<div><mjx-doc><mjx-head></mjx-head><mjx-body>${elem.innerHTML}</mjx-body></mjx-doc></div>`;
76
+ temp.shadowRoot.innerHTML = `<div><mjx-doc><mjx-head></mjx-head><mjx-body>${inner}</mjx-body></mjx-doc></div>`;
71
77
 
72
78
  elem.appendChild(temp);
73
79
  await window.MathJax.startup.promise;
74
80
  window.MathJax.typesetShadow(temp.shadowRoot);
81
+
75
82
  return temp.shadowRoot.firstChild;
76
83
  }
77
84
 
@@ -96,6 +96,7 @@ export const ArrowKeysMixin = superclass => class extends superclass {
96
96
  } else {
97
97
  return;
98
98
  }
99
+ e.stopPropagation();
99
100
  e.preventDefault();
100
101
  }
101
102
 
@@ -11,6 +11,13 @@ const keyCodes = {
11
11
  ESCAPE: 27
12
12
  };
13
13
 
14
+ export function isInteractiveDescendant(node) {
15
+ if (!node) return false;
16
+ return !!findComposedAncestor(node, node => {
17
+ return node.classList && node.classList.contains('interactive-trap');
18
+ });
19
+ }
20
+
14
21
  export const InteractiveMixin = superclass => class extends LocalizeCoreElement(superclass) {
15
22
 
16
23
  static get properties() {
@@ -70,17 +77,19 @@ export const InteractiveMixin = superclass => class extends LocalizeCoreElement(
70
77
 
71
78
  return html`
72
79
  <div class="${classMap(classes)}" @keydown="${this._handleInteractiveKeyDown}">
73
- <button
74
- class="interactive-toggle d2l-offscreen"
75
- @blur="${this._handleInteractiveToggleBlur}"
76
- @click="${this._handleInteractiveToggleClick}"
77
- @focus="${this._handleInteractiveToggleFocus}"
78
- tabindex="${ifDefined(this._hasInteractiveAncestor && !this._interactive ? '0' : '-1')}">
79
- ${`${label}, ${this.localize('components.interactive.instructions')}`}
80
- </button>
80
+ <button
81
+ class="interactive-toggle d2l-offscreen"
82
+ @blur="${this._handleInteractiveToggleBlur}"
83
+ @click="${this._handleInteractiveToggleClick}"
84
+ @focus="${this._handleInteractiveToggleFocus}"
85
+ tabindex="${ifDefined(this._hasInteractiveAncestor && !this._interactive ? '0' : '-1')}">
86
+ ${`${label}, ${this.localize('components.interactive.instructions')}`}
87
+ </button>
88
+ <div class="interactive-trap">
81
89
  <span class="interactive-trap-start" @focus="${this._handleInteractiveTrapStartFocus}" tabindex="${ifDefined(this._hasInteractiveAncestor ? '0' : undefined)}"></span>
82
90
  <div class="interactive-container-content" @focusin="${this._handleInteractiveContentFocusIn}" @focusout="${this._handleInteractiveContentFocusOut}">${inner}</div>
83
91
  <span class="interactive-trap-end" @focus="${this._handleInteractiveTrapEndFocus}" tabindex="${ifDefined(this._hasInteractiveAncestor ? '0' : undefined)}"></span>
92
+ </div>
84
93
  </div>
85
94
  `;
86
95
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "2.14.8",
3
+ "version": "2.15.1",
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",