saasufy-components 10.2.1 → 10.3.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/if-group.js CHANGED
@@ -1,16 +1,13 @@
1
- import { debouncer } from './utils.js';
2
-
3
- const DEBOUNCE_DELAY = 0;
4
-
5
1
  class IfGroup extends HTMLElement {
6
2
  constructor() {
7
3
  super();
8
4
  this.isReady = false;
5
+ this.renderPending = false;
6
+ this.lastViewportNode = null;
7
+ this.lastRenderedContent = null;
9
8
  this.attachShadow({ mode: 'open' });
10
9
  this.shadowRoot.innerHTML = '<slot name="content"></slot><slot name="viewport"></slot>';
11
10
 
12
- let debounce = debouncer();
13
-
14
11
  this.processTemplates = () => {
15
12
  let viewportSlot = this.shadowRoot.querySelector('slot[name="viewport"]');
16
13
  let viewportNode = viewportSlot.assignedNodes()[0];
@@ -32,10 +29,33 @@ class IfGroup extends HTMLElement {
32
29
  for (let node of contentNodes) {
33
30
  contentList.push(node.innerHTML);
34
31
  }
35
- viewportNode.innerHTML = contentList.join('');
32
+ let content = contentList.join('');
33
+
34
+ // Rewriting innerHTML with identical markup recreates the nodes, which loses
35
+ // decoded images, focus and scroll position; greedy-refresh forces that reset.
36
+ if (
37
+ !this.hasAttribute('greedy-refresh') &&
38
+ viewportNode === this.lastViewportNode &&
39
+ content === this.lastRenderedContent
40
+ ) return;
41
+
42
+ this.lastViewportNode = viewportNode;
43
+ this.lastRenderedContent = content;
44
+
45
+ viewportNode.innerHTML = content;
46
+ };
47
+
48
+ // Coalescing on a microtask keeps the write ahead of the next paint; deferring
49
+ // with a timeout lets the browser paint the empty viewport first, which flickers.
50
+ this.debouncedProcessTemplates = () => {
51
+ if (this.renderPending) return;
52
+ this.renderPending = true;
53
+ queueMicrotask(() => {
54
+ this.renderPending = false;
55
+ this.processTemplates();
56
+ });
36
57
  };
37
58
 
38
- this.debouncedProcessTemplates = debounce(this.processTemplates, DEBOUNCE_DELAY);
39
59
  this.shadowRoot.addEventListener('slotchange', this.debouncedProcessTemplates);
40
60
  }
41
61
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saasufy-components",
3
- "version": "10.2.1",
3
+ "version": "10.3.0",
4
4
  "description": "Components for Saasufy.",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/switch-group.js CHANGED
@@ -1,16 +1,13 @@
1
- import { debouncer } from './utils.js';
2
-
3
- const DEBOUNCE_DELAY = 0;
4
-
5
1
  class SwitchGroup extends HTMLElement {
6
2
  constructor() {
7
3
  super();
8
4
  this.isReady = false;
5
+ this.renderPending = false;
6
+ this.lastViewportNode = null;
7
+ this.lastRenderedContent = null;
9
8
  this.attachShadow({ mode: 'open' });
10
9
  this.shadowRoot.innerHTML = '<slot name="content"></slot><slot name="viewport"></slot>';
11
10
 
12
- let debounce = debouncer();
13
-
14
11
  this.processTemplates = () => {
15
12
  let viewportSlot = this.shadowRoot.querySelector('slot[name="viewport"]');
16
13
  let viewportNode = viewportSlot.assignedNodes()[0];
@@ -45,10 +42,33 @@ class SwitchGroup extends HTMLElement {
45
42
  }
46
43
  }
47
44
 
48
- viewportNode.innerHTML = contentList.join('');
45
+ let content = contentList.join('');
46
+
47
+ // Rewriting innerHTML with identical markup recreates the nodes, which loses
48
+ // decoded images, focus and scroll position; greedy-refresh forces that reset.
49
+ if (
50
+ !this.hasAttribute('greedy-refresh') &&
51
+ viewportNode === this.lastViewportNode &&
52
+ content === this.lastRenderedContent
53
+ ) return;
54
+
55
+ this.lastViewportNode = viewportNode;
56
+ this.lastRenderedContent = content;
57
+
58
+ viewportNode.innerHTML = content;
59
+ };
60
+
61
+ // Coalescing on a microtask keeps the write ahead of the next paint; deferring
62
+ // with a timeout lets the browser paint the empty viewport first, which flickers.
63
+ this.debouncedProcessTemplates = () => {
64
+ if (this.renderPending) return;
65
+ this.renderPending = true;
66
+ queueMicrotask(() => {
67
+ this.renderPending = false;
68
+ this.processTemplates();
69
+ });
49
70
  };
50
71
 
51
- this.debouncedProcessTemplates = debounce(this.processTemplates, DEBOUNCE_DELAY);
52
72
  this.shadowRoot.addEventListener('slotchange', this.debouncedProcessTemplates);
53
73
  }
54
74