@brightspace-ui/core 2.98.5 → 2.99.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.
@@ -36,10 +36,10 @@ class FilterTags extends LocalizeCoreElement(LitElement) {
36
36
  super();
37
37
 
38
38
  this._allActiveFilters = new Map();
39
- this._filters = new IdSubscriberController(this,
40
- { onUnsubscribe: this._removeLostFilter.bind(this) },
41
- { idPropertyName: 'filterIds' }
42
- );
39
+ this._filters = new IdSubscriberController(this, 'active-filters', {
40
+ idPropertyName: 'filterIds',
41
+ onUnsubscribe: this._removeLostFilter.bind(this)
42
+ });
43
43
  }
44
44
 
45
45
  render() {
@@ -136,7 +136,7 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
136
136
  line-height: unset;
137
137
  overflow: hidden;
138
138
  }
139
-
139
+
140
140
  .d2l-filter-dimension-set-value-text {
141
141
  -webkit-box-orient: vertical;
142
142
  display: -webkit-box;
@@ -191,10 +191,10 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
191
191
  this._totalAppliedCount = 0;
192
192
 
193
193
  this._activeFilters = null;
194
- this._activeFiltersSubscribers = new SubscriberRegistryController(this,
195
- { onSubscribe: this._updateActiveFiltersSubscriber.bind(this), updateSubscribers: this._updateActiveFiltersSubscribers.bind(this) },
196
- {}
197
- );
194
+ this._activeFiltersSubscribers = new SubscriberRegistryController(this, 'active-filters', {
195
+ onSubscribe: this._updateActiveFiltersSubscriber.bind(this),
196
+ updateSubscribers: this._updateActiveFiltersSubscribers.bind(this)
197
+ });
198
198
  }
199
199
 
200
200
  static get focusElementSelector() {
@@ -268,10 +268,6 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
268
268
  `;
269
269
  }
270
270
 
271
- getSubscriberController() {
272
- return this._activeFiltersSubscribers;
273
- }
274
-
275
271
  requestFilterClearAll() {
276
272
  this._handleClearAll();
277
273
  }
@@ -24,10 +24,13 @@
24
24
  <h2>Checkbox with multi-line label</h2>
25
25
  <d2l-demo-snippet>
26
26
  <template>
27
- <d2l-input-checkbox style="width: 200px;">
27
+ <d2l-input-checkbox style="overflow: hidden; width: 200px;">
28
28
  Label for checkbox that wraps nicely onto
29
29
  multiple lines and stays aligned
30
30
  </d2l-input-checkbox>
31
+ <d2l-input-checkbox style="overflow: hidden; width: 200px;">
32
+ https://en.wikipedia.org/wiki/Dark_matter
33
+ </d2l-input-checkbox>
31
34
  </template>
32
35
  </d2l-demo-snippet>
33
36
 
@@ -9,6 +9,7 @@ class TestInputRadioLabel extends RtlMixin(LitElement) {
9
9
  css`
10
10
  :host {
11
11
  display: block;
12
+ overflow: hidden;
12
13
  width: 200px;
13
14
  }
14
15
  `
@@ -34,6 +35,10 @@ class TestInputRadioLabel extends RtlMixin(LitElement) {
34
35
  Label for radio that wraps nicely onto
35
36
  multiple lines and stays aligned
36
37
  </label>
38
+ <label class="d2l-input-radio-label">
39
+ <input type="radio" name="myGroup" value="long">
40
+ https://en.wikipedia.org/wiki/Dark_matter
41
+ </label>
37
42
  `;
38
43
  }
39
44
 
@@ -120,8 +120,8 @@ class InputCheckbox extends FocusMixin(SkeletonMixin(RtlMixin(LitElement))) {
120
120
  margin-bottom: 0;
121
121
  }
122
122
  label {
123
- display: inline-block;
124
- white-space: nowrap;
123
+ display: flex;
124
+ overflow-wrap: anywhere;
125
125
  }
126
126
  .d2l-input-checkbox-wrapper {
127
127
  display: inline-block;
@@ -60,6 +60,7 @@ export const radioStyles = css`
60
60
  font-weight: 400;
61
61
  line-height: 1.2rem;
62
62
  margin-bottom: 0.9rem;
63
+ overflow-wrap: anywhere;
63
64
  padding-left: 1.7rem;
64
65
  padding-right: 0;
65
66
  vertical-align: middle;
@@ -76,7 +76,7 @@ export const ListItemExpandCollapseMixin = superclass => class extends superclas
76
76
  this._siblingHasNestedItems = false;
77
77
  this._renderExpandCollapseSlot = false;
78
78
  this._showNestedLoadingSpinner = false;
79
- this._parentChildUpdateSubscription = new EventSubscriberController(this, {}, { eventName: 'd2l-list-child-status' });
79
+ this._parentChildUpdateSubscription = new EventSubscriberController(this, 'list-child-status');
80
80
  }
81
81
 
82
82
  connectedCallback() {
@@ -69,11 +69,10 @@ class List extends PageableMixin(SelectionMixin(LitElement)) {
69
69
  this._listItemChanges = [];
70
70
  this._childHasExpandCollapseToggle = false;
71
71
 
72
- this._listChildrenUpdatedSubscribers = new SubscriberRegistryController(
73
- this,
74
- { onSubscribe: this._updateActiveSubscriber.bind(this), updateSubscribers: this._updateActiveSubscribers.bind(this) },
75
- { eventName: 'd2l-list-child-status' }
76
- );
72
+ this._listChildrenUpdatedSubscribers = new SubscriberRegistryController(this, 'list-child-status', {
73
+ onSubscribe: this._updateActiveSubscriber.bind(this),
74
+ updateSubscribers: this._updateActiveSubscribers.bind(this)
75
+ });
77
76
  }
78
77
 
79
78
  connectedCallback() {
@@ -185,10 +184,6 @@ class List extends PageableMixin(SelectionMixin(LitElement)) {
185
184
  return new SelectionInfo(keys, selectionInfo.state);
186
185
  }
187
186
 
188
- getSubscriberController() {
189
- return this._listChildrenUpdatedSubscribers;
190
- }
191
-
192
187
  _getItemByIndex(index) {
193
188
  const items = this.getItems();
194
189
  if (index > items.length - 1) return;
@@ -12,29 +12,19 @@ import { SubscriberRegistryController } from '@brightspace-ui/core/controllers/s
12
12
  class CableSubscription extends LitElement {
13
13
  constructor() {
14
14
  super();
15
- this._sportsSubscribers = new SubscriberRegistryController(this,
16
- { onSubscribe: this._unlockSportsChannels.bind(this) },
17
- { eventName: 'd2l-channels-subscribe-sports' }
18
- );
19
-
20
- this._movieSubscribers = new SubscriberRegistryController(this, {},
21
- { onSubscribe: this._unlockMovieChannels.bind(this), updateSubscribers: this._sendMovieGuide.bind(this) },
22
- { eventName: 'd2l-channels-subscribe-movies' }
23
- );
24
-
25
- // This controller only supports registering by id - no event is needed
26
- this._kidsChannelSubscribers = new SubscriberRegistryController(this,
27
- { onSubscribe: this._unlockKidsChannels.bind(this) }, {});
28
- }
29
15
 
30
- getSubscriberController(controllerId) {
31
- if (controllerId === 'sports') {
32
- return this._sportsSubscribers;
33
- } else if (controllerId === 'movies') {
34
- return this._movieSubscribers;
35
- } else if (controllerId === 'kids') {
36
- return this._kidsChannelSubscribers;
16
+ this._sportsSubscribers = new SubscriberRegistryController(this, 'channels-sports', {
17
+ onSubscribe: this._unlockSportsChannels.bind(this)
18
+ });
19
+
20
+ this._movieSubscribers = new SubscriberRegistryController(this, 'channels-movies', {
21
+ onSubscribe: this._unlockMovieChannels.bind(this),
22
+ updateSubscribers: this._sendMovieGuide.bind(this)
37
23
  }
24
+
25
+ this._kidsChannelSubscribers = new SubscriberRegistryController(this, 'channels-kids', {
26
+ onSubscribe: this._unlockKidsChannels.bind(this)
27
+ });
38
28
  }
39
29
 
40
30
  _sendMovieGuide(subscribers) {
@@ -49,15 +39,13 @@ class CableSubscription extends LitElement {
49
39
  }
50
40
  ```
51
41
 
52
- When creating the controller, you can pass in callbacks to run whenever a subscriber is added, removed, or `updateSubscribers` is called (which handles request debouncing for you).
53
-
54
- The `*subscriberController`s will use a `getSubscriberController` method that needs to be exposed on the registry component. If you only have one `SubscriberRegistryController` you can simple return that. If you have multiple, you will return the proper controller depending on the id the subscriber component passed to you.
42
+ When creating the controller, you must provide a unique name for the subscription (e.g. `'channels-sports'`). You may also pass in an optional `updateSubscribers` callback (invoked by calling `.updateSubscribers` on the controller, with built-in debouncing), and lifecycle callbacks to run whenever a subscriber is added (`onSubscribe`) or removed (`onUnsubscribe`).
55
43
 
56
44
  Once this has been set up, components can subscribe to particular registries two different ways:
57
- 1. Using a matching event name with `EventSubscriberController`. The component will need to be a child of the registry component for this to work.
58
- 2. By pointing to the registry component's id with `IdSubscriberController`. The component will need to be in the same DOM scope as the registry component for this to work.
45
+ 1. Using `EventSubscriberController` with the target subscription name. The component will need to be a child of the registry component for this to work.
46
+ 2. Using `IdSubscriberController` with the target subscription name and the `idPropertyName` option, which will point to the registry component's id. The component will need to be in the same DOM scope as the registry component for this to work.
59
47
 
60
- Like the `SubscriberRegistryController`, these `*subscriberController`s take optional callbacks to throw at different points in the subscription process.
48
+ Like the `SubscriberRegistryController`, these `*subscriberController`s take optional callbacks invoked at different points in the subscription process.
61
49
 
62
50
  ```js
63
51
  import { EventSubscriberController, IdSubscriberController } from '@brightspace-ui/core/controllers/subscriber/subscriberControllers.js';
@@ -72,15 +60,12 @@ class GeneralViewer extends LitElement {
72
60
  constructor() {
73
61
  super();
74
62
  this._subscribedChannels = new Set();
75
-
76
- this._sportsSubscription = new EventSubscriberController(this,
77
- { onError: this._onSportsError.bind(this) }
78
- { eventName: 'd2l-channels-subscribe-sports', controllerId: 'sports' }
79
- );
80
-
81
- this._movieSubscription = new EventSubscriberController(this, {},
82
- { eventName: 'd2l-channels-subscribe-movies', controllerId: 'movies' }
83
- );
63
+
64
+ this._sportsSubscription = new EventSubscriberController(this, 'channels-sports', {
65
+ onError: this._onSportsError.bind(this)
66
+ }
67
+
68
+ this._movieSubscription = new EventSubscriberController(this, 'channels-movies');
84
69
  }
85
70
 
86
71
  addChannels(channels) {
@@ -106,10 +91,11 @@ class YoungerViewer extends LitElement {
106
91
  super();
107
92
  this._subscribedChannels = new Set();
108
93
 
109
- this._kidsSubscription = new IdSubscriberController(this,
110
- { onSubscribe: this._onSubscribe.bind(this), onUnsubscribe: this._onUnsubscribe.bind(this) },
111
- { idPropertyName: 'for', controllerId: 'kids' }
112
- );
94
+ this._kidsSubscription = new IdSubscriberController(this, 'channels-kids', {
95
+ idPropertyName: 'for',
96
+ onSubscribe: this._onSubscribe.bind(this),
97
+ onUnsubscribe: this._onUnsubscribe.bind(this)
98
+ });
113
99
  }
114
100
 
115
101
  addChannels(channels) {
@@ -129,6 +115,7 @@ class YoungerViewer extends LitElement {
129
115
  ```
130
116
 
131
117
  An example of what this could look like altogether:
118
+
132
119
  ```html
133
120
  <cable-subscription id="rogers">
134
121
  <general-viewer></general-viewer>
@@ -136,13 +123,12 @@ An example of what this could look like altogether:
136
123
  <younger-viewer for="rogers"></younger-viewer>
137
124
  ```
138
125
 
139
- As of the Lit 2 upgrade, the lifecycle methods `hostConnected`, `hostDisconnected`, and `hostUpdated` will be called automatically.
140
126
  ## Available Callbacks
141
127
 
142
128
  ### SubscriberRegistryController
143
129
  | Callback Name | Description | Passed to Callback |
144
130
  |---|---|---|
145
- | `onSubscribe` | Runs whenever a new subscriber is added | Subscriber that was just subscribed |
131
+ | `onSubscribe` | Runs whenever a new subscriber is added | Subscriber that was just subscribed |
146
132
  | `onUnsubscribe` | Runs whenever a subscriber is removed | Subscriber that was just unsubscribed |
147
133
  | `updateSubscribers` | Runs whenever `updateSubscribers` is called on the controller, handles debouncing requests for you | Map of all current subscribers |
148
134
 
@@ -1,14 +1,52 @@
1
1
  import { cssEscape } from '../../helpers/dom.js';
2
2
 
3
- export class SubscriberRegistryController {
3
+ class BaseController {
4
+ constructor(host, name, options = {}) {
5
+ if (!host || !name) throw new TypeError('SubscriberController: missing host or subscription name');
4
6
 
5
- constructor(host, callbacks, options) {
6
- this._host = host;
7
7
  host.addController(this);
8
- this._callbacks = callbacks || {};
9
- this._eventName = options && options.eventName;
10
- this._subscribers = new Map();
8
+ this._host = host;
9
+ this._name = name;
10
+ this._options = options;
11
+ this._eventName = `d2l-subscribe-${this._name}`;
12
+ }
13
+ }
14
+
15
+ class BaseSubscriber extends BaseController {
16
+ _subscribe(target = this._host, targetLabel) {
17
+ const isBroadcast = target === this._host;
18
+
19
+ const options = isBroadcast ? { bubbles: true, composed: true } : {};
20
+ const evt = new CustomEvent(this._eventName, {
21
+ ...options,
22
+ detail: { subscriber: this._host }
23
+ });
24
+ target.dispatchEvent(evt);
25
+
26
+ const { registry, registryController } = evt.detail;
27
+ if (!registry) {
28
+ if (this._options.onError) this._options.onError();
29
+ return;
30
+ }
31
+
32
+ if (targetLabel) {
33
+ this._registries.set(targetLabel, registry);
34
+ this._registryControllers.set(targetLabel, registryController);
35
+ } else {
36
+ this._registry = registry;
37
+ this._registryController = registryController;
38
+ }
39
+
40
+ if (this._options.onSubscribe) this._options.onSubscribe(registry);
41
+ }
42
+ }
43
+
44
+ export class SubscriberRegistryController extends BaseController {
45
+
46
+ constructor(host, name, options) {
47
+ super(host, name, options);
11
48
 
49
+ this._subscribers = new Map();
12
50
  this._handleSubscribe = this._handleSubscribe.bind(this);
13
51
  }
14
52
 
@@ -27,24 +65,24 @@ export class SubscriberRegistryController {
27
65
  subscribe(target) {
28
66
  if (this._subscribers.has(target)) return;
29
67
  this._subscribers.set(target, target);
30
- if (this._callbacks.onSubscribe) this._callbacks.onSubscribe(target);
68
+ if (this._options.onSubscribe) this._options.onSubscribe(target);
31
69
  }
32
70
 
33
71
  unsubscribe(target) {
34
72
  this._subscribers.delete(target);
35
- if (this._callbacks.onUnsubscribe) this._callbacks.onUnsubscribe(target);
73
+ if (this._options.onUnsubscribe) this._options.onUnsubscribe(target);
36
74
  }
37
75
 
38
76
  updateSubscribers() {
39
77
  if (!this._subscribers || this._subscribers.size === 0) return;
40
- if (!this._callbacks.updateSubscribers) return;
78
+ if (!this._options.updateSubscribers) return;
41
79
 
42
80
  // debounce the updates
43
81
  if (this._updateSubscribersRequested) return;
44
82
 
45
83
  this._updateSubscribersRequested = true;
46
84
  setTimeout(() => {
47
- this._callbacks.updateSubscribers(this._subscribers);
85
+ this._options.updateSubscribers(this._subscribers);
48
86
  this._updateSubscribersRequested = false;
49
87
  }, 0);
50
88
  }
@@ -52,20 +90,19 @@ export class SubscriberRegistryController {
52
90
  _handleSubscribe(e) {
53
91
  e.stopPropagation();
54
92
  e.detail.registry = this._host;
55
- const target = e.composedPath()[0];
93
+ e.detail.registryController = this;
94
+ const target = e.detail.subscriber;
56
95
  this.subscribe(target);
57
96
  }
58
97
  }
59
98
 
60
- export class EventSubscriberController {
99
+ export class EventSubscriberController extends BaseSubscriber {
100
+
101
+ constructor(host, name, options) {
102
+ super(host, name, options);
61
103
 
62
- constructor(host, callbacks, options) {
63
- this._host = host;
64
- host.addController(this);
65
- this._callbacks = callbacks || {};
66
- this._eventName = options && options.eventName;
67
- this._controllerId = options && options.controllerId;
68
104
  this._registry = null;
105
+ this._registryController = null;
69
106
  }
70
107
 
71
108
  get registry() {
@@ -74,39 +111,24 @@ export class EventSubscriberController {
74
111
 
75
112
  hostConnected() {
76
113
  // delay subscription otherwise import/upgrade order can cause selection mixin to miss event
77
- requestAnimationFrame(() => {
78
- const evt = new CustomEvent(this._eventName, {
79
- bubbles: true,
80
- composed: true,
81
- detail: {}
82
- });
83
- this._host.dispatchEvent(evt);
84
- this._registry = evt.detail.registry;
85
-
86
- if (!this._registry) {
87
- if (this._callbacks.onError) this._callbacks.onError();
88
- return;
89
- }
90
- if (this._callbacks.onSubscribe) this._callbacks.onSubscribe(this._registry);
91
- });
114
+ requestAnimationFrame(() => this._subscribe());
92
115
  }
93
116
 
94
117
  hostDisconnected() {
95
- if (this._registry) this._registry.getSubscriberController(this._controllerId).unsubscribe(this._host);
118
+ if (this._registryController) this._registryController.unsubscribe(this._host);
96
119
  }
97
120
 
98
121
  }
99
122
 
100
- export class IdSubscriberController {
123
+ export class IdSubscriberController extends BaseSubscriber {
124
+
125
+ constructor(host, name, options) {
126
+ super(host, name, options);
101
127
 
102
- constructor(host, callbacks, options) {
103
- this._host = host;
104
- host.addController(this);
105
- this._callbacks = callbacks || {};
106
128
  this._idPropertyName = options && options.idPropertyName;
107
129
  this._idPropertyValue = this._idPropertyName ? this._host[this._idPropertyName] : undefined;
108
- this._controllerId = options && options.controllerId;
109
130
  this._registries = new Map();
131
+ this._registryControllers = new Map();
110
132
  this._timeouts = new Set();
111
133
  }
112
134
 
@@ -117,8 +139,8 @@ export class IdSubscriberController {
117
139
  hostDisconnected() {
118
140
  if (this._registryObserver) this._registryObserver.disconnect();
119
141
  this._timeouts.forEach(timeoutId => clearTimeout(timeoutId));
120
- this._registries.forEach(registry => {
121
- registry.getSubscriberController(this._controllerId).unsubscribe(this._host);
142
+ this._registryControllers.forEach(controller => {
143
+ controller.unsubscribe(this._host);
122
144
  });
123
145
  }
124
146
 
@@ -129,11 +151,12 @@ export class IdSubscriberController {
129
151
  this._idPropertyValue = propertyValue;
130
152
 
131
153
  if (this._registryObserver) this._registryObserver.disconnect();
132
- this._registries.forEach(registry => {
133
- registry.getSubscriberController(this._controllerId).unsubscribe(this._host);
134
- if (this._callbacks.onUnsubscribe) this._callbacks.onUnsubscribe(registry.id);
154
+ this._registryControllers.forEach((controller, key) => {
155
+ controller.unsubscribe(this._host);
156
+ if (this._options.onUnsubscribe) this._options.onUnsubscribe(key);
135
157
  });
136
158
  this._registries = new Map();
159
+ this._registryControllers = new Map();
137
160
 
138
161
  this._updateRegistries();
139
162
 
@@ -159,7 +182,7 @@ export class IdSubscriberController {
159
182
 
160
183
  _updateRegistry(registryId, elapsedTime) {
161
184
  let registryComponent = this._host.getRootNode().querySelector(`#${cssEscape(registryId)}`);
162
- if (!registryComponent && this._callbacks.onError) {
185
+ if (!registryComponent && this._options.onError) {
163
186
  if (elapsedTime < 3000) {
164
187
  const timeoutId = setTimeout(() => {
165
188
  this._timeouts.delete(timeoutId);
@@ -167,20 +190,18 @@ export class IdSubscriberController {
167
190
  }, 100);
168
191
  this._timeouts.add(timeoutId);
169
192
  } else {
170
- this._callbacks.onError(registryId);
193
+ this._options.onError(registryId);
171
194
  }
172
195
  }
173
196
 
174
197
  registryComponent = registryComponent || undefined;
175
198
  if (this._registries.get(registryId) === registryComponent) return;
176
199
 
177
- if (registryComponent) {
178
- registryComponent.getSubscriberController(this._controllerId).subscribe(this._host);
179
- this._registries.set(registryId, registryComponent);
180
- if (this._callbacks.onSubscribe) this._callbacks.onSubscribe(registryComponent);
181
- } else {
200
+ if (registryComponent) this._subscribe(registryComponent, registryId);
201
+ else {
182
202
  this._registries.delete(registryId);
183
- if (this._callbacks.onUnsubscribe) this._callbacks.onUnsubscribe(registryId);
203
+ this._registryControllers.delete(registryId);
204
+ if (this._options.onUnsubscribe) this._options.onUnsubscribe(registryId);
184
205
  }
185
206
  }
186
207
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "2.98.5",
3
+ "version": "2.99.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",