### Install @plumeria/headlessui with pnpm
Source: https://plumeria.dev/docs/api-reference/components/headlessui.md
Install the package using pnpm. Requires configuration of @plumeria/core and your bundler as described in the Installation section.
```sh
pnpm i @plumeria/headlessui
```
--------------------------------
### Install @plumeria/headlessui with yarn
Source: https://plumeria.dev/docs/api-reference/components/headlessui.md
Install the package using yarn. Requires configuration of @plumeria/core and your bundler as described in the Installation section.
```sh
yarn add @plumeria/headlessui
```
--------------------------------
### Install @plumeria/headlessui with npm
Source: https://plumeria.dev/docs/api-reference/components/headlessui.md
Install the package using npm. Requires configuration of @plumeria/core and your bundler as described in the Installation section.
```sh
npm i @plumeria/headlessui
```
--------------------------------
### Minimum context
Source: https://plumeria.dev/docs/ai-agent-resources.md
Use this minimal context to provide an agent with the essential Plumeria documentation links when a shorter prompt is sufficient. It includes the installation guide, the AI rules, and the core documentation.
```text
https://plumeria.dev/docs/getting-started/installation.md
https://plumeria.dev/docs/ai.md
https://plumeria.dev/docs.md
```
--------------------------------
### Install Plumeria with yarn
Source: https://plumeria.dev/docs/getting-started
Install @plumeria/core as a dev dependency using yarn.
```bash
yarn add -D @plumeria/core
```
--------------------------------
### Install Plumeria with pnpm
Source: https://plumeria.dev/docs/getting-started
Install @plumeria/core as a dev dependency using pnpm.
```bash
pnpm add -D @plumeria/core
```
--------------------------------
### Install Plumeria with npm
Source: https://plumeria.dev/docs/getting-started
Install @plumeria/core as a dev dependency using npm.
```bash
npm install -D @plumeria/core
```
--------------------------------
### Configure @plumeria/unplugin
Source: https://plumeria.dev/docs/api-reference/plugins/unplugin.md
Basic configuration example for the Plumeria plugin within a bundler setup.
```ts
import plumeria from '@plumeria/unplugin';
export default {
plugins: [
plumeria.vite({
include: ['**/*.{ts,tsx}'],
exclude: ['**/node_modules/**'],
devEmitToDisk: false,
styleProp: 'sx',
}),
],
};
```
--------------------------------
### Install @plumeria/inspector with yarn
Source: https://plumeria.dev/docs/api-reference/components/inspector.md
Install the package using the yarn package manager.
```sh
yarn add @plumeria/inspector
```
--------------------------------
### StaticStyles usage examples
Source: https://plumeria.dev/docs/api-reference/types/StaticStyles.md
Usage examples for the Chip component. Passing a static style is accepted, while passing a dynamic style results in a type error.
```tsx
// ok
// Type error
```
--------------------------------
### Install @plumeria/inspector with pnpm
Source: https://plumeria.dev/docs/api-reference/components/inspector.md
Install the package using the pnpm package manager.
```sh
pnpm i @plumeria/inspector
```
--------------------------------
### Configure withPlumeria options
Source: https://plumeria.dev/docs/api-reference/plugins/next-plugin.md
Example of passing options to withPlumeria, including include, exclude, and styleProp.
```ts
export default withPlumeria(nextConfig, {
include: ['./src/**/*.{ts,tsx}'],
exclude: ['**/node_modules/**', '**/.next/**'],
styleProp: 'sx',
});
```
--------------------------------
### Install @plumeria/next-plugin with npm, yarn, or pnpm
Source: https://plumeria.dev/docs/getting-started/installation.md
Install the Next.js plugin as a dev dependency using your preferred package manager.
```sh
npm i -D @plumeria/next-plugin
```
```sh
yarn add -D @plumeria/next-plugin
```
```sh
pnpm add -D @plumeria/next-plugin
```
--------------------------------
### Install oxlint and rimraf for plumerialint
Source: https://plumeria.dev/docs/getting-started/installation.md
Install `oxlint` and `rimraf` as dev dependencies. `oxlint` is required to run the `plumerialint` command, and `rimraf` is recommended for cleaning the cache in Next.js projects.
```sh
pnpm i -D oxlint rimraf
```
--------------------------------
### Install @plumeria/inspector with npm
Source: https://plumeria.dev/docs/api-reference/components/inspector.md
Install the package using the npm package manager.
```sh
npm i @plumeria/inspector
```
--------------------------------
### Install Plumeria ESLint plugin with npm
Source: https://plumeria.dev/docs/getting-started/editor-integration.md
Install the required ESLint plugin and oxlint using npm.
```sh
npm i --save-dev @plumeria/eslint-plugin oxlint
```
--------------------------------
### Install @plumeria/unplugin with yarn
Source: https://plumeria.dev/docs/api-reference/plugins/unplugin.md
Install the plugin using the yarn package manager.
```sh
yarn add -D @plumeria/unplugin
```
--------------------------------
### Install @plumeria/unplugin with npm
Source: https://plumeria.dev/docs/api-reference/plugins/unplugin.md
Install the plugin using the npm package manager.
```sh
npm i -D @plumeria/unplugin
```
--------------------------------
### Install @plumeria/eslint-plugin with npm, yarn, or pnpm
Source: https://plumeria.dev/docs/api-reference/plugins/eslint-plugin.md
Install the @plumeria/eslint-plugin package using npm, yarn, or pnpm. Choose the command that matches your package manager.
```sh
npm i --save-dev @plumeria/eslint-plugin
```
```sh
yarn add -D @plumeria/eslint-plugin
```
```sh
pnpm i --save-dev @plumeria/eslint-plugin
```
--------------------------------
### User integration example (app.tsx)
Source: https://plumeria.dev/docs/integration/component-library.md
Shows the entire integration from a user's perspective: import the component and use it. The component brings its own stylesheet, so no bundler configuration or `@plumeria/*` dependency is needed.
```tsx
import { Card } from 'your-lib';
export const App = () => ;
```
--------------------------------
### css.use() usage example
Source: https://plumeria.dev/docs/api-reference/javascript/use.md
Shows how to use css.use() to get a class name string for external components. Both classStyle and css.use() are compiled at build time with zero runtime overhead.
```ts
import * as css from '@plumeria/core';
const styles = css.create({
text: { fontSize: '16px' }
});
// Get the class name as a string
const className = css.use(styles.text);
// Apply to an external component
```
--------------------------------
### Install @plumeria/unplugin with npm, yarn, or pnpm
Source: https://plumeria.dev/docs/integration/rolldown.md
Install the @plumeria/unplugin package using npm, yarn, or pnpm. These are alternative package manager commands for the same installation step.
```sh
npm i -D @plumeria/unplugin
```
```sh
yarn add -D @plumeria/unplugin
```
```sh
pnpm i -D @plumeria/unplugin
```
--------------------------------
### Define physical and logical padding properties
Source: https://plumeria.dev/docs/reference/specificity.md
Example showing how paddingTop and paddingBlockStart are treated as the same property in horizontal writing modes.
```js
const styles = css.create({
physical: { paddingTop: 4 },
logical: { paddingBlockStart: 10 },
});
```
--------------------------------
### Install @plumeria/unplugin with pnpm
Source: https://plumeria.dev/docs/api-reference/plugins/unplugin.md
Install the plugin using the pnpm package manager.
```sh
pnpm i -D @plumeria/unplugin
```
--------------------------------
### Define static media query breakpoints with createStatic
Source: https://plumeria.dev/docs/api-reference/javascript/createStatic.md
Example from the '#example' section defining breakpoints for standard media queries using createStatic. These static values can be used inside create or createTheme as conditions.
```ts
import * as css from '@plumeria/core';
export const breakpoints = css.createStatic({
xs: '@media (max-width: 480px)',
sm: '@media (max-width: 640px)',
md: '@media (max-width: 768px)',
lg: '@media (max-width: 1024px)',
xl: '@media (max-width: 1280px)',
});
```
--------------------------------
### Install Plumeria ESLint plugin with yarn
Source: https://plumeria.dev/docs/getting-started/editor-integration.md
Install the required ESLint plugin and oxlint using yarn.
```sh
yarn add -D @plumeria/eslint-plugin oxlint
```
--------------------------------
### Define and use keyframes
Source: https://plumeria.dev/docs/api-reference/javascript/keyframes.md
Example showing how to define an animation using css.keyframes and apply it within a css.create style object.
```ts
import * as css from '@plumeria/core'
const fadeIn = css.keyframes({
from: {
opacity: 0,
},
to: {
opacity: 1,
},
});
const styles = css.create({
box: {
animationName: fadeIn,
animationDuration: '1s',
animationTimingFunction: 'ease-in-out',
},
});
```
```css
@keyframes kf-x34h9adh {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.xhc714s1:not(#\#) { animation-name: kf-x34h9adh; }
.xdm4omap:not(#\#) { animation-duration: 1s; }
.xvct32ng:not(#\#) { animation-timing-function: ease-in-out; }
```
--------------------------------
### Install @plumeria/unplugin with npm, yarn, or pnpm
Source: https://plumeria.dev/docs/getting-started/installation.md
Install the Vite plugin as a dev dependency using your preferred package manager.
```sh
npm i -D @plumeria/unplugin
```
```sh
yarn add -D @plumeria/unplugin
```
```sh
pnpm add -D @plumeria/unplugin
```
--------------------------------
### Macro usage example
Source: https://plumeria.dev/docs/getting-started/editor-integration.md
The expected expansion behavior for the classStyle snippet in JSX.
```jsx
-> Enter ->
```
--------------------------------
### Install @plumeria/codemod with npm, yarn, or pnpm
Source: https://plumeria.dev/docs/api-reference/codemod.md
Install the codemod as a dev dependency using npm, yarn, or pnpm. The package depends on ESLint and its TypeScript parser, and on nothing from Plumeria.
```sh
npm i --save-dev @plumeria/codemod
```
```sh
yarn add -D @plumeria/codemod
```
```sh
pnpm i --save-dev @plumeria/codemod
```
--------------------------------
### Example compiled component output
Source: https://plumeria.dev/docs/testing.md
The resulting HTML after the Plumeria plugin compiles a component, showing generated class names.
```html
Vite + React
```
--------------------------------
### Install @plumeria/core with npm, yarn, or pnpm
Source: https://plumeria.dev/docs/getting-started/installation.md
Install the core package as a dev dependency using your preferred package manager. The core package contains only type definitions; the bundle and runtime are not included.
```sh
npm i -D @plumeria/core
```
```sh
yarn add -D @plumeria/core
```
```sh
pnpm i -D @plumeria/core
```
--------------------------------
### Define styles with pseudo-classes
Source: https://plumeria.dev/docs/reference/specificity.md
Example of defining separate styles for :hover and :focus states using css.create.
```js
const styles = css.create({
hovered: { ':hover': { color: 'red' } },
focused: { ':focus': { color: 'blue' } },
});
```
--------------------------------
### TypeScript example using marker and extended
Source: https://plumeria.dev/docs/api-reference/javascript/marker.md
Complete TypeScript example showing how to use `css.marker` and `css.extended` to style a child element based on parent hover states. It defines keyframes, creates styles with markers on 'grand' and 'parent', and applies extended styles to the child.
```tsx
import * as css from '@plumeria/core';
const animation = css.keyframes({
'0%': {
scale: 1.2,
},
'50%': {
scale: 1.3,
},
'100%': {
scale: 1.2,
},
});
const styles = css.create({
grand: {
display: 'flex',
flexDirection: 'column',
gap: 15,
alignItems: 'center',
justifyContent: 'center',
width: '100%',
minHeight: 250,
padding: 20,
border: '2px dashed #c4c4c466',
borderRadius: 12,
transition: 'all 0.3s',
...css.marker('grand', ':hover'), // [!code highlight]
},
parent: {
display: 'flex',
flexDirection: 'column',
gap: 10,
alignItems: 'center',
justifyContent: 'center',
width: '80%',
minHeight: 120,
padding: 10,
backgroundColor: '#f5f5f7',
border: '2px solid #c4c4c444',
borderRadius: 8,
transition: 'all 0.3s',
...css.marker('parent', ':hover'), // [!code highlight]
},
child: {
padding: '8px 16px',
fontWeight: 'bold',
color: '#86868b',
background: '#e8e8ed',
borderRadius: 6,
transition: 'all 0.3s',
[css.extended('grand', ':hover')]: { // [!code highlight]
color: '#0066cc',
background: '#e1f0ff',
},
[css.extended('parent', ':hover')]: { // [!code highlight]
color: '#ffffff',
background: '#ff9500',
scale: 1.2,
':hover': {
background: 'skyblue',
animationName: animation,
animationDuration: '1.2s',
animationTimingFunction: 'ease-in-out',
animationIterationCount: 'infinite',
},
},
},
discription: {
fontSize: '14px',
color: '#86868b',
},
});
const MarkerExtended = () => {
return (
Grand Container (Hover me)
Parent Container (Hover me too)
Child Element
);
};
```
--------------------------------
### Use static breakpoints in create for responsive styles
Source: https://plumeria.dev/docs/api-reference/javascript/createStatic.md
Usage example showing how to use static values defined by createStatic (like breakpoints.sm and breakpoints.lg) as keys in the create function to apply conditional styles.
```ts
import * as css from "@plumeria/core";
import { breakpoints } from "lib/mediaQuery";
export const styles = css.create({
container: {
[breakpoints.sm]: {
padding: 16,
},
[breakpoints.lg]: {
padding: 32,
},
},
});
```
--------------------------------
### Spinner.module.css with keyframes
Source: https://plumeria.dev/docs/api-reference/codemod.md
Example stylesheet with a `@keyframes` rule and an `animation` shorthand. The migration converts the keyframes into a `css.keyframes` binding and splits the shorthand into longhands.
```css
/* Spinner.module.css */
@keyframes spin { from { rotate: 0deg } to { rotate: 360deg } }
.icon { animation: spin 1s linear infinite }
```
--------------------------------
### Card.module.css before migration
Source: https://plumeria.dev/docs/api-reference/codemod.md
Example `Card.module.css` stylesheet that the migration converts. It shows a base class, a `composes` rule, a hover state, and a descendant selector.
```css
.base { font-size: 12px }
.card { composes: base; padding: 16px }
.card:hover { background: teal }
.card .card-title { color: red }
```
--------------------------------
### Generated CSS from marker and extended example
Source: https://plumeria.dev/docs/api-reference/javascript/marker.md
The CSS output generated from the TypeScript example. It shows how `marker` sets CSS variables on hover and `extended` uses `@container style()` queries to apply styles to child elements.
```css
.xtkxh191:hover {
--xl0a2l54-grand-hover: 1;
}
.xhcsnlrf:hover {
--xmlppxj5-parent-hover: 1;
}
@container style(--xl0a2l54-grand-hover: 1) {
.x84muc4x:not(#\#) {
color: #06c;
}
.x2x6k4j2:not(#\#):not(#\#) {
background-color: #e1f0ff;
}
}
@container style(--xmlppxj5-parent-hover: 1) {
.xr8ck8y9:not(#\#) {
color: #fff;
}
.xb1yp2w2:not(#\#):not(#\#) {
background-color: #ff9500;
}
.xewf73ay:not(#\#) {
scale: 1.3;
}
.x8odz1r5:not(#\#):not(#\#) {
animation-name: kf-xmortmuw;
}
.x0guwijo:not(#\#):not(#\#) {
animation-duration: 1.2s;
}
.xek6euru:not(#\#):not(#\#) {
animation-timing-function: ease-in-out;
}
.xwdc6dqv:not(#\#):not(#\#) {
animation-iteration-count: infinite;
}
.xd9yj17o:not(#\#):hover {
color: #0ff;
}
}
```
--------------------------------
### Configure property rejection options
Source: https://plumeria.dev/docs/api-reference/plugins/unplugin.md
Examples of using withoutPhysicalProperties to enforce property naming conventions.
```ts
plumeria.vite({ withoutPhysicalProperties: true });
```
```ts
plumeria.vite({ withoutPhysicalProperties: { sizes: true } });
```
--------------------------------
### Trigger animations on hover
Source: https://plumeria.dev/docs/api-reference/javascript/keyframes.md
Example demonstrating how to apply keyframes within pseudo-selectors like :hover.
```ts
const styles = css.create({
card: {
transition: 'transform 0.3s ease',
':hover': {
animationName: fadeIn,
animationDuration: '0.5s',
},
},
});
```
--------------------------------
### Rename property signature
Source: https://plumeria.dev/docs/api-reference/codemod.md
Example of the transformation applied to property signatures annotated with Style.
```diff
interface CardProps {
- classStyle?: Style;
+ sx?: Style;
}
```
--------------------------------
### classStyle usage example
Source: https://plumeria.dev/docs/api-reference/javascript/use.md
Shows how to apply styles with the classStyle prop. Supports arrays for conditional styles; false values are excluded automatically.
```tsx
import * as css from '@plumeria/core';
const styles = css.create({
base: { color: 'red' },
active: { fontWeight: 'bold' }
});
function Component({ active }) {
return (
Hello
);
}
```
--------------------------------
### Use Style in Component
Source: https://plumeria.dev/docs/api-reference/types/Style.md
Example of using styles created with css.create in a component's classStyle prop.
```tsx
import * as css from '@plumeria/core';
const styles = css.create({
base: {
color: 'red',
},
active: {
fontWeight: 'bold',
},
});
export function Component({ active }: { active: boolean }) {
return ;
}
```
--------------------------------
### Configure esbuild with @plumeria/unplugin
Source: https://plumeria.dev/docs/integration/esbuild.md
Example esbuild build script that uses the plumeria.esbuild plugin to compile Plumeria styles into the CSS asset. The plugin is configured with an include regex for JSX/TSX files.
```ts
import esbuild from 'esbuild';
import plumeria from '@plumeria/unplugin';
esbuild
.build({
entryPoints: ['src/index.tsx'],
bundle: true,
outfile: 'dist/bundle.js',
plugins: [
plumeria.esbuild({
include: /\.[jt]sx?$/,
}),
],
loader: {
'.tsx': 'tsx',
'.ts': 'ts',
},
format: 'esm',
minify: false,
})
.catch(() => process.exit(1));
```
--------------------------------
### Run rename-prop with npx
Source: https://plumeria.dev/docs/api-reference/codemod.md
Runs the codemod without installing it locally. Use this to apply the rename-prop transform directly via npx.
```sh
npx @plumeria/codemod rename-prop classStyle sx
```
--------------------------------
### Class list order in JSX
Source: https://plumeria.dev/docs/api-reference/codemod.md
Demonstrates that class lists in JSX carry no inherent order, as both examples render the same page.
```tsx
```
--------------------------------
### Generated CSS for markers and extended styles
Source: https://plumeria.dev/docs/api-reference/codemod.md
Example of how css.marker and css.extended are compiled into CSS custom properties and container queries.
```css
.grand:hover {
--xl0a2l54-grand-hover: 1;
}
@container style(--xl0a2l54-grand-hover: 1) {
.child {
color: #0066cc;
}
}
```
--------------------------------
### Reported conversion issues
Source: https://plumeria.dev/docs/api-reference/codemod.md
Example of the diagnostic output generated when Plumeria constructs cannot be statically resolved or exported.
```text
src/Card.tsx
8:5 dynamic-value
The value of `color` cannot be represented statically.
12:3 spread-create
Top-level spreads cannot name a CSS Module class.
19:16 style-type-reference
`css.StaticStyles` has no CSS Modules equivalent, and the import that
declares it does not survive the export of Card.tsx.
```
--------------------------------
### Using CSSProperties with satisfies in createStatic
Source: https://plumeria.dev/docs/api-reference/types/CSSProperties.md
Example showing how to use CSSProperties with satisfies to create a static style object and then use it in a create call. The spread of flexBox is compiled by createStatic.
```typescript
import * as css from '@plumeria/core';
const flexBox = css.createStatic({
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
} satisfies css.CSSProperties);
export const styles = css.create({
container: {
...flexBox,
backgroundColor: 'red',
},
});
```
--------------------------------
### Define overlapping border shorthands
Source: https://plumeria.dev/docs/reference/specificity.md
Example of borderTop and borderBlockWidth overlapping on border-top-width without a clear specificity ranking.
```js
const styles = css.create({
edge: { borderTop: '1px solid red' },
axis: { borderBlockWidth: 5 },
});
```
--------------------------------
### Rename JSX attribute
Source: https://plumeria.dev/docs/api-reference/codemod.md
Example of the transformation applied to JSX attributes.
```diff
-
+
```
--------------------------------
### Composition order override
Source: https://plumeria.dev/docs/api-reference/codemod.md
Example showing the transformation of a dynamic classStyle array into an override class to maintain composition order.
```diff
-
+
```
```css
.surfaceOverRaised:not(#\#) {
padding: 8px;
color: black;
}
```
--------------------------------
### Build error for css.create in component markup
Source: https://plumeria.dev/docs/integration/frameworks.md
Example of the build error encountered when attempting to use css.create directly inside a component file.
```text
[plugin @plumeria/unplugin:vite] src/components/HelloWorld.vue
Error: x Expected '', got ':'
```
--------------------------------
### Type-only module definition
Source: https://plumeria.dev/docs/api-reference/codemod.md
Example of a module declaring only style prop types, which is not reached by the codemod.
```ts
import type { StyleProps } from '@plumeria/core';
export type CardProps = {
classStyle?: StyleProps<'color'>;
};
```
--------------------------------
### Configure custom styleProp
Source: https://plumeria.dev/docs/api-reference/plugins/unplugin.md
Example of setting a custom style property name in the plugin configuration and declaring it for TypeScript.
```ts
plumeria.vite({ styleProp: 'sx' });
```
```ts
import type { Style } from '@plumeria/core';
declare global {
namespace React {
interface HTMLAttributes {
sx?: Style;
}
interface SVGAttributes {
sx?: Style;
}
}
}
```
--------------------------------
### Using StyleProps in a component (TypeScript)
Source: https://plumeria.dev/docs/api-reference/types/StyleProps.md
Shows how to use StyleProps to type a component's style prop, restricting it to specific properties like 'color' and 'fontSize'. The example imports from '@plumeria/core' and creates a Text component that accepts a classStyle prop.
```tsx
import * as css from '@plumeria/core';
const styles = css.create({
base: {
fontSize: '14px',
},
});
type TextProps = {
classStyle?: css.StyleProps<'color' | 'fontSize'>;
};
export function Text({ classStyle }: TextProps) {
return ;
}
```
--------------------------------
### Migrate from CSS Modules
Source: https://plumeria.dev/docs/why-plumeria.md
Run this command to convert each `*.module.css` file to a `*.styles.ts` file and update consumers. Unconvertible descendant rules become markers with extended styles.
```sh
npx @plumeria/codemod migrate --from css-modules
```
--------------------------------
### Migrate from Plumeria back to CSS Modules
Source: https://plumeria.dev/docs/why-plumeria.md
Run this command to convert `*.styles.ts` files back to `*.module.css`, moving theme tokens and animations to global CSS and call sites to `className`. This is an export, not a round trip.
```sh
npx @plumeria/codemod migrate --from plumeria
```
--------------------------------
### Configure rollup.config.js with plumeria.rollup()
Source: https://plumeria.dev/docs/integration/rollup.md
Configure rollup to use the Plumeria unplugin. The plugin is added as plumeria.rollup() and must be placed before postcss({ extract: true }) to compile Plumeria styles into the CSS asset. The example also includes plugins for resolving modules, commonjs, replacing process.env.NODE_ENV, and esbuild for JSX/TSX.
```js
import plumeria from '@plumeria/unplugin';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import replace from '@rollup/plugin-replace';
import esbuild from 'rollup-plugin-esbuild';
import postcss from 'rollup-plugin-postcss';
export default {
input: 'src/index.tsx',
output: {
dir: 'dist',
format: 'esm',
},
plugins: [
plumeria.rollup(),
postcss({ extract: true }),
resolve({ extensions: ['.js', '.jsx', '.ts', '.tsx'] }),
commonjs(),
replace({
'process.env.NODE_ENV': JSON.stringify('development'),
preventAssignment: true,
}),
esbuild({
include: /\.[jt]sx?$/,
sourceMap: false,
minify: false,
target: 'es2022',
jsx: 'automatic',
}),
],
};
```
--------------------------------
### Rspack configuration with Plumeria plugin
Source: https://plumeria.dev/docs/integration/rspack.md
Example rspack.config.js that sets up the Plumeria unplugin, SWC loader for TypeScript/React, and React refresh in development. The plugin is added via plumeria.rspack() and the config enables HMR on port 3000.
```ts
import { rspack } from '@rspack/core';
import { ReactRefreshRspackPlugin } from '@rspack/plugin-react-refresh';
import plumeria from '@plumeria/unplugin';
const isDev = process.env.NODE_ENV === 'development';
export default {
entry: './src/index.tsx',
output: {
filename: 'bundle.js',
clean: true,
},
resolve: {
extensions: ['.ts', '.tsx', '.js'],
},
module: {
rules: [
{
test: /\.tsx?$/,
use: {
loader: 'builtin:swc-loader',
options: {
jsc: {
parser: { syntax: 'typescript', tsx: true },
transform: {
react: {
runtime: 'automatic',
development: isDev,
refresh: isDev,
},
},
},
},
},
},
],
},
plugins: [
plumeria.rspack(),
new rspack.HtmlRspackPlugin({ template: './src/index.html' }),
isDev && new ReactRefreshRspackPlugin(),
].filter(Boolean),
devServer: {
hot: true,
port: 3000,
},
};
```
--------------------------------
### Test style compilation with @plumeria/unplugin transform
Source: https://plumeria.dev/docs/ai.md
For projects using @plumeria/unplugin, call the transform directly to test what a style compiles to. It returns the rewritten code and the stylesheet, without a component, DOM, or bundler. The example extracts the CSS ID from the rewritten code and loads the stylesheet.
```js
const { unpluginFactory } = require('@plumeria/unplugin/factory');
const plugin = unpluginFactory();
const { code } = await plugin.transform(source, id);
const cssId = code.match(/import "(.+\.zero\.css)"/)[1];
const css = plugin.load(cssId);
```
--------------------------------
### Custom cross-fade with viewTransition (TypeScript and CSS)
Source: https://plumeria.dev/docs/api-reference/javascript/viewTransition.md
This example shows how to use viewTransition with custom keyframes for a long cross-fade. The TypeScript code defines fadeIn and fadeOut animations and passes them to viewTransition, then creates a CSS rule with the returned view-transition-name. The CSS output shows the generated keyframes and view-transition rules.
```ts
import * as css from '@plumeria/core';
const fadeIn = css.keyframes({
from: { opacity: 0 },
to: { opacity: 1 },
});
const fadeOut = css.keyframes({
from: { opacity: 1 },
to: { opacity: 0 },
});
const longCrossFade = css.viewTransition({
old: {
animationName: fadeOut,
animationDuration: '1.2s',
},
new: {
animationName: fadeIn,
animationDuration: '1.2s',
},
});
export const transition = css.create({
name: {
viewTransitionName: longCrossFade,
},
});
```
```css
@keyframes kf-x34h9adh {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes kf-xmzotw7h {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
::view-transition-old(vt-xsq18f68) {
animation-name: kf-xmzotw7h;
animation-duration: 1.2s;
}
::view-transition-new(vt-xsq18f68) {
animation-name: kf-x34h9adh;
animation-duration: 1.2s;
}
.xa6j6hgv {
view-transition-name: vt-xjp967de;
}
```
--------------------------------
### Migrating Tailwind Variants to Plumeria css.create
Source: https://plumeria.dev/docs/ai.md
Comparison showing the transition from a dynamic tv() configuration to a static css.create() implementation. Note that external overrides are handled via the classStyle array rather than twMerge.
```tsx
// --- Before ---
const button = tv({
base: 'inline-flex rounded font-medium',
variants: {
size: { sm: 'h-8 px-3 text-sm', lg: 'h-12 px-6 text-lg' },
tone: { primary: 'bg-blue-500 text-white', danger: 'bg-red-500 text-white' },
},
compoundVariants: [{ size: 'lg', tone: 'primary', class: 'shadow-lg' }],
defaultVariants: { size: 'sm', tone: 'primary' },
});
;
// --- After (values resolved from the project's compiled CSS, not recalled) ---
const styles = css.create({
base: { display: 'inline-flex', borderRadius: '4px', fontWeight: 500 },
lgPrimary: { boxShadow: '0 10px 15px -3px rgb(0 0 0 / 0.1)' },
});
const sizeStyles = css.create({
sm: { height: '32px', paddingInline: '12px', fontSize: '14px' },
lg: { height: '48px', paddingInline: '24px', fontSize: '18px' },
});
const toneStyles = css.create({
primary: { backgroundColor: '#3b82f6', color: '#fff' },
danger: { backgroundColor: '#ef4444', color: '#fff' },
});
type ButtonProps = {
size?: keyof typeof sizeStyles;
tone?: keyof typeof toneStyles;
styleArray?: css.Style;
};
export const Button = ({ size = 'sm', tone = 'primary', styleArray }: ButtonProps) => (
);
```
--------------------------------
### Nested blocks are covered - type error example
Source: https://plumeria.dev/docs/api-reference/types/StyleProps.md
Shows that StyleProps checks properties inside nested blocks (like pseudo-classes). This example causes a type error because 'position' is not enumerated in the StyleProps.
```tsx
// Type error, position is not enumerated
```
--------------------------------
### Example usage of AtomicClassNameFor with @plumeria/core
Source: https://plumeria.dev/docs/api-reference/types/AtomicClassNameFor.md
Shows how to use AtomicClassNameFor to type a variable that holds an atomic class name. The example demonstrates that assigning a class name for a different property causes a type error.
```typescript
import * as css from '@plumeria/core';
const styles = css.create({
text: {
color: 'red',
fontSize: '12px',
},
});
const color: css.AtomicClassNameFor<'color', 'red'> = styles.text.color; // ok
const wrong: css.AtomicClassNameFor<'color', 'red'> = styles.text.fontSize; // Type error
```
--------------------------------
### Functional pseudo-classes usage
Source: https://plumeria.dev/docs/api-reference/javascript/marker.md
Example of using functional pseudo-classes like :has() with marker and extended.
```ts
const styles = css.create({
wrap: {
...css.marker('wrap', ':has(a:hover)'),
},
child: {
[css.extended('wrap', ':has(a:hover)')]: { color: 'red' },
},
});
```
```css
.xwpr9f08:has(a:hover) {
--xg204awn-wrap-has: 1;
}
@container style(--xg204awn-wrap-has: 1) {
.xof70rr5:not(#\#) {
color: red;
}
}
```
--------------------------------
### Configure Vite for Qwik integration
Source: https://plumeria.dev/docs/integration/frameworks.md
Place plumeria.vite() before qwikVite() in the plugins array to ensure proper compilation order.
```ts
import { defineConfig } from 'vite';
import { qwikVite } from '@builder.io/qwik/optimizer';
import plumeria from '@plumeria/unplugin';
export default defineConfig({
plugins: [plumeria.vite(), qwikVite({ csr: true })],
});
```
--------------------------------
### Create plumeria.d.ts with @plumeria/core/class-style reference
Source: https://plumeria.dev/docs/getting-started/installation.md
Create a `plumeria.d.ts` file at the application root. This reference is required because `@plumeria/core` does not ship its own prop declaration; it names the styling prop your project compiles with.
```ts
/* application root */
///
```
--------------------------------
### Build script with esbuild and @plumeria/unplugin (build.js)
Source: https://plumeria.dev/docs/integration/component-library.md
Build script for a library using esbuild and the Plumeria unplugin. It bundles the component, externalizes React, and prepends the stylesheet import to the output because build tools do not wire the CSS automatically.
```js
import esbuild from 'esbuild';
import fs from 'node:fs';
import plumeria from '@plumeria/unplugin';
await esbuild.build({
entryPoints: ['src/index.tsx'],
bundle: true,
outfile: 'dist/index.js',
external: ['react', 'react/jsx-runtime'],
plugins: [plumeria.esbuild({ include: /\.[jt]sx?$/ })],
loader: { '.tsx': 'tsx', '.ts': 'ts' },
format: 'esm',
jsx: 'automatic',
});
fs.writeFileSync(
'dist/index.js',
`import './index.css';\n${fs.readFileSync('dist/index.js', 'utf-8')}`,
);
```
--------------------------------
### Component source and build output (src/index.tsx, dist/index.js, dist/index.css)
Source: https://plumeria.dev/docs/integration/component-library.md
Shows the source component, the emitted JavaScript, and the extracted CSS. The build removes the `css.create` call and `@plumeria/core` import, leaving string literals and a flat rule list.
```tsx
import * as css from '@plumeria/core';
const styles = css.create({
card: { display: 'flex', padding: '16px', borderRadius: '8px' },
title: { fontSize: '18px', fontWeight: 'bold' },
});
export const Card = ({ title }: { title: string }) => (
{title}
);
```
```js
import './index.css';
import { jsx } from 'react/jsx-runtime';
var Card = ({ title }) =>
jsx('div', {
className: 'xxp6epoh xqqbxt1d xyqr9vb7',
children: jsx('h2', { className: 'xpdfgu2b xybc5i37', children: title }),
});
export { Card };
```
```css
.xxp6epoh { display: flex; }
.xqqbxt1d { padding: 16px; }
.xyqr9vb7 { border-radius: 8px; }
.xpdfgu2b:not(#\#) { font-size: 18px; }
.xybc5i37:not(#\#) { font-weight: 700; }
```
--------------------------------
### Basic usage of css.create
Source: https://plumeria.dev/docs/api-reference/javascript/create.md
Defines styles for a container and text using plain objects, then applies them via `classStyle` in a React component. The bundler cleans up the call.
```tsx
import * as css from '@plumeria/core'
const styles = css.create({
container: {
display: 'flex',
justifyContent: 'space-between',
},
text: {
fontSize: '14px',
textDecoration: 'none',
},
})
export default function App() {
return (
);
}
```
--------------------------------
### Vite configuration with options for include, exclude, and styleProp
Source: https://plumeria.dev/docs/integration/vite.md
Configure the plugin with include and exclude glob patterns and a custom style prop. The default styleProp is 'classStyle'.
```ts
export default defineConfig({
plugins: [
plumeria.vite({
include: ['./src/**/*.{ts,tsx}'],
exclude: ['**/node_modules/**'],
styleProp: 'sx',
}),
],
});
```
--------------------------------
### Use WithoutProperties in a component
Source: https://plumeria.dev/docs/api-reference/types/WithoutProperties.md
An example of using WithoutProperties to restrict specific style properties in a Panel component.
```tsx
import * as css from '@plumeria/core';
const styles = css.create({
base: {
display: 'flex',
padding: '8px',
},
});
type PanelProps = {
classStyle?: css.WithoutProperties<'position' | 'top' | 'left'>;
};
export function Panel({ classStyle }: PanelProps) {
return ;
}
```
--------------------------------
### Configure ESLint 8
Source: https://plumeria.dev/docs/getting-started/editor-integration.md
Legacy configuration format for ESLint 8.
```json
{
"plugins": ["@plumeria"],
"extends": ["plugin:@plumeria/recommended"],
"rules": {}
}
```
--------------------------------
### Migrate multiple css.create calls in Button.tsx
Source: https://plumeria.dev/docs/api-reference/codemod.md
Demonstrates how multiple css.create calls in a single file are consolidated into a shared stylesheet, with key collisions resolved by renaming.
```diff
- const styles = css.create({ base: { color: 'red' } });
- const hoverStyles = css.create({ base: { color: 'blue' } });
+ import styles from './Button.module.css';
export const Button = () => (
-
+
);
```
--------------------------------
### Validate WithoutProperties usage
Source: https://plumeria.dev/docs/api-reference/types/WithoutProperties.md
Examples of valid and invalid usage of the Panel component based on the defined style restrictions.
```tsx
// ok when tinted only sets color
// Type error when pinned sets position
```
--------------------------------
### Configure vitest.config.ts for Plumeria
Source: https://plumeria.dev/docs/testing.md
Integrate the Plumeria plugin into your Vite configuration for Vitest. This setup uses the jsdom environment.
```ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
import plumeria from '@plumeria/unplugin';
export default defineConfig({
plugins: [react(), plumeria.vite()],
test: {
environment: 'jsdom',
},
});
```
--------------------------------
### View migration reports
Source: https://plumeria.dev/docs/api-reference/codemod.md
The tool reports rules that cannot be converted, such as external compositions or sibling combinators, providing the file path, line number, and reason for the report.
```text
src/Card.module.css
9:3 composes-external composes: base from './shared.module.css'
A class composed from another file is not resolved. Convert that
stylesheet too, then pass both at the call site as an array.
12:1 sibling-combinator .item + .item
A container query reaches descendants, never siblings, so no marker
states this. Whether an ordinal such as `:not(:first-child)` is
equivalent depends on the markup.
```
--------------------------------
### Test style compilation with @plumeria/turbopack-loader
Source: https://plumeria.dev/docs/ai.md
For projects on @plumeria/next-plugin, call the loader its build runs with a custom loader context. The loader returns the rewritten code and writes its stylesheet only when NODE_ENV is development or production; a test run is neither, so the file is left alone. Read class names from the returned code and derive them; do not hard-code them.
```js
const loader = require('@plumeria/turbopack-loader');
const fn = loader.default ?? loader;
const compile = (source) =>
new Promise((resolve, reject) => {
fn.call(
{
resourcePath: `${__dirname}/fixture.tsx`,
async: () => (err, content) => (err ? reject(err) : resolve(content)),
addDependency: () => {},
clearDependencies: () => {},
},
source,
);
});
```
--------------------------------
### Enable recommended config in ESLint
Source: https://plumeria.dev/docs/api-reference/plugins/eslint-plugin.md
Enable the recommended configuration from the Plumeria ESLint plugin. This turns on all recommended rules.
```js
import plumeria from '@plumeria/eslint-plugin';
export default [plumeria.configs.recommended];
```
--------------------------------
### Import styles into a Vue component
Source: https://plumeria.dev/docs/integration/frameworks.md
Import the styles defined in the separate TypeScript module into the script setup block of a .vue component.
```html
card
```
--------------------------------
### Prompt for your coding agent
Source: https://plumeria.dev/docs/ai-agent-resources.md
Use this prompt to instruct a coding agent to read the Plumeria documentation in the specified order before making changes. It establishes AI.md as authoritative and warns against applying runtime CSS-in-JS conventions because Plumeria styles are compiled statically.
```text
Read these Plumeria documents in order before making changes:
1. Installation — https://plumeria.dev/docs/getting-started/installation.md
2. Rules for AI agents — https://plumeria.dev/docs/ai.md
3. Introduction and core usage — https://plumeria.dev/docs.md
Follow AI.md as authoritative. Inspect the existing project's bundler and framework,
then read the matching integration guide before changing configuration. Do not apply
runtime CSS-in-JS conventions to Plumeria: its styles are compiled statically.
```
--------------------------------
### Define overlapping states in one style
Source: https://plumeria.dev/docs/reference/specificity.md
Example of defining multiple pseudo-classes within a single style object, which relies on source order for resolution.
```js
const styles = css.create({
button: {
':hover': { color: 'red' },
':focus': { color: 'blue' },
},
});
```
--------------------------------
### Configure ESLint CJS
Source: https://plumeria.dev/docs/getting-started/editor-integration.md
Configuration for CommonJS-based projects.
```js
const eslint = require('@eslint/js');
const tseslint = require('typescript-eslint');
const { defineConfig } = require('eslint/config');
const { plumeria } = require('@plumeria/eslint-plugin');
module.exports = defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
plumeria.flatConfigs.recommended, // [!code ++]
{
files: ['**/*.{ts,tsx}'],
}
);
```
--------------------------------
### Define overlapping media query conditions
Source: https://plumeria.dev/docs/reference/specificity.md
Example where two media queries overlap, allowing the optimizer to place the narrower condition last to ensure consistent results.
```js
const styles = css.create({
medium: { '@media (min-width: 600px)': { color: 'red' } },
wide: { '@media (min-width: 900px)': { color: 'blue' } },
});
```
--------------------------------
### Run dry-run migration
Source: https://plumeria.dev/docs/api-reference/codemod.md
Use the --dry-run flag to inspect the migration process without modifying files. The output shows the planned file transformations and a summary of the conversion.
```sh
npx @plumeria/codemod migrate --from css-modules --dry-run
```
```text
src/Card.module.css -> src/Card.styles.ts
1 stylesheet(s) would be converted, 1 consumer(s) rewritten.
Run without --dry-run to apply.
```
--------------------------------
### Nested blocks are covered - style definition
Source: https://plumeria.dev/docs/api-reference/types/StyleProps.md
Defines a style with a nested pseudo-class ':hover' that sets 'position: fixed'. This style is used in the previous example to demonstrate that nested properties are also checked by StyleProps.
```typescript
const styles = css.create({
hoverPinned: {
':hover': {
position: 'fixed',
},
},
});
```
--------------------------------
### Configure no-physical-properties or no-logical-properties
Source: https://plumeria.dev/docs/api-reference/plugins/eslint-plugin/optional-rules.md
Configure either rule to warn and rename the opposite spelling. The comments show the suggested rename direction for each rule. Turning both on is contradictory; pick one direction.
```js
'@plumeria/no-physical-properties': 'warn'
// paddingLeft → rename to paddingInlineStart
'@plumeria/no-logical-properties': 'warn'
// paddingInlineStart → rename to paddingLeft
```
--------------------------------
### Usage examples with StyleProps
Source: https://plumeria.dev/docs/api-reference/types/StyleProps.md
Shows valid and invalid usage of the Text component with StyleProps. The first line is valid because 'tinted' only sets color, while the second line causes a type error because 'pinned' sets position, which is not enumerated.
```tsx
// ok when tinted only sets color
// Type error when pinned sets position
```
--------------------------------
### VSCode snippet suggestions settings
Source: https://plumeria.dev/docs/getting-started/editor-integration.md
Configure settings.json to prioritize snippet suggestions at the top of the completion list.
```json
{
// ...other settings
"editor.snippetSuggestions": "top",
// ...
}
```