mount-observer 0.0.24 → 0.0.25
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/MountObserver.js +31 -6
- package/README.md +3 -3
- package/getWhereAttrSelector.js +2 -2
- package/package.json +1 -1
- package/types.d.ts +14 -3
package/MountObserver.js
CHANGED
|
@@ -31,7 +31,7 @@ export class MountObserver extends EventTarget {
|
|
|
31
31
|
}
|
|
32
32
|
#calculatedSelector;
|
|
33
33
|
#attrParts;
|
|
34
|
-
#
|
|
34
|
+
#fullListOfEnhancementAttrs;
|
|
35
35
|
//get #attrVals
|
|
36
36
|
async #selector() {
|
|
37
37
|
if (this.#calculatedSelector !== undefined)
|
|
@@ -43,7 +43,7 @@ export class MountObserver extends EventTarget {
|
|
|
43
43
|
const { getWhereAttrSelector } = await import('./getWhereAttrSelector.js');
|
|
44
44
|
const info = await getWhereAttrSelector(whereAttr, withoutAttrs);
|
|
45
45
|
const { fullListOfAttrs, calculatedSelector, partitionedAttrs } = info;
|
|
46
|
-
this.#
|
|
46
|
+
this.#fullListOfEnhancementAttrs = fullListOfAttrs;
|
|
47
47
|
this.#attrParts = partitionedAttrs;
|
|
48
48
|
this.#calculatedSelector = calculatedSelector;
|
|
49
49
|
return this.#calculatedSelector;
|
|
@@ -119,7 +119,7 @@ export class MountObserver extends EventTarget {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
const rootMutObs = mutationObserverLookup.get(within);
|
|
122
|
-
const fullListOfAttrs = this.#
|
|
122
|
+
const fullListOfAttrs = this.#fullListOfEnhancementAttrs;
|
|
123
123
|
rootMutObs.addEventListener('mutation-event', async (e) => {
|
|
124
124
|
//TODO: disconnected
|
|
125
125
|
if (this.#isComplex) {
|
|
@@ -151,6 +151,7 @@ export class MountObserver extends EventTarget {
|
|
|
151
151
|
const newValue = target.getAttribute(attributeName);
|
|
152
152
|
const parts = this.#attrParts[idx];
|
|
153
153
|
const attrChangeInfo = {
|
|
154
|
+
isSOfTAttr: false,
|
|
154
155
|
oldValue,
|
|
155
156
|
name: attributeName,
|
|
156
157
|
newValue,
|
|
@@ -245,8 +246,9 @@ export class MountObserver extends EventTarget {
|
|
|
245
246
|
}
|
|
246
247
|
}
|
|
247
248
|
readAttrs(match, branchIndexes) {
|
|
248
|
-
const fullListOfAttrs = this.#
|
|
249
|
+
const fullListOfAttrs = this.#fullListOfEnhancementAttrs;
|
|
249
250
|
const attrChangeInfos = [];
|
|
251
|
+
const oldValue = null;
|
|
250
252
|
if (fullListOfAttrs !== undefined) {
|
|
251
253
|
const attrParts = this.#attrParts;
|
|
252
254
|
for (let idx = 0, ii = fullListOfAttrs.length; idx < ii; idx++) {
|
|
@@ -257,17 +259,40 @@ export class MountObserver extends EventTarget {
|
|
|
257
259
|
continue;
|
|
258
260
|
}
|
|
259
261
|
const name = fullListOfAttrs[idx];
|
|
260
|
-
const oldValue = null;
|
|
261
262
|
const newValue = match.getAttribute(name);
|
|
262
263
|
attrChangeInfos.push({
|
|
263
264
|
idx,
|
|
265
|
+
isSOfTAttr: false,
|
|
264
266
|
newValue,
|
|
265
267
|
oldValue,
|
|
266
268
|
name,
|
|
267
269
|
parts
|
|
268
270
|
});
|
|
269
271
|
}
|
|
270
|
-
|
|
272
|
+
}
|
|
273
|
+
const { observedAttrsWhenMounted } = this.#mountInit;
|
|
274
|
+
if (observedAttrsWhenMounted !== undefined) {
|
|
275
|
+
for (const observedAttr of observedAttrsWhenMounted) {
|
|
276
|
+
const attrIsString = typeof observedAttr === 'string';
|
|
277
|
+
const name = attrIsString ? observedAttr : observedAttr.name;
|
|
278
|
+
let mapsTo;
|
|
279
|
+
let newValue = match.getAttribute(name);
|
|
280
|
+
if (!attrIsString) {
|
|
281
|
+
const { customParser, instanceOf, mapsTo: mt, valIfNull } = observedAttr;
|
|
282
|
+
if (instanceOf || customParser)
|
|
283
|
+
throw 'NI';
|
|
284
|
+
if (newValue === null)
|
|
285
|
+
newValue = valIfNull;
|
|
286
|
+
mapsTo = mt;
|
|
287
|
+
}
|
|
288
|
+
attrChangeInfos.push({
|
|
289
|
+
isSOfTAttr: true,
|
|
290
|
+
newValue,
|
|
291
|
+
oldValue,
|
|
292
|
+
name,
|
|
293
|
+
mapsTo
|
|
294
|
+
});
|
|
295
|
+
}
|
|
271
296
|
}
|
|
272
297
|
return attrChangeInfos;
|
|
273
298
|
}
|
package/README.md
CHANGED
|
@@ -337,7 +337,7 @@ We want to be alerted by the discovery of elements adorned by these attributes,
|
|
|
337
337
|
|
|
338
338
|
I think it is useful to divide [attributes](https://jakearchibald.com/2024/attributes-vs-properties/) that we would want to observe into two categories:
|
|
339
339
|
|
|
340
|
-
1. Invariably named, prefix-less, "top-level" attributes that serve as the "source of
|
|
340
|
+
1. Invariably named, prefix-less, "top-level" attributes that serve as the "source of truth" for key features of the DOM element itself. We will refer to these attributes as "Source of Truth" attributes.
|
|
341
341
|
|
|
342
342
|
Examples are many built-in global attributes, like lang, or contenteditable, or more specialized examples such as "content" for the meta tag. I think in the vast majority of cases, setting the property values corresponding to these attributes results in directly reflecting those property values to the attributes. There are exceptions, especially for non-string attributes like the checked property of the input element / type=checkbox. And there are usually no events we can subscribe to in order to know when the property changes. Hijacking the property setter in order to observe changes may not always work or feel very resilient. So monitoring the attribute value is often the most effective way of observing when the property/attribute state for these elements change. And some attributes (like the microdata attributes such as itemprop) don't even have properties that they pair with!
|
|
343
343
|
|
|
@@ -722,12 +722,12 @@ Often, we will want to define a large number of "mount observer script elements
|
|
|
722
722
|
|
|
723
723
|
This is a problem space that [be-hive](https://github.com/bahrus/be-hive) is grappling with, and is used as an example for this section, to simply make things more concrete. But we can certainly envision other "frameworks" that could leverage this feature for a variety of purposes, including other families of behaviors/enhancements, or "binding from a distance" syntaxes.
|
|
724
724
|
|
|
725
|
-
In particular, *be-hive* supports publishing [enhancements](https://github.com/bahrus/be-enhanced) that take advantage of the DOM filtering ability that the MountObserver provides, that "ties the knot" based on CSS matches in the DOM to behaviors/enhancements that we want to attach directly onto the matching elements. *be-hive
|
|
725
|
+
In particular, *be-hive* supports publishing [enhancements](https://github.com/bahrus/be-enhanced) that take advantage of the DOM filtering ability that the MountObserver provides, that "ties the knot" based on CSS matches in the DOM to behaviors/enhancements that we want to attach directly onto the matching elements. *be-hive* seeks to take advantage of the inheritable infrastructure that MOSEs provide, but we don't want to burden the developer with having to manually list all these configurations, we want it to happen automatically, only expecting manual intervention when we need some special customizations within a specific ShadowDOM scope.
|
|
726
726
|
|
|
727
727
|
To support this, we propose these highlights:
|
|
728
728
|
|
|
729
729
|
1. Adding a static "synthesize" method to the MountObserver api. This would provide a kind of passage-way from the imperative api to the declarative one.
|
|
730
|
-
2. As the
|
|
730
|
+
2. As the *synthesize* method is called repeatedly from different packages that work within that framework, it creates a cluster of MOSEs wrapped inside the "synthesizing" custom element ("be-hive") that the framework developer authors. It appends script elements with type="mountobserver" to the custom element instance sitting in the DOM, that dispatches events from the synthesizing custom element it gets appended to, so subscribers in child Shadow DOM's don't need to add a general mutation observer in order to know when parent shadow roots had a MOSE inserted that it needs to act on. This allows the child Shadow DOM's to inherit (in this case) behaviors/enhancements from the parent Shadow DOM.
|
|
731
731
|
|
|
732
732
|
So framework developers can develop a bespoke custom element that inherits from the class "*Synthesizer*" that is part of this package / proposal, that is used to group families of MountObservers together.
|
|
733
733
|
|
package/getWhereAttrSelector.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export async function getWhereAttrSelector(whereAttr, withoutAttrs) {
|
|
2
|
-
const { hasBase, hasBranchIn, hasRootIn
|
|
3
|
-
const fullListOfAttrs =
|
|
2
|
+
const { hasBase, hasBranchIn, hasRootIn } = whereAttr;
|
|
3
|
+
const fullListOfAttrs = [];
|
|
4
4
|
const partitionedAttrs = [];
|
|
5
5
|
if (hasBase !== undefined) {
|
|
6
6
|
const hasRootInGuaranteed = hasRootIn || [{
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -2,13 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
export interface JSONSerializableMountInit{
|
|
4
4
|
readonly on?: CSSMatch,
|
|
5
|
-
observedAttrsWhenMounted?: string[],
|
|
5
|
+
readonly observedAttrsWhenMounted?: (string | ObservedSourceOfTruthAttribute)[],
|
|
6
6
|
readonly whereAttr?: WhereAttr,
|
|
7
7
|
readonly whereElementIntersectsWith?: IntersectionObserverInit,
|
|
8
8
|
readonly whereMediaMatches?: MediaQuery,
|
|
9
9
|
readonly import?: ImportString | [ImportString, ImportAssertions] | PipelineProcessor,
|
|
10
10
|
|
|
11
11
|
}
|
|
12
|
+
|
|
13
|
+
export interface ObservedSourceOfTruthAttribute {
|
|
14
|
+
name: string,
|
|
15
|
+
mapsTo?: string,
|
|
16
|
+
valIfNull?: any,
|
|
17
|
+
instanceOf?: any,
|
|
18
|
+
customParser?: (newValue: string | null, oldValue: string | null, instance: Element) => any
|
|
19
|
+
}
|
|
20
|
+
|
|
12
21
|
export interface MountInit extends JSONSerializableMountInit{
|
|
13
22
|
|
|
14
23
|
readonly withTargetShadowRoot?: ShadowRoot,
|
|
@@ -106,9 +115,11 @@ interface AttrParts{
|
|
|
106
115
|
interface AttrChangeInfo{
|
|
107
116
|
oldValue: string | null,
|
|
108
117
|
newValue: string | null,
|
|
109
|
-
|
|
118
|
+
isSOfTAttr: boolean,
|
|
119
|
+
idx?: number,
|
|
110
120
|
name: string,
|
|
111
|
-
parts
|
|
121
|
+
parts?: AttrParts,
|
|
122
|
+
mapsTo?: string,
|
|
112
123
|
}
|
|
113
124
|
|
|
114
125
|
//#region mount event
|