@brightspace-ui/core 3.33.1 → 3.35.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -216,7 +216,10 @@ class HtmlBlock extends LitElement {
216
216
 
217
217
  const contextValsPromise = contextKeysPromise.then(contextKeys => {
218
218
  return Promise.allSettled(contextKeys.map(key => {
219
- return tryGet(key, undefined, ctx => this._context.set(key, ctx));
219
+ return tryGet(key, undefined, ctx => {
220
+ this._context.set(key, ctx);
221
+ this.updated(new Map([['_context']]));
222
+ });
220
223
  }));
221
224
  });
222
225
 
@@ -234,24 +237,17 @@ class HtmlBlock extends LitElement {
234
237
  'd2l-html-block-compact': this.compact
235
238
  };
236
239
 
237
- if (this._embedsFeatureEnabled()) {
238
- return html`
239
- <div class="${classMap(renderContainerClasses)}">
240
- ${!this.noDeferredRendering ? until(this._processEmbeds(), nothing) : nothing}
241
- </div>
242
- ${this.noDeferredRendering ? html`<slot @slotchange="${this._handleSlotChange}"></slot>` : ''}
243
- `;
244
- } else {
245
- return html`
246
- <div class="${classMap(renderContainerClasses)}"></div>
247
- ${this.noDeferredRendering ? html`<slot @slotchange="${this._handleSlotChange}"></slot>` : ''}
248
- `;
249
- }
240
+ return html`
241
+ <div class="${classMap(renderContainerClasses)}">
242
+ ${!this.noDeferredRendering ? until(this._processEmbeds(), nothing) : nothing}
243
+ </div>
244
+ ${this.noDeferredRendering ? html`<slot @slotchange="${this._handleSlotChange}"></slot>` : ''}
245
+ `;
250
246
  }
251
247
 
252
248
  async updated(changedProperties) {
253
249
  super.updated(changedProperties);
254
- if ((changedProperties.has('html') || changedProperties.has('_context')) && this.html !== undefined && this.html !== null && !this.noDeferredRendering) {
250
+ if ((changedProperties.has('embeds') || changedProperties.has('_context')) && this.html !== undefined && this.html !== null && !this.noDeferredRendering) {
255
251
  await this._updateRenderContainer();
256
252
  }
257
253
  }
@@ -260,10 +256,6 @@ class HtmlBlock extends LitElement {
260
256
  return this._renderersProcessedPromise;
261
257
  }
262
258
 
263
- _embedsFeatureEnabled() {
264
- return window.D2L?.LP?.Web?.UI?.Flags.Flag('shield-7574-enable-embed-rendering-framework', true);
265
- }
266
-
267
259
  async _handleSlotChange(e) {
268
260
  if (!e.target || !this.shadowRoot || !this.noDeferredRendering) return;
269
261
  await this._renderInline(e.target);
@@ -272,6 +264,7 @@ class HtmlBlock extends LitElement {
272
264
  async _processEmbeds() {
273
265
  const htmlFragment = document.createRange().createContextualFragment(this.html);
274
266
  await renderEmbeds(htmlFragment);
267
+ this.updated(new Map([['embeds']]));
275
268
  return htmlFragment;
276
269
  }
277
270
 
@@ -315,7 +308,6 @@ class HtmlBlock extends LitElement {
315
308
 
316
309
  async _updateRenderContainer() {
317
310
  const renderContainer = this.shadowRoot.querySelector('.d2l-html-block-rendered');
318
- if (!this._embedsFeatureEnabled()) renderContainer.innerHTML = this.html;
319
311
  await this._processRenderers(renderContainer);
320
312
  }
321
313
 
@@ -41,6 +41,7 @@ class TestTable extends RtlMixin(DemoPassthroughMixin(TableWrapper, 'd2l-table-w
41
41
  static get properties() {
42
42
  return {
43
43
  paging: { type: Boolean, reflect: true },
44
+ multiLine: { type: Boolean, attribute: 'multi-line' },
44
45
  showButtons: { type: Boolean, attribute: 'show-buttons' },
45
46
  stickyControls: { attribute: 'sticky-controls', type: Boolean, reflect: true },
46
47
  visibleBackground: { attribute: 'visible-background', type: Boolean, reflect: true },
@@ -72,6 +73,7 @@ class TestTable extends RtlMixin(DemoPassthroughMixin(TableWrapper, 'd2l-table-w
72
73
  constructor() {
73
74
  super();
74
75
 
76
+ this.multiLine = false;
75
77
  this.paging = false;
76
78
  this.showButtons = false;
77
79
  this.stickyControls = false;
@@ -99,11 +101,25 @@ class TestTable extends RtlMixin(DemoPassthroughMixin(TableWrapper, 'd2l-table-w
99
101
 
100
102
  <table class="d2l-table">
101
103
  <thead>
102
- <tr>
103
- <th scope="col" sticky><d2l-selection-select-all></d2l-selection-select-all></th>
104
- ${this._renderDoubleSortButton('Location')}
105
- ${columns.map(columnHeading => this._renderSortButton(columnHeading))}
106
- </tr>
104
+ ${this.multiLine ? html`
105
+ <tr>
106
+ <th scope="col" sticky><d2l-selection-select-all></d2l-selection-select-all></th>
107
+ ${this._renderDoubleSortButton('Location')}
108
+ <th scope="col" colspan="${columns.length}" sticky>
109
+ Metrics
110
+ </th>
111
+ </tr>
112
+ <tr>
113
+ <th scope="col" sticky></th>
114
+ ${columns.map(columnHeading => this._renderSortButton(columnHeading))}
115
+ </tr>
116
+ ` : html`
117
+ <tr>
118
+ <th scope="col" sticky><d2l-selection-select-all></d2l-selection-select-all></th>
119
+ ${this._renderDoubleSortButton('Location')}
120
+ ${columns.map(columnHeading => this._renderSortButton(columnHeading))}
121
+ </tr>
122
+ `}
107
123
  </thead>
108
124
  <tbody>
109
125
  <tr class="d2l-table-header">
@@ -182,7 +198,7 @@ class TestTable extends RtlMixin(DemoPassthroughMixin(TableWrapper, 'd2l-table-w
182
198
  _renderDoubleSortButton(name) {
183
199
  const noSort = this._sortField?.toLowerCase() !== 'city' && this._sortField?.toLowerCase() !== 'country';
184
200
  return html`
185
- <th scope="col">
201
+ <th rowspan="${this.multiLine ? 2 : 1}" scope="col">
186
202
  <d2l-table-col-sort-button
187
203
  ?desc="${this._sortDesc}"
188
204
  ?nosort="${noSort}">${name}
@@ -80,6 +80,13 @@
80
80
  </template>
81
81
  </d2l-demo-snippet>
82
82
 
83
+ <h2>Multi-line with scroll-wrapper + sticky</h2>
84
+ <d2l-demo-snippet>
85
+ <template>
86
+ <d2l-test-table multi-line sticky-headers sticky-controls sticky-headers-scroll-wrapper style="width: 400px;"></d2l-test-table>
87
+ </template>
88
+ </d2l-demo-snippet>
89
+
83
90
  <div style="margin-bottom: 1000px;"></div>
84
91
  </d2l-demo-page>
85
92
  </body>
@@ -599,16 +599,87 @@ export class TableWrapper extends RtlMixin(PageableMixin(SelectionMixin(LitEleme
599
599
  const body = this._table.querySelector('tbody');
600
600
  if (!head || !body) return;
601
601
 
602
- const firstRowHead = head.rows[0];
603
- const firstRowBody = body.rows[0];
604
- if (!firstRowHead || !firstRowBody || firstRowHead.cells.length !== firstRowBody.cells.length) return;
602
+ const candidateRowHeadCells = [];
605
603
 
606
- for (let i = 0; i < firstRowHead.cells.length; i++) {
607
- const headCell = firstRowHead.cells[i];
608
- const bodyCell = firstRowBody.cells[i];
609
- const bodyStyle = getComputedStyle(bodyCell);
604
+ // Max length of one of our body rows, which we'll try to map to our candidate head cells.
605
+ const maxRowBodyLength = Math.max(...([...body.rows].map(row => row.cells.length)));
606
+
607
+ const headCellsMap = [];
608
+ for (let i = 0; i < head.rows.length; i++) {
609
+ headCellsMap[i] = [];
610
+ }
611
+
612
+ // Build a map of which cells "exist" in each head row so we can pick out
613
+ // a candidate in each column to sync widths with.
614
+ for (let rowIndex = 0; rowIndex < head.rows.length; rowIndex++) {
615
+ const rowMap = headCellsMap[rowIndex];
616
+
617
+ let spanOffset = 0;
618
+ for (let colIndex = 0; colIndex < maxRowBodyLength; colIndex++) {
619
+ if (rowMap[colIndex] === null) {
620
+ spanOffset++;
621
+ continue;
622
+ }
623
+
624
+ const cell = head.rows[rowIndex].cells[colIndex - spanOffset];
625
+ rowMap[colIndex] = cell;
626
+
627
+ if (!cell) continue;
628
+
629
+ const colSpan = cell.colSpan;
630
+ const rowSpan = cell.rowSpan;
631
+
632
+ for (let offset = 1; offset < colSpan; offset++) {
633
+ rowMap[colIndex + offset] = null;
634
+ }
635
+
636
+ for (let offset = 1; offset < rowSpan; offset++) {
637
+ headCellsMap[rowIndex + offset][colIndex] = null;
638
+ }
639
+ }
640
+ }
641
+
642
+ // Pick out a single head cell for each column to sync widths.
643
+ for (let i = 0; i < maxRowBodyLength; i++) {
644
+ let candidateCell;
645
+ for (const rowMap of headCellsMap) {
646
+ const cell = rowMap[i];
647
+
648
+ if (cell && cell.colSpan === 1) {
649
+ candidateCell = cell;
650
+ break;
651
+ }
652
+ }
653
+
654
+ // This does not support heads without at least one single-column
655
+ // spanning cell in each column.
656
+ if (!candidateCell) return;
657
+
658
+ candidateRowHeadCells[i] = candidateCell;
659
+ }
660
+
661
+ // Pick the body row with the most cells (and no colspans) to measure against
662
+ const candidateRowBody = [...body.rows].find(row => {
663
+ return row.cells.length === maxRowBodyLength
664
+ && ![...row.cells].find(cell => cell.colSpan > 1);
665
+ });
666
+
667
+ if (candidateRowHeadCells.length === 0 || !candidateRowBody) return;
668
+
669
+ let candidateRowBodyLength = 0;
670
+ for (const cell of candidateRowBody.cells) {
671
+ candidateRowBodyLength += cell.colSpan;
672
+ }
673
+
674
+ if (candidateRowHeadCells.length !== candidateRowBodyLength) return;
675
+
676
+ for (let i = 0; i < candidateRowHeadCells.length; i++) {
677
+ const headCell = candidateRowHeadCells[i];
610
678
  const headStyle = getComputedStyle(headCell);
611
679
 
680
+ const bodyCell = candidateRowBody.cells[i];
681
+ const bodyStyle = getComputedStyle(bodyCell);
682
+
612
683
  if (headCell.clientWidth > bodyCell.clientWidth) {
613
684
  const headOverallWidth = parseFloat(headStyle.width) + parseFloat(headStyle.paddingLeft) + parseFloat(headStyle.paddingRight);
614
685
  bodyCell.style.minWidth = `${headOverallWidth - parseFloat(bodyStyle.paddingLeft) - parseFloat(bodyStyle.paddingRight)}px`;
@@ -11944,6 +11944,11 @@
11944
11944
  "name": "d2l-test-table",
11945
11945
  "path": "./components/table/demo/table-test.js",
11946
11946
  "attributes": [
11947
+ {
11948
+ "name": "multi-line",
11949
+ "type": "boolean",
11950
+ "default": "false"
11951
+ },
11947
11952
  {
11948
11953
  "name": "paging",
11949
11954
  "type": "boolean",
@@ -12001,6 +12006,12 @@
12001
12006
  }
12002
12007
  ],
12003
12008
  "properties": [
12009
+ {
12010
+ "name": "multiLine",
12011
+ "attribute": "multi-line",
12012
+ "type": "boolean",
12013
+ "default": "false"
12014
+ },
12004
12015
  {
12005
12016
  "name": "paging",
12006
12017
  "attribute": "paging",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.33.1",
3
+ "version": "3.35.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",