sygnal 6.5.0 → 7.0.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/CHANGELOG.md +156 -0
- package/README.md +2 -0
- package/dist/astro/index.cjs.js +423 -27
- package/dist/astro/index.cjs.js.map +1 -1
- package/dist/astro/index.mjs +423 -27
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/server.cjs.js.map +1 -1
- package/dist/astro/server.mjs.map +1 -1
- package/dist/devtools.cjs.js +141 -3
- package/dist/devtools.cjs.js.map +1 -1
- package/dist/devtools.esm.js +141 -4
- package/dist/devtools.esm.js.map +1 -1
- package/dist/diagnostics.cjs.js +169 -14
- package/dist/diagnostics.cjs.js.map +1 -1
- package/dist/diagnostics.esm.js +168 -15
- package/dist/diagnostics.esm.js.map +1 -1
- package/dist/guide/accessibility.md +2 -0
- package/dist/guide/ai-chat.md +6 -6
- package/dist/guide/behaviors.md +1 -1
- package/dist/guide/element-commands.md +4 -2
- package/dist/guide/forms-reference.md +89 -3
- package/dist/guide/forms.md +8 -8
- package/dist/guide/http.md +77 -7
- package/dist/guide/migrating-to-7.md +314 -0
- package/dist/guide/recipes/ai-summarize.md +2 -1
- package/dist/guide/recipes/i18n.md +1 -1
- package/dist/guide/ui/tabs.md +5 -4
- package/dist/guide/ui/tooltip.md +24 -0
- package/dist/index.cjs.js +781 -320
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +319 -43
- package/dist/index.esm.js +781 -320
- package/dist/index.esm.js.map +1 -1
- package/dist/sygnal.min.js +1 -1
- package/dist/sygnal.min.js.map +1 -1
- package/dist/ui.cjs.js +96 -11
- package/dist/ui.cjs.js.map +1 -1
- package/dist/ui.esm.js +96 -12
- package/dist/ui.esm.js.map +1 -1
- package/dist/vike/config/package.json +1 -1
- package/dist/vike/onRenderClient.cjs.js +63 -43
- package/dist/vike/onRenderClient.cjs.js.map +1 -1
- package/dist/vike/onRenderClient.mjs +63 -43
- package/dist/vike/onRenderClient.mjs.map +1 -1
- package/dist/vike/onRenderHtml.cjs.js +21 -25
- package/dist/vike/onRenderHtml.cjs.js.map +1 -1
- package/dist/vike/onRenderHtml.mjs +21 -25
- package/dist/vike/onRenderHtml.mjs.map +1 -1
- package/dist/vite/plugin.cjs.js +410 -27
- package/dist/vite/plugin.cjs.js.map +1 -1
- package/dist/vite/plugin.mjs +410 -27
- package/dist/vite/plugin.mjs.map +1 -1
- package/llms.txt +17 -16
- package/package.json +1 -1
- package/src/astro/index.d.ts +8 -0
- package/src/astro/index.ts +18 -0
- package/src/core/actions.ts +28 -21
- package/src/core/define.ts +2 -0
- package/src/core/hooks.ts +8 -2
- package/src/core/hosts/collection.ts +4 -3
- package/src/core/instance.ts +60 -16
- package/src/core/runtime.ts +5 -1
- package/src/core/view.ts +2 -0
- package/src/cycle/dom/utils.ts +4 -2
- package/src/devtools.d.ts +13 -0
- package/src/devtools.ts +3 -0
- package/src/extra/ai/chat/behavior.ts +3 -3
- package/src/extra/ai/commandBar.ts +3 -3
- package/src/extra/ai/compose/behavior.ts +3 -3
- package/src/extra/ai/transports/shared.ts +8 -2
- package/src/extra/behaviors.ts +21 -0
- package/src/extra/devGraph.ts +111 -0
- package/src/extra/devMcp.ts +1 -1
- package/src/extra/devtools.ts +18 -0
- package/src/extra/diagnostics/checks/fetch.ts +21 -1
- package/src/extra/diagnostics/checks/forms.ts +4 -3
- package/src/extra/diagnostics/checks/index.ts +2 -1
- package/src/extra/diagnostics/checks/inspect.ts +68 -6
- package/src/extra/diagnostics/checks/next.ts +3 -0
- package/src/extra/diagnostics/checks/public.d.ts +133 -12
- package/src/extra/diagnostics/checks/timingAudit.ts +47 -0
- package/src/extra/diagnostics/codes.ts +19 -0
- package/src/extra/fetchDriver.ts +112 -7
- package/src/extra/fetchEventSource.ts +113 -0
- package/src/extra/form.ts +68 -26
- package/src/extra/formHelpers.ts +3 -1
- package/src/extra/lens.ts +3 -2
- package/src/extra/queryCache.ts +4 -3
- package/src/extra/socketDriver.ts +10 -4
- package/src/extra/testing.ts +68 -11
- package/src/index.d.ts +199 -30
- package/src/index.ts +1 -0
- package/src/shared.ts +3 -0
- package/src/ui/dialog.ts +3 -2
- package/src/ui/tooltips.ts +92 -0
- package/src/ui.d.ts +35 -0
- package/src/ui.ts +1 -0
- package/src/vike/onRenderClient.ts +44 -46
- package/src/vike/onRenderHtml.ts +5 -26
- package/src/vike/shell.ts +33 -0
- package/src/vite/graph.ts +255 -0
- package/src/vite/mcp.ts +3 -3
- package/src/vite/plugin.d.ts +19 -0
- package/src/vite/plugin.ts +144 -25
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,162 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Sygnal are listed here. Versions follow [semantic versioning](https://semver.org). Releases before 5.4.0 are described in the [GitHub releases](https://github.com/tpresley/sygnal/releases) and tags.
|
|
4
4
|
|
|
5
|
+
## 7.0.0 — 2026-10-19
|
|
6
|
+
|
|
7
|
+
**Read [Migrating to 7.0](https://sygnal.js.org/guide/migrating-to-7/) before upgrading.** 7.0
|
|
8
|
+
has one reducer timing contract and no option to switch back; apps that aren't ready stay on 6.x.
|
|
9
|
+
|
|
10
|
+
**Measured impact.** Size: the kanban gate is (a) 42,844 B with `nativeGlobalThis: false` (6.6.0:
|
|
11
|
+
42,495 B; budget raised from 42,700 B to 43,000 B for the binding lifetimes) and (b) 38,834 B by
|
|
12
|
+
default. Most of the growth is the binding-lifetime bookkeeping; the single timing contract is
|
|
13
|
+
smaller than the opt-in switch it replaced (−181 B against the 7.0 candidate). The timing audit is
|
|
14
|
+
in the dev diagnostics entry (0 production bytes), and the upload, SSE, form and `tooltips()`
|
|
15
|
+
features add nothing to an app that doesn't use them. The perf count gate is within its limits.
|
|
16
|
+
|
|
17
|
+
**Companion packages.**
|
|
18
|
+
- **`sygnal-check` 0.11.0:** checks reducer timing and binding changes against the Sygnal version
|
|
19
|
+
installed for each source package (7: every output gets the committed state, changed known
|
|
20
|
+
targets remount; 6: the 6.x contracts). New **SYG256** (an output guard that rejects the state
|
|
21
|
+
its own action writes, in a Sygnal 7 project); **SYG454** (an unkeyed dynamic `byId` selection)
|
|
22
|
+
only for an installed Sygnal 6. SYG731 accepts state announced through text, `aria-label`,
|
|
23
|
+
`aria-live` or `role="status"`; SYG609 also reports intent sources with no driver; `progress`
|
|
24
|
+
counts as a reply-action key (SYG102 / SYG112). Explanations for SYG257 and SYG636. Its caret
|
|
25
|
+
range doesn't reach 0.11.0 from `^0.10.0`, so update the dev dependency.
|
|
26
|
+
- **`create-sygnal-app` 2.9.0:** every template depends on `sygnal` ^7.0.0 and `sygnal-check`
|
|
27
|
+
^0.11.0 and has `npm run check` (TypeScript templates: sygnal-check and `tsc --noEmit`).
|
|
28
|
+
Scaffolding into a directory that holds only `.git` and/or `.DS_Store` keeps that metadata, and
|
|
29
|
+
`.` gets a valid package name from the directory.
|
|
30
|
+
- **VS Code extension 0.8.0:** bundles `sygnal-check` 0.11.0 for Sygnal 7 and existing Sygnal 6
|
|
31
|
+
apps; workspace checkers need 0.11.0 or later (earlier ones fall back to the bundled checker).
|
|
32
|
+
- **Claude Code plugin 0.2.0:** the `sygnal-dev` skill describes Sygnal 7; a project's
|
|
33
|
+
`sygnal-check` older than 0.11.0 is refused only when the project has Sygnal 7.
|
|
34
|
+
|
|
35
|
+
### Breaking: STATE runs first, and output sinks see its result
|
|
36
|
+
|
|
37
|
+
In every model entry STATE now runs first, whatever the key order, and every other sink (EFFECT,
|
|
38
|
+
EVENTS, PARENT, ELEMENT, HTTP and other drivers) gets the committed state, calculated fields
|
|
39
|
+
included, as `state` and `props.state`. The new `props.previousState` (fourth argument) is the
|
|
40
|
+
state from before the action; a STATE reducer gets the old state in both. 6.x gave every reducer
|
|
41
|
+
the state from before the action.
|
|
42
|
+
|
|
43
|
+
- An output that computed the update itself now applies it twice: in
|
|
44
|
+
`INC: { STATE: s => ({ ...s, n: s.n + 1 }), PARENT: s => ({ n: s.n + 1 }) }`, PARENT becomes
|
|
45
|
+
`s => ({ n: s.n })`.
|
|
46
|
+
- A value STATE clears or deletes (a submitted draft, a removed record) is read from
|
|
47
|
+
`previousState`.
|
|
48
|
+
- A guard that admits the action (a loading or status flag STATE sets) tests `previousState`.
|
|
49
|
+
Keep the output guard: STATE returning `ABORT` doesn't cancel the other sinks.
|
|
50
|
+
- When STATE returns `ABORT` or the same state, or throws, the other sinks still run, with
|
|
51
|
+
`state === previousState`.
|
|
52
|
+
- When STATE removes the component's own state (`STATE: () => undefined` in a Collection item, or
|
|
53
|
+
a child bound with `state="x"` / `byId()` deleting its record), the other sinks get its last
|
|
54
|
+
state, so `REMOVE: { STATE: () => undefined, EVENTS: event('REMOVED', (s) => s.id) }` works as
|
|
55
|
+
before.
|
|
56
|
+
- Behaviors: the first argument is the slice after STATE, `props.state` the host state after
|
|
57
|
+
STATE, `props.previousState` the host state before the action; the old slice is
|
|
58
|
+
`props.previousState[key]`. Every built-in behavior (form, chat, compose, commandBar, undo,
|
|
59
|
+
pager, selection, sortable, and the `sygnal/ui` dialog, popover, tooltip, tabs, accordion and
|
|
60
|
+
disclosure) is on this contract.
|
|
61
|
+
- Libraries that support 6 and 7 read old values as `props.previousState ?? state`.
|
|
62
|
+
|
|
63
|
+
### New: the timing audit (SYG257)
|
|
64
|
+
|
|
65
|
+
An opt-in dev check for upgrading 6.x code: with `renderComponent(C, { timingAudit: true })`,
|
|
66
|
+
`sygnal({ diagnostics: { timingAudit: true } })` in `vite.config`, `configureTimingAudit(true)`
|
|
67
|
+
from `'sygnal/diagnostics'` or `globalThis.__SYGNAL_TIMING_AUDIT__ = true`, every output sink that
|
|
68
|
+
reads a top-level state field its action's STATE changed reports **SYG257** (info, once per
|
|
69
|
+
component, action, sink and field). Keep `state` where the new value is meant; read
|
|
70
|
+
`previousState` where the old one was. It is off by default because in code written for 7.0
|
|
71
|
+
reading the new value is the intent, and it adds nothing to production builds.
|
|
72
|
+
|
|
73
|
+
sygnal-check's **SYG256** (warning) reports an output guard that contradicts the same action's
|
|
74
|
+
literal STATE write, the loading/admission pitfall above. sygnal-check reads the installed
|
|
75
|
+
Sygnal version per package; **SYG454** (a `byId()` selection without a key) applies only to
|
|
76
|
+
Sygnal 6.
|
|
77
|
+
|
|
78
|
+
### Breaking: a child follows the record its state binding points at
|
|
79
|
+
|
|
80
|
+
When a child's `state` path, or its `byId()` field, id or idKey, changes, Sygnal disposes the old
|
|
81
|
+
child and mounts a new one: `DISPOSE` runs with the last state, pending requests, delayed `next()`
|
|
82
|
+
actions and subscriptions are cancelled, initialization reruns and local state starts from its
|
|
83
|
+
defaults. The child's DOM is replaced, so focus, caret, scroll position and in-progress input
|
|
84
|
+
inside it are lost. The same applies to Collection/VirtualCollection `from` and Switchable
|
|
85
|
+
`state` (all items or pages, hidden ones included, even when ids overlap). Deleting the bound
|
|
86
|
+
record disposes the child too, after the deleting action's outputs; re-adding the same id gets a
|
|
87
|
+
new child, never the old pending work. A new `byId()` call with the same arguments, field edits
|
|
88
|
+
and reordering keep the child. `key={selected.id}` is no longer needed for a selection.
|
|
89
|
+
|
|
90
|
+
**A stable explicit key no longer keeps a child across a target change**: lift state that must
|
|
91
|
+
survive the change into the parent. A child with a custom lens keeps its binding until its key
|
|
92
|
+
changes.
|
|
93
|
+
|
|
94
|
+
### New: uploads, SSE auth, form files and types, `tooltips()`
|
|
95
|
+
|
|
96
|
+
- **Upload and download progress** on `makeFetchDriver` requests: `progress: 'UPLOADING'` (a reply
|
|
97
|
+
action) or `progress: true` (`HTTP.progress(category)`) sends `{ phase, loaded, total, fraction }`
|
|
98
|
+
steps, throttled to one every 50 ms per phase. Such a request goes over XMLHttpRequest, the only
|
|
99
|
+
way to see upload progress in every browser; fetch-only `init` options it can't honour are
|
|
100
|
+
SYG636. Tests: `t.progress('HTTP', { loaded, total }, 'UPLOADING')`.
|
|
101
|
+
- **`multipart: { file, title }`** on a request: the multipart/form-data body as data, the way
|
|
102
|
+
`json` is; a model never builds a `FormData`.
|
|
103
|
+
- **The `form` behavior** takes file inputs (a field's value is its `File`, `multiple` an array,
|
|
104
|
+
validated by the schema), keeps the submit's progress in `state.form.progress`
|
|
105
|
+
(`progress: 'form.PROGRESS'`) and counts start-overs in `state.form.resets` (key a file input
|
|
106
|
+
with it). `request: { url }` (or `(data, state) => request`) sends a valid submit itself, as
|
|
107
|
+
JSON or multipart, with `form.DONE` / `form.ERRORS` wired: the common save needs no model entry.
|
|
108
|
+
`form.RESET` from a click goes back to the start values (it used to take the event as values).
|
|
109
|
+
- **Form types from the schema**: a typed Standard Schema (zod, valibot, arktype) types
|
|
110
|
+
`state.form.values` and `fields.x.value`; `FormOutput<typeof uses.form>` is the submit data.
|
|
111
|
+
- **SSE connections take `headers`** (`{ authorization: 'Bearer ' + state.token }`): such a stream
|
|
112
|
+
is read with fetch (`Last-Event-ID`, `retry`), since EventSource can't send headers.
|
|
113
|
+
- **`tooltips()`** in `sygnal/ui`: one behavior and one state slice for every tooltip of a
|
|
114
|
+
component (glossary terms, icon toolbars), one tip at a time.
|
|
115
|
+
- `Component<State, any>` keeps `state` typed; SYG731 accepts state announced through text,
|
|
116
|
+
`aria-label`, `aria-live` or `role="status"`; sygnal-check's SYG609 also reports intent sources
|
|
117
|
+
with no driver; a test wait that times out on the fake clock names the pending timer; every
|
|
118
|
+
create-sygnal-app template has `npm run check` (TypeScript: sygnal-check and `tsc --noEmit`).
|
|
119
|
+
|
|
120
|
+
### Also included
|
|
121
|
+
|
|
122
|
+
- A child that fails to instantiate is no longer retried on every parent render.
|
|
123
|
+
- State-wait timeout messages report queued simulated inputs; the testing guide separates
|
|
124
|
+
serialized simulated input from synchronous native bursts.
|
|
125
|
+
- TypeScript tests can use `t.query<HTMLInputElement>(selector)` and `t.queryAll<…>(selector)`
|
|
126
|
+
(type assertions, not runtime checks); typed control tokens keep their inference.
|
|
127
|
+
- The combined Rollup build exits normally (compiler watcher lifecycle fix).
|
|
128
|
+
- The release workflow checks the CHANGELOG headings of the new versions before the gates and
|
|
129
|
+
any publish.
|
|
130
|
+
|
|
131
|
+
### Changed
|
|
132
|
+
|
|
133
|
+
- **The app graph's banner line says why it's missing.** When the dev server's graph route is on but the project has no `sygnal-check` 0.10.0 or later, `sygnal/vite` prints `➜ Sygnal graph: needs sygnal-check 0.10.0 or later in this project (npm i -D sygnal-check)` instead of nothing (the URL already answered 404 with the same hint).
|
|
134
|
+
- **`astro dev` prints the graph page's address** under Astro's own banner (Astro never runs Vite's URL printing), and the Astro integration takes the `graph` option (`sygnal({ graph: false })`).
|
|
135
|
+
- **The repository's examples link `sygnal-check`** (`file:../../sygnal-check`, as they link `sygnal`), so `npm run dev` in any of them serves the app graph; `examples/mcp-app` moves off `sygnal-check` ^0.7.0.
|
|
136
|
+
|
|
137
|
+
## 6.6.0 — 2026-10-16
|
|
138
|
+
|
|
139
|
+
The app graph as an interactive page: `sygnal-check --graph=html`, live with `--watch` or at `/__sygnal/graph` in the Vite dev server, in a VS Code panel and in Sygnal DevTools. See [The App Graph](https://sygnal.js.org/guide/app-graph/).
|
|
140
|
+
|
|
141
|
+
**Measured impact.** Size: the kanban gate stays flat, (a) 42,495 B with `nativeGlobalThis: false` (6.5.0: 42,496 B; budget 42,700 B): the runtime `contextConsumes` getter costs 9 B in the core, and nothing else in this release reaches an app bundle (the graph page, the Vite route, the dev stamps and the DevTools bridge are dev-only; a `vite build` contains none of them). The perf count gate is within its limits.
|
|
142
|
+
|
|
143
|
+
**Companion packages.**
|
|
144
|
+
- **`sygnal-check` 0.10.0:** `--graph=html` writes the graph as one self-contained page (no network, runs no app code) and opens it: cards for every component, render / Collection / Switchable / Vike layout edges, EVENTS, context and `PARENT` overlays, a health list, a detail panel with line links into the editor (`--editor`), traces of events, context fields, actions and state keys, search, filters, an EVENTS table, SVG / JSON / Mermaid export, and directory groups folded above 150 components. `--graph=html --watch` serves it on 127.0.0.1 behind a token and updates it on every save (`--poll`, `--port`). `--graph=mermaid` prints a flowchart (`--events=false`). `--out`, `--open` / `--no-open`. `--graph[=<format>] --base <ref>` compares the graph with a git ref without a checkout (`--graph --json --base` prints the diff for CI). The graph gains `key`, `entry`, `viewOnly`, Vike `route`s and layout edges, child `id` / `external` / `widget` / `state`, `childSelects`, `emitterIds` / `selectorIds`, `writes` / `removes` on actions, `stateReads`, and source lines on actions, selectors, children, context entries and EVENTS sites, in `--graph --json`, the MCP `graph` tool and the language server's new `sygnal/graph` request. New rules **SYG170** (a context field no provider above gives) and **SYG171** (`PARENT` that no parent selects). Its caret range doesn't reach 0.10.0 from `^0.9.0`, so update the dev dependency; `sygnal/vite`'s graph route needs 0.10.0 or later.
|
|
145
|
+
- **`create-sygnal-app` 2.8.0:** every template depends on `sygnal` ^6.6.0 and `sygnal-check` ^0.10.0.
|
|
146
|
+
- **VS Code extension 0.7.0:** **Sygnal: Show App Graph**, the page in a panel that updates as you type; bundles `sygnal-check` 0.10.0.
|
|
147
|
+
- **Claude Code plugin 0.1.5:** the `sygnal-dev` skill mentions the graph page and `--graph --json`.
|
|
148
|
+
|
|
149
|
+
### Added
|
|
150
|
+
|
|
151
|
+
- **The app graph in the Vite dev server.** `sygnal/vite` serves the live graph page at `/__sygnal/graph` (local requests only) when `sygnal-check` 0.10.0 or later is installed, and prints its address. In dev it also stamps each component function with its static key (a non-enumerable `__sygnalKey`, reported by `inspect()` as `key`), so the page's **Live data** shows which components are mounted, their instance counts, a flash when an action runs and each instance's state, from the app tabs of the same origin. New option `graph` (default `true`); `graph: false` turns off the route, the stamps and the bridge. `vite build`, `vite preview` and Vitest get none of it.
|
|
152
|
+
- **`installGraphBridge()`** in `sygnal/devtools`: connects the page's apps to the graph page's live data over a same-origin `BroadcastChannel` (`sygnal:graph`). The Vite plugin calls it in dev.
|
|
153
|
+
- **App graph in the DevTools panel.** An **App graph** button draws the running app's `inspect()` graph with the same page: a card per component under each parent (`×N` for several instances), each app as its own group, action flashes and instance state.
|
|
154
|
+
- **More in the runtime `inspect()`** (the `sygnal/diagnostics` dev entry): `key`, `entry`, `viewOnly`, `app`, `shown`, `children[].ids`, `events[type].emitterIds` / `selectorIds`, the time of each diagnostic (`timestamp`), and `contextConsumes`: the context fields the component's latest render read (a read-only getter in the core, 9 B gzip). The `InspectGraph` type gains these and the static graph's new fields, all optional.
|
|
155
|
+
|
|
156
|
+
### Fixed
|
|
157
|
+
|
|
158
|
+
- **A Transition's leave, or a Portal mounted late, under jsdom.** The DOM "poke" that re-emits the app's DOM source after such a change created its event with the global `Event`. jsdom refuses an event from another realm, so a jsdom test whose environment was torn down while a leave transition's timer was pending failed with "parameter 1 is not of type 'Event'" (the 6.5.0 release's CI run did once). It now creates the event from the element's own window. Browsers were not affected.
|
|
159
|
+
- **Nested Vike Layouts and Wrappers (`sygnal/vike`).** Vike lists a cumulative config's values closest to the page first, so a page under `pages/admin/` gets `[adminLayout, rootLayout]`. `sygnal/vike` treated the first as the outermost, so the admin Layout rendered outside the root Layout, on the server and on hydration. Client-side navigation also kept the first page's Layouts and Wrappers, so going from `/` to `/admin` never added the admin Layout (nor did going back remove it), and navigating from a page with no Layout to one with a Layout swapped the Page into the old app. Now the root's Layout is outermost and every Wrapper is outside every Layout, as in `vike-react`. Navigation keeps mounted, with their state, the Layouts and Wrappers that two pages share (from the outside in), adds the new page's others and removes the ones it lacks. A page with one Layout and one Wrapper renders and hydrates as before. The Vike example has an `/admin` page with a nested Layout.
|
|
160
|
+
|
|
5
161
|
## 6.5.0 — 2026-10-14
|
|
6
162
|
|
|
7
163
|
State paths: a child's `state`, a Switchable's `state` and a Collection's `from` reach nested state (`state="settings.rules"`, `from="board.cards"`) without a hand-written lens. Additive, except that a `state` / `from` string with a `.` or `[` now means a path (SYG428 reports a state that still has a key with a dot in its name). The first full release published by the keyless release workflow.
|
package/README.md
CHANGED
|
@@ -9,6 +9,8 @@ A reactive component framework with pure functions, zero side effects, and autom
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
> **Upgrading from 6.x?** Sygnal 7.0 changes reducer timing: output sinks (EFFECT, EVENTS, PARENT, HTTP, ...) now see the state after the action's STATE update. See [Migrating to 7.0](https://sygnal.js.org/guide/migrating-to-7/).
|
|
13
|
+
|
|
12
14
|
## Why Sygnal?
|
|
13
15
|
|
|
14
16
|
- **Pure components** — Views are plain functions. All side effects are handled by drivers, outside your code.
|