cajoa 0.7.0 → 0.8.0

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 +83 -33
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -3,22 +3,34 @@
3
3
  A small, beginner-friendly frontend framework built on **signals** and **JSX**.
4
4
  No virtual DOM, no hooks rules, no re-rendering components.
5
5
 
6
- > ⚠️ **v0.6 (early stage).** The API may still change. Not production-ready yet.
6
+ > ⚠️ **Early stage.** The API may still change before 1.0.
7
7
 
8
8
  ## Why Cajoa?
9
9
 
10
10
  - **Components run once.** A component is just a function that builds DOM. Only the parts that depend on a signal update.
11
11
  - **Plain JSX.** Write `<button onClick={...}>`, no special syntax to learn.
12
- - **Tiny and readable.** The whole core is small enough to read in one sitting.
12
+ - **Tiny and readable.** The core is small enough to read in one sitting.
13
+ - **Renderer-agnostic core.** `@cajoa/core` has no DOM dependency, so other targets (native, SSR) can plug in their own renderer.
13
14
  - **TypeScript-first**, ESM + CommonJS, zero runtime dependencies.
14
15
 
15
- ## Install
16
+ ## Get started
17
+
18
+ The fastest way is the starter:
16
19
 
17
20
  ```bash
18
21
  npm create cajoa@latest my-app
22
+ cd my-app
23
+ npm install
24
+ npm run dev
19
25
  ```
20
26
 
21
- ## Setup (JSX)
27
+ Or add Cajoa to an existing project:
28
+
29
+ ```bash
30
+ npm install cajoa
31
+ ```
32
+
33
+ ### Manual JSX setup
22
34
 
23
35
  In your `tsconfig.json`:
24
36
 
@@ -31,7 +43,7 @@ In your `tsconfig.json`:
31
43
  }
32
44
  ```
33
45
 
34
- If you use Vite and your JSX is not transformed, also set it in `vite.config.ts`
46
+ With Vite, also set it in `vite.config.ts`
35
47
  (`oxc: { jsx: { runtime: "automatic", importSource: "cajoa" } }` on newer Vite,
36
48
  or `esbuild: { jsx: "automatic", jsxImportSource: "cajoa" }` on older ones).
37
49
 
@@ -55,7 +67,7 @@ render(Counter, document.getElementById("app")!);
55
67
 
56
68
  ## Two rules to remember
57
69
 
58
- Cajoa has no compiler, so JSX expressions run exactly once. That gives two rules:
70
+ Cajoa has no compiler yet, so JSX expressions run exactly once. That gives two rules:
59
71
 
60
72
  1. **Pass the signal, don't call it.**
61
73
  `{count}` is reactive. `{count()}` is read once and never updates.
@@ -82,6 +94,37 @@ const [todos, setTodos] = createSignal([{ id: 1, text: "Learn Cajoa" }]);
82
94
 
83
95
  ## Routing
84
96
 
97
+ ## Forms, styles and events
98
+
99
+ ```tsx
100
+ const [name, setName] = createSignal("");
101
+ const [agree, setAgree] = createSignal(false);
102
+
103
+ <form>
104
+ <input
105
+ placeholder="Name"
106
+ value={name}
107
+ onInput={(e) => setName(e.target.value)}
108
+ />
109
+ <label>
110
+ <input
111
+ type="checkbox"
112
+ checked={agree}
113
+ onChange={(e) => setAgree(e.target.checked)}
114
+ />
115
+ I agree
116
+ </label>
117
+ <p style={() => ({ color: agree() ? "green" : "gray", fontSize: "18px" })}>
118
+ Hello, {() => name() || "stranger"}!
119
+ </p>
120
+ </form>;
121
+ ```
122
+
123
+ - `value`, `checked` and `selected` are set as DOM properties, so they stay in sync even after the user typed. Write `value` after `type`, `min` and `max`.
124
+ - `style` takes a string or an object (camelCase keys, kebab-case keys, or custom properties like `--accent`). Numbers are not converted to `px`, so write `"12px"`. For a reactive style, pass a function: `style={() => ({ color: color() })}`. An object with signals inside, like `style={{ color: color() }}`, is read once.
125
+ - Events are native DOM events. `onChange` fires when a field loses focus, so use `onInput` for every keystroke. `onDoubleClick` listens to `dblclick`.
126
+ - `className` and `htmlFor` work. Inline string handlers like `onclick="..."` are ignored.
127
+
85
128
  ```tsx
86
129
  import { render, Router, Route, Link, useParams } from "cajoa";
87
130
 
@@ -106,6 +149,15 @@ render(
106
149
 
107
150
  Routes are matched in order, so put `path="*"` last.
108
151
 
152
+ ## Packages
153
+
154
+ | Package | What it is |
155
+ | -------------- | ------------------------------------------------------------------------------------------ |
156
+ | `cajoa` | The package most apps install (core + DOM) |
157
+ | `@cajoa/core` | Renderer-agnostic core: signals, JSX runtime, `Show`, `For`, context, `Renderer` interface |
158
+ | `@cajoa/dom` | DOM renderer and router |
159
+ | `create-cajoa` | Project starter (`npm create cajoa@latest`) |
160
+
109
161
  ## API
110
162
 
111
163
  ### Reactivity
@@ -116,13 +168,15 @@ Routes are matched in order, so put `path="*"` last.
116
168
  | `createEffect(fn)` | Runs `fn` now and again whenever a signal it read changes. |
117
169
  | `createMemo(fn)` | Cached computed value. Only notifies when the result changes. |
118
170
  | `batch(fn)` | Groups several `set` calls into one update. |
171
+ | `untrack(fn)` | Runs `fn` without subscribing to signals. |
119
172
 
120
173
  ### Components
121
174
 
122
- | Component | What it does |
123
- | ---------------------- | ---------------------------------------------------------------------------------------------------- |
124
- | `<Show when fallback>` | Conditional rendering. `children` and `fallback` are functions. |
125
- | `<For each key?>` | List rendering. Reuses DOM nodes for unchanged items. The child is a function that returns a `Node`. |
175
+ | Component | What it does |
176
+ | ---------------------- | --------------------------------------------------------------------------------------------------------- |
177
+ | `<Show when fallback>` | Conditional rendering. `children` and `fallback` are functions. |
178
+ | `<For each key?>` | List rendering. Reuses DOM nodes for unchanged items. The child is a function that returns a single node. |
179
+ | `<>...</>` (Fragment) | Groups siblings without a wrapper element. |
126
180
 
127
181
  ### Rendering
128
182
 
@@ -157,7 +211,6 @@ Routes are matched in order, so put `path="*"` last.
157
211
  | `navigate(to, { replace? })` | Navigates programmatically. |
158
212
  | `useParams()` | Reads the route params (`{ id: "7" }`). |
159
213
  | `usePath()` | Returns a signal getter for the current pathname. |
160
- | `untrack(fn)` | Runs `fn` without subscribing to signals. |
161
214
 
162
215
  ### Renderer
163
216
 
@@ -167,20 +220,12 @@ Routes are matched in order, so put `path="*"` last.
167
220
  | `getRenderer()` | Returns the current renderer. |
168
221
  | `domRenderer` | The built-in DOM renderer. |
169
222
 
170
- ## Packages
171
-
172
- | Package | What it is |
173
- | ------------- | -------------------------------------------------------------------- |
174
- | `cajoa` | The package most apps install (core + DOM) |
175
- | `@cajoa/core` | Renderer-agnostic core: signals, JSX runtime, `Show`, `For`, context |
176
- | `@cajoa/dom` | DOM renderer and router |
177
-
178
223
  ## Good to know
179
224
 
180
225
  - `For` uses the item itself as the key by default. If you pass `key`, items with the same key are **not** re-rendered when their data changes, so keys must be unique and the item should hold its own signals if it needs to update.
181
- - `useContext` only works while a component is being created (or inside `onMount` / effects). Read it at the top of your component and use the value later in handlers.
226
+ - Inside `<For>`, return a single element (not a fragment), because `For` reuses that node.
227
+ - `useContext` and `useParams` only work while a component is being created (or inside `onMount` / effects). Read them at the top of your component and use the value later in handlers.
182
228
  - Updating an object in place will not trigger effects. Set a new object instead.
183
- - Fragments (`<>...</>`) work anywhere, but inside `<For>` the child must be a single element, because `For` reuses that node.
184
229
 
185
230
  ## Known limitations
186
231
 
@@ -188,26 +233,29 @@ Routes are matched in order, so put `path="*"` last.
188
233
  - Router: pathname only (no query/hash handling), no nested routes, no `base` path.
189
234
  - `<Show>` and `<Router>` return a function, so they must sit inside an element, not be the root returned by `render`.
190
235
  - Single-page apps need a server fallback to `index.html` for unknown paths.
236
+ - SVG is not supported yet: `<svg>` is created as an HTML element, so it does not render.
237
+ - No `ref` prop yet.
238
+ - `<select value>` works only when the `<option>` elements are direct children of the `<select>`.
191
239
  - `createMemo` can show a brief inconsistent state when memos depend on each other.
192
240
  - `set` calls are not batched automatically inside event handlers. Wrap them in `batch()`.
193
- - The Router and event names (`onClick`) are still web-specific for now.
241
+ - Types in the core use a loose `HostNode` type for now.
194
242
 
195
243
  ## Roadmap
196
244
 
197
- - [x] Signals and effects
198
- - [x] DOM bindings and `render`
199
- - [x] `Show`, `For` (keyed)
200
- - [x] Lifecycle and disposal
201
- - [x] `createMemo`, `batch`
202
- - [x] Context
245
+ - [x] Signals, effects, memo, batch
246
+ - [x] DOM bindings, `Show`, keyed `For`, Fragments
247
+ - [x] Lifecycle, context
203
248
  - [x] JSX support
204
- - [x] Fragments
205
249
  - [x] Router
206
- - [x] Renderer abstraction (core no longer depends on DOM)
207
- - [ ] Split into packages ('@cajoa/core', '@cajoa/dom')
250
+ - [x] Renderer abstraction, split into packages
251
+ - [x] Automated releases
252
+ - [x] Form, style and event handling in the DOM renderer
253
+ - [ ] SVG and `ref` support
208
254
  - [ ] Vite plugin (removes the two rules above)
209
- - [ ] Native renderer (mobile, desktop)
255
+ - [ ] Better form and style handling in the DOM renderer
256
+ - [ ] Native renderers (mobile, desktop)
210
257
  - [ ] SSR
258
+ - [ ] Docs site
211
259
 
212
260
  ## Development
213
261
 
@@ -215,9 +263,11 @@ Routes are matched in order, so put `path="*"` last.
215
263
  npm install
216
264
  npm test # run tests
217
265
  npm run dev # open the playground
218
- npm run build # build to dist/
266
+ npm run verify # typecheck, tests, build, sync and package checks
219
267
  ```
220
268
 
269
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for the release flow.
270
+
221
271
  ## License
222
272
 
223
273
  [Apache-2.0](./LICENSE)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cajoa",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "A small, beginner-friendly frontend framework built on signals and JSX.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -56,8 +56,8 @@
56
56
  ],
57
57
  "sideEffects": true,
58
58
  "dependencies": {
59
- "@cajoa/core": "^0.7.0",
60
- "@cajoa/dom": "^0.7.0"
59
+ "@cajoa/core": "^0.8.0",
60
+ "@cajoa/dom": "^0.8.0"
61
61
  },
62
62
  "scripts": {
63
63
  "build": "tsup src/index.ts --format esm,cjs --dts --clean",