@radishland/runtime 0.4.1 → 0.5.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/index.js +100 -127
- package/package.json +4 -4
package/client/index.js
CHANGED
|
@@ -128,6 +128,11 @@ var object = (init) => {
|
|
|
128
128
|
};
|
|
129
129
|
|
|
130
130
|
// src/handler-registry.ts
|
|
131
|
+
var DirectiveEvent = class extends CustomEvent {
|
|
132
|
+
constructor(type2, detail) {
|
|
133
|
+
super(type2, { bubbles: true, composed: true, cancelable: true, detail });
|
|
134
|
+
}
|
|
135
|
+
};
|
|
131
136
|
var HandlerRegistry = class extends HTMLElement {
|
|
132
137
|
#cleanup = [];
|
|
133
138
|
/**
|
|
@@ -154,130 +159,139 @@ var HandlerRegistry = class extends HTMLElement {
|
|
|
154
159
|
return this[identifier];
|
|
155
160
|
}
|
|
156
161
|
#handleAttr(e) {
|
|
157
|
-
if (e instanceof
|
|
158
|
-
const { identifier,
|
|
159
|
-
if (identifier in this && target instanceof HTMLElement &&
|
|
162
|
+
if (e instanceof DirectiveEvent) {
|
|
163
|
+
const { identifier, key, target } = e.detail;
|
|
164
|
+
if (identifier in this && target instanceof HTMLElement && key in target) {
|
|
160
165
|
const ref = this.lookup(identifier);
|
|
161
166
|
this.effect(() => {
|
|
162
|
-
if (booleanAttributes.includes(
|
|
163
|
-
target.toggleAttribute(
|
|
167
|
+
if (booleanAttributes.includes(key)) {
|
|
168
|
+
target.toggleAttribute(key, ref.valueOf());
|
|
164
169
|
} else {
|
|
165
|
-
target.setAttribute(
|
|
170
|
+
target.setAttribute(key, `${ref}`);
|
|
166
171
|
}
|
|
167
172
|
});
|
|
173
|
+
target.removeAttribute("attr:" + key);
|
|
168
174
|
e.stopPropagation();
|
|
169
175
|
}
|
|
170
176
|
}
|
|
171
177
|
}
|
|
172
178
|
#handleBool(e) {
|
|
173
|
-
if (e instanceof
|
|
174
|
-
const { identifier,
|
|
179
|
+
if (e instanceof DirectiveEvent) {
|
|
180
|
+
const { identifier, key, target } = e.detail;
|
|
175
181
|
if (identifier in this && target instanceof HTMLElement) {
|
|
176
182
|
const ref = this.lookup(identifier);
|
|
177
183
|
this.effect(() => {
|
|
178
|
-
target.toggleAttribute(
|
|
184
|
+
target.toggleAttribute(key, ref.valueOf());
|
|
179
185
|
});
|
|
186
|
+
target.removeAttribute("bool:" + key);
|
|
180
187
|
e.stopPropagation();
|
|
181
188
|
}
|
|
182
189
|
}
|
|
183
190
|
}
|
|
184
191
|
#handleOn(e) {
|
|
185
|
-
if (e instanceof
|
|
186
|
-
const { identifier,
|
|
187
|
-
if (identifier in this && typeof this.lookup(identifier) === "function") {
|
|
188
|
-
target.addEventListener(
|
|
192
|
+
if (e instanceof DirectiveEvent) {
|
|
193
|
+
const { identifier, key, target } = e.detail;
|
|
194
|
+
if (identifier in this && target instanceof HTMLElement && typeof this.lookup(identifier) === "function") {
|
|
195
|
+
target.addEventListener(key, this.lookup(identifier).bind(this));
|
|
196
|
+
target.removeAttribute("on:" + key);
|
|
189
197
|
e.stopPropagation();
|
|
190
198
|
}
|
|
191
199
|
}
|
|
192
200
|
}
|
|
193
201
|
#handleClass(e) {
|
|
194
|
-
if (e instanceof
|
|
202
|
+
if (e instanceof DirectiveEvent) {
|
|
195
203
|
const { identifier, target } = e.detail;
|
|
196
|
-
if (identifier in this) {
|
|
204
|
+
if (identifier in this && target instanceof HTMLElement) {
|
|
197
205
|
this.effect(() => {
|
|
198
206
|
const classList = this.lookup(identifier)?.valueOf();
|
|
199
|
-
if (classList && typeof classList === "object") {
|
|
207
|
+
if (target instanceof HTMLElement && classList && typeof classList === "object") {
|
|
200
208
|
for (const [k, v] of Object.entries(classList)) {
|
|
201
209
|
const force = !!v?.valueOf();
|
|
202
210
|
for (const className of k.split(" ")) {
|
|
203
|
-
target.classList.toggle(
|
|
204
|
-
className,
|
|
205
|
-
force
|
|
206
|
-
);
|
|
211
|
+
target.classList.toggle(className, force);
|
|
207
212
|
}
|
|
208
213
|
}
|
|
209
214
|
}
|
|
210
215
|
});
|
|
216
|
+
target.removeAttribute("classList");
|
|
211
217
|
e.stopPropagation();
|
|
212
218
|
}
|
|
213
219
|
}
|
|
214
220
|
}
|
|
215
221
|
#handleUse(e) {
|
|
216
|
-
if (e instanceof
|
|
217
|
-
const {
|
|
218
|
-
if (
|
|
219
|
-
const cleanup = this.lookup(
|
|
222
|
+
if (e instanceof DirectiveEvent) {
|
|
223
|
+
const { key, target } = e.detail;
|
|
224
|
+
if (key in this && typeof this.lookup(key) === "function" && target instanceof HTMLElement) {
|
|
225
|
+
const cleanup = this.lookup(key).bind(this)(target);
|
|
220
226
|
if (typeof cleanup === "function") {
|
|
221
227
|
this.#cleanup.push(cleanup);
|
|
222
228
|
}
|
|
229
|
+
target.removeAttribute("use:" + key);
|
|
223
230
|
e.stopPropagation();
|
|
224
231
|
}
|
|
225
232
|
}
|
|
226
233
|
}
|
|
227
234
|
#handleProp(e) {
|
|
228
|
-
if (e instanceof
|
|
229
|
-
const { identifier,
|
|
230
|
-
if (identifier in this &&
|
|
235
|
+
if (e instanceof DirectiveEvent) {
|
|
236
|
+
const { identifier, key, target } = e.detail;
|
|
237
|
+
if (identifier in this && key in target && target instanceof HTMLElement) {
|
|
231
238
|
const ref = this.lookup(identifier);
|
|
232
239
|
this.effect(() => {
|
|
233
|
-
if (isState(target[
|
|
234
|
-
target[
|
|
240
|
+
if (isState(target[key])) {
|
|
241
|
+
target[key].value = ref.valueOf();
|
|
235
242
|
} else {
|
|
236
|
-
target[
|
|
243
|
+
target[key] = ref.valueOf();
|
|
237
244
|
}
|
|
238
245
|
});
|
|
246
|
+
target.removeAttribute("prop:" + key);
|
|
239
247
|
e.stopPropagation();
|
|
240
248
|
}
|
|
241
249
|
}
|
|
242
250
|
}
|
|
243
251
|
#handleText(e) {
|
|
244
|
-
if (e instanceof
|
|
252
|
+
if (e instanceof DirectiveEvent) {
|
|
245
253
|
const { identifier, target } = e.detail;
|
|
246
254
|
if (identifier in this && target instanceof HTMLElement) {
|
|
247
255
|
const ref = this.lookup(identifier);
|
|
248
256
|
this.effect(() => {
|
|
249
257
|
target.textContent = `${ref}`;
|
|
250
258
|
});
|
|
259
|
+
target.removeAttribute("text");
|
|
251
260
|
e.stopPropagation();
|
|
252
261
|
}
|
|
253
262
|
}
|
|
254
263
|
}
|
|
255
264
|
#handleHTML(e) {
|
|
256
|
-
if (e instanceof
|
|
265
|
+
if (e instanceof DirectiveEvent) {
|
|
257
266
|
const { identifier, target } = e.detail;
|
|
258
267
|
if (identifier in this && target instanceof HTMLElement) {
|
|
259
268
|
const ref = this.lookup(identifier);
|
|
260
269
|
this.effect(() => {
|
|
261
270
|
target.innerHTML = `${ref}`;
|
|
262
271
|
});
|
|
272
|
+
target.removeAttribute("html");
|
|
263
273
|
e.stopPropagation();
|
|
264
274
|
}
|
|
265
275
|
}
|
|
266
276
|
}
|
|
267
277
|
#handleBind(e) {
|
|
268
|
-
if (e instanceof
|
|
269
|
-
const { identifier,
|
|
270
|
-
if (identifier in this && target instanceof HTMLElement &&
|
|
278
|
+
if (e instanceof DirectiveEvent) {
|
|
279
|
+
const { identifier, key, target } = e.detail;
|
|
280
|
+
if (identifier in this && target instanceof HTMLElement && key in target) {
|
|
271
281
|
const state = this.lookup(identifier);
|
|
272
282
|
if (isState(state)) {
|
|
273
|
-
state.value = target[
|
|
274
|
-
target.addEventListener(
|
|
275
|
-
|
|
276
|
-
|
|
283
|
+
state.value = target[key];
|
|
284
|
+
target.addEventListener(
|
|
285
|
+
bindingConfig[key].event,
|
|
286
|
+
() => {
|
|
287
|
+
state.value = target[key];
|
|
288
|
+
}
|
|
289
|
+
);
|
|
277
290
|
this.effect(() => {
|
|
278
|
-
target[
|
|
291
|
+
target[key] = state.value;
|
|
279
292
|
});
|
|
280
293
|
}
|
|
294
|
+
target.removeAttribute("bind:" + key);
|
|
281
295
|
e.stopPropagation();
|
|
282
296
|
}
|
|
283
297
|
}
|
|
@@ -289,30 +303,20 @@ var HandlerRegistry = class extends HTMLElement {
|
|
|
289
303
|
for (const attribute of attr) {
|
|
290
304
|
const [_, key] = attribute.localName.split(":");
|
|
291
305
|
if (!key) throw new Error("Missing <key> in attr:<key>");
|
|
292
|
-
const attrRequest = new
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
detail: {
|
|
297
|
-
attribute: key,
|
|
298
|
-
identifier: attribute.value || key,
|
|
299
|
-
target: element
|
|
300
|
-
}
|
|
306
|
+
const attrRequest = new DirectiveEvent("rad::attr", {
|
|
307
|
+
key,
|
|
308
|
+
identifier: attribute.value || key,
|
|
309
|
+
target: element
|
|
301
310
|
});
|
|
302
311
|
element.dispatchEvent(attrRequest);
|
|
303
312
|
}
|
|
304
313
|
for (const property of Object.keys(bindingConfig)) {
|
|
305
314
|
if (element.hasAttribute(`bind:${property}`)) {
|
|
306
315
|
const identifier = element.getAttribute(`bind:${property}`)?.trim() || property;
|
|
307
|
-
const bindRequest = new
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
detail: {
|
|
312
|
-
property,
|
|
313
|
-
identifier,
|
|
314
|
-
target: element
|
|
315
|
-
}
|
|
316
|
+
const bindRequest = new DirectiveEvent("rad::bind", {
|
|
317
|
+
key: property,
|
|
318
|
+
identifier,
|
|
319
|
+
target: element
|
|
316
320
|
});
|
|
317
321
|
element.dispatchEvent(bindRequest);
|
|
318
322
|
}
|
|
@@ -322,41 +326,28 @@ var HandlerRegistry = class extends HTMLElement {
|
|
|
322
326
|
const [_, key] = bool.localName.split(":");
|
|
323
327
|
if (!key) throw new Error("Missing <key> in bool:<key>");
|
|
324
328
|
element.dispatchEvent(
|
|
325
|
-
new
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
detail: {
|
|
330
|
-
attribute: key,
|
|
331
|
-
identifier: bool.value || key,
|
|
332
|
-
target: element
|
|
333
|
-
}
|
|
329
|
+
new DirectiveEvent("rad::bool", {
|
|
330
|
+
key,
|
|
331
|
+
identifier: bool.value || key,
|
|
332
|
+
target: element
|
|
334
333
|
})
|
|
335
334
|
);
|
|
336
335
|
}
|
|
337
336
|
const classList = element.getAttribute("classlist");
|
|
338
337
|
if (classList) {
|
|
339
|
-
const classRequest = new
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
detail: {
|
|
344
|
-
identifier: classList,
|
|
345
|
-
target: element
|
|
346
|
-
}
|
|
338
|
+
const classRequest = new DirectiveEvent("rad::classlist", {
|
|
339
|
+
identifier: classList,
|
|
340
|
+
key: "classList",
|
|
341
|
+
target: element
|
|
347
342
|
});
|
|
348
343
|
element.dispatchEvent(classRequest);
|
|
349
344
|
}
|
|
350
345
|
const html = element.getAttribute("html");
|
|
351
346
|
if (html) {
|
|
352
|
-
const htmlRequest = new
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
detail: {
|
|
357
|
-
identifier: html,
|
|
358
|
-
target: element
|
|
359
|
-
}
|
|
347
|
+
const htmlRequest = new DirectiveEvent("rad::html", {
|
|
348
|
+
identifier: html,
|
|
349
|
+
key: "innerHTML",
|
|
350
|
+
target: element
|
|
360
351
|
});
|
|
361
352
|
element.dispatchEvent(htmlRequest);
|
|
362
353
|
}
|
|
@@ -364,15 +355,10 @@ var HandlerRegistry = class extends HTMLElement {
|
|
|
364
355
|
for (const event of events) {
|
|
365
356
|
const [_, type2] = event.localName.split(":");
|
|
366
357
|
if (!type2) throw new Error("Missing <type> in on:<type>");
|
|
367
|
-
const onRequest = new
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
detail: {
|
|
372
|
-
type: type2,
|
|
373
|
-
identifier: event.value || type2,
|
|
374
|
-
target: element
|
|
375
|
-
}
|
|
358
|
+
const onRequest = new DirectiveEvent("rad::on", {
|
|
359
|
+
key: type2,
|
|
360
|
+
identifier: event.value || type2,
|
|
361
|
+
target: element
|
|
376
362
|
});
|
|
377
363
|
element.dispatchEvent(onRequest);
|
|
378
364
|
}
|
|
@@ -380,28 +366,19 @@ var HandlerRegistry = class extends HTMLElement {
|
|
|
380
366
|
for (const prop of props) {
|
|
381
367
|
const [_, key] = prop.localName.split(":");
|
|
382
368
|
if (!key) throw new Error("Missing <key> in prop:<key>");
|
|
383
|
-
const propRequest = new
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
detail: {
|
|
388
|
-
property: key,
|
|
389
|
-
identifier: prop.value || key,
|
|
390
|
-
target: element
|
|
391
|
-
}
|
|
369
|
+
const propRequest = new DirectiveEvent("rad::prop", {
|
|
370
|
+
key,
|
|
371
|
+
identifier: prop.value || key,
|
|
372
|
+
target: element
|
|
392
373
|
});
|
|
393
374
|
element.dispatchEvent(propRequest);
|
|
394
375
|
}
|
|
395
376
|
const text = element.getAttribute("text");
|
|
396
377
|
if (text) {
|
|
397
|
-
const textRequest = new
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
detail: {
|
|
402
|
-
identifier: text,
|
|
403
|
-
target: element
|
|
404
|
-
}
|
|
378
|
+
const textRequest = new DirectiveEvent("rad::text", {
|
|
379
|
+
identifier: text,
|
|
380
|
+
key: "textContent",
|
|
381
|
+
target: element
|
|
405
382
|
});
|
|
406
383
|
element.dispatchEvent(textRequest);
|
|
407
384
|
}
|
|
@@ -409,14 +386,10 @@ var HandlerRegistry = class extends HTMLElement {
|
|
|
409
386
|
for (const hook of hooks) {
|
|
410
387
|
const [_, identifier] = hook.localName.split(":");
|
|
411
388
|
if (!identifier) throw new Error("Missing <id> in use:<id>");
|
|
412
|
-
const useRequest = new
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
detail: {
|
|
417
|
-
identifier,
|
|
418
|
-
target: element
|
|
419
|
-
}
|
|
389
|
+
const useRequest = new DirectiveEvent("rad::use", {
|
|
390
|
+
key: identifier,
|
|
391
|
+
identifier: "",
|
|
392
|
+
target: element
|
|
420
393
|
});
|
|
421
394
|
element.dispatchEvent(useRequest);
|
|
422
395
|
}
|
|
@@ -430,11 +403,11 @@ var HandlerRegistry = class extends HTMLElement {
|
|
|
430
403
|
this.hydrate(node.shadowRoot);
|
|
431
404
|
console.log("exiting shadow root");
|
|
432
405
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
406
|
+
}
|
|
407
|
+
let child = node.firstChild;
|
|
408
|
+
while (child) {
|
|
409
|
+
this.hydrate(child);
|
|
410
|
+
child = child.nextSibling;
|
|
438
411
|
}
|
|
439
412
|
}
|
|
440
413
|
connectedCallback() {
|
|
@@ -468,13 +441,13 @@ customElements?.whenDefined("handler-registry").then(() => {
|
|
|
468
441
|
return node instanceof HandlerRegistry ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
|
|
469
442
|
}
|
|
470
443
|
);
|
|
471
|
-
let current = tw.
|
|
472
|
-
while (current
|
|
444
|
+
let current = tw.firstChild();
|
|
445
|
+
while (current) {
|
|
446
|
+
if (current instanceof HandlerRegistry) {
|
|
447
|
+
current.hydrate();
|
|
448
|
+
}
|
|
473
449
|
current = tw.nextNode();
|
|
474
450
|
}
|
|
475
|
-
if (current) {
|
|
476
|
-
current.hydrate();
|
|
477
|
-
}
|
|
478
451
|
});
|
|
479
452
|
|
|
480
453
|
export { HandlerRegistry, computed, effect, isState, reactive, signal };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@radishland/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The Radish runtime",
|
|
6
6
|
"author": "Frédéric Crozatier",
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"runtime"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@preact/signals-core": "^1.
|
|
36
|
+
"@preact/signals-core": "^1.10.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"tsup": "^8.
|
|
40
|
-
"typescript": "^5.
|
|
39
|
+
"tsup": "^8.5.0",
|
|
40
|
+
"typescript": "^5.8.3"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "tsup"
|