@lankajs/solid 0.1.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.
- package/LICENSE +21 -0
- package/README.md +43 -0
- package/dist/chunk-5WRI5ZAA.js +31 -0
- package/dist/chunk-5WRI5ZAA.js.map +1 -0
- package/dist/index.d.ts +109 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/testing.d.ts +46 -0
- package/dist/testing.js +12638 -0
- package/dist/testing.js.map +1 -0
- package/package.json +56 -0
- package/skills/lanka-solid/SKILL.md +157 -0
- package/skills/lanka-solid/reference.md +222 -0
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lankajs/solid",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "module: One function — `useLankaVM` — over a signal, and the access tracking core already does.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/lankajs/lanka.git",
|
|
10
|
+
"directory": "modules/bindings/solid"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/lankajs/lanka/tree/main/modules/bindings/solid#readme",
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./testing": {
|
|
21
|
+
"types": "./dist/testing.d.ts",
|
|
22
|
+
"default": "./dist/testing.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"LICENSE",
|
|
29
|
+
"README.md",
|
|
30
|
+
"skills"
|
|
31
|
+
],
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"lanka": "^2.0.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@solidjs/testing-library": "^0.8.10",
|
|
37
|
+
"@lankajs/tool-testing": "^2.0.0"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"solid-js": "^1.9.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependenciesMeta": {
|
|
43
|
+
"@solidjs/testing-library": {
|
|
44
|
+
"optional": true
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsup",
|
|
49
|
+
"lint": "eslint src _playground --max-warnings=0",
|
|
50
|
+
"test": "vitest run",
|
|
51
|
+
"test:coverage": "vitest run --coverage",
|
|
52
|
+
"test:watch": "vitest",
|
|
53
|
+
"bench": "vitest bench --run",
|
|
54
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lanka-solid
|
|
3
|
+
description: Read a lanka ViewModel from a Solid component with useLankaVM, which answers an Accessor, or read it the way Solid reads a store with toLankaSolidVM. Use when writing or reviewing a Solid or SolidStart screen in a lanka application, when JSX does not update after state changed, when a read outside an owner leaks a subscription, when deciding where a ViewModel's writes belong, or when reviewing code that imports `@lankajs/solid`.
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
author: lankajs
|
|
7
|
+
package: @lankajs/solid
|
|
8
|
+
version: "0.1.0"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# @lankajs/solid
|
|
12
|
+
|
|
13
|
+
One call to read a ViewModel, plus the store-shaped read Solid expects for an
|
|
14
|
+
object. `reference.md` beside this file is the full guide.
|
|
15
|
+
|
|
16
|
+
> [!NOTE]
|
|
17
|
+
> Only what the framework or a gate refuses is binding. Everything else here is a
|
|
18
|
+
> recommendation you can adapt.
|
|
19
|
+
|
|
20
|
+
## Pick the call
|
|
21
|
+
|
|
22
|
+
| The situation | Use |
|
|
23
|
+
| ----------------------------------------- | ----------------------------------------------- |
|
|
24
|
+
| a component reads a ViewModel | `useLankaVM(todoVM)` — an `Accessor` |
|
|
25
|
+
| it needs one derived value | `useLankaVM(todoVM, (s) => s.todos.length)` |
|
|
26
|
+
| the codebase reads like `createStore` | `toLankaSolidVM(todoVM)` — `todos.rows` |
|
|
27
|
+
| outside a component — a handler, a module | `todoVM.getState()` |
|
|
28
|
+
| a component test | `renderWithLanka` from `@lankajs/solid/testing` |
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { For, Show } from "solid-js";
|
|
32
|
+
import { useLankaVM } from "@lankajs/solid";
|
|
33
|
+
import { todoVM } from "./todoVM";
|
|
34
|
+
|
|
35
|
+
export const TodoScreen = () => {
|
|
36
|
+
const state = useLankaVM(todoVM);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<Show when={!state().isLoading} fallback={<p>loading</p>}>
|
|
40
|
+
<ul onClick={() => void state().load()}>
|
|
41
|
+
<For each={state().todos}>{(todo) => <li>{todo.title}</li>}</For>
|
|
42
|
+
</ul>
|
|
43
|
+
</Show>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
It answers an **`Accessor`** — Solid's own idea of reactivity, which is the one
|
|
49
|
+
thing the shelf does not make uniform. Call it where you read: `state().todos`
|
|
50
|
+
inside the JSX, not destructured above it.
|
|
51
|
+
|
|
52
|
+
## The store-shaped read
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { toLankaSolidVM } from "@lankajs/solid";
|
|
56
|
+
|
|
57
|
+
const todos = toLankaSolidVM(todoVM);
|
|
58
|
+
|
|
59
|
+
<For each={todos.rows}>{(row) => <li>{row}</li>}</For>;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
No call, and the read itself is the subscription: it registers the surrounding
|
|
63
|
+
computation with Solid AND records the key in the access tracker, in one access,
|
|
64
|
+
so a view that never read `unread` is not re-run when it moves.
|
|
65
|
+
|
|
66
|
+
**It is the read half only.** Solid's store is a write path as well, and a
|
|
67
|
+
ViewModel's writes belong to its actions; a `setStore` beside them would be a
|
|
68
|
+
second place state changes. `$stop` is the one meta member, `$`-prefixed so it
|
|
69
|
+
cannot collide with a state key.
|
|
70
|
+
|
|
71
|
+
## What re-renders
|
|
72
|
+
|
|
73
|
+
Without a selector the accessor carries a value that RECORDS which keys you read,
|
|
74
|
+
and the next change re-runs a computation only if one of those moved. With a
|
|
75
|
+
selector, the selector decides and tracking is bypassed.
|
|
76
|
+
|
|
77
|
+
Tracking earns its place even in a framework that already skips work: without it
|
|
78
|
+
every change writes a new object into the signal and every expression reading ANY
|
|
79
|
+
part of it re-runs. The tracker keeps the signal UNCHANGED when nothing you read
|
|
80
|
+
moved — and an unchanged signal is work Solid never starts.
|
|
81
|
+
|
|
82
|
+
> [!WARNING]
|
|
83
|
+
> **The blind spot.** Tracking sees keys you read DIRECTLY. A key reached only
|
|
84
|
+
> inside a derived getter is invisible to it, so a change to that key re-runs
|
|
85
|
+
> nothing and the screen freezes with no error. Set
|
|
86
|
+
> `enableAccessTrackingOptimization: false` on such a ViewModel. Do NOT read the
|
|
87
|
+
> underlying keys in the view "for the side effect": that is dead code, and a
|
|
88
|
+
> refactor or a lint autofix removes it. In development the framework announces
|
|
89
|
+
> the mismatch by ViewModel and key name.
|
|
90
|
+
|
|
91
|
+
## Releasing the subscription
|
|
92
|
+
|
|
93
|
+
Inside a component or a root, `onCleanup` releases it with the owner and you do
|
|
94
|
+
nothing. Called outside one there is no owner, so the accessor carries `stop()`
|
|
95
|
+
and you own it.
|
|
96
|
+
|
|
97
|
+
## Testing
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
import { renderWithLanka } from "@lankajs/solid/testing";
|
|
101
|
+
|
|
102
|
+
renderWithLanka(() => <TodoScreen />, {
|
|
103
|
+
fakes: { gateways: { TodoGateway: { list: () => Promise.resolve([]) } } },
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Every call gets a fresh instance and disposes the previous one.
|
|
108
|
+
|
|
109
|
+
## A selector that builds an object
|
|
110
|
+
|
|
111
|
+
A selector answering a fresh object is never identical to its own last answer,
|
|
112
|
+
so the reader wakes for EVERY change in the ViewModel — including the keys the
|
|
113
|
+
selector exists to ignore. Hold it:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { createLankaShallowHold } from "lanka/viewmodel";
|
|
117
|
+
|
|
118
|
+
const hold = createLankaShallowHold<{ title: string }>();
|
|
119
|
+
const mission = useLankaVM(missionVM, (s) => hold({ title: s.title }));
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
One hold per reader, declared inside the component — never at module level and never
|
|
123
|
+
shared between two components. A selector answering a **primitive** needs none
|
|
124
|
+
of this. The comparison is one level deep: own keys, same count, `Object.is` on
|
|
125
|
+
each value, arrays included.
|
|
126
|
+
|
|
127
|
+
## Never do these
|
|
128
|
+
|
|
129
|
+
- **Never pass an object-building selector without a hold.** The reader then
|
|
130
|
+
wakes for every change in the ViewModel, selector or no selector.
|
|
131
|
+
- **Never destructure the accessor's value.** `const { todos } = state()` reads
|
|
132
|
+
once, outside any computation, and never tracks again.
|
|
133
|
+
- **Never call the accessor above the JSX.** `const todos = state().todos` at the
|
|
134
|
+
top of a component reads in the component body, which runs once; read where the
|
|
135
|
+
value is used.
|
|
136
|
+
- **Never write through `toLankaSolidVM`.** It is the read half; writes are the
|
|
137
|
+
ViewModel's actions, and a second write path is a second place state changes.
|
|
138
|
+
- **Never leave a read outside an owner unstopped.** No owner means no
|
|
139
|
+
`onCleanup`, so `$stop` or `stop()` is yours to call.
|
|
140
|
+
- **Never assume Solid's fine-grained updates make tracking redundant.** Without
|
|
141
|
+
it every reader of the signal re-runs.
|
|
142
|
+
|
|
143
|
+
## Symptom → cause
|
|
144
|
+
|
|
145
|
+
| What you see | What it is |
|
|
146
|
+
| ------------------------------------------------- | ------------------------------------------------- |
|
|
147
|
+
| a screen repainting for changes it never selected | an object selector with no hold |
|
|
148
|
+
| the first paint is right, nothing updates | the accessor's value was destructured |
|
|
149
|
+
| a whole component re-runs on any change | the accessor read once, above the JSX |
|
|
150
|
+
| the screen never updates, no error | the tracking blind spot — a derived getter |
|
|
151
|
+
| a subscription outliving the component | a read outside an owner, `stop()` never called |
|
|
152
|
+
| state changing from two places | a write path added beside the ViewModel's actions |
|
|
153
|
+
|
|
154
|
+
## More
|
|
155
|
+
|
|
156
|
+
`reference.md` — the full guide: the tracking rules, the store-shaped read in
|
|
157
|
+
detail, and what this package deliberately is not.
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
<!-- Generated from modules/bindings/solid/GUIDE.md by scripts/skills.mjs. Edit the guide. -->
|
|
2
|
+
|
|
3
|
+
> **`@lankajs/solid@0.1.0`** — this document describes that version.
|
|
4
|
+
>
|
|
5
|
+
> Install: `npm install @lankajs/solid solid-js zustand` (the peers are not optional; only npm adds a missing one for you).
|
|
6
|
+
>
|
|
7
|
+
> Complete code, compiled and run in CI: [modules/bindings/solid/_playground/playground.test.tsx](https://github.com/lankajs/lanka/blob/main/modules/bindings/solid/_playground/playground.test.tsx)
|
|
8
|
+
|
|
9
|
+
# @lankajs/solid — user guide
|
|
10
|
+
|
|
11
|
+
How a Solid component reads a lanka ViewModel.
|
|
12
|
+
|
|
13
|
+
## You will learn
|
|
14
|
+
|
|
15
|
+
- the one call this package publishes, and what it answers
|
|
16
|
+
- when a component re-renders and when it deliberately does not
|
|
17
|
+
- why a selector that builds an object needs a hold, and when it needs nothing
|
|
18
|
+
- what to do about a ViewModel that derives what the screen shows
|
|
19
|
+
- how to test a Solid component with a live framework behind it
|
|
20
|
+
|
|
21
|
+
## When to reach for this
|
|
22
|
+
|
|
23
|
+
Reach for it the moment a Solid component has to read a lanka ViewModel — that
|
|
24
|
+
is the whole job, and there is no other supported way to do it. Install this one
|
|
25
|
+
package and no other binding: the five are alternatives, not layers.
|
|
26
|
+
|
|
27
|
+
You do NOT need it to reach the rest of the framework. Gateways, scenarios and
|
|
28
|
+
the locator are plain calls with no view in them, and `viewModel.getState()`
|
|
29
|
+
works anywhere, including on a server.
|
|
30
|
+
|
|
31
|
+
> [!NOTE]
|
|
32
|
+
> Everything below is how this package is _meant_ to be used, not how it must
|
|
33
|
+
> be. The framework bends at the seams it publishes — see
|
|
34
|
+
> [ARCHITECTURE.md](https://github.com/lankajs/lanka/blob/main/ARCHITECTURE.md) for what is checked and what is
|
|
35
|
+
> merely advice.
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install @lankajs/solid solid-js zustand
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
> [!IMPORTANT]
|
|
44
|
+
> `solid-js` is already in your project; `zustand` is `lanka`'s own peer. npm
|
|
45
|
+
> adds a missing peer for you and pnpm does not, so the line names all of them.
|
|
46
|
+
|
|
47
|
+
## The one call
|
|
48
|
+
|
|
49
|
+
`useLankaVM` is a function. Every member of `modules/bindings/` publishes that same
|
|
50
|
+
name, so moving a screen from one framework to another rewrites the view and not
|
|
51
|
+
the vocabulary.
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { For, Show } from "solid-js";
|
|
55
|
+
import { useLankaVM } from "@lankajs/solid";
|
|
56
|
+
import { todoVM } from "./todoVM";
|
|
57
|
+
|
|
58
|
+
export const TodoScreen = () => {
|
|
59
|
+
const state = useLankaVM(todoVM);
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<Show when={!state().isLoading} fallback={<p>loading</p>}>
|
|
63
|
+
<ul onClick={() => void state().load()}>
|
|
64
|
+
<For each={state().todos}>{(todo) => <li>{todo.title}</li>}</For>
|
|
65
|
+
</ul>
|
|
66
|
+
</Show>
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
It answers **an `Accessor`** — the one thing this shelf does not make uniform,
|
|
72
|
+
because that is Solid's own idea of reactivity and a binding that hid it
|
|
73
|
+
would be a second reactivity system fighting the first.
|
|
74
|
+
|
|
75
|
+
## Reading it the way Solid reads an object
|
|
76
|
+
|
|
77
|
+
`useLankaVM` answers an `Accessor`, which is Solid's own shape for a value and
|
|
78
|
+
the one every other binding on the shelf parallels: `state().rows`.
|
|
79
|
+
|
|
80
|
+
It is not how Solid holds an OBJECT. `createStore` gives a proxy read as
|
|
81
|
+
`state.rows` — no call, and the read itself is the subscription — so this package
|
|
82
|
+
publishes the read half of that shape:
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
import { toLankaSolidVM } from "@lankajs/solid";
|
|
86
|
+
|
|
87
|
+
const todos = toLankaSolidVM(todosVM);
|
|
88
|
+
|
|
89
|
+
<For each={todos.rows}>{(row) => <li>{row}</li>}</For>;
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The read registers the surrounding computation with Solid AND records the key in
|
|
93
|
+
the access tracker, in one access — so a view that never read `unread` is not
|
|
94
|
+
re-run when it moves.
|
|
95
|
+
|
|
96
|
+
It is the read half only. Solid's store is a write path as well, and a
|
|
97
|
+
ViewModel's writes belong to its actions; a `setStore` beside them would be a
|
|
98
|
+
second place state changes.
|
|
99
|
+
|
|
100
|
+
`$stop` is the one member it adds, `$`-prefixed so it cannot collide with a
|
|
101
|
+
state key. An owner releases the subscription for you; a reader built outside
|
|
102
|
+
one has none, so that call is yours.
|
|
103
|
+
|
|
104
|
+
## What re-renders, and what does not
|
|
105
|
+
|
|
106
|
+
Without a selector you get a value that RECORDS which keys you read. The next
|
|
107
|
+
change re-renders only if one of those moved:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
// reads `todos`; a change to `isLoading` alone repaints nothing
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
With a selector, the selector decides and tracking is bypassed:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
const count = useLankaVM(todoVM, (state) => state.todos.length);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
> [!WARNING]
|
|
120
|
+
> **The blind spot.** Tracking sees keys you read DIRECTLY. A key reached only
|
|
121
|
+
> inside a derived getter — an action calling `get()` — is invisible to it, so a
|
|
122
|
+
> change to that key re-renders nothing and the screen freezes with no error.
|
|
123
|
+
>
|
|
124
|
+
> Set `enableAccessTrackingOptimization: false` on such a ViewModel. Do NOT patch
|
|
125
|
+
> it in the view by reading the underlying keys "for the side effect": that is
|
|
126
|
+
> dead code, and a refactor or a lint autofix removes it.
|
|
127
|
+
>
|
|
128
|
+
> In development the framework announces the mismatch by ViewModel and key name.
|
|
129
|
+
|
|
130
|
+
## A selector that builds its answer
|
|
131
|
+
|
|
132
|
+
`useLankaVM(vm, (state) => ({ … }))` is safe — nothing loops — but on its own it
|
|
133
|
+
wakes the reader for **every** change in the ViewModel, including the keys the
|
|
134
|
+
selector exists to ignore. The reason is identity: that object is new on every
|
|
135
|
+
call, and a binding compares selections with `Object.is`.
|
|
136
|
+
|
|
137
|
+
`createLankaShallowHold` is the comparison that fixes it. It answers the
|
|
138
|
+
PREVIOUS object while nothing in the selection moved, one level deep — own keys,
|
|
139
|
+
same count, `Object.is` on each value, arrays included:
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
import { createLankaShallowHold } from "lanka/viewmodel";
|
|
143
|
+
import { useLankaVM } from "@lankajs/solid";
|
|
144
|
+
|
|
145
|
+
export const MissionScreen = () => {
|
|
146
|
+
const hold = createLankaShallowHold<{ title: string; status: string }>();
|
|
147
|
+
const mission = useLankaVM(missionVM, (state) =>
|
|
148
|
+
hold({ title: state.title, status: state.status }),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<h1>
|
|
153
|
+
{mission().title} — {mission().status}
|
|
154
|
+
</h1>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
One hold per reader, created inside the component beside the read — never at
|
|
160
|
+
module level and never shared between two of them, because the answer it holds
|
|
161
|
+
belongs to whoever selected it.
|
|
162
|
+
|
|
163
|
+
A selector answering a **primitive** needs none of this: `(state) => state.title`
|
|
164
|
+
compares equal to itself and was always free. A selection with a **nested**
|
|
165
|
+
object wants a selector that picks the leaves — comparing deeper would mean
|
|
166
|
+
walking a state of unknown size on every read, which is the cost a selector was
|
|
167
|
+
taken to avoid.
|
|
168
|
+
|
|
169
|
+
## Releasing the subscription
|
|
170
|
+
|
|
171
|
+
Inside a component or a root, `onCleanup` releases the subscription with the
|
|
172
|
+
owner and you do nothing. Called outside one there is no owner, so the accessor
|
|
173
|
+
carries `stop()` and you own it.
|
|
174
|
+
|
|
175
|
+
## Why tracking earns its place in a framework that already skips work
|
|
176
|
+
|
|
177
|
+
Solid re-runs only what a changed signal fed, so a coarse binding would be less
|
|
178
|
+
wrong here than elsewhere. It would still be wrong: without tracking, every
|
|
179
|
+
change writes a new object into the signal and every expression reading ANY part
|
|
180
|
+
of it re-runs. The tracker is what keeps the signal UNCHANGED when nothing you
|
|
181
|
+
read moved — and an unchanged signal is work Solid never starts.
|
|
182
|
+
|
|
183
|
+
## Testing
|
|
184
|
+
|
|
185
|
+
`@lankajs/solid/testing` renders a component with a bootstrapped framework, so a component
|
|
186
|
+
test needs no bootstrap preamble of its own:
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
import { renderWithLanka } from "@lankajs/solid/testing";
|
|
190
|
+
|
|
191
|
+
renderWithLanka(TodoScreen, {
|
|
192
|
+
fakes: { gateways: { TodoGateway: { list: () => Promise.resolve([]) } } },
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Every call gets a FRESH instance and disposes the previous one, so a test never
|
|
197
|
+
inherits its neighbour's subscriptions.
|
|
198
|
+
|
|
199
|
+
## What this package is not
|
|
200
|
+
|
|
201
|
+
It is a subscription and a render trigger, and nothing else. The recording of
|
|
202
|
+
which keys you read, the comparison that decides whether a change is worth a
|
|
203
|
+
render, and the blind-spot warning are all in `lanka` itself — which is why the
|
|
204
|
+
behaviour you see is the framework's rather than this package's reading of it,
|
|
205
|
+
and why `lankaViewBindingConformance` can hold every binding to one list.
|
|
206
|
+
|
|
207
|
+
If this package ever needs more than the ViewModel port gives it, the port has
|
|
208
|
+
the defect and the fix belongs in `lanka`, for every framework at once.
|
|
209
|
+
|
|
210
|
+
## Recap
|
|
211
|
+
|
|
212
|
+
- `useLankaVM(todoVM)` is the one call, and every binding publishes that name.
|
|
213
|
+
- It answers an `Accessor`: `state().todos`. That difference is Solid's, and the shelf does not hide it.
|
|
214
|
+
- Tracking still earns its place: without it every change writes a new object into the signal and every effect reading any part of it re-runs.
|
|
215
|
+
- A key reached only through a derived getter is invisible to tracking: set `enableAccessTrackingOptimization: false` on that ViewModel.
|
|
216
|
+
- `toLankaSolidVM` reads the way a Solid store does, for the read half only — writes stay in the ViewModel's actions.
|
|
217
|
+
- Inside a component or a root the subscription is released for you; outside one, `$stop()` is yours to call.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
Maintaining this package: [SKILL.md](https://github.com/lankajs/lanka/blob/main/modules/bindings/solid/SKILL.md) · What it is:
|
|
222
|
+
[README.md](https://github.com/lankajs/lanka/blob/main/modules/bindings/solid/README.md) · Repository map: [../../../README.md](https://github.com/lankajs/lanka/blob/main/README.md)
|