@brightspace-ui/core 2.39.1 → 2.42.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.
@@ -254,7 +254,7 @@ A tag-list allowing the user to see (and remove) the currently applied filters.
254
254
  display: block;
255
255
  max-width: 100%;
256
256
  }
257
- }
257
+ }
258
258
  </style>
259
259
  <div class="filter-wrapper">
260
260
  <d2l-filter-tags filter-ids="core-filter core-filter-2"></d2l-filter-tags>
@@ -298,6 +298,81 @@ A tag-list allowing the user to see (and remove) the currently applied filters.
298
298
  | `label` | String | The text displayed in this component's label |
299
299
  <!-- docs: end hidden content -->
300
300
 
301
+ ## Filter Overflow Group [d2l-filter-overflow-group]
302
+
303
+ The `d2l-filter-overflow-group` is a container for multiple filters that handles overflow on smaller screens. Overflowing filters are displayed in a single filter.
304
+
305
+ <!-- docs: demo live name:d2l-filter-overflow-group align:start display:block autoSize:false size:medium -->
306
+ ```html
307
+ <script type="module">
308
+ import '@brightspace-ui/core/components/filter/filter.js';
309
+ import '@brightspace-ui/core/components/filter/filter-dimension-set.js';
310
+ import '@brightspace-ui/core/components/filter/filter-dimension-set-value.js';
311
+ import '@brightspace-ui/core/components/filter/filter-overflow-group.js';
312
+ </script>
313
+ <d2l-filter-overflow-group>
314
+ <d2l-filter>
315
+ <d2l-filter-dimension-set key="skill" text="Skill">
316
+ <d2l-filter-dimension-set-value key="communication" text="Fall"></d2l-filter-dimension-set-value>
317
+ <d2l-filter-dimension-set-value key="leadership" text="Winter"></d2l-filter-dimension-set-value>
318
+ <d2l-filter-dimension-set-value key="management" text="Spring"></d2l-filter-dimension-set-value>
319
+ <d2l-filter-dimension-set-value key="planning" text="Summer"></d2l-filter-dimension-set-value>
320
+ </d2l-filter-dimension-set>
321
+ </d2l-filter>
322
+ <d2l-filter>
323
+ <d2l-filter-dimension-set key="type" text="Type" selection-single>
324
+ <d2l-filter-dimension-set-value key="certificate" text="Certificate"></d2l-filter-dimension-set-value>
325
+ <d2l-filter-dimension-set-value key="degree" text="Degree"></d2l-filter-dimension-set-value>
326
+ <d2l-filter-dimension-set-value key="diploma" text="Diploma"></d2l-filter-dimension-set-value>
327
+ <d2l-filter-dimension-set-value key="course" text="Course"></d2l-filter-dimension-set-value>
328
+ </d2l-filter-dimension-set>
329
+ </d2l-filter>
330
+ <d2l-filter>
331
+ <d2l-filter-dimension-set key="course" text="Course" select-all>
332
+ <d2l-filter-dimension-set-value key="art" text="Art"></d2l-filter-dimension-set-value>
333
+ <d2l-filter-dimension-set-value key="astronomy" text="Astronomy" selected></d2l-filter-dimension-set-value>
334
+ <d2l-filter-dimension-set-value key="biology" text="Biology"></d2l-filter-dimension-set-value>
335
+ <d2l-filter-dimension-set-value key="chemistry" text="Chemistry"></d2l-filter-dimension-set-value>
336
+ </d2l-filter-dimension-set>
337
+ <d2l-filter-dimension-set key="duration" text="Duration">
338
+ <d2l-filter-dimension-set-value key="lessthanthree" text="< 3 months"></d2l-filter-dimension-set-value>
339
+ <d2l-filter-dimension-set-value key="threetosix" text="3-6 months"></d2l-filter-dimension-set-value>
340
+ <d2l-filter-dimension-set-value key="sixtotwelve" text="6-12 months"></d2l-filter-dimension-set-value>
341
+ </d2l-filter-dimension-set>
342
+ </d2l-filter>
343
+ <d2l-filter>
344
+ <d2l-filter-dimension-set key="provider" text="Semester3">
345
+ <d2l-filter-dimension-set-value key="mcmaster" text="McMaster"></d2l-filter-dimension-set-value>
346
+ <d2l-filter-dimension-set-value key="powered" text="PowerED"></d2l-filter-dimension-set-value>
347
+ <d2l-filter-dimension-set-value key="guelph" text="University of Guelph"></d2l-filter-dimension-set-value>
348
+ <d2l-filter-dimension-set-value key="manitoba" text="University of Manitoba"></d2l-filter-dimension-set-value>
349
+ </d2l-filter-dimension-set>
350
+ </d2l-filter>
351
+ <d2l-filter>
352
+ <d2l-filter-dimension-set key="format" text="Format">
353
+ <d2l-filter-dimension-set-value key="selfpaced" text="Self-Paced"></d2l-filter-dimension-set-value>
354
+ <d2l-filter-dimension-set-value key="instructor" text="Instructor Lead" selected></d2l-filter-dimension-set-value>
355
+ </d2l-filter-dimension-set>
356
+ </d2l-filter>
357
+ <d2l-filter>
358
+ <d2l-filter-dimension-set key="language" text="Language" selection-single>
359
+ <d2l-filter-dimension-set-value key="english" text="English"></d2l-filter-dimension-set-value>
360
+ <d2l-filter-dimension-set-value key="french" text="French"></d2l-filter-dimension-set-value>
361
+ <d2l-filter-dimension-set-value key="spanish" text="Spanish"></d2l-filter-dimension-set-value>
362
+ </d2l-filter-dimension-set>
363
+ </d2l-filter>
364
+ </d2l-filter-overflow-group>
365
+ ```
366
+
367
+ <!-- docs: start hidden content -->
368
+ ### Properties
369
+
370
+ | Property | Type | Description |
371
+ |---|---|---|
372
+ | `min-to-show` | Number | The minimum number of elements to always show. Please consult the design team when using this attribute. |
373
+ | `max-to-show` | Number | The maximum number of elements to show |
374
+ <!-- docs: end hidden content -->
375
+
301
376
  ## Filter Dimension: Date [d2l-filter-dimension-date]
302
377
 
303
378
  **Coming Soon!**
@@ -0,0 +1,168 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <link rel="stylesheet" href="../../demo/styles.css" type="text/css">
6
+ <script type="module">
7
+ import '../../demo/demo-page.js';
8
+ import '../../filter/filter.js';
9
+ import '../../filter/filter-dimension-set.js';
10
+ import '../../filter/filter-dimension-set-value.js';
11
+ import '../../filter/filter-overflow-group.js';
12
+ import '../../filter/filter-tags.js';
13
+ </script>
14
+ <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1.0">
15
+ <meta charset="UTF-8">
16
+ <style>
17
+ d2l-filter-tags {
18
+ padding-top: 1rem;
19
+ }
20
+ </style>
21
+ </head>
22
+
23
+ <body unresolved>
24
+
25
+ <d2l-demo-page page-title="d2l-filter-overflow-group">
26
+
27
+ <h2>Filter Overflow Group</h2>
28
+ <d2l-demo-snippet>
29
+ <template>
30
+ <d2l-filter-overflow-group>
31
+ <d2l-filter>
32
+ <d2l-filter-dimension-set key="skill" text="Skill">
33
+ <d2l-filter-dimension-set-value key="communication" text="Fall"></d2l-filter-dimension-set-value>
34
+ <d2l-filter-dimension-set-value key="leadership" text="Winter"></d2l-filter-dimension-set-value>
35
+ <d2l-filter-dimension-set-value key="management" text="Spring"></d2l-filter-dimension-set-value>
36
+ <d2l-filter-dimension-set-value key="planning" text="Summer"></d2l-filter-dimension-set-value>
37
+ </d2l-filter-dimension-set>
38
+ </d2l-filter>
39
+ <d2l-filter>
40
+ <d2l-filter-dimension-set key="type" text="Type" selection-single>
41
+ <d2l-filter-dimension-set-value key="certificate" text="Certificate"></d2l-filter-dimension-set-value>
42
+ <d2l-filter-dimension-set-value key="degree" text="Degree"></d2l-filter-dimension-set-value>
43
+ <d2l-filter-dimension-set-value key="diploma" text="Diploma"></d2l-filter-dimension-set-value>
44
+ <d2l-filter-dimension-set-value key="course" text="Course"></d2l-filter-dimension-set-value>
45
+ </d2l-filter-dimension-set>
46
+ </d2l-filter>
47
+ <d2l-filter>
48
+ <d2l-filter-dimension-set key="provider" text="Semester3">
49
+ <d2l-filter-dimension-set-value key="mcmaster" text="McMaster"></d2l-filter-dimension-set-value>
50
+ <d2l-filter-dimension-set-value key="powered" text="PowerED"></d2l-filter-dimension-set-value>
51
+ <d2l-filter-dimension-set-value key="guelph" text="University of Guelph"></d2l-filter-dimension-set-value>
52
+ <d2l-filter-dimension-set-value key="manitoba" text="University of Manitoba"></d2l-filter-dimension-set-value>
53
+ </d2l-filter-dimension-set>
54
+ </d2l-filter>
55
+ <d2l-filter>
56
+ <d2l-filter-dimension-set key="format" text="Format">
57
+ <d2l-filter-dimension-set-value key="selfpaced" text="Self-Paced"></d2l-filter-dimension-set-value>
58
+ <d2l-filter-dimension-set-value key="instructor" text="Instructor Lead" selected></d2l-filter-dimension-set-value>
59
+ </d2l-filter-dimension-set>
60
+ </d2l-filter>
61
+ <d2l-filter>
62
+ <d2l-filter-dimension-set key="language" text="Language" selection-single>
63
+ <d2l-filter-dimension-set-value key="english" text="English"></d2l-filter-dimension-set-value>
64
+ <d2l-filter-dimension-set-value key="french" text="French"></d2l-filter-dimension-set-value>
65
+ <d2l-filter-dimension-set-value key="spanish" text="Spanish"></d2l-filter-dimension-set-value>
66
+ </d2l-filter-dimension-set>
67
+ </d2l-filter>
68
+ <d2l-filter>
69
+ <d2l-filter-dimension-set key="course" text="Course" select-all>
70
+ <d2l-filter-dimension-set-value key="art" text="Art"></d2l-filter-dimension-set-value>
71
+ <d2l-filter-dimension-set-value key="astronomy" text="Astronomy" selected></d2l-filter-dimension-set-value>
72
+ <d2l-filter-dimension-set-value key="biology" text="Biology"></d2l-filter-dimension-set-value>
73
+ <d2l-filter-dimension-set-value key="chemistry" text="Chemistry"></d2l-filter-dimension-set-value>
74
+ <d2l-filter-dimension-set-value key="drama" text="Drama"></d2l-filter-dimension-set-value>
75
+ <d2l-filter-dimension-set-value key="english" text="English"></d2l-filter-dimension-set-value>
76
+ <d2l-filter-dimension-set-value key="how-to" text="How To Write a How To Article With a Flashy Title"></d2l-filter-dimension-set-value>
77
+ <d2l-filter-dimension-set-value key="math" text="Math"></d2l-filter-dimension-set-value>
78
+ <d2l-filter-dimension-set-value key="physics" text="Physics"></d2l-filter-dimension-set-value>
79
+ <d2l-filter-dimension-set-value key="stats" text="Statistics"></d2l-filter-dimension-set-value>
80
+ <d2l-filter-dimension-set-value key="writerscraft" text="Writer's Craft"></d2l-filter-dimension-set-value>
81
+ </d2l-filter-dimension-set>
82
+ <d2l-filter-dimension-set key="duration" text="Duration">
83
+ <d2l-filter-dimension-set-value key="lessthanthree" text="< 3 months"></d2l-filter-dimension-set-value>
84
+ <d2l-filter-dimension-set-value key="threetosix" text="3-6 months"></d2l-filter-dimension-set-value>
85
+ <d2l-filter-dimension-set-value key="sixtotwelve" text="6-12 months"></d2l-filter-dimension-set-value>
86
+ </d2l-filter-dimension-set>
87
+ <d2l-filter-dimension-set key="hoursperweek" text="SemesterNested" selection-single>
88
+ <d2l-filter-dimension-set-value key="lessthanfive" text="< 5 hrs/week"></d2l-filter-dimension-set-value>
89
+ <d2l-filter-dimension-set-value key="fivetoten" text="5-10 hrs/week" selected></d2l-filter-dimension-set-value>
90
+ <d2l-filter-dimension-set-value key="tentotwenty" text="10-20 hrs/week"></d2l-filter-dimension-set-value>
91
+ </d2l-filter-dimension-set>
92
+ </d2l-filter>
93
+ </d2l-filter-overflow-group>
94
+ </template>
95
+ </d2l-demo-snippet>
96
+
97
+ <h2>Filter Overflow Group with Tags (external to d2l-filter-overflow-group)</h2>
98
+ <d2l-demo-snippet>
99
+ <template>
100
+ <d2l-filter-overflow-group>
101
+ <d2l-filter id="filter1">
102
+ <d2l-filter-dimension-set key="skill" text="Skill">
103
+ <d2l-filter-dimension-set-value key="communication" text="Fall"></d2l-filter-dimension-set-value>
104
+ <d2l-filter-dimension-set-value key="leadership" text="Winter"></d2l-filter-dimension-set-value>
105
+ <d2l-filter-dimension-set-value key="management" text="Spring"></d2l-filter-dimension-set-value>
106
+ <d2l-filter-dimension-set-value key="planning" text="Summer"></d2l-filter-dimension-set-value>
107
+ </d2l-filter-dimension-set>
108
+ </d2l-filter>
109
+ <d2l-filter id="filter2">
110
+ <d2l-filter-dimension-set key="type" text="Type" selection-single>
111
+ <d2l-filter-dimension-set-value key="certificate" text="Certificate"></d2l-filter-dimension-set-value>
112
+ <d2l-filter-dimension-set-value key="degree" text="Degree"></d2l-filter-dimension-set-value>
113
+ <d2l-filter-dimension-set-value key="diploma" text="Diploma"></d2l-filter-dimension-set-value>
114
+ <d2l-filter-dimension-set-value key="course" text="Course"></d2l-filter-dimension-set-value>
115
+ </d2l-filter-dimension-set>
116
+ </d2l-filter>
117
+ <d2l-filter id="filter3">
118
+ <d2l-filter-dimension-set key="provider" text="Semester3">
119
+ <d2l-filter-dimension-set-value key="mcmaster" text="McMaster"></d2l-filter-dimension-set-value>
120
+ <d2l-filter-dimension-set-value key="powered" text="PowerED"></d2l-filter-dimension-set-value>
121
+ <d2l-filter-dimension-set-value key="guelph" text="University of Guelph"></d2l-filter-dimension-set-value>
122
+ <d2l-filter-dimension-set-value key="manitoba" text="University of Manitoba"></d2l-filter-dimension-set-value>
123
+ </d2l-filter-dimension-set>
124
+ </d2l-filter>
125
+ <d2l-filter id="filter4">
126
+ <d2l-filter-dimension-set key="format" text="Format">
127
+ <d2l-filter-dimension-set-value key="selfpaced" text="Self-Paced"></d2l-filter-dimension-set-value>
128
+ <d2l-filter-dimension-set-value key="instructor" text="Instructor Lead" selected></d2l-filter-dimension-set-value>
129
+ </d2l-filter-dimension-set>
130
+ </d2l-filter>
131
+ <d2l-filter id="filter5">
132
+ <d2l-filter-dimension-set key="language" text="Language" selection-single>
133
+ <d2l-filter-dimension-set-value key="english" text="English"></d2l-filter-dimension-set-value>
134
+ <d2l-filter-dimension-set-value key="french" text="French"></d2l-filter-dimension-set-value>
135
+ <d2l-filter-dimension-set-value key="spanish" text="Spanish"></d2l-filter-dimension-set-value>
136
+ </d2l-filter-dimension-set>
137
+ </d2l-filter>
138
+ <d2l-filter id="filter6">
139
+ <d2l-filter-dimension-set key="course" text="Course" select-all>
140
+ <d2l-filter-dimension-set-value key="art" text="Art"></d2l-filter-dimension-set-value>
141
+ <d2l-filter-dimension-set-value key="astronomy" text="Astronomy" selected></d2l-filter-dimension-set-value>
142
+ <d2l-filter-dimension-set-value key="biology" text="Biology"></d2l-filter-dimension-set-value>
143
+ <d2l-filter-dimension-set-value key="chemistry" text="Chemistry"></d2l-filter-dimension-set-value>
144
+ <d2l-filter-dimension-set-value key="drama" text="Drama"></d2l-filter-dimension-set-value>
145
+ <d2l-filter-dimension-set-value key="english" text="English"></d2l-filter-dimension-set-value>
146
+ <d2l-filter-dimension-set-value key="how-to" text="How To Write a How To Article With a Flashy Title"></d2l-filter-dimension-set-value>
147
+ <d2l-filter-dimension-set-value key="math" text="Math"></d2l-filter-dimension-set-value>
148
+ <d2l-filter-dimension-set-value key="physics" text="Physics"></d2l-filter-dimension-set-value>
149
+ <d2l-filter-dimension-set-value key="stats" text="Statistics"></d2l-filter-dimension-set-value>
150
+ <d2l-filter-dimension-set-value key="writerscraft" text="Writer's Craft"></d2l-filter-dimension-set-value>
151
+ </d2l-filter-dimension-set>
152
+ <d2l-filter-dimension-set key="duration" text="Duration">
153
+ <d2l-filter-dimension-set-value key="lessthanthree" text="< 3 months"></d2l-filter-dimension-set-value>
154
+ <d2l-filter-dimension-set-value key="threetosix" text="3-6 months"></d2l-filter-dimension-set-value>
155
+ <d2l-filter-dimension-set-value key="sixtotwelve" text="6-12 months"></d2l-filter-dimension-set-value>
156
+ </d2l-filter-dimension-set>
157
+ <d2l-filter-dimension-set key="hoursperweek" text="SemesterNested" selection-single>
158
+ <d2l-filter-dimension-set-value key="lessthanfive" text="< 5 hrs/week"></d2l-filter-dimension-set-value>
159
+ <d2l-filter-dimension-set-value key="fivetoten" text="5-10 hrs/week" selected></d2l-filter-dimension-set-value>
160
+ <d2l-filter-dimension-set-value key="tentotwenty" text="10-20 hrs/week"></d2l-filter-dimension-set-value>
161
+ </d2l-filter-dimension-set>
162
+ </d2l-filter-overflow-group>
163
+ <d2l-filter-tags filter-ids="filter1 filter2 filter3 filter4 filter5 filter6" label="Applied Filters:"></d2l-filter-tags>
164
+ </template>
165
+ </d2l-demo-snippet>
166
+ </d2l-demo-page>
167
+ </body>
168
+ </html>
@@ -0,0 +1,65 @@
1
+ import './filter.js';
2
+ import { css, html, LitElement } from 'lit';
3
+ import { OVERFLOW_CLASS, OverflowGroupMixin } from '../overflow-group/overflow-group-mixin.js';
4
+ import { RtlMixin } from '../../mixins/rtl-mixin.js';
5
+
6
+ function createFilterItem(node) {
7
+ const dimensionSets = node.querySelectorAll('d2l-filter-dimension-set');
8
+ const clones = Array.from(dimensionSets).map((set) => set.cloneNode(true));
9
+ return clones;
10
+ }
11
+
12
+ /**
13
+ * A component that can be used to display a group of filters that will be put into an overflow filter when they no longer fit on the first line of their container
14
+ * @slot - d2l-filters to be added to the container
15
+ */
16
+ class FilterOverflowGroup extends OverflowGroupMixin(RtlMixin(LitElement)) {
17
+
18
+ static get styles() {
19
+ return [super.styles, css`
20
+ ::slotted(d2l-filter) {
21
+ margin-right: 0.3rem;
22
+ }
23
+ :host([dir="rtl"]) ::slotted(d2l-filter) {
24
+ margin-left: 0.3rem;
25
+ margin-right: 0;
26
+ }
27
+ `];
28
+ }
29
+
30
+ firstUpdated(changedProperties) {
31
+ super.firstUpdated(changedProperties);
32
+
33
+ this.addEventListener('d2l-filter-change', this._handleFilterChange);
34
+ }
35
+
36
+ convertToOverflowItem(node) {
37
+ const tagName = node.tagName.toLowerCase();
38
+ if (tagName !== 'd2l-filter') console.warn(`d2l-filter-overflow-group: ${tagName} is invalid in this group. This group should only contain d2l-filter direct child elements.`);
39
+ else return createFilterItem(node);
40
+ }
41
+
42
+ getOverflowContainer(overflowItems) {
43
+ return html`
44
+ <d2l-filter class="${OVERFLOW_CLASS}" @d2l-filter-change="${this._handleFilterChange}">
45
+ ${overflowItems}
46
+ </d2l-filter>
47
+ `;
48
+ }
49
+
50
+ _handleFilterChange(e) {
51
+ const target = (e.target.classList && e.target.classList.contains(OVERFLOW_CLASS)) ? this : e.target;
52
+ e.detail.dimensions.forEach((dimension) => {
53
+ const filterSet = target.querySelector(`d2l-filter-dimension-set[key=${dimension.dimensionKey}`);
54
+ if (!filterSet) return;
55
+ dimension.changes.forEach((change) => {
56
+ const filterSetValue = filterSet.querySelector(`d2l-filter-dimension-set-value[key=${change.valueKey}]`);
57
+ if (!filterSetValue) return;
58
+ filterSetValue.selected = change.selected;
59
+ });
60
+ });
61
+ }
62
+
63
+ }
64
+
65
+ customElements.define('d2l-filter-overflow-group', FilterOverflowGroup);
@@ -2,6 +2,7 @@ import { css, html, nothing } from 'lit';
2
2
  import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
3
3
  import { offscreenStyles } from '../offscreen/offscreen.js';
4
4
  import ResizeObserver from 'resize-observer-polyfill/dist/ResizeObserver.es.js';
5
+ import { styleMap } from 'lit/directives/style-map.js';
5
6
 
6
7
  export const OVERFLOW_CLASS = 'd2l-overflow-container';
7
8
  export const OVERFLOW_MINI_CLASS = 'd2l-overflow-container-mini';
@@ -28,8 +29,7 @@ export const OverflowGroupMixin = superclass => class extends LocalizeCoreElemen
28
29
  static get properties() {
29
30
  return {
30
31
  /**
31
- * Use predefined classes on slot elements to set min and max slotted items to show
32
- * @type {boolean}
32
+ * @ignore
33
33
  */
34
34
  autoShow: {
35
35
  type: Boolean,
@@ -95,7 +95,9 @@ export const OverflowGroupMixin = superclass => class extends LocalizeCoreElemen
95
95
  this._handleResize = this._handleResize.bind(this);
96
96
  this._resizeObserver = new ResizeObserver((entries) => requestAnimationFrame(() => this._handleResize(entries)));
97
97
 
98
+ this._hasResized = false;
98
99
  this._isObserving = false;
100
+ this._itemHeight = 0;
99
101
  this._mini = this.openerType === OPENER_TYPE.ICON;
100
102
  this._overflowContainerHidden = false;
101
103
  this._slotItems = [];
@@ -129,8 +131,13 @@ export const OverflowGroupMixin = superclass => class extends LocalizeCoreElemen
129
131
  }
130
132
  });
131
133
 
134
+ const containerStyles = {
135
+ minHeight: this.autoShow ? 'none' : `${this._itemHeight}px`,
136
+ maxHeight: this.autoShow ? 'none' : `${this._itemHeight}px`
137
+ };
138
+
132
139
  return html`
133
- <div class="d2l-overflow-group-container">
140
+ <div class="d2l-overflow-group-container" style="${styleMap(containerStyles)}">
134
141
  <slot @slotchange="${this._handleSlotChange}"></slot>
135
142
  ${overflowContainer}
136
143
  </div>
@@ -163,6 +170,14 @@ export const OverflowGroupMixin = superclass => class extends LocalizeCoreElemen
163
170
  }
164
171
  }
165
172
 
173
+ convertToOverflowItem() {
174
+ throw new Error('OverflowGroupMixin.convertToOverflowItem must be overridden');
175
+ }
176
+
177
+ getOverflowContainer() {
178
+ throw new Error('OverflowGroupMixin.getOverflowContainer must be overridden');
179
+ }
180
+
166
181
  _autoDetectBoundaries(items) {
167
182
  if (!items) return;
168
183
 
@@ -196,6 +211,7 @@ export const OverflowGroupMixin = superclass => class extends LocalizeCoreElemen
196
211
  } else if (this._overflowContainer) {
197
212
  this._overflowContainerWidth = this._overflowContainer.offsetWidth;
198
213
  }
214
+ this._overflowContainerWidth = this._overflowContainerWidth || 0;
199
215
 
200
216
  const showing = {
201
217
  count: 0,
@@ -268,12 +284,15 @@ export const OverflowGroupMixin = superclass => class extends LocalizeCoreElemen
268
284
 
269
285
  _getItemLayouts(filteredNodes) {
270
286
  const items = filteredNodes.map((node) => {
287
+ node.removeAttribute('data-is-chomped');
271
288
  const computedStyles = window.getComputedStyle(node);
289
+ const itemHidden = computedStyles.display === 'none';
290
+ this._itemHeight = !itemHidden ? Math.max(this._itemHeight, Math.ceil(parseFloat(computedStyles.height))) : this._itemHeight;
272
291
 
273
292
  return {
274
293
  type: node.tagName.toLowerCase(),
275
294
  isChomped: false,
276
- isHidden: computedStyles.display === 'none',
295
+ isHidden: itemHidden,
277
296
  width: Math.ceil(parseFloat(computedStyles.width) || 0)
278
297
  + parseInt(computedStyles.marginRight) || 0
279
298
  + parseInt(computedStyles.marginLeft) || 0,
@@ -307,20 +326,44 @@ export const OverflowGroupMixin = superclass => class extends LocalizeCoreElemen
307
326
  if (!mutations || mutations.length === 0) return;
308
327
  if (this._updateOverflowItemsRequested) return;
309
328
 
329
+ let isWidthModifyingMutation = false;
330
+ for (const mutation of mutations) {
331
+ if (mutation.attributeName
332
+ && (mutation.attributeName === 'selected' || mutation.attributeName === 'text')
333
+ ) {
334
+ isWidthModifyingMutation = true;
335
+ break;
336
+ }
337
+ }
338
+
310
339
  this._updateOverflowItemsRequested = true;
311
340
  setTimeout(() => {
312
- this._overflowItems = this._slotItems.map(node => this.convertToOverflowItem(node));
341
+ this._overflowItems = this._slotItems.map((node) => this.convertToOverflowItem(node));
342
+
343
+ // when certain attributes change the corresponding item width can also change and so we need to re-get the layouts and chomp
344
+ if (isWidthModifyingMutation) {
345
+ this._itemLayouts = this._getItemLayouts(this._slotItems);
346
+ this._chomp();
347
+ }
313
348
  this._updateOverflowItemsRequested = false;
314
349
  this.requestUpdate();
315
350
  }, 0);
316
351
  }
317
352
 
318
- _handleResize(entries) {
353
+ async _handleResize(entries) {
354
+ await (document.fonts ? document.fonts.ready : Promise.resolve()); // computed widths can be incorrect if we don't wait for fonts to load
319
355
  this._availableWidth = Math.ceil(entries[0].contentRect.width);
320
- this._chomp();
356
+
357
+ if (!this._hasResized) {
358
+ this._hasResized = true;
359
+ await this._handleSlotChange();
360
+ } else {
361
+ this._chomp();
362
+ }
321
363
  }
322
364
 
323
365
  _handleSlotChange() {
366
+ if (!this._hasResized) return;
324
367
  requestAnimationFrame(async() => {
325
368
  await this._getItems();
326
369
 
@@ -56,6 +56,7 @@ function createMenuItemSeparator() {
56
56
  * A component that can be used to display a set of buttons, links or menus that will be put into a dropdown menu when they no longer fit on the first line of their container
57
57
  * @slot - Buttons, dropdown buttons, links or other items to be added to the container
58
58
  * @attr {'default'|'icon'} [opener-type="default"] - Set the opener type to 'icon' for a `...` menu icon instead of `More actions` text
59
+ * @attr {boolean} auto-show - Use predefined classes on slot elements to set min and max buttons to show
59
60
  */
60
61
  class OverflowGroup extends OverflowGroupMixin(RtlMixin(LitElement)) {
61
62
 
@@ -3359,6 +3359,63 @@
3359
3359
  }
3360
3360
  ]
3361
3361
  },
3362
+ {
3363
+ "name": "d2l-filter-overflow-group",
3364
+ "path": "./components/filter/filter-overflow-group.js",
3365
+ "description": "A component that can be used to display a group of filters that will be put into an overflow filter when they no longer fit on the first line of their container",
3366
+ "attributes": [
3367
+ {
3368
+ "name": "max-to-show",
3369
+ "description": "maximum amount of slotted items to show",
3370
+ "type": "number",
3371
+ "default": "-1"
3372
+ },
3373
+ {
3374
+ "name": "min-to-show",
3375
+ "description": "minimum amount of slotted items to show",
3376
+ "type": "number",
3377
+ "default": "1"
3378
+ }
3379
+ ],
3380
+ "properties": [
3381
+ {
3382
+ "name": "autoShow",
3383
+ "type": "boolean",
3384
+ "default": "false"
3385
+ },
3386
+ {
3387
+ "name": "maxToShow",
3388
+ "attribute": "max-to-show",
3389
+ "description": "maximum amount of slotted items to show",
3390
+ "type": "number",
3391
+ "default": "-1"
3392
+ },
3393
+ {
3394
+ "name": "minToShow",
3395
+ "attribute": "min-to-show",
3396
+ "description": "minimum amount of slotted items to show",
3397
+ "type": "number",
3398
+ "default": "1"
3399
+ },
3400
+ {
3401
+ "name": "openerType",
3402
+ "type": "string",
3403
+ "default": "\"DEFAULT\""
3404
+ }
3405
+ ],
3406
+ "events": [
3407
+ {
3408
+ "name": "d2l-overflow-group-updated",
3409
+ "description": "Dispatched when there is an update performed to the overflow group"
3410
+ }
3411
+ ],
3412
+ "slots": [
3413
+ {
3414
+ "name": "",
3415
+ "description": "d2l-filters to be added to the container"
3416
+ }
3417
+ ]
3418
+ },
3362
3419
  {
3363
3420
  "name": "d2l-filter-tags",
3364
3421
  "path": "./components/filter/filter-tags.js",
@@ -8766,12 +8823,6 @@
8766
8823
  "type": "'default'|'subtle'",
8767
8824
  "default": "\"\\\"default\\\"\""
8768
8825
  },
8769
- {
8770
- "name": "auto-show",
8771
- "description": "Use predefined classes on slot elements to set min and max slotted items to show",
8772
- "type": "boolean",
8773
- "default": "false"
8774
- },
8775
8826
  {
8776
8827
  "name": "max-to-show",
8777
8828
  "description": "maximum amount of slotted items to show",
@@ -8789,6 +8840,11 @@
8789
8840
  "description": "Set the opener type to 'icon' for a `...` menu icon instead of `More actions` text",
8790
8841
  "type": "'default'|'icon'",
8791
8842
  "default": "\"default\""
8843
+ },
8844
+ {
8845
+ "name": "auto-show",
8846
+ "description": "Use predefined classes on slot elements to set min and max buttons to show",
8847
+ "type": "boolean"
8792
8848
  }
8793
8849
  ],
8794
8850
  "properties": [
@@ -8801,8 +8857,6 @@
8801
8857
  },
8802
8858
  {
8803
8859
  "name": "autoShow",
8804
- "attribute": "auto-show",
8805
- "description": "Use predefined classes on slot elements to set min and max slotted items to show",
8806
8860
  "type": "boolean",
8807
8861
  "default": "false"
8808
8862
  },
package/helpers/README.md CHANGED
@@ -107,6 +107,10 @@ isComposedAncestor(ancestorNode, node);
107
107
 
108
108
  // returns true/false whether the element is visible regardless of positioning
109
109
  isVisible(node);
110
+
111
+ // similar to document.querySelector or element.querySelector,
112
+ // except it queries not just the light DOM but also shadow DOM
113
+ querySelectorComposed(node, selector)
110
114
  ```
111
115
 
112
116
  ## Focus
package/helpers/dom.js CHANGED
@@ -227,3 +227,26 @@ export function isVisible(node) {
227
227
  return true;
228
228
 
229
229
  }
230
+
231
+ export function querySelectorComposed(node, selector) {
232
+
233
+ if (!node || (node.nodeType !== 1 && node.nodeType !== 9 && node.nodeType !== 11)) {
234
+ throw new TypeError('Invalid node. Must be nodeType document, element or document fragment');
235
+ }
236
+ if (typeof selector !== 'string') {
237
+ throw new TypeError('Invalid selector');
238
+ }
239
+
240
+ const elem = node.querySelector(selector);
241
+ if (elem) return elem;
242
+
243
+ const allElems = node.querySelectorAll('*');
244
+ for (const elem of allElems) {
245
+ if (elem.shadowRoot) {
246
+ const nestedElem = querySelectorComposed(elem.shadowRoot, selector);
247
+ if (nestedElem) return nestedElem;
248
+ }
249
+ }
250
+
251
+ return null;
252
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "2.39.1",
3
+ "version": "2.42.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",