Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
139 commits
Select commit Hold shift + click to select a range
9b4abd2
wip
ryanatkn Jan 7, 2026
73b6f72
wip
ryanatkn Jan 7, 2026
fc67e19
wip
ryanatkn Jan 7, 2026
95a7988
wip
ryanatkn Jan 7, 2026
f4d51f2
wip
ryanatkn Jan 7, 2026
b9b10c6
wip
ryanatkn Jan 7, 2026
9b38dbc
wip
ryanatkn Jan 7, 2026
e86095b
wip
ryanatkn Jan 7, 2026
40024e4
wip
ryanatkn Jan 7, 2026
1057f8d
wip
ryanatkn Jan 7, 2026
4b6e511
wip
ryanatkn Jan 7, 2026
9f23206
wip
ryanatkn Jan 8, 2026
49e3e3d
wip
ryanatkn Jan 8, 2026
2053e35
wip
ryanatkn Jan 8, 2026
0444dc5
wip
ryanatkn Jan 8, 2026
eb535dc
wip
ryanatkn Jan 8, 2026
c892ae1
wip
ryanatkn Jan 9, 2026
c6819bc
wip
ryanatkn Jan 9, 2026
31b64f4
wip
ryanatkn Jan 9, 2026
8204ccc
wip
ryanatkn Jan 10, 2026
2f78568
wip
ryanatkn Jan 10, 2026
c4fbc10
wip
ryanatkn Jan 10, 2026
48ffaf1
wip
ryanatkn Jan 10, 2026
0c420b5
wip
ryanatkn Jan 10, 2026
1a71c7c
wip
ryanatkn Jan 10, 2026
980454b
wip
ryanatkn Jan 10, 2026
a896b66
wip
ryanatkn Jan 10, 2026
6419521
wip
ryanatkn Jan 10, 2026
97894a4
wip
ryanatkn Jan 10, 2026
29d14e4
wip
ryanatkn Jan 10, 2026
341b327
wip
ryanatkn Jan 11, 2026
cb87983
wip
ryanatkn Jan 11, 2026
1c252d6
wip
ryanatkn Jan 11, 2026
7b787e6
wip
ryanatkn Jan 11, 2026
1816167
wip
ryanatkn Jan 11, 2026
4d9043b
wip
ryanatkn Jan 11, 2026
a5ecec9
wip
ryanatkn Jan 11, 2026
6cf44c5
wip
ryanatkn Jan 11, 2026
cb5d026
wip
ryanatkn Jan 11, 2026
4d84f7c
wip
ryanatkn Jan 11, 2026
f54017a
wip
ryanatkn Jan 11, 2026
5258449
wip
ryanatkn Jan 11, 2026
34f9d6b
wip
ryanatkn Jan 11, 2026
2010177
wip
ryanatkn Jan 11, 2026
5134a8e
wip
ryanatkn Jan 11, 2026
3bab96b
wip
ryanatkn Jan 11, 2026
5d841ce
wip
ryanatkn Jan 11, 2026
22e7db1
wip
ryanatkn Jan 11, 2026
ee73a34
wip
ryanatkn Jan 12, 2026
00c85b1
wip
ryanatkn Jan 12, 2026
329a2e9
wip
ryanatkn Jan 12, 2026
1ebfd01
wip
ryanatkn Jan 12, 2026
df411d9
wip
ryanatkn Jan 12, 2026
73ab8c5
wip
ryanatkn Jan 12, 2026
c5b09d5
wip
ryanatkn Jan 12, 2026
e4389f9
wip
ryanatkn Jan 12, 2026
c914774
wip
ryanatkn Jan 12, 2026
20cd205
wip
ryanatkn Jan 12, 2026
44b2247
Merge branch 'main' into css-literals
ryanatkn Jan 12, 2026
8518e67
wip
ryanatkn Jan 12, 2026
6519b1e
wip
ryanatkn Jan 12, 2026
31bb8c8
wip
ryanatkn Jan 12, 2026
5388883
wip
ryanatkn Jan 12, 2026
239f06d
wip
ryanatkn Jan 13, 2026
f51e53e
wip
ryanatkn Jan 13, 2026
23dcba2
wip
ryanatkn Jan 13, 2026
bc3f53d
wip
ryanatkn Jan 13, 2026
2f77457
wip
ryanatkn Jan 13, 2026
f6dd199
wip
ryanatkn Jan 13, 2026
3e9b88a
wip
ryanatkn Jan 13, 2026
010056e
wip
ryanatkn Jan 13, 2026
3070510
wip
ryanatkn Jan 13, 2026
d9b0882
wip
ryanatkn Jan 14, 2026
c906c10
wip
ryanatkn Jan 14, 2026
04eb30c
wip
ryanatkn Jan 14, 2026
d617c1b
wip
ryanatkn Jan 14, 2026
c5994b2
wip
ryanatkn Jan 14, 2026
79281eb
wip
ryanatkn Jan 14, 2026
cd858c0
wip
ryanatkn Jan 14, 2026
56e60ad
wip
ryanatkn Jan 14, 2026
288bedc
wip
ryanatkn Jan 14, 2026
72c4805
wip
ryanatkn Jan 15, 2026
472d2a1
wip
ryanatkn Jan 15, 2026
a324c2e
wip
ryanatkn Jan 15, 2026
351b244
wip
ryanatkn Jan 15, 2026
67840f2
wip
ryanatkn Jan 15, 2026
8ea6343
wip
ryanatkn Jan 15, 2026
5b482dc
wip
ryanatkn Jan 15, 2026
472d881
wip
ryanatkn Jan 15, 2026
a9631bd
wip
ryanatkn Jan 15, 2026
2e693a1
wip
ryanatkn Jan 15, 2026
70b1f88
wip
ryanatkn Jan 15, 2026
92ef593
wip
ryanatkn Jan 15, 2026
867ee74
wip
ryanatkn Jan 16, 2026
645df52
wip
ryanatkn Jan 16, 2026
e95a133
wip
ryanatkn Jan 16, 2026
9f39e75
wip
ryanatkn Jan 16, 2026
05b1672
wip
ryanatkn Jan 16, 2026
8b13372
wip
ryanatkn Jan 17, 2026
8d16ba4
wip
ryanatkn Jan 17, 2026
d09476b
wip
ryanatkn Jan 17, 2026
316d0f2
wip
ryanatkn Jan 18, 2026
ce1fc62
wip
ryanatkn Jan 18, 2026
371043f
wip
ryanatkn Jan 18, 2026
30715e4
wip
ryanatkn Jan 18, 2026
ab0f393
wip
ryanatkn Jan 18, 2026
6c977f6
wip
ryanatkn Jan 18, 2026
d219995
wip
ryanatkn Jan 18, 2026
097066a
wip
ryanatkn Jan 18, 2026
487920e
wip
ryanatkn Jan 18, 2026
abdc0a2
wip
ryanatkn Jan 18, 2026
da6fb93
wip
ryanatkn Jan 18, 2026
36c912e
wip
ryanatkn Jan 18, 2026
360e5c7
wip
ryanatkn Jan 19, 2026
c89a6d2
wip
ryanatkn Jan 19, 2026
e41273b
wip
ryanatkn Jan 19, 2026
8039c45
wip
ryanatkn Jan 19, 2026
b35d577
wip
ryanatkn Jan 19, 2026
a15c7c7
wip
ryanatkn Jan 19, 2026
88b9c85
wip
ryanatkn Jan 19, 2026
1b834e0
wip
ryanatkn Jan 19, 2026
42dc913
wip
ryanatkn Jan 19, 2026
afd2264
wip
ryanatkn Jan 19, 2026
da89d16
wip
ryanatkn Jan 19, 2026
f55e800
wip
ryanatkn Jan 19, 2026
5f18fbc
wip
ryanatkn Jan 19, 2026
00ec416
wip
ryanatkn Jan 20, 2026
a40ea78
wip
ryanatkn Jan 20, 2026
25608b3
wip
ryanatkn Jan 20, 2026
5c4f3a6
wip
ryanatkn Jan 20, 2026
9a02830
wip
ryanatkn Jan 20, 2026
521e356
wip
ryanatkn Jan 20, 2026
8d58181
wip
ryanatkn Jan 20, 2026
558e18c
wip
ryanatkn Jan 20, 2026
e40cf87
wip
ryanatkn Jan 20, 2026
6aac1e6
wip
ryanatkn Jan 20, 2026
459172f
wip
ryanatkn Jan 20, 2026
e8accc9
wip
ryanatkn Jan 20, 2026
c496a5b
wip
ryanatkn Jan 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/empty-knives-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fuzdev/fuz_css': minor
---

implement CSS literal classes
17 changes: 9 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
# Deps
node_modules
node_modules/

# Output
/.svelte-kit
/build
/dist
/dist_*
/target
/.gro
/.zzz
.svelte-kit/
build/
dist/
dist_*/
target/
.gro/
.fuz/
.zzz/

# Env
.env*
Expand Down
148 changes: 135 additions & 13 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
# Fuz CSS framework and design system
# fuz_css framework and design system

CSS framework and design system built around **semantic styles** and **style variables** (design tokens as CSS custom properties). Early alpha with breaking changes ahead.
CSS framework and design system for semantic HTML.
It styles HTML elements by default and integrates
custom properties, themes, and utility classes into a complete system.
Early alpha with breaking changes ahead.

For code style, see the `fuz-stack` skill. For UI components (themes, color scheme controls), see `@fuzdev/fuz_ui`.

## Gro commands

```bash
gro check # typecheck, test, lint, format check (run before committing)
gro typecheck # typecheck only (faster iteration)
gro test # run tests (SKIP_EXAMPLE_TESTS=1 to skip slow integration tests)
gro gen # regenerate theme.css and other .gen files
gro build # build the package for production
```

## Design decisions

### Two core concepts
Expand All @@ -26,7 +39,56 @@ For code style, see the `fuz-stack` skill. For UI components (themes, color sche

### Smart utility class generation

[gen_fuz_css.ts](src/lib/gen_fuz_css.ts) scans source files with regex extractors, collects class names, and outputs only CSS for classes actually used. Dynamic [interpreters](src/lib/css_class_interpreters.ts) handle pattern-based classes like `opacity_50`, `font_weight_700`, `z_index_100`.
Two generators available, both using AST-based extraction ([css_class_extractor.ts](src/lib/css_class_extractor.ts)) and per-file caching with content hash validation:

1. **Gro generator** - [gen_fuz_css.ts](src/lib/gen_fuz_css.ts) for SvelteKit projects using Gro
2. **Vite plugin** - [vite_plugin_fuz_css.ts](src/lib/vite_plugin_fuz_css.ts) for Svelte/React/Preact/Solid via `virtual:fuz.css`

Both output only CSS for classes actually used. Supports Svelte 5.16+ class syntax, JSX `className`, clsx/cn calls, and `// @fuz-classes` comment hints.

**Shared options (both generators):**

- `filter_file` - Which files to extract from (default: `.svelte`, `.html`, `.ts`, `.js`, `.tsx`, `.jsx`, excluding tests/gen files)
- `class_definitions` - Additional definitions to merge with builtins (user takes precedence)
- `class_interpreters` - Custom interpreters (replaces builtins if provided)
- `include_classes` - Classes to always include (for dynamic class names)
- `exclude_classes` - Classes to exclude (filter false positives)
- `acorn_plugins` - Additional acorn plugins (use `acorn-jsx` for React/Preact/Solid)
- `on_error` - `'log'` (default) or `'throw'` for CSS-literal errors
- `cache_dir` - Cache directory (default: `.fuz/cache/css`)

**Gro-only options:**

- `include_stats` - Include file statistics in output
- `project_root` - Project root directory (default: `process.cwd()`)
- `concurrency` - Max concurrent file processing (default: 8)
- `cache_io_concurrency` - Max concurrent cache I/O (default: 50)

**Key implementation differences:**

- **HMR**: Vite plugin has HMR with 10ms debouncing; Gro regenerates on file change
- **Cache writes**: Vite uses fire-and-forget; Gro awaits with concurrency control
- **External files**: Both use hashed paths in `_external/` subdirectory for files outside project root (e.g., symlinked deps with pnpm)
- **Error types**: Both throw `CssGenerationError` with `diagnostics` property for programmatic error access
- **CI behavior**: Both skip cache writes on CI

### Three class types

- **Token classes** - Map to style variables: `p_md`, `color_a_5`, `gap_lg`
- **Composite classes** - Multi-property shortcuts: `box`, `row`, `ellipsis`
- **Literal classes** - CSS `property:value` syntax: `display:flex`, `opacity:50%`

All class types support modifiers: responsive (`md:`), state (`hover:`), color-scheme (`dark:`), pseudo-element (`before:`).

### CSS-literal syntax

Literal classes use `property:value` syntax that maps 1:1 to CSS:

- `display:flex` → `display: flex;`
- `hover:opacity:80%` → `:hover { opacity: 80%; }`
- `md:dark:hover:opacity:80%` → nested media/ancestor/state wrappers

Space encoding uses `~` for multi-value properties (`margin:0~auto`). Arbitrary breakpoints via `min-width(800px):` and `max-width(600px):`.

## Variable naming

Expand All @@ -44,11 +106,30 @@ See [variables.ts](src/lib/variables.ts) for definitions, [variable_data.ts](src

## Usage

Import [style.css](src/lib/style.css) + [theme.css](src/lib/theme.css) for base styles. Optionally generate project-specific `fuz.css` using [gen_fuz_css()](src/lib/gen_fuz_css.ts) in a Gro generator.
Import [style.css](src/lib/style.css) + [theme.css](src/lib/theme.css) for base styles. Generate utility classes via:

**SvelteKit (Gro):** Use [gen_fuz_css()](src/lib/gen_fuz_css.ts) in a `.gen.css.ts` file.

**Vite (Svelte/React/Preact/Solid):**

```ts
// vite.config.ts
import {vite_plugin_fuz_css} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js';
import jsx from 'acorn-jsx'; // only needed for JSX frameworks

export default defineConfig({
plugins: [vite_plugin_fuz_css({acorn_plugins: [jsx()]})],
});

// main.ts
import '@fuzdev/fuz_css/style.css';
import '@fuzdev/fuz_css/theme.css'; // or bring your own
import 'virtual:fuz.css';
```

## Docs

[src/routes/docs/](src/routes/docs/) has pages for: colors, themes, variables, classes, typography, buttons, forms, elements, layout, borders, shadows, shading. See [tomes.ts](src/routes/docs/tomes.ts) for structure.
[src/routes/docs/](src/routes/docs/) has pages for: introduction, api, examples, semantic, themes, variables, classes, colors, buttons, elements, forms, typography, borders, shading, shadows, layout. See [tomes.ts](src/routes/docs/tomes.ts) for structure.

## File organization

Expand All @@ -58,18 +139,35 @@ Import [style.css](src/lib/style.css) + [theme.css](src/lib/theme.css) for base

- [variables.ts](src/lib/variables.ts) - All style variable definitions (~250+)
- [variable.ts](src/lib/variable.ts) - `StyleVariable` type and validation
- [variable_data.ts](src/lib/variable_data.ts) - Size variants, color intensities, CSS data values
- [variable_data.ts](src/lib/variable_data.ts) - Size, color, and border variant definitions
- [theme.ts](src/lib/theme.ts) - Theme rendering, `ColorScheme` type, `render_theme_style()`
- [themes.ts](src/lib/themes.ts) - Theme definitions (base, low/high contrast)

**CSS extraction:**

- [css_class_extractor.ts](src/lib/css_class_extractor.ts) - AST-based class extraction from Svelte/TS/JSX files
- [file_filter.ts](src/lib/file_filter.ts) - `FileFilter` type and `filter_file_default` for filtering extractable files
- [diagnostics.ts](src/lib/diagnostics.ts) - `SourceLocation`, `ExtractionDiagnostic`, `GenerationDiagnostic` types

**CSS generation:**

- [gen_fuz_css.ts](src/lib/gen_fuz_css.ts) - Main generator API for Gro
- [css_classes.ts](src/lib/css_classes.ts) - All static class definitions (~1000+)
- [css_class_generators.ts](src/lib/css_class_generators.ts) - Class template generation functions
- [css_class_composites.ts](src/lib/css_class_composites.ts) - Composite classes (`.box`, `.row`, `.column`, `.ellipsis`)
- [css_class_interpreters.ts](src/lib/css_class_interpreters.ts) - Dynamic interpreters for opacity, font-weight, z-index, border-radius
- [css_class_helpers.ts](src/lib/css_class_helpers.ts) - CSS class extraction, `CssClasses` collection, `generate_classes_css()`
- [gen_fuz_css.ts](src/lib/gen_fuz_css.ts) - Gro generator API with per-file caching
- [vite_plugin_fuz_css.ts](src/lib/vite_plugin_fuz_css.ts) - Vite plugin for Svelte/React/Preact/Solid, `virtual:fuz.css` virtual module with HMR
- [css_cache.ts](src/lib/css_cache.ts) - Cache infrastructure (`.fuz/cache/css/`)
- [css_classes.ts](src/lib/css_classes.ts) - `CssClasses` collection for tracking classes per-file
- [css_class_generation.ts](src/lib/css_class_generation.ts) - `CssClassDefinition` types, `generate_classes_css()`
- [css_class_definitions.ts](src/lib/css_class_definitions.ts) - Combined token + composite class registry
- [css_class_generators.ts](src/lib/css_class_generators.ts) - Token class template generators
- [css_class_composites.ts](src/lib/css_class_composites.ts) - Composite classes (`.box`, `.row`, `.column`, `.ellipsis`, `.pane`, `.panel`)
- [css_class_resolution.ts](src/lib/css_class_resolution.ts) - `resolve_composes()` for composing definitions
- [css_class_interpreters.ts](src/lib/css_class_interpreters.ts) - `modified_class_interpreter` and `css_literal_interpreter`
- [css_literal.ts](src/lib/css_literal.ts) - CSS-literal parser and validator
- [css_ruleset_parser.ts](src/lib/css_ruleset_parser.ts) - CSS ruleset parsing, selector modification
- [modifiers.ts](src/lib/modifiers.ts) - Modifier definitions (breakpoints, states, pseudo-elements)

**Example utilities:**

- [example_class_utilities.ts](src/lib/example_class_utilities.ts) - Demo exports for testing node_modules extraction

**Stylesheets:**

Expand All @@ -83,7 +181,31 @@ Import [style.css](src/lib/style.css) + [theme.css](src/lib/theme.css) for base
- [fuz.css](src/routes/fuz.css) - Generated optimized utility classes for this site
- [fuz.gen.css.ts](src/routes/fuz.gen.css.ts) - Generator using `gen_fuz_css()`

### Examples - [examples/](examples/)

Vite plugin examples:

- [vite-svelte/](examples/vite-svelte/) - Svelte 5 example
- [vite-react/](examples/vite-react/) - React 19 example
- [vite-preact/](examples/vite-preact/) - Preact example
- [vite-solid/](examples/vite-solid/) - Solid example

Each demonstrates token, composite, and literal classes with responsive/hover/dark modifiers. Uses classes from [example_class_utilities.ts](src/lib/example_class_utilities.ts) to verify node_modules extraction.

**Important:** All 4 example App files must be kept in sync. When updating one, update all others with equivalent changes (accounting for framework differences like React's `className` vs others' `class`). The [vite_plugin_examples.test.ts](src/test/vite_plugin_examples.test.ts) verifies all examples produce the same CSS classes.

### Tests - [src/test/](src/test/)

- [variable.test.ts](src/test/variable.test.ts) - StyleVariable type validation
- [variables.test.ts](src/test/variables.test.ts) - Variable consistency (no duplicates, valid names)
- [css_class_helpers.test.ts](src/test/css_class_helpers.test.ts) - CSS extraction from Svelte/JS patterns
- [styles.test.ts](src/test/styles.test.ts) - Style output tests
- [css_classes.test.ts](src/test/css_classes.test.ts) - CssClasses collection tests
- [css_cache.test.ts](src/test/css_cache.test.ts) - Cache save/load, version invalidation, atomic writes
- [css_class_generation.test.ts](src/test/css_class_generation.test.ts) - CSS escaping, generation, interpreters
- [css_class_resolution.test.ts](src/test/css_class_resolution.test.ts) - Class resolution, cycle detection
- [css_class_extractor.test.ts](src/test/css_class_extractor.test.ts) - AST extraction, location tracking
- [css_class_extractor.jsx.test.ts](src/test/css_class_extractor.jsx.test.ts) - JSX-specific extraction
- [css_literal.test.ts](src/test/css_literal.test.ts) - CSS-literal parsing, validation, modifiers
- [css_ruleset_parser.test.ts](src/test/css_ruleset_parser.test.ts) - Ruleset parsing, selector modification
- [diagnostics.test.ts](src/test/diagnostics.test.ts) - Diagnostic formatting tests
- [vite_plugin_examples.test.ts](src/test/vite_plugin_examples.test.ts) - Integration tests building examples (skip with `SKIP_EXAMPLE_TESTS=1`)
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
# Fuz CSS
# fuz_css

[<img src="/static/logo.svg" alt="a fuzzy tuft of green moss" align="right" width="192" height="192">](https://css.fuz.dev/)

> CSS framework and design system 🌿 magical organic stylesheets
> CSS with more utility 🪴

fuz_css is a CSS framework and design system for semantic HTML.
It styles elements by default and
integrates custom properties, themes, and utility classes into a complete system.
It's Svelte-first but works with plain HTML/JS/TS, React, Preact, Solid, and other JSX frameworks.

Fuz CSS is a CSS framework and design system built around semantic styles and style variables.
It's in early alpha with breaking changes ahead.
Feedback and design input in
the [discussions](https://github.com/fuzdev/fuz_css/discussions).

- view the [docs](https://css.fuz.dev/docs) at [css.fuz.dev](https://css.fuz.dev/)
- help with feedback and design in the [issues](https://github.com/fuzdev/fuz_css/issues)
and [discussions](https://github.com/fuzdev/fuz_css/discussions)
- more about the stack at [fuz.dev](https://www.fuz.dev/)
View the [docs](https://css.fuz.dev/docs) at [css.fuz.dev](https://css.fuz.dev/).
More about the stack at [fuz.dev](https://www.fuz.dev/)

## License [🐦](https://wikipedia.org/wiki/Free_and_open-source_software)

Expand Down
3 changes: 2 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ import {configs, ts_config} from '@ryanatkn/eslint-config';

ts_config.rules['no-console'] = 1;

export default configs;
// Ignore examples directory - each example has its own tsconfig
export default [{ignores: ['examples/**']}, ...configs];
12 changes: 12 additions & 0 deletions examples/vite-preact/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>fuz_css + Preact</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading