@brightspace-ui/core 2.43.0 → 2.43.1

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.
@@ -1,6 +1,7 @@
1
1
  import '../colors/colors.js';
2
2
  import { codeStyles, HtmlBlockCodeRenderer } from '../../helpers/prism.js';
3
- import { css, LitElement } from 'lit';
3
+ import { css, html, LitElement } from 'lit';
4
+ import { classMap } from 'lit/directives/class-map.js';
4
5
  import { HtmlAttributeObserverController } from '../../controllers/attributeObserver/htmlAttributeObserverController.js';
5
6
  import { HtmlBlockMathRenderer } from '../../helpers/mathjax.js';
6
7
  import { requestInstance } from '../../mixins/provider-mixin.js';
@@ -140,6 +141,7 @@ class HtmlBlock extends RtlMixin(LitElement) {
140
141
  compact: { type: Boolean },
141
142
  /**
142
143
  * Whether to display the HTML in inline mode
144
+ * @type {Boolean}
143
145
  */
144
146
  inline: { type: Boolean },
145
147
  /**
@@ -161,13 +163,17 @@ class HtmlBlock extends RtlMixin(LitElement) {
161
163
  text-align: left;
162
164
  }
163
165
  :host([inline]),
164
- :host([inline]) div.d2l-html-block-rendered {
166
+ :host([inline]) .d2l-html-block-rendered {
165
167
  display: inline;
166
168
  }
167
169
  :host([hidden]),
168
- :host([no-deferred-rendering]) div.d2l-html-block-rendered {
170
+ :host([no-deferred-rendering]) .d2l-html-block-rendered,
171
+ slot {
169
172
  display: none;
170
173
  }
174
+ :host([no-deferred-rendering]) slot {
175
+ display: contents;
176
+ }
171
177
  :host([dir="rtl"]) {
172
178
  text-align: right;
173
179
  }
@@ -209,52 +215,60 @@ class HtmlBlock extends RtlMixin(LitElement) {
209
215
 
210
216
  firstUpdated(changedProperties) {
211
217
  super.firstUpdated(changedProperties);
218
+ this._updateContextKeys();
219
+ }
212
220
 
213
- if (this._renderContainer) return;
214
-
215
- // The d2l-html-block-rendered class is used to apply CSS outside of the html-block component. Do not change lightly.
216
- this.shadowRoot.innerHTML += '<div class="d2l-html-block-rendered'
217
- + `${this.compact ? ' d2l-html-block-compact' : ''}`
218
- + '"></div><slot'
219
- + `${!this.noDeferredRendering ? ' style="display: none"' : ''}`
220
- + '></slot>';
221
+ render() {
222
+ const renderContainerClasses = {
223
+ 'd2l-html-block-rendered': true,
224
+ 'd2l-html-block-compact': this.compact
225
+ };
221
226
 
222
- this.shadowRoot.querySelector('slot').addEventListener('slotchange', async e => await this._render(e.target));
223
- this._renderContainer = this.shadowRoot.querySelector('.d2l-html-block-rendered');
224
- this._context = this._contextObserverController ? { ...this._contextObserverController.values } : {};
227
+ return html`
228
+ <div class="${classMap(renderContainerClasses)}"></div>
229
+ <slot @slotchange="${this._handleSlotChange}"></slot>
230
+ `;
225
231
  }
226
232
 
227
- updated() {
228
- super.updated();
229
- if (this._contextObserverController && this._contextObjectHasChanged()) this._render();
233
+ updated(changedProperties) {
234
+ super.updated(changedProperties);
235
+ if (this._contextChanged()) {
236
+ this._render();
237
+ this._updateContextKeys();
238
+ }
230
239
  }
231
240
 
232
- _contextObjectHasChanged() {
233
- if (this._context.size !== this._contextObserverController.values.size) return true;
234
- for (const [attr, val] of this._context) {
241
+ _contextChanged() {
242
+ if (!this._contextObserverController) return false;
243
+
244
+ if (this._contextKeys.size !== this._contextObserverController.values.size) return true;
245
+ for (const [attr, val] of this._contextKeys) {
235
246
  if (!this._contextObserverController.values.has(attr)) return true;
236
247
  if (this._contextObserverController.values.get(attr) !== val) return true;
237
248
  }
238
249
  return false;
239
250
  }
240
251
 
252
+ async _handleSlotChange(e) {
253
+ if (!e.target) return;
254
+ await this._render(e.target);
255
+ }
256
+
241
257
  async _processRenderers(elem) {
242
258
  for (const renderer of getRenderers()) {
243
259
  if (this._contextObserverController && renderer.contextAttributes) {
244
260
  const contextValues = new Map();
245
261
  renderer.contextAttributes.forEach(attr => contextValues.set(attr, this._contextObserverController.values.get(attr)));
246
- elem = await renderer.render(elem, {
262
+ await renderer.render(elem, {
247
263
  contextValues: contextValues,
248
264
  noDeferredRendering: this.noDeferredRendering
249
265
  });
250
266
  } else {
251
- elem = await renderer.render(elem, {
267
+ await renderer.render(elem, {
252
268
  noDeferredRendering: this.noDeferredRendering
253
269
  });
254
270
  }
255
271
  }
256
-
257
- return elem;
258
272
  }
259
273
 
260
274
  async _render(slot) {
@@ -274,20 +288,16 @@ class HtmlBlock extends RtlMixin(LitElement) {
274
288
  }
275
289
 
276
290
  _stamp(slot) {
277
- const stampHTML = async nodes => {
278
- if (nodes && nodes.length > 0) {
279
-
280
- let temp = document.createElement('div');
281
- temp.style.display = 'none';
282
- nodes.forEach(node => temp.appendChild(node.cloneNode(true)));
291
+ const renderContainer = this.shadowRoot.querySelector('.d2l-html-block-rendered');
283
292
 
284
- this._renderContainer.appendChild(temp);
285
- temp = await this._processRenderers(temp);
286
- this._renderContainer.innerHTML = temp.innerHTML;
293
+ const stampHTML = async nodes => {
294
+ renderContainer.innerHTML = '';
295
+ if (!nodes || nodes.length === 0) return;
287
296
 
288
- } else {
289
- this._renderContainer.innerHTML = '';
290
- }
297
+ // Nodes must be cloned into the render container before processing, as
298
+ // some renderers require connected nodes (e.g. MathJax).
299
+ nodes.forEach(node => renderContainer.appendChild(node.cloneNode(true)));
300
+ await this._processRenderers(renderContainer);
291
301
  };
292
302
 
293
303
  if (this._contentObserver) this._contentObserver.disconnect();
@@ -303,6 +313,15 @@ class HtmlBlock extends RtlMixin(LitElement) {
303
313
  stampHTML(slottedNodes);
304
314
  }
305
315
 
316
+ _updateContextKeys() {
317
+ if (!this._contextObserverController) return;
318
+ if (!this._contextKeys) this._contextKeys = new Map();
319
+
320
+ this._contextObserverController.values.forEach((val, attr) => {
321
+ this._contextKeys.set(attr, val);
322
+ });
323
+ }
324
+
306
325
  }
307
326
 
308
327
  customElements.define('d2l-html-block', HtmlBlock);
@@ -3813,7 +3813,7 @@
3813
3813
  {
3814
3814
  "name": "inline",
3815
3815
  "description": "Whether to display the HTML in inline mode",
3816
- "type": "boolean",
3816
+ "type": "Boolean",
3817
3817
  "default": "false"
3818
3818
  },
3819
3819
  {
@@ -3835,7 +3835,7 @@
3835
3835
  "name": "inline",
3836
3836
  "attribute": "inline",
3837
3837
  "description": "Whether to display the HTML in inline mode",
3838
- "type": "boolean",
3838
+ "type": "Boolean",
3839
3839
  "default": "false"
3840
3840
  },
3841
3841
  {
@@ -61,35 +61,18 @@ export class HtmlBlockMathRenderer {
61
61
  // This work-around should be removed when linebreaks are natively supported.
62
62
  // MathJax issue: https://github.com/mathjax/MathJax/issues/2312
63
63
  // A duplicate that explains our exact issue: https://github.com/mathjax/MathJax/issues/2495
64
- const lineBreakStyle = 'display: block; height: 0.5rem;';
65
-
66
- // If we're opting out of deferred rendering, we need to rely
67
- // on the global MathJax install for rendering.
68
- if (options.noDeferredRendering) {
69
- elem.querySelectorAll('mspace[linebreak="newline"]').forEach(elm => {
70
- elm.setAttribute('style', lineBreakStyle);
71
- });
72
-
73
- await window.MathJax.startup.promise;
74
- renderingPromise = renderingPromise.then(() => window.MathJax.typesetShadow(elem.getRootNode(), elem));
75
- await renderingPromise;
76
- return elem;
77
- }
78
-
79
- const inner = elem.innerHTML.replace(/<mspace linebreak="newline">/gi, `<mspace linebreak="newline" style="${lineBreakStyle}">`);
80
-
81
- const temp = document.createElement('div');
82
- temp.style.display = 'none';
83
- temp.attachShadow({ mode: 'open' });
84
- temp.shadowRoot.innerHTML = `<div><mjx-doc><mjx-head></mjx-head><mjx-body>${inner}</mjx-body></mjx-doc></div>`;
64
+ elem.querySelectorAll('mspace[linebreak="newline"]').forEach(elm => {
65
+ elm.style.display = 'block';
66
+ elm.style.height = '0.5rem';
67
+ });
85
68
 
86
- elem.appendChild(temp);
69
+ // If we're using deferred rendering, we need to create a document structure
70
+ // within the element so MathJax can appropriately process math.
71
+ if (!options.noDeferredRendering) elem.innerHTML = `<mjx-doc><mjx-head></mjx-head><mjx-body>${elem.innerHTML}</mjx-body></mjx-doc>`;
87
72
 
88
73
  await window.MathJax.startup.promise;
89
- renderingPromise = renderingPromise.then(() => window.MathJax.typesetShadow(temp.shadowRoot));
74
+ renderingPromise = renderingPromise.then(() => window.MathJax.typesetShadow(elem.getRootNode(), elem));
90
75
  await renderingPromise;
91
-
92
- return temp.shadowRoot.firstChild;
93
76
  }
94
77
 
95
78
  }
@@ -129,12 +112,18 @@ export function loadMathJax(mathJaxConfig) {
129
112
  const AbstractHandler = window.MathJax._.core.Handler.AbstractHandler.prototype;
130
113
  const startup = window.MathJax.startup;
131
114
 
115
+ const getFirstChild = doc => {
116
+ const child = doc.firstChild;
117
+ if (!child || child.nodeType === Node.ELEMENT_NODE) return child;
118
+ else return child.nextElementSibling;
119
+ };
120
+
132
121
  //
133
122
  // Extend HTMLAdaptor to handle shadowDOM as the document
134
123
  //
135
124
  class ShadowAdaptor extends HTMLAdaptor {
136
125
  body(doc) {
137
- return doc.body || (doc.firstChild || {}).lastChild || doc;
126
+ return doc.body || (getFirstChild(doc) || {}).lastChild || doc;
138
127
  }
139
128
  create(kind, ns) {
140
129
  const document = (this.document.createElement ? this.document : this.window.document);
@@ -143,10 +132,10 @@ export function loadMathJax(mathJaxConfig) {
143
132
  document.createElement(kind));
144
133
  }
145
134
  head(doc) {
146
- return doc.head || (doc.firstChild || {}).firstChild || doc;
135
+ return doc.head || (getFirstChild(doc) || {}).firstChild || doc;
147
136
  }
148
137
  root(doc) {
149
- return doc.documentElement || doc.firstChild || doc;
138
+ return doc.documentElement || getFirstChild(doc) || doc;
150
139
  }
151
140
  text(text) {
152
141
  const document = (this.document.createTextNode ? this.document : this.window.document);
package/helpers/prism.js CHANGED
@@ -450,8 +450,6 @@ export async function formatCodeElement(elem) {
450
450
 
451
451
  if (!elem.dataset.language && languageInfo.key !== 'plain') elem.dataset.language = languageInfo.desc;
452
452
  Prism.highlightElement(code);
453
-
454
- return elem;
455
453
  }
456
454
 
457
455
  export class HtmlBlockCodeRenderer {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "2.43.0",
3
+ "version": "2.43.1",
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",
@@ -44,7 +44,7 @@
44
44
  "license": "Apache-2.0",
45
45
  "devDependencies": {
46
46
  "@babel/eslint-parser": "^7",
47
- "@brightspace-ui/stylelint-config": "^0.6",
47
+ "@brightspace-ui/stylelint-config": "^0.7",
48
48
  "@open-wc/testing": "^3",
49
49
  "@web/dev-server": "^0.1",
50
50
  "@web/test-runner": "^0.14",