@radishland/runtime 0.2.0 → 0.3.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 +76 -78
- package/client/index.js +12 -14
- package/client/utils.d.ts +2 -10
- package/client/utils.js +4 -37
- package/package.json +5 -6
package/client/boot.js
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
// src/utils.ts
|
2
|
-
var spaces_sep_by_comma = /\s*,\s*/;
|
3
2
|
var bindingConfig = {
|
4
3
|
"checked": {
|
5
4
|
type: ["boolean"],
|
@@ -13,25 +12,27 @@ var bindingConfig = {
|
|
13
12
|
|
14
13
|
// src/boot.ts
|
15
14
|
var hydrateElement = (element) => {
|
16
|
-
const attributes = [
|
17
|
-
|
18
|
-
|
19
|
-
const
|
15
|
+
const attributes = [...element.attributes];
|
16
|
+
const attr = attributes.filter((a) => a.localName.startsWith("attr:"));
|
17
|
+
for (const attribute of attr) {
|
18
|
+
const [_, key] = attribute.localName.split(":");
|
19
|
+
if (!key) throw new Error("Missing <key> in attr:<key>");
|
20
|
+
const attrRequest = new CustomEvent("rad::attr", {
|
20
21
|
bubbles: true,
|
21
22
|
cancelable: true,
|
22
23
|
composed: true,
|
23
24
|
detail: {
|
24
25
|
attribute: key,
|
25
|
-
identifier: value || key,
|
26
|
+
identifier: attribute.value || key,
|
26
27
|
target: element
|
27
28
|
}
|
28
29
|
});
|
29
30
|
element.dispatchEvent(attrRequest);
|
30
31
|
}
|
31
32
|
for (const property of Object.keys(bindingConfig)) {
|
32
|
-
if (element.hasAttribute(
|
33
|
-
const identifier = element.getAttribute(
|
34
|
-
const bindRequest = new CustomEvent("
|
33
|
+
if (element.hasAttribute(`bind:${property}`)) {
|
34
|
+
const identifier = element.getAttribute(`bind:${property}`)?.trim() || property;
|
35
|
+
const bindRequest = new CustomEvent("rad::bind", {
|
35
36
|
bubbles: true,
|
36
37
|
cancelable: true,
|
37
38
|
composed: true,
|
@@ -44,27 +45,26 @@ var hydrateElement = (element) => {
|
|
44
45
|
element.dispatchEvent(bindRequest);
|
45
46
|
}
|
46
47
|
}
|
47
|
-
const
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
}
|
48
|
+
const bools = attributes.filter((a) => a.localName.startsWith("bool:"));
|
49
|
+
for (const bool of bools) {
|
50
|
+
const [_, key] = bool.localName.split(":");
|
51
|
+
if (!key) throw new Error("Missing <key> in bool:<key>");
|
52
|
+
element.dispatchEvent(
|
53
|
+
new CustomEvent("rad::bool", {
|
54
|
+
bubbles: true,
|
55
|
+
cancelable: true,
|
56
|
+
composed: true,
|
57
|
+
detail: {
|
58
|
+
attribute: key,
|
59
|
+
identifier: bool.value || key,
|
60
|
+
target: element
|
61
|
+
}
|
62
|
+
})
|
63
|
+
);
|
64
64
|
}
|
65
|
-
const classList = element.getAttribute("
|
65
|
+
const classList = element.getAttribute("classlist");
|
66
66
|
if (classList) {
|
67
|
-
const classRequest = new CustomEvent("
|
67
|
+
const classRequest = new CustomEvent("rad::classlist", {
|
68
68
|
bubbles: true,
|
69
69
|
cancelable: true,
|
70
70
|
composed: true,
|
@@ -75,9 +75,9 @@ var hydrateElement = (element) => {
|
|
75
75
|
});
|
76
76
|
element.dispatchEvent(classRequest);
|
77
77
|
}
|
78
|
-
const html = element.getAttribute("
|
78
|
+
const html = element.getAttribute("html");
|
79
79
|
if (html) {
|
80
|
-
const htmlRequest = new CustomEvent("
|
80
|
+
const htmlRequest = new CustomEvent("rad::html", {
|
81
81
|
bubbles: true,
|
82
82
|
cancelable: true,
|
83
83
|
composed: true,
|
@@ -88,43 +88,41 @@ var hydrateElement = (element) => {
|
|
88
88
|
});
|
89
89
|
element.dispatchEvent(htmlRequest);
|
90
90
|
}
|
91
|
-
const events =
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
}
|
91
|
+
const events = attributes.filter((a) => a.localName.startsWith("on:"));
|
92
|
+
for (const event of events) {
|
93
|
+
const [_, type] = event.localName.split(":");
|
94
|
+
if (!type) throw new Error("Missing <type> in on:<type>");
|
95
|
+
const onRequest = new CustomEvent("rad::on", {
|
96
|
+
bubbles: true,
|
97
|
+
cancelable: true,
|
98
|
+
composed: true,
|
99
|
+
detail: {
|
100
|
+
type,
|
101
|
+
identifier: event.value || type,
|
102
|
+
target: element
|
103
|
+
}
|
104
|
+
});
|
105
|
+
element.dispatchEvent(onRequest);
|
107
106
|
}
|
108
|
-
const props =
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
}
|
107
|
+
const props = attributes.filter((a) => a.localName.startsWith("prop:"));
|
108
|
+
for (const prop of props) {
|
109
|
+
const [_, key] = prop.localName.split(":");
|
110
|
+
if (!key) throw new Error("Missing <key> in prop:<key>");
|
111
|
+
const propRequest = new CustomEvent("rad::prop", {
|
112
|
+
bubbles: true,
|
113
|
+
cancelable: true,
|
114
|
+
composed: true,
|
115
|
+
detail: {
|
116
|
+
property: key,
|
117
|
+
identifier: prop.value || key,
|
118
|
+
target: element
|
119
|
+
}
|
120
|
+
});
|
121
|
+
element.dispatchEvent(propRequest);
|
124
122
|
}
|
125
|
-
const text = element.getAttribute("
|
123
|
+
const text = element.getAttribute("text");
|
126
124
|
if (text) {
|
127
|
-
const textRequest = new CustomEvent("
|
125
|
+
const textRequest = new CustomEvent("rad::text", {
|
128
126
|
bubbles: true,
|
129
127
|
cancelable: true,
|
130
128
|
composed: true,
|
@@ -135,20 +133,20 @@ var hydrateElement = (element) => {
|
|
135
133
|
});
|
136
134
|
element.dispatchEvent(textRequest);
|
137
135
|
}
|
138
|
-
const hooks =
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
}
|
150
|
-
|
151
|
-
|
136
|
+
const hooks = attributes.filter((a) => a.localName.startsWith("use:"));
|
137
|
+
for (const hook of hooks) {
|
138
|
+
const [_, identifier] = hook.localName.split(":");
|
139
|
+
if (!identifier) throw new Error("Missing <id> in use:<id>");
|
140
|
+
const useRequest = new CustomEvent("rad::use", {
|
141
|
+
bubbles: true,
|
142
|
+
cancelable: true,
|
143
|
+
composed: true,
|
144
|
+
detail: {
|
145
|
+
identifier,
|
146
|
+
target: element
|
147
|
+
}
|
148
|
+
});
|
149
|
+
element.dispatchEvent(useRequest);
|
152
150
|
}
|
153
151
|
};
|
154
152
|
var hydrate = (root) => {
|
package/client/index.js
CHANGED
@@ -12,11 +12,9 @@ function type(value) {
|
|
12
12
|
if (!["object", "function"].includes(baseType)) {
|
13
13
|
return baseType;
|
14
14
|
}
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
return tag;
|
19
|
-
}
|
15
|
+
const tag = value[Symbol.toStringTag];
|
16
|
+
if (typeof tag === "string") {
|
17
|
+
return tag;
|
20
18
|
}
|
21
19
|
if (baseType === "function" && Function.prototype.toString.call(value).startsWith("class")) {
|
22
20
|
return "class";
|
@@ -283,15 +281,15 @@ var HandlerRegistry = class extends HTMLElement {
|
|
283
281
|
connectedCallback() {
|
284
282
|
console.log(`${this.tagName} connected`);
|
285
283
|
const { signal: signal2 } = this.abortController;
|
286
|
-
this.addEventListener("
|
287
|
-
this.addEventListener("
|
288
|
-
this.addEventListener("
|
289
|
-
this.addEventListener("
|
290
|
-
this.addEventListener("
|
291
|
-
this.addEventListener("
|
292
|
-
this.addEventListener("
|
293
|
-
this.addEventListener("
|
294
|
-
this.addEventListener("
|
284
|
+
this.addEventListener("rad::attr", this.#handleAttr, { signal: signal2 });
|
285
|
+
this.addEventListener("rad::bind", this.#handleBind, { signal: signal2 });
|
286
|
+
this.addEventListener("rad::bool", this.#handleBool, { signal: signal2 });
|
287
|
+
this.addEventListener("rad::classlist", this.#handleClass, { signal: signal2 });
|
288
|
+
this.addEventListener("rad::html", this.#handleHTML, { signal: signal2 });
|
289
|
+
this.addEventListener("rad::on", this.#handleOn, { signal: signal2 });
|
290
|
+
this.addEventListener("rad::prop", this.#handleProp, { signal: signal2 });
|
291
|
+
this.addEventListener("rad::text", this.#handleText, { signal: signal2 });
|
292
|
+
this.addEventListener("rad::use", this.#handleUse, { signal: signal2 });
|
295
293
|
}
|
296
294
|
disconnectedCallback() {
|
297
295
|
this.abortController.abort();
|
package/client/utils.d.ts
CHANGED
@@ -1,14 +1,6 @@
|
|
1
1
|
declare const spaces_sep_by_comma: RegExp;
|
2
|
-
/**
|
3
|
-
* Idempotent string conversion to kebab-case
|
4
|
-
*/
|
5
|
-
declare const toKebabCase: (str: string) => string;
|
6
|
-
/**
|
7
|
-
* Idempotent string conversion to PascalCase
|
8
|
-
*/
|
9
|
-
declare const toPascalCase: (str: string) => string;
|
10
2
|
type LooseAutocomplete<T extends string> = T | Omit<string, T>;
|
11
|
-
type Types = LooseAutocomplete<"null" | "undefined" | "boolean" | "number" | "bigint" | "string" | "symbol" | "function" | "class" | "array" | "date" | "error" | "regexp" | "object">;
|
3
|
+
type Types = LooseAutocomplete<"null" | "undefined" | "boolean" | "number" | "bigint" | "string" | "symbol" | "function" | "AsyncFunction" | "class" | "array" | "date" | "error" | "regexp" | "object">;
|
12
4
|
/**
|
13
5
|
* A more reliable `typeof` function
|
14
6
|
*/
|
@@ -25,4 +17,4 @@ declare const bindingConfig: {
|
|
25
17
|
};
|
26
18
|
};
|
27
19
|
|
28
|
-
export { bindingConfig, booleanAttributes, spaces_sep_by_comma,
|
20
|
+
export { bindingConfig, booleanAttributes, spaces_sep_by_comma, type };
|
package/client/utils.js
CHANGED
@@ -1,36 +1,5 @@
|
|
1
1
|
// src/utils.ts
|
2
|
-
var is_upper = /[A-Z]/;
|
3
2
|
var spaces_sep_by_comma = /\s*,\s*/;
|
4
|
-
var toKebabCase = (str) => {
|
5
|
-
let kebab = "";
|
6
|
-
for (let index = 0; index < str.length; index++) {
|
7
|
-
const char = str[index];
|
8
|
-
if (index !== 0 && is_upper.test(char)) {
|
9
|
-
kebab += `-${char.toLowerCase()}`;
|
10
|
-
} else {
|
11
|
-
kebab += char.toLowerCase();
|
12
|
-
}
|
13
|
-
}
|
14
|
-
return kebab;
|
15
|
-
};
|
16
|
-
var toPascalCase = (str) => {
|
17
|
-
let pascal = "";
|
18
|
-
let toUpper = true;
|
19
|
-
for (let index = 0; index < str.length; index++) {
|
20
|
-
const char = str[index];
|
21
|
-
if (char === "-") {
|
22
|
-
toUpper = true;
|
23
|
-
continue;
|
24
|
-
}
|
25
|
-
if (toUpper) {
|
26
|
-
pascal += char.toUpperCase();
|
27
|
-
toUpper = false;
|
28
|
-
} else {
|
29
|
-
pascal += char.toLowerCase();
|
30
|
-
}
|
31
|
-
}
|
32
|
-
return pascal;
|
33
|
-
};
|
34
3
|
function type(value) {
|
35
4
|
if (value === null) {
|
36
5
|
return "null";
|
@@ -42,11 +11,9 @@ function type(value) {
|
|
42
11
|
if (!["object", "function"].includes(baseType)) {
|
43
12
|
return baseType;
|
44
13
|
}
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
return tag;
|
49
|
-
}
|
14
|
+
const tag = value[Symbol.toStringTag];
|
15
|
+
if (typeof tag === "string") {
|
16
|
+
return tag;
|
50
17
|
}
|
51
18
|
if (baseType === "function" && Function.prototype.toString.call(value).startsWith("class")) {
|
52
19
|
return "class";
|
@@ -118,4 +85,4 @@ var bindingConfig = {
|
|
118
85
|
}
|
119
86
|
};
|
120
87
|
|
121
|
-
export { bindingConfig, booleanAttributes, spaces_sep_by_comma,
|
88
|
+
export { bindingConfig, booleanAttributes, spaces_sep_by_comma, type };
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@radishland/runtime",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.3.0",
|
4
4
|
"type": "module",
|
5
5
|
"description": "The Radish runtime",
|
6
6
|
"author": "Frédéric Crozatier",
|
@@ -12,10 +12,6 @@
|
|
12
12
|
"url": "https://github.com/radishland/radish/issues"
|
13
13
|
},
|
14
14
|
"license": "MIT",
|
15
|
-
"scripts": {
|
16
|
-
"build": "tsup",
|
17
|
-
"prepublishOnly": "pnpm build"
|
18
|
-
},
|
19
15
|
"exports": {
|
20
16
|
".": {
|
21
17
|
"import": "./client/index.js",
|
@@ -46,5 +42,8 @@
|
|
46
42
|
"devDependencies": {
|
47
43
|
"tsup": "^8.4.0",
|
48
44
|
"typescript": "^5.7.3"
|
45
|
+
},
|
46
|
+
"scripts": {
|
47
|
+
"build": "tsup"
|
49
48
|
}
|
50
|
-
}
|
49
|
+
}
|