xote 6.0.0 → 6.0.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.
Files changed (2) hide show
  1. package/README.md +33 -191
  2. package/package.json +11 -1
package/README.md CHANGED
@@ -1,19 +1,9 @@
1
- # xote
1
+ # [Xote](https://brnrdog.github.io/xote/)
2
2
  ![NPM Version](https://img.shields.io/npm/v/xote)
3
3
  ![npm bundle size](https://img.shields.io/bundlephobia/min/xote)
4
4
  ![npm bundle size](https://img.shields.io/bundlephobia/minzip/xote)
5
5
 
6
- Xote is a lightweight UI library for ReScript that combines fine-grained reactivity with a minimal component system. Built on [rescript-signals](https://brnrdog.github.io/rescript-signals), it provides declarative components, JSX support, and signal-based routing for building reactive web applications.
7
-
8
- ## Features
9
-
10
- - **Reactive Components**: Declarative UI building with JSX support and direct DOM updates
11
- - **Signal-based Reactivity**: Powered by [rescript-signals](https://brnrdog.github.io/rescript-signals) for automatic dependency tracking
12
- - **Fine-grained Updates**: Direct DOM manipulation without virtual DOM diffing
13
- - **Signal-based Router**: SPA navigation with pattern matching and dynamic parameters
14
- - **Server-Side Rendering**: SSR with hydration and automatic state transfer
15
- - **Lightweight**: Minimal runtime footprint
16
- - **Type-safe**: Full ReScript type safety throughout
6
+ 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.
17
7
 
18
8
  ## Getting Started
19
9
 
@@ -21,10 +11,6 @@ Xote is a lightweight UI library for ReScript that combines fine-grained reactiv
21
11
 
22
12
  ```bash
23
13
  npm install xote
24
- # or
25
- yarn add xote
26
- # or
27
- pnpm add xote
28
14
  ```
29
15
 
30
16
  Then, add it to your ReScript project's `rescript.json`. You'll need to declare `xote` as a dependency, configure JSX to use Xote's transform, and open `Xote` so the JSX module resolves:
@@ -40,24 +26,10 @@ Then, add it to your ReScript project's `rescript.json`. You'll need to declare
40
26
  }
41
27
  ```
42
28
 
43
- `-open Xote` makes `Component`, `Html`, `Signal`, `Router`, etc. available unqualified inside your source files.
44
-
45
- ## Why Xote?
46
-
47
- Xote uses **rescript-signals** for reactive primitives (Signal, Computed, Effect), and it adds:
48
-
49
- - **Component System**: A minimal but powerful component model with JSX support for declarative UI
50
- - **Direct DOM Updates**: Fine-grained reactivity that updates DOM elements directly, no virtual DOM
51
- - **Signal-based Router**: Client-side routing with pattern matching and reactive location state
52
- - **Reactive Attributes**: Support for static, signal-based, and computed attributes on elements
53
- - **Automatic Cleanup**: Effect disposal and memory management built into the component lifecycle
54
-
55
- Xote focuses on clarity, control, and performance. The goal is to offer precise, fine-grained updates and predictable behavior with minimal abstractions, while leveraging the robust type system from ReScript.
29
+ Optional: the `-open Xote` flag makes Xote modules available unqualified inside your source files.
56
30
 
57
31
  ### Quick Example
58
32
 
59
- #### Using JSX
60
-
61
33
  ```rescript
62
34
  open Xote
63
35
 
@@ -66,16 +38,29 @@ module App = {
66
38
  // Create reactive state
67
39
  let count = Signal.make(0)
68
40
 
69
- // Event handler
70
- let increment = (_evt: Dom.event) => Signal.update(count, n => n + 1)
41
+ // Create a derived state
42
+ let doubled = Computed.make(() => Signal.get(count) * 2)
43
+
44
+ // Logs every time count changes:
45
+ Effect.run(() => {
46
+ Console.log2("Count is ", Signal.get(count))
47
+ })
71
48
 
72
49
  // Build the UI with JSX
73
50
  <div>
74
51
  <h1> {Node.text("Counter")} </h1>
75
52
  <p>
76
- {Node.signalText(() => `Count: ${Signal.get(count)->Int.toString}`)}
53
+ {Node.text("Count: ")}
54
+ {Node.signalInt(count)}
55
+ </p>
56
+ <p>
57
+ {Node.text("Doubled: ")
58
+ {Node.signalInt(doubled)}
59
+ </p>
60
+ <p>
61
+ {Node.signalText(() => "Count is " ++ Signal.get(count) % 2 == 0 ? "even" : "odd")
77
62
  </p>
78
- <button onClick={increment}>
63
+ <button onClick={(_evt: Dom.event) => Signal.update(count, n => n + 1)}>
79
64
  {Node.text("Increment")}
80
65
  </button>
81
66
  </div>
@@ -88,170 +73,27 @@ Node.mountById(<App />, "app")
88
73
 
89
74
  ## Core Concepts
90
75
 
91
- ### Reactive Primitives (from rescript-signals)
76
+ Xote focuses on clarity, control, and performance. The goal is to offer precise, fine-grained updates and predictable behavior with a minimal set of abstractions, while leveraging the robust type system from ReScript.
77
+
78
+ ### Reactive Primitives
79
+
80
+ Xote uses **[rescript-signals](https://github.com/brnrdog/rescript-signals)** for its reactive primitives:
92
81
 
93
82
  - **Signal**: Reactive state container - `Signal.make(value)`
94
83
  - **Computed**: Derived reactive value that updates automatically - `Computed.make(() => ...)`
95
84
  - **Effect**: Side-effect functions that re-run when dependencies change - `Effect.run(() => ...)`
96
85
 
97
- All reactive primitives feature automatic dependency tracking - no manual subscriptions needed.
98
-
99
- ### Xote Features
100
-
101
- - **Component**: Declarative UI builder with JSX syntax and function-based APIs
102
- - **Router**: Signal-based navigation for SPAs with pattern matching and dynamic routes
103
-
104
- ### Component Features
105
-
106
- - **JSX syntax**: Use HTML tags like `<div>`, `<button>`, `<input>`
107
- - **Props**: Standard HTML attributes like `class`, `id`, `style`, `value`, `placeholder`
108
- - **Event handlers**: `onClick`, `onInput`, `onChange`, `onSubmit`, etc.
109
- - **Reactive content**: Wrap reactive text with `Node.signalText(() => ...)` (also `signalInt` and `signalFloat` for non-string values)
110
- - **HTML helpers**: `Html.div`, `Html.button`, `Html.p`, etc. for the function-based API; JSX covers the rest
111
- - **Component functions**: Define reusable components as functions that return JSX
112
-
113
- ### Xote.Router Features
86
+ All reactive primitives feature automatic dependency tracking. No manual subscriptions needed.
114
87
 
115
- - **Initialization**: Call `Router.init()` once at app start
116
- - **Imperative navigation**: Use `Router.push()` and `Router.replace()` to navigate programmatically
117
- - **Declarative routing**: Define routes with `Router.routes()` and render components based on URL patterns
118
- - **Dynamic parameters**: Extract URL parameters using `:param` syntax (e.g., `/users/:id`)
119
- - **Navigation links**: Use `Router.link()` for SPA navigation without page reload
120
- - **Reactive location**: Access current route via `Router.location` signal
88
+ ### Component System
121
89
 
122
- ## Server-Side Rendering (SSR)
123
-
124
- Xote supports server-side rendering with hydration. The same component code runs on both server and client, with the server rendering HTML and the client attaching reactivity to the existing DOM.
125
-
126
- ### Basic SSR Setup
127
-
128
- **Shared component** (`App.res`):
129
- ```rescript
130
- open Xote
131
-
132
- let makeAppState = () => {
133
- // SSRState.make creates a signal that syncs between server and client
134
- let count = SSRState.make("count", 0, SSRState.Codec.int)
135
- let items = SSRState.make("items", ["Apple", "Banana"], SSRState.Codec.array(SSRState.Codec.string))
136
- (count, items)
137
- }
138
-
139
- let app = (count, items) => () => {
140
- <div>
141
- <p> {Node.signalText(() => `Count: ${Signal.get(count)->Int.toString}`)} </p>
142
- <button onClick={_ => Signal.update(count, n => n + 1)}>
143
- {Node.text("+")}
144
- </button>
145
- </div>
146
- }
147
- ```
148
-
149
- **Server entry** (`server.res`):
150
- ```rescript
151
- open Xote
152
-
153
- let (count, items) = App.makeAppState()
154
- let appComponent = App.app(count, items)
155
-
156
- let html = SSR.renderDocument(
157
- ~head="<title>My App</title>",
158
- ~scripts=["./client.res.mjs"],
159
- ~stateScript=SSRState.generateScript(),
160
- appComponent,
161
- )
162
-
163
- Console.log(html)
164
- ```
165
-
166
- **Client entry** (`client.res`):
167
- ```rescript
168
- open Xote
90
+ On top of the reactive primitives with signals, Xote provides a declarative component system:
169
91
 
170
- let (count, items) = App.makeAppState()
171
- let appComponent = App.app(count, items)
172
-
173
- Hydration.hydrateById(appComponent, "root")
174
- ```
175
-
176
- ### Running the SSR Example
177
-
178
- ```bash
179
- # Generate HTML
180
- node server.res.mjs > index.html
181
-
182
- # Serve with Vite (or any static server)
183
- npx vite
184
- ```
185
-
186
- ### SSR Features
187
-
188
- - **`SSR.renderToString`**: Render component to HTML string
189
- - **`SSR.renderDocument`**: Render full HTML document with head, scripts, styles
190
- - **`SSRState.make`**: Create signals that automatically sync between server and client
191
- - **`SSRState.generateScript`**: Generate `<script>` tag with serialized state
192
- - **`Hydration.hydrate`**: Attach reactivity to server-rendered DOM
193
- - **`SSRContext.isServer` / `isClient`**: Environment detection for conditional logic
194
-
195
- ### Built-in Codecs for State Serialization
196
-
197
- ```rescript
198
- SSRState.Codec.int
199
- SSRState.Codec.float
200
- SSRState.Codec.string
201
- SSRState.Codec.bool
202
- SSRState.Codec.array(itemCodec)
203
- SSRState.Codec.option(itemCodec)
204
- SSRState.Codec.dict(valueCodec)
205
- SSRState.Codec.tuple2(codec1, codec2)
206
- SSRState.Codec.tuple3(codec1, codec2, codec3)
207
- SSRState.Codec.make(~encode, ~decode) // Custom codec
208
- ```
209
-
210
- ## Examples
211
-
212
- Check some examples of applications built with Xote at https://brnrdog.github.io/xote/demos/.
213
-
214
- ### Running Examples Locally
215
-
216
- To run the example demos locally:
217
-
218
- 1. Clone the repository:
219
- ```bash
220
- git clone https://github.com/brnrdog/xote.git
221
- cd xote
222
- ```
223
-
224
- 2. Install dependencies:
225
- ```bash
226
- npm install
227
- ```
228
-
229
- 3. Compile ReScript and start the dev server:
230
- ```bash
231
- npm run res:dev # In one terminal (watches ReScript files)
232
- npm run dev # In another terminal (starts Vite dev server)
233
- ```
234
-
235
- 4. Open your browser and navigate to `http://localhost:5173`
236
-
237
- The demo app includes a navigation menu to explore all examples interactively.
238
-
239
- ## Documentation
240
-
241
- Comprehensive documentation with live embedded demos is available at:
242
-
243
- **https://brnrdog.github.io/xote/**
244
-
245
-
246
- ### Building Documentation Locally
247
-
248
- To build and preview the documentation site:
249
-
250
- ```bash
251
- npm run docs:start
252
- ```
253
-
254
- This will build the demos and start the documentation server at `http://localhost:3000`.
92
+ - **JSX Support**: Build user interface using JSX, in a declarative and familiar manner
93
+ - **Reactive DOM Nodes**: Fine-grained reactivity that updates DOM nodes directly, no virtual DOM required
94
+ - **Built-in Router**: Client-side routing with pattern matching and reactive location state
95
+ - **Automatic Cleanup**: Effect disposal and memory management built into the component lifecycle
96
+ - **Server-side Rendering**: pre-render your pages on the server with full hydration
255
97
 
256
98
  ## License
257
99
 
package/package.json CHANGED
@@ -1,11 +1,21 @@
1
1
  {
2
2
  "name": "xote",
3
- "version": "6.0.0",
3
+ "version": "6.0.1",
4
4
  "repository": {
5
5
  "url": "https://github.com/brnrdog/xote"
6
6
  },
7
7
  "main": "./dist/xote.cjs",
8
8
  "module": "./dist/xote.mjs",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/xote.mjs",
12
+ "require": "./dist/xote.cjs",
13
+ "default": "./dist/xote.mjs"
14
+ },
15
+ "./src/*": "./src/*",
16
+ "./package.json": "./package.json",
17
+ "./rescript.json": "./rescript.json"
18
+ },
9
19
  "sideEffects": false,
10
20
  "files": [
11
21
  "dist",