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 CHANGED
@@ -31,7 +31,7 @@ export class MountObserver extends EventTarget {
31
31
  }
32
32
  #calculatedSelector;
33
33
  #attrParts;
34
- #fullListOfAttrs;
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.#fullListOfAttrs = fullListOfAttrs;
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.#fullListOfAttrs;
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.#fullListOfAttrs;
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
- //this.dispatchEvent(new AttrChangeEvent(match, attrChangeInfos));
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 the truth" for key features of the DOM element itself. We will refer to these attributes as "Source of Truth" attributes.
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" seeks to take advantage of the inheritable infrastructure that MountObserver script elements 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.
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 Synthesize method is called repeatedly from different packages that work with that framework, it creates a cluster of MOSEs wrapped inside a 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.
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
 
@@ -1,6 +1,6 @@
1
1
  export async function getWhereAttrSelector(whereAttr, withoutAttrs) {
2
- const { hasBase, hasBranchIn, hasRootIn, isIn } = whereAttr;
3
- const fullListOfAttrs = isIn !== undefined ? [...isIn] : [];
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mount-observer",
3
- "version": "0.0.24",
3
+ "version": "0.0.25",
4
4
  "description": "Observe and act on css matches.",
5
5
  "main": "MountObserver.js",
6
6
  "module": "MountObserver.js",
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
- idx: number,
118
+ isSOfTAttr: boolean,
119
+ idx?: number,
110
120
  name: string,
111
- parts: AttrParts,
121
+ parts?: AttrParts,
122
+ mapsTo?: string,
112
123
  }
113
124
 
114
125
  //#region mount event