@radishland/runtime 0.1.1 → 0.2.0
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/client/boot.js +151 -128
- package/client/index.js +45 -40
- package/client/utils.d.ts +0 -2
- package/client/utils.js +0 -2
- package/package.json +1 -1
package/client/boot.js
CHANGED
@@ -2,147 +2,170 @@
|
|
2
2
|
var spaces_sep_by_comma = /\s*,\s*/;
|
3
3
|
var bindingConfig = {
|
4
4
|
"checked": {
|
5
|
-
element: ["input"],
|
6
5
|
type: ["boolean"],
|
7
6
|
event: "change"
|
8
7
|
},
|
9
8
|
"value": {
|
10
|
-
element: ["input", "select", "textarea"],
|
11
9
|
type: ["string", "number"],
|
12
10
|
event: "input"
|
13
11
|
}
|
14
12
|
};
|
15
13
|
|
16
14
|
// src/boot.ts
|
17
|
-
var
|
18
|
-
(
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
for (const hook of hooks) {
|
45
|
-
const useRequest = new CustomEvent("@use-request", {
|
46
|
-
bubbles: true,
|
47
|
-
cancelable: true,
|
48
|
-
composed: true,
|
49
|
-
detail: {
|
50
|
-
hook
|
51
|
-
}
|
52
|
-
});
|
53
|
-
entry.dispatchEvent(useRequest);
|
54
|
-
}
|
15
|
+
var hydrateElement = (element) => {
|
16
|
+
const attributes = ["@attr", "@attr|client"].map((item) => element?.getAttribute(item)).filter((attr) => attr !== null && attr !== void 0).flatMap((attr) => attr.trim().split(spaces_sep_by_comma));
|
17
|
+
for (const attribute of attributes) {
|
18
|
+
const [key, value] = attribute.split(":");
|
19
|
+
const attrRequest = new CustomEvent("@attr-request", {
|
20
|
+
bubbles: true,
|
21
|
+
cancelable: true,
|
22
|
+
composed: true,
|
23
|
+
detail: {
|
24
|
+
attribute: key,
|
25
|
+
identifier: value || key,
|
26
|
+
target: element
|
27
|
+
}
|
28
|
+
});
|
29
|
+
element.dispatchEvent(attrRequest);
|
30
|
+
}
|
31
|
+
for (const property of Object.keys(bindingConfig)) {
|
32
|
+
if (element.hasAttribute(`@bind:${property}`)) {
|
33
|
+
const identifier = element.getAttribute(`@bind:${property}`)?.trim() || property;
|
34
|
+
const bindRequest = new CustomEvent("@bind-request", {
|
35
|
+
bubbles: true,
|
36
|
+
cancelable: true,
|
37
|
+
composed: true,
|
38
|
+
detail: {
|
39
|
+
property,
|
40
|
+
identifier,
|
41
|
+
target: element
|
55
42
|
}
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
43
|
+
});
|
44
|
+
element.dispatchEvent(bindRequest);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
const booleanAttributes = element.getAttribute("@bool")?.trim().split(spaces_sep_by_comma);
|
48
|
+
if (booleanAttributes) {
|
49
|
+
for (const bool of booleanAttributes) {
|
50
|
+
const [key, value] = bool.split(":");
|
51
|
+
element.dispatchEvent(
|
52
|
+
new CustomEvent("@bool-request", {
|
53
|
+
bubbles: true,
|
54
|
+
cancelable: true,
|
55
|
+
composed: true,
|
56
|
+
detail: {
|
57
|
+
attribute: key,
|
58
|
+
identifier: value || key,
|
59
|
+
target: element
|
70
60
|
}
|
61
|
+
})
|
62
|
+
);
|
63
|
+
}
|
64
|
+
}
|
65
|
+
const classList = element.getAttribute("@class");
|
66
|
+
if (classList) {
|
67
|
+
const classRequest = new CustomEvent("@class-request", {
|
68
|
+
bubbles: true,
|
69
|
+
cancelable: true,
|
70
|
+
composed: true,
|
71
|
+
detail: {
|
72
|
+
identifier: classList,
|
73
|
+
target: element
|
74
|
+
}
|
75
|
+
});
|
76
|
+
element.dispatchEvent(classRequest);
|
77
|
+
}
|
78
|
+
const html = element.getAttribute("@html");
|
79
|
+
if (html) {
|
80
|
+
const htmlRequest = new CustomEvent("@html-request", {
|
81
|
+
bubbles: true,
|
82
|
+
cancelable: true,
|
83
|
+
composed: true,
|
84
|
+
detail: {
|
85
|
+
identifier: html,
|
86
|
+
target: element
|
87
|
+
}
|
88
|
+
});
|
89
|
+
element.dispatchEvent(htmlRequest);
|
90
|
+
}
|
91
|
+
const events = element.getAttribute("@on")?.trim().split(spaces_sep_by_comma);
|
92
|
+
if (events) {
|
93
|
+
for (const event of events) {
|
94
|
+
const [type, handler] = event.split(":");
|
95
|
+
const onRequest = new CustomEvent("@on-request", {
|
96
|
+
bubbles: true,
|
97
|
+
cancelable: true,
|
98
|
+
composed: true,
|
99
|
+
detail: {
|
100
|
+
type,
|
101
|
+
identifier: handler || type,
|
102
|
+
target: element
|
71
103
|
}
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
const htmlRequest = new CustomEvent("@html-request", {
|
89
|
-
bubbles: true,
|
90
|
-
cancelable: true,
|
91
|
-
composed: true,
|
92
|
-
detail: {
|
93
|
-
identifier
|
94
|
-
}
|
95
|
-
});
|
96
|
-
entry.dispatchEvent(htmlRequest);
|
97
|
-
}
|
98
|
-
const classList = entry.hasAttribute("@class");
|
99
|
-
if (classList) {
|
100
|
-
const identifier = entry.getAttribute("@class") || "class";
|
101
|
-
const classRequest = new CustomEvent("@class-request", {
|
102
|
-
bubbles: true,
|
103
|
-
cancelable: true,
|
104
|
-
composed: true,
|
105
|
-
detail: {
|
106
|
-
identifier
|
107
|
-
}
|
108
|
-
});
|
109
|
-
entry.dispatchEvent(classRequest);
|
110
|
-
}
|
111
|
-
const attributes = [
|
112
|
-
...entry.getAttribute("@attr")?.trim().split(spaces_sep_by_comma) ?? [],
|
113
|
-
...entry.getAttribute("@attr|client")?.trim().split(spaces_sep_by_comma) ?? []
|
114
|
-
];
|
115
|
-
if (attributes.length > 0) {
|
116
|
-
for (const attribute of attributes) {
|
117
|
-
const [key, value] = attribute.split(":");
|
118
|
-
const attrRequest = new CustomEvent("@attr-request", {
|
119
|
-
bubbles: true,
|
120
|
-
cancelable: true,
|
121
|
-
composed: true,
|
122
|
-
detail: {
|
123
|
-
attribute: key,
|
124
|
-
identifier: value || key
|
125
|
-
}
|
126
|
-
});
|
127
|
-
entry.dispatchEvent(attrRequest);
|
128
|
-
}
|
104
|
+
});
|
105
|
+
element.dispatchEvent(onRequest);
|
106
|
+
}
|
107
|
+
}
|
108
|
+
const props = element.getAttribute("@prop")?.trim().split(spaces_sep_by_comma);
|
109
|
+
if (props) {
|
110
|
+
for (const prop of props) {
|
111
|
+
const [key, value] = prop.split(":");
|
112
|
+
const propRequest = new CustomEvent("@prop-request", {
|
113
|
+
bubbles: true,
|
114
|
+
cancelable: true,
|
115
|
+
composed: true,
|
116
|
+
detail: {
|
117
|
+
property: key,
|
118
|
+
identifier: value || key,
|
119
|
+
target: element
|
129
120
|
}
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
121
|
+
});
|
122
|
+
element.dispatchEvent(propRequest);
|
123
|
+
}
|
124
|
+
}
|
125
|
+
const text = element.getAttribute("@text");
|
126
|
+
if (text) {
|
127
|
+
const textRequest = new CustomEvent("@text-request", {
|
128
|
+
bubbles: true,
|
129
|
+
cancelable: true,
|
130
|
+
composed: true,
|
131
|
+
detail: {
|
132
|
+
identifier: text,
|
133
|
+
target: element
|
134
|
+
}
|
135
|
+
});
|
136
|
+
element.dispatchEvent(textRequest);
|
137
|
+
}
|
138
|
+
const hooks = element.getAttribute("@use")?.trim().split(spaces_sep_by_comma);
|
139
|
+
if (hooks) {
|
140
|
+
for (const hook of hooks) {
|
141
|
+
const useRequest = new CustomEvent("@use-request", {
|
142
|
+
bubbles: true,
|
143
|
+
cancelable: true,
|
144
|
+
composed: true,
|
145
|
+
detail: {
|
146
|
+
identifier: hook,
|
147
|
+
target: element
|
144
148
|
}
|
149
|
+
});
|
150
|
+
element.dispatchEvent(useRequest);
|
151
|
+
}
|
152
|
+
}
|
153
|
+
};
|
154
|
+
var hydrate = (root) => {
|
155
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
156
|
+
let node = walker.currentNode;
|
157
|
+
do {
|
158
|
+
if (node instanceof Element) {
|
159
|
+
console.log(node.tagName);
|
160
|
+
hydrateElement(node);
|
161
|
+
if (node.shadowRoot) {
|
162
|
+
console.log("entering shadow root");
|
163
|
+
hydrate(node.shadowRoot);
|
164
|
+
console.log("exiting shadow root");
|
145
165
|
}
|
146
|
-
|
147
|
-
});
|
148
|
-
}
|
166
|
+
}
|
167
|
+
} while (node = walker.nextNode());
|
168
|
+
};
|
169
|
+
customElements?.whenDefined("handler-registry").then(() => {
|
170
|
+
hydrate(document.body);
|
171
|
+
});
|
package/client/index.js
CHANGED
@@ -79,12 +79,10 @@ var booleanAttributes = [
|
|
79
79
|
];
|
80
80
|
var bindingConfig = {
|
81
81
|
"checked": {
|
82
|
-
element: ["input"],
|
83
82
|
type: ["boolean"],
|
84
83
|
event: "change"
|
85
84
|
},
|
86
85
|
"value": {
|
87
|
-
element: ["input", "select", "textarea"],
|
88
86
|
type: ["string", "number"],
|
89
87
|
event: "input"
|
90
88
|
}
|
@@ -139,10 +137,9 @@ var HandlerRegistry = class extends HTMLElement {
|
|
139
137
|
*
|
140
138
|
* The `abort` method of the controller is called in the `disconnectedCallback` method. It allows to cleanup event handlers and other abortable operations
|
141
139
|
*/
|
142
|
-
abortController;
|
140
|
+
abortController = new AbortController();
|
143
141
|
constructor() {
|
144
142
|
super();
|
145
|
-
this.abortController = new AbortController();
|
146
143
|
}
|
147
144
|
/**
|
148
145
|
* Creates an effect that is automatically cleaned up when the component is disconnected
|
@@ -150,7 +147,7 @@ var HandlerRegistry = class extends HTMLElement {
|
|
150
147
|
* An optional AbortSignal can be provided to abort the effect prematurely
|
151
148
|
*/
|
152
149
|
effect(callback) {
|
153
|
-
effect(callback,
|
150
|
+
effect(callback, this.abortController);
|
154
151
|
}
|
155
152
|
/**
|
156
153
|
* Looks up an identifier on the instance
|
@@ -158,19 +155,46 @@ var HandlerRegistry = class extends HTMLElement {
|
|
158
155
|
lookup(identifier) {
|
159
156
|
return this[identifier];
|
160
157
|
}
|
158
|
+
#handleAttr(e) {
|
159
|
+
if (e instanceof CustomEvent) {
|
160
|
+
const { identifier, attribute, target } = e.detail;
|
161
|
+
if (identifier in this && target instanceof HTMLElement && attribute in target) {
|
162
|
+
const ref = this.lookup(identifier);
|
163
|
+
this.effect(() => {
|
164
|
+
if (booleanAttributes.includes(attribute)) {
|
165
|
+
target.toggleAttribute(attribute, ref.valueOf());
|
166
|
+
} else {
|
167
|
+
target.setAttribute(attribute, `${ref}`);
|
168
|
+
}
|
169
|
+
});
|
170
|
+
e.stopPropagation();
|
171
|
+
}
|
172
|
+
}
|
173
|
+
}
|
174
|
+
#handleBool(e) {
|
175
|
+
if (e instanceof CustomEvent) {
|
176
|
+
const { identifier, attribute, target } = e.detail;
|
177
|
+
if (identifier in this && target instanceof HTMLElement) {
|
178
|
+
const ref = this.lookup(identifier);
|
179
|
+
this.effect(() => {
|
180
|
+
target.toggleAttribute(attribute, ref.valueOf());
|
181
|
+
});
|
182
|
+
e.stopPropagation();
|
183
|
+
}
|
184
|
+
}
|
185
|
+
}
|
161
186
|
#handleOn(e) {
|
162
187
|
if (e instanceof CustomEvent) {
|
163
|
-
const {
|
164
|
-
if (
|
165
|
-
|
188
|
+
const { identifier, type: type2, target } = e.detail;
|
189
|
+
if (identifier in this && typeof this.lookup(identifier) === "function") {
|
190
|
+
target.addEventListener(type2, this.lookup(identifier).bind(this));
|
166
191
|
e.stopPropagation();
|
167
192
|
}
|
168
193
|
}
|
169
194
|
}
|
170
195
|
#handleClass(e) {
|
171
|
-
|
172
|
-
|
173
|
-
const { identifier } = e.detail;
|
196
|
+
if (e instanceof CustomEvent) {
|
197
|
+
const { identifier, target } = e.detail;
|
174
198
|
if (identifier in this) {
|
175
199
|
this.effect(() => {
|
176
200
|
const classList = this.lookup(identifier)?.valueOf();
|
@@ -192,9 +216,9 @@ var HandlerRegistry = class extends HTMLElement {
|
|
192
216
|
}
|
193
217
|
#handleUse(e) {
|
194
218
|
if (e instanceof CustomEvent) {
|
195
|
-
const {
|
196
|
-
if (
|
197
|
-
const cleanup = this.lookup(
|
219
|
+
const { identifier, target } = e.detail;
|
220
|
+
if (identifier in this && typeof this.lookup(identifier) === "function") {
|
221
|
+
const cleanup = this.lookup(identifier).bind(this)(target);
|
198
222
|
if (typeof cleanup === "function") {
|
199
223
|
this.#cleanup.push(cleanup);
|
200
224
|
}
|
@@ -202,28 +226,10 @@ var HandlerRegistry = class extends HTMLElement {
|
|
202
226
|
}
|
203
227
|
}
|
204
228
|
}
|
205
|
-
#handleAttr(e) {
|
206
|
-
if (e instanceof CustomEvent) {
|
207
|
-
const { identifier, attribute } = e.detail;
|
208
|
-
const target = e.target;
|
209
|
-
if (identifier in this && target instanceof HTMLElement && attribute in target) {
|
210
|
-
const ref = this.lookup(identifier);
|
211
|
-
this.effect(() => {
|
212
|
-
if (booleanAttributes.includes(attribute)) {
|
213
|
-
ref.valueOf() ? target.setAttribute(attribute, "") : target.removeAttribute(attribute);
|
214
|
-
} else {
|
215
|
-
target.setAttribute(attribute, `${ref}`);
|
216
|
-
}
|
217
|
-
});
|
218
|
-
e.stopPropagation();
|
219
|
-
}
|
220
|
-
}
|
221
|
-
}
|
222
229
|
#handleProp(e) {
|
223
230
|
if (e instanceof CustomEvent) {
|
224
|
-
const { identifier, property } = e.detail;
|
225
|
-
|
226
|
-
if (identifier in this && target && property in target) {
|
231
|
+
const { identifier, property, target } = e.detail;
|
232
|
+
if (identifier in this && property in target) {
|
227
233
|
const ref = this.lookup(identifier);
|
228
234
|
this.effect(() => {
|
229
235
|
target[property] = ref.valueOf();
|
@@ -234,8 +240,7 @@ var HandlerRegistry = class extends HTMLElement {
|
|
234
240
|
}
|
235
241
|
#handleText(e) {
|
236
242
|
if (e instanceof CustomEvent) {
|
237
|
-
const target = e.
|
238
|
-
const { identifier } = e.detail;
|
243
|
+
const { identifier, target } = e.detail;
|
239
244
|
if (identifier in this && target instanceof HTMLElement) {
|
240
245
|
const ref = this.lookup(identifier);
|
241
246
|
this.effect(() => {
|
@@ -247,8 +252,7 @@ var HandlerRegistry = class extends HTMLElement {
|
|
247
252
|
}
|
248
253
|
#handleHTML(e) {
|
249
254
|
if (e instanceof CustomEvent) {
|
250
|
-
const { identifier } = e.detail;
|
251
|
-
const target = e.target;
|
255
|
+
const { identifier, target } = e.detail;
|
252
256
|
if (identifier in this && target instanceof HTMLElement) {
|
253
257
|
const ref = this.lookup(identifier);
|
254
258
|
this.effect(() => {
|
@@ -260,8 +264,7 @@ var HandlerRegistry = class extends HTMLElement {
|
|
260
264
|
}
|
261
265
|
#handleBind(e) {
|
262
266
|
if (e instanceof CustomEvent) {
|
263
|
-
const { identifier, property } = e.detail;
|
264
|
-
const target = e.target;
|
267
|
+
const { identifier, property, target } = e.detail;
|
265
268
|
if (identifier in this && target instanceof HTMLElement && property in target) {
|
266
269
|
const state = this.lookup(identifier);
|
267
270
|
if (isState(state)) {
|
@@ -278,8 +281,10 @@ var HandlerRegistry = class extends HTMLElement {
|
|
278
281
|
}
|
279
282
|
}
|
280
283
|
connectedCallback() {
|
284
|
+
console.log(`${this.tagName} connected`);
|
281
285
|
const { signal: signal2 } = this.abortController;
|
282
286
|
this.addEventListener("@attr-request", this.#handleAttr, { signal: signal2 });
|
287
|
+
this.addEventListener("@bool-request", this.#handleBool, { signal: signal2 });
|
283
288
|
this.addEventListener("@class-request", this.#handleClass, { signal: signal2 });
|
284
289
|
this.addEventListener("@on-request", this.#handleOn, { signal: signal2 });
|
285
290
|
this.addEventListener("@use-request", this.#handleUse, { signal: signal2 });
|
package/client/utils.d.ts
CHANGED
@@ -16,12 +16,10 @@ declare function type(value: unknown): Types;
|
|
16
16
|
declare const booleanAttributes: string[];
|
17
17
|
declare const bindingConfig: {
|
18
18
|
checked: {
|
19
|
-
element: string[];
|
20
19
|
type: string[];
|
21
20
|
event: string;
|
22
21
|
};
|
23
22
|
value: {
|
24
|
-
element: string[];
|
25
23
|
type: string[];
|
26
24
|
event: string;
|
27
25
|
};
|
package/client/utils.js
CHANGED
@@ -109,12 +109,10 @@ var booleanAttributes = [
|
|
109
109
|
];
|
110
110
|
var bindingConfig = {
|
111
111
|
"checked": {
|
112
|
-
element: ["input"],
|
113
112
|
type: ["boolean"],
|
114
113
|
event: "change"
|
115
114
|
},
|
116
115
|
"value": {
|
117
|
-
element: ["input", "select", "textarea"],
|
118
116
|
type: ["string", "number"],
|
119
117
|
event: "input"
|
120
118
|
}
|