@salty-css/vite 0.1.0-alpha.36 → 0.1.0-alpha.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +321 -551
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -1,458 +1,357 @@
1
1
  ![Salty CSS Banner](https://salty-css.dev/assets/banners/dvd.svg)
2
2
 
3
- # Salty CSS - CSS-in-JS library that is kinda sweet
3
+ # Salty CSS CSS-in-JS that compiles away
4
4
 
5
- Is there anything saltier than CSS in frontend web development? Salty CSS is built to provide better developer experience for developers looking for performant and feature rich CSS-in-JS solutions.
5
+ Salty CSS is a build-time, type-safe CSS-in-JS library. You author styles in `.css.ts` files; the compiler emits real CSS, your runtime ships zero styling logic.
6
6
 
7
- [Get started](#get-started) | [API](#api) | [Discord](https://discord.gg/R6kr4KxMhP) | [Website](https://salty-css.dev/) | [GitHub](https://github.com/margarita-form/salty-css) | [NPM](https://www.npmjs.com/package/@salty-css/core)
7
+ [Get started](#get-started) · [API index](#api-index) · [Docs](https://salty-css.dev/docs) · [Discord](https://discord.gg/R6kr4KxMhP) · [GitHub](https://github.com/margarita-form/salty-css) · [NPM](https://www.npmjs.com/package/@salty-css/core)
8
8
 
9
9
  ## Features
10
10
 
11
- - Build time compilation to achieve awesome runtime performance and minimal size
12
- - Next.js, React Server Components, Astro, Vite and Webpack support
13
- - Type safety with out of the box TypeScript and ESLint plugin
14
- - Advanced CSS variables configuration to allow smooth token usage
15
- - Style templates to create reusable styles easily
11
+ - **Build-time compilation** no runtime style injection, no FOUC, no client bundle cost.
12
+ - **Framework support** — Next.js (App + Pages, React Server Components, Webpack & Turbopack), React + Vite, React + Webpack, Astro.
13
+ - **Type safety** TypeScript-first authoring, generated token types, an [ESLint plugin](https://www.npmjs.com/package/@salty-css/eslint-plugin-core).
14
+ - **Design tokens & theming** static, responsive (media-bound), and conditional (data-attribute / class-bound) variables in one place.
15
+ - **Templates** reusable style bundles with their own variants.
16
+ - **Modifiers** — custom value transformers (`'space:3'` → `'12px'`) defined in config.
17
+ - **Variants, compound variants, anyOf variants, default variants** out of the box.
16
18
 
17
19
  ## Get started
18
20
 
19
- Fastest way to get started with any framework is
20
-
21
21
  ```bash
22
22
  npx salty-css init
23
23
  ```
24
24
 
25
- Other guides:
25
+ `init` detects your framework, installs the right packages, creates `salty.config.ts`, and wires the bundler plugin. Per-framework setup:
26
26
 
27
- - Next.js → [Next.js guide](#nextjs) + [Next.js example app](https://github.com/margarita-form/salty-css-website)
28
- - React + Vite → [React + Vite guide](#react--vite) + [React example code](#code-examples)
29
- - React + Webpack Guide coming soon
27
+ - **Next.js** → [salty-css.dev/docs/installation](https://salty-css.dev/docs/installation) `withSaltyCss(nextConfig)` in `next.config.ts`. Auto-detects Webpack vs Turbopack; React Server Components supported.
28
+ - **React + Vite** → [salty-css.dev/docs/installation](https://salty-css.dev/docs/installation) `saltyPlugin(__dirname)` in `vite.config.ts`.
29
+ - **Astro** [salty-css.dev/docs/installation](https://salty-css.dev/docs/installation) `saltyIntegration()` in `astro.config.mjs`.
30
30
 
31
- ## Useful commands
31
+ React + Webpack (without Next.js) is also supported via `@salty-css/webpack`.
32
32
 
33
- - Create component: `npx salty-css generate [filePath]`
34
- - Build: `npx salty-css build [directory]`
35
- - Update Salty CSS packages: `npx salty-css up`
33
+ ## CLI
36
34
 
37
- ## Good to know
35
+ | Command | Alias | What it does |
36
+ | ----------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------ |
37
+ | `npx salty-css init [directory]` | — | Detect framework, install packages, create `salty.config.ts`, wire the plugin. |
38
+ | `npx salty-css generate [filePath]` | `g` | Scaffold a new Salty component file. Flags: `--name`, `--className`, `--tag`. |
39
+ | `npx salty-css build [directory]` | `b` | Compile `*.css.ts` files into `saltygen/index.css`. Not needed when the bundler plugin is running. Flags: `--watch`, `--mode`. |
40
+ | `npx salty-css update [version]` | `up` | Update all `@salty-css/*` packages. Defaults to `latest`. Flags: `--dir`, `--yes`. |
41
+ | `npx salty-css --version` | — | Print CLI version. |
38
42
 
39
- 1. All Salty CSS functions (`styled`, `classNames`, `keyframes`, etc.) must be created in `*.css.ts` or `*.css.tsx` files. This is to ensure best build performance.
40
- 2. Salty CSS components created with styled function can extend non Salty CSS components (`export const CustomLink = styled(NextJSLink, { ... });`) but those components must take in `className` prop for styles to apply.
41
- 3. Among common types like `string` and `number`, CSS-in-JS properties in Salty CSS do support `functions` and `promises` as values (`styled('span', { base: { color: async () => 'red' } });`) but running asynchronous tasks or importing heavy 3rd party libraries into `*.css.ts` or `*.css.tsx` files can cause longer build times.
43
+ Full reference: [salty-css.dev/docs/cli](https://salty-css.dev/docs/cli).
42
44
 
43
- ## Get support
45
+ ## Good to know
44
46
 
45
- To get help with problems, [Join Salty CSS Discord server](https://discord.gg/R6kr4KxMhP).
47
+ 1. **File extensions matter.** `styled`, `className`, `keyframes`, and every `defineX(...)` call must live in a file ending `.css.ts`, `.css.tsx`, `.salty.ts`, `.styles.ts`, or `.styled.ts`. The compiler ignores everything else.
48
+ 2. **Extending non-Salty components is fine** — `styled(NextLink, { ... })` — as long as the wrapped component forwards `className` to a DOM element.
49
+ 3. **Async values & functions are allowed** (`base: { color: async () => 'red' }`), but heavy imports inside `*.css.ts` slow the build.
50
+ 4. **React Server Components are supported** via `@salty-css/next` — no `'use client'` needed for styled output.
46
51
 
47
- ## API
52
+ ## ESLint
48
53
 
49
- ### Component styling
54
+ Salty CSS ships a small ESLint plugin and matching shareable config. Two rules, both `error` by default, both autofixable, both scoped to Salty files (`.css.ts`, `.css.tsx`, `.salty.ts`, `.styles.ts`, `.styled.ts`):
50
55
 
51
- - [styled](#styled-function) (react only) - create React components that can be used anywhere easily
52
- - [className](#class-name-function) (framework agnostic) - create a CSS class string that can be applied to any element
56
+ - **`@salty-css/core/must-be-exported`** every `styled`, `className`, `keyframes`, and `defineX*` call must be exported; the compiler ignores anything else.
57
+ - **`@salty-css/core/no-variants-in-base`** `variants` must be a sibling of `base`, not nested inside it.
53
58
 
54
- ### Global styling
59
+ ```bash
60
+ npm i -D @salty-css/eslint-plugin-core @salty-css/eslint-config-core
61
+ ```
55
62
 
56
- - [defineGlobalStyles](#global-styles) - set global styles like `html` and `body`
57
- - [defineVariables](#variables) - create CSS variables (tokens) that can be used in any styling function
58
- - [defineMediaQuery](#media-queries) - create CSS media queries and use them in any styling function
59
- - [defineTemplates](#templates) - create reusable templates that can be applied when same styles are used over and over again
60
- - [defineFont](#custom-fonts) - register custom fonts via `@font-face` (or a remote stylesheet) and expose them as a CSS variable
61
- - [defineImport](#importing-additional-css) - pull in external CSS files (relative, public, node_modules, or URL)
62
- - [keyframes](#keyframes-animations) - create CSS keyframes animation that can be used and imported in any styling function
63
+ **Flat config (ESLint 9+):**
63
64
 
64
- ### Styling helpers & utility
65
+ ```js
66
+ // eslint.config.mjs
67
+ import saltyConfig from '@salty-css/eslint-config-core/flat';
65
68
 
66
- - [defineViewportClamp](#viewport-clamp) - create CSS clamp functions that are based on user's viewport and can calculate relative values easily
67
- - [color](#color-function) - transform any valid color code or variable to be darker, lighter etc. easily (uses [color library by Qix-](https://github.com/Qix-/color))
69
+ export default [saltyConfig];
70
+ ```
68
71
 
69
- ### Salty CSS CLI
72
+ **Legacy (`.eslintrc`):**
70
73
 
71
- In your existing repository you can use `npx salty-css [command]` to initialize a project, generate components, update related packages and build required files.
74
+ ```js
75
+ module.exports = { extends: ['@salty-css/eslint-config-core'] };
76
+ ```
72
77
 
73
- - Initialize project `npx salty-css init [directory]` - Installs required packages, detects framework in use and creates project files to the provided directory. Directory can be left blank if you want files to be created to the current directory.
74
- - Generate component → `npx salty-css update [version]` - Update @salty-css packages in your repository. Default version is "latest". Additional options like `--dir`, `--tag`, `--name` and `--className` are also supported.
75
- - Build files → `npx salty-css build [directory/filename]` - Compile Salty CSS related files in your project. This should not be needed if you are using tools like Next.js or Vite
78
+ Full reference[salty-css.dev/docs/eslint](https://salty-css.dev/docs/eslint).
79
+
80
+ ## API index
81
+
82
+ | Symbol | Import | One-liner | Docs |
83
+ | ----------------------------------------------- | ------------------------------ | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
84
+ | [`styled`](#styled) | `@salty-css/react/styled` | React component factory with variants & extension. | [api/styled](https://salty-css.dev/docs/api/styled) |
85
+ | [`className`](#classname) | `@salty-css/react/class-name` | CSS class string with `.variant()` chaining. | [api/classname](https://salty-css.dev/docs/api/classname) |
86
+ | [Variants](#variants) | — | `variants`, `compoundVariants`, `anyOfVariants`, `defaultVariants` semantics. | [variants](https://salty-css.dev/docs/variants) |
87
+ | [Overrides](#overrides) | — | Extend components, swap element, override per-instance via `style`. | [overrides](https://salty-css.dev/docs/overrides) |
88
+ | [ESLint plugin](#eslint) | `@salty-css/eslint-config-core` | Two rules: enforce `export` and correct `variants` placement on Salty files. | [eslint](https://salty-css.dev/docs/eslint) |
89
+ | [`defineConfig`](#defineconfig) | `@salty-css/core/config` | Top-level project config. | [api/config](https://salty-css.dev/docs/api/config) |
90
+ | [`defineVariables`](#definevariables) | `@salty-css/core/factories` | Static, responsive, and conditional CSS variables (tokens). | [variables](https://salty-css.dev/docs/variables) |
91
+ | [Theming](#theming) | — | `data-theme` switcher built on conditional variables. | [theming](https://salty-css.dev/docs/theming) |
92
+ | [`defineGlobalStyles`](#defineglobalstyles) | `@salty-css/core/factories` | Global rules (`html`, `body`, etc.). | [api/define-factories](https://salty-css.dev/docs/api/define-factories) |
93
+ | [`defineMediaQuery`](#definemediaquery) | `@salty-css/core/factories` | Named, reusable media queries. | [media-queries](https://salty-css.dev/docs/media-queries) |
94
+ | [`defineTemplates`](#definetemplates) | `@salty-css/core/factories` | Reusable style bundles, optionally with variants. | [templates](https://salty-css.dev/docs/templates) |
95
+ | [`defineFont`](#definefont) | `@salty-css/core/factories` | `@font-face` (or `@import`) + CSS variable in one. | [fonts](https://salty-css.dev/docs/fonts) |
96
+ | [`defineImport`](#defineimport) | `@salty-css/core/factories` | Pull external CSS into Salty's `imports` layer. | [imports](https://salty-css.dev/docs/imports) |
97
+ | [`keyframes`](#keyframes) | `@salty-css/react/keyframes` | Typed `@keyframes` with params and initial-state injection. | [animations](https://salty-css.dev/docs/animations) |
98
+ | [`defineViewportClamp`](#defineviewportclamp) | `@salty-css/core/helpers` | Fluid `clamp()` values that scale with the viewport. | [viewport-clamp](https://salty-css.dev/docs/viewport-clamp) |
99
+ | [`color`](#color) | `@salty-css/core/helpers` | Color manipulation (`alpha`, `darken`, …). | [color-function](https://salty-css.dev/docs/color-function) |
100
+ | [Modifiers](#modifiers) | (on `defineConfig`) | Custom value transformers, e.g. `'space:3'` → `'12px'`. | [modifiers](https://salty-css.dev/docs/modifiers) |
101
+ | [`withSaltyCss`](#withsaltycss-nextjs) | `@salty-css/next` | Next.js config wrapper (Webpack + Turbopack). | [installation](https://salty-css.dev/docs/installation) |
102
+ | [`saltyPlugin` (Vite)](#saltyplugin-vite) | `@salty-css/vite` | Vite plugin. | [installation](https://salty-css.dev/docs/installation) |
103
+ | [`saltyPlugin` (Webpack)](#saltyplugin-webpack) | `@salty-css/webpack` | Webpack loader + plugin. | [installation](https://salty-css.dev/docs/installation) |
104
+ | [`saltyIntegration`](#saltyintegration-astro) | `@salty-css/astro/integration` | Astro integration. | [installation](https://salty-css.dev/docs/installation) |
76
105
 
77
- ## Styled function
106
+ ---
78
107
 
79
- Styled function is the main way to use Salty CSS within React. Styled function creates a React component that then can be used anywhere in your app. All styled functions must be created in `.css.ts` or `.css.tsx` files
108
+ ## `styled`
80
109
 
81
110
  ```ts
82
- // /components/my-component.css.ts
111
+ // components/button.css.ts
83
112
  import { styled } from '@salty-css/react/styled';
84
113
 
85
- // Define a component with a styled function. First argument is the component name or existing component to extend and second argument is the object containing the styles and other options
86
- export const Component = styled('div', {
87
- className: 'wrapper', // Define optional custom class name that will be included for this component
88
- element: 'section', // Override the html element that will be rendered for this component
114
+ export const Button = styled('button', {
115
+ className: 'btn', // optional custom class
116
+ element: 'button', // optional element override
89
117
  base: {
90
- // 👉 Add your CSS-in-JS base styles here! 👈
118
+ padding: '0.6em 1.2em',
119
+ border: '1px solid currentColor',
120
+ '&:hover': { background: 'black', color: 'white' },
91
121
  },
92
122
  variants: {
93
- // Define conditional styles that will be applied to the component based on the variant prop values
123
+ variant: {
124
+ outlined: {},
125
+ solid: { background: 'black', color: 'white' },
126
+ },
94
127
  },
95
128
  compoundVariants: [
96
- // Define conditional styles that will be applied to the component based on the combination of variant prop values
129
+ /* { variant: 'solid', size: 'lg', css: { ... } } */
97
130
  ],
98
- defaultVariants: {
99
- // Set default variant prop values
100
- },
101
- defaultProps: {
102
- // Add additional default props for the component (eg, id and other html element attributes)
103
- },
104
- passProps: true, // Pass variant props to the rendered element / parent component (default: false)
105
- priority: 1, // Override automatic priotity layer with a custom value (0-8), higher is considered more important
131
+ defaultVariants: { variant: 'outlined' },
132
+ defaultProps: { type: 'button' },
133
+ passProps: false, // pass variant props through to the rendered element
134
+ priority: undefined, // 0–8, higher wins; usually leave to auto
106
135
  });
107
136
  ```
108
137
 
109
- Example usage:
110
-
111
138
  ```tsx
112
- import { Component } from './my-component.css';
113
-
114
- export const Page = () => {
115
- return <Component>Hello world</Component>;
116
- };
139
+ <Button variant="solid">Save</Button>
117
140
  ```
118
141
 
119
- ## Class name function
142
+ See full reference → [salty-css.dev/docs/api/styled](https://salty-css.dev/docs/api/styled).
120
143
 
121
- Create CSS class names with possibility to add scope and media queries etc. Function `className` is quite similar to `styled` but does not allow extending components or classes.
144
+ ## `className`
145
+
146
+ Framework-agnostic class-string factory. The return value is a `string` you can drop in `className=`, plus a `.variant(name, value)` method for chaining variant classes.
122
147
 
123
148
  ```ts
124
- // /components/my-class.css.ts
149
+ // components/card.css.ts
125
150
  import { className } from '@salty-css/react/class-name';
126
151
 
127
- // Define a CSS class with className function. First and only argument is the object containing the styles and other options
128
- export const myClass = className({
129
- className: 'wrapper', // Define optional custom class name that will be included to the scope
152
+ export const card = className({
153
+ className: 'card',
130
154
  base: {
131
- // 👉 Add your CSS-in-JS base styles here! 👈
155
+ padding: '1rem',
156
+ borderRadius: '8px',
157
+ },
158
+ variants: {
159
+ tone: {
160
+ neutral: { background: '#f6f6f6' },
161
+ brand: { background: '{colors.brand.main}' },
162
+ },
132
163
  },
133
164
  });
134
165
  ```
135
166
 
136
- Example usage:
137
-
138
167
  ```tsx
139
- import { myClass } from './my-class.css';
168
+ <div className={`${card.variant('tone', 'brand')}`}>Hello</div>
169
+ ```
140
170
 
141
- export const Page = () => {
142
- return <div className={myClass}>Hello world</div>;
143
- };
171
+ See full reference [salty-css.dev/docs/api/classname](https://salty-css.dev/docs/api/classname).
172
+
173
+ ## Variants
174
+
175
+ `styled` and `className` share the same variant shape:
176
+
177
+ - **`variants`** — named axes (e.g. `size: { sm, md, lg }`). Each axis becomes a prop.
178
+ - **`compoundVariants`** — array; styles applied only when **all** listed axes match.
179
+ - **`anyOfVariants`** — array; styles applied when **any** listed axis matches.
180
+ - **`defaultVariants`** — values used when the prop is omitted at the call site.
181
+
182
+ ```ts
183
+ styled('a', {
184
+ base: { textDecoration: 'none' },
185
+ variants: {
186
+ size: { sm: { fontSize: 14 }, lg: { fontSize: 18 } },
187
+ underline: { true: { textDecoration: 'underline' } },
188
+ },
189
+ compoundVariants: [{ size: 'lg', underline: true, css: { textUnderlineOffset: 4 } }],
190
+ defaultVariants: { size: 'sm' },
191
+ });
144
192
  ```
145
193
 
146
- ## Global styles
194
+ Boolean variants accept `true`/`false` keys; pass them as `<Link underline />` shorthand. See [salty-css.dev/docs/variants](https://salty-css.dev/docs/variants).
195
+
196
+ ## Overrides
197
+
198
+ - **Extend any component:** `styled(ExistingComponent, { ... })`. The wrapped component must accept `className`.
199
+ - **Swap the rendered element** for one instance: `<Button as="a" href="/x" />` (use `passProps` if you want variant props to reach the underlying element).
200
+ - **Per-instance style overrides:** `<Box style={{ ... }} />` and `<Box css={{ ... }} />` accept regular React `style` and Salty's `css` prop (overrides apply at the highest priority).
201
+
202
+ See [salty-css.dev/docs/overrides](https://salty-css.dev/docs/overrides) for `as`, `style`, CSS-variable overrides, and ref forwarding.
203
+
204
+ ## `defineConfig`
147
205
 
148
206
  ```ts
149
- // /styles/global.css.ts
150
- import { defineGlobalStyles } from '@salty-css/core/factories';
207
+ // salty.config.ts
208
+ import { defineConfig } from '@salty-css/core/config';
151
209
 
152
- export default defineGlobalStyles({
153
- html: {
154
- fontFamily: 'Arial, sans-serif',
210
+ export const config = defineConfig({
211
+ importStrategy: 'root', // 'root' | 'component'
212
+ variables: {
213
+ /* see defineVariables */
214
+ },
215
+ global: {
216
+ /* see defineGlobalStyles */
217
+ },
218
+ templates: {
219
+ /* see defineTemplates */
155
220
  },
156
- body: {
157
- backgroundColor: '#fff',
158
- margin: 0,
221
+ modifiers: {
222
+ /* see Modifiers */
159
223
  },
160
- // Add more global styles as needed
224
+ reset: 'default', // 'default' | 'none' | GlobalStyles
225
+ externalModules: ['react', 'react-dom'],
226
+ strict: true, // true | 'warn' | false
227
+ defaultUnit: 'px', // px, rem, em, vh, vw, % …
161
228
  });
162
229
  ```
163
230
 
164
- ## Variables
231
+ Full reference → [salty-css.dev/docs/api/config](https://salty-css.dev/docs/api/config).
232
+
233
+ ## `defineVariables`
234
+
235
+ Tokens come in three flavours — static, responsive (media-bound), conditional (class/data-attribute-bound):
165
236
 
166
237
  ```ts
167
- // /styles/variables.css.ts
238
+ // styles/variables.css.ts
168
239
  import { defineVariables } from '@salty-css/core/factories';
169
240
 
170
241
  export default defineVariables({
171
- /*
172
- Define static variable token (like colors, font sizes, etc.). and use them in your styles (e.g. color: '{colors.brand.highlight}').
173
- Variables can be nested (colors.brand.main) and can reference other variables.
174
- */
175
242
  colors: {
176
243
  dark: '#111',
177
244
  light: '#fefefe',
178
- brand: {
179
- main: '#0070f3',
180
- highlight: '#ff4081',
181
- },
182
- },
183
- fontFamily: {
184
- heading: 'Arial, sans-serif',
185
- body: 'Georgia, serif',
245
+ brand: { main: '#0070f3', highlight: '#ff4081' },
186
246
  },
187
-
188
- /*
189
- Define variables that are responsive to a media query (defined in media.css.ts) asn use them in your styles as normal (e.g. font-size: '{fontSize.heading.regular}').
190
- These variables will be automatically updated when the media query is matched. Base values are used when no media query is matched.
191
- */
192
247
  responsive: {
193
- base: {
194
- fontSize: {
195
- heading: {
196
- small: '32px',
197
- regular: '48px',
198
- large: '64px',
199
- },
200
- body: {
201
- small: '16px',
202
- regular: '20px',
203
- large: '24px',
204
- },
205
- },
206
- },
207
- '@largeMobileDown': {
208
- fontSize: {
209
- heading: {
210
- small: '20px',
211
- regular: '32px',
212
- large: '48px',
213
- },
214
- body: {
215
- small: '14px',
216
- regular: '16px',
217
- large: '20px',
218
- },
219
- },
220
- },
248
+ base: { fontSize: { heading: '48px', body: '16px' } },
249
+ '@largeMobileDown': { fontSize: { heading: '32px', body: '14px' } },
221
250
  },
222
-
223
- /*
224
- Conditional variables are used to define styles that depend on a class name (e.g. <div className="theme-dark">). or data-attribute (e.g. <div data-theme="dark">). Names for these variables will be "{theme.backgroundColor}" and "{theme.textColor}".
225
- */
226
251
  conditional: {
227
252
  theme: {
228
- dark: {
229
- backgroundColor: '{colors.dark}',
230
- textColor: '{colors.light}',
231
- },
232
- light: {
233
- backgroundColor: '{colors.light}',
234
- textColor: '{colors.dark}',
235
- },
253
+ dark: { backgroundColor: '{colors.dark}', textColor: '{colors.light}' },
254
+ light: { backgroundColor: '{colors.light}', textColor: '{colors.dark}' },
236
255
  },
237
256
  },
238
257
  });
239
258
  ```
240
259
 
241
- Example usage:
260
+ Use as string references: `{colors.brand.main}`, `{fontSize.heading}`, `{theme.textColor}`.
242
261
 
243
- ```ts
244
- styled('span', {
245
- base: {
246
- // Use of static font family variable
247
- fontFamily: '{fontFamily.heading}',
248
- // Use of responsive font size variable
249
- fontSize: '{fontSize.heading.regular}',
250
- // Use of conditional theme text color variable
251
- color: '{theme.textColor}',
252
- },
253
- });
254
- ```
262
+ See [salty-css.dev/docs/variables](https://salty-css.dev/docs/variables).
255
263
 
256
- ## Media queries
264
+ ## Theming
257
265
 
258
- Create global media queries that can be either used directly as a scope (e.g. `'@MEDIA_QUERY_NAME': { color: 'blue' }`) or imported to be used in JS.
266
+ The `conditional` bucket above wires up data-attribute / class-based themes with zero providers. Toggle a `data-theme` attribute on `<html>` (or any ancestor) and conditional variables resolve to the matching branch:
259
267
 
260
- ```ts
261
- // /styles/media.css.ts
262
- import { defineMediaQuery } from '@salty-css/react/config';
263
-
264
- export const largePortraitUp = defineMediaQuery((media) => media.minWidth(600));
265
- export const largeMobileDown = defineMediaQuery((media) => media.maxWidth(600));
268
+ ```html
269
+ <html data-theme="dark">
270
+ <!-- '{theme.textColor}' resolves to '{colors.light}' -->
271
+ </html>
266
272
  ```
267
273
 
268
- Example usage:
274
+ See the dark-mode walkthrough (with SSR flash fix) → [salty-css.dev/docs/theming](https://salty-css.dev/docs/theming).
275
+
276
+ ## `defineGlobalStyles`
269
277
 
270
278
  ```ts
271
- styled('span', { base: { fontSize: '64px', '@largeMobileDown': { fontSize: '32px' } } });
272
- ```
279
+ // styles/global.css.ts
280
+ import { defineGlobalStyles } from '@salty-css/core/factories';
273
281
 
274
- ## Templates
282
+ export default defineGlobalStyles({
283
+ html: { fontFamily: 'Inter, system-ui, sans-serif' },
284
+ body: { margin: 0, background: '#fff' },
285
+ });
286
+ ```
275
287
 
276
- With templates you can create reusable styles that can be used in any styles function. Templates can be static (all values defined in the template) or functions (parameters can be passed to define values). Templates can be used in styles by using template's name (e.g. textStyle) as property name and for static a key as the value for functions any supported parameter value can be used as the value.
288
+ ## `defineMediaQuery`
277
289
 
278
290
  ```ts
279
- // /styles/templates.css.ts
280
- import { defineTemplates } from '@salty-css/core/factories';
291
+ // styles/media.css.ts
292
+ import { defineMediaQuery } from '@salty-css/core/factories';
281
293
 
282
- export default defineTemplates({
283
- // Static templates for text styles.
284
- textStyle: {
285
- headline: {
286
- small: {
287
- fontSize: '{fontSize.heading.small}',
288
- },
289
- regular: {
290
- fontSize: '{fontSize.heading.regular}',
291
- },
292
- large: {
293
- fontSize: '{fontSize.heading.large}',
294
- },
295
- },
296
- body: {
297
- small: {
298
- fontSize: '{fontSize.body.small}',
299
- lineHeight: '1.5em',
300
- },
301
- regular: {
302
- fontSize: '{fontSize.body.regular}',
303
- lineHeight: '1.33em',
304
- },
305
- },
306
- },
307
- // Dynamic function templates for card styles.
308
- card: (value: string) => {
309
- return {
310
- padding: value,
311
- borderRadius: '8px',
312
- boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
313
- };
314
- },
315
- });
294
+ export const largeMobileDown = defineMediaQuery((media) => media.maxWidth(600));
295
+ export const darkMode = defineMediaQuery((media) => media.prefersColorScheme('dark'));
316
296
  ```
317
297
 
318
- Example usage:
319
-
320
298
  ```ts
321
- styled('div', { base: { textStyle: 'headline.large', card: '20px' } });
299
+ styled('span', { base: { fontSize: 64, '@largeMobileDown': { fontSize: 32 } } });
322
300
  ```
323
301
 
324
- ### Template variants
302
+ See [salty-css.dev/docs/media-queries](https://salty-css.dev/docs/media-queries).
303
+
304
+ ## `defineTemplates`
325
305
 
326
- Static templates can opt into named variants by switching a node from a plain styles object to a "rich" shape with `base` and `variants` keys — the same authoring API as `styled`. Variants declared at a parent node are inherited by every descendant leaf, so one declaration of `weight` on `heading` flows down to `heading.large`, `heading.small`, etc.
306
+ Reusable style bundles. Static templates pick values by dot-path; function templates take a parameter.
327
307
 
328
308
  ```ts
329
- // /styles/templates.css.ts
309
+ // styles/templates.css.ts
330
310
  import { defineTemplates } from '@salty-css/core/factories';
331
311
 
332
312
  export default defineTemplates({
333
313
  textStyle: {
334
314
  heading: {
335
- // Rich node: variants declared here are available to every child leaf.
336
- base: {
337
- fontFamily: '{fontFamily.heading}',
338
- lineHeight: '1.1em',
339
- },
315
+ base: { fontFamily: '{fontFamily.heading}', lineHeight: 1.1 },
340
316
  variants: {
341
- weight: {
342
- light: { fontWeight: 300 },
343
- regular: { fontWeight: 500 },
344
- heavy: { fontWeight: 800 },
345
- },
346
- italic: {
347
- true: { fontStyle: 'italic' },
348
- },
317
+ weight: { regular: { fontWeight: 500 }, heavy: { fontWeight: 800 } },
349
318
  },
350
- defaultVariants: {
351
- weight: 'regular',
352
- },
353
- compoundVariants: [
354
- // Applied when ALL listed axes match.
355
- { weight: 'heavy', italic: true, css: { letterSpacing: '-0.01em' } },
356
- ],
357
- // Leaves can be plain styles…
319
+ large: { fontSize: '{fontSize.heading.large}' },
358
320
  small: { fontSize: '{fontSize.heading.small}' },
359
- regular: { fontSize: '{fontSize.heading.regular}' },
360
- // …or rich, with their own additional variants / overrides.
361
- large: {
362
- base: { fontSize: '{fontSize.heading.large}' },
363
- variants: {
364
- weight: {
365
- // Override the inherited bundle just for `large`.
366
- heavy: { fontWeight: 900, letterSpacing: '-0.02em' },
367
- },
368
- },
369
- },
370
321
  },
371
322
  },
323
+ card: (padding: string) => ({
324
+ padding,
325
+ borderRadius: 8,
326
+ boxShadow: '0 0 10px rgba(0,0,0,0.1)',
327
+ }),
372
328
  });
373
329
  ```
374
330
 
375
- Apply variants at the call site in either of two equivalent forms — string query or object:
376
-
377
331
  ```ts
378
- styled('h1', {
379
- base: {
380
- // String form: `path@axis=value&axis=value&boolFlag`
381
- textStyle: 'heading.large@weight=heavy&italic',
382
- },
383
- });
384
-
385
- styled('h2', {
386
- base: {
387
- // Object form: `name` is the dot-path, the rest are axis values.
388
- textStyle: { name: 'heading.large', weight: 'heavy', italic: true },
389
- },
390
- });
391
-
392
- // No variants — existing simple usage still works.
393
- styled('p', { base: { textStyle: 'heading.regular' } });
332
+ styled('h1', { base: { textStyle: 'heading.large@weight=heavy', card: '20px' } });
394
333
  ```
395
334
 
396
- Behaviour worth knowing:
397
-
398
- - **Inheritance is parent → leaf only.** A leaf sees variants from its ancestors; siblings and children are invisible.
399
- - **Closest wins.** If the same axis/value bundle is declared at multiple levels, the deepest one replaces (not merges) the ancestor's bundle for that single call.
400
- - **`defaultVariants` apply when the call site omits an axis.** Walked bottom-up, same closest-wins rule.
401
- - **`compoundVariants` (AND) and `anyOfVariants` (OR) are accumulated top-down** across the path — every matching rule contributes.
402
- - **Boolean axes accept a shorthand.** `@italic` is equivalent to `@italic=true`; in object form pass `italic: true`.
403
- - **Reserved keys** inside a rich node: `base`, `variants`, `defaultVariants`, `compoundVariants`, `anyOfVariants`. Don't use `name` as an axis (reserved for the object call-site form).
404
- - **Function templates** (e.g. `card: (v) => ({ … })`) don't support variants — keep them as plain functions.
405
-
406
- ## Custom fonts
407
-
408
- Register custom fonts that will be emitted as `@font-face` declarations and exposed as a CSS variable. Mirrors the developer experience of Next.js / Astro font loaders, but generated at build time alongside the rest of your Salty CSS output.
409
-
410
- The returned object stringifies to its `font-family` value and exposes helpers for explicit usage:
335
+ Rich-node variants, inheritance, and the `compoundVariants`/`anyOfVariants` rules: [salty-css.dev/docs/templates](https://salty-css.dev/docs/templates).
411
336
 
412
- - `Font.variable` → CSS variable name (e.g. `--font-inter`)
413
- - `Font.fontFamily` → final `font-family` string with fallbacks
414
- - `Font.className` → class that sets the variable + applies the font on a subtree
415
- - `Font.style` → object you can spread on a React `style` prop
337
+ ## `defineFont`
416
338
 
417
339
  ```ts
418
- // /styles/fonts.css.ts
340
+ // styles/fonts.css.ts
419
341
  import { defineFont } from '@salty-css/core/factories';
420
342
 
421
- // 1. Local or self-hosted @font-face sources.
422
- // URLs are passed through as-is (use a public-folder path or a CDN URL).
423
343
  export const Inter = defineFont({
424
- name: 'Inter', // CSS font-family value
425
- variable: '--font-inter', // Optional — accepts 'font-inter' too; if omitted we derive `--font-<name>-<hash>` from the inputs
426
- display: 'swap', // Optional default applied to variants without their own `display`
427
- fallback: ['system-ui', 'sans-serif'], // Optional family fallbacks appended after `name`
344
+ name: 'Inter',
345
+ variable: '--font-inter',
346
+ display: 'swap',
347
+ fallback: 'system-ui, sans-serif',
428
348
  variants: [
429
- {
430
- weight: 400,
431
- style: 'normal',
432
- // Shorthand: pass a string and the `format()` descriptor is auto-detected
433
- // from the file extension (woff2, woff, ttf, otf, eot, svg, ttc).
434
- src: '/fonts/inter-400.woff2',
435
- },
436
- {
437
- weight: 700,
438
- style: 'normal',
439
- // Multiple sources can be a string array — first entry is preferred;
440
- // the browser picks the first format it supports.
441
- src: ['/fonts/inter-700.woff2', '/fonts/inter-700.ttf'],
442
- },
443
- {
444
- weight: 400,
445
- style: 'italic',
446
- // Use the `{ url, format }` object form when the URL has no recognisable
447
- // extension (signed CDN URLs, query-only endpoints, etc.). You can also
448
- // mix strings and objects in the same array.
449
- src: ['/fonts/inter-400-italic.woff2', { url: 'https://cdn.example.com/inter-italic', format: 'woff' }],
450
- },
349
+ { weight: 400, style: 'normal', src: '/fonts/inter-400.woff2' },
350
+ { weight: 700, style: 'normal', src: ['/fonts/inter-700.woff2', '/fonts/inter-700.ttf'] },
451
351
  ],
452
352
  });
453
353
 
454
- // 2. Remote stylesheet (Google Fonts, etc.). Emits `@import url(...)` and still
455
- // registers the CSS variable so usage stays the same as the @font-face flow.
354
+ // Or pull a remote stylesheet (e.g. Google Fonts) emits @import + variable.
456
355
  export const InterCdn = defineFont({
457
356
  name: 'Inter',
458
357
  variable: '--font-inter',
@@ -460,306 +359,177 @@ export const InterCdn = defineFont({
460
359
  });
461
360
  ```
462
361
 
463
- Example usage:
464
-
465
- ```tsx
466
- import { Inter } from './fonts.css';
467
- import { styled } from '@salty-css/react/styled';
468
-
469
- // Apply the font globally by attaching its className high up in the tree.
470
- // This sets `--font-inter` on the subtree and applies `font-family: var(--font-inter)`.
471
- export const App = ({ children }) => <div className={Inter.className}>{children}</div>;
472
-
473
- // `Inter` stringifies to its font-family value (with fallbacks), so it can be used directly.
474
- export const Heading = styled('h1', {
475
- base: {
476
- fontFamily: `${Inter}`,
477
- },
478
- });
479
-
480
- // Or reference the CSS variable explicitly.
481
- export const Body = styled('p', {
482
- base: {
483
- fontFamily: `var(${Inter.variable})`,
484
- },
485
- });
486
- ```
362
+ `Inter.className`, `Inter.variable`, `Inter.fontFamily`, and `Inter.style` are available for explicit usage. See [salty-css.dev/docs/fonts](https://salty-css.dev/docs/fonts).
487
363
 
488
- ## Importing additional CSS
364
+ ## `defineImport`
489
365
 
490
- Use `defineImport` to pull in CSS that lives outside of Salty's authoring API — a reset stylesheet from npm, a Google Fonts URL, an asset in your app's `public/` folder, or a sibling `.css` file. The compiler turns each spec into an `@import` rule in the generated `saltygen/index.css`, so the imported stylesheets travel with the rest of your build.
366
+ Pull external CSS into Salty's `imports` cascade layer (which sits **before** `reset`, `global`, `templates`, and your component layers so your styles always win).
491
367
 
492
368
  ```ts
493
- // /styles/imports.css.ts
369
+ // styles/imports.css.ts
494
370
  import { defineImport } from '@salty-css/core/factories';
495
371
 
496
372
  export default defineImport(
497
- // Relative to this file
498
- './reset.css',
499
- // From node_modules (bare specifier — same as Vite / native CSS @import)
500
- 'modern-normalize/modern-normalize.css',
501
- // From node_modules (~ prefix — same resolver, webpack-style)
502
- '~normalize.css/normalize.css',
503
- // From your app's public/ folder (served at the host root)
504
- '/fonts/inter.css',
505
- // External URL
506
- 'https://fonts.googleapis.com/css2?family=Inter&display=swap',
507
- // Object form — attach media or supports() conditions
508
- { url: './print.css', media: 'print' },
509
- { url: './p3.css', supports: 'color(display-p3 1 1 1)' }
373
+ './reset.css', // relative
374
+ 'modern-normalize/modern-normalize.css', // node_modules
375
+ '~normalize.css/normalize.css', // node_modules (~ form)
376
+ '/fonts/inter.css', // public/ folder
377
+ 'https://fonts.googleapis.com/css2?family=Inter', // URL
378
+ { url: './print.css', media: 'print' }, // media-conditional
379
+ { url: './p3.css', supports: 'color(display-p3 1 1 1)' } // supports-conditional
510
380
  );
511
381
  ```
512
382
 
513
- Path resolution:
514
-
515
- | Pattern | Behaviour |
516
- | --------------------------- | ---------------------------------------------------------------------------------------- |
517
- | `http://`, `https://`, `//` | Emitted verbatim |
518
- | Starts with `/` | Public-folder URL — emitted verbatim, the browser resolves it against your host |
519
- | Starts with `./` or `../` | Resolved at build time relative to the file that called `defineImport` |
520
- | `~package/file.css` | Stripped of the leading `~`, then resolved from `node_modules` and copied into the build |
521
- | `package/file.css` (bare) | Same `node_modules` resolution as the `~` form |
522
-
523
- All imports are placed inside a new `imports` cascade layer that sits **before** `reset`, `global`, `templates`, and your component styles. This means your own styles always win over third-party CSS you pull in — which is what most teams expect when they drop in something like `modern-normalize`.
383
+ Layer order: `@layer imports, reset, global, templates, fonts, l0…l8;`. See [salty-css.dev/docs/imports](https://salty-css.dev/docs/imports).
524
384
 
525
- The full layer order in the generated `index.css` is:
526
-
527
- ```css
528
- @layer imports, reset, global, templates, l0, l1, l2, l3, l4, l5, l6, l7, l8;
529
- ```
530
-
531
- ## Keyframes animations
385
+ ## `keyframes`
532
386
 
533
387
  ```ts
534
- // /styles/animations.css.ts
388
+ // styles/animations.css.ts
535
389
  import { keyframes } from '@salty-css/react/keyframes';
536
390
 
537
391
  export const fadeIn = keyframes({
538
- // Name of the animation in final CSS
539
392
  animationName: 'fadeIn',
540
- // Add `from` or `0%` to the component's css making it the initial state.
541
- appendInitialStyles: true,
542
- // CSS animation default params used with the value
543
- params: {
544
- delay: '250ms',
545
- fillMode: 'forwards',
546
- },
547
- // Rest is animation timeline
548
- from: {
549
- opacity: 0,
550
- },
551
- to: {
552
- opacity: 1,
553
- },
393
+ appendInitialStyles: true, // injects `from`/`0%` as base styles on the component
394
+ params: { delay: '250ms', fillMode: 'forwards' },
395
+ from: { opacity: 0 },
396
+ to: { opacity: 1 },
554
397
  });
555
398
  ```
556
399
 
557
- Example usage:
558
-
559
400
  ```ts
560
- import { fadeIn } from 'path-to-animations.css.ts';
561
-
562
- export const Wrapper = styled('div', { base: { animation: fadeIn } });
401
+ styled('div', { base: { animation: fadeIn } });
563
402
  ```
564
403
 
565
- ## Viewport clamp
404
+ See [salty-css.dev/docs/animations](https://salty-css.dev/docs/animations).
566
405
 
567
- Create a CSS clamp function based on screen sizes. Useful when aiming to create font sizes or spacings that scale with the screen.
406
+ ## `defineViewportClamp`
568
407
 
569
408
  ```ts
570
- // /styles/clamp.css.ts
571
- import { defineViewportClamp } from '@salty-css/react/helpers';
409
+ // styles/clamp.css.ts
410
+ import { defineViewportClamp } from '@salty-css/core/helpers';
572
411
 
573
412
  export const fhdClamp = defineViewportClamp({ screenSize: 1920 });
574
- export const mobileClamp = defineViewportClamp({ screenSize: 640 });
413
+ export const mobileClamp = defineViewportClamp({ screenSize: 640, axis: 'horizontal' });
575
414
  ```
576
415
 
577
- Example usage:
578
-
579
416
  ```ts
580
417
  styled('span', { base: { fontSize: fhdClamp(96), '@largeMobileDown': { fontSize: mobileClamp(48) } } });
581
418
  ```
582
419
 
583
- ## Color function
584
-
585
- Modify any color easily, add opacity, darken...
420
+ Options: `screenSize`, `axis` (`'horizontal' | 'vertical'`), `minMultiplier`, `maxMultiplier`, `minMaxUnit`. See [salty-css.dev/docs/viewport-clamp](https://salty-css.dev/docs/viewport-clamp).
586
421
 
587
- Example usage:
422
+ ## `color`
588
423
 
589
424
  ```ts
590
425
  import { color } from '@salty-css/core/helpers';
426
+ import { styled } from '@salty-css/react/styled';
591
427
 
592
- export const Wrapper = styled('span', { base: { backgroundColor: color('#000').alpha(0.5) } });
428
+ export const Tint = styled('span', {
429
+ base: { backgroundColor: color('#000').alpha(0.5) },
430
+ });
593
431
  ```
594
432
 
595
- ## Usage
596
-
597
- ### Next.js
598
-
599
- ![salty-next](https://github.com/user-attachments/assets/2cf6a93f-cdd5-4f5f-ab2e-3bc8bcfb83e8)
600
-
601
- Salty CSS provides Next.js App & Pages router support with full React Server Components support.
602
-
603
- ### Add Salty CSS to Next.js
604
-
605
- 1. In your existing Next.js repository you can run `npx salty-css init` to automatically configure Salty CSS.
606
- 2. Create your first Salty CSS component with `npx salty-css generate [filePath]` (e.g. src/custom-wrapper)
607
- 3. Import your component for example to `page.tsx` and see it working!
608
-
609
- And note: steps 2 & 3 are just to show how get new components up and running, step 1 does all of the important stuff 🤯
610
-
611
- #### Manual configuration
433
+ Backed by the [Qix-/color](https://github.com/Qix-/color) library — `.alpha()`, `.darken()`, `.lighten()`, `.mix()`, etc. See [salty-css.dev/docs/color-function](https://salty-css.dev/docs/color-function).
612
434
 
613
- 1. For Next.js support install `npm i @salty-css/next @salty-css/core @salty-css/react`
614
- 2. Create `salty.config.ts` to your app directory
615
- 3. Add Salty CSS plugin to next.js config
435
+ ## Modifiers
616
436
 
617
- - **Next.js 15:** In `next.config.ts` add import for salty plugin `import { withSaltyCss } from '@salty-css/next';` and then add `withSaltyCss` to wrap your nextConfig export like so `export default withSaltyCss(nextConfig);`
618
- - **Next.js 14 and older:** In `next.config.js` add import for salty plugin `const { withSaltyCss } = require('@salty-css/next');` and then add `withSaltyCss` to wrap your nextConfig export like so `module.exports = withSaltyCss(nextConfig);`
437
+ Custom value transformers registered on `defineConfig`. Each modifier is a `{ pattern, transform }` pair: when Salty sees a string value matching `pattern`, it replaces it with `transform(match).value` (and optionally emits extra CSS via `transform(match).css`).
619
438
 
620
- Both Webpack and Turbopack are supported. `withSaltyCss` auto-detects which bundler Next.js is using (`next dev --turbopack` sets `process.env.TURBOPACK=1`), so no extra config is required. To force a specific bundler, pass `{ bundler: 'webpack' | 'turbopack' }` as the second argument.
621
-
622
- 4. Make sure that `salty.config.ts` and `next.config.ts` are in the same folder!
623
- 5. Build `saltygen` directory by running your app once or with cli `npx salty-css build [directory]`
624
- 6. Import global styles from `saltygen/index.css` to some global css file with `@import 'insert_path_to_index_css';`.
625
-
626
- [Check out Next.js demo project](https://github.com/margarita-form/salty-css-website) or [react example code](#code-examples)
627
-
628
- ---
629
-
630
- ### React + Vite
631
-
632
- ![salty-vite-react](https://github.com/user-attachments/assets/12ec5b6a-0dcc-48fa-afc1-d337fc8f800c)
633
-
634
- ### Add Salty CSS to your React + Vite app
635
-
636
- 1. In your existing Vite repository you can run `npx salty-css init` to automatically configure Salty CSS.
637
- 2. Create your first Salty CSS component with `npx salty-css generate [filePath]` (e.g. src/custom-wrapper)
638
- 3. Import your component for example to `main.tsx` and see it working!
639
-
640
- And note: steps 2 & 3 are just to show how get new components up and running, step 1 does all of the important stuff 🤯
641
-
642
- ### Test it out
439
+ ```ts
440
+ // salty.config.ts
441
+ import { defineConfig } from '@salty-css/core/config';
643
442
 
644
- Check out React + Vite + Salty CSS demo repository at https://github.com/margarita-form/salty-css-react-vite-demo or view it in CodeSandbox:
443
+ export const config = defineConfig({
444
+ modifiers: {
445
+ spaceShorthand: {
446
+ pattern: /^space:(\d+)$/,
447
+ transform: (match) => {
448
+ const n = Number(match.replace('space:', ''));
449
+ return { value: `${n * 4}px` };
450
+ },
451
+ },
452
+ },
453
+ });
454
+ ```
645
455
 
646
- [![Edit margarita-form/salty-css-react-vite-demo/main](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/github/margarita-form/salty-css-react-vite-demo/main?import=true&embed=1)
456
+ ```ts
457
+ styled('div', { base: { padding: 'space:3' } }); // → padding: 12px
458
+ ```
647
459
 
648
- ### Manual configuration
460
+ See [salty-css.dev/docs/modifiers](https://salty-css.dev/docs/modifiers).
649
461
 
650
- 1. For Vite support install `npm i @salty-css/vite @salty-css/core`
651
- 2. In `vite.config` add import for salty plugin `import { saltyPlugin } from '@salty-css/vite';` and then add `saltyPlugin(__dirname)` to your vite configuration plugins
652
- 3. Make sure that `salty.config.ts` and `vite.config.ts` are in the same folder!
653
- 4. Build `saltygen` directory by running your app once or with cli `npx salty-css build [directory]`
654
- 5. Import global styles from `saltygen/index.css` to some global css file with `@import 'insert_path_to_index_css';`.
462
+ ## `withSaltyCss` (Next.js)
655
463
 
656
- [Check out react example code](#code-examples)
464
+ ```ts
465
+ // next.config.ts
466
+ import { withSaltyCss } from '@salty-css/next';
657
467
 
658
- ---
468
+ const nextConfig = {
469
+ /* your config */
470
+ };
471
+ export default withSaltyCss(nextConfig);
472
+ // Or pin a bundler: withSaltyCss(nextConfig, { bundler: 'webpack' })
473
+ ```
659
474
 
660
- ### Create components
475
+ Options: `mode` (build mode override), `bundler` (`'auto' | 'webpack' | 'turbopack'`, defaults to auto-detect via `process.env.TURBOPACK`), `dir` (project root for Turbopack — defaults to `nextConfig.turbopack.root` or `process.cwd()`).
661
476
 
662
- 1. Create salty components with styled only inside files that end with `.css.ts`, `.salty.ts` `.styled.ts` or `.styles.ts`
477
+ Next.js 14 CommonJS:
663
478
 
664
- ## Code examples
479
+ ```js
480
+ const { withSaltyCss } = require('@salty-css/next');
481
+ module.exports = withSaltyCss(nextConfig);
482
+ ```
665
483
 
666
- ### Basic usage example with Button
484
+ See [salty-css.dev/docs/installation](https://salty-css.dev/docs/installation).
667
485
 
668
- **Salty config**
486
+ ## `saltyPlugin` (Vite)
669
487
 
670
- ```tsx
671
- import { defineConfig } from '@salty-css/core/config';
488
+ ```ts
489
+ // vite.config.ts
490
+ import { defineConfig } from 'vite';
491
+ import { saltyPlugin } from '@salty-css/vite';
672
492
 
673
- export const config = defineConfig({
674
- variables: {
675
- colors: {
676
- brand: '#111',
677
- highlight: 'yellow',
678
- },
679
- },
680
- global: {
681
- html: {
682
- backgroundColor: '#f8f8f8',
683
- },
684
- },
493
+ export default defineConfig({
494
+ plugins: [saltyPlugin(__dirname)],
685
495
  });
686
496
  ```
687
497
 
688
- **Wrapper** (`components/wrapper/wrapper.css.ts`)
498
+ Options: `{ mode }`.
689
499
 
690
- ```tsx
691
- import { styled } from '@salty-css/react/styled';
500
+ ## `saltyPlugin` (Webpack)
692
501
 
693
- export const Wrapper = styled('div', {
694
- base: {
695
- display: 'block',
696
- padding: '2vw',
697
- },
698
- });
502
+ ```js
503
+ // webpack.config.js
504
+ const { saltyPlugin } = require('@salty-css/webpack');
505
+
506
+ module.exports = (env, argv) => {
507
+ const config = {
508
+ /* … */
509
+ };
510
+ saltyPlugin(config, __dirname);
511
+ return config;
512
+ };
699
513
  ```
700
514
 
701
- **Button** (`components/button/button.css.ts`)
515
+ Signature: `saltyPlugin(config, dir, isServer?, cjs?, { mode? })`.
702
516
 
703
- ```tsx
704
- import { styled } from '@salty-css/react/styled';
517
+ ## `saltyIntegration` (Astro)
705
518
 
706
- export const Button = styled('button', {
707
- base: {
708
- display: 'block',
709
- padding: `0.6em 1.2em`,
710
- border: '1px solid currentColor',
711
- background: 'transparent',
712
- color: 'currentColor',
713
- cursor: 'pointer',
714
- transition: '200ms',
715
- textDecoration: 'none',
716
- '&:hover': {
717
- background: 'black',
718
- borderColor: 'black',
719
- color: 'white',
720
- },
721
- '&:disabled': {
722
- opacity: 0.25,
723
- pointerEvents: 'none',
724
- },
725
- },
726
- variants: {
727
- variant: {
728
- outlined: {
729
- // same as default styles
730
- },
731
- solid: {
732
- '&:not(:hover)': {
733
- background: 'black',
734
- borderColor: 'black',
735
- color: 'white',
736
- },
737
- '&:hover': {
738
- background: 'transparent',
739
- borderColor: 'currentColor',
740
- color: 'currentColor',
741
- },
742
- },
743
- },
744
- },
519
+ ```ts
520
+ // astro.config.mjs
521
+ import { defineConfig } from 'astro/config';
522
+ import saltyIntegration from '@salty-css/astro/integration';
523
+
524
+ export default defineConfig({
525
+ integrations: [saltyIntegration()],
745
526
  });
746
527
  ```
747
528
 
748
- **Your React component file**
529
+ Options: `srcDir` (defaults to `'src'`), `rootDir` (defaults to the Astro config root).
749
530
 
750
- ```tsx
751
- import { Wrapper } from '../components/wrapper/wrapper.css';
752
- import { Button } from '../components/button/button.css';
753
-
754
- export const IndexPage = () => {
755
- return (
756
- <Wrapper>
757
- <Button variant="solid" onClick={() => alert('It is a button.')}>
758
- Outlined
759
- </Button>
760
- </Wrapper>
761
- );
762
- };
763
- ```
531
+ ---
532
+
533
+ ## Support
764
534
 
765
- More examples coming soon
535
+ Help, questions, or feedback → [Join the Salty CSS Discord](https://discord.gg/R6kr4KxMhP). Bug reports → [GitHub issues](https://github.com/margarita-form/salty-css/issues).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salty-css/vite",
3
- "version": "0.1.0-alpha.36",
3
+ "version": "0.1.0-alpha.37",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "typings": "./dist/index.d.ts",
@@ -34,11 +34,11 @@
34
34
  }
35
35
  },
36
36
  "dependencies": {
37
- "@salty-css/core": "0.1.0-alpha.36",
37
+ "@salty-css/core": "0.1.0-alpha.37",
38
38
  "vite": "^6.4.1"
39
39
  },
40
40
  "peerDependencies": {
41
- "@salty-css/react": "0.1.0-alpha.36"
41
+ "@salty-css/react": "0.1.0-alpha.37"
42
42
  },
43
43
  "peerDependenciesMeta": {
44
44
  "@salty-css/react": {