ilha 0.8.5 → 0.9.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.
- package/README.md +77 -0
- package/dist/{index-BUonLJXu.d.ts → index-C0SWn9oq.d.ts} +49 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2121 -5
- package/dist/jsx-dev-runtime.d.ts +1 -1
- package/dist/jsx-dev-runtime.js +3 -1
- package/dist/{jsx-runtime-DZl50XF-.d.ts → jsx-runtime-DBCAZ9YL.d.ts} +1 -1
- package/dist/jsx-runtime.d.ts +2 -2
- package/dist/jsx-runtime.js +162 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -766,6 +766,83 @@ const styles = css`
|
|
|
766
766
|
|
|
767
767
|
---
|
|
768
768
|
|
|
769
|
+
## JSX Runtime
|
|
770
|
+
|
|
771
|
+
Prefer JSX over the `html` tag? `ilha` ships a JSX runtime (`ilha/jsx-runtime`) that produces the same XSS-safe output — JSX expressions evaluate to the same `RawHtml` values the `html` tag returns, so the two syntaxes are interchangeable and can be mixed freely.
|
|
772
|
+
|
|
773
|
+
### Setup
|
|
774
|
+
|
|
775
|
+
Enable the automatic JSX transform in `tsconfig.json` (works with TypeScript, Bun, Vite, esbuild, etc.):
|
|
776
|
+
|
|
777
|
+
```jsonc
|
|
778
|
+
{
|
|
779
|
+
"compilerOptions": {
|
|
780
|
+
"jsx": "react-jsx",
|
|
781
|
+
"jsxImportSource": "ilha",
|
|
782
|
+
},
|
|
783
|
+
}
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
### Usage
|
|
787
|
+
|
|
788
|
+
```tsx
|
|
789
|
+
import ilha from "ilha";
|
|
790
|
+
|
|
791
|
+
const Counter = ilha
|
|
792
|
+
.state("count", 0)
|
|
793
|
+
.on("button@click", ({ state }) => state.count(state.count() + 1))
|
|
794
|
+
.render(({ state }) => (
|
|
795
|
+
<div>
|
|
796
|
+
<p>Count: {state.count}</p>
|
|
797
|
+
<button>Increment</button>
|
|
798
|
+
</div>
|
|
799
|
+
));
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
Interpolated children follow the same rules as the `html` tag — strings are escaped, signal accessors are auto-called, islands become hydration slots, arrays are flattened. Use `raw()` to opt out of escaping, and `<></>` (Fragment) to group siblings without a wrapper element.
|
|
803
|
+
|
|
804
|
+
### Attributes
|
|
805
|
+
|
|
806
|
+
| Feature | Behaviour |
|
|
807
|
+
| --------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
808
|
+
| `class` / `className` | Accepts a string, an array (`["a", cond && "b"]`), or an object (`{ active: isActive }`) |
|
|
809
|
+
| `htmlFor` | Alias for `for` |
|
|
810
|
+
| `style` | Accepts a string or an object (`{ backgroundColor: "teal" }` → `background-color:teal`) |
|
|
811
|
+
| Boolean attributes | `true` renders the bare attribute, `false`/`null`/`undefined` omit it |
|
|
812
|
+
| `bind:*` | Two-way bindings, same as in `html` templates — pass a signal accessor: `<input bind:value={state.name} />` |
|
|
813
|
+
| `key` | Keys a child island for reorder-safe rendering (same as `.key()`). Keys must be non-empty and must not contain `:` |
|
|
814
|
+
|
|
815
|
+
For safety, `on*` attributes (e.g. `onclick`) and `srcdoc` are stripped — attach event listeners with `.on()` instead — and URL attributes (`href`, `src`, `action`, …) with unsafe schemes like `javascript:` are dropped.
|
|
816
|
+
|
|
817
|
+
### Islands as components
|
|
818
|
+
|
|
819
|
+
Islands are plain functions, so they compose as JSX components — props and keys work as you'd expect:
|
|
820
|
+
|
|
821
|
+
```tsx
|
|
822
|
+
const Badge = ilha
|
|
823
|
+
.input<{ label: string }>()
|
|
824
|
+
.render(({ input }) => <span class="badge">{input.label}</span>);
|
|
825
|
+
|
|
826
|
+
const Card = ilha.render(() => (
|
|
827
|
+
<div class="card">
|
|
828
|
+
<Badge label="New" />
|
|
829
|
+
<p>Card content</p>
|
|
830
|
+
</div>
|
|
831
|
+
));
|
|
832
|
+
|
|
833
|
+
const List = ilha.render(() => (
|
|
834
|
+
<ul>
|
|
835
|
+
{items.map((item) => (
|
|
836
|
+
<li>
|
|
837
|
+
<Item key={item.id} name={item.name} />
|
|
838
|
+
</li>
|
|
839
|
+
))}
|
|
840
|
+
</ul>
|
|
841
|
+
));
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
---
|
|
845
|
+
|
|
769
846
|
## SSR + Hydration
|
|
770
847
|
|
|
771
848
|
The recommended SSR + hydration pattern uses `.hydratable()` on the server and `ilha.mount()` on the client.
|
|
@@ -61,7 +61,7 @@ type ContextSignal<T> = {
|
|
|
61
61
|
(): T;
|
|
62
62
|
(value: T): void;
|
|
63
63
|
};
|
|
64
|
-
declare function
|
|
64
|
+
declare function ilhaContextFn<T>(key: string, initial: T): ContextSignal<T>;
|
|
65
65
|
/**
|
|
66
66
|
* Create a free-standing reactive signal that lives outside any island.
|
|
67
67
|
* Useful for sharing state across islands without prop drilling, or for
|
|
@@ -74,6 +74,33 @@ declare function ilhaContext<T>(key: string, initial: T): ContextSignal<T>;
|
|
|
74
74
|
* so when the signal changes, dependents re-run as if it were local state.
|
|
75
75
|
*/
|
|
76
76
|
declare function ilhaSignal<T>(initial: T): SignalAccessor<T>;
|
|
77
|
+
/**
|
|
78
|
+
* Create a free-standing read-only reactive value derived from other signals.
|
|
79
|
+
* The computation is lazy and cached: `fn` re-runs only when a signal it read
|
|
80
|
+
* changed and the computed is read again. Reading it inside a `.derived()`,
|
|
81
|
+
* `.effect()`, `.render()`, or top-level `effect()` subscribes that scope —
|
|
82
|
+
* dependents re-run when the computed's value changes.
|
|
83
|
+
*
|
|
84
|
+
* ```ts
|
|
85
|
+
* const items = ilha.signal([1, 2, 3]);
|
|
86
|
+
* const total = ilha.computed(() => items().reduce((a, b) => a + b, 0));
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
declare function ilhaComputed<T>(fn: () => T): SignalAccessor<T>;
|
|
90
|
+
/**
|
|
91
|
+
* Run a free-standing reactive effect outside any island. `fn` runs once
|
|
92
|
+
* immediately and again whenever a signal it read changes. It may return a
|
|
93
|
+
* cleanup function, invoked before each re-run and on stop. Signal writes
|
|
94
|
+
* inside the effect are batched. Returns a stop function that disposes the
|
|
95
|
+
* effect and runs the final cleanup.
|
|
96
|
+
*
|
|
97
|
+
* ```ts
|
|
98
|
+
* const stop = effect(() => {
|
|
99
|
+
* document.title = `${cart.count()} items`;
|
|
100
|
+
* });
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
declare function ilhaEffect(fn: () => void | (() => void)): () => void;
|
|
77
104
|
/**
|
|
78
105
|
* Run `fn` with reactive tracking suspended. Reading signals inside `fn`
|
|
79
106
|
* returns their current value without subscribing the surrounding scope.
|
|
@@ -134,6 +161,17 @@ interface Island<TInput = Record<string, unknown>, _TStateMap extends Record<str
|
|
|
134
161
|
mount(host: Element, props?: Partial<TInput>): () => void;
|
|
135
162
|
hydratable(props: Partial<TInput>, options: HydratableOptions): Promise<string>;
|
|
136
163
|
key(key: string): KeyedIsland<TInput>;
|
|
164
|
+
/**
|
|
165
|
+
* Register this island as a custom element, usable from plain HTML or any
|
|
166
|
+
* framework: `Counter.define("x-counter", { observe: ["label"] })` then
|
|
167
|
+
* `<x-counter label="hi"></x-counter>`. Observed attributes become string
|
|
168
|
+
* input props and re-resolve input on change; richer props can be assigned
|
|
169
|
+
* via the element's `props` property. Mounts on connect, unmounts on
|
|
170
|
+
* disconnect. No-op (with a dev warning) where customElements is missing.
|
|
171
|
+
*/
|
|
172
|
+
define(tagName: string, options?: {
|
|
173
|
+
observe?: string[];
|
|
174
|
+
}): void;
|
|
137
175
|
[ISLAND]: true;
|
|
138
176
|
}
|
|
139
177
|
interface KeyedIsland<TInput> {
|
|
@@ -290,8 +328,12 @@ declare const ilha: IlhaBuilder<Record<string, unknown>, Record<never, never>, R
|
|
|
290
328
|
raw: typeof ilhaRaw;
|
|
291
329
|
mount: typeof mountAll;
|
|
292
330
|
from: typeof ilhaFrom;
|
|
293
|
-
context: typeof
|
|
331
|
+
context: typeof ilhaContextFn & {
|
|
332
|
+
/** Remove a context signal from the registry. Returns true if it existed. */delete(key: string): boolean; /** Remove all context signals from the registry (e.g. between tests). */
|
|
333
|
+
clear(): void;
|
|
334
|
+
};
|
|
294
335
|
signal: typeof ilhaSignal;
|
|
336
|
+
computed: typeof ilhaComputed;
|
|
295
337
|
batch: typeof batch;
|
|
296
338
|
untrack: typeof untrack;
|
|
297
339
|
onUncaughtError: typeof onUncaughtError;
|
|
@@ -303,6 +345,9 @@ declare const raw: typeof ilhaRaw;
|
|
|
303
345
|
declare const css: typeof ilhaCss;
|
|
304
346
|
declare const mount: typeof mountAll;
|
|
305
347
|
declare const from: typeof ilhaFrom;
|
|
306
|
-
declare const context: typeof
|
|
348
|
+
declare const context: typeof ilhaContextFn & {
|
|
349
|
+
/** Remove a context signal from the registry. Returns true if it existed. */delete(key: string): boolean; /** Remove all context signals from the registry (e.g. between tests). */
|
|
350
|
+
clear(): void;
|
|
351
|
+
};
|
|
307
352
|
//#endregion
|
|
308
|
-
export {
|
|
353
|
+
export { mount as A, css as C, ilhaComputed as D, ilha as E, raw as M, untrack as N, ilhaEffect as O, context as S, html as T, OnMountContext as _, ErrorSource as a, __ilhaJsxSlot as b, HandlerContextFor as c, Island as d, IslandDerived as f, MountResult as g, MountOptions as h, ErrorContext as i, onUncaughtError as j, ilhaSignal as k, HydratableOptions as l, KeyedIsland as m, DerivedValue as n, ExternalSignal as o, IslandState as p, EffectContext as r, HandlerContext as s, DerivedAccessor as t, ISLAND_MOUNT_INTERNAL as u, RawHtml as v, from as w, batch as x, SignalAccessor as y };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
export { DerivedAccessor, DerivedValue, EffectContext, ErrorContext, ErrorSource, ExternalSignal, HandlerContext, HandlerContextFor, HydratableOptions, ISLAND_MOUNT_INTERNAL, Island, IslandDerived, IslandState, KeyedIsland, MountOptions, MountResult, OnMountContext, RawHtml, SignalAccessor, __ilhaJsxSlot, batch, context, css, ilha as default, from, html, ilhaSignal, ilhaSignal as signal, mount, onUncaughtError, raw, untrack };
|
|
1
|
+
import { A as mount, C as css, D as ilhaComputed, E as ilha, M as raw, N as untrack, O as ilhaEffect, S as context, T as html, _ as OnMountContext, a as ErrorSource, b as __ilhaJsxSlot, c as HandlerContextFor, d as Island, f as IslandDerived, g as MountResult, h as MountOptions, i as ErrorContext, j as onUncaughtError, k as ilhaSignal, l as HydratableOptions, m as KeyedIsland, n as DerivedValue, o as ExternalSignal, p as IslandState, r as EffectContext, s as HandlerContext, t as DerivedAccessor, u as ISLAND_MOUNT_INTERNAL, v as RawHtml, w as from, x as batch, y as SignalAccessor } from "./index-C0SWn9oq.js";
|
|
2
|
+
export { DerivedAccessor, DerivedValue, EffectContext, ErrorContext, ErrorSource, ExternalSignal, HandlerContext, HandlerContextFor, HydratableOptions, ISLAND_MOUNT_INTERNAL, Island, IslandDerived, IslandState, KeyedIsland, MountOptions, MountResult, OnMountContext, RawHtml, SignalAccessor, __ilhaJsxSlot, batch, ilhaComputed as computed, context, css, ilha as default, ilhaEffect as effect, from, html, ilhaSignal, ilhaSignal as signal, mount, onUncaughtError, raw, untrack };
|