@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 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 = ["@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", {
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(`@bind:${property}`)) {
33
- const identifier = element.getAttribute(`@bind:${property}`)?.trim() || property;
34
- const bindRequest = new CustomEvent("@bind-request", {
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 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
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("@class");
65
+ const classList = element.getAttribute("classlist");
66
66
  if (classList) {
67
- const classRequest = new CustomEvent("@class-request", {
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("@html");
78
+ const html = element.getAttribute("html");
79
79
  if (html) {
80
- const htmlRequest = new CustomEvent("@html-request", {
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 = 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
103
- }
104
- });
105
- element.dispatchEvent(onRequest);
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 = 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
120
- }
121
- });
122
- element.dispatchEvent(propRequest);
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("@text");
123
+ const text = element.getAttribute("text");
126
124
  if (text) {
127
- const textRequest = new CustomEvent("@text-request", {
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 = 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
148
- }
149
- });
150
- element.dispatchEvent(useRequest);
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
- if (typeof value === "object" && Symbol.toStringTag in value) {
16
- const tag = value[Symbol.toStringTag];
17
- if (typeof tag === "string") {
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("@attr-request", this.#handleAttr, { signal: signal2 });
287
- this.addEventListener("@bool-request", this.#handleBool, { signal: signal2 });
288
- this.addEventListener("@class-request", this.#handleClass, { signal: signal2 });
289
- this.addEventListener("@on-request", this.#handleOn, { signal: signal2 });
290
- this.addEventListener("@use-request", this.#handleUse, { signal: signal2 });
291
- this.addEventListener("@prop-request", this.#handleProp, { signal: signal2 });
292
- this.addEventListener("@html-request", this.#handleHTML, { signal: signal2 });
293
- this.addEventListener("@text-request", this.#handleText, { signal: signal2 });
294
- this.addEventListener("@bind-request", this.#handleBind, { signal: signal2 });
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, toKebabCase, toPascalCase, type };
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
- if (typeof value === "object" && Symbol.toStringTag in value) {
46
- const tag = value[Symbol.toStringTag];
47
- if (typeof tag === "string") {
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, toKebabCase, toPascalCase, type };
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.2.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
+ }