xote 7.0.0-beta.1 → 7.1.0-beta.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 +71 -41
- package/dist/{RuntimeJsxProp.res-A6N-qWoK.js → RuntimeJsxProp.res-gr8AK5hj.js} +1 -1
- package/dist/{RuntimeJsxProp.res-D3W5GXqT.mjs → RuntimeJsxProp.res-k7-PNxKK.mjs} +1 -1
- package/dist/{View.res-SuqJrQPC.mjs → View.res-3LSynUOy.mjs} +260 -207
- package/dist/View.res-DhZkE_sC.js +1 -0
- package/dist/client.cjs +1 -1
- package/dist/client.mjs +2 -2
- package/dist/hydration.cjs +1 -1
- package/dist/hydration.mjs +1 -1
- package/dist/mdx.cjs +1 -1
- package/dist/mdx.mjs +1 -1
- package/dist/router.cjs +1 -1
- package/dist/router.mjs +2 -2
- package/dist/xote.cjs +1 -1
- package/dist/xote.mjs +397 -344
- package/dist/xote.umd.js +1 -1
- package/package.json +9 -3
- package/ppx/LICENSE.OCaml +548 -0
- package/ppx/README.md +307 -0
- package/ppx/build.sh +10 -0
- package/ppx/ppx.ml +1346 -0
- package/src/View.res +69 -0
- package/src/View.res.mjs +68 -0
- package/dist/View.res-C36--SJD.js +0 -1
package/README.md
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
<p>
|
|
2
|
+
<a href="https://xote.dev/">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/banner.svg">
|
|
5
|
+
<source media="(prefers-color-scheme: light)" srcset="docs/banner-light.svg">
|
|
6
|
+
<img src="docs/banner.svg" alt="xote - Fine-grained reactivity for ReScript" width="400" />
|
|
7
|
+
</picture>
|
|
8
|
+
</a>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p>
|
|
12
|
+
<a href="https://www.npmjs.com/package/xote"><img src="https://img.shields.io/npm/v/xote" alt="NPM Version" /></a>
|
|
13
|
+
<a href="https://bundlephobia.com/package/xote"><img src="https://badgen.net/bundlephobia/min/xote" alt="Bundle size" /></a>
|
|
14
|
+
<a href="https://bundlephobia.com/package/xote"><img src="https://badgen.net/bundlephobia/minzip/xote" alt="Bundle size (gzip)" /></a>
|
|
15
|
+
</p>
|
|
5
16
|
|
|
6
17
|
xote is a lightweight [ReScript](https://rescript-lang.org/) library that combines fine-grained reactivity and a declarative component system for building user interfaces for the web.
|
|
7
18
|
|
|
@@ -34,43 +45,6 @@ This README uses the application-facing names for public code:
|
|
|
34
45
|
- `Prop` is the static-or-reactive prop module.
|
|
35
46
|
- `View.Text`, `View.Int`, `View.For`, `View.Show`, `View.Attr.*`, `Router.location`, and `SSRState.signal` are the building blocks used throughout these examples.
|
|
36
47
|
|
|
37
|
-
### JavaScript
|
|
38
|
-
|
|
39
|
-
Xote is built for ReScript first, but the compiled package can also be used from JavaScript. Import the focused client entry and build nodes with `View` or `Html` helpers:
|
|
40
|
-
|
|
41
|
-
```js
|
|
42
|
-
import { Signal, Computed, Effect, View } from "xote/client";
|
|
43
|
-
|
|
44
|
-
const count = Signal.make(0);
|
|
45
|
-
const doubled = Computed.make(() => Signal.get(count) * 2);
|
|
46
|
-
|
|
47
|
-
Effect.run(() => {
|
|
48
|
-
console.log("Count:", Signal.get(count));
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const app = View.element("div", [], [], [
|
|
52
|
-
View.element("h1", [], [], [View.text("Counter")]),
|
|
53
|
-
View.element("p", [], [], [
|
|
54
|
-
View.text("Count: "),
|
|
55
|
-
View.signalText(() => String(Signal.get(count))),
|
|
56
|
-
]),
|
|
57
|
-
View.element("p", [], [], [
|
|
58
|
-
View.text("Doubled: "),
|
|
59
|
-
View.signalText(() => String(Signal.get(doubled))),
|
|
60
|
-
]),
|
|
61
|
-
View.element(
|
|
62
|
-
"button",
|
|
63
|
-
[],
|
|
64
|
-
[["click", () => Signal.update(count, n => n + 1)]],
|
|
65
|
-
[View.text("Increment")],
|
|
66
|
-
),
|
|
67
|
-
]);
|
|
68
|
-
|
|
69
|
-
View.mountById(app, "app");
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Use `xote/client` for browser UI, `xote/router` for routing, `xote/ssr` for server rendering, `xote/hydration` for hydrating server-rendered pages, and `xote/mdx` for MDX integration.
|
|
73
|
-
|
|
74
48
|
### Quick Example
|
|
75
49
|
|
|
76
50
|
```rescript
|
|
@@ -230,6 +204,25 @@ let todos = Signal.make([
|
|
|
230
204
|
</p>
|
|
231
205
|
```
|
|
232
206
|
|
|
207
|
+
### Auto-tracked Blocks
|
|
208
|
+
|
|
209
|
+
When a block of UI depends on several signals at once, `View.tracked` lets you read them inline — every signal read while the body runs subscribes the block automatically, and the block re-renders when any of them changes:
|
|
210
|
+
|
|
211
|
+
```rescript
|
|
212
|
+
let loggedIn = Signal.make(false)
|
|
213
|
+
let name = Signal.make("Ada")
|
|
214
|
+
|
|
215
|
+
{View.tracked(() =>
|
|
216
|
+
if Signal.get(loggedIn) {
|
|
217
|
+
<p> <View.Text> {`Hello, ${Signal.get(name)}`} </View.Text> </p>
|
|
218
|
+
} else {
|
|
219
|
+
<p> <View.Text> "Please log in" </View.Text> </p>
|
|
220
|
+
}
|
|
221
|
+
)}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Dependencies are re-discovered on every run, so conditional reads work: above, `name` is only tracked while `loggedIn` is true. The tradeoff is granularity — a tracked block replaces its children wholesale (no diffing) when a dependency changes, so keep tracked blocks small and prefer `View.For` with `by` for lists.
|
|
225
|
+
|
|
233
226
|
### Static or Reactive Props
|
|
234
227
|
|
|
235
228
|
Use `Prop` when a component prop can accept either a static value or a signal:
|
|
@@ -286,6 +279,43 @@ For server/client state transfer, prefer `SSRState.signal` when creating a synce
|
|
|
286
279
|
let count = SSRState.signal("count", 0, SSRState.Codec.int)
|
|
287
280
|
```
|
|
288
281
|
|
|
282
|
+
### JavaScript Interop
|
|
283
|
+
|
|
284
|
+
Xote is built for ReScript first, but the compiled package can also be used from JavaScript. Import the focused client entry and build nodes with `View` or `Html` helpers:
|
|
285
|
+
|
|
286
|
+
```js
|
|
287
|
+
import { Signal, Computed, Effect, View } from "xote/client";
|
|
288
|
+
|
|
289
|
+
const count = Signal.make(0);
|
|
290
|
+
const doubled = Computed.make(() => Signal.get(count) * 2);
|
|
291
|
+
|
|
292
|
+
Effect.run(() => {
|
|
293
|
+
console.log("Count:", Signal.get(count));
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
const app = View.element("div", [], [], [
|
|
297
|
+
View.element("h1", [], [], [View.text("Counter")]),
|
|
298
|
+
View.element("p", [], [], [
|
|
299
|
+
View.text("Count: "),
|
|
300
|
+
View.signalText(() => String(Signal.get(count))),
|
|
301
|
+
]),
|
|
302
|
+
View.element("p", [], [], [
|
|
303
|
+
View.text("Doubled: "),
|
|
304
|
+
View.signalText(() => String(Signal.get(doubled))),
|
|
305
|
+
]),
|
|
306
|
+
View.element(
|
|
307
|
+
"button",
|
|
308
|
+
[],
|
|
309
|
+
[["click", () => Signal.update(count, n => n + 1)]],
|
|
310
|
+
[View.text("Increment")],
|
|
311
|
+
),
|
|
312
|
+
]);
|
|
313
|
+
|
|
314
|
+
View.mountById(app, "app");
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Use `xote/client` for browser UI, `xote/router` for routing, `xote/ssr` for server rendering, `xote/hydration` for hydrating server-rendered pages, and `xote/mdx` for MDX integration.
|
|
318
|
+
|
|
289
319
|
Check the [website](https://brnrdog.github.io/xote/) for more comprehensive documentations about Xote and Signals.
|
|
290
320
|
|
|
291
321
|
## Releasing
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require("./RuntimeAttr.res-Cr5Qmz0i.js"),t=require("./View.res-
|
|
1
|
+
const e=require("./RuntimeAttr.res-Cr5Qmz0i.js"),t=require("./View.res-DhZkE_sC.js");var n=e.D({a:()=>p,button:()=>a,div:()=>r,h1:()=>s,h2:()=>c,h3:()=>l,input:()=>o,li:()=>f,p:()=>u,span:()=>i,ul:()=>d});function r(e,n,r,i){return t.a(`div`,e,n,r,void 0)}function i(e,n,r,i){return t.a(`span`,e,n,r,void 0)}function a(e,n,r,i){return t.a(`button`,e,n,r,void 0)}function o(e,n,r){return t.a(`input`,e,n,void 0,void 0)}function s(e,n,r,i){return t.a(`h1`,e,n,r,void 0)}function c(e,n,r,i){return t.a(`h2`,e,n,r,void 0)}function l(e,n,r,i){return t.a(`h3`,e,n,r,void 0)}function u(e,n,r,i){return t.a(`p`,e,n,r,void 0)}function d(e,n,r,i){return t.a(`ul`,e,n,r,void 0)}function f(e,n,r,i){return t.a(`li`,e,n,r,void 0)}function p(e,n,r,i){return t.a(`a`,e,n,r,void 0)}function m(e,n){return t.f(n)?n.TAG===`Reactive`?t.s(e,n._0):t.r(e,n._0):t.u(n)?t.i(e,n):t.d(n)?t.s(e,n):t.r(e,n)}function h(n,r){if(t.f(r)){if(r.TAG!==`Reactive`)return t.r(n,e.t(r._0));let i=r._0,a=t.x(()=>e.t(e.l(i)),void 0,void 0);return t.s(n,a)}if(t.u(r))return t.i(n,()=>e.t(r()));if(!t.d(r))return t.r(n,e.t(r));let i=t.x(()=>e.t(e.l(r)),void 0,void 0);return t.s(n,i)}Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return h}});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { D as e, l as t, t as n } from "./RuntimeAttr.res-DAZkL5CF.mjs";
|
|
2
|
-
import { a as r, d as i, f as a, i as o, r as s, s as c, u as l, x as u } from "./View.res-
|
|
2
|
+
import { a as r, d as i, f as a, i as o, r as s, s as c, u as l, x as u } from "./View.res-3LSynUOy.mjs";
|
|
3
3
|
//#region src/Html.res.mjs
|
|
4
4
|
var d = /* @__PURE__ */ e({
|
|
5
5
|
a: () => S,
|