p-elements-core 1.2.32-rc8 → 1.2.32
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/.editorconfig +17 -17
- package/.gitlab-ci.yml +18 -18
- package/CHANGELOG.md +201 -201
- package/demo/sample.js +1 -1
- package/demo/screen.css +16 -16
- package/dist/p-elements-core-modern.js +1 -1
- package/dist/p-elements-core.js +1 -1
- package/docs/package-lock.json +6897 -6897
- package/docs/package.json +27 -27
- package/docs/src/404.md +8 -8
- package/docs/src/_data/demos/hello-world/hello-world.tsx +35 -35
- package/docs/src/_data/demos/hello-world/index.html +10 -10
- package/docs/src/_data/demos/hello-world/project.json +7 -7
- package/docs/src/_data/demos/timer/demo-timer.tsx +120 -120
- package/docs/src/_data/demos/timer/icons.tsx +62 -62
- package/docs/src/_data/demos/timer/index.html +12 -12
- package/docs/src/_data/demos/timer/project.json +8 -8
- package/docs/src/_data/global.js +13 -13
- package/docs/src/_data/helpers.js +19 -19
- package/docs/src/_includes/layouts/base.njk +30 -30
- package/docs/src/_includes/layouts/playground.njk +40 -40
- package/docs/src/_includes/partials/app-header.njk +8 -8
- package/docs/src/_includes/partials/head.njk +14 -14
- package/docs/src/_includes/partials/nav.njk +19 -19
- package/docs/src/_includes/partials/top-nav.njk +51 -51
- package/docs/src/documentation/custom-element.md +221 -221
- package/docs/src/documentation/decorators/bind.md +71 -71
- package/docs/src/documentation/decorators/custom-element-config.md +63 -63
- package/docs/src/documentation/decorators/property.md +83 -83
- package/docs/src/documentation/decorators/query.md +66 -66
- package/docs/src/documentation/decorators/render-property-on-set.md +60 -60
- package/docs/src/documentation/decorators.md +9 -9
- package/docs/src/documentation/reactive-properties.md +53 -53
- package/docs/src/index.d.ts +25 -25
- package/docs/src/index.md +3 -3
- package/docs/src/scripts/components/app-mode-switch/app-mode-switch.css +78 -78
- package/docs/src/scripts/components/app-mode-switch/app-mode-switch.tsx +166 -166
- package/docs/src/scripts/components/app-playground/app-playground.tsx +189 -189
- package/docs/tsconfig.json +22 -22
- package/index.html +10 -2
- package/package.json +1 -1
- package/readme.md +206 -206
- package/src/custom-element-controller.ts +31 -31
- package/src/custom-element.test.ts +906 -906
- package/src/custom-element.ts +3 -8
- package/src/decorators/bind.test.ts +163 -163
- package/src/decorators/bind.ts +46 -46
- package/src/decorators/custom-element-config.ts +17 -17
- package/src/decorators/property.test.ts +279 -279
- package/src/decorators/query.test.ts +146 -146
- package/src/decorators/query.ts +12 -12
- package/src/decorators/render-property-on-set.ts +3 -3
- package/src/helpers/css.ts +71 -71
- package/src/maquette/cache.ts +35 -35
- package/src/maquette/dom.ts +115 -115
- package/src/maquette/h.ts +100 -100
- package/src/maquette/index.ts +12 -12
- package/src/maquette/interfaces.ts +536 -536
- package/src/maquette/jsx.ts +61 -61
- package/src/maquette/mapping.ts +56 -56
- package/src/maquette/projection.ts +666 -666
- package/src/maquette/projector.ts +205 -205
- package/src/sample/mixin/highlight.tsx +33 -33
- package/src/sample/sample.tsx +98 -0
|
@@ -1,205 +1,205 @@
|
|
|
1
|
-
import { applyDefaultProjectionOptions, dom } from "./dom";
|
|
2
|
-
/**
|
|
3
|
-
* A projector is used to create the real DOM from the the virtual DOM and to keep it up-to-date afterwards.
|
|
4
|
-
*
|
|
5
|
-
* You can call [[append]], [[merge]], [[insertBefore]] and [[replace]] to add the virtual DOM to the real DOM.
|
|
6
|
-
* The `renderFunction` callbacks will be called to create the real DOM immediately.
|
|
7
|
-
* Afterwards, the `renderFunction` callbacks will be called again to update the DOM on the next animation-frame after:
|
|
8
|
-
*
|
|
9
|
-
* - The Projector's [[scheduleRender]] function was called
|
|
10
|
-
* - An event handler (like `onclick`) on a rendered [[VNode]] was called.
|
|
11
|
-
*
|
|
12
|
-
* The projector stops when [[stop]] is called or when an error is thrown during rendering.
|
|
13
|
-
* It is possible to use `window.onerror` to handle these errors.
|
|
14
|
-
* Instances of [[Projector]] can be created using [[createProjector]].
|
|
15
|
-
*
|
|
16
|
-
* If you need a customized projector, please check the maquette-advanced-projector project which provides a
|
|
17
|
-
* versatile stand-in replacement.
|
|
18
|
-
*/
|
|
19
|
-
import {
|
|
20
|
-
EventHandler,
|
|
21
|
-
EventHandlerInterceptor,
|
|
22
|
-
Projection,
|
|
23
|
-
ProjectionOptions,
|
|
24
|
-
Projector,
|
|
25
|
-
ProjectorOptions,
|
|
26
|
-
ProjectorPerformanceLogger,
|
|
27
|
-
VNode,
|
|
28
|
-
VNodeProperties,
|
|
29
|
-
} from "./interfaces";
|
|
30
|
-
|
|
31
|
-
let createParentNodePath = (node: Node | null, rootNode: Element) => {
|
|
32
|
-
let parentNodePath: Node[] = [];
|
|
33
|
-
while (node && node !== rootNode) {
|
|
34
|
-
parentNodePath.push(node);
|
|
35
|
-
node = node.parentNode;
|
|
36
|
-
}
|
|
37
|
-
return parentNodePath;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
let find: <T>(items: T[], predicate: (item: T) => boolean) => T | undefined;
|
|
41
|
-
if ((Array.prototype as any).find) {
|
|
42
|
-
find = (items, predicate) => items.find(predicate);
|
|
43
|
-
} else {
|
|
44
|
-
find = (items, predicate) => items.filter(predicate)[0];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
let findVNodeByParentNodePath = (vnode: VNode, parentNodePath: Node[]): VNode | undefined => {
|
|
48
|
-
let result: VNode | undefined = vnode;
|
|
49
|
-
parentNodePath.forEach((node) => {
|
|
50
|
-
result =
|
|
51
|
-
result && result.children
|
|
52
|
-
? find(result.children, (child) => child.domNode === node)
|
|
53
|
-
: undefined;
|
|
54
|
-
});
|
|
55
|
-
return result;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
let createEventHandlerInterceptor = (
|
|
59
|
-
projector: Projector,
|
|
60
|
-
getProjection: () => Projection | undefined,
|
|
61
|
-
performanceLogger: ProjectorPerformanceLogger
|
|
62
|
-
): EventHandlerInterceptor => {
|
|
63
|
-
return (
|
|
64
|
-
propertyName: string,
|
|
65
|
-
eventHandler: EventHandler,
|
|
66
|
-
domNode: Node,
|
|
67
|
-
properties: VNodeProperties,
|
|
68
|
-
) => {
|
|
69
|
-
// modified event handler
|
|
70
|
-
return function(this: Node, evt: Event): boolean | undefined | void {
|
|
71
|
-
performanceLogger("domEvent", evt);
|
|
72
|
-
let projection = getProjection();
|
|
73
|
-
// Guard: projection may be undefined when an event handler is invoked synchronously
|
|
74
|
-
// during initial DOM creation (e.g. by a custom-element setter calling onchange).
|
|
75
|
-
if (!projection) {
|
|
76
|
-
return eventHandler.apply(this, arguments);
|
|
77
|
-
}
|
|
78
|
-
let parentNodePath = createParentNodePath(evt.currentTarget as Element, projection.domNode);
|
|
79
|
-
parentNodePath.reverse();
|
|
80
|
-
let matchingVNode = findVNodeByParentNodePath(projection.getLastRender(), parentNodePath);
|
|
81
|
-
|
|
82
|
-
projector.scheduleRender();
|
|
83
|
-
|
|
84
|
-
let result: any;
|
|
85
|
-
if (matchingVNode) {
|
|
86
|
-
/* eslint-disable prefer-rest-params */
|
|
87
|
-
let listener =
|
|
88
|
-
matchingVNode.properties![`on${evt.type}`] ??
|
|
89
|
-
(matchingVNode.properties!.on![evt.type] as { listener: EventHandler }).listener ??
|
|
90
|
-
(matchingVNode.properties!.on![evt.type] as EventHandler);
|
|
91
|
-
result = listener.apply(matchingVNode.properties!.bind || this, arguments);
|
|
92
|
-
/* eslint-enable prefer-rest-params */
|
|
93
|
-
}
|
|
94
|
-
if (result === undefined && (this as HTMLElement).hasAttribute("data-force-event-handler")) {
|
|
95
|
-
result = eventHandler.apply(this, arguments);
|
|
96
|
-
}
|
|
97
|
-
performanceLogger("domEventProcessed", evt);
|
|
98
|
-
return result;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
};
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Creates a [[Projector]] instance using the provided projectionOptions.
|
|
106
|
-
*
|
|
107
|
-
* For more information, see [[Projector]].
|
|
108
|
-
*
|
|
109
|
-
* @param projectorOptions Options that influence how the DOM is rendered and updated.
|
|
110
|
-
*/
|
|
111
|
-
export let createProjector = (projectorOptions?: ProjectorOptions): Projector => {
|
|
112
|
-
let projector: Projector;
|
|
113
|
-
let projectionOptions = applyDefaultProjectionOptions(projectorOptions);
|
|
114
|
-
let performanceLogger = projectionOptions.performanceLogger!;
|
|
115
|
-
let renderCompleted = true;
|
|
116
|
-
let scheduled: number | undefined;
|
|
117
|
-
let stopped = false;
|
|
118
|
-
let projections = [] as Projection[];
|
|
119
|
-
let renderFunctions = [] as (() => VNode)[]; // matches the projections array
|
|
120
|
-
|
|
121
|
-
let addProjection = (
|
|
122
|
-
/* one of: dom.append, dom.insertBefore, dom.replace, dom.merge */
|
|
123
|
-
domFunction: (node: Element, vnode: VNode, projectionOptions: ProjectionOptions) => Projection,
|
|
124
|
-
/* the parameter of the domFunction */
|
|
125
|
-
node: Element,
|
|
126
|
-
renderFunction: () => VNode
|
|
127
|
-
): void => {
|
|
128
|
-
let projection: Projection | undefined;
|
|
129
|
-
let getProjection = () => projection;
|
|
130
|
-
projectionOptions.eventHandlerInterceptor = createEventHandlerInterceptor(
|
|
131
|
-
projector,
|
|
132
|
-
getProjection,
|
|
133
|
-
performanceLogger
|
|
134
|
-
);
|
|
135
|
-
projection = domFunction(node, renderFunction(), projectionOptions);
|
|
136
|
-
projections.push(projection);
|
|
137
|
-
renderFunctions.push(renderFunction);
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
let doRender = () => {
|
|
141
|
-
scheduled = undefined;
|
|
142
|
-
if (!renderCompleted) {
|
|
143
|
-
return; // The last render threw an error, it should have been logged in the browser console.
|
|
144
|
-
}
|
|
145
|
-
renderCompleted = false;
|
|
146
|
-
performanceLogger("renderStart", undefined);
|
|
147
|
-
for (let i = 0; i < projections.length; i++) {
|
|
148
|
-
let updatedVnode = renderFunctions[i]();
|
|
149
|
-
performanceLogger("rendered", undefined);
|
|
150
|
-
projections[i].update(updatedVnode);
|
|
151
|
-
performanceLogger("patched", undefined);
|
|
152
|
-
}
|
|
153
|
-
performanceLogger("renderDone", undefined);
|
|
154
|
-
renderCompleted = true;
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
projector = {
|
|
158
|
-
renderNow: doRender,
|
|
159
|
-
scheduleRender: () => {
|
|
160
|
-
if (!scheduled && !stopped) {
|
|
161
|
-
scheduled = requestAnimationFrame(doRender);
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
stop: () => {
|
|
165
|
-
if (scheduled) {
|
|
166
|
-
cancelAnimationFrame(scheduled);
|
|
167
|
-
scheduled = undefined;
|
|
168
|
-
}
|
|
169
|
-
stopped = true;
|
|
170
|
-
},
|
|
171
|
-
|
|
172
|
-
resume: () => {
|
|
173
|
-
stopped = false;
|
|
174
|
-
renderCompleted = true;
|
|
175
|
-
projector.scheduleRender();
|
|
176
|
-
},
|
|
177
|
-
|
|
178
|
-
append: (parentNode, renderFunction) => {
|
|
179
|
-
addProjection(dom.append, parentNode, renderFunction);
|
|
180
|
-
},
|
|
181
|
-
|
|
182
|
-
insertBefore: (beforeNode, renderFunction) => {
|
|
183
|
-
addProjection(dom.insertBefore, beforeNode, renderFunction);
|
|
184
|
-
},
|
|
185
|
-
|
|
186
|
-
merge: (domNode, renderFunction) => {
|
|
187
|
-
addProjection(dom.merge, domNode, renderFunction);
|
|
188
|
-
},
|
|
189
|
-
|
|
190
|
-
replace: (domNode, renderFunction) => {
|
|
191
|
-
addProjection(dom.replace, domNode, renderFunction);
|
|
192
|
-
},
|
|
193
|
-
|
|
194
|
-
detach: (renderFunction) => {
|
|
195
|
-
for (let i = 0; i < renderFunctions.length; i++) {
|
|
196
|
-
if (renderFunctions[i] === renderFunction) {
|
|
197
|
-
renderFunctions.splice(i, 1);
|
|
198
|
-
return projections.splice(i, 1)[0];
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
throw new Error("renderFunction was not found");
|
|
202
|
-
},
|
|
203
|
-
};
|
|
204
|
-
return projector;
|
|
205
|
-
};
|
|
1
|
+
import { applyDefaultProjectionOptions, dom } from "./dom";
|
|
2
|
+
/**
|
|
3
|
+
* A projector is used to create the real DOM from the the virtual DOM and to keep it up-to-date afterwards.
|
|
4
|
+
*
|
|
5
|
+
* You can call [[append]], [[merge]], [[insertBefore]] and [[replace]] to add the virtual DOM to the real DOM.
|
|
6
|
+
* The `renderFunction` callbacks will be called to create the real DOM immediately.
|
|
7
|
+
* Afterwards, the `renderFunction` callbacks will be called again to update the DOM on the next animation-frame after:
|
|
8
|
+
*
|
|
9
|
+
* - The Projector's [[scheduleRender]] function was called
|
|
10
|
+
* - An event handler (like `onclick`) on a rendered [[VNode]] was called.
|
|
11
|
+
*
|
|
12
|
+
* The projector stops when [[stop]] is called or when an error is thrown during rendering.
|
|
13
|
+
* It is possible to use `window.onerror` to handle these errors.
|
|
14
|
+
* Instances of [[Projector]] can be created using [[createProjector]].
|
|
15
|
+
*
|
|
16
|
+
* If you need a customized projector, please check the maquette-advanced-projector project which provides a
|
|
17
|
+
* versatile stand-in replacement.
|
|
18
|
+
*/
|
|
19
|
+
import {
|
|
20
|
+
EventHandler,
|
|
21
|
+
EventHandlerInterceptor,
|
|
22
|
+
Projection,
|
|
23
|
+
ProjectionOptions,
|
|
24
|
+
Projector,
|
|
25
|
+
ProjectorOptions,
|
|
26
|
+
ProjectorPerformanceLogger,
|
|
27
|
+
VNode,
|
|
28
|
+
VNodeProperties,
|
|
29
|
+
} from "./interfaces";
|
|
30
|
+
|
|
31
|
+
let createParentNodePath = (node: Node | null, rootNode: Element) => {
|
|
32
|
+
let parentNodePath: Node[] = [];
|
|
33
|
+
while (node && node !== rootNode) {
|
|
34
|
+
parentNodePath.push(node);
|
|
35
|
+
node = node.parentNode;
|
|
36
|
+
}
|
|
37
|
+
return parentNodePath;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
let find: <T>(items: T[], predicate: (item: T) => boolean) => T | undefined;
|
|
41
|
+
if ((Array.prototype as any).find) {
|
|
42
|
+
find = (items, predicate) => items.find(predicate);
|
|
43
|
+
} else {
|
|
44
|
+
find = (items, predicate) => items.filter(predicate)[0];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let findVNodeByParentNodePath = (vnode: VNode, parentNodePath: Node[]): VNode | undefined => {
|
|
48
|
+
let result: VNode | undefined = vnode;
|
|
49
|
+
parentNodePath.forEach((node) => {
|
|
50
|
+
result =
|
|
51
|
+
result && result.children
|
|
52
|
+
? find(result.children, (child) => child.domNode === node)
|
|
53
|
+
: undefined;
|
|
54
|
+
});
|
|
55
|
+
return result;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
let createEventHandlerInterceptor = (
|
|
59
|
+
projector: Projector,
|
|
60
|
+
getProjection: () => Projection | undefined,
|
|
61
|
+
performanceLogger: ProjectorPerformanceLogger
|
|
62
|
+
): EventHandlerInterceptor => {
|
|
63
|
+
return (
|
|
64
|
+
propertyName: string,
|
|
65
|
+
eventHandler: EventHandler,
|
|
66
|
+
domNode: Node,
|
|
67
|
+
properties: VNodeProperties,
|
|
68
|
+
) => {
|
|
69
|
+
// modified event handler
|
|
70
|
+
return function(this: Node, evt: Event): boolean | undefined | void {
|
|
71
|
+
performanceLogger("domEvent", evt);
|
|
72
|
+
let projection = getProjection();
|
|
73
|
+
// Guard: projection may be undefined when an event handler is invoked synchronously
|
|
74
|
+
// during initial DOM creation (e.g. by a custom-element setter calling onchange).
|
|
75
|
+
if (!projection) {
|
|
76
|
+
return eventHandler.apply(this, arguments);
|
|
77
|
+
}
|
|
78
|
+
let parentNodePath = createParentNodePath(evt.currentTarget as Element, projection.domNode);
|
|
79
|
+
parentNodePath.reverse();
|
|
80
|
+
let matchingVNode = findVNodeByParentNodePath(projection.getLastRender(), parentNodePath);
|
|
81
|
+
|
|
82
|
+
projector.scheduleRender();
|
|
83
|
+
|
|
84
|
+
let result: any;
|
|
85
|
+
if (matchingVNode) {
|
|
86
|
+
/* eslint-disable prefer-rest-params */
|
|
87
|
+
let listener =
|
|
88
|
+
matchingVNode.properties![`on${evt.type}`] ??
|
|
89
|
+
(matchingVNode.properties!.on![evt.type] as { listener: EventHandler }).listener ??
|
|
90
|
+
(matchingVNode.properties!.on![evt.type] as EventHandler);
|
|
91
|
+
result = listener.apply(matchingVNode.properties!.bind || this, arguments);
|
|
92
|
+
/* eslint-enable prefer-rest-params */
|
|
93
|
+
}
|
|
94
|
+
if (result === undefined && (this as HTMLElement).hasAttribute("data-force-event-handler")) {
|
|
95
|
+
result = eventHandler.apply(this, arguments);
|
|
96
|
+
}
|
|
97
|
+
performanceLogger("domEventProcessed", evt);
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Creates a [[Projector]] instance using the provided projectionOptions.
|
|
106
|
+
*
|
|
107
|
+
* For more information, see [[Projector]].
|
|
108
|
+
*
|
|
109
|
+
* @param projectorOptions Options that influence how the DOM is rendered and updated.
|
|
110
|
+
*/
|
|
111
|
+
export let createProjector = (projectorOptions?: ProjectorOptions): Projector => {
|
|
112
|
+
let projector: Projector;
|
|
113
|
+
let projectionOptions = applyDefaultProjectionOptions(projectorOptions);
|
|
114
|
+
let performanceLogger = projectionOptions.performanceLogger!;
|
|
115
|
+
let renderCompleted = true;
|
|
116
|
+
let scheduled: number | undefined;
|
|
117
|
+
let stopped = false;
|
|
118
|
+
let projections = [] as Projection[];
|
|
119
|
+
let renderFunctions = [] as (() => VNode)[]; // matches the projections array
|
|
120
|
+
|
|
121
|
+
let addProjection = (
|
|
122
|
+
/* one of: dom.append, dom.insertBefore, dom.replace, dom.merge */
|
|
123
|
+
domFunction: (node: Element, vnode: VNode, projectionOptions: ProjectionOptions) => Projection,
|
|
124
|
+
/* the parameter of the domFunction */
|
|
125
|
+
node: Element,
|
|
126
|
+
renderFunction: () => VNode
|
|
127
|
+
): void => {
|
|
128
|
+
let projection: Projection | undefined;
|
|
129
|
+
let getProjection = () => projection;
|
|
130
|
+
projectionOptions.eventHandlerInterceptor = createEventHandlerInterceptor(
|
|
131
|
+
projector,
|
|
132
|
+
getProjection,
|
|
133
|
+
performanceLogger
|
|
134
|
+
);
|
|
135
|
+
projection = domFunction(node, renderFunction(), projectionOptions);
|
|
136
|
+
projections.push(projection);
|
|
137
|
+
renderFunctions.push(renderFunction);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
let doRender = () => {
|
|
141
|
+
scheduled = undefined;
|
|
142
|
+
if (!renderCompleted) {
|
|
143
|
+
return; // The last render threw an error, it should have been logged in the browser console.
|
|
144
|
+
}
|
|
145
|
+
renderCompleted = false;
|
|
146
|
+
performanceLogger("renderStart", undefined);
|
|
147
|
+
for (let i = 0; i < projections.length; i++) {
|
|
148
|
+
let updatedVnode = renderFunctions[i]();
|
|
149
|
+
performanceLogger("rendered", undefined);
|
|
150
|
+
projections[i].update(updatedVnode);
|
|
151
|
+
performanceLogger("patched", undefined);
|
|
152
|
+
}
|
|
153
|
+
performanceLogger("renderDone", undefined);
|
|
154
|
+
renderCompleted = true;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
projector = {
|
|
158
|
+
renderNow: doRender,
|
|
159
|
+
scheduleRender: () => {
|
|
160
|
+
if (!scheduled && !stopped) {
|
|
161
|
+
scheduled = requestAnimationFrame(doRender);
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
stop: () => {
|
|
165
|
+
if (scheduled) {
|
|
166
|
+
cancelAnimationFrame(scheduled);
|
|
167
|
+
scheduled = undefined;
|
|
168
|
+
}
|
|
169
|
+
stopped = true;
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
resume: () => {
|
|
173
|
+
stopped = false;
|
|
174
|
+
renderCompleted = true;
|
|
175
|
+
projector.scheduleRender();
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
append: (parentNode, renderFunction) => {
|
|
179
|
+
addProjection(dom.append, parentNode, renderFunction);
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
insertBefore: (beforeNode, renderFunction) => {
|
|
183
|
+
addProjection(dom.insertBefore, beforeNode, renderFunction);
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
merge: (domNode, renderFunction) => {
|
|
187
|
+
addProjection(dom.merge, domNode, renderFunction);
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
replace: (domNode, renderFunction) => {
|
|
191
|
+
addProjection(dom.replace, domNode, renderFunction);
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
detach: (renderFunction) => {
|
|
195
|
+
for (let i = 0; i < renderFunctions.length; i++) {
|
|
196
|
+
if (renderFunctions[i] === renderFunction) {
|
|
197
|
+
renderFunctions.splice(i, 1);
|
|
198
|
+
return projections.splice(i, 1)[0];
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
throw new Error("renderFunction was not found");
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
return projector;
|
|
205
|
+
};
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
export interface HighlightableInterface {
|
|
3
|
-
highlight: boolean;
|
|
4
|
-
}
|
|
5
|
-
import type { CustomElement } from "../../custom-element";
|
|
6
|
-
|
|
7
|
-
type Constructor<T> = new (...args: any[]) => T;
|
|
8
|
-
|
|
9
|
-
export const Highlightable =
|
|
10
|
-
<T extends Constructor<CustomElement>>(superClass: T) => {
|
|
11
|
-
class HighlightableElement extends superClass {
|
|
12
|
-
get highlight() {
|
|
13
|
-
return this.#highlight;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
set highlight(value) {
|
|
17
|
-
this.#highlight = value;
|
|
18
|
-
let color = "unset";
|
|
19
|
-
if (value) {
|
|
20
|
-
color = "yellow";
|
|
21
|
-
}
|
|
22
|
-
const div = this?.shadowRoot.querySelector("div");
|
|
23
|
-
if (div) {
|
|
24
|
-
div.style.backgroundColor = color;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
#highlight = false;
|
|
29
|
-
}
|
|
30
|
-
// ...and a helper render method:
|
|
31
|
-
|
|
32
|
-
return HighlightableElement as Constructor<HighlightableInterface> & T;
|
|
33
|
-
};
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
export interface HighlightableInterface {
|
|
3
|
+
highlight: boolean;
|
|
4
|
+
}
|
|
5
|
+
import type { CustomElement } from "../../custom-element";
|
|
6
|
+
|
|
7
|
+
type Constructor<T> = new (...args: any[]) => T;
|
|
8
|
+
|
|
9
|
+
export const Highlightable =
|
|
10
|
+
<T extends Constructor<CustomElement>>(superClass: T) => {
|
|
11
|
+
class HighlightableElement extends superClass {
|
|
12
|
+
get highlight() {
|
|
13
|
+
return this.#highlight;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
set highlight(value) {
|
|
17
|
+
this.#highlight = value;
|
|
18
|
+
let color = "unset";
|
|
19
|
+
if (value) {
|
|
20
|
+
color = "yellow";
|
|
21
|
+
}
|
|
22
|
+
const div = this?.shadowRoot.querySelector("div");
|
|
23
|
+
if (div) {
|
|
24
|
+
div.style.backgroundColor = color;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#highlight = false;
|
|
29
|
+
}
|
|
30
|
+
// ...and a helper render method:
|
|
31
|
+
|
|
32
|
+
return HighlightableElement as Constructor<HighlightableInterface> & T;
|
|
33
|
+
};
|
package/src/sample/sample.tsx
CHANGED
|
@@ -427,3 +427,101 @@ class SuperAnchorElement extends HTMLAnchorElement {
|
|
|
427
427
|
}
|
|
428
428
|
|
|
429
429
|
window.customElements.define("super-a", SuperAnchorElement, { extends: "a" });
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
// Bring your own projector in non shadow root element
|
|
433
|
+
@CustomElementConfig({
|
|
434
|
+
tagName: "bring-your-own-projector",
|
|
435
|
+
})
|
|
436
|
+
export class BringYourOwnProjector extends CustomElement {
|
|
437
|
+
|
|
438
|
+
constructor() {
|
|
439
|
+
super();
|
|
440
|
+
this.initProjector();
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
init() {
|
|
444
|
+
console.log("This is a lifecycle for BringYourOwnProjector");
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
initProjector() {
|
|
448
|
+
this.rootElement = document.createElement("div");
|
|
449
|
+
this.rootElement.classList.add("root");
|
|
450
|
+
this.createProjector(this.rootElement, this.render);
|
|
451
|
+
console.log("init");
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
@PropertyRenderOnSet
|
|
455
|
+
name: string = "foo";
|
|
456
|
+
|
|
457
|
+
#_doneSOmething = false;
|
|
458
|
+
|
|
459
|
+
get doneSomething() {
|
|
460
|
+
return this.#_doneSOmething;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
doItNow(value) {
|
|
464
|
+
this.#_doneSOmething = value;
|
|
465
|
+
this.renderNow();
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
rootElement: HTMLDivElement;
|
|
469
|
+
|
|
470
|
+
render() {
|
|
471
|
+
return <div>Hello {this.name} {this.doneSomething && <p>We did it!!</p>}</div>;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
connectedCallback() {
|
|
475
|
+
this.appendChild(this.rootElement);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Bring your own projector in non shadow root element
|
|
481
|
+
@CustomElementConfig({
|
|
482
|
+
tagName: "bring-your-own-projector-in-shadow-root",
|
|
483
|
+
})
|
|
484
|
+
export class BringYourOwnProjectorInShadowRoot extends CustomElement {
|
|
485
|
+
|
|
486
|
+
constructor() {
|
|
487
|
+
super();
|
|
488
|
+
this.initProjector();
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
init() {
|
|
492
|
+
console.log("This is a lifecycle for BringYourOwnProjector");
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
initProjector() {
|
|
496
|
+
this.attachShadow({ mode: "open" });
|
|
497
|
+
this.rootElement = document.createElement("div");
|
|
498
|
+
this.rootElement.classList.add("root");
|
|
499
|
+
this.createProjector(this.rootElement, this.render);
|
|
500
|
+
console.log("init");
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
@PropertyRenderOnSet
|
|
504
|
+
name: string = "foo";
|
|
505
|
+
|
|
506
|
+
#_doneSOmething = false;
|
|
507
|
+
|
|
508
|
+
get doneSomething() {
|
|
509
|
+
return this.#_doneSOmething;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
doItNow(value) {
|
|
513
|
+
this.#_doneSOmething = value;
|
|
514
|
+
this.renderNow();
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
rootElement: HTMLDivElement;
|
|
518
|
+
|
|
519
|
+
render() {
|
|
520
|
+
return <div>Hello {this.name} {this.doneSomething && <p>We did it!!</p>}</div>;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
connectedCallback() {
|
|
524
|
+
this.shadowRoot.appendChild(this.rootElement);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
}
|