saasufy-components 2.8.0 → 2.10.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.
package/README.md CHANGED
@@ -223,10 +223,15 @@ A general purpose modal component.
223
223
 
224
224
  A component which can be used to guarantee that certain children components are always rendered at the same time (once they are loaded) to provide a smooth user experience.
225
225
 
226
+ ### if-group
227
+
228
+ A modal component which exposes a `show-content` property which can be set to true or false to show or hide its content.
229
+ It's intended to be placed inside a `model-viewer`, `collection-browser` or `collection-reducer` component such that the true/false value of the `show-content` attribute can be computed using a template `{{expression}}` placeholder. Unlike `conditional-group`, this component requires a template and a viewport to be slotted in. The content of the template will not be processed unless the `show-content` condition is met.
230
+
226
231
  ### conditional-group
227
232
 
228
233
  A modal component which exposes a `show-content` property which can be set to true or false to show or hide its content.
229
- It's intended to be placed inside a `model-viewer`, `collection-browser` or `collection-reducer` component such that the true/false value of the `show-content` attribute can be computed using a template `{{expression}}` placeholder.
234
+ It's intended to be placed inside a `model-viewer`, `collection-browser` or `collection-reducer` component such that the true/false value of the `show-content` attribute can be computed using a template `{{expression}}` placeholder. Unlike `if-group`, this component does not require a template, however, the trade-off is that the slotted content will be pre-processed by the browser even when the expression is false. This may not be suitable if you want to (for example) render child images conditionally because the browser will preload images based on their `src` attributes, even if they are not shown.
230
235
 
231
236
  ### collection-adder-group
232
237
 
@@ -23,7 +23,16 @@ class ConditionalGroup extends HTMLElement {
23
23
 
24
24
  render() {
25
25
  let showContent = this.getAttribute('show-content');
26
- this.shadowRoot.innerHTML = showContent != null && showContent !== 'false' ? '<slot></slot>' : '';
26
+ if (
27
+ !showContent ||
28
+ showContent === 'false' ||
29
+ showContent === 'null' ||
30
+ showContent === 'undefined'
31
+ ) {
32
+ this.shadowRoot.innerHTML = '';
33
+ return;
34
+ }
35
+ this.shadowRoot.innerHTML = '<slot></slot>';
27
36
  }
28
37
  }
29
38
 
package/if-group.js ADDED
@@ -0,0 +1,58 @@
1
+ import { debouncer } from './utils.js';
2
+
3
+ const DEBOUNCE_DELAY = 0;
4
+
5
+ class IfGroup extends HTMLElement {
6
+ constructor() {
7
+ super();
8
+ this.isReady = false;
9
+ this.attachShadow({ mode: 'open' });
10
+ this.shadowRoot.innerHTML = '<slot name="content"></slot><slot name="viewport"></slot>';
11
+
12
+ let debounce = debouncer();
13
+
14
+ this.processTemplates = () => {
15
+ let viewportSlot = this.shadowRoot.querySelector('slot[name="viewport"]');
16
+ let viewportNode = viewportSlot.assignedNodes()[0];
17
+ if (!viewportNode) return;
18
+
19
+ let showContent = this.getAttribute('show-content');
20
+ if (
21
+ !showContent ||
22
+ showContent === 'false' ||
23
+ showContent === 'null' ||
24
+ showContent === 'undefined'
25
+ ) return;
26
+
27
+ let contentSlot = this.shadowRoot.querySelector('slot[name="content"]');
28
+ let contentNodes = contentSlot.assignedNodes();
29
+ if (!contentNodes.length) return;
30
+
31
+ let contentList = [];
32
+ for (let node of contentNodes) {
33
+ contentList.push(node.innerHTML);
34
+ }
35
+ viewportNode.innerHTML = contentList.join('');
36
+ };
37
+
38
+ this.debouncedProcessTemplates = debounce(this.processTemplates, DEBOUNCE_DELAY);
39
+ this.shadowRoot.addEventListener('slotchange', this.debouncedProcessTemplates);
40
+ }
41
+
42
+ static get observedAttributes() {
43
+ return [
44
+ 'show-content'
45
+ ];
46
+ }
47
+
48
+ attributeChangedCallback() {
49
+ if (!this.isReady) return;
50
+ this.processTemplates();
51
+ }
52
+
53
+ connectedCallback() {
54
+ this.isReady = true;
55
+ }
56
+ }
57
+
58
+ window.customElements.define('if-group', IfGroup);
package/model-viewer.js CHANGED
@@ -161,8 +161,6 @@ class ModelViewer extends SocketConsumer {
161
161
  (async () => {
162
162
  this.modelChangeConsumer = this.model.listener('change').createConsumer();
163
163
  for await (let event of this.modelChangeConsumer) {
164
- // Ignore change events which originate from this collection instance.
165
- if (!event.isRemote) continue;
166
164
  this.renderItem();
167
165
  }
168
166
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saasufy-components",
3
- "version": "2.8.0",
3
+ "version": "2.10.0",
4
4
  "description": "Components for Saasufy.",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/utils.js CHANGED
@@ -18,6 +18,12 @@ export function toSafeHTML(text) {
18
18
  return text;
19
19
  }
20
20
 
21
+ export function toExpression(html) {
22
+ return html.replace(/&amp;/g, '&')
23
+ .replace(/&lt;/g, '<')
24
+ .replace(/&gt;/g, '>');
25
+ }
26
+
21
27
  export function debouncer() {
22
28
  let debounceTimeout = null;
23
29
  return function (callback, duration) {
@@ -213,7 +219,7 @@ export function renderTemplate(templateString, data, socket) {
213
219
  try {
214
220
  return toSafeHTML(
215
221
  execExpression(
216
- expString,
222
+ toExpression(expString),
217
223
  options
218
224
  )
219
225
  );