Plumeria 21.2
Plumeria v21.2 lets a package share Plumeria definitions. An app reads the css.createStatic values, styles and keyframes a package exports as it reads its own modules, and @plumeria/wind, the Tailwind CSS design tokens as a package, is the first one built this way.
1. Definitions from a package
Until now the compiler read definitions only from the app's own files. A package opts in by pointing a plumeria condition at its TypeScript source:
{
"name": "@acme/tokens",
"exports": {
".": {
"plumeria": "./src/index.ts",
"types": "./src/index.ts"
}
}
}import * as css from '@plumeria/core';
export const brand = css.createStatic({
primary: '#0b5fff',
});An app that lists the package in its dependencies reads it like a local module:
import * as css from '@plumeria/core';
import { brand } from '@acme/tokens';
const styles = css.create({
button: {
backgroundColor: brand.primary,
},
});The compiler follows the plumeria condition, including subpath and pattern exports such as @acme/tokens/colors, and packages linked from a pnpm store. dependencies, devDependencies, peerDependencies and optionalDependencies all count. A package without the condition is not read.
An import whose names are all compiled away is now removed from the output, so the bundler never resolves @acme/tokens here. A package that exports only definitions can ship its source alone. One that also exports runtime code keeps a default condition for it, and an import still read at runtime, rendered as a component or re-exported stays in place. See Across packages.
2. @plumeria/wind
@plumeria/wind provides the Tailwind CSS v4.3.3 design tokens as css.createStatic values: the color palettes, spacing, type scale, font weights, radius, shadows, easing, breakpoints and animations.
npm i -D @plumeria/windimport * as css from '@plumeria/core';
import * as t from '@plumeria/wind';
const styles = css.create({
button: {
paddingInline: t.spacing[4],
fontSize: t.text.sm,
color: t.slate[50],
backgroundColor: t.blue[600],
borderRadius: t.radius.md,
},
});It is built the way section 1 describes: its package.json points a plumeria condition at src/index.ts, and there is no build output. Every value is compiled into the styles that read it and the import is removed, so nothing from the package reaches the bundle. It generates no utility classes. The full list is in @plumeria/wind.
3. Namespace imports
21.0 made a namespace read of a definition a compile error. A read by name now compiles as a named import does:
import * as css from '@plumeria/core';
import * as tokens from './tokens';
const styles = css.create({
link: { color: tokens.blue[500] },
});tokens.blue is read as import { blue }, and the namespace import is removed when nothing else uses it. A string key, destructuring, a rest element or passing tokens as a whole still stops the build and asks for a named import. See Imports.
4. Lint
no-combinator checks only the css.createStatic values that start with : or [, the ones that become a selector when used as a key. A value with spaces, such as a shadow or a font stack, is no longer reported. no-unknown-css-properties accepts fit-tolerance, min-size and max-size.
Upgrading
A module imported only for its definitions is no longer loaded through that import. If it also runs code on import, such as importing a global stylesheet, import it for its side effects as well:
import './tokens';Release notes
21.2.3 (Oct 31, 2026)
- Fix: a
css.createStaticorcss.createThemekey read by number, such asblue[500], compiles likeblue['500'], instead of dropping the declaration without an error in a style imported from another file or incss.keyframes, and instead of stopping the build in a template literal, a computed key or the module that defines it - Fix: a key read through a const, such as
blue[k]afterconst k = '500', compiles like the quoted key in a style imported from another file and in the module that defines it - Fix: the lint rules that read a static value, such as
validate-at-rules, check[bp[500]]as they check[bp['500']]
21.2.2 (Oct 31, 2026)
- Fix: a computed key the build cannot inline, such as
[MOBILE]read from a plain module, stops the build and points atcss.createStaticinstead of dropping the rule without an error - Fix: a spread of a function call, such as
...mixin(), stops the build instead of dropping what it returns without an error - Fix: a shorthand holding a runtime value, such as
{ margin }, stops the build like the same property written out instead of dropping the declaration without an error - Fix: a shorthand holding
css.keyframes, such as{ animationName }, compiles like the same property written out - Fix: a method or an accessor in a style, such as
get margin() { ... }, stops the build instead of dropping the declaration without an error - Fix:
migrate --from plumeriajoins aclassStylelist member it cannot name, such as a prop, as a class string, instead of exporting the styles and leaving a list that no longer builds - Update: lead README.md with what decides the winning style
21.2.1 (Oct 30, 2026)
- Update: use a namespace import in README.md
21.2.0 (Oct 30, 2026)
- Feat: a package can share its Plumeria definitions as source: when its
exportspoint aplumeriacondition at its TypeScript files, as in"plumeria": "./src/index.ts", an app that lists it in its dependencies reads the definitions it exports, such ascss.createStaticvalues,css.createstyles andcss.keyframesnames, as it reads a local module, including subpath and pattern exports and packages linked from a pnpm store - Feat:
@plumeria/windprovides the Tailwind CSS v4.3.3 design tokens, such as the color palettes, spacing, type scale, radius, shadows and animations, ascss.createStaticvalues; each value is compiled into the styles that read it, so the package adds nothing to the bundle - Feat: a definition read by name through a namespace import, such as
tokens.blue[500]afterimport * as tokens from './tokens', compiles as it does throughimport { blue }; a string key, destructuring, a rest element or the namespace passed as a whole still stops the build and asks for a named import - Fix: an import whose names are all compiled away, such as a
css.createStaticimport read only insidecss.create, is removed from the output, so the bundler no longer resolves or loads that module; an import still read at runtime, rendered as a component or re-exported is kept - Fix: reading a module's exports before the first project scan, as
resolveExportandresolveExportValuecan, no longer leaves that module out of the scan - Fix:
no-combinatorchecks only thecss.createStaticvalues that start with:or[, the ones that become a selector when used as a key, so a value with spaces, such as a shadow or a font stack, is no longer reported - Update:
no-unknown-css-propertiesacceptsfit-tolerance,min-sizeandmax-size, from the latest MDN and webref data

