@brightspace-ui/core 1.203.0 → 1.206.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.
@@ -38,7 +38,7 @@ The `d2l-button` element can be used just like the native button element, but al
38
38
  ![Button](./screenshots/button.png?raw=true)
39
39
  <!-- docs: end hidden content -->
40
40
 
41
- <!-- docs: demo live name: d2l-button -->
41
+ <!-- docs: demo live name:d2l-button -->
42
42
  ```html
43
43
  <script type="module">
44
44
  import '@brightspace-ui/core/components/button/button.js';
@@ -82,7 +82,6 @@ class Card extends RtlMixin(LitElement) {
82
82
  box-sizing: border-box;
83
83
  display: inline-block;
84
84
  position: relative;
85
- transition: transform 300ms ease-out 50ms, box-shadow 0.2s;
86
85
  z-index: 0;
87
86
  }
88
87
  .d2l-card-container {
@@ -185,10 +184,6 @@ class Card extends RtlMixin(LitElement) {
185
184
  border: none;
186
185
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.03);
187
186
  }
188
- :host(:hover),
189
- :host([subtle]:hover) {
190
- transform: translateY(-4px);
191
- }
192
187
  :host(:hover) {
193
188
  box-shadow: 0 2px 14px 1px rgba(0, 0, 0, 0.06);
194
189
  }
@@ -203,7 +198,6 @@ class Card extends RtlMixin(LitElement) {
203
198
  :host([subtle][_active]:hover) {
204
199
  border-color: transparent;
205
200
  box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px var(--d2l-color-celestine);
206
- transform: translateY(-4px);
207
201
  }
208
202
  /* .d2l-card-link-container-hover is used to only color/underline when
209
203
  hovering the anchor; these styles are not applied when hovering actions */
@@ -225,9 +219,16 @@ class Card extends RtlMixin(LitElement) {
225
219
  box-shadow: none;
226
220
  transform: none;
227
221
  }
228
- @media (prefers-reduced-motion: reduce) {
222
+ @media (prefers-reduced-motion: no-preference) {
229
223
  :host {
230
- transition: none;
224
+ transition: transform 300ms ease-out 50ms, box-shadow 0.2s;
225
+ }
226
+
227
+ :host(:hover),
228
+ :host([subtle]:hover),
229
+ :host([_active]:hover),
230
+ :host([subtle][_active]:hover) {
231
+ transform: translateY(-4px);
231
232
  }
232
233
  }
233
234
  `];
@@ -9,10 +9,8 @@
9
9
  import '../html-block.js';
10
10
  import { provideInstance } from '../../../mixins/provider-mixin.js';
11
11
 
12
- // demo replacement renderer for html-block
13
- provideInstance(document, 'html-block-renderers', [
14
- async elem => {
15
-
12
+ class DemoReplacementRenderer {
13
+ async render(elem) {
16
14
  const elemsToReplace = elem.querySelectorAll('[data-replace-me-id]');
17
15
  if (elemsToReplace.length === 0) return elem;
18
16
 
@@ -32,15 +30,15 @@
32
30
  });
33
31
 
34
32
  return elem;
35
-
36
33
  }
37
- ]);
34
+ }
35
+
36
+ // demo replacement renderer for html-block
37
+ provideInstance(document, 'html-block-renderers', [ new DemoReplacementRenderer() ]);
38
38
 
39
39
  </script>
40
40
  <script>
41
- if (window.location.search.indexOf('latex=true') !== -1) {
42
- document.getElementsByTagName('html')[0].dataset.mathjaxContext = JSON.stringify({ renderLatex: true });
43
- }
41
+ document.getElementsByTagName('html')[0].dataset.mathjaxContext = JSON.stringify({ renderLatex: window.location.search.indexOf('latex=true') !== -1 });
44
42
  </script>
45
43
  </head>
46
44
  <body unresolved>
@@ -1,6 +1,7 @@
1
1
  import '../colors/colors.js';
2
2
  import { css, LitElement } from 'lit-element/lit-element.js';
3
- import { htmlBlockMathRenderer } from '../../helpers/mathjax.js';
3
+ import { HtmlAttributeObserverController } from '../../helpers/htmlAttributeObserverController.js';
4
+ import { HtmlBlockMathRenderer } from '../../helpers/mathjax.js';
4
5
  import { requestInstance } from '../../mixins/provider-mixin.js';
5
6
 
6
7
  export const htmlBlockContentStyles = css`
@@ -106,6 +107,7 @@ let renderers;
106
107
  const getRenderers = () => {
107
108
  if (renderers) return renderers;
108
109
  const tempRenderers = requestInstance(document, 'html-block-renderers');
110
+ const htmlBlockMathRenderer = new HtmlBlockMathRenderer();
109
111
  renderers = (tempRenderers ? [ htmlBlockMathRenderer, ...tempRenderers ] : [ htmlBlockMathRenderer ]);
110
112
  return renderers;
111
113
  };
@@ -135,8 +137,22 @@ class HtmlBlock extends LitElement {
135
137
  `];
136
138
  }
137
139
 
140
+ constructor() {
141
+ super();
142
+
143
+ const rendererContextAttributes = getRenderers().reduce((attrs, currentRenderer) => {
144
+ if (currentRenderer.contextAttributes) currentRenderer.contextAttributes.forEach(attr => attrs.push(attr));
145
+ return attrs;
146
+ }, []);
147
+
148
+ if (rendererContextAttributes.length === 0) return;
149
+ this._contextObserverController = new HtmlAttributeObserverController(this, ...rendererContextAttributes);
150
+ }
151
+
138
152
  connectedCallback() {
139
153
  super.connectedCallback();
154
+ if (this._contextObserverController) this._contextObserverController.hostConnected();
155
+
140
156
  if (!this._templateObserver) return;
141
157
 
142
158
  const template = this.querySelector('template');
@@ -145,6 +161,7 @@ class HtmlBlock extends LitElement {
145
161
 
146
162
  disconnectedCallback() {
147
163
  super.disconnectedCallback();
164
+ if (this._contextObserverController) this._contextObserverController.hostDisconnected();
148
165
  if (this._templateObserver) this._templateObserver.disconnect();
149
166
  }
150
167
 
@@ -155,6 +172,36 @@ class HtmlBlock extends LitElement {
155
172
 
156
173
  this.shadowRoot.innerHTML += '<div class="d2l-html-block-rendered"></div><slot></slot>';
157
174
 
175
+ this.shadowRoot.querySelector('slot').addEventListener('slotchange', async e => {
176
+
177
+ const template = e.target.assignedNodes({ flatten: true })
178
+ .find(node => (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'TEMPLATE'));
179
+
180
+ this._stamp(template);
181
+
182
+ });
183
+ this._renderContainer = this.shadowRoot.querySelector('.d2l-html-block-rendered');
184
+ this._context = this._contextObserverController ? { ...this._contextObserverController.values } : {};
185
+ }
186
+
187
+ updated() {
188
+ super.updated();
189
+ if (this._contextObserverController && this._contextObjectHasChanged()) {
190
+ const template = this.querySelector('template');
191
+ this._stamp(template);
192
+ }
193
+ }
194
+
195
+ _contextObjectHasChanged() {
196
+ if (this._context.size !== this._contextObserverController.values.size) return true;
197
+ for (const [attr, val] of this._context) {
198
+ if (!this._contextObserverController.values.has(attr)) return true;
199
+ if (this._contextObserverController.values.get(attr) !== val) return true;
200
+ }
201
+ return false;
202
+ }
203
+
204
+ _stamp(template) {
158
205
  const stampHTML = async template => {
159
206
  const fragment = template ? document.importNode(template.content, true) : null;
160
207
  if (fragment) {
@@ -162,8 +209,14 @@ class HtmlBlock extends LitElement {
162
209
  let temp = document.createElement('div');
163
210
  temp.appendChild(fragment);
164
211
 
165
- for (const render of HtmlBlock._renderers) {
166
- temp = await render(temp);
212
+ for (const renderer of getRenderers()) {
213
+ if (this._contextObserverController && renderer.contextAttributes) {
214
+ const contextValues = new Map();
215
+ renderer.contextAttributes.forEach(attr => contextValues.set(attr, this._contextObserverController.values.get(attr)));
216
+ temp = await renderer.render(temp, contextValues);
217
+ } else {
218
+ temp = await renderer.render(temp);
219
+ }
167
220
  }
168
221
  this._renderContainer.innerHTML = temp.innerHTML;
169
222
 
@@ -172,26 +225,13 @@ class HtmlBlock extends LitElement {
172
225
  }
173
226
  };
174
227
 
175
- this.shadowRoot.querySelector('slot').addEventListener('slotchange', async e => {
176
-
177
- const template = e.target.assignedNodes({ flatten: true })
178
- .find(node => (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'TEMPLATE'));
179
-
180
- if (this._templateObserver) this._templateObserver.disconnect();
181
- if (template) {
182
- this._templateObserver = new MutationObserver(() => stampHTML(template));
183
- this._templateObserver.observe(template.content, { attributes: true, childList: true, subtree: true });
184
- }
185
-
186
- stampHTML(template);
187
-
188
- });
189
- this._renderContainer = this.shadowRoot.querySelector('.d2l-html-block-rendered');
190
-
191
- }
228
+ if (this._templateObserver) this._templateObserver.disconnect();
229
+ if (template) {
230
+ this._templateObserver = new MutationObserver(() => stampHTML(template));
231
+ this._templateObserver.observe(template.content, { attributes: true, childList: true, subtree: true });
232
+ }
192
233
 
193
- static get _renderers() {
194
- return getRenderers();
234
+ stampHTML(template);
195
235
  }
196
236
 
197
237
  }
@@ -1,24 +1,25 @@
1
1
  const controllerCallbacks = new Map();
2
2
 
3
3
  const contextObserver = new MutationObserver(mutations => {
4
- mutations.forEach(mutation => {
5
- controllerCallbacks.forEach(callback => callback(mutation.attributeName));
6
- });
4
+ controllerCallbacks.forEach(callback => callback(
5
+ mutations.map(mutation => mutation.attributeName)
6
+ ));
7
7
  });
8
8
 
9
9
  export class HtmlAttributeObserverController {
10
10
 
11
- constructor(host, attribute) {
12
- this._host = host;
13
- this._attribute = attribute;
11
+ constructor(host, ...attributes) {
12
+ if (attributes.length === 0) throw new Error(
13
+ 'Can\'t construct controller; must supply at least one observed attribute.'
14
+ );
14
15
 
15
- this.value = undefined;
16
+ this._host = host;
17
+ this._attributes = attributes;
18
+ this.values = new Map();
16
19
  }
17
20
 
18
21
  hostConnected() {
19
- this.value = document.documentElement.hasAttribute(this._attribute)
20
- ? document.documentElement.getAttribute(this._attribute)
21
- : undefined;
22
+ this._updateAttributeValues(this._attributes);
22
23
  if (controllerCallbacks.size === 0) contextObserver.observe(document.documentElement, { attributes: true });
23
24
  controllerCallbacks.set(this, this._handleContextChange.bind(this));
24
25
  }
@@ -27,12 +28,22 @@ export class HtmlAttributeObserverController {
27
28
  controllerCallbacks.delete(this);
28
29
  }
29
30
 
30
- _handleContextChange(attributeName) {
31
- if (attributeName !== this._attribute) return;
32
- this.value = document.documentElement.hasAttribute(this._attribute)
33
- ? document.documentElement.getAttribute(this._attribute)
34
- : undefined;
31
+ _handleContextChange(attributeNames) {
32
+ const attributes = attributeNames.filter(attr => this._attributes.includes(attr));
33
+ if (attributes.length === 0) return;
34
+ this._updateAttributeValues(attributes);
35
35
  this._host.requestUpdate();
36
36
  }
37
37
 
38
+ _updateAttributeValues(names) {
39
+ names.forEach(name => {
40
+ this.values.set(
41
+ name,
42
+ document.documentElement.hasAttribute(name)
43
+ ? document.documentElement.getAttribute(name)
44
+ : undefined
45
+ );
46
+ });
47
+ }
48
+
38
49
  }
@@ -1,24 +1,38 @@
1
+ const mathjaxContextAttribute = 'data-mathjax-context';
2
+
1
3
  let mathJaxLoaded;
2
4
 
3
- export async function htmlBlockMathRenderer(elem) {
4
- const context = JSON.parse(document.documentElement.getAttribute('data-mathjax-context')) || {};
5
- const isLatexSupported = context.renderLatex;
5
+ export class HtmlBlockMathRenderer {
6
6
 
7
- if (!elem.querySelector('math') && !(isLatexSupported && /\$\$|\\\(|\\\[|\\begin{|\\ref{|\\eqref{/.test(elem.innerHTML))) return elem;
7
+ get contextAttributes() {
8
+ return [mathjaxContextAttribute];
9
+ }
8
10
 
9
- const mathJaxConfig = {
10
- renderLatex: isLatexSupported,
11
- outputScale: context.outputScale || 1
12
- };
11
+ async render(elem, contextValues) {
12
+ if (!contextValues) return elem;
13
+ const contextVal = contextValues.get(mathjaxContextAttribute);
14
+ if (contextVal === undefined) return elem;
15
+
16
+ const context = JSON.parse(contextVal) || {};
17
+ const isLatexSupported = context.renderLatex;
18
+
19
+ if (!elem.querySelector('math') && !(isLatexSupported && /\$\$|\\\(|\\\[|\\begin{|\\ref{|\\eqref{/.test(elem.innerHTML))) return elem;
20
+
21
+ const mathJaxConfig = {
22
+ renderLatex: isLatexSupported,
23
+ outputScale: context.outputScale || 1
24
+ };
25
+
26
+ await loadMathJax(mathJaxConfig);
13
27
 
14
- await loadMathJax(mathJaxConfig);
28
+ const temp = document.createElement('div');
29
+ temp.attachShadow({ mode: 'open' });
30
+ temp.shadowRoot.innerHTML = `<div><mjx-doc><mjx-head></mjx-head><mjx-body>${elem.innerHTML}</mjx-body></mjx-doc></div>`;
15
31
 
16
- const temp = document.createElement('div');
17
- temp.attachShadow({ mode: 'open' });
18
- temp.shadowRoot.innerHTML = `<div><mjx-doc><mjx-head></mjx-head><mjx-body>${elem.innerHTML}</mjx-body></mjx-doc></div>`;
32
+ window.MathJax.typesetShadow(temp.shadowRoot);
33
+ return temp.shadowRoot.firstChild;
34
+ }
19
35
 
20
- window.MathJax.typesetShadow(temp.shadowRoot);
21
- return temp.shadowRoot.firstChild;
22
36
  }
23
37
 
24
38
  export function loadMathJax(mathJaxConfig) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "1.203.0",
3
+ "version": "1.206.0",
4
4
  "description": "A collection of accessible, free, open-source web components for building Brightspace applications",
5
5
  "repository": "https://github.com/BrightspaceUI/core.git",
6
6
  "publishConfig": {