Readiness: Implemented
Reference
Packages
Every @uniflowed/* package, what it is for, and whether it is real yet. They
include runnable Flow libraries, host facades, and private declaration surfaces.
The tables below distinguish their implementation and publication status.
Released says whether a release sends the package to npm. On npm is in
every release. In this repository only is a package uf uses itself, or one
whose functions still need the native runtime, and is not meant to be installed
on its own. The column is checked against
tools/release/published-packages.txt, pending-packages.txt and each
package's private flag, so it cannot drift from what a release sends.
Three rules hold across all of them, and uf_lib has tests that enforce each:
no export * unless the package is a peer facade for React, Relay or React
Native; no side effects at import time, so a bundler can drop what you do not
use; and a // @flow pragma on every file.
Private declarations
The following private packages contain declarations whose runtime functions
all call nativeRuntimeRequired and throw. They have no JavaScript imports
or package dependency consumers in this repository. Their names remain in
uf_lib as proposed contracts; that registry is metadata, not a native binding
loader. Do not import these functions into an application.
| Packages | Available implementation |
|---|---|
@uniflowed/jsx-runtime, @uniflowed/react-compiler | React's JSX runtime, and the official Rust compiler through uf build / uf dev |
@uniflowed/cli, @uniflowed/lint, @uniflowed/lib | The uf binary, its linter, and uf inspect |
@uniflowed/pm, @uniflowed/rm, @uniflowed/prepare | The corresponding uf commands |
@uniflowed/runtime, @uniflowed/loader | Host integration and router data loading |
@uniflowed/markdown | Markdown and MDX through uf build |
@uniflowed/motion | Motion components in @uniflowed/ui |
@uniflowed/pwa | The declared package has no runtime implementation |
Other private packages need a different decision: browser and vrt have
working browser and visual testing implementations; sql implements the
runtime used by generated queries; std has runnable subpaths beside its
unimplemented root; hmr has a working client beside an unavailable native
channel. Their private flag alone is not a reason to delete them.
The unused ORM declaration surface has been removed.
Core
| Package | What it is | Released |
|---|---|---|
@uniflowed/core | The pieces every other package builds on | On npm |
@uniflowed/react | React, re-exported by name, with Flow's own types | On npm |
@uniflowed/jsx-runtime | Declaration only; use React’s JSX runtime | In this repository only |
@uniflowed/react-compiler | Declaration only; uf build and uf dev run the official Rust compiler | In this repository only |
@uniflowed/runtime | Declaration only; host capabilities are implemented by the toolchain | In this repository only |
@uniflowed/std | The standard library: the parts of Go's that JavaScript does not have | On npm |
Application
| Package | What it is | Released |
|---|---|---|
@uniflowed/router | The file-system router: matching, layouts, loaders, Link | On npm |
@uniflowed/server | The server adapter | On npm |
@uniflowed/config | defineConfig, and the config's Flow types | On npm |
@uniflowed/vite | The Vite plugin, the driver, and the host Flow loaders | On npm |
@uniflowed/host | Running Flow on Node.js, Deno or Bun with no bundler: node --import @uniflowed/host/register app.js | On npm |
@uniflowed/loader | Module loading on each host | In this repository only |
@uniflowed/markdown | Markdown and MDX | In this repository only |
@uniflowed/web | Web platform bindings, and web vitals | On npm |
A React app that keeps its own Vite config and only borrows uf's Flow
transform should import uniflowedPackages from @uniflowed/host/transform
and pass it to optimizeDeps.exclude. @uniflowed/* packages ship Flow
source, so Vite's optimizer must leave them to the same transform hook that
handles application files.
Data
| Package | What it is | Released |
|---|---|---|
@uniflowed/fetch | Typed HTTP — Data in the browser | On npm |
@uniflowed/query | Caching, revalidation, request de-duplication — Data in the browser | On npm |
@uniflowed/effect | Typed effects: failures in the type, not in a catch | On npm |
@uniflowed/state | Atomic state — the guide | On npm |
@uniflowed/form | Forms: uncontrolled inputs, typed values, narrow subscriptions — the guide | On npm |
@uniflowed/immer | Immutable updates written as mutations of a draft: produce, produceWithPatches and applyPatches, with results frozen unless setAutoFreeze(false) | On npm |
@uniflowed/cell | Fine-grained reactivity: state and derived — the layer below | On npm |
@uniflowed/validator | Schemas that parse rather than assert — Validating input | On npm |
@uniflowed/sql | The runtime sqlc's Flow target generates code against: exact codecs and driver adapters | On npm |
@uniflowed/i18n | MessageFormat 2, with a message's arguments in the type | On npm |
@uniflowed/graphql, @uniflowed/relay | GraphQL | On npm |
@uniflowed/temporal | Temporal, on every host. The implementation is @uniflowed/core/temporal, which is what installs today; this name adds the calendar surface that needs the binary | On npm |
Interface
| Package | What it is | Released |
|---|---|---|
@uniflowed/ui | Components you own, built on the render types | On npm |
@uniflowed/hooks | The hook library — the browser half has a server answer for every one | On npm |
@uniflowed/motion | Animation | In this repository only |
@uniflowed/stylex | Static styles | On npm |
@uniflowed/react-native | React Native, re-exported as the app's peer runtime, plus @uniflowed/react-native/metro for Metro config | On npm |
@uniflowed/tui | Terminal interfaces — see the guide | On npm |
Testing
| Package | What it is | Released |
|---|---|---|
@uniflowed/test | describe, it, expect, the hooks, and the worker uf test spawns | On npm |
@uniflowed/react-testing | React Testing Library's surface, over a happy-dom window it installs on the first render | On npm |
@uniflowed/react-native-testing | React Native test-tree queries. Rendering still waits for the native host config | On npm |
@uniflowed/mock | Request mocking at the level MSW works at | On npm |
@uniflowed/story | Stories | On npm |
@uniflowed/vrt | Visual regression | On npm |
Tooling
| Package | What it is | Released |
|---|---|---|
@uniflowed/cli | The CLI's JavaScript half | In this repository only |
@uniflowed/lint | Lint rule types | In this repository only |
@uniflowed/lib | The registry every package is declared in | In this repository only |
@uniflowed/pm, @uniflowed/rm | Package and runtime management | In this repository only |
@uniflowed/prepare, @uniflowed/pwa | Build preparation, progressive web apps | In this repository only |
@uniflowed/hmr | Declarations for the hot-update client the dev server uses | In this repository only |
@uniflowed/brand | The design tokens this site is built from | On npm |
What @uniflowed/ui ships today
The registry in crates/uf_lib/src/ui.rs names every component the package is
going to have. These are the ones that exist. Each implements the WAI-ARIA
authoring practices pattern it is named after — the roles, the aria-* wiring,
the focus management and the whole keyboard map — and ships no styles at all.
| Component | Pattern | The part that is easy to leave out |
|---|---|---|
Field | — | The label, description, error and aria-invalid wiring, and never an aria-describedby pointing at an element that is not there |
Switch, Checkbox, Toggle | Switch, Checkbox, Button (aria-pressed) | Three components, because a reader hears "on", "checked" and "pressed" — a setting, an answer, an action that stays applied — and the third state and the Enter key differ between them |
RadioGroup | Radio Group | Arrows that check as they move, and a tab stop on the first item while nothing is chosen, without which an unanswered group cannot be reached by Tab at all |
ToggleGroup | Button, Radio Group | One tab stop for a row of toggle buttons. type="single" is a radio group drawn as segments, and is rendered by RadioGroup rather than written twice |
Tabs | Tabs | One tab stop for the whole list, and the choice between automatic and manual activation |
Collapsible | Disclosure | aria-expanded, and an aria-controls that names the content only while there is content to name |
Accordion | Accordion | The heading level is the caller's, each panel is a region named after its header, and the closed ones stay findable by the browser's find-in-page |
NavigationMenu | Disclosure Navigation Menu | A <nav> of links behind aria-expanded buttons — not role="menu", which is for application commands and tells a reader the wrong thing about what they are looking at |
Dialog | Dialog (Modal) | A focus trap that cannot be escaped, focus given back, the page held still and made inert |
Menu | Menu | Arrow keys, Home/End, typeahead, submenus, and one Escape closing one level |
Combobox | Combobox | aria-activedescendant over a list the caller filters, and the count a reader is told |
The arrow keys follow the reader, not the compass. In a page that reads
right to left the first item of a row is the rightmost one, so ArrowLeft moves
to the next tab and a submenu opens onto the left. Every set here asks the DOM
which way the page reads at the moment a key is pressed, so putting dir="rtl"
where you would have put it anyway is the whole configuration; a dir="ltr"
island inside an RTL page keeps its own keys. Home and End are not mirrored:
they name the first and last item in reading order.
Which arrow keys a set claims follows its orientation, and the pair it does
not claim is left to the page — ArrowDown in a horizontal set scrolls, as it
does everywhere else. aria-orientation says which pair is live, so a reader is
told rather than left to guess. This is a deliberate narrowing of the WAI-ARIA
practices for RadioGroup, which list both pairs; the reasoning is in
npm/ui/radio-group.js.
A closed section is hidden, not removed. Collapsible and Accordion leave
their panels in the document and mark them hidden="until-found", so the
browser's find-in-page can still reach the text inside a collapsed section,
reveal it, and scroll to the match. Closed tab panels and closed navigation
groups are removed instead, and both modules say why. React cannot express
hidden="until-found" through the hidden prop — it is on React's list of
boolean attributes, so the string is flattened to hidden="" — so the
components upgrade the attribute after React commits it.
Publishing status
Some of these are on npm and most are not. The published set —
tools/release/published-packages.txt in the repository — is the closure a
real uf project needs plus the test runner, and every name in it goes out
together on each uf@* tag, so they are always at one version. The rest
resolve only through the repository's npm workspace, which is how this site — a
real uf project in docs/ — imports them.
Every release so far is a prerelease, so name the prerelease tag when you
install one by hand: npm install @uniflowed/ui@alpha. That gives you the
newest release whatever the latest tag happens to point at.
uf new needs no tag at all. The manifest it writes pins the exact version
of the uf that wrote it, so a new project's packages and the binary that
scaffolded them are one release.
Edit this pagedocs/app/reference/packages/$page.mdx