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 CHANGED
@@ -1,7 +1,18 @@
1
- # [xote](https://xote.dev/)
2
- ![NPM Version](https://img.shields.io/npm/v/xote)
3
- ![npm bundle size](https://badgen.net/bundlephobia/min/xote)
4
- ![npm bundle size](https://badgen.net/bundlephobia/minzip/xote)
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-C36--SJD.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
+ 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-SuqJrQPC.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-3LSynUOy.mjs";
3
3
  //#region src/Html.res.mjs
4
4
  var d = /* @__PURE__ */ e({
5
5
  a: () => S,