## tscss (TypeScript-powered CSS utilities)

Write TypeScript functions in your CSS. Compose reusable directives that generate declarations, selectors, animations, and more at build time.

## Features

• ⚡ **Zero Runtime** — Compiles to CSS at build time via lightningcss. No client JavaScript added.
<br />
• 🖊️ **CSS Native** — Feels like writing plain CSS.
<br />
• 🎨 **Rich Helpers** — Built-in backgrounds, colors, math, transforms, borders, and layout helpers.
<br />
• 🔌 **Extensible** — Custom directives with `defineHelper`. Schema validation, aliases, and root-level CSS generation.
<br />
• 🏗️ **Vite Plugin** — Drop-in integration with HMR, `@import` inlining, and automatic directive loading.
<br />
• 🛡️ **Schema Validated** — Runtime argument validation with valibot. Clear error messages on misuse.
<br />
• 🏷️ **Custom Properties** — Emit `--var` declarations and `@property` rules automatically.

## Installation

```bash
bun add @subwaytime/tscss
# or
npm install @subwaytime/tscss
# or
pnpm add @subwaytime/tscss
# or
yarn add @subwaytime/tscss
```

## Quick Start

Add the plugin to your `vite.config.ts`:

```ts
import { defineConfig } from 'vite';
import { tscss } from '@subwaytime/tscss/vite';

export default defineConfig({
  plugins: [
    tscss(),
  ],
});
```

Now use tscss directives in your CSS:

```css
.test {
  @paper(50px);
  color: @mix(red, blue, 50);
  border-radius: @perfectBorder(inner, 1rem, 0.25rem);
}
```

The plugin automatically inlines `@import` statements, resolves custom directives, and provides HMR for directive files.

## Built-in Helpers

### Backgrounds

```css
.test {
  @paper(50px);           /* blueprint grid */
  @grid(20px);            /* line grid */
  @dotPattern(10px);      /* dot pattern */
  @checkerboard(20px);    /* checkerboard */
  @verticalLines(20px);   /* vertical stripes */
  @horizontalLines(20px); /* horizontal stripes */
}
```

### Colors

```css
.test {
  color: @mix(red, blue, 50);
  color: @lighten(#333, 20);
  color: @darken(#fff, 10);
  color: @opacity(red, 50);
  color: @complement(red);
  color: @black(#ff0000, 30);
  color: @white(#ff0000, 30);
  color: @tint(#333, 20);
  color: @saturate(red, 50);
  color: @grayscale(#ff0000);
}
```

### Math & Transforms

```css
.test {
  font-size: @pxToRem(16px);
  width: @lerp(0px, 100px, 0.5);
  margin: @negate(1rem);
  @ratio(100px, 200px);
  color: @toOklch(#ff0000);
  color: @toOklab(#ff0000);
  color: @toRgb(#ff0000);
  color: @toHsl(#ff0000);
  color: @toHwb(#ff0000);
}
```

### Borders & Layout

```css
.btn {
  @perfectBorder(inner, 1rem, 0.25rem);
}

.grid {
  @autoGrid(200px, 3);
}
```

## Directive Factories

### `cssVar` — Custom Properties

```ts
import { cssVar } from '@subwaytime/tscss/directives';

const primary = cssVar('primary');
// @primary(blue) → --primary: blue

const size = cssVar({
  name: 'size',
  transform: (v) => `calc(${v} / 16px * 1rem)`,
});
// @size(16px) → --size: calc(16px / 16px * 1rem)

const typedColor = cssVar({
  name: 'primary',
  typed: { syntax: '<color>', inherits: false, initialValue: 'blue' },
});
// @primary(red) → @property --primary { ... } + --primary: red
```

### `declaration` — Fixed Property

```ts
const bg = declaration('background', (args) =>
  `linear-gradient(${args[0]}, transparent)`
);
// .test { @bg(red); } → background: linear-gradient(red, transparent);
```

### `selector` — Selector Variants

```ts
const hover = selector(() => '&:hover');
// .btn { @hover() { color: red; } } → .btn:hover { color: red; }
```

### `media` — Responsive Queries

```ts
const mobile = media('(max-width: 768px)');
// @mobile { padding: 1rem; } → @media (max-width: 768px) { padding: 1rem; }
```

### `keyframes` — Animations

```ts
const fadeIn = keyframes('fadeIn', {
  '0%': { opacity: '0' },
  '100%': { opacity: '1' },
});
// animation: @fadeIn 0.3s ease → @keyframes fadeIn { ... }
```

### `fontFace` — Font Loading

```ts
const myFont = fontFace({ src: "url('/font.woff2')", family: 'MyFont' });
// @myFont → @font-face { ... } + font-family: MyFont;
```

## Custom Directives

```ts
import { defineHelper } from '@subwaytime/tscss/directives';

const hero = defineHelper({
  property: 'background',
  value: (args) => `linear-gradient(${args[0] || 'red'}, blue)`,
});
// .test { @hero; } → background: linear-gradient(red, blue);
```

Custom directives support schema validation, aliases, spawn for root-level CSS generation (e.g., `@keyframes`, `@font-face`), and `.value` composition.

### Bare Arguments

All helpers accept natural CSS syntax without quotes:

```css
.test {
  color: @mix(red, blue, 50);
  color: @mix('red', 'blue', '50');
  width: @lerp(0px, 100px, 0.5);
  background: @black(var(--origin), 30);
}
```

### Custom Directive Loading

Load custom directives from a directory:

```ts
import { defineConfig } from 'vite';
import { tscss } from '@subwaytime/tscss/vite';

export default defineConfig({
  plugins: [
    tscss({
      directives: './src/css-directives',
      include: /\.css$/,
      exclude: /node_modules/,
    }),
  ],
});
```

The plugin loads `.ts` and `.js` files from the specified directory and makes them available as directives in your CSS.

## Development

```bash
bun install

bun test

bun run bundle
```

## License

MIT © 2026-PRESENT [Leon Langer](https://github.com/subwaytime)
