@radishland/runtime 0.0.8 → 0.1.1

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.
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/client/boot.js ADDED
@@ -0,0 +1,148 @@
1
+ // src/utils.ts
2
+ var spaces_sep_by_comma = /\s*,\s*/;
3
+ var bindingConfig = {
4
+ "checked": {
5
+ element: ["input"],
6
+ type: ["boolean"],
7
+ event: "change"
8
+ },
9
+ "value": {
10
+ element: ["input", "select", "textarea"],
11
+ type: ["string", "number"],
12
+ event: "input"
13
+ }
14
+ };
15
+
16
+ // src/boot.ts
17
+ var bindingsQueryString = Object.keys(bindingConfig).map(
18
+ (property) => `[\\@bind\\:${property}]`
19
+ ).join(",");
20
+ setTimeout(() => {
21
+ customElements?.whenDefined("handler-registry").then(() => {
22
+ document.querySelectorAll(
23
+ `[\\@on],[\\@use],[\\@attr],[\\@attr\\|client],[\\@prop],${bindingsQueryString},[\\@text],[\\@html]`
24
+ ).forEach(
25
+ (entry) => {
26
+ const events = entry.getAttribute("@on")?.trim()?.split(spaces_sep_by_comma);
27
+ if (events) {
28
+ for (const event of events) {
29
+ const [type, handler] = event.split(":");
30
+ const onRequest = new CustomEvent("@on-request", {
31
+ bubbles: true,
32
+ cancelable: true,
33
+ composed: true,
34
+ detail: {
35
+ type,
36
+ handler: handler || type
37
+ }
38
+ });
39
+ entry.dispatchEvent(onRequest);
40
+ }
41
+ }
42
+ const hooks = entry.getAttribute("@use")?.trim()?.split(spaces_sep_by_comma);
43
+ if (hooks) {
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
+ }
55
+ }
56
+ const props = entry.getAttribute("@prop")?.trim().split(spaces_sep_by_comma);
57
+ if (props) {
58
+ for (const prop of props) {
59
+ const [key, value] = prop.split(":");
60
+ const propRequest = new CustomEvent("@prop-request", {
61
+ bubbles: true,
62
+ cancelable: true,
63
+ composed: true,
64
+ detail: {
65
+ property: key,
66
+ identifier: value || key
67
+ }
68
+ });
69
+ entry.dispatchEvent(propRequest);
70
+ }
71
+ }
72
+ const text = entry.hasAttribute("@text");
73
+ if (text) {
74
+ const identifier = entry.getAttribute("@text") || "text";
75
+ const textRequest = new CustomEvent("@text-request", {
76
+ bubbles: true,
77
+ cancelable: true,
78
+ composed: true,
79
+ detail: {
80
+ identifier
81
+ }
82
+ });
83
+ entry.dispatchEvent(textRequest);
84
+ }
85
+ const html = entry.hasAttribute("@html");
86
+ if (html) {
87
+ const identifier = entry.getAttribute("@html") || "html";
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
+ }
129
+ }
130
+ for (const property of Object.keys(bindingConfig)) {
131
+ if (entry.hasAttribute(`@bind:${property}`)) {
132
+ const identifier = entry.getAttribute(`@bind:${property}`)?.trim() || property;
133
+ const bindRequest = new CustomEvent("@bind-request", {
134
+ bubbles: true,
135
+ cancelable: true,
136
+ composed: true,
137
+ detail: {
138
+ property,
139
+ identifier
140
+ }
141
+ });
142
+ entry.dispatchEvent(bindRequest);
143
+ }
144
+ }
145
+ }
146
+ );
147
+ });
148
+ }, 100);
package/client/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Signal } from 'signal-polyfill';
1
+ import { Signal, ReadonlySignal } from '@preact/signals-core';
2
2
 
3
3
  interface AutonomousCustomElement {
4
4
  /**
@@ -30,7 +30,6 @@ interface AutonomousCustomElement {
30
30
  formStateRestoreCallback?(): void;
31
31
  }
32
32
 
33
- type ReactivityOptions = { deep: boolean };
34
33
  type Destructor = () => void;
35
34
  type EffectCallback = () => Destructor | void;
36
35
  type EffectOptions = {
@@ -57,33 +56,50 @@ declare class HandlerRegistry extends HTMLElement implements AutonomousCustomEle
57
56
  *
58
57
  * An optional AbortSignal can be provided to abort the effect prematurely
59
58
  */
60
- $effect(callback: EffectCallback, options?: EffectOptions): void;
59
+ effect(callback: EffectCallback): void;
60
+ /**
61
+ * Looks up an identifier on the instance
62
+ */
63
+ lookup(identifier: string): any;
61
64
  connectedCallback(): void;
62
65
  disconnectedCallback(): void;
63
66
  }
64
67
 
65
- declare class ReactiveValue<T> extends Signal.State<T> {
66
- private get;
67
- private set;
68
- get value(): T;
69
- set value(newValue: T);
70
- }
71
- declare class ReactiveComputation<T> extends Signal.Computed<T> {
72
- private get;
73
- get value(): T;
74
- }
75
- declare const $object: <T extends Record<PropertyKey, any>>(init: T, options?: ReactivityOptions) => T;
76
- declare const $array: <T extends ArrayLike<any>>(init: T, options?: ReactivityOptions) => T;
77
- declare const isState: (s: unknown) => s is InstanceType<typeof ReactiveValue>;
78
- declare const isComputed: (s: unknown) => s is InstanceType<typeof ReactiveComputation>;
79
- declare const getValue: (signal: unknown) => unknown;
80
- declare const $state: <T>(initialValue: T, options?: Signal.Options<T | undefined>) => ReactiveValue<T>;
81
- declare const $computed: <T>(computation: () => T, options?: Signal.Options<T>) => ReactiveComputation<T>;
68
+ declare const isState: (value: unknown) => value is InstanceType<typeof Signal>;
82
69
  /**
83
- * Create an unowned effect that must be cleanup up manually
70
+ * Creates a new signal
84
71
  *
85
- * Accept an AbortSignal to abort the effect
72
+ * @param value The initial value
73
+ */
74
+ declare const signal: <T>(value: T) => Signal<T>;
75
+ /**
76
+ * Creates a read-only computed signal based on the values of other signals
77
+ *
78
+ * The computed value is updated when a tracked dependency changes
79
+ *
80
+ * @param computation The callback function doing the computation
81
+ */
82
+ declare const computed: <T>(computation: () => T) => ReadonlySignal<T>;
83
+ /**
84
+ * Creates an unowned effect that must be cleaned up manually and runs arbitrary code in response to signals change.
85
+ *
86
+ * @param cb The effect callback to run when a tracked dependency changes. Can return a cleanup function, executed when the effect is re-run or is disposed of.
87
+ *
88
+ * @param options An AbortSignal can be passed to abort the effect
89
+ *
90
+ * @return a function to unsubscribe and cleanup the effect
91
+ */
92
+ declare const effect: (cb: EffectCallback, options?: EffectOptions) => Destructor;
93
+ /**
94
+ * Creates a deeply reactive proxied object or array
95
+ *
96
+ * @example const obj = reactive({ a: { b: { c: 1 } } });
97
+ const computation = computed(() => obj.a.b.c * 2});
98
+
99
+ assertEquals(computation.value, 2);
100
+ obj.a.b.c = 2;
101
+ assertEquals(computation.value, 4);
86
102
  */
87
- declare const $effect: (cb: EffectCallback, options?: EffectOptions) => Destructor;
103
+ declare const reactive: <T>(thing: T) => T;
88
104
 
89
- export { $array, $computed, $effect, $object, $state, HandlerRegistry, ReactiveComputation, ReactiveValue, getValue, isComputed, isState };
105
+ export { HandlerRegistry, computed, effect, isState, reactive, signal };
package/client/index.js CHANGED
@@ -1,6 +1,32 @@
1
- import { Signal } from 'signal-polyfill';
1
+ import { effect as effect$1, Signal, signal as signal$1, computed as computed$1 } from '@preact/signals-core';
2
2
 
3
3
  // src/utils.ts
4
+ function type(value) {
5
+ if (value === null) {
6
+ return "null";
7
+ }
8
+ if (value === void 0) {
9
+ return "undefined";
10
+ }
11
+ const baseType = typeof value;
12
+ if (!["object", "function"].includes(baseType)) {
13
+ return baseType;
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
+ }
20
+ }
21
+ if (baseType === "function" && Function.prototype.toString.call(value).startsWith("class")) {
22
+ return "class";
23
+ }
24
+ const className = value.constructor.name;
25
+ if (typeof className === "string" && className !== "") {
26
+ return className.toLowerCase();
27
+ }
28
+ return baseType;
29
+ }
4
30
  var booleanAttributes = [
5
31
  "allowfullscreen",
6
32
  // on <iframe>
@@ -51,8 +77,6 @@ var booleanAttributes = [
51
77
  "selected"
52
78
  // on <option>
53
79
  ];
54
-
55
- // src/config.ts
56
80
  var bindingConfig = {
57
81
  "checked": {
58
82
  element: ["input"],
@@ -65,126 +89,47 @@ var bindingConfig = {
65
89
  event: "input"
66
90
  }
67
91
  };
68
- var ReactiveValue = class extends Signal.State {
69
- // @ts-ignore see above
70
- get;
71
- // @ts-ignore see above
72
- set;
73
- get value() {
74
- return super.get();
75
- }
76
- set value(newValue) {
77
- super.set(newValue);
78
- }
92
+ var isState = (value) => {
93
+ return value instanceof Signal;
79
94
  };
80
- var ReactiveComputation = class extends Signal.Computed {
81
- // @ts-ignore see above
82
- get;
83
- get value() {
84
- return super.get();
85
- }
95
+ var signal = (value) => {
96
+ return signal$1(value);
86
97
  };
87
- var maybeReactiveObjectType = (thing, options) => {
88
- if (typeof thing === "object") {
89
- if (Array.isArray(thing)) {
90
- return $array(thing, options);
91
- } else if (thing) {
92
- return $object(thing, options);
93
- }
94
- }
95
- return thing;
98
+ var computed = (computation) => {
99
+ return computed$1(computation);
96
100
  };
97
- var $object = (init, options = { deep: false }) => {
98
- if (options.deep === true) {
99
- for (const [key, value] of Object.entries(init)) {
100
- init[key] = maybeReactiveObjectType(value, options);
101
- }
101
+ var effect = (cb, options) => {
102
+ if (options?.signal.aborted) return () => {
103
+ };
104
+ const dispose = effect$1(cb);
105
+ options?.signal.addEventListener("abort", dispose);
106
+ return dispose;
107
+ };
108
+ var reactive = (thing) => {
109
+ if (type(thing) === "object" || type(thing) === "array") {
110
+ return object(thing);
102
111
  }
103
- const state = new Signal.State(init);
104
- const proxy = new Proxy(init, {
105
- get(_target, p, _receiver) {
106
- return state.get()[p];
107
- },
108
- set(_target, p, newValue, _receiver) {
109
- state.set({
110
- ...state.get(),
111
- [p]: maybeReactiveObjectType(newValue, options)
112
- });
113
- return true;
114
- }
115
- });
116
- return proxy;
112
+ return thing;
117
113
  };
118
- var $array = (init, options = { deep: false }) => {
119
- if (options.deep) {
120
- for (const [key, value] of Object.entries(init)) {
121
- init[key] = maybeReactiveObjectType(value, options);
122
- }
114
+ var object = (init) => {
115
+ for (const [key, value] of Object.entries(init)) {
116
+ init[key] = reactive(value);
123
117
  }
124
- const state = new Signal.State(init);
118
+ const state = signal(init);
125
119
  const proxy = new Proxy(init, {
126
120
  get(_target, p, _receiver) {
127
- return state.get()[p];
121
+ return state.value[p];
128
122
  },
129
123
  set(_target, p, newValue, _receiver) {
130
- state.set({
131
- ...state.get(),
132
- [p]: maybeReactiveObjectType(newValue, options)
133
- });
124
+ state.value = {
125
+ ...state.value,
126
+ [p]: reactive(newValue)
127
+ };
134
128
  return true;
135
129
  }
136
130
  });
137
131
  return proxy;
138
132
  };
139
- var isState = (s) => {
140
- return Signal.isState(s);
141
- };
142
- var isComputed = (s) => {
143
- return Signal.isComputed(s);
144
- };
145
- var getValue = (signal) => {
146
- if (isState(signal) || isComputed(signal)) {
147
- return signal.value;
148
- }
149
- return signal;
150
- };
151
- var $state = (initialValue, options) => {
152
- return new ReactiveValue(initialValue, options);
153
- };
154
- var $computed = (computation, options) => {
155
- return new ReactiveComputation(computation, options);
156
- };
157
- var pending = false;
158
- var watcher = new Signal.subtle.Watcher(() => {
159
- if (!pending) {
160
- pending = true;
161
- queueMicrotask(() => {
162
- pending = false;
163
- for (const s of watcher.getPending()) s.get();
164
- watcher.watch();
165
- });
166
- }
167
- });
168
- var $effect = (cb, options) => {
169
- if (options?.signal?.aborted) return () => {
170
- };
171
- let destroy;
172
- const c = new Signal.Computed(() => {
173
- destroy?.();
174
- destroy = cb() ?? void 0;
175
- });
176
- watcher.watch(c);
177
- c.get();
178
- let cleaned = false;
179
- const cleanup = () => {
180
- if (cleaned) return;
181
- destroy?.();
182
- watcher.unwatch(c);
183
- cleaned = true;
184
- };
185
- options?.signal.addEventListener("abort", cleanup);
186
- return cleanup;
187
- };
188
133
 
189
134
  // src/handler-registry.ts
190
135
  var HandlerRegistry = class extends HTMLElement {
@@ -204,19 +149,20 @@ var HandlerRegistry = class extends HTMLElement {
204
149
  *
205
150
  * An optional AbortSignal can be provided to abort the effect prematurely
206
151
  */
207
- $effect(callback, options) {
208
- const signals = [this.abortController.signal];
209
- if (options?.signal) signals.push(options.signal);
210
- $effect(callback, { ...options, signal: AbortSignal.any(signals) });
152
+ effect(callback) {
153
+ effect(callback, { signal: this.abortController.signal });
211
154
  }
212
- #get(identifier) {
155
+ /**
156
+ * Looks up an identifier on the instance
157
+ */
158
+ lookup(identifier) {
213
159
  return this[identifier];
214
160
  }
215
161
  #handleOn(e) {
216
162
  if (e instanceof CustomEvent) {
217
- const { handler, type } = e.detail;
218
- if (handler in this && typeof this.#get(handler) === "function") {
219
- e.target?.addEventListener(type, this.#get(handler).bind(this));
163
+ const { handler, type: type2 } = e.detail;
164
+ if (handler in this && typeof this.lookup(handler) === "function") {
165
+ e.target?.addEventListener(type2, this.lookup(handler).bind(this));
220
166
  e.stopPropagation();
221
167
  }
222
168
  }
@@ -226,11 +172,11 @@ var HandlerRegistry = class extends HTMLElement {
226
172
  if (e instanceof CustomEvent && target) {
227
173
  const { identifier } = e.detail;
228
174
  if (identifier in this) {
229
- this.$effect(() => {
230
- const classList = getValue(this.#get(identifier));
175
+ this.effect(() => {
176
+ const classList = this.lookup(identifier)?.valueOf();
231
177
  if (classList && typeof classList === "object") {
232
178
  for (const [k, v] of Object.entries(classList)) {
233
- const force = !!getValue(v);
179
+ const force = !!v?.valueOf();
234
180
  for (const className of k.split(" ")) {
235
181
  target.classList.toggle(
236
182
  className,
@@ -247,8 +193,8 @@ var HandlerRegistry = class extends HTMLElement {
247
193
  #handleUse(e) {
248
194
  if (e instanceof CustomEvent) {
249
195
  const { hook } = e.detail;
250
- if (hook in this && typeof this.#get(hook) === "function") {
251
- const cleanup = this.#get(hook).bind(this)(e.target);
196
+ if (hook in this && typeof this.lookup(hook) === "function") {
197
+ const cleanup = this.lookup(hook).bind(this)(e.target);
252
198
  if (typeof cleanup === "function") {
253
199
  this.#cleanup.push(cleanup);
254
200
  }
@@ -261,20 +207,14 @@ var HandlerRegistry = class extends HTMLElement {
261
207
  const { identifier, attribute } = e.detail;
262
208
  const target = e.target;
263
209
  if (identifier in this && target instanceof HTMLElement && attribute in target) {
264
- const ref = this.#get(identifier);
265
- const setAttr = () => {
266
- const value = getValue(ref);
210
+ const ref = this.lookup(identifier);
211
+ this.effect(() => {
267
212
  if (booleanAttributes.includes(attribute)) {
268
- value ? target.setAttribute(attribute, "") : target.removeAttribute(attribute);
213
+ ref.valueOf() ? target.setAttribute(attribute, "") : target.removeAttribute(attribute);
269
214
  } else {
270
- target.setAttribute(attribute, `${value}`);
215
+ target.setAttribute(attribute, `${ref}`);
271
216
  }
272
- };
273
- if (isState(ref) || isComputed(ref)) {
274
- this.$effect(() => setAttr());
275
- } else {
276
- setAttr();
277
- }
217
+ });
278
218
  e.stopPropagation();
279
219
  }
280
220
  }
@@ -284,16 +224,10 @@ var HandlerRegistry = class extends HTMLElement {
284
224
  const { identifier, property } = e.detail;
285
225
  const target = e.target;
286
226
  if (identifier in this && target && property in target) {
287
- const ref = this.#get(identifier);
288
- const setProp = () => {
289
- const value = getValue(ref);
290
- target[property] = value;
291
- };
292
- if (isState(ref) || isComputed(ref)) {
293
- this.$effect(() => setProp());
294
- } else {
295
- setProp();
296
- }
227
+ const ref = this.lookup(identifier);
228
+ this.effect(() => {
229
+ target[property] = ref.valueOf();
230
+ });
297
231
  e.stopPropagation();
298
232
  }
299
233
  }
@@ -303,16 +237,10 @@ var HandlerRegistry = class extends HTMLElement {
303
237
  const target = e.target;
304
238
  const { identifier } = e.detail;
305
239
  if (identifier in this && target instanceof HTMLElement) {
306
- const ref = this.#get(identifier);
307
- const setTextContent = () => {
308
- const value = getValue(ref);
309
- target.textContent = `${value}`;
310
- };
311
- if (isState(ref) || isComputed(ref)) {
312
- this.$effect(() => setTextContent());
313
- } else {
314
- setTextContent();
315
- }
240
+ const ref = this.lookup(identifier);
241
+ this.effect(() => {
242
+ target.textContent = `${ref}`;
243
+ });
316
244
  e.stopPropagation();
317
245
  }
318
246
  }
@@ -322,16 +250,10 @@ var HandlerRegistry = class extends HTMLElement {
322
250
  const { identifier } = e.detail;
323
251
  const target = e.target;
324
252
  if (identifier in this && target instanceof HTMLElement) {
325
- const ref = this.#get(identifier);
326
- const setInnerHTML = () => {
327
- const value = getValue(ref);
328
- target.innerHTML = `${value}`;
329
- };
330
- if (isState(ref) || isComputed(ref)) {
331
- this.$effect(() => setInnerHTML());
332
- } else {
333
- setInnerHTML();
334
- }
253
+ const ref = this.lookup(identifier);
254
+ this.effect(() => {
255
+ target.innerHTML = `${ref}`;
256
+ });
335
257
  e.stopPropagation();
336
258
  }
337
259
  }
@@ -341,13 +263,13 @@ var HandlerRegistry = class extends HTMLElement {
341
263
  const { identifier, property } = e.detail;
342
264
  const target = e.target;
343
265
  if (identifier in this && target instanceof HTMLElement && property in target) {
344
- const state = this.#get(identifier);
266
+ const state = this.lookup(identifier);
345
267
  if (isState(state)) {
346
268
  state.value = target[property];
347
269
  target.addEventListener(bindingConfig[property].event, () => {
348
270
  state.value = target[property];
349
271
  });
350
- this.$effect(() => {
272
+ this.effect(() => {
351
273
  target[property] = state.value;
352
274
  });
353
275
  }
@@ -356,15 +278,15 @@ var HandlerRegistry = class extends HTMLElement {
356
278
  }
357
279
  }
358
280
  connectedCallback() {
359
- const { signal } = this.abortController;
360
- this.addEventListener("@attr-request", this.#handleAttr, { signal });
361
- this.addEventListener("@class-request", this.#handleClass, { signal });
362
- this.addEventListener("@on-request", this.#handleOn, { signal });
363
- this.addEventListener("@use-request", this.#handleUse, { signal });
364
- this.addEventListener("@prop-request", this.#handleProp, { signal });
365
- this.addEventListener("@html-request", this.#handleHTML, { signal });
366
- this.addEventListener("@text-request", this.#handleText, { signal });
367
- this.addEventListener("@bind-request", this.#handleBind, { signal });
281
+ const { signal: signal2 } = this.abortController;
282
+ this.addEventListener("@attr-request", this.#handleAttr, { signal: signal2 });
283
+ this.addEventListener("@class-request", this.#handleClass, { signal: signal2 });
284
+ this.addEventListener("@on-request", this.#handleOn, { signal: signal2 });
285
+ this.addEventListener("@use-request", this.#handleUse, { signal: signal2 });
286
+ this.addEventListener("@prop-request", this.#handleProp, { signal: signal2 });
287
+ this.addEventListener("@html-request", this.#handleHTML, { signal: signal2 });
288
+ this.addEventListener("@text-request", this.#handleText, { signal: signal2 });
289
+ this.addEventListener("@bind-request", this.#handleBind, { signal: signal2 });
368
290
  }
369
291
  disconnectedCallback() {
370
292
  this.abortController.abort();
@@ -375,4 +297,4 @@ var HandlerRegistry = class extends HTMLElement {
375
297
  };
376
298
  customElements?.define("handler-registry", HandlerRegistry);
377
299
 
378
- export { $array, $computed, $effect, $object, $state, HandlerRegistry, ReactiveComputation, ReactiveValue, getValue, isComputed, isState };
300
+ export { HandlerRegistry, computed, effect, isState, reactive, signal };
@@ -0,0 +1,30 @@
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
+ 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">;
12
+ /**
13
+ * A more reliable `typeof` function
14
+ */
15
+ declare function type(value: unknown): Types;
16
+ declare const booleanAttributes: string[];
17
+ declare const bindingConfig: {
18
+ checked: {
19
+ element: string[];
20
+ type: string[];
21
+ event: string;
22
+ };
23
+ value: {
24
+ element: string[];
25
+ type: string[];
26
+ event: string;
27
+ };
28
+ };
29
+
30
+ export { bindingConfig, booleanAttributes, spaces_sep_by_comma, toKebabCase, toPascalCase, type };
@@ -0,0 +1,123 @@
1
+ // src/utils.ts
2
+ var is_upper = /[A-Z]/;
3
+ 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
+ function type(value) {
35
+ if (value === null) {
36
+ return "null";
37
+ }
38
+ if (value === void 0) {
39
+ return "undefined";
40
+ }
41
+ const baseType = typeof value;
42
+ if (!["object", "function"].includes(baseType)) {
43
+ return baseType;
44
+ }
45
+ if (typeof value === "object" && Symbol.toStringTag in value) {
46
+ const tag = value[Symbol.toStringTag];
47
+ if (typeof tag === "string") {
48
+ return tag;
49
+ }
50
+ }
51
+ if (baseType === "function" && Function.prototype.toString.call(value).startsWith("class")) {
52
+ return "class";
53
+ }
54
+ const className = value.constructor.name;
55
+ if (typeof className === "string" && className !== "") {
56
+ return className.toLowerCase();
57
+ }
58
+ return baseType;
59
+ }
60
+ var booleanAttributes = [
61
+ "allowfullscreen",
62
+ // on <iframe>
63
+ "async",
64
+ // on <script>
65
+ "autofocus",
66
+ // on <button>, <input>, <select>, <textarea>
67
+ "autoplay",
68
+ // on <audio>, <video>
69
+ "checked",
70
+ // on <input type="checkbox">, <input type="radio">
71
+ "controls",
72
+ // on <audio>, <video>
73
+ "default",
74
+ // on <track>
75
+ "defer",
76
+ // on <script>
77
+ "disabled",
78
+ // on form elements like <button>, <fieldset>, <input>, <optgroup>, <option>,<select>, <textarea>
79
+ "formnovalidate",
80
+ // on <button>, <input type="submit">
81
+ "hidden",
82
+ // global
83
+ "inert",
84
+ // global
85
+ "ismap",
86
+ // on <img>
87
+ "itemscope",
88
+ // global; part of microdata
89
+ "loop",
90
+ // on <audio>, <video>
91
+ "multiple",
92
+ // on <input type="file">, <select>
93
+ "muted",
94
+ // on <audio>, <video>
95
+ "nomodule",
96
+ // on <script>
97
+ "novalidate",
98
+ // on <form>
99
+ "open",
100
+ // on <details>
101
+ "readonly",
102
+ // on <input>, <textarea>
103
+ "required",
104
+ // on <input>, <select>, <textarea>
105
+ "reversed",
106
+ // on <ol>
107
+ "selected"
108
+ // on <option>
109
+ ];
110
+ var bindingConfig = {
111
+ "checked": {
112
+ element: ["input"],
113
+ type: ["boolean"],
114
+ event: "change"
115
+ },
116
+ "value": {
117
+ element: ["input", "select", "textarea"],
118
+ type: ["string", "number"],
119
+ event: "input"
120
+ }
121
+ };
122
+
123
+ export { bindingConfig, booleanAttributes, spaces_sep_by_comma, toKebabCase, toPascalCase, type };
package/package.json CHANGED
@@ -1,9 +1,16 @@
1
1
  {
2
2
  "name": "@radishland/runtime",
3
- "version": "0.0.8",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "description": "The Radish runtime",
6
6
  "author": "Frédéric Crozatier",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/radishland/radish.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/radishland/radish/issues"
13
+ },
7
14
  "license": "MIT",
8
15
  "scripts": {
9
16
  "build": "tsup",
@@ -13,6 +20,14 @@
13
20
  ".": {
14
21
  "import": "./client/index.js",
15
22
  "types": "./client/index.d.ts"
23
+ },
24
+ "./boot": {
25
+ "import": "./client/boot.js",
26
+ "types": "./client/boot.d.ts"
27
+ },
28
+ "./utils": {
29
+ "import": "./client/utils.js",
30
+ "types": "./client/utils.d.ts"
16
31
  }
17
32
  },
18
33
  "files": [
@@ -21,8 +36,12 @@
21
36
  "LICENCE",
22
37
  "package.json"
23
38
  ],
39
+ "keywords": [
40
+ "radish",
41
+ "runtime"
42
+ ],
24
43
  "dependencies": {
25
- "signal-polyfill": "^0.2.2"
44
+ "@preact/signals-core": "^1.8.0"
26
45
  },
27
46
  "devDependencies": {
28
47
  "tsup": "^8.4.0",