@skirbi/sugar 0.0.11 → 0.0.13
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/Changes +57 -1
- package/lib/htmlelement.mjs +6 -0
- package/lib/index.mjs +1 -1
- package/lib/with-connected-sugar.mjs +35 -30
- package/package.json +1 -1
package/Changes
CHANGED
|
@@ -1,9 +1,63 @@
|
|
|
1
1
|
Revision history for @skirbi/sugar
|
|
2
2
|
|
|
3
|
+
0.0.13 2026-04-16 13:27:59Z
|
|
4
|
+
|
|
5
|
+
* Fix jsdoc build issue
|
|
6
|
+
* Retro actively fix Changelog for v0.0.9, we missed two small additions in
|
|
7
|
+
testing.mjs
|
|
8
|
+
* Add assertQuerySelector() method
|
|
9
|
+
|
|
10
|
+
0.0.12 2026-04-13 00:51:51Z
|
|
11
|
+
|
|
12
|
+
* While checking other Semtic units, we tightened a few tests and exposed an
|
|
13
|
+
issue in how components were rendered and rerendered.
|
|
14
|
+
|
|
15
|
+
We added new test cases to separate what already worked from what did not,
|
|
16
|
+
and validated those cases against Livewire. That led to a small redesign of
|
|
17
|
+
the `connectedSugar` API.
|
|
18
|
+
|
|
19
|
+
The result is fairly clean: a consumer now defines two selectors:
|
|
20
|
+
|
|
21
|
+
* `renderGuardSelector` indicates whether the component is already fully
|
|
22
|
+
rendered.
|
|
23
|
+
* `morphTriggerSelector` indicates whether the component has been morphed back
|
|
24
|
+
to its authored state.
|
|
25
|
+
|
|
26
|
+
Based on these checks, `connectedCallbackSugar()` is called when needed, and
|
|
27
|
+
the component can normalize itself back to its canonical DOM.
|
|
28
|
+
|
|
29
|
+
The previously advised pattern for `connectedCallbackSugar()` is now
|
|
30
|
+
obsolete.
|
|
31
|
+
|
|
32
|
+
This
|
|
33
|
+
|
|
34
|
+
connectedCallbackSugar() {
|
|
35
|
+
this._compile();
|
|
36
|
+
this._observeChildListOnce(...);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
Becomes:
|
|
40
|
+
|
|
41
|
+
class SugarParent extends withConnectedSugar(HTMLElementSugar) {
|
|
42
|
+
static tag = 'sugar-parent';
|
|
43
|
+
|
|
44
|
+
static renderGuardSelector = ':scope > div[data-sugar-parent]'
|
|
45
|
+
static morphTriggerSelector = ':scope > sugar-child';
|
|
46
|
+
|
|
47
|
+
static _tpl = this.tpl(`
|
|
48
|
+
<div data-sugar-parent></div>
|
|
49
|
+
`);
|
|
50
|
+
|
|
51
|
+
connectedCallbackSugar() {
|
|
52
|
+
/* Whatever you want to do here to (re-)render the component */
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
3
57
|
0.0.11 2026-02-24 16:53:49Z
|
|
4
58
|
|
|
5
59
|
* Fix comparing HTML nodes. Whitespace text nodes are a PITA, we deal with
|
|
6
|
-
them and now you can just compare two nodes regardless how you wrote it.
|
|
60
|
+
<F2>them and now you can just compare two nodes regardless how you wrote it.
|
|
7
61
|
Whitespace kinda matters in HTML I guess, until it doesn't.
|
|
8
62
|
|
|
9
63
|
0.0.10 2026-02-24 03:09:34Z
|
|
@@ -95,6 +149,8 @@ Revision history for @skirbi/sugar
|
|
|
95
149
|
}
|
|
96
150
|
XActions.register();
|
|
97
151
|
|
|
152
|
+
* Add `tick` and `morphReplace` methods in `testing.mjs`.
|
|
153
|
+
|
|
98
154
|
0.0.8 2026-02-23 03:32:55Z
|
|
99
155
|
|
|
100
156
|
* Add assertComponentContract testing method. The idea is this:
|
package/lib/htmlelement.mjs
CHANGED
|
@@ -327,5 +327,11 @@ export class HTMLElementSugar extends HTMLElement {
|
|
|
327
327
|
getConfig() {
|
|
328
328
|
return { ...this.config };
|
|
329
329
|
}
|
|
330
|
+
|
|
331
|
+
static assertQuerySelector(haystack, needle, msg) {
|
|
332
|
+
const item = haystack.querySelector(needle)
|
|
333
|
+
if (!item) throw new Error(msg);
|
|
334
|
+
return item;
|
|
335
|
+
}
|
|
330
336
|
}
|
|
331
337
|
|
package/lib/index.mjs
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
export const withConnectedSugar = (Base) =>
|
|
2
2
|
class extends Base {
|
|
3
3
|
static renderGuardSelector = '';
|
|
4
|
+
static morphTriggerSelector = '';
|
|
5
|
+
|
|
6
|
+
connectedCallback() {
|
|
7
|
+
this._syncObservedAttributesToConfig();
|
|
8
|
+
this._armMorphObserver();
|
|
9
|
+
|
|
10
|
+
if (this._shouldRenderOnConnect()) {
|
|
11
|
+
this.connectedCallbackSugar();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
4
14
|
|
|
5
15
|
_syncObservedAttributesToConfig() {
|
|
6
16
|
for (const attr of this.constructor.observedAttributes ?? []) {
|
|
@@ -9,48 +19,43 @@ export const withConnectedSugar = (Base) =>
|
|
|
9
19
|
}
|
|
10
20
|
}
|
|
11
21
|
|
|
12
|
-
|
|
13
|
-
const guard = this.constructor.renderGuardSelector;
|
|
14
|
-
if (guard) return !this.querySelector(guard);
|
|
15
|
-
|
|
16
|
-
if (this._rendered) return false;
|
|
17
|
-
this._rendered = true;
|
|
18
|
-
return true;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Install a single MutationObserver that calls `fn()` when direct children
|
|
23
|
-
* change and `when()` returns true.
|
|
24
|
-
*
|
|
25
|
-
* Intended for morphdom/livewire scenarios where the host stays the same
|
|
26
|
-
* instance.
|
|
27
|
-
*
|
|
28
|
-
* @param {Function} when - predicate
|
|
29
|
-
* @param {Function} fn - callback
|
|
30
|
-
*/
|
|
31
|
-
_observeChildListOnce(when, fn) {
|
|
22
|
+
_armMorphObserver() {
|
|
32
23
|
if (this._sugarMo) return;
|
|
33
24
|
|
|
34
25
|
this._sugarMo = new MutationObserver(() => {
|
|
35
|
-
if (
|
|
26
|
+
if (this._shouldRenderOnMorph()) {
|
|
27
|
+
this.connectedCallbackSugar();
|
|
28
|
+
}
|
|
36
29
|
});
|
|
37
30
|
|
|
38
31
|
this._sugarMo.observe(this, { childList: true });
|
|
39
32
|
}
|
|
40
33
|
|
|
34
|
+
_shouldRenderOnMorph() {
|
|
35
|
+
return this._hasMorphTrigger() && !this._hasRenderedShape();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
_hasMorphTrigger() {
|
|
39
|
+
const sel = this.constructor.morphTriggerSelector;
|
|
40
|
+
return !!(sel && this.querySelector(sel));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
_shouldRenderOnConnect() {
|
|
44
|
+
const guard = this.constructor.renderGuardSelector;
|
|
45
|
+
if (guard) return !this._hasRenderedShape();
|
|
46
|
+
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
_hasRenderedShape() {
|
|
51
|
+
const sel = this.constructor.renderGuardSelector;
|
|
52
|
+
return !!(sel && this.querySelector(sel));
|
|
53
|
+
}
|
|
54
|
+
|
|
41
55
|
disconnectedCallback() {
|
|
42
|
-
// polite cleanup
|
|
43
56
|
this._sugarMo?.disconnect();
|
|
44
57
|
this._sugarMo = null;
|
|
45
58
|
}
|
|
46
59
|
|
|
47
|
-
connectedCallback() {
|
|
48
|
-
this._syncObservedAttributesToConfig();
|
|
49
|
-
if (!this._shouldRenderOnConnect()) return;
|
|
50
|
-
|
|
51
|
-
if (typeof this.connectedCallbackSugar === 'function') {
|
|
52
|
-
this.connectedCallbackSugar();
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
60
|
};
|
|
56
61
|
|
package/package.json
CHANGED