2025-03-04 20:16:50 +02:00
|
|
|
|
# @antebudimir/eslint-plugin-vanilla-extract
|
|
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
[](https://github.com/antebudimir/eslint-plugin-vanilla-extract/actions/workflows/ci.yml)
|
|
|
|
|
|
[](https://coveralls.io/github/antebudimir/eslint-plugin-vanilla-extract?branch=main)
|
|
|
|
|
|
[](https://www.npmjs.com/package/@antebudimir/eslint-plugin-vanilla-extract)
|
|
|
|
|
|

|
2025-03-04 22:18:10 +02:00
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
An ESLint plugin for enforcing best practices in
|
|
|
|
|
|
[vanilla-extract](https://github.com/vanilla-extract-css/vanilla-extract) CSS styles, including CSS property ordering
|
|
|
|
|
|
and additional linting rules. Available presets are for alphabetical and
|
|
|
|
|
|
[concentric](https://rhodesmill.org/brandon/2011/concentric-css/) CSS ordering. The plugin also supports a custom group
|
|
|
|
|
|
ordering option based on groups available in [concentric CSS](src/css-rules/concentric-order/concentric-groups.ts).
|
2025-03-04 20:16:50 +02:00
|
|
|
|
|
2025-03-10 20:04:45 +02:00
|
|
|
|
## Demo
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
2025-03-04 20:16:50 +02:00
|
|
|
|
## Features
|
|
|
|
|
|
|
|
|
|
|
|
- Enforces CSS property ordering in vanilla-extract style objects with two available presets:
|
|
|
|
|
|
- Alphabetical ordering for clean, predictable style organization
|
|
|
|
|
|
- Concentric ordering for logical, outside-in property arrangement
|
|
|
|
|
|
- Custom group ordering option for more fine-grained control
|
2025-04-19 20:41:17 +03:00
|
|
|
|
- Compatible with ESLint 8.57.0+ and fully optimized for ESLint 9's flat config system
|
2025-03-04 20:16:50 +02:00
|
|
|
|
- Provides auto-fix capability to automatically sort properties
|
|
|
|
|
|
- Handles multiple vanilla-extract APIs (style, styleVariants, recipe, globalStyle, etc.)
|
|
|
|
|
|
- Handles complex cases like nested objects, arrays of styles, and pseudo selectors
|
|
|
|
|
|
- Works with camelCase properties as used in vanilla-extract
|
2025-03-07 11:15:10 +02:00
|
|
|
|
- Additional linting rules for enhanced code quality (see roadmap for upcoming features)
|
2025-03-04 20:16:50 +02:00
|
|
|
|
|
|
|
|
|
|
## Requirements
|
|
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
- ESLint 8.57.0 or higher
|
2025-03-04 20:16:50 +02:00
|
|
|
|
- Node.js 18.18.0 or higher
|
2025-03-06 06:23:54 +02:00
|
|
|
|
- ESM (ECMAScript Modules) only
|
2025-04-19 20:41:17 +03:00
|
|
|
|
- Flat config system using either:
|
|
|
|
|
|
- `eslint.config.mjs` (recommended, always works with ESM plugins)
|
|
|
|
|
|
- `eslint.config.js` (only if your package.json has `"type": "module"`)
|
2025-03-04 20:16:50 +02:00
|
|
|
|
|
|
|
|
|
|
## Installation
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Using npm
|
|
|
|
|
|
npm install --save-dev @antebudimir/eslint-plugin-vanilla-extract
|
|
|
|
|
|
|
|
|
|
|
|
# Using yarn
|
|
|
|
|
|
yarn add --dev @antebudimir/eslint-plugin-vanilla-extract
|
|
|
|
|
|
|
|
|
|
|
|
# Using pnpm
|
|
|
|
|
|
pnpm add -D @antebudimir/eslint-plugin-vanilla-extract
|
2025-04-19 20:41:17 +03:00
|
|
|
|
|
|
|
|
|
|
# For ESLint 8.57.0 with flat config, you'll also need:
|
|
|
|
|
|
npm install --save-dev @eslint/eslintrc @eslint/js
|
|
|
|
|
|
yarn add --dev @eslint/eslintrc @eslint/js
|
|
|
|
|
|
pnpm add -D @eslint/eslintrc @eslint/js
|
2025-03-04 20:16:50 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
|
|
|
2025-03-06 06:23:54 +02:00
|
|
|
|
**Note: This plugin is ESM-only.** It must be used with ESM configurations and can't be used with CommonJS `require()`.
|
|
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
### Configuration Options
|
|
|
|
|
|
|
|
|
|
|
|
There are two main ways to configure this plugin in your ESLint flat config:
|
2025-03-04 20:16:50 +02:00
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
### Option 1: Using extends (recommended, available from v1.10.0)
|
|
|
|
|
|
|
|
|
|
|
|
The simplest way to apply the recommended ruleset:
|
2025-03-04 20:16:50 +02:00
|
|
|
|
|
|
|
|
|
|
```typescript
|
2025-04-19 20:41:17 +03:00
|
|
|
|
import { defineConfig } from 'eslint/config';
|
2025-03-04 20:16:50 +02:00
|
|
|
|
import vanillaExtract from '@antebudimir/eslint-plugin-vanilla-extract';
|
|
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
export default defineConfig([
|
|
|
|
|
|
{
|
|
|
|
|
|
files: ['**/*.css.ts'],
|
|
|
|
|
|
ignores: ['src/**/theme-contract.css.ts'],
|
|
|
|
|
|
extends: [vanillaExtract.configs.recommended],
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Option 2: Using plugins with explicit rule configuration
|
|
|
|
|
|
|
|
|
|
|
|
This approach gives you more control over individual rules:
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
import { defineConfig } from 'eslint/config';
|
|
|
|
|
|
import vanillaExtract from '@antebudimir/eslint-plugin-vanilla-extract';
|
|
|
|
|
|
|
|
|
|
|
|
export default defineConfig([
|
2025-04-07 13:00:55 +03:00
|
|
|
|
{
|
|
|
|
|
|
files: ['**/*.css.ts'],
|
|
|
|
|
|
ignores: ['src/**/theme-contract.css.ts'],
|
|
|
|
|
|
plugins: {
|
|
|
|
|
|
'vanilla-extract': vanillaExtract,
|
|
|
|
|
|
},
|
|
|
|
|
|
rules: {
|
|
|
|
|
|
// Apply all recommended rules
|
|
|
|
|
|
...vanillaExtract.configs.recommended.rules,
|
2025-04-19 20:41:17 +03:00
|
|
|
|
|
2025-04-07 13:00:55 +03:00
|
|
|
|
// Optionally override specific rules
|
|
|
|
|
|
// 'vanilla-extract/concentric-order': 'warn', // Change severity from error to warn
|
|
|
|
|
|
// 'vanilla-extract/no-empty-style-blocks': 'off', // Disable a recommended rule
|
2025-04-12 20:43:11 +03:00
|
|
|
|
// 'vanilla-extract/no-zero-unit': 'warn', // Change severity from error to warn
|
2025-04-19 20:41:17 +03:00
|
|
|
|
|
2025-04-07 13:00:55 +03:00
|
|
|
|
// Add additional rules not in recommended config
|
|
|
|
|
|
// 'vanilla-extract/alphabetical-order': 'error', // Override concentric-order rule
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
### Using with FlatCompat (for ESLint 8.57.0 & 8.57.1)
|
|
|
|
|
|
|
|
|
|
|
|
If you're migrating from legacy ESLint configurations, you can use the `FlatCompat` utility to convert them while adding
|
|
|
|
|
|
vanilla-extract support:
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
import path from 'path';
|
|
|
|
|
|
import { fileURLToPath } from 'url';
|
|
|
|
|
|
import { FlatCompat } from '@eslint/eslintrc';
|
|
|
|
|
|
import js from '@eslint/js';
|
|
|
|
|
|
import vanillaExtract from '@antebudimir/eslint-plugin-vanilla-extract';
|
|
|
|
|
|
|
|
|
|
|
|
// Mimic CommonJS variables
|
|
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
|
|
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
|
|
|
|
|
|
|
|
// Create a compatibility layer instance
|
|
|
|
|
|
const compat = new FlatCompat({
|
|
|
|
|
|
baseDirectory: __dirname,
|
|
|
|
|
|
recommendedConfig: js.configs.recommended,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
export default [
|
|
|
|
|
|
// Convert your existing ESLint configs
|
|
|
|
|
|
...compat.config({
|
|
|
|
|
|
extends: [
|
|
|
|
|
|
'eslint:recommended',
|
|
|
|
|
|
'plugin:@typescript-eslint/recommended',
|
|
|
|
|
|
// etc
|
|
|
|
|
|
],
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
|
|
// Add vanilla-extract by using explicit rule config
|
|
|
|
|
|
{
|
|
|
|
|
|
files: ['**/*.css.ts'],
|
|
|
|
|
|
ignores: ['src/**/theme-contract.css.ts'],
|
|
|
|
|
|
plugins: {
|
|
|
|
|
|
'vanilla-extract': vanillaExtract,
|
|
|
|
|
|
},
|
|
|
|
|
|
rules: {
|
|
|
|
|
|
// Apply all recommended rules
|
|
|
|
|
|
...vanillaExtract.configs.recommended.rules,
|
|
|
|
|
|
// or specify rule by rule as described above
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### Common Issues with FlatCompat
|
|
|
|
|
|
|
|
|
|
|
|
1. **Error: "Unexpected top-level property 'files'"**
|
|
|
|
|
|
|
|
|
|
|
|
- Solution: When using `compat.config()`, use `overrides` instead of `files` at the top level.
|
|
|
|
|
|
|
|
|
|
|
|
2. **Error: "Missing parameter 'recommendedConfig' in FlatCompat constructor"**
|
|
|
|
|
|
|
|
|
|
|
|
- Solution: Import `js` from `@eslint/js` and add `recommendedConfig: js.configs.recommended` to the FlatCompat
|
|
|
|
|
|
constructor.
|
|
|
|
|
|
|
|
|
|
|
|
3. **Error: "Unexpected undefined config at user-defined index 0"**
|
|
|
|
|
|
- Solution: Make sure you're using a default export for your configuration array.
|
|
|
|
|
|
|
|
|
|
|
|
### VS Code Integration
|
|
|
|
|
|
|
|
|
|
|
|
For VS Code users, add these settings to your `.vscode/settings.json`:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"eslint.useFlatConfig": true,
|
|
|
|
|
|
"eslint.experimental.useFlatConfig": true,
|
|
|
|
|
|
"eslint.validate": ["javascript", "typescript", "typescriptreact"]
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2025-04-07 13:00:55 +03:00
|
|
|
|
### Recommended Configuration
|
|
|
|
|
|
|
|
|
|
|
|
The recommended configuration enables the following rules with error severity:
|
|
|
|
|
|
|
|
|
|
|
|
- `vanilla-extract/concentric-order`: Enforces concentric CSS property ordering
|
|
|
|
|
|
- `vanilla-extract/no-empty-style-blocks`: Prevents empty style blocks
|
2025-04-16 09:43:06 +03:00
|
|
|
|
- `vanilla-extract/no-unknown-unit`: prohibits usage of unrecognized CSS units.
|
2025-04-12 20:43:11 +03:00
|
|
|
|
- `vanilla-extract/no-zero-unit`: removes unnecessary units for zero values
|
2025-04-07 13:00:55 +03:00
|
|
|
|
|
|
|
|
|
|
You can use the recommended configuration as a starting point and override rules as needed for your project.
|
|
|
|
|
|
|
|
|
|
|
|
### Custom Configuration
|
|
|
|
|
|
|
|
|
|
|
|
If you prefer not to use the recommended configuration, you can still configure rules manually:
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
2025-03-04 20:16:50 +02:00
|
|
|
|
export default [
|
|
|
|
|
|
{
|
|
|
|
|
|
files: ['**/*.css.ts'],
|
|
|
|
|
|
ignores: ['src/**/theme-contract.css.ts'],
|
|
|
|
|
|
plugins: {
|
|
|
|
|
|
'vanilla-extract': vanillaExtract,
|
|
|
|
|
|
},
|
|
|
|
|
|
rules: {
|
|
|
|
|
|
// 'vanilla-extract/alphabetical-order': 'warn',
|
|
|
|
|
|
// OR
|
|
|
|
|
|
// 'vanilla-extract/concentric-order': 'warn',
|
|
|
|
|
|
// OR
|
|
|
|
|
|
'vanilla-extract/custom-order': [
|
|
|
|
|
|
'warn',
|
|
|
|
|
|
{
|
|
|
|
|
|
groupOrder: ['font', 'dimensions', 'margin', 'padding', 'position', 'border'], // example group order
|
|
|
|
|
|
// optional
|
|
|
|
|
|
sortRemainingProperties: 'concentric', // 'alphabetical' is default
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
2025-04-16 09:43:06 +03:00
|
|
|
|
'vanilla-extract/no-unknown-unit': 'error',
|
2025-04-12 20:43:11 +03:00
|
|
|
|
'vanilla-extract/no-zero-unit': 'warn',
|
2025-03-04 20:16:50 +02:00
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Rules
|
|
|
|
|
|
|
|
|
|
|
|
### vanilla-extract/alphabetical-order
|
|
|
|
|
|
|
|
|
|
|
|
This rule enforces that CSS properties in vanilla-extract style objects follow alphabetical ordering.
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// ❌ Incorrect
|
|
|
|
|
|
import { style } from '@vanilla-extract/css';
|
|
|
|
|
|
|
|
|
|
|
|
export const myStyle = style({
|
|
|
|
|
|
display: 'flex',
|
|
|
|
|
|
justifyContent: 'center',
|
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
|
height: 19,
|
|
|
|
|
|
marginBottom: 1,
|
|
|
|
|
|
marginLeft: 2,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// ✅ Correct
|
|
|
|
|
|
import { style } from '@vanilla-extract/css';
|
|
|
|
|
|
|
|
|
|
|
|
export const myStyle = style({
|
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
|
display: 'flex',
|
|
|
|
|
|
height: 19,
|
|
|
|
|
|
justifyContent: 'center',
|
|
|
|
|
|
marginBottom: 1,
|
|
|
|
|
|
marginLeft: 2,
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### vanilla-extract/concentric-order
|
|
|
|
|
|
|
|
|
|
|
|
This rule enforces that CSS properties in vanilla-extract style objects follow the concentric CSS ordering pattern,
|
|
|
|
|
|
which organizes properties from outside to inside.
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// ❌ Incorrect
|
|
|
|
|
|
import { style } from '@vanilla-extract/css';
|
|
|
|
|
|
|
|
|
|
|
|
export const myStyle = style({
|
|
|
|
|
|
color: 'red',
|
|
|
|
|
|
display: 'flex',
|
|
|
|
|
|
position: 'relative',
|
|
|
|
|
|
padding: '10px',
|
|
|
|
|
|
margin: '20px',
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// ✅ Correct
|
|
|
|
|
|
import { style } from '@vanilla-extract/css';
|
|
|
|
|
|
|
|
|
|
|
|
export const myStyle = style({
|
|
|
|
|
|
position: 'relative',
|
|
|
|
|
|
display: 'flex',
|
|
|
|
|
|
margin: '20px',
|
|
|
|
|
|
padding: '10px',
|
|
|
|
|
|
color: 'red',
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### vanilla-extract/custom-order
|
|
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
The `vanilla-extract/custom-order` rule enables you to enforce a custom ordering of CSS properties in your
|
|
|
|
|
|
vanilla-extract styles. You can specify an array of property groups in your preferred order, and the rule will ensure
|
|
|
|
|
|
that properties within these groups are sorted according to their position in the concentric CSS model.
|
2025-03-04 20:16:50 +02:00
|
|
|
|
|
2025-03-12 06:06:40 +02:00
|
|
|
|
Key features of this rule include:
|
2025-03-04 20:16:50 +02:00
|
|
|
|
|
2025-03-12 06:06:40 +02:00
|
|
|
|
1. Custom group ordering: Define your preferred order of CSS property groups.
|
2025-04-19 20:41:17 +03:00
|
|
|
|
2. Handling of unspecified groups: All groups not included in the custom array will have their properties sorted after
|
|
|
|
|
|
the last specified group.
|
|
|
|
|
|
3. Flexible sorting options: You can choose to sort remaining properties either alphabetically or following the
|
|
|
|
|
|
concentric CSS order by setting the `sortRemainingProperties` option to 'alphabetical' or 'concentric' respectively.
|
2025-03-12 06:06:40 +02:00
|
|
|
|
|
|
|
|
|
|
Default behavior:
|
|
|
|
|
|
|
|
|
|
|
|
- If not set, `sortRemainingProperties` defaults to 'alphabetical'.
|
2025-04-19 20:41:17 +03:00
|
|
|
|
- If no `groupOrder` is specified or an empty array is provided, the rule will default to sorting all properties
|
|
|
|
|
|
alphabetically, and `sortRemainingProperties` will be ignored even if set.
|
2025-03-12 06:06:40 +02:00
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
To configure the rule, add it to your ESLint configuration file with your desired options. You can customize the
|
|
|
|
|
|
`groups` array to include any number of available CSS property groups you want to enforce, with a minimum of one group
|
|
|
|
|
|
required.
|
2025-03-04 20:16:50 +02:00
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// ❌ Incorrect (Unordered)
|
|
|
|
|
|
import { style } from '@vanilla-extract/css';
|
|
|
|
|
|
|
|
|
|
|
|
export const myStyle = style({
|
|
|
|
|
|
color: 'blue',
|
|
|
|
|
|
padding: '10px',
|
|
|
|
|
|
fontFamily: 'Arial, sans-serif',
|
|
|
|
|
|
margin: '20px',
|
|
|
|
|
|
width: '200px',
|
|
|
|
|
|
border: '1px solid black',
|
|
|
|
|
|
display: 'flex',
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// ✅ Correct
|
|
|
|
|
|
import { style } from '@vanilla-extract/css';
|
|
|
|
|
|
|
|
|
|
|
|
export const myStyle = style({
|
|
|
|
|
|
// font group
|
|
|
|
|
|
fontFamily: 'Arial, sans-serif',
|
|
|
|
|
|
color: 'blue',
|
|
|
|
|
|
|
|
|
|
|
|
// dimensions group
|
|
|
|
|
|
width: '200px',
|
|
|
|
|
|
|
|
|
|
|
|
// margin group
|
|
|
|
|
|
margin: '20px',
|
|
|
|
|
|
|
|
|
|
|
|
// padding group
|
|
|
|
|
|
padding: '10px',
|
|
|
|
|
|
|
|
|
|
|
|
// display group
|
|
|
|
|
|
display: 'flex',
|
|
|
|
|
|
|
|
|
|
|
|
// border group
|
|
|
|
|
|
border: '1px solid black',
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2025-04-06 11:37:34 +03:00
|
|
|
|
### vanilla-extract/no-empty-style-blocks
|
|
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
This rule detects and prevents empty style blocks in vanilla-extract stylesheets. It helps maintain cleaner codebases by
|
|
|
|
|
|
eliminating empty style definitions that often result from incomplete refactoring or forgotten implementations.
|
2025-04-06 11:37:34 +03:00
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// ❌ Incorrect
|
|
|
|
|
|
import { style } from '@vanilla-extract/css';
|
|
|
|
|
|
|
|
|
|
|
|
export const emptyStyle = style({});
|
|
|
|
|
|
|
|
|
|
|
|
export const nestedEmpty = style({
|
|
|
|
|
|
color: 'blue',
|
|
|
|
|
|
|
|
|
|
|
|
':hover': {},
|
|
|
|
|
|
'@media': {
|
|
|
|
|
|
'(min-width: 768px)': {},
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
export const recipeWithEmptyVariants = recipe({
|
|
|
|
|
|
base: { color: 'black' },
|
|
|
|
|
|
variants: {},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// ✅ Correct
|
|
|
|
|
|
import { style } from '@vanilla-extract/css';
|
|
|
|
|
|
|
|
|
|
|
|
export const nestedEmpty = style({
|
|
|
|
|
|
color: 'blue',
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
export const recipeWithEmptyVariants = recipe({
|
|
|
|
|
|
base: { color: 'black' },
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2025-04-16 09:43:06 +03:00
|
|
|
|
## vanilla-extract/no-unknown-unit
|
|
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
This rule enforces the use of valid CSS units in vanilla-extract style objects. It prevents typos and non-standard units
|
|
|
|
|
|
that could cause styling issues or browser compatibility problems.
|
2025-04-16 09:43:06 +03:00
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// ❌ Incorrect
|
|
|
|
|
|
import { style, globalStyle, recipe } from '@vanilla-extract/css';
|
|
|
|
|
|
|
|
|
|
|
|
export const invalidStyle = style({
|
2025-04-19 20:41:17 +03:00
|
|
|
|
margin: '5abc', // Non-existent unit
|
2025-04-16 09:43:06 +03:00
|
|
|
|
fontSize: '1.5rems', // Typo in unit
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
export const myRecipe = recipe({
|
|
|
|
|
|
variants: {
|
|
|
|
|
|
size: {
|
2025-04-19 20:41:17 +03:00
|
|
|
|
large: { padding: '4xm' }, // Invalid unit
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
2025-04-16 09:43:06 +03:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// ✅ Correct
|
|
|
|
|
|
import { style, globalStyle, recipe } from '@vanilla-extract/css';
|
|
|
|
|
|
|
|
|
|
|
|
export const validStyle = style({
|
|
|
|
|
|
margin: '5rem',
|
|
|
|
|
|
fontSize: '1.5rem',
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
export const myRecipe = recipe({
|
|
|
|
|
|
variants: {
|
|
|
|
|
|
size: {
|
2025-04-19 20:41:17 +03:00
|
|
|
|
large: { padding: '4em' },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
2025-04-16 09:43:06 +03:00
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2025-04-12 20:43:11 +03:00
|
|
|
|
## vanilla-extract/no-zero-unit
|
|
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
This rule enforces the removal of unnecessary units for zero values in vanilla-extract style objects. It helps maintain
|
|
|
|
|
|
cleaner and more consistent CSS by eliminating redundant units when the value is zero.
|
2025-04-12 20:43:11 +03:00
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// ❌ Incorrect
|
|
|
|
|
|
import { style } from '@vanilla-extract/css';
|
|
|
|
|
|
|
|
|
|
|
|
export const myStyle = style({
|
|
|
|
|
|
margin: '0px',
|
|
|
|
|
|
padding: '0rem',
|
|
|
|
|
|
width: '0%',
|
|
|
|
|
|
height: '0vh',
|
|
|
|
|
|
top: '-0em',
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// ✅ Correct
|
|
|
|
|
|
import { style } from '@vanilla-extract/css';
|
|
|
|
|
|
|
|
|
|
|
|
export const myStyle = style({
|
|
|
|
|
|
margin: '0',
|
|
|
|
|
|
padding: '0',
|
|
|
|
|
|
width: '0',
|
|
|
|
|
|
height: '0',
|
|
|
|
|
|
top: '0',
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2025-03-08 23:05:23 +02:00
|
|
|
|
## Font Face Declarations
|
|
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
For `fontFace` and `globalFontFace` API calls, all three ordering rules (alphabetical, concentric, and custom) enforce
|
|
|
|
|
|
the same special ordering:
|
2025-03-08 23:05:23 +02:00
|
|
|
|
|
|
|
|
|
|
1. The `src` property always appears first
|
|
|
|
|
|
2. All remaining properties are sorted alphabetically
|
|
|
|
|
|
|
|
|
|
|
|
This special handling is applied because:
|
|
|
|
|
|
|
|
|
|
|
|
- The `src` property is the most critical property in font face declarations
|
|
|
|
|
|
- Consistent ordering improves readability for these specific APIs
|
|
|
|
|
|
- Font-related properties are specialized and benefit from standardized ordering
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// ✅ Correct ordering for font faces
|
|
|
|
|
|
export const theFont = fontFace({
|
|
|
|
|
|
src: ['url("/fonts/MyFont.woff2") format("woff2")', 'url("/fonts/MyFont.woff") format("woff")'],
|
|
|
|
|
|
ascentOverride: '90%',
|
|
|
|
|
|
descentOverride: '10%',
|
|
|
|
|
|
fontDisplay: 'swap',
|
|
|
|
|
|
fontFeatureSettings: '"liga" 1',
|
|
|
|
|
|
fontStretch: 'normal',
|
|
|
|
|
|
// ...other properties in alphabetical order
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Opinionated, but it is what it is. If someone has a suggestion for a better ordering, let me know!
|
|
|
|
|
|
|
2025-03-04 20:16:50 +02:00
|
|
|
|
## Concentric CSS Model
|
|
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
Here's a list of all available groups from the provided
|
|
|
|
|
|
[concentricGroups](src/css-rules/concentric-order/concentric-groups.ts) array:
|
2025-03-04 20:16:50 +02:00
|
|
|
|
|
|
|
|
|
|
1. boxSizing
|
|
|
|
|
|
2. position
|
|
|
|
|
|
3. display
|
|
|
|
|
|
4. flex
|
|
|
|
|
|
5. grid
|
|
|
|
|
|
6. alignment
|
|
|
|
|
|
7. columns
|
|
|
|
|
|
8. transform
|
|
|
|
|
|
9. transitions
|
|
|
|
|
|
10. visibility
|
|
|
|
|
|
11. shape
|
|
|
|
|
|
12. margin
|
|
|
|
|
|
13. outline
|
|
|
|
|
|
14. border
|
|
|
|
|
|
15. boxShadow
|
|
|
|
|
|
16. background
|
|
|
|
|
|
17. cursor
|
|
|
|
|
|
18. padding
|
|
|
|
|
|
19. dimensions
|
|
|
|
|
|
20. overflow
|
|
|
|
|
|
21. listStyle
|
|
|
|
|
|
22. tables
|
|
|
|
|
|
23. animation
|
|
|
|
|
|
24. text
|
|
|
|
|
|
25. textSpacing
|
|
|
|
|
|
26. font
|
|
|
|
|
|
27. content
|
|
|
|
|
|
28. counters
|
|
|
|
|
|
29. breaks
|
|
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
These groups represent different categories of CSS properties, organized in a concentric order from outside to inside.
|
|
|
|
|
|
Each group contains related CSS properties that affect specific aspects of an element's styling and layout.
|
2025-03-04 20:16:50 +02:00
|
|
|
|
|
|
|
|
|
|
## Roadmap
|
|
|
|
|
|
|
|
|
|
|
|
The roadmap outlines the project's current status and future plans:
|
|
|
|
|
|
|
|
|
|
|
|
### Completed Milestones
|
|
|
|
|
|
|
|
|
|
|
|
- Initial release with support for alphabetical, concentric, and custom group CSS ordering.
|
|
|
|
|
|
- Auto-fix capability integrated into ESLint.
|
2025-03-08 23:05:23 +02:00
|
|
|
|
- Support for multiple vanilla-extract APIs (e.g., `style`, `styleVariants`, `recipe`, `globalStyle`, `fontFace`, etc.).
|
2025-04-06 11:37:34 +03:00
|
|
|
|
- `no-empty-style-blocks` rule to disallow empty blocks.
|
2025-04-07 13:00:55 +03:00
|
|
|
|
- Recommended ESLint configuration for the plugin.
|
2025-04-12 20:43:11 +03:00
|
|
|
|
- `no-zero-unit` rule to disallow units when the value is zero.
|
2025-04-16 09:43:06 +03:00
|
|
|
|
- `no-unknown-unit` rule to disallow unknown units.
|
2025-04-19 20:41:17 +03:00
|
|
|
|
- Support for using the plugin’s recommended config via the extends field (as discussed in
|
|
|
|
|
|
[issue #3](https://github.com/antebudimir/eslint-plugin-vanilla-extract/issues/3))
|
2025-04-06 11:37:34 +03:00
|
|
|
|
- Comprehensive rule testing.
|
2025-03-04 20:16:50 +02:00
|
|
|
|
|
|
|
|
|
|
### Current Work
|
|
|
|
|
|
|
2025-04-19 20:41:17 +03:00
|
|
|
|
- `no-number-trailing-zero` rule to disallow trailing zeros in numbers.
|
2025-03-04 20:16:50 +02:00
|
|
|
|
|
|
|
|
|
|
### Upcoming Features
|
|
|
|
|
|
|
2025-03-08 23:05:23 +02:00
|
|
|
|
- `no-px-unit` rule to disallow use of `px` units with configurable whitelist.
|
2025-03-07 11:15:10 +02:00
|
|
|
|
- `prefer-logical-properties` rule to enforce use of logical properties.
|
|
|
|
|
|
- `prefer-theme-tokens` rule to enforce use of theme tokens instead of hard-coded values when available.
|
2025-03-08 23:05:23 +02:00
|
|
|
|
- `no-global-style` rule to disallow use of `globalStyle` function.
|
2025-04-19 20:41:17 +03:00
|
|
|
|
- `property-unit-match` rule to enforce valid units per CSS property specs. **Note**: This feature will only be
|
|
|
|
|
|
implemented if there's sufficient interest from the community.
|
|
|
|
|
|
- Option to sort properties within user-defined concentric groups alphabetically instead of following the concentric
|
|
|
|
|
|
order. **Note**: This feature will only be implemented if there's sufficient interest from the community.
|
2025-03-04 20:16:50 +02:00
|
|
|
|
|
|
|
|
|
|
## Contributing
|
|
|
|
|
|
|
|
|
|
|
|
All well-intentioned contributions are welcome, of course! Please feel free to submit a Pull Request or get in touch via
|
|
|
|
|
|
GitHub issues.
|
|
|
|
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
|
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|