@brightspace-ui/core 1.213.1 → 1.216.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 (76) hide show
  1. package/components/button/button-mixin.js +1 -1
  2. package/components/calendar/calendar.js +5 -5
  3. package/components/card/card-footer-link.js +2 -2
  4. package/components/card/card.js +1 -1
  5. package/components/demo/code-view.js +2 -2
  6. package/components/demo/demo-snippet.js +5 -2
  7. package/components/dialog/dialog-confirm.js +1 -0
  8. package/components/dialog/dialog-mixin.js +7 -2
  9. package/components/dropdown/dropdown-button-subtle.js +1 -1
  10. package/components/dropdown/dropdown-button.js +1 -1
  11. package/components/dropdown/dropdown-content-mixin.js +6 -6
  12. package/components/dropdown/dropdown-context-menu.js +1 -1
  13. package/components/dropdown/dropdown-menu.js +1 -0
  14. package/components/dropdown/dropdown-more.js +1 -1
  15. package/components/dropdown/dropdown-opener-mixin.js +1 -0
  16. package/components/dropdown/dropdown-tabs.js +1 -0
  17. package/components/dropdown/dropdown.js +1 -0
  18. package/components/expand-collapse/expand-collapse-content.js +4 -4
  19. package/components/filter/filter.js +5 -4
  20. package/components/focus-trap/focus-trap.js +6 -5
  21. package/components/form/demo/form-demo.js +1 -1
  22. package/components/form/demo/form-dialog-demo.js +4 -4
  23. package/components/form/demo/form-native-demo.js +1 -1
  24. package/components/form/form-element-mixin.js +12 -3
  25. package/components/form/form-errory-summary.js +2 -2
  26. package/components/form/form-native.js +1 -1
  27. package/components/form/form.js +1 -1
  28. package/components/hierarchical-view/hierarchical-view-mixin.js +7 -6
  29. package/components/html-block/demo/html-block.html +31 -0
  30. package/components/html-block/html-block.js +18 -7
  31. package/components/inputs/demo/input-radio-solo-test.js +1 -1
  32. package/components/inputs/demo/input-radio-spacer-test.js +1 -1
  33. package/components/inputs/demo/input-select-test.js +1 -1
  34. package/components/inputs/input-checkbox.js +1 -1
  35. package/components/inputs/input-date-range.js +4 -3
  36. package/components/inputs/input-date-time-range-to.js +1 -1
  37. package/components/inputs/input-date-time-range.js +4 -3
  38. package/components/inputs/input-date-time.js +6 -5
  39. package/components/inputs/input-date.js +3 -0
  40. package/components/inputs/input-number.js +2 -1
  41. package/components/inputs/input-percent.js +2 -1
  42. package/components/inputs/input-search.js +3 -3
  43. package/components/inputs/input-text.js +8 -8
  44. package/components/inputs/input-textarea.js +5 -5
  45. package/components/inputs/input-time-range.js +4 -4
  46. package/components/inputs/input-time.js +1 -1
  47. package/components/link/link.js +1 -1
  48. package/components/list/README.md +91 -59
  49. package/components/list/demo/list-drag-and-drop.js +25 -16
  50. package/components/list/list-header.js +1 -0
  51. package/components/list/list-item-button.js +1 -0
  52. package/components/list/list-item-checkbox-mixin.js +4 -2
  53. package/components/list/list-item-drag-drop-mixin.js +12 -6
  54. package/components/list/list-item-generic-layout.js +5 -4
  55. package/components/list/list-item-mixin.js +1 -0
  56. package/components/list/list-item.js +1 -0
  57. package/components/list/list.js +9 -4
  58. package/components/menu/demo/custom-view.js +1 -1
  59. package/components/menu/menu-item-link.js +1 -1
  60. package/components/menu/menu-item-mixin.js +1 -1
  61. package/components/menu/menu.js +2 -2
  62. package/components/overflow-group/overflow-group.js +1 -1
  63. package/components/scroll-wrapper/demo/scroll-wrapper-test.js +1 -1
  64. package/components/selection/selection-action.js +1 -1
  65. package/components/selection/selection-input.js +1 -1
  66. package/components/selection/selection-select-all.js +1 -1
  67. package/components/switch/switch-mixin.js +1 -1
  68. package/components/table/table-col-sort-button.js +1 -1
  69. package/components/tabs/tabs.js +20 -15
  70. package/components/tooltip/tooltip.js +1 -1
  71. package/custom-elements.json +97 -69
  72. package/directives/animate/animate.js +35 -18
  73. package/helpers/demo/announce-test.js +1 -0
  74. package/mixins/arrow-keys-mixin.js +3 -1
  75. package/package.json +1 -1
  76. package/templates/primary-secondary/primary-secondary.js +2 -1
@@ -108,7 +108,7 @@ export const ButtonMixin = superclass => class extends FocusVisiblePolyfillMixin
108
108
  }
109
109
 
110
110
  focus() {
111
- const button = this.shadowRoot.querySelector('button');
111
+ const button = this.shadowRoot && this.shadowRoot.querySelector('button');
112
112
  if (button) button.focus();
113
113
  }
114
114
 
@@ -557,7 +557,7 @@ class Calendar extends LocalizeCoreElement(RtlMixin(LitElement)) {
557
557
  await this.updateComplete;
558
558
  this._focusDateAddFocus();
559
559
  } else {
560
- const button = this.shadowRoot.querySelector('d2l-button-icon');
560
+ const button = this.shadowRoot && this.shadowRoot.querySelector('d2l-button-icon');
561
561
  if (button) button.focus();
562
562
  }
563
563
  }
@@ -582,7 +582,7 @@ class Calendar extends LocalizeCoreElement(RtlMixin(LitElement)) {
582
582
 
583
583
  async _getDateElement(date) {
584
584
  await this.updateComplete;
585
- return this.shadowRoot.querySelector(`td[data-date="${date.getDate()}"][data-month="${date.getMonth()}"][data-year="${date.getFullYear()}"]`);
585
+ return this.shadowRoot && this.shadowRoot.querySelector(`td[data-date="${date.getDate()}"][data-month="${date.getMonth()}"][data-year="${date.getFullYear()}"]`);
586
586
  }
587
587
 
588
588
  _getInitialFocusDate() {
@@ -715,7 +715,7 @@ class Calendar extends LocalizeCoreElement(RtlMixin(LitElement)) {
715
715
  if (!canUpdateFocusDate) this._focusDate = undefined;
716
716
  if (this._focusDate) this._focusDateAddFocus();
717
717
  else {
718
- const buttons = this.shadowRoot.querySelectorAll('d2l-button-icon');
718
+ const buttons = this.shadowRoot && this.shadowRoot.querySelectorAll('d2l-button-icon');
719
719
  if (buttons && buttons.length > 0) buttons[0].focus();
720
720
  }
721
721
  preventDefault = true;
@@ -742,7 +742,7 @@ class Calendar extends LocalizeCoreElement(RtlMixin(LitElement)) {
742
742
  if (!canUpdateFocusDate) this._focusDate = undefined;
743
743
  if (this._focusDate) this._focusDateAddFocus();
744
744
  else {
745
- const buttons = this.shadowRoot.querySelectorAll('d2l-button-icon');
745
+ const buttons = this.shadowRoot && this.shadowRoot.querySelectorAll('d2l-button-icon');
746
746
  if (buttons && buttons.length > 1) buttons[1].focus();
747
747
  }
748
748
  preventDefault = true;
@@ -832,7 +832,7 @@ class Calendar extends LocalizeCoreElement(RtlMixin(LitElement)) {
832
832
  }
833
833
 
834
834
  await this.updateComplete; // for case of keyboard navigation where second month contains no enabled dates
835
- if (this.shadowRoot.querySelector('.d2l-calendar-date:enabled')) {
835
+ if (this.shadowRoot && this.shadowRoot.querySelector('.d2l-calendar-date:enabled')) {
836
836
  const validDates = this.shadowRoot.querySelectorAll('.d2l-calendar-date:enabled');
837
837
  const focusDate = validDates[latestPossibleFocusDate ? (validDates.length - 1) : 0].parentNode;
838
838
  const year = focusDate.getAttribute('data-year');
@@ -149,11 +149,11 @@ class CardFooterLink extends RtlMixin(LitElement) {
149
149
  }
150
150
 
151
151
  _onBlur() {
152
- this.shadowRoot.querySelector('d2l-count-badge-icon').forceFocusRing = false;
152
+ if (this.shadowRoot) this.shadowRoot.querySelector('d2l-count-badge-icon').forceFocusRing = false;
153
153
  }
154
154
 
155
155
  _onFocus() {
156
- this.shadowRoot.querySelector('d2l-count-badge-icon').forceFocusRing = true;
156
+ if (this.shadowRoot) this.shadowRoot.querySelector('d2l-count-badge-icon').forceFocusRing = true;
157
157
  }
158
158
 
159
159
  }
@@ -307,7 +307,7 @@ class Card extends RtlMixin(LitElement) {
307
307
  }
308
308
 
309
309
  focus() {
310
- const elem = this.shadowRoot.querySelector('a');
310
+ const elem = this.shadowRoot && this.shadowRoot.querySelector('a');
311
311
  if (!elem) return;
312
312
  elem.focus();
313
313
  }
@@ -36,7 +36,7 @@ class CodeView extends LitElement {
36
36
  const path = `/node_modules/prismjs/components/prism-${language}.min.js`;
37
37
  this._dependenciesPromise = import(path);
38
38
  }
39
- this._updateCode(this.shadowRoot.querySelector('slot'));
39
+ if (this.shadowRoot) this._updateCode(this.shadowRoot.querySelector('slot'));
40
40
  super.attributeChangedCallback(name, oldval, newval);
41
41
  }
42
42
 
@@ -52,7 +52,7 @@ class CodeView extends LitElement {
52
52
  }
53
53
 
54
54
  forceUpdate() {
55
- this._updateCode(this.shadowRoot.querySelector('slot'));
55
+ if (this.shadowRoot) this._updateCode(this.shadowRoot.querySelector('slot'));
56
56
  }
57
57
 
58
58
  get _codeTemplate() {
@@ -105,18 +105,19 @@ class DemoSnippet extends LitElement {
105
105
 
106
106
  changedProperties.forEach((_, prop) => {
107
107
  if (prop === '_code') {
108
- this.shadowRoot.querySelector('d2l-code-view').forceUpdate();
108
+ if (this.shadowRoot) this.shadowRoot.querySelector('d2l-code-view').forceUpdate();
109
109
  this._updateHasSkeleton();
110
110
  }
111
111
  });
112
112
  }
113
113
 
114
114
  forceCodeUpdate() {
115
- this._updateCode(this.shadowRoot.querySelector('slot:not([name="_demo"])'));
115
+ if (this.shadowRoot) this._updateCode(this.shadowRoot.querySelector('slot:not([name="_demo"])'));
116
116
  }
117
117
 
118
118
  _applyAttr(name, value, applyToShadowRoot) {
119
119
  const query = this._isTemplate ? 'slot[name="_demo"]' : 'slot:not([name="_demo"])';
120
+ if (!this.shadowRoot) return;
120
121
  const nodes = this.shadowRoot.querySelector(query).assignedNodes();
121
122
  if (nodes.length === 0) return;
122
123
  const doApply = (nodes, isRoot) => {
@@ -191,6 +192,7 @@ class DemoSnippet extends LitElement {
191
192
  }
192
193
 
193
194
  _removeImportedDemo() {
195
+ if (!this.shadowRoot) return;
194
196
  const nodes = this.shadowRoot.querySelector('slot[name="_demo"]').assignedNodes();
195
197
  for (let i = nodes.length - 1; i === 0; i--) {
196
198
  nodes[i].parentNode.removeChild(nodes[i]);
@@ -231,6 +233,7 @@ class DemoSnippet extends LitElement {
231
233
  _updateHasSkeleton() {
232
234
 
233
235
  const query = this._isTemplate ? 'slot[name="_demo"]' : 'slot:not([name="_demo"])';
236
+ if (!this.shadowRoot) return;
234
237
  const nodes = this.shadowRoot.querySelector(query).assignedNodes();
235
238
 
236
239
  const doApply = (nodes) => {
@@ -81,6 +81,7 @@ class DialogConfirm extends DialogMixin(LitElement) {
81
81
  }
82
82
 
83
83
  _focusInitial() {
84
+ if (!this.shadowRoot) return;
84
85
  const footer = this.shadowRoot.querySelector('.d2l-dialog-footer-slot');
85
86
  const nodes = footer.assignedNodes();
86
87
  for (let i = 0; i < nodes.length; i++) {
@@ -129,7 +129,7 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
129
129
 
130
130
  _addHandlers() {
131
131
  window.addEventListener('resize', this._updateSize);
132
- this.shadowRoot.querySelector('.d2l-dialog-content').addEventListener('scroll', this._updateOverflow);
132
+ if (this.shadowRoot) this.shadowRoot.querySelector('.d2l-dialog-content').addEventListener('scroll', this._updateOverflow);
133
133
  }
134
134
 
135
135
  _close(action) {
@@ -139,6 +139,7 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
139
139
  clearDismissible(this._dismissibleId);
140
140
  this._dismissibleId = null;
141
141
 
142
+ if (!this.shadowRoot) return;
142
143
  const dialog = this.shadowRoot.querySelector('.d2l-dialog-outer');
143
144
 
144
145
  const doClose = () => {
@@ -161,6 +162,7 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
161
162
  }
162
163
 
163
164
  _focusFirst() {
165
+ if (!this.shadowRoot) return;
164
166
  const content = this.shadowRoot.querySelector('.d2l-dialog-content');
165
167
  if (content) {
166
168
  const firstFocusable = getNextFocusable(content);
@@ -187,6 +189,7 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
187
189
  }
188
190
 
189
191
  _getHeight() {
192
+ if (!this.shadowRoot) return;
190
193
 
191
194
  const availableHeight = this._ifrauContextInfo
192
195
  ? this._ifrauContextInfo.availableHeight - this._margin.top - this._margin.bottom
@@ -303,6 +306,7 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
303
306
  this._action = undefined;
304
307
  this._addHandlers();
305
308
 
309
+ if (!this.shadowRoot) return;
306
310
  const dialog = this.shadowRoot.querySelector('.d2l-dialog-outer');
307
311
 
308
312
  const animPromise = new Promise((resolve) => {
@@ -357,7 +361,7 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
357
361
 
358
362
  _removeHandlers() {
359
363
  window.removeEventListener('resize', this._updateSize);
360
- this.shadowRoot.querySelector('.d2l-dialog-content').removeEventListener('scroll', this._updateOverflow);
364
+ if (this.shadowRoot) this.shadowRoot.querySelector('.d2l-dialog-content').removeEventListener('scroll', this._updateOverflow);
361
365
  }
362
366
 
363
367
  _render(inner, info, iframeTopOverride) {
@@ -423,6 +427,7 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
423
427
  }
424
428
 
425
429
  _updateOverflow() {
430
+ if (!this.shadowRoot) return;
426
431
  const content = this.shadowRoot.querySelector('.d2l-dialog-content');
427
432
  this._overflowTop = (content.scrollTop > 0);
428
433
  this._overflowBottom = (content.scrollHeight > content.scrollTop + content.clientHeight);
@@ -41,7 +41,7 @@ class DropdownButtonSubtle extends DropdownOpenerMixin(LitElement) {
41
41
  * @return {HTMLElement}
42
42
  */
43
43
  getOpenerElement() {
44
- return this.shadowRoot.querySelector('d2l-button-subtle');
44
+ return this.shadowRoot && this.shadowRoot.querySelector('d2l-button-subtle');
45
45
  }
46
46
 
47
47
  }
@@ -72,7 +72,7 @@ class DropdownButton extends DropdownOpenerMixin(RtlMixin(LitElement)) {
72
72
  * @return {HTMLElement}
73
73
  */
74
74
  getOpenerElement() {
75
- return this.shadowRoot.querySelector('d2l-button');
75
+ return this.shadowRoot && this.shadowRoot.querySelector('d2l-button');
76
76
  }
77
77
 
78
78
  }
@@ -338,7 +338,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
338
338
  };
339
339
 
340
340
  if (!reduceMotion && this._useMobileStyling && this.mobileTray && isVisible(this)) {
341
- this.shadowRoot.querySelector('.d2l-dropdown-content-width')
341
+ if (this.shadowRoot) this.shadowRoot.querySelector('.d2l-dropdown-content-width')
342
342
  .addEventListener('animationend', hide, { once: true });
343
343
  this._closing = true;
344
344
  this._showBackdrop = false;
@@ -399,15 +399,15 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
399
399
  }
400
400
 
401
401
  __getContentBottom() {
402
- return this.shadowRoot.querySelector('.d2l-dropdown-content-bottom');
402
+ return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-bottom');
403
403
  }
404
404
 
405
405
  __getContentContainer() {
406
- return this.shadowRoot.querySelector('.d2l-dropdown-content-container');
406
+ return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-container');
407
407
  }
408
408
 
409
409
  __getContentTop() {
410
- return this.shadowRoot.querySelector('.d2l-dropdown-content-top');
410
+ return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-top');
411
411
  }
412
412
 
413
413
  __getOpener() {
@@ -420,11 +420,11 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
420
420
  }
421
421
 
422
422
  __getPositionContainer() {
423
- return this.shadowRoot.querySelector('.d2l-dropdown-content-position');
423
+ return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-position');
424
424
  }
425
425
 
426
426
  __getWidthContainer() {
427
- return this.shadowRoot.querySelector('.d2l-dropdown-content-width');
427
+ return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-width');
428
428
  }
429
429
 
430
430
  __handleFooterSlotChange(e) {
@@ -55,7 +55,7 @@ class DropdownContextMenu extends DropdownOpenerMixin(VisibleOnAncestorMixin(Lit
55
55
  * @return {HTMLElement}
56
56
  */
57
57
  getOpenerElement() {
58
- return this.shadowRoot.querySelector('d2l-button-icon');
58
+ return this.shadowRoot && this.shadowRoot.querySelector('d2l-button-icon');
59
59
  }
60
60
 
61
61
  }
@@ -51,6 +51,7 @@ class DropdownMenu extends ThemeMixin(DropdownContentMixin(LitElement)) {
51
51
  }
52
52
 
53
53
  __getMenuElement() {
54
+ if (!this.shadowRoot) return undefined;
54
55
  return this.shadowRoot.querySelector('.d2l-dropdown-content-slot')
55
56
  .assignedNodes().filter(node => node.hasAttribute
56
57
  && (node.getAttribute('role') === 'menu' || node.getAttribute('role') === 'listbox'))[0];
@@ -55,7 +55,7 @@ class DropdownMore extends DropdownOpenerMixin(VisibleOnAncestorMixin(LitElement
55
55
  * @return {HTMLElement}
56
56
  */
57
57
  getOpenerElement() {
58
- return this.shadowRoot.querySelector('d2l-button-icon');
58
+ return this.shadowRoot && this.shadowRoot.querySelector('d2l-button-icon');
59
59
  }
60
60
 
61
61
  }
@@ -170,6 +170,7 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
170
170
  }
171
171
 
172
172
  __getContentElement() {
173
+ if (!this.shadowRoot) return undefined;
173
174
  return this.shadowRoot.querySelector('slot:not([name])').assignedNodes()
174
175
  .filter(node => node.hasAttribute && node.hasAttribute('dropdown-content'))[0];
175
176
  }
@@ -37,6 +37,7 @@ class DropdownTabs extends DropdownContentMixin(LitElement) {
37
37
  }
38
38
 
39
39
  _getTabsElement() {
40
+ if (!this.shadowRoot) return undefined;
40
41
  return this.shadowRoot.querySelector('.d2l-dropdown-content-container > slot')
41
42
  .assignedNodes()
42
43
  .filter(node => node.hasAttribute && node.tagName === 'D2L-TABS')[0];
@@ -21,6 +21,7 @@ class Dropdown extends DropdownOpenerMixin(LitElement) {
21
21
  * @return {HTMLElement}
22
22
  */
23
23
  getOpenerElement() {
24
+ if (!this.shadowRoot) return undefined;
24
25
  return this.shadowRoot.querySelector('slot')
25
26
  .assignedNodes()
26
27
  .filter(node => node.classList && node.classList.contains('d2l-dropdown-opener'))[0];
@@ -117,8 +117,8 @@ class ExpandCollapseContent extends LitElement {
117
117
  await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
118
118
  if (this._state === states.PREEXPANDING) {
119
119
  this._state = states.EXPANDING;
120
- const content = this.shadowRoot.querySelector('.d2l-expand-collapse-content-inner');
121
- this._height = `${content.scrollHeight}px`;
120
+ const content = this.shadowRoot && this.shadowRoot.querySelector('.d2l-expand-collapse-content-inner');
121
+ if (content) this._height = `${content.scrollHeight}px`;
122
122
  }
123
123
  }
124
124
  } else {
@@ -134,8 +134,8 @@ class ExpandCollapseContent extends LitElement {
134
134
  this._eventPromiseResolve();
135
135
  } else {
136
136
  this._state = states.PRECOLLAPSING;
137
- const content = this.shadowRoot.querySelector('.d2l-expand-collapse-content-inner');
138
- this._height = `${content.scrollHeight}px`;
137
+ const content = this.shadowRoot && this.shadowRoot.querySelector('.d2l-expand-collapse-content-inner');
138
+ if (content) this._height = `${content.scrollHeight}px`;
139
139
  await this.updateComplete;
140
140
  await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
141
141
  if (this._state === states.PRECOLLAPSING) {
@@ -213,7 +213,7 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
213
213
  }
214
214
 
215
215
  focus() {
216
- const opener = this.shadowRoot.querySelector('d2l-dropdown-button-subtle');
216
+ const opener = this.shadowRoot && this.shadowRoot.querySelector('d2l-dropdown-button-subtle');
217
217
  if (opener) opener.focus();
218
218
  }
219
219
 
@@ -523,7 +523,7 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
523
523
  }
524
524
 
525
525
  _handleDimensionHide() {
526
- this.shadowRoot.querySelector(`d2l-hierarchical-view[data-key="${this._activeDimensionKey}"]`).hide();
526
+ if (this.shadowRoot) this.shadowRoot.querySelector(`d2l-hierarchical-view[data-key="${this._activeDimensionKey}"]`).hide();
527
527
  }
528
528
 
529
529
  _handleDimensionHideKeyPress(e) {
@@ -538,8 +538,9 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
538
538
  }
539
539
 
540
540
  _handleDimensionShowComplete() {
541
- const returnButton = this.shadowRoot.querySelector('d2l-button-icon[icon="tier1:chevron-left"]');
542
- returnButton.focus();
541
+ const returnButton = this.shadowRoot
542
+ && this.shadowRoot.querySelector('d2l-button-icon[icon="tier1:chevron-left"]');
543
+ if (returnButton) returnButton.focus();
543
544
  }
544
545
 
545
546
  _handleDimensionShowStart(e) {
@@ -56,18 +56,19 @@ class FocusTrap extends LitElement {
56
56
  }
57
57
 
58
58
  focus() {
59
- const focusable = this.shadowRoot.querySelector('.d2l-focus-trap-start');
59
+ const focusable = this.shadowRoot && this.shadowRoot.querySelector('.d2l-focus-trap-start');
60
60
  if (focusable) focusable.focus();
61
61
  }
62
62
 
63
63
  _focusFirst() {
64
- const focusable = getNextFocusable(this.shadowRoot.querySelector('.d2l-focus-trap-start'));
64
+ const focusable = this.shadowRoot &&
65
+ getNextFocusable(this.shadowRoot.querySelector('.d2l-focus-trap-start'));
65
66
  if (focusable) forceFocusVisible(focusable);
66
67
  this.dispatchEvent(new CustomEvent('d2l-focus-trap-enter', { bubbles: true, composed: true }));
67
68
  }
68
69
 
69
70
  _getContainer() {
70
- return this.shadowRoot.querySelector('.d2l-focus-trap-start').parentNode;
71
+ return this.shadowRoot && this.shadowRoot.querySelector('.d2l-focus-trap-start').parentNode;
71
72
  }
72
73
 
73
74
  _handleBodyFocus(e) {
@@ -80,7 +81,7 @@ class FocusTrap extends LitElement {
80
81
 
81
82
  _handleEndFocusIn(e) {
82
83
  const container = this._getContainer();
83
- if (isComposedAncestor(container, e.relatedTarget)) {
84
+ if (this.shadowRoot && isComposedAncestor(container, e.relatedTarget)) {
84
85
  // user is exiting trap via forward tabbing...
85
86
  const firstFocusable = getNextFocusable(this.shadowRoot.querySelector('.d2l-focus-trap-start'));
86
87
  if (firstFocusable) {
@@ -96,7 +97,7 @@ class FocusTrap extends LitElement {
96
97
 
97
98
  _handleStartFocusIn(e) {
98
99
  const container = this._getContainer();
99
- if (isComposedAncestor(container, e.relatedTarget)) {
100
+ if (this.shadowRoot && isComposedAncestor(container, e.relatedTarget)) {
100
101
  // user is exiting trap via back tabbing...
101
102
  const lastFocusable = getPreviousFocusable(this.shadowRoot.querySelector('.d2l-focus-trap-end'));
102
103
  if (lastFocusable) {
@@ -86,7 +86,7 @@ class FormNestedDemo extends LitElement {
86
86
  }
87
87
 
88
88
  _submit() {
89
- this.shadowRoot.querySelector('#root').submit();
89
+ if (this.shadowRoot) this.shadowRoot.querySelector('#root').submit();
90
90
  }
91
91
 
92
92
  _validatePassword(e) {
@@ -66,11 +66,11 @@ class FormDialogDemo extends LitElement {
66
66
  e.stopPropagation();
67
67
  // eslint-disable-next-line no-console
68
68
  console.log(e.detail.formData);
69
- this.shadowRoot.querySelector('#dialog').opened = false;
69
+ if (this.shadowRoot) this.shadowRoot.querySelector('#dialog').opened = false;
70
70
  }
71
71
 
72
72
  _onDialogSubmitClicked() {
73
- this.shadowRoot.querySelector('#dialog-secondary-form').submit();
73
+ if (this.shadowRoot) this.shadowRoot.querySelector('#dialog-secondary-form').submit();
74
74
  }
75
75
 
76
76
  _onSubmit(e) {
@@ -79,11 +79,11 @@ class FormDialogDemo extends LitElement {
79
79
  }
80
80
 
81
81
  _onSubmitClicked() {
82
- this.shadowRoot.querySelector('#dialog-main-form').submit();
82
+ if (this.shadowRoot) this.shadowRoot.querySelector('#dialog-main-form').submit();
83
83
  }
84
84
 
85
85
  _openDialog() {
86
- this.shadowRoot.querySelector('#dialog').opened = true;
86
+ if (this.shadowRoot) this.shadowRoot.querySelector('#dialog').opened = true;
87
87
  }
88
88
 
89
89
  _validatePassword(e) {
@@ -69,7 +69,7 @@ class FormNativeDemo extends LitElement {
69
69
  }
70
70
 
71
71
  _onClick(e) {
72
- this.shadowRoot.querySelector('d2l-form-native').requestSubmit(e.target);
72
+ if (this.shadowRoot) this.shadowRoot.querySelector('d2l-form-native').requestSubmit(e.target);
73
73
  }
74
74
 
75
75
  _validatePassword(e) {
@@ -136,9 +136,6 @@ export const FormElementMixin = superclass => class extends LocalizeCoreElement(
136
136
  /** @ignore */
137
137
  this.childErrors = new Map();
138
138
  this._errors = [];
139
-
140
- this.shadowRoot.addEventListener('d2l-validation-custom-connected', this._validationCustomConnected);
141
- this.shadowRoot.addEventListener('d2l-form-element-errors-change', this._onFormElementErrorsChange);
142
139
  }
143
140
 
144
141
  /** @ignore */
@@ -160,6 +157,18 @@ export const FormElementMixin = superclass => class extends LocalizeCoreElement(
160
157
  return this._validity;
161
158
  }
162
159
 
160
+ connectedCallback() {
161
+ super.connectedCallback();
162
+ this.shadowRoot.addEventListener('d2l-validation-custom-connected', this._validationCustomConnected);
163
+ this.shadowRoot.addEventListener('d2l-form-element-errors-change', this._onFormElementErrorsChange);
164
+ }
165
+
166
+ disconnectedCallback() {
167
+ super.disconnectedCallback();
168
+ this.shadowRoot.removeEventListener('d2l-validation-custom-connected', this._validationCustomConnected);
169
+ this.shadowRoot.removeEventListener('d2l-form-element-errors-change', this._onFormElementErrorsChange);
170
+ }
171
+
163
172
  updated(changedProperties) {
164
173
  if (changedProperties.has('_errors') || changedProperties.has('childErrors')) {
165
174
  let errors = this._errors;
@@ -104,8 +104,8 @@ class FormErrorSummary extends LocalizeCoreElement(RtlMixin(LitElement)) {
104
104
  } else {
105
105
  focusEleSelector = 'd2l-button-icon';
106
106
  }
107
- const focusEle = this.shadowRoot.querySelector(focusEleSelector);
108
- focusEle.focus();
107
+ const focusEle = this.shadowRoot && this.shadowRoot.querySelector(focusEleSelector);
108
+ if (focusEle) focusEle.focus();
109
109
  }
110
110
 
111
111
  _toggleExpandCollapse(e) {
@@ -133,7 +133,7 @@ class FormNative extends FormMixin(LitElement) {
133
133
  }
134
134
  }
135
135
  this._errors = errorMap;
136
- if (errorMap.size > 0) {
136
+ if (this.shadowRoot && errorMap.size > 0) {
137
137
  const errorSummary = this.shadowRoot.querySelector('d2l-form-error-summary');
138
138
  this.updateComplete.then(() => errorSummary.focus());
139
139
  }
@@ -100,7 +100,7 @@ class Form extends FormMixin(LitElement) {
100
100
  const flattenedErrorMap = flattenMap(errorMap);
101
101
  this._errors = errorMap;
102
102
  if (errorMap.size > 0) {
103
- const errorSummary = this.shadowRoot.querySelector('d2l-form-error-summary');
103
+ const errorSummary = this.shadowRoot && this.shadowRoot.querySelector('d2l-form-error-summary');
104
104
  if (errorSummary) {
105
105
  this.updateComplete.then(() => errorSummary.focus());
106
106
  }
@@ -222,7 +222,7 @@ export const HierarchicalViewMixin = superclass => class extends superclass {
222
222
  }
223
223
 
224
224
  isActive() {
225
- if (this.childView && !this.shown) {
225
+ if ((this.childView && !this.shown) || !this.shadowRoot) {
226
226
  return false;
227
227
  } else {
228
228
  const content = this.shadowRoot.querySelector('.d2l-hierarchical-view-content');
@@ -290,7 +290,7 @@ export const HierarchicalViewMixin = superclass => class extends superclass {
290
290
 
291
291
  this.__isAutoSized = true;
292
292
  let rect;
293
- if (view === this) {
293
+ if (view === this && this.shadowRoot) {
294
294
  rect = this.shadowRoot.querySelector('.d2l-hierarchical-view-content').getBoundingClientRect();
295
295
  } else {
296
296
  rect = view.getBoundingClientRect();
@@ -325,6 +325,7 @@ export const HierarchicalViewMixin = superclass => class extends superclass {
325
325
  view.resize();
326
326
  return;
327
327
  }
328
+ if (!this.shadowRoot) return;
328
329
  const content = this.shadowRoot.querySelector('.d2l-hierarchical-view-content');
329
330
  const contentRect = content.getBoundingClientRect();
330
331
  if (contentRect.height < 1) return;
@@ -432,7 +433,7 @@ export const HierarchicalViewMixin = superclass => class extends superclass {
432
433
  if (rootTarget === this || !rootTarget.hierarchicalView) return;
433
434
 
434
435
  const parentView = this.__getParentViewFromEvent(e);
435
- if (parentView === this) {
436
+ if (this.shadowRoot && parentView === this) {
436
437
  const content = this.shadowRoot.querySelector('.d2l-hierarchical-view-content');
437
438
 
438
439
  const data = e.detail.data;
@@ -495,16 +496,16 @@ export const HierarchicalViewMixin = superclass => class extends superclass {
495
496
  /* deep link scenario */
496
497
  this.show(e.detail.data, e.detail.sourceView);
497
498
  }
498
- const content = this.shadowRoot.querySelector('.d2l-hierarchical-view-content');
499
+ const content = this.shadowRoot && this.shadowRoot.querySelector('.d2l-hierarchical-view-content');
499
500
 
500
- if (reduceMotion) {
501
+ if (this.shadowRoot && reduceMotion) {
501
502
 
502
503
  content.classList.add('d2l-child-view-show');
503
504
  requestAnimationFrame(() => {
504
505
  e.detail.sourceView.__dispatchShowComplete(e.detail.data, e.detail);
505
506
  });
506
507
 
507
- } else {
508
+ } else if (this.shadowRoot) {
508
509
 
509
510
  if (e.detail.isSource && this.__getParentViewFromEvent(e) === this) {
510
511
  const animationEnd = () => {
@@ -80,6 +80,37 @@
80
80
  </template>
81
81
  </d2l-demo-snippet>
82
82
 
83
+ <h2>HTML Block (compact)</h2>
84
+
85
+ <d2l-demo-snippet>
86
+ <template>
87
+ <d2l-html-block compact>
88
+ <template>
89
+ <h1>heading 1</h1>
90
+ <h2>heading 2</h2>
91
+ <h3>heading 3</h3>
92
+ <h4>heading 4</h4>
93
+ <h5>heading 5</h5>
94
+ <h6>heading 6</h6>
95
+ <div><strong>strong</strong></div>
96
+ <div><b>bold</b></div>
97
+ <div>text</div>
98
+ <pre>preformatted</pre>
99
+ <p>paragraph</p>
100
+ <ul>
101
+ <li>unordered item 1</li>
102
+ <li>unordered item 2</li>
103
+ </ul>
104
+ <ol>
105
+ <li>ordered item 1</li>
106
+ <li>ordered item 2</li>
107
+ </ol>
108
+ <div><a href="https://d2l.com">anchor</a></div>
109
+ </template>
110
+ </d2l-html-block>
111
+ </template>
112
+ </d2l-demo-snippet>
113
+
83
114
  <h2>HTML Block (math)</h2>
84
115
 
85
116
  <d2l-demo-snippet>