mount-observer 0.0.18 → 0.0.20
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 +5 -3
- package/README.md +135 -41
- package/birtualizeMatch.js +3 -3
- package/package.json +1 -1
- package/types.d.ts +9 -3
package/MountObserver.js
CHANGED
|
@@ -15,9 +15,10 @@ export class MountObserver extends EventTarget {
|
|
|
15
15
|
super();
|
|
16
16
|
const { on, whereElementIntersectsWith, whereMediaMatches } = init;
|
|
17
17
|
let isComplex = false;
|
|
18
|
+
//TODO: further this problem further. Starting to think this is basically not polyfillable
|
|
18
19
|
if (on !== undefined) {
|
|
19
20
|
const reducedMatch = on.replaceAll(':not(', '');
|
|
20
|
-
isComplex = reducedMatch.includes(' ') || reducedMatch.includes(':');
|
|
21
|
+
isComplex = reducedMatch.includes(' ') || (reducedMatch.includes(':') && reducedMatch.includes('('));
|
|
21
22
|
}
|
|
22
23
|
this.#isComplex = isComplex;
|
|
23
24
|
if (whereElementIntersectsWith || whereMediaMatches)
|
|
@@ -74,7 +75,7 @@ export class MountObserver extends EventTarget {
|
|
|
74
75
|
this.#templLookUp.set(id, templ);
|
|
75
76
|
return templ;
|
|
76
77
|
}
|
|
77
|
-
|
|
78
|
+
disconnect(within) {
|
|
78
79
|
const nodeToMonitor = this.#isComplex ? (within instanceof ShadowRoot ? within : within.getRootNode()) : within;
|
|
79
80
|
const currentCount = refCount.get(nodeToMonitor);
|
|
80
81
|
if (currentCount !== undefined) {
|
|
@@ -98,6 +99,7 @@ export class MountObserver extends EventTarget {
|
|
|
98
99
|
console.warn(refCountErr);
|
|
99
100
|
}
|
|
100
101
|
}
|
|
102
|
+
this.dispatchEvent(new Event('disconnectedCallback'));
|
|
101
103
|
}
|
|
102
104
|
async observe(within) {
|
|
103
105
|
await this.#selector();
|
|
@@ -314,7 +316,7 @@ export class MountObserver extends EventTarget {
|
|
|
314
316
|
}
|
|
315
317
|
}
|
|
316
318
|
const refCountErr = 'mount-observer ref count mismatch';
|
|
317
|
-
export const inclTemplQry = 'template[
|
|
319
|
+
export const inclTemplQry = 'template[src^="#"]:not([hidden])';
|
|
318
320
|
// https://github.com/webcomponents-cg/community-protocols/issues/12#issuecomment-872415080
|
|
319
321
|
/**
|
|
320
322
|
* The `mutation-event` event represents something that happened.
|
package/README.md
CHANGED
|
@@ -7,11 +7,11 @@ Note that much of what is described below has not yet been polyfilled.
|
|
|
7
7
|
|
|
8
8
|
# The MountObserver api.
|
|
9
9
|
|
|
10
|
-
Author: Bruce B. Anderson
|
|
10
|
+
Author: Bruce B. Anderson (with valuable feedback from @doeixd )
|
|
11
11
|
|
|
12
12
|
Issues / pr's / polyfill: [mount-observer](https://github.com/bahrus/mount-observer)
|
|
13
13
|
|
|
14
|
-
Last Update: 2024-
|
|
14
|
+
Last Update: 2024-5-5
|
|
15
15
|
|
|
16
16
|
## Benefits of this API
|
|
17
17
|
|
|
@@ -19,7 +19,8 @@ What follows is a far more ambitious alternative to the [lazy custom element pro
|
|
|
19
19
|
|
|
20
20
|
["Binding from a distance"](https://github.com/WICG/webcomponents/issues/1035#issuecomment-1806393525) refers to empowering the developer to essentially manage their own "stylesheets" -- but rather than for purposes of styling, using these rules to attach behaviors, set property values, etc, to the HTML as it streams in. Libraries that take this approach include [Corset](https://corset.dev/) and [trans-render](https://github.com/bahrus/trans-render). The concept has been promoted by a [number](https://bkardell.com/blog/CSSLike.html) [of](https://www.w3.org/TR/NOTE-AS) [prominent](https://www.xanthir.com/blog/b4K_0) voices in the community.
|
|
21
21
|
|
|
22
|
-
The underlying theme is this api is meant to make it easy for the developer to do the right thing, by encouraging lazy loading and smaller footprints. It rolls up most all the other observer api's into one.
|
|
22
|
+
The underlying theme is this api is meant to make it easy for the developer to do the right thing, by encouraging lazy loading and smaller footprints. It rolls up most all the other observer api's into one, including, potentially, [this one](https://github.com/whatwg/dom/issues/1285).
|
|
23
|
+
|
|
23
24
|
|
|
24
25
|
### Does this api make the impossible possible?
|
|
25
26
|
|
|
@@ -27,7 +28,9 @@ There is quite a bit of functionality this proposal would open up, that is excee
|
|
|
27
28
|
|
|
28
29
|
1. It is unclear how to use mutation observers to observe changes to [custom state](https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet). The closest thing might be a solution like [this](https://davidwalsh.name/detect-node-insertion), but that falls short for elements that aren't visible, or during template instantiation, and requires carefully constructed "negating" queries if needing to know when the css selector is no longer matching.
|
|
29
30
|
|
|
30
|
-
2. For simple css matches, like "my-element", or "[name='hello']" it is enough to use a mutation observer, and only observe the elements within the specified DOM region (more on that below). But as CSS has evolved, it is quite easy to think of numerous css selectors that would require us to expand our mutation observer to need to scan the entire Shadow DOM realm, or the entire DOM tree outside any Shadow DOM, for any and all mutations (including attribute changes), and re-evaluate every single element within the specified DOM region for new matches or old matches that no longer match. Things like child selectors, :has, and so on. All this is done, miraculously, by the browser in a performant way. Reproducing this in userland using JavaScript alone, matching the same performance seems impossible.
|
|
31
|
+
2. For simple css matches, like "my-element", or "[name='hello']" it is enough to use a mutation observer, and only observe the elements within the specified DOM region (more on that below). But as CSS has evolved, it is quite easy to think of numerous css selectors that would require us to expand our mutation observer to need to scan the entire Shadow DOM realm, or the entire DOM tree outside any Shadow DOM, for any and all mutations (including attribute changes), and re-evaluate every single element within the specified DOM region for new matches or old matches that no longer match. Things like child selectors, :has, and so on. All this is done, miraculously, by the browser in a performant way. Reproducing this in userland using JavaScript alone, matching the same performance seems impossible.
|
|
32
|
+
|
|
33
|
+
|
|
31
34
|
|
|
32
35
|
3. Knowing when an element, previously being monitored for, passes totally "out-of-scope", so that no more hard references to the element remain. This would allow for cleanup of no longer needed weak references without requiring polling.
|
|
33
36
|
|
|
@@ -44,6 +47,9 @@ The amount of code necessary to accomplish these common tasks designed to improv
|
|
|
44
47
|
|
|
45
48
|
The extra flexibility this new primitive would provide could be quite useful to things other than lazy loading of custom elements, such as implementing [custom enhancements](https://github.com/WICG/webcomponents/issues/1000) as well as [binding from a distance](https://github.com/WICG/webcomponents/issues/1035#issuecomment-1806393525) in userland.
|
|
46
49
|
|
|
50
|
+
> [!Note]
|
|
51
|
+
> Reading through the historical links tied to the selector-observer proposal this proposal helped spawn, I may have painted an overly optimistic picture of [what the platform is capable of](https://github.com/whatwg/dom/issues/398). It does leave me a little puzzled why this isn't an issue when it comes to styling, and also if some of the advances that were utilized to support :has could be applied to this problem space, so that maybe the arguments raised there have weakened. Even if the concerns raised are as relevant today, I think considering the use cases this proposal envisions, that the objections could be overcome, for the following reasons: 1. For scenarios where lazy loading is the primary objective, "bunching" multiple DOM mutations together and only reevaluating when things are quite idle is perfectly reasonable. Also, for binding from a distance, most of the mutations that need responding to quickly will be when the *state of the host* changes, so DOM mutations play a somewhat muted role in that regard. Again, bunching multiple DOM mutations together, even if adds a bit of a delay, also seems reasonable. I also think the platform could add an "analysis" step to look at the query and categorize it as "simple" queries vs complex. Selector queries that are driven by the characteristics of the element itself (localName, attributes, etc) could be handled in a more expedited fashion. Those that the platform does expect to require more babysitting could be monitored for less vigilantly. Maybe in the latter case, a console.warning could be emitted during initialization. The other use case, for lazy loading custom elements and custom enhancements based on attributes, I think most of the time this would fit the "simple" scenario, so again there wouldn't be much of an issue.
|
|
52
|
+
|
|
47
53
|
## First use case -- lazy loading custom elements
|
|
48
54
|
|
|
49
55
|
To specify the equivalent of what the alternative proposal linked to above would do, we can do the following:
|
|
@@ -53,37 +59,61 @@ const observer = new MountObserver({
|
|
|
53
59
|
on:'my-element',
|
|
54
60
|
import: './my-element.js',
|
|
55
61
|
do: {
|
|
56
|
-
mount: ({localName}, {
|
|
62
|
+
mount: ({localName}, {modules, observer}) => {
|
|
57
63
|
if(!customElements.get(localName)) {
|
|
58
|
-
customElements.define(localName,
|
|
64
|
+
customElements.define(localName, modules[0].MyElement);
|
|
59
65
|
}
|
|
66
|
+
observer.disconnect();
|
|
60
67
|
}
|
|
61
68
|
}
|
|
62
69
|
});
|
|
63
70
|
observer.observe(document);
|
|
64
71
|
```
|
|
65
72
|
|
|
66
|
-
|
|
73
|
+
Invoking "disconnect" as shown above causes the observer to emit event "disconnectedCallback".
|
|
74
|
+
|
|
75
|
+
The argument can also be an array of objects that fit the pattern shown above.
|
|
76
|
+
|
|
77
|
+
If no imports are specified, it would go straight to do.* (if any such callbacks are specified), and it will also dispatch events as discussed below.
|
|
67
78
|
|
|
68
79
|
This only searches for elements matching 'my-element' outside any shadow DOM.
|
|
69
80
|
|
|
70
81
|
But the observe method can accept a node within the document, or a shadowRoot, or a node inside a shadowRoot as well.
|
|
71
82
|
|
|
72
|
-
The
|
|
83
|
+
The "observer" constant above is a class instance that inherits from EventTarget, which means it can be subscribed to by outside interests.
|
|
84
|
+
|
|
85
|
+
## The import key
|
|
86
|
+
|
|
87
|
+
This proposal has been amended to support multiple imports, including of different types:
|
|
73
88
|
|
|
74
89
|
```JavaScript
|
|
75
90
|
const observer = new MountObserver({
|
|
76
|
-
on:
|
|
77
|
-
import:
|
|
91
|
+
on:'my-element',
|
|
92
|
+
import: [
|
|
93
|
+
['./my-element-small.css', {type: 'css'}],
|
|
94
|
+
'./my-element.js',
|
|
95
|
+
]
|
|
96
|
+
do: {
|
|
97
|
+
mount: ({localName}, {modules, observer}) => {
|
|
98
|
+
if(!customElements.get(localName)) {
|
|
99
|
+
customElements.define(localName, modules[1].MyElement);
|
|
100
|
+
}
|
|
101
|
+
observer.disconnect();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
78
104
|
});
|
|
79
|
-
observer.observe(
|
|
105
|
+
observer.observe(document);
|
|
80
106
|
```
|
|
81
107
|
|
|
82
|
-
|
|
108
|
+
Th key can accept either a single import or multiple (via an array).
|
|
109
|
+
|
|
110
|
+
The do event won't be invoked until all the imports have been successfully completed and inserted into the modules array.
|
|
111
|
+
|
|
112
|
+
Previously, this proposal called for allowing arrow functions as well, thinking that could be a good interim way to support bundlers. But the valuable input provided by [doeixd](https://github.com/doeixd) makes me think that that interim support could just as effectively be done by the developer in the do methods.
|
|
113
|
+
|
|
114
|
+
This proposal would also include support for JSON and HTML module imports.
|
|
83
115
|
|
|
84
|
-
This proposal would also include support for CSS, JSON, HTML module imports.
|
|
85
116
|
|
|
86
|
-
The "observer" constant above is a class instance that inherits from EventTarget, which means it can be subscribed to by outside interests.
|
|
87
117
|
|
|
88
118
|
## Binding from a distance
|
|
89
119
|
|
|
@@ -140,7 +170,7 @@ const observer = new MountObserver({
|
|
|
140
170
|
},
|
|
141
171
|
import: ['./my-element-small.css', {type: 'css'}],
|
|
142
172
|
do: {
|
|
143
|
-
mount: ({localName}, {
|
|
173
|
+
mount: ({localName}, {modules}) => {
|
|
144
174
|
...
|
|
145
175
|
},
|
|
146
176
|
dismount: ...,
|
|
@@ -153,7 +183,13 @@ const observer = new MountObserver({
|
|
|
153
183
|
})
|
|
154
184
|
```
|
|
155
185
|
|
|
156
|
-
Callbacks like we see above are useful for tight coupling, and probably are unmatched in terms of performance. The expression that the "do" field points to could also be a (stateful) user defined class instance.
|
|
186
|
+
Callbacks like we see above are useful for tight coupling, and probably are unmatched in terms of performance. The expression that the "do" field points to could also be a (stateful) user defined class instance.
|
|
187
|
+
|
|
188
|
+
<!--
|
|
189
|
+
|
|
190
|
+
[TODO] Maybe should also (optionally?) pass back which checks failed and which succeeded on dismount. Not sure I really see a use case for it, but leaving the thought here for now
|
|
191
|
+
|
|
192
|
+
-->
|
|
157
193
|
|
|
158
194
|
However, since these rules may be of interest to multiple parties, it is useful to also provide the ability for multiple parties to subscribe to these css rules. This can be done via:
|
|
159
195
|
|
|
@@ -201,7 +237,41 @@ If an element that is in "mounted" state according to a MountObserver instance i
|
|
|
201
237
|
3) If the mounted element is added outside the rootNode being observed, the mountObserver instance will dispatch event "exit", and the MountObserver instance will relinquish any further responsibility for this element.
|
|
202
238
|
4) Ideally event "forget" would be dispatched just before the platform garbage collects an element the MountObserver instance is still monitoring, after all hard references are relinquished (or is that self-contradictory?).
|
|
203
239
|
5) If the new place it was added remains within the original rootNode and remains mounted, the MountObserver instance dispatches event "reconfirmed".
|
|
204
|
-
6) If the element no longer satisfies the criteria of the MountObserver instance, the MountObserver instance will dispatch event "dismount".
|
|
240
|
+
6) If the element no longer satisfies the criteria of the MountObserver instance, the MountObserver instance will dispatch event "dismount".
|
|
241
|
+
|
|
242
|
+
## Dismounting
|
|
243
|
+
|
|
244
|
+
In many cases, it will be critical to inform the developer **why** the element no longer satisfies all the criteria. For example, we may be using an intersection observer, and when we've scrolled away from view, we can "shut down" until the element is (nearly) scrolled back into view. We may also be displaying things differently depending on the network speed. How we should respond when one of the original conditions, but not the other, no longer applies, is of paramount importance.
|
|
245
|
+
|
|
246
|
+
So the dismount event should provide a "checklist" of all the conditions, and their current value:
|
|
247
|
+
|
|
248
|
+
```JavaScript
|
|
249
|
+
mediaMatches: true,
|
|
250
|
+
containerMatches: true,
|
|
251
|
+
satisifiesCustomCondition: true,
|
|
252
|
+
whereLangIn: ['en-GB'],
|
|
253
|
+
whereConnection:{
|
|
254
|
+
effectiveTypeMatches: true
|
|
255
|
+
},
|
|
256
|
+
isIntersecting: false,
|
|
257
|
+
changedConditions: ['isIntersecting']
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Get play-by-play updates?
|
|
261
|
+
|
|
262
|
+
An issue raised by @doeixd, I think, is what if we want to be informed of the status of all the conditions that are applicable to an element being mounted / dismounted? I can see scenarios where this would be useful, for reasons similar to wanting to know why the element dismounted.
|
|
263
|
+
|
|
264
|
+
Since this could have a negative impact on performance, I think it should be something we opt-in to:
|
|
265
|
+
|
|
266
|
+
```JavaScript
|
|
267
|
+
getPlayByPlay: true
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Now the question is when should this progress reporting start? It could either start the moment the element becomes mounted the first time. Or it could happen the moment any of the conditions are satisfied. But some of the conditions could be trivially satisfied for the vast majority of elements (e.g. network speed is 4g or greater).
|
|
271
|
+
|
|
272
|
+
So I believe the prudent thing to do is wait for all the conditions to be satisfied, before engaging in this kind of commentary, i.e. after the first mount.
|
|
273
|
+
|
|
274
|
+
The alternative to providing this feature, which I'm leaning towards, is to just ask the developer to create "specialized" mountObserver construction arguments, that turn on and off precisely when the developer needs to know.
|
|
205
275
|
|
|
206
276
|
## A tribute to attributes
|
|
207
277
|
|
|
@@ -211,6 +281,7 @@ Being that for both custom elements, as well as (hopefully) [custom enhancements
|
|
|
211
281
|
|
|
212
282
|
We want to be alerted by the discovery of elements adorned by these attributes, but then continue to be alerted to changes of their values, and we can't enumerate which values we are interested in, so we must subscribe to all values as they change.
|
|
213
283
|
|
|
284
|
+
<!--
|
|
214
285
|
### Scenario 1 -- Custom Element integration with ObserveObservedAttributes API [WIP]
|
|
215
286
|
|
|
216
287
|
Example:
|
|
@@ -236,13 +307,16 @@ Example:
|
|
|
236
307
|
}, 1000);
|
|
237
308
|
</script>
|
|
238
309
|
```
|
|
310
|
+
-->
|
|
311
|
+
|
|
239
312
|
|
|
313
|
+
### Custom Enhancements in userland
|
|
240
314
|
|
|
241
|
-
|
|
315
|
+
[This proposal could take quite a while to see the light of day, if ever](https://github.com/WICG/webcomponents/issues/1000).
|
|
242
316
|
|
|
243
|
-
|
|
317
|
+
In the meantime, we want to provide the most help for providing for custom enhancements in userland, and for any other kind of (progressive) enhancement based on attributes going forward.
|
|
244
318
|
|
|
245
|
-
Suppose we have a progressive enhancement that we want to apply based on the presence of 1 or more attributes.
|
|
319
|
+
Suppose we have a (progressive) enhancement that we want to apply based on the presence of 1 or more attributes.
|
|
246
320
|
|
|
247
321
|
To make this discussion concrete, let's suppose the "canonical" names of those attributes are:
|
|
248
322
|
|
|
@@ -284,7 +358,7 @@ So let's say we want to insist that on custom elements, we must have the data- p
|
|
|
284
358
|
|
|
285
359
|
And we want to support an alternative, more semantic sounding prefix to data, say enh-*, endorsed by [this proposal](https://github.com/WICG/webcomponents/issues/1000).
|
|
286
360
|
|
|
287
|
-
Here's what the api **doesn't** provide:
|
|
361
|
+
Here's what the api **doesn't** provide (as originally proposed):
|
|
288
362
|
|
|
289
363
|
## Rejected option -- The carpal syndrome syntax
|
|
290
364
|
|
|
@@ -415,6 +489,18 @@ const mo = new MountObserver({
|
|
|
415
489
|
});
|
|
416
490
|
```
|
|
417
491
|
|
|
492
|
+
## Resolving ambiguity
|
|
493
|
+
|
|
494
|
+
Because we want the multiple root values (enh-*, data-enh-*, *) to be treated as equivalent, from a developer point of view, we have a possible ambiguity -- what if more than one root is present for the same base, branch and leaf? Which value trumps the others?
|
|
495
|
+
|
|
496
|
+
Tentative rules:
|
|
497
|
+
|
|
498
|
+
1. Roots must differ in length.
|
|
499
|
+
2. If one value is null (attribute not present) and the other a string, the one with the string value trumps.
|
|
500
|
+
3. If two or more equivalent attributes have string values, the one with the longer root prevails.
|
|
501
|
+
|
|
502
|
+
The thinking here is that longer roots indicate higher "specificity", so it is safer to use that one.
|
|
503
|
+
|
|
418
504
|
## Preemptive downloading
|
|
419
505
|
|
|
420
506
|
There are two significant steps to imports, each of which imposes a cost:
|
|
@@ -434,7 +520,7 @@ const observer = new MountObserver({
|
|
|
434
520
|
loading: 'eager',
|
|
435
521
|
import: './my-element.js',
|
|
436
522
|
do:{
|
|
437
|
-
mount: (matchingElement, {
|
|
523
|
+
mount: (matchingElement, {modules}) => customElements.define(modules[0].MyElement)
|
|
438
524
|
}
|
|
439
525
|
})
|
|
440
526
|
```
|
|
@@ -447,21 +533,22 @@ This proposal "sneaks in" one more feature, that perhaps should stand separately
|
|
|
447
533
|
|
|
448
534
|
Also, this proposal is partly focused on better management of importing resources "from a distance", in particular via imports carried out via http. Is it such a stretch to look closely at scenarios where that distance happens to be shorter, i.e. found somewhere [in the document tree structure](https://github.com/tc39/proposal-module-expressions)?
|
|
449
535
|
|
|
450
|
-
The mount-observer is always on the lookout for template tags with
|
|
536
|
+
The mount-observer is always on the lookout for template tags with a src attribute starting with #:
|
|
451
537
|
|
|
452
538
|
```html
|
|
453
|
-
<template
|
|
539
|
+
<template src=#id-of-source-template></template>
|
|
454
540
|
```
|
|
455
541
|
|
|
456
542
|
For example:
|
|
457
543
|
|
|
458
544
|
```html
|
|
459
|
-
<div>
|
|
460
|
-
<
|
|
461
|
-
|
|
462
|
-
<
|
|
545
|
+
<div>Your Mother Should Know</div>
|
|
546
|
+
<div>I Am the Walrus</div>
|
|
547
|
+
<template src=#id-of-source-template>
|
|
548
|
+
<span slot=slot1>hello</span>
|
|
549
|
+
<span slot=slot2>goodbye<span>
|
|
463
550
|
</template>
|
|
464
|
-
<div>
|
|
551
|
+
<div>Strawberry Fields Forever</div>
|
|
465
552
|
```
|
|
466
553
|
|
|
467
554
|
When it encounters such a thing, it searches "upwardly" through the chain of ShadowRoots for a template with id=id-of-source-template (in this case), and caches them as it finds them.
|
|
@@ -470,9 +557,7 @@ Let's say the source template looks as follows:
|
|
|
470
557
|
|
|
471
558
|
```html
|
|
472
559
|
<template id=id-of-source-template>
|
|
473
|
-
|
|
474
|
-
<slot name=slot1></slot>
|
|
475
|
-
<slot name=slot2></slot>
|
|
560
|
+
<div>I don't know why you say <slot name=slot2></slot> I say <slot name=slot1></slot></div>
|
|
476
561
|
</template>
|
|
477
562
|
```
|
|
478
563
|
|
|
@@ -480,11 +565,10 @@ What we would end up with is:
|
|
|
480
565
|
|
|
481
566
|
|
|
482
567
|
```html
|
|
483
|
-
<div>
|
|
484
|
-
|
|
485
|
-
<div>hello</div>
|
|
486
|
-
<div>
|
|
487
|
-
<div>Some additional stuff</div>
|
|
568
|
+
<div>Your Mother Should Know</div>
|
|
569
|
+
<div>I Am the Walrus</div>
|
|
570
|
+
<div>I don't know why you say <span>goodbye</span> I say <span>hello</span></div>
|
|
571
|
+
<div>Strawberry Fields Forever</div>
|
|
488
572
|
```
|
|
489
573
|
|
|
490
574
|
Some significant differences with genuine slot support as used with (ShadowDOM'd) custom elements
|
|
@@ -498,7 +582,7 @@ This proposal (and polyfill) also supports the option to utilize ShadowDOM / slo
|
|
|
498
582
|
|
|
499
583
|
```html
|
|
500
584
|
<template id=chorus>
|
|
501
|
-
<template
|
|
585
|
+
<template src=#beautiful>
|
|
502
586
|
<span slot=subjectIs>
|
|
503
587
|
<slot name=subjectIs1></slot>
|
|
504
588
|
</span>
|
|
@@ -509,7 +593,7 @@ This proposal (and polyfill) also supports the option to utilize ShadowDOM / slo
|
|
|
509
593
|
<slot name=verb1></slot> bring
|
|
510
594
|
<slot name=pronoun1></slot> down</div>
|
|
511
595
|
<div>Oh no</div>
|
|
512
|
-
<template
|
|
596
|
+
<template src=#beautiful>
|
|
513
597
|
<span slot=subjectIs>
|
|
514
598
|
<slot name=subjectIs2></slot>
|
|
515
599
|
</span>
|
|
@@ -521,11 +605,11 @@ This proposal (and polyfill) also supports the option to utilize ShadowDOM / slo
|
|
|
521
605
|
</div>
|
|
522
606
|
<div>Oh no</div>
|
|
523
607
|
|
|
524
|
-
<template
|
|
608
|
+
<template src=#down></template>
|
|
525
609
|
</template>
|
|
526
610
|
|
|
527
611
|
<div class=chorus>
|
|
528
|
-
<template
|
|
612
|
+
<template src=#chorus shadowRootModeOnLoad=open></template>
|
|
529
613
|
<span slot=verb1>can't</span>
|
|
530
614
|
<span slot=verb2>can't</span>
|
|
531
615
|
<span slot=pronoun1>me</span>
|
|
@@ -535,3 +619,13 @@ This proposal (and polyfill) also supports the option to utilize ShadowDOM / slo
|
|
|
535
619
|
</div>
|
|
536
620
|
```
|
|
537
621
|
|
|
622
|
+
> [!NOTE]
|
|
623
|
+
> An intriguing sounding alternative to using the template tag that disappears, as shown above, is to use a new tag for this purpose. I think something along the lines of what is [proposed here](https://github.com/WICG/webcomponents/issues/1059) has a much better semantic ring to it:
|
|
624
|
+
|
|
625
|
+
```html
|
|
626
|
+
<compose src="#sharedHeader"></compose>
|
|
627
|
+
<compose src="#productCard"></compose>
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
The discussion there leads to an open question whether a processing instruction would be better. I think the compose tag would make much more sense, vs a processing instruction, as it could then support slotted children (behaving similar to the Beatles' example above). Or maybe another tag should be introduced that is the equivalent of the slot, to avoid confusion. or some equivalent. But I strongly suspect that could significantly reduce the payload size of some documents, if we can reuse blocks of HTML, inserting sections of customized content for each instance.
|
|
631
|
+
|
package/birtualizeMatch.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { inclTemplQry } from './MountObserver.js';
|
|
2
2
|
export async function birtualizeMatch(self, el, level) {
|
|
3
|
-
const
|
|
4
|
-
el.removeAttribute('
|
|
5
|
-
const templID =
|
|
3
|
+
const src = el.getAttribute('src');
|
|
4
|
+
el.removeAttribute('src');
|
|
5
|
+
const templID = src.substring(1);
|
|
6
6
|
const fragment = self.objNde?.deref();
|
|
7
7
|
if (fragment === undefined)
|
|
8
8
|
return;
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -33,6 +33,11 @@ export interface WhereAttr{
|
|
|
33
33
|
hasBase: string | [delimiter, string],
|
|
34
34
|
hasBranchIn?: Array<string> | [delimiter, Array<string>],
|
|
35
35
|
hasRootIn?: Array<RootCnfg>,
|
|
36
|
+
/**
|
|
37
|
+
* Used by consumers to track the universal meaning of this combination
|
|
38
|
+
* regardless of how the actual name values may be changed.
|
|
39
|
+
*/
|
|
40
|
+
metadata?: any,
|
|
36
41
|
}
|
|
37
42
|
type CSSMatch = string;
|
|
38
43
|
type ImportString = string;
|
|
@@ -51,7 +56,7 @@ export interface IMountObserver {
|
|
|
51
56
|
// readonly mountedRefs: WeakRef<Element>[],
|
|
52
57
|
// readonly dismountedRefs: WeakRef<Element>[],
|
|
53
58
|
observe(within: Node): void;
|
|
54
|
-
|
|
59
|
+
disconnect(within: Node): void;
|
|
55
60
|
module?: any;
|
|
56
61
|
}
|
|
57
62
|
|
|
@@ -61,7 +66,7 @@ export interface MountContext{
|
|
|
61
66
|
}
|
|
62
67
|
|
|
63
68
|
type PipelineStage = 'Inspecting' | 'PreImport' | 'PostImport' | 'Import'
|
|
64
|
-
export type PipelineProcessor<ReturnType = void> = (matchingElement: Element, observer: IMountObserver, ctx: MountContext) => Promise<ReturnType
|
|
69
|
+
export type PipelineProcessor<ReturnType = void> = (matchingElement: Element, observer: IMountObserver, ctx: MountContext) => Promise<ReturnType> | ReturnType;
|
|
65
70
|
|
|
66
71
|
//#region mutation event
|
|
67
72
|
export type mutationEventName = 'mutation-event';
|
|
@@ -83,7 +88,8 @@ interface AttrParts{
|
|
|
83
88
|
branchIdx: number,
|
|
84
89
|
leaf?: string, //TODO
|
|
85
90
|
leafIdx?: number, //TODO
|
|
86
|
-
rootCnfg?: RootCnfg
|
|
91
|
+
rootCnfg?: RootCnfg,
|
|
92
|
+
metadata?: any,
|
|
87
93
|
}
|
|
88
94
|
|
|
89
95
|
interface AttrChangeInfo{
|