mount-observer 0.0.32 → 0.0.34
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 +3 -0
- package/MountObserver.ts +429 -0
- package/RootMutObs.ts +40 -0
- package/Synthesizer.ts +121 -0
- package/compose.js +6 -1
- package/compose.ts +124 -0
- package/getWhereAttrSelector.ts +92 -0
- package/package.json +3 -2
- package/playwright.config.ts +29 -0
- package/ts-refs/LICENSE +21 -0
- package/ts-refs/README.md +18 -0
- package/ts-refs/be-enhanced/types.d.ts +31 -0
- package/ts-refs/be-value-added/types.d.ts +34 -0
- package/ts-refs/mount-observer/types.d.ts +201 -0
- package/ts-refs/trans-render/types.d.ts +503 -0
package/compose.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { ILoadEvent, loadEventName } from './ts-refs/mount-observer/types';
|
|
2
|
+
import { MountObserver, inclTemplQry } from './MountObserver.js';
|
|
3
|
+
|
|
4
|
+
export const childRefsKey = Symbol.for('Wr0WPVh84k+O93miuENdMA');
|
|
5
|
+
export const cloneKey = Symbol.for('LD97VKZYc02CQv23DT/6fQ');
|
|
6
|
+
|
|
7
|
+
export async function compose(
|
|
8
|
+
self: MountObserver,
|
|
9
|
+
el: HTMLTemplateElement,
|
|
10
|
+
level: number
|
|
11
|
+
){
|
|
12
|
+
if(!el.hasAttribute('src')){
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const src = el.getAttribute('src');
|
|
16
|
+
el.removeAttribute('src');
|
|
17
|
+
const templID = src!.substring(1);
|
|
18
|
+
const fragment = self.objNde?.deref() as DocumentFragment;
|
|
19
|
+
if(fragment === undefined) return;
|
|
20
|
+
const templ = self.findByID(templID, fragment);
|
|
21
|
+
if(!(templ instanceof HTMLTemplateElement)) throw 404;
|
|
22
|
+
const clone = templ.content.cloneNode(true) as DocumentFragment;
|
|
23
|
+
const slots = el.content.querySelectorAll(`[slot]`);
|
|
24
|
+
|
|
25
|
+
for(const slot of slots){
|
|
26
|
+
const name = slot.getAttribute('slot')!;
|
|
27
|
+
const slotQry = `slot[name="${name}"]`;
|
|
28
|
+
const targets = Array.from(clone.querySelectorAll(slotQry));
|
|
29
|
+
const innerTempls = clone.querySelectorAll(inclTemplQry) as NodeListOf<HTMLTemplateElement>;
|
|
30
|
+
for(const innerTempl of innerTempls){
|
|
31
|
+
const innerSlots = innerTempl.content.querySelectorAll(slotQry);
|
|
32
|
+
for(const innerSlot of innerSlots){
|
|
33
|
+
targets.push(innerSlot);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
for(const target of targets){
|
|
37
|
+
const slotClone = slot.cloneNode(true) as Element;
|
|
38
|
+
target.after(slotClone);
|
|
39
|
+
target.remove();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
await self.composeFragment(clone, level + 1);
|
|
43
|
+
const shadowRootModeOnLoad = el.getAttribute('shadowRootModeOnLoad') as null | ShadowRootMode;
|
|
44
|
+
if(shadowRootModeOnLoad === null && level === 0){
|
|
45
|
+
|
|
46
|
+
const slotMap = el.getAttribute('slotmap');
|
|
47
|
+
let map = slotMap === null ? undefined : JSON.parse(slotMap);
|
|
48
|
+
const slots = clone.querySelectorAll('[slot]');
|
|
49
|
+
for(const slot of slots){
|
|
50
|
+
if(map !== undefined){
|
|
51
|
+
const slotName = slot.slot;
|
|
52
|
+
for(const key in map){
|
|
53
|
+
if(slot.matches(key)){
|
|
54
|
+
const targetAttSymbols = map[key] as string;
|
|
55
|
+
for(const sym of targetAttSymbols){
|
|
56
|
+
switch(sym){
|
|
57
|
+
case '|':
|
|
58
|
+
slot.setAttribute('itemprop', slotName);
|
|
59
|
+
break;
|
|
60
|
+
case '$':
|
|
61
|
+
slot.setAttribute('itemscope', '');
|
|
62
|
+
slot.setAttribute('itemprop', slotName);
|
|
63
|
+
break;
|
|
64
|
+
case '@':
|
|
65
|
+
slot.setAttribute('name', slotName);
|
|
66
|
+
break;
|
|
67
|
+
case '.':
|
|
68
|
+
slot.classList.add(slotName);
|
|
69
|
+
break;
|
|
70
|
+
case '%':
|
|
71
|
+
slot.part.add(slotName);
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
slot.removeAttribute('slot');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
}
|
|
82
|
+
if(level === 0){
|
|
83
|
+
const refs: Array<WeakRef<Element>> = [];
|
|
84
|
+
for(const child of clone.children){
|
|
85
|
+
refs.push(new WeakRef(child));
|
|
86
|
+
}
|
|
87
|
+
(<any>el)[childRefsKey] = refs;
|
|
88
|
+
}
|
|
89
|
+
//if template has itemscope attribute, assume want to do some data binding before instantiating into
|
|
90
|
+
//DOM fragment.
|
|
91
|
+
let cloneStashed = false;
|
|
92
|
+
if(el.hasAttribute('itemscope')){
|
|
93
|
+
(<any>el)[cloneKey] = clone;
|
|
94
|
+
cloneStashed = true;
|
|
95
|
+
}else{
|
|
96
|
+
if(shadowRootModeOnLoad !== null){
|
|
97
|
+
const parent = el.parentElement;
|
|
98
|
+
if(parent === null) throw 404;
|
|
99
|
+
if(parent.shadowRoot === null) parent.attachShadow({mode: shadowRootModeOnLoad});
|
|
100
|
+
parent.shadowRoot?.append(clone);
|
|
101
|
+
}else{
|
|
102
|
+
el.after(clone);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if(level === 0){
|
|
106
|
+
el.dispatchEvent(new LoadEvent(clone));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if(!cloneStashed){
|
|
110
|
+
if(level !== 0 || (slots.length === 0 && el.attributes.length === 0)) el.remove();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export class LoadEvent extends Event implements ILoadEvent{
|
|
116
|
+
static eventName: loadEventName = 'load';
|
|
117
|
+
constructor(public clone: DocumentFragment){
|
|
118
|
+
super(LoadEvent.eventName);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
interface HTMLElementEventMap{
|
|
123
|
+
'load': LoadEvent,
|
|
124
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {AttrParts, RootCnfg, WhereAttr} from './ts-refs/mount-observer/types';
|
|
2
|
+
export async function getWhereAttrSelector(whereAttr: WhereAttr, withoutAttrs: string){
|
|
3
|
+
const {hasBase, hasBranchIn, hasRootIn} = whereAttr;
|
|
4
|
+
|
|
5
|
+
const fullListOfAttrs: Array<string> = [];
|
|
6
|
+
const partitionedAttrs: Array<AttrParts> = [];
|
|
7
|
+
if(hasBase !== undefined){
|
|
8
|
+
const hasRootInGuaranteed: Array<RootCnfg> = hasRootIn || [{
|
|
9
|
+
start: '',
|
|
10
|
+
context: 'Both'
|
|
11
|
+
} as RootCnfg]
|
|
12
|
+
|
|
13
|
+
let prefixLessMatches: Array<{
|
|
14
|
+
rootToBaseDelimiter: string,
|
|
15
|
+
base: string,
|
|
16
|
+
branch?: string,
|
|
17
|
+
leaf?: string //todo,
|
|
18
|
+
baseToBranchDelimiter?: string,
|
|
19
|
+
}> = [];
|
|
20
|
+
const hasBaseIsString = typeof hasBase === 'string';
|
|
21
|
+
const baseSelector = hasBaseIsString ? hasBase : hasBase[1];
|
|
22
|
+
const rootToBaseDelimiter = hasBaseIsString ? '-' : hasBase[0];
|
|
23
|
+
if(hasBranchIn !== undefined){
|
|
24
|
+
let baseToBranchDelimiter = '-';
|
|
25
|
+
let branches: Array<string> | undefined;
|
|
26
|
+
if(hasBranchIn.length === 2 && Array.isArray(hasBranchIn[1])){
|
|
27
|
+
baseToBranchDelimiter = hasBranchIn[0];
|
|
28
|
+
branches = hasBranchIn[1];
|
|
29
|
+
}else{
|
|
30
|
+
branches = hasBranchIn as Array<string>;
|
|
31
|
+
}
|
|
32
|
+
prefixLessMatches = branches.map(x => ({
|
|
33
|
+
rootToBaseDelimiter,
|
|
34
|
+
base: baseSelector,
|
|
35
|
+
baseToBranchDelimiter: x ? baseToBranchDelimiter : '',
|
|
36
|
+
branch: x
|
|
37
|
+
}));
|
|
38
|
+
}else{
|
|
39
|
+
prefixLessMatches.push({
|
|
40
|
+
rootToBaseDelimiter,
|
|
41
|
+
base: baseSelector,
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
for(const rootCnfg of hasRootInGuaranteed){
|
|
45
|
+
const {start} = rootCnfg;
|
|
46
|
+
for(const match of prefixLessMatches){
|
|
47
|
+
const {base, baseToBranchDelimiter, branch, rootToBaseDelimiter} = match;
|
|
48
|
+
let branchIdx = 0;
|
|
49
|
+
for(const prefixLessMatch of prefixLessMatches){
|
|
50
|
+
const {base, baseToBranchDelimiter, branch} = prefixLessMatch;
|
|
51
|
+
const startAndRootToBaseDelimiter = start ? `${start}${rootToBaseDelimiter}` : '';
|
|
52
|
+
//TODO: could probably reduce the size of the code below
|
|
53
|
+
if(branch){
|
|
54
|
+
//will always have branch?
|
|
55
|
+
const name = `${startAndRootToBaseDelimiter}${base}${baseToBranchDelimiter}${branch}`
|
|
56
|
+
fullListOfAttrs.push(name);
|
|
57
|
+
partitionedAttrs.push({
|
|
58
|
+
root: start,
|
|
59
|
+
name,
|
|
60
|
+
base,
|
|
61
|
+
branch,
|
|
62
|
+
branchIdx,
|
|
63
|
+
rootCnfg
|
|
64
|
+
});
|
|
65
|
+
}else{
|
|
66
|
+
const name = `${startAndRootToBaseDelimiter}${base}`;
|
|
67
|
+
fullListOfAttrs.push(name);
|
|
68
|
+
partitionedAttrs.push({
|
|
69
|
+
root: start,
|
|
70
|
+
name,
|
|
71
|
+
base,
|
|
72
|
+
rootCnfg,
|
|
73
|
+
branchIdx
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
branchIdx++;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
const listOfSelectors = fullListOfAttrs.map(s => `${withoutAttrs}[${s}]`);
|
|
85
|
+
const calculatedSelector = listOfSelectors.join(',');
|
|
86
|
+
return {
|
|
87
|
+
fullListOfAttrs,
|
|
88
|
+
calculatedSelector,
|
|
89
|
+
partitionedAttrs,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mount-observer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.34",
|
|
4
4
|
"description": "Observe and act on css matches.",
|
|
5
5
|
"main": "MountObserver.js",
|
|
6
6
|
"module": "MountObserver.js",
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
30
|
"*.js",
|
|
31
|
-
"
|
|
31
|
+
"*.ts",
|
|
32
|
+
"./ts-refs/*"
|
|
32
33
|
],
|
|
33
34
|
"types": "./ts-refs/mount-observer/types.d.ts",
|
|
34
35
|
"scripts": {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// playwright.config.ts
|
|
2
|
+
import { PlaywrightTestConfig, devices } from '@playwright/test';
|
|
3
|
+
const config: PlaywrightTestConfig = {
|
|
4
|
+
webServer: {
|
|
5
|
+
command: 'npm run serve',
|
|
6
|
+
url: 'http://localhost:3030/',
|
|
7
|
+
timeout: 120 * 1000,
|
|
8
|
+
reuseExistingServer: !process.env.CI,
|
|
9
|
+
},
|
|
10
|
+
use: {
|
|
11
|
+
baseURL: 'http://localhost:3030/',
|
|
12
|
+
},
|
|
13
|
+
projects: [
|
|
14
|
+
{
|
|
15
|
+
name: 'chromium',
|
|
16
|
+
use: { ...devices['Desktop Chrome'] },
|
|
17
|
+
},
|
|
18
|
+
//firefox lacks support for import assertions
|
|
19
|
+
{
|
|
20
|
+
name: 'firefox',
|
|
21
|
+
use: { ...devices['Desktop Firefox'] },
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'webkit',
|
|
25
|
+
use: { ...devices['Desktop Safari'] },
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
export default config;
|
package/ts-refs/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Bruce B. Anderson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# ts-refs
|
|
2
|
+
|
|
3
|
+
The recent typescript [blog post](https://devblogs.microsoft.com/typescript/announcing-typescript-5-5/#the-jsdoc-import-tag) found it amusing, it seems, to imply that developers were all quite aware that the buildless typescript Microsoft supports had support for importing modules from type definition files:
|
|
4
|
+
|
|
5
|
+
> To avoid this, developers typically had to use import(...) types in JSDoc comments.
|
|
6
|
+
|
|
7
|
+
Where were developers supposed to learn that such an option even existed?
|
|
8
|
+
|
|
9
|
+
[No](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html) [idea](https://www.google.com/search?q=jsdoc+import+types+from+type+definition+files&sca_esv=f583aec8b3671997&sxsrf=ADLYWILWHAvQOa24i969M3KTSHnvI4CCtQ%3A1722464335667&source=hp&ei=T7iqZu_wJuTzkPIP3NfOsAw&iflsig=AL9hbdgAAAAAZqrGX5766U3yi_U8VDQynbrnqQTG0duO&ved=0ahUKEwiv1PTWp9KHAxXkOUQIHdyrE8YQ4dUDCBg&uact=5&oq=jsdoc+import+types+from+type+definition+files&gs_lp=Egdnd3Mtd2l6Ii1qc2RvYyBpbXBvcnQgdHlwZXMgZnJvbSB0eXBlIGRlZmluaXRpb24gZmlsZXMyBRAhGKABMgUQIRigATIFECEYoAEyBRAhGKABMgUQIRirAjIFECEYqwJIpwpQAFgAcAB4AJABAJgBeqABeqoBAzAuMbgBA8gBAPgBAvgBAZgCAaAChgGYAwCSBwMwLjGgB5wH&sclient=gws-wiz)
|
|
10
|
+
|
|
11
|
+
Anyway, my experiments with it are promising, and I'm excited to use this feature, in order to avoid adding to the global warming that requiring compiling my ts files has to be adding to.
|
|
12
|
+
|
|
13
|
+
But I've found that a sticking point to this solution has to do with [lack of full support for bare import specifiers / import maps](https://github.com/microsoft/TypeScript/issues/43326). This causes problems when importing types from one package, which imports chains of types from another dependent package.
|
|
14
|
+
|
|
15
|
+
Having gone this far, I feel compelled to find workarounds until that critical issue is sorted out.
|
|
16
|
+
|
|
17
|
+
So the solution is this interim library, shared by projects that use this feature, via git's [submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules)
|
|
18
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Actions, Compacts, Handlers, Infractions, Positractions, Hitches } from '../trans-render/froop/types';
|
|
2
|
+
export {IEnhancement, BEAllProps} from '../trans-render/be/types';
|
|
3
|
+
|
|
4
|
+
export type Enhancement = string; //camelCase;
|
|
5
|
+
export type EnhKey = string; //lisp case;
|
|
6
|
+
export type FQN = string;
|
|
7
|
+
|
|
8
|
+
export interface PropInfo{
|
|
9
|
+
dry?: boolean;
|
|
10
|
+
ro?: boolean;
|
|
11
|
+
def?: any;
|
|
12
|
+
propName?: string,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type PropLookup = {[key: string]: PropInfo}
|
|
16
|
+
|
|
17
|
+
export interface BEConfig<TProps = any, TActions = TProps, ETProps = TProps>{
|
|
18
|
+
propDefaults?: Partial<{[key in keyof TProps]: TProps[key]}>;
|
|
19
|
+
propInfo?: Partial<{[key in keyof TProps]: PropInfo}>;
|
|
20
|
+
actions?: Actions<TProps, TActions>;
|
|
21
|
+
/**
|
|
22
|
+
* inferred actions
|
|
23
|
+
*/
|
|
24
|
+
infractions?: Infractions<TProps>,
|
|
25
|
+
compacts?: Compacts<TProps, TProps & TActions>;
|
|
26
|
+
hitch?: Hitches<TProps, TActions>
|
|
27
|
+
handlers?: Handlers<ETProps, TActions>;
|
|
28
|
+
positractions?: Positractions<TProps, TActions>;
|
|
29
|
+
watchedBranches?: Set<number>;
|
|
30
|
+
}
|
|
31
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ActionOnEventConfigs } from "trans-render/froop/types";
|
|
2
|
+
import {JSONValue} from 'trans-render/lib/types';
|
|
3
|
+
import {IEnhancement, BEAllProps} from 'trans-render/be/types';
|
|
4
|
+
|
|
5
|
+
//export type TMicroElement = HTMLLinkElement | HTMLMetaElement | HTMLDataElement | HTMLTimeElement;
|
|
6
|
+
|
|
7
|
+
export interface BVAEndUserProps extends IEnhancement{
|
|
8
|
+
beVigilant?: boolean;
|
|
9
|
+
value?: string | boolean | number | Date | JSONValue;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface BVAAllProps extends BVAEndUserProps{
|
|
13
|
+
attached?: boolean;
|
|
14
|
+
mutOptions?: MutationObserverInit;
|
|
15
|
+
valueFromTextContent?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// export interface Output{
|
|
19
|
+
// attr: string,
|
|
20
|
+
// val: string,
|
|
21
|
+
// }
|
|
22
|
+
|
|
23
|
+
export type BVAP = Partial<BVAAllProps>
|
|
24
|
+
|
|
25
|
+
export interface BVAActions{
|
|
26
|
+
hydrate(self: BVAAllProps): BVAP;
|
|
27
|
+
parseAttr(self: BVAAllProps): BVAP;
|
|
28
|
+
onValChange(self: this): void;
|
|
29
|
+
obs(self: this): void;
|
|
30
|
+
obsTC(self: this): BVAP;
|
|
31
|
+
obsAttr(self: this): BVAP;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type PropTypes = 'href' | 'content' | 'value' | 'dateTime' | 'textContent'
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
//import { MountObserver } from "./MountObserver";
|
|
2
|
+
|
|
3
|
+
export interface JSONSerializableMountInit{
|
|
4
|
+
readonly on?: CSSMatch,
|
|
5
|
+
readonly observedAttrsWhenMounted?: (string | ObservedSourceOfTruthAttribute)[],
|
|
6
|
+
readonly whereAttr?: WhereAttr,
|
|
7
|
+
readonly whereElementIntersectsWith?: IntersectionObserverInit,
|
|
8
|
+
readonly whereMediaMatches?: MediaQuery,
|
|
9
|
+
readonly import?: ImportString | [ImportString, ImportAssertions] | PipelineProcessor,
|
|
10
|
+
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ObservedSourceOfTruthAttribute<TProps = any> {
|
|
14
|
+
name: string,
|
|
15
|
+
mapsTo?: keyof TProps & string,
|
|
16
|
+
valIfNull?: any,
|
|
17
|
+
valIfFalsy?: any,
|
|
18
|
+
instanceOf?: any,
|
|
19
|
+
customParser?: (newValue: string | null, oldValue: string | null, instance: Element) => any
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface MountInit extends JSONSerializableMountInit{
|
|
23
|
+
|
|
24
|
+
readonly withTargetShadowRoot?: ShadowRoot,
|
|
25
|
+
readonly whereInstanceOf?: Array<{new(): Element}>,
|
|
26
|
+
readonly whereSatisfies?: PipelineProcessor<boolean>,
|
|
27
|
+
readonly do?: MountObserverCallbacks
|
|
28
|
+
// /**
|
|
29
|
+
// * Purpose -- there are scenarios where we may only want to affect changes that occur after the initial
|
|
30
|
+
// * server rendering, so we only want to mount elements that appear
|
|
31
|
+
// */
|
|
32
|
+
// readonly ignoreInitialMatches?: boolean,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface MountObserverCallbacks{
|
|
36
|
+
readonly mount?: PipelineProcessor,
|
|
37
|
+
readonly dismount?: PipelineProcessor,
|
|
38
|
+
readonly disconnect?: PipelineProcessor,
|
|
39
|
+
readonly reconfirm?: PipelineProcessor,
|
|
40
|
+
readonly exit?: PipelineProcessor,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface RootCnfg{
|
|
44
|
+
start: string,
|
|
45
|
+
context: 'BuiltIn' | 'CustomElement' | 'Both'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
//export type RootAttrOptions = Array<string | RootCnfg>;
|
|
49
|
+
export type delimiter = string;
|
|
50
|
+
export interface WhereAttr{
|
|
51
|
+
|
|
52
|
+
hasBase?: string | [delimiter, string],
|
|
53
|
+
hasBranchIn?: Array<string> | [delimiter, Array<string>],
|
|
54
|
+
hasRootIn?: Array<RootCnfg>,
|
|
55
|
+
/**
|
|
56
|
+
* Used by consumers to track the universal meaning of this combination
|
|
57
|
+
* regardless of how the actual name values may be changed.
|
|
58
|
+
*/
|
|
59
|
+
metadata?: any,
|
|
60
|
+
}
|
|
61
|
+
type CSSMatch = string;
|
|
62
|
+
type ImportString = string;
|
|
63
|
+
type MediaQuery = string;
|
|
64
|
+
|
|
65
|
+
export interface AttribMatch{
|
|
66
|
+
names: string[],
|
|
67
|
+
//for boolean, support true/false/mixed
|
|
68
|
+
// type?: 'number' | 'string' | 'date' | 'json-object' | 'boolean',
|
|
69
|
+
// valConverter?: (s: string) => any,
|
|
70
|
+
// validator?: (v: any) => boolean;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface IMountObserver {
|
|
74
|
+
// readonly mountInit: MountInit,
|
|
75
|
+
// readonly mountedRefs: WeakRef<Element>[],
|
|
76
|
+
// readonly dismountedRefs: WeakRef<Element>[],
|
|
77
|
+
observe(within: Node): void;
|
|
78
|
+
disconnect(within: Node): void;
|
|
79
|
+
module?: any;
|
|
80
|
+
mountedElements: WeakSet<Element>;
|
|
81
|
+
readAttrs(match: Element, branchIndexes?: Set<number>) : AttrChangeInfo[]
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface MountContext{
|
|
85
|
+
stage?: PipelineStage,
|
|
86
|
+
initializing?: boolean,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
type PipelineStage = 'Inspecting' | 'PreImport' | 'PostImport' | 'Import'
|
|
90
|
+
export type PipelineProcessor<ReturnType = void> = (matchingElement: Element, observer: IMountObserver, ctx: MountContext) => Promise<ReturnType> | ReturnType;
|
|
91
|
+
|
|
92
|
+
//#region mutation event
|
|
93
|
+
export type mutationEventName = 'mutation-event';
|
|
94
|
+
export interface MutationEvent{
|
|
95
|
+
mutationRecords: Array<MutationRecord>
|
|
96
|
+
}
|
|
97
|
+
export type mutationEventHandler = (e: MutationEvent) => void;
|
|
98
|
+
|
|
99
|
+
export interface AddMutationEventListener {
|
|
100
|
+
addEventListener(eventName: mutationEventName, handler: mutationEventHandler, options?: AddEventListenerOptions): void;
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
|
|
104
|
+
interface AttrParts{
|
|
105
|
+
name: string,
|
|
106
|
+
root?: string,
|
|
107
|
+
base?: string,
|
|
108
|
+
branch?: string,
|
|
109
|
+
branchIdx: number,
|
|
110
|
+
leaf?: string, //TODO
|
|
111
|
+
leafIdx?: number, //TODO
|
|
112
|
+
rootCnfg?: RootCnfg,
|
|
113
|
+
metadata?: any,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
interface AttrChangeInfo{
|
|
117
|
+
oldValue: string | null,
|
|
118
|
+
newValue: string | null,
|
|
119
|
+
isSOfTAttr: boolean,
|
|
120
|
+
idx?: number,
|
|
121
|
+
name: string,
|
|
122
|
+
parts?: AttrParts,
|
|
123
|
+
mapsTo?: string,
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
//#region mount event
|
|
127
|
+
export type mountEventName = 'mount';
|
|
128
|
+
export interface IMountEvent{
|
|
129
|
+
mountedElement: Element,
|
|
130
|
+
}
|
|
131
|
+
export type mountEventHandler = (e: IMountEvent) => void;
|
|
132
|
+
|
|
133
|
+
export interface AddMountEventListener {
|
|
134
|
+
addEventListener(eventName: mountEventName, handler: mountEventHandler, options?: AddEventListenerOptions): void;
|
|
135
|
+
}
|
|
136
|
+
//#endregion
|
|
137
|
+
|
|
138
|
+
//#region dismount event
|
|
139
|
+
export type dismountEventName = 'dismount';
|
|
140
|
+
export interface IDismountEvent {
|
|
141
|
+
dismountedElement: Element
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export type dismountEventHandler = (e: IDismountEvent) => void;
|
|
145
|
+
|
|
146
|
+
export interface AddDismountEventListener {
|
|
147
|
+
addEventListener(eventName: dismountEventName, handler: dismountEventHandler, options?: AddEventListenerOptions): void;
|
|
148
|
+
}
|
|
149
|
+
//#endregion
|
|
150
|
+
|
|
151
|
+
//#region disconnected event
|
|
152
|
+
export type disconnectedEventName = 'disconnect';
|
|
153
|
+
export interface IDisconnectEvent {
|
|
154
|
+
disconnectedElement: Element
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export type disconnectedEventHandler = (e: IDisconnectEvent) => void;
|
|
158
|
+
|
|
159
|
+
export interface AddDisconnectEventListener {
|
|
160
|
+
addEventListener(eventName: disconnectedEventName, handler: disconnectedEventHandler, options?: AddEventListenerOptions): void;
|
|
161
|
+
}
|
|
162
|
+
//endregion
|
|
163
|
+
|
|
164
|
+
//#region attribute change event
|
|
165
|
+
export type attrChangeEventName = 'attrChange';
|
|
166
|
+
export interface IAttrChangeEvent extends IMountEvent {
|
|
167
|
+
attrChangeInfos: Array<AttrChangeInfo>,
|
|
168
|
+
}
|
|
169
|
+
export type attrChangeEventHandler = (e: IAttrChangeEvent) => void;
|
|
170
|
+
export interface AddAttrChangeEventListener{
|
|
171
|
+
addEventListener(eventName: attrChangeEventName, handler: attrChangeEventHandler, options?: AddEventListenerOptions): void;
|
|
172
|
+
}
|
|
173
|
+
//#endregion
|
|
174
|
+
|
|
175
|
+
//#region load event
|
|
176
|
+
export type loadEventName = 'load';
|
|
177
|
+
export interface ILoadEvent {
|
|
178
|
+
clone: DocumentFragment
|
|
179
|
+
}
|
|
180
|
+
export type loadEventHandler = (e: ILoadEvent) => void;
|
|
181
|
+
export interface AddLoadEventListener{
|
|
182
|
+
addEventListener(eventName: loadEventName, handler: loadEventHandler, options?: AddEventListenerOptions): void
|
|
183
|
+
}
|
|
184
|
+
//#endregion
|
|
185
|
+
|
|
186
|
+
//#region MountObserver Script Element
|
|
187
|
+
export interface MOSEAddedProps<TSynConfig=any>{
|
|
188
|
+
init: JSONSerializableMountInit;
|
|
189
|
+
observer: IMountObserver;
|
|
190
|
+
do: MountObserverCallbacks;
|
|
191
|
+
synConfig: TSynConfig;
|
|
192
|
+
}
|
|
193
|
+
export interface MOSE<TSynConfig=any>
|
|
194
|
+
extends HTMLScriptElement, MOSEAddedProps<TSynConfig>{
|
|
195
|
+
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
//#endregion
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|