Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 26 additions & 0 deletions .changeset/precompiled-utilities-and-token-export.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
'@e412/rnui-themes': minor
'@e412/rnui-react': patch
---

Add a precompiled utility layer and a declared token export.

**Why:** rnui is normally consumed with Tailwind running in the consumer's build, so any class you write compiles on demand. But it is also consumed *precompiled* — as a single stylesheet embedded in a design tool or preview. In that mode a class Tailwind never emitted silently does nothing: no error, no warning, the element just renders unstyled. Ordinary layout markup (`gap-10`, `grid-cols-4`, `max-w-4xl`, `text-3xl`) hit this constantly.

**`@e412/rnui-themes/utilities`** — a precompiled stylesheet (~353 KB, ~40 KB gzip) covering complete scales rather than only the values rnui's own components happen to use:

- spacing `0`–`24` across `p m gap space-x space-y w h min-w min-h` and every axis/side variant
- `text-xs`–`text-9xl`, `font-thin`–`font-black`, `tracking-*`, `leading-*`
- `grid-cols-1..12`, `col-span-*`, `row-span-*`
- `max-w-xs`–`max-w-7xl`, `rounded-*`, `border-*`, `opacity-0..100`
- `sm: md: lg: xl:` responsive and `hover: focus: active: disabled: dark:` states on the interactive subset

Import it only if you cannot run Tailwind yourself; if you can, keep importing `@e412/rnui-themes` and let your build compile what you use.

**`@e412/rnui-themes/safelist`** — the safelist source, for adding these scales to your own Tailwind build.

**`dist/utilities.json`** — the classes that actually shipped, derived from the compiled output rather than the safelist source, so tooling can tell a consumer "`gap-9` is not in this bundle" instead of letting it fail silently.

**`dist/tokens.json`** — the declared public token surface: 399 tokens across every theme, each with its name, theme, `kind` (`color` | `dimension` | `font` | `radius`), value, and light/dark pair. Built from the hand-authored theme sources, never from compiled CSS, so Tailwind's internal custom properties are structurally excluded. This is now the source of truth for token extraction — do not scan the generated stylesheets. Tokens a theme's dark ramp omits are flagged `darkInherited` rather than silently presented as declared.

**`@e412/rnui-react`:** renamed the private custom properties `--cell-size` / `--cell-radius` (Calendar) and `--data-grid-fill-size` (DataGrid) to a `--rnui-_` prefix, so they are unambiguously internal and not mistaken for design tokens. These were never documented as customization points. `--sidebar-width` and `--sidebar-width-icon` are deliberately unchanged: they are set via a `style` prop on `SidebarProvider`, which is a supported override.
50 changes: 50 additions & 0 deletions .changeset/three-deliberate-themes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
'@e412/rnui-themes': major
---

**Breaking:** replaces the eight theme presets with three.

`amber`, `crimson`, `forest`, `ocean`, `oxide`, `rose`, `slate` and `violet` are removed, along with their subpath exports. They were one neutral shell with the accent hue swapped — over-saturated, muddy in dark mode, and named for color rather than for use. Eight mediocre options are worse than three deliberate ones.

| New slug | Character | Body / Headings | Radius |
| --- | --- | --- | --- |
| `press` | Editorial — warm paper, near-black ink, high contrast | Source Sans 3 / Source Serif 4 | `0.5rem` |
| `console` | Technical — dense, low-chroma, terminal-adjacent | Geist / Geist Mono | `0.125rem` |
| `signal` | Brand-forward — warm neutral shell, one confident accent | Instrument Sans / Space Grotesk | `0.75rem` |

### Migration

Every `[data-theme="…"]` value changes. Map by the intent behind the old choice, not by hue:

| Was | Use | Why |
| --- | --- | --- |
| `slate`, `oxide` | `press` | Editorial/professional, serif-or-substantial headings |
| `ocean`, `violet` | `console` | Cool, technical, restrained |
| `rose`, `amber`, `crimson` | `signal` | Warm shell carried by one confident accent |
| `forest` | `press` or `signal` | Depending on whether the serif pairing mattered |

```diff
- <html data-theme="ocean">
+ <html data-theme="console">
```

```diff
- @import '@e412/rnui-themes/ocean';
+ @import '@e412/rnui-themes/console';
```

If you were extending a preset, re-point the selector — the token names are unchanged, so overrides carry over as-is:

```diff
- [data-theme='ocean'] { --primary: oklch(0.48 0.15 220); }
+ [data-theme='console'] { --primary: oklch(0.48 0.15 220); }
```

### What else changed

- **Every theme now defines `--font-heading` and `--font-mono`.** Previously only two of the eight set a heading face; the rest silently fell back to the system stack, which made them look unfinished next to the ones that didn't.
- **Complete dark ramps.** Dark surfaces step monotonically by at least 4% lightness, so elevation reads as elevation instead of noise, and dark chroma never exceeds the light value for the same token — raising chroma to compensate for darkness is what produced the muddiness.
- **Accessibility is a floor, not a preset.** Every `*`/`*-foreground` pair clears WCAG AA in both modes (4.5:1 text, 3:1 borders and rings), verified in the build by `scripts/check-contrast.mjs`, which fails on a regression. There is no separate "high contrast" theme: `press` is the high-contrast option by character, and the floor applies to all three equally.
- **The default theme (no `data-theme`) also now meets that floor.** Its look is otherwise unchanged, but 17 tokens moved to clear AA — `text-warning` was 1.89:1 and `text-success` 2.45:1 against the page background.
- **One accent per theme.** `--primary`, `--focus`, `--ring` and `--sidebar-primary` derive from a single hue; `--accent` is a tint of it rather than a second color. Status colors (`--success`, `--info`, `--warning`, `--destructive`) keep the same hues across all three so they stay recognizable.
- Theme sources are generated from an anchor spec by `scripts/generate-themes.mjs`; edit the anchors there rather than the emitted CSS.
Loading