@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.
Files changed (2) hide show
  1. package/client/index.js +100 -127
  2. 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 CustomEvent) {
158
- const { identifier, attribute, target } = e.detail;
159
- if (identifier in this && target instanceof HTMLElement && attribute in target) {
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(attribute)) {
163
- target.toggleAttribute(attribute, ref.valueOf());
167
+ if (booleanAttributes.includes(key)) {
168
+ target.toggleAttribute(key, ref.valueOf());
164
169
  } else {
165
- target.setAttribute(attribute, `${ref}`);
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 CustomEvent) {
174
- const { identifier, attribute, target } = e.detail;
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(attribute, ref.valueOf());
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 CustomEvent) {
186
- const { identifier, type: type2, target } = e.detail;
187
- if (identifier in this && typeof this.lookup(identifier) === "function") {
188
- target.addEventListener(type2, this.lookup(identifier).bind(this));
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 CustomEvent) {
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 CustomEvent) {
217
- const { identifier, target } = e.detail;
218
- if (identifier in this && typeof this.lookup(identifier) === "function") {
219
- const cleanup = this.lookup(identifier).bind(this)(target);
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 CustomEvent) {
229
- const { identifier, property, target } = e.detail;
230
- if (identifier in this && property in target) {
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[property])) {
234
- target[property].value = ref.valueOf();
240
+ if (isState(target[key])) {
241
+ target[key].value = ref.valueOf();
235
242
  } else {
236
- target[property] = ref.valueOf();
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 CustomEvent) {
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 CustomEvent) {
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 CustomEvent) {
269
- const { identifier, property, target } = e.detail;
270
- if (identifier in this && target instanceof HTMLElement && property in target) {
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[property];
274
- target.addEventListener(bindingConfig[property].event, () => {
275
- state.value = target[property];
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[property] = state.value;
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 CustomEvent("rad::attr", {
293
- bubbles: true,
294
- cancelable: true,
295
- composed: true,
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 CustomEvent("rad::bind", {
308
- bubbles: true,
309
- cancelable: true,
310
- composed: true,
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 CustomEvent("rad::bool", {
326
- bubbles: true,
327
- cancelable: true,
328
- composed: true,
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 CustomEvent("rad::classlist", {
340
- bubbles: true,
341
- cancelable: true,
342
- composed: true,
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 CustomEvent("rad::html", {
353
- bubbles: true,
354
- cancelable: true,
355
- composed: true,
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 CustomEvent("rad::on", {
368
- bubbles: true,
369
- cancelable: true,
370
- composed: true,
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 CustomEvent("rad::prop", {
384
- bubbles: true,
385
- cancelable: true,
386
- composed: true,
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 CustomEvent("rad::text", {
398
- bubbles: true,
399
- cancelable: true,
400
- composed: true,
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 CustomEvent("rad::use", {
413
- bubbles: true,
414
- cancelable: true,
415
- composed: true,
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
- let child = node.firstElementChild;
434
- while (child) {
435
- this.hydrate(child);
436
- child = child.nextElementSibling;
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.currentNode;
472
- while (current && !(current instanceof HandlerRegistry)) {
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.4.1",
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.8.0"
36
+ "@preact/signals-core": "^1.10.0"
37
37
  },
38
38
  "devDependencies": {
39
- "tsup": "^8.4.0",
40
- "typescript": "^5.7.3"
39
+ "tsup": "^8.5.0",
40
+ "typescript": "^5.8.3"
41
41
  },
42
42
  "scripts": {
43
43
  "build": "tsup"