AsheeUI 3.0.0
The contract release: core keeps the rules, the renderers keep the pixels, the umbrella becomes the intersection, and the two reference applications prove it.
| Field | Value |
|---|---|
| Version | 3.0.0 |
| Packages | asheeui 3.0.0, @asheeui/core 3.0.0, @asheeui/web 2.8.0, @asheeui/native 2.8.0, @asheeui/puck 2.3.1, @asheeui/cli 1.0.1 |
| Previous release | the 2.7 line (@asheeui/web and @asheeui/native 2.7.0, core 2.5.0) |
| Breaking changes for an existing application | Yes. This is the major where core stops rendering and the umbrella stops being export * over the renderers. |
AsheeUI 3.0 is the release where the contract stopped being an engine. @asheeui/core keeps the
tokens, the rules, the types and the configuration cascade — the part that is true on both platforms.
Every pixel decision moved to the renderer that compiles it. The umbrella stopped re-exporting both
renderers and became the list of names that are actually portable.
The result is a smaller core, two renderers that own their implementations, and one import a shared screen can use without learning which platform it is on.
What changed
Core is the contract, not the engine
- Both class dictionaries left core: the web's constants moved to
@asheeui/web, the platform's to@asheeui/native.@asheeui/corenow declares no dependencies and contains no class string. - Core keeps the tokens, the typography role table, the palette model, the cascade, the shared rules
(
isFieldInvalid,resolveFieldStatusColor,UnderlineRadius,selectTheme, the breakpoint resolver) and the configuration types. - The compatibility matrix moved to
@asheeui/core/dev. It is data for tooling — the parity guard, the umbrella guard, the CLI, this documentation — not something a component renders. pnpm check:core-charteris the ratchet: no class string, no dependency, no renderer import, and every export has a reader. It is a blocking CI step.
The umbrella is the intersection
asheeui publishes 182 names (90 from core, 92 from the branch renderer) plus AsheeConfig. A name
is on it only when both renderers publish it under the same name and contract.
- The list is declared once, as
PORTABLE_APIin@asheeui/core, and both umbrella entries are generated from it. The branches cannot drift. - Renderer-only names stay with their renderer:
Breadcrumb,ResizableScreen,SkipLinkand the keyboard family on the web;RowListandTabBaron a device. - The umbrella owns three subpaths:
asheeui/styles(the web stylesheet),asheeui/tailwind-preset(the native preset) andasheeui/section-kit(the composition vocabulary). - The renderers are optional peers; an application installs the one it builds for.
The native contract is complete
Every component the matrix promises for native is implemented and tested with the platform's own tooling. The native parity guard reads what the package publishes, not what its file names suggest, and fails when the matrix, the exports and the queue disagree. The queue is empty.
The provider names align with the web renderer: AsheeUIProvider is the current name, and
AsheeNativeProvider is an alias that warns once per process.
Puck is one document, two renderers
@asheeui/puck keeps one set of block specs and two renderings. The editor is a web concern; a device
bundle imports the native renderer and never @puckeditor/core. The editor is an optional peer of the
web half alone. See Puck.
Two reference applications
The repository ships a fitness tracker as one shared kit and two applications: TanStack Start on the
web with a top Navbar, Expo on a device with a header and a bottom TabBar, and a Puck studio on
both. It is the layout the monorepo blueprint describes, with seven screens.
Breaking changes
| Change | What to do |
|---|---|
Class dictionaries and cn are no longer published by @asheeui/core |
Import the renderer's own utility, or stay on the portable surface |
| The compatibility matrix moved | Change @asheeui/core to @asheeui/core/dev |
ExternalColorVariant is no longer a root export |
Type a palette as ExternalColorConfig; the variant is its internal shape |
The umbrella is no longer export * |
A name only one renderer has must be imported from that renderer |
asheeui/styles and asheeui/tailwind-preset are the umbrella paths |
The renderer paths still work; the umbrella path is the default |
RowList and TabBar are native-only |
Keep them in the native shell, not in a shared screen |
| The native provider names changed | AsheeUIProvider, AsheeUIProviderProps, AsheeConfigContext, useAsheeConfig; the old names warn and are removed in the next major |
The detailed paths are Migrating the umbrella and Migrating the core layer. The target layout is the monorepo blueprint.
What was deliberately not done
| Not done | Why |
|---|---|
| Per-component subpaths | The umbrella is one entry and three subpaths; a page imports the name, not a door per component |
| A native Puck editor | Composing is a web authoring concern; the device renders the document |
| One Tailwind version for both | The web is Tailwind 4 and NativeWind is Tailwind 3; the umbrella spans both rather than pretending they are one compiler |
| Sharing renderer source | Sharing source would give one platform the other's behaviour, which is what the contract split exists to avoid |
The release set
| Package | Version | What it contains |
|---|---|---|
asheeui |
3.0.0 |
The portable surface, generated from PORTABLE_API |
@asheeui/core |
3.0.0 |
Tokens, rules, types, cascade; no classes, no dependencies |
@asheeui/web |
2.8.0 |
The DOM renderer and its dictionaries |
@asheeui/native |
2.8.0 |
The React Native renderer and its dictionaries |
@asheeui/puck |
2.3.1 |
The shared block specs and the two renderings |
@asheeui/cli |
1.0.1 |
asheeui list and asheeui check against the published matrix |
The packages version independently. The current release keeps the table and the short form; the migration hub records every breaking change.