@brightspace-ui/core 1.239.0 → 1.240.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.
@@ -208,9 +208,9 @@ This component is built to be used alongside the [d2l-filter-dimension-set](#fil
208
208
 
209
209
  **Coming Soon!**
210
210
 
211
- ## Filter Dimension: Tags [d2l-filter-dimension-tags]
211
+ ## Tags for Applied Filters [d2l-filter-tags]
212
212
 
213
- **Coming Soon!**
213
+ **This is in progress now! Stable API expected by May.**
214
214
 
215
215
  <!-- docs: start hidden content -->
216
216
  ## Future Improvements
@@ -118,6 +118,10 @@ export const FormElementMixin = superclass => class extends LocalizeCoreElement(
118
118
  this._validationCustomConnected = this._validationCustomConnected.bind(this);
119
119
  this._onFormElementErrorsChange = this._onFormElementErrorsChange.bind(this);
120
120
 
121
+ this._firstUpdateResolve = null;
122
+ this._firstUpdatePromise = new Promise((resolve) => {
123
+ this._firstUpdateResolve = resolve;
124
+ });
121
125
  this._validationCustoms = new Set();
122
126
  this._validity = new FormElementValidityState({});
123
127
  /** @ignore */
@@ -168,6 +172,11 @@ export const FormElementMixin = superclass => class extends LocalizeCoreElement(
168
172
  this.shadowRoot.removeEventListener('d2l-form-element-errors-change', this._onFormElementErrorsChange);
169
173
  }
170
174
 
175
+ firstUpdated(changedProperties) {
176
+ super.firstUpdated(changedProperties);
177
+ this._firstUpdateResolve();
178
+ }
179
+
171
180
  updated(changedProperties) {
172
181
  if (changedProperties.has('_errors') || changedProperties.has('childErrors')) {
173
182
  let errors = this._errors;
@@ -195,6 +204,11 @@ export const FormElementMixin = superclass => class extends LocalizeCoreElement(
195
204
  if (this.noValidate) {
196
205
  return [];
197
206
  }
207
+
208
+ // validation can be requested before first update, which can cause issues
209
+ // if validation logic depends on rendered DOM
210
+ await this._firstUpdatePromise;
211
+
198
212
  const customs = [...this._validationCustoms].filter(custom => custom.forElement === this || !isCustomFormElement(custom.forElement));
199
213
  const results = await Promise.all(customs.map(custom => custom.validate()));
200
214
  const errors = customs.map(custom => custom.failureText).filter((_, i) => !results[i]);
@@ -26,9 +26,13 @@ export const FormMixin = superclass => class extends LocalizeCoreElement(supercl
26
26
  this._onNativeSubmit = this._onNativeSubmit.bind(this);
27
27
 
28
28
  this.trackChanges = false;
29
+ this._errors = new Map();
30
+ this._firstUpdateResolve = null;
31
+ this._firstUpdatePromise = new Promise((resolve) => {
32
+ this._firstUpdateResolve = resolve;
33
+ });
29
34
  this._tooltips = new Map();
30
35
  this._validationCustoms = new Set();
31
- this._errors = new Map();
32
36
 
33
37
  this.addEventListener('d2l-form-errors-change', this._onErrorsChange);
34
38
  this.addEventListener('d2l-form-element-errors-change', this._onErrorsChange);
@@ -50,6 +54,7 @@ export const FormMixin = superclass => class extends LocalizeCoreElement(supercl
50
54
  this.addEventListener('change', this._onFormElementChange);
51
55
  this.addEventListener('input', this._onFormElementChange);
52
56
  this.addEventListener('focusout', this._onFormElementChange);
57
+ this._firstUpdateResolve();
53
58
  }
54
59
 
55
60
  // eslint-disable-next-line no-unused-vars
@@ -150,6 +155,9 @@ export const FormMixin = superclass => class extends LocalizeCoreElement(supercl
150
155
  }
151
156
 
152
157
  async _validateFormElement(ele, showNewErrors) {
158
+ // if validation occurs before we've rendered,
159
+ // localization may not have loaded yet
160
+ await this._firstUpdatePromise;
153
161
  ele.id = ele.id || getUniqueId();
154
162
  if (isCustomFormElement(ele)) {
155
163
  return ele.validate(showNewErrors);
@@ -149,6 +149,7 @@ export const HierarchicalViewMixin = superclass => class extends superclass {
149
149
  this.__intersectionObserver.disconnect();
150
150
  this.__isAutoSized = false;
151
151
  }
152
+ if (this.__resizeObserver) this.__resizeObserver.disconnect();
152
153
  }
153
154
 
154
155
  firstUpdated(changedProperties) {
@@ -116,16 +116,9 @@ class InputDateTimeRangeTo extends SkeletonMixin(LocalizeCoreElement(LitElement)
116
116
 
117
117
  disconnectedCallback() {
118
118
  super.disconnectedCallback();
119
-
120
119
  this._disconnectObservers();
121
120
  }
122
121
 
123
- firstUpdated(changedProperties) {
124
- super.firstUpdated(changedProperties);
125
-
126
- this._startObserving();
127
- }
128
-
129
122
  render() {
130
123
  const containerClassMap = {
131
124
  'd2l-input-date-time-range-to-container': true,
@@ -181,9 +174,12 @@ class InputDateTimeRangeTo extends SkeletonMixin(LocalizeCoreElement(LitElement)
181
174
  _startObserving() {
182
175
  if (!this.shadowRoot || !this._parentNode) return;
183
176
 
177
+ const container = this.shadowRoot.querySelector('.d2l-input-date-time-range-to-container');
184
178
  const leftElem = this.shadowRoot.querySelector('.d2l-input-date-time-range-start-container');
179
+ let leftElemHeight = 0;
180
+
185
181
  this._leftElemResizeObserver = this._leftElemResizeObserver || new ResizeObserver(() => {
186
- this._leftElemHeight = Math.ceil(parseFloat(getComputedStyle(leftElem).getPropertyValue('height')));
182
+ leftElemHeight = Math.ceil(parseFloat(getComputedStyle(leftElem).getPropertyValue('height')));
187
183
  });
188
184
  this._leftElemResizeObserver.disconnect();
189
185
  this._leftElemResizeObserver.observe(leftElem);
@@ -191,8 +187,8 @@ class InputDateTimeRangeTo extends SkeletonMixin(LocalizeCoreElement(LitElement)
191
187
  this._parentElemResizeObserver = this._parentElemResizeObserver || new ResizeObserver(async() => {
192
188
  this._blockDisplay = false;
193
189
  await this.updateComplete;
194
- const height = Math.ceil(parseFloat(getComputedStyle(this.shadowRoot.querySelector('.d2l-input-date-time-range-to-container')).getPropertyValue('height')));
195
- if (height >= (this._leftElemHeight * 2)) this._blockDisplay = true; // switch to _blockDisplay styles if content has wrapped (needed for "to" to occupy its own line)
190
+ const height = Math.ceil(parseFloat(getComputedStyle(container).getPropertyValue('height')));
191
+ if (height >= (leftElemHeight * 2)) this._blockDisplay = true; // switch to _blockDisplay styles if content has wrapped (needed for "to" to occupy its own line)
196
192
  else this._blockDisplay = false;
197
193
  });
198
194
  this._parentElemResizeObserver.disconnect();
@@ -186,6 +186,12 @@ class InputDate extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(
186
186
  return super.validationMessage;
187
187
  }
188
188
 
189
+ disconnectedCallback() {
190
+ super.disconnectedCallback();
191
+ if (this._hiddenContentResizeObserver) this._hiddenContentResizeObserver.disconnect();
192
+ if (this._hiddenCalendarResizeObserver) this._hiddenCalendarResizeObserver.disconnect();
193
+ }
194
+
189
195
  async firstUpdated(changedProperties) {
190
196
  super.firstUpdated(changedProperties);
191
197
 
@@ -254,6 +254,11 @@ class InputTime extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(
254
254
  this.requestUpdate('value', oldValue);
255
255
  }
256
256
 
257
+ disconnectedCallback() {
258
+ super.disconnectedCallback();
259
+ if (this._hiddenContentResizeObserver) this._hiddenContentResizeObserver.disconnect();
260
+ }
261
+
257
262
  async firstUpdated(changedProperties) {
258
263
  super.firstUpdated(changedProperties);
259
264
 
@@ -97,7 +97,6 @@ export const ListItemCheckboxMixin = superclass => class extends SkeletonMixin(L
97
97
  }
98
98
 
99
99
  setSelected(selected, suppressEvent = false) {
100
- //if (this.selected === selected) return;
101
100
  if (this.selected === selected || (this.selected === undefined && !selected)) return;
102
101
  this.selected = selected;
103
102
  if (!suppressEvent) this._dispatchSelected(selected);
@@ -249,10 +249,15 @@ class OverflowGroup extends RtlMixin(LocalizeCoreElement(LitElement)) {
249
249
  this.openerStyle = OPENER_STYLE.DEFAULT;
250
250
  this.openerType = OPENER_TYPE.DEFAULT;
251
251
  this._mini = this.openerType === OPENER_TYPE.ICON;
252
-
252
+ this._resizeObserver = null;
253
253
  this._slotItems = [];
254
254
  }
255
255
 
256
+ disconnectedCallback() {
257
+ super.disconnectedCallback();
258
+ if (this._resizeObserver) this._resizeObserver.disconnect();
259
+ }
260
+
256
261
  async firstUpdated() {
257
262
  super.firstUpdated();
258
263
 
@@ -261,8 +266,8 @@ class OverflowGroup extends RtlMixin(LocalizeCoreElement(LitElement)) {
261
266
 
262
267
  this._container = this.shadowRoot.querySelector('.d2l-overflow-group-container');
263
268
 
264
- const resizeObserver = new ResizeObserver(this._throttledResize);
265
- resizeObserver.observe(this._container);
269
+ this._resizeObserver = new ResizeObserver(this._throttledResize);
270
+ this._resizeObserver.observe(this._container);
266
271
  }
267
272
 
268
273
  render() {
@@ -37,4 +37,11 @@ The `d2l-scroll-wrapper` element can be used to wrap content which may overflow
37
37
  | Property | Type | Description |
38
38
  |---|---|---|
39
39
  | `hide-actions` | Boolean, default: `false` | Whether to hide left/right scroll buttons |
40
+
41
+ ### Variables
42
+
43
+ | Variable | Type | Description |
44
+ |---|---|---|
45
+ | `--d2l-scroll-wrapper-overflow-y` | [Any valid overflow-y setting](https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-y), defaults to `visible` | Set the `overflow-y` property of the inner scroll wrapper |
46
+
40
47
  <!-- docs: end hidden content -->
@@ -53,11 +53,11 @@ class ScrollWrapper extends FocusVisiblePolyfillMixin(RtlMixin(LitElement)) {
53
53
  :host([hidden]) {
54
54
  display: none;
55
55
  }
56
-
57
56
  .d2l-scroll-wrapper-container {
58
57
  box-sizing: border-box;
59
58
  outline: none;
60
59
  overflow-x: auto;
60
+ overflow-y: var(--d2l-scroll-wrapper-overflow-y, visible);
61
61
  }
62
62
  .d2l-scroll-wrapper-container.focus-visible {
63
63
  box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px var(--d2l-color-celestine), 0 2px 12px 0 rgba(0, 0, 0, 0.15);
@@ -143,14 +143,21 @@ class ScrollWrapper extends FocusVisiblePolyfillMixin(RtlMixin(LitElement)) {
143
143
  this.hideActions = false;
144
144
  this._container = null;
145
145
  this._hScrollbar = true;
146
+ this._resizeObserver = null;
146
147
  this._scrollbarLeft = false;
147
148
  this._scrollbarRight = false;
148
149
  }
149
150
 
151
+ disconnectedCallback() {
152
+ super.disconnectedCallback();
153
+ if (this._resizeObserver) this._resizeObserver.disconnect();
154
+ }
155
+
150
156
  firstUpdated(changedProperties) {
151
157
  super.firstUpdated(changedProperties);
152
158
  this._container = this.shadowRoot.querySelector('.d2l-scroll-wrapper-container');
153
- new ResizeObserver(() => requestAnimationFrame(() => this.checkScrollbar())).observe(this._container);
159
+ this._resizeObserver = new ResizeObserver(() => requestAnimationFrame(() => this.checkScrollbar()));
160
+ this._resizeObserver.observe(this._container);
154
161
  }
155
162
 
156
163
  render() {
@@ -172,8 +179,7 @@ class ScrollWrapper extends FocusVisiblePolyfillMixin(RtlMixin(LitElement)) {
172
179
 
173
180
  checkScrollbar() {
174
181
  if (!this._container) return;
175
- const hScrollbar = Math.abs(this._container.offsetWidth - this._container.scrollWidth);
176
- this._hScrollbar = (hScrollbar > 0);
182
+ this._hScrollbar = this._container.offsetWidth !== this._container.scrollWidth;
177
183
  this._checkScrollThresholds();
178
184
  }
179
185
 
@@ -266,6 +266,11 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
266
266
 
267
267
  }
268
268
 
269
+ disconnectedCallback() {
270
+ super.disconnectedCallback();
271
+ if (this._resizeObserver) this._resizeObserver.disconnect();
272
+ }
273
+
269
274
  firstUpdated(changedProperties) {
270
275
  super.firstUpdated(changedProperties);
271
276
 
@@ -1,74 +1,11 @@
1
- import { LocalizeMixin } from '../mixins/localize-mixin.js';
1
+ import { LocalizeDynamicMixin } from '../mixins/localize-dynamic-mixin.js';
2
2
 
3
- export const LocalizeCoreElement = superclass => class extends LocalizeMixin(superclass) {
3
+ export const LocalizeCoreElement = superclass => class extends LocalizeDynamicMixin(superclass) {
4
4
 
5
- static async getLocalizeResources(langs) {
6
- let translations;
7
- for await (const lang of langs) {
8
- switch (lang) {
9
- case 'ar':
10
- translations = await import('./ar.js');
11
- break;
12
- case 'cy':
13
- translations = await import('./cy.js');
14
- break;
15
- case 'da':
16
- translations = await import('./da.js');
17
- break;
18
- case 'de':
19
- translations = await import('./de.js');
20
- break;
21
- case 'en':
22
- translations = await import('./en.js');
23
- break;
24
- case 'es-es':
25
- translations = await import('./es-es.js');
26
- break;
27
- case 'es':
28
- translations = await import('./es.js');
29
- break;
30
- case 'fr-fr':
31
- translations = await import('./fr-fr.js');
32
- break;
33
- case 'fr':
34
- translations = await import('./fr.js');
35
- break;
36
- case 'ja':
37
- translations = await import('./ja.js');
38
- break;
39
- case 'ko':
40
- translations = await import('./ko.js');
41
- break;
42
- case 'nl':
43
- translations = await import('./nl.js');
44
- break;
45
- case 'pt':
46
- translations = await import('./pt.js');
47
- break;
48
- case 'sv':
49
- translations = await import('./sv.js');
50
- break;
51
- case 'tr':
52
- translations = await import('./tr.js');
53
- break;
54
- case 'zh-tw':
55
- translations = await import('./zh-tw.js');
56
- break;
57
- case 'zh':
58
- translations = await import('./zh.js');
59
- break;
60
- }
61
- if (translations && translations.default) {
62
- return {
63
- language: lang,
64
- resources: translations.default
65
- };
66
- }
67
- }
68
- translations = await import('./en.js');
5
+ static get localizeConfig() {
69
6
  return {
70
- language: 'en',
71
- resources: translations.default
7
+ importFunc: async lang => (await import(`./${lang}.js`)).default
72
8
  };
73
9
  }
10
+
74
11
  };
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "1.239.0",
3
+ "version": "1.240.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",
@@ -903,6 +903,7 @@ class TemplatePrimarySecondary extends FocusVisiblePolyfillMixin(RtlMixin(Locali
903
903
  resizer.disconnect();
904
904
  }
905
905
  this._hasConnectedResizers = false;
906
+ if (this._resizeObserver) this._resizeObserver.disconnect();
906
907
  }
907
908
 
908
909
  firstUpdated(changedProperties) {