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.
- package/README.md +33 -191
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
# xote
|
|
1
|
+
# [Xote](https://brnrdog.github.io/xote/)
|
|
2
2
|

|
|
3
3
|

|
|
4
4
|

|
|
5
5
|
|
|
6
|
-
Xote is a lightweight
|
|
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
|
|
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
|
-
//
|
|
70
|
-
let
|
|
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.
|
|
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={
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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.
|
|
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",
|