Migrating the core layer
The shrink: which names left `@asheeui/core` for a renderer, which moved to `@asheeui/core/dev`, and the ten that were deleted.
@asheeui/core used to be the framework's engine: class dictionaries, the class merge, per-component
fallbacks, the compatibility matrix and the contracts all lived there, and both renderers reached
in. That made core depend on pixels it could not compile, and it made a class string a shared
contract.
Core is the contract now. It holds the tokens, the rules, the types and the configuration
pipeline; the renderers own their class strings and the values only they compile. This is the
consumer-facing migration for that move. CORE-MIGRATION-REPORT.md is the record; this page is what
changes in your imports.
The rule
A class string is a decision about pixels, and the two platforms' pixels are not the same one. So:
- the renderer that compiles a class string publishes it;
- core publishes the tokens, the rules and the types both platforms name;
- the 21 strings both renderers compile are the documented exception: each renderer states them in
its own
portable.ts, andpackages/core/src/shared/style-parity.test.tsfails when a pair stops matching.
A contributor's one-line test for the next component: would both platforms render this exact string? If no, it belongs to a renderer. If yes, it belongs to core only if a script or both renderers read it.
Where the names went
| Name (example) | Before | Now |
|---|---|---|
BUTTON_SIZE_CLASS, ALERT_ICON_CLASS, every web *_CLASS |
@asheeui/core |
@asheeui/web — packages/web/src/styles/<component>.ts |
NATIVE_BUTTON_SIZE_CLASS, every native *_CLASS |
@asheeui/core |
@asheeui/native — packages/native/src/styles/<component>.ts |
SPACE_PADDING_Y_CLASS and the other paired strings |
@asheeui/core |
each renderer's portable.ts, asserted equal |
cn |
@asheeui/core |
@asheeui/web (Tailwind merge) and @asheeui/native (the platform's merge) |
FALLBACK_BUTTON_CONFIG, defaultButtonConfig, every per-component fallback/default |
@asheeui/core |
the renderer that states the values; native keeps the shared names with the platform's values |
COMPONENT_SUPPORT, findComponentSupport, PlatformSupport, PLATFORM_SUPPORT_LABEL |
@asheeui/core |
@asheeui/core/dev |
FieldConfig, Size, Radius, Space, Variant, Color, ThemeName, ExternalConfig, the typography role table, the cascade, selectTheme |
@asheeui/core |
unchanged |
The class constant keeps its name on the side it moved to. A web component imports
BUTTON_SIZE_CLASS from @asheeui/web; a native one imports NATIVE_BUTTON_SIZE_CLASS from
@asheeui/native. Neither package imports the other's.
The ten deletions
These had no reader in the framework, its tests, the docs or any package. They are gone, not aliased:
| Name | Why |
|---|---|
TextContract, ButtonContract, CardContract, StackContract, BadgeContract |
described props the components already declare; a second statement can disagree with the shipped component |
_ColorConfigGuards |
a type-level helper left behind |
FontSize, FontWeight, Elevation |
aliases; the *_STEP maps and ELEVATION_LEVEL are the values |
NATIVE_STEPPER_LABEL_CLASS |
a native class constant with no native reader |
contracts.ts itself was retired in the same work. To be precise: the five *Contract types above
were deleted when C4 found no reader, and B19 then retired the module. Substitution and
LinkSubstitution — the two types the renderers still read — live in
packages/core/src/shared/substitution.ts and are exported from @asheeui/core (and asheeui),
while ThemedContract and InputContract were deleted with the module. The module's prose now
documents PORTABLE_API.
The matrix moved to a subpath
// before
import { COMPONENT_SUPPORT } from "@asheeui/core";
// now — data only tooling reads
import { COMPONENT_SUPPORT } from "@asheeui/core/dev";
The root entry no longer reaches the matrix, which is what stops an application bundle carrying the
inventory. The docs generator, the parity guard and the CLI read @asheeui/core/dev.
What did not move
- The token scales:
SPACING_STEP,RADIUS_STEP,FONT_SIZE_STEP,FONT_WEIGHT_STEP,COLOR_ROLE,VARIANT,SIZE,MIN_TOUCH_TARGET,ELEVATION_LEVEL. - The vocabulary:
DeepPartial,ComponentsConfig,ConfigIssue,validateConfig,PaletteRole,AnnouncementRole,MessageVariant,ColumnSortDirection,RowCountLabelValues. - The rules both platforms answer the same way:
isFieldInvalid,resolveFieldStatusColor,UnderlineRadius,selectTheme, the cascade resolvers (mergeObject,resolveCascade,resolveClassKey,resolveConfigCascade,resolveRadiusKey,resolveGridColumns). - The shared types and the component configuration sections.
@asheeui/core still declares no dependencies and publishes no class string.
pnpm check:core-charter is the guard: no class string, no dependency, no renderer import, and no
export without a reader.
Finding a moved name
node scripts/audit/core-usage.mjs # the per-file usage class of every core export
node scripts/audit/core-usage.mjs --json # per-export rows, for a codemod
Then import it from the renderer the row names. A name that does not appear in either renderer's entry was one of the ten deletions, or an internal that was never public.
Checking the migration
pnpm build
pnpm check:core-charter # 4/4, no class string and no unread export
pnpm check:umbrella # the portable surface still sees the names it needs
pnpm verify:distribution # the published core has no dependencies and resolves
The shrink is a major release of @asheeui/core. The changelog groups the moves; this guide is
the index.