Skip to content

feat: add compile-time raw color helpers - #18

Draft
e-simpson wants to merge 6 commits into
mgcrea:mainfrom
e-simpson:codex/raw-color-utilities
Draft

feat: add compile-time raw color helpers#18
e-simpson wants to merge 6 commits into
mgcrea:mainfrom
e-simpson:codex/raw-color-utilities

Conversation

@e-simpson

@e-simpson e-simpson commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds compile-time helpers for React Native APIs that need raw color strings rather than style objects:

const blue = twColor`blue-500`;
const tint = useTwColor("scheme:accent");
const colors = useTwColors({
  background: "scheme:background",
  text: "scheme:text",
  accent: "blue-500/[.37]",
});
  • twColor resolves one static module- or component-scope token with zero runtime work and rejects scheme:.
  • useTwColor() and useTwColors() resolve reactive scheme colors with the Babel plugin's configured custom or native theme hook.
  • Palette names, utility-form names, integer/arbitrary opacity, arbitrary hex, and outline colors share the parser's color grammar.
  • Calls compile to string literals and conditional expressions with no runtime Tailwind lookup.

Dependency / merge order

Please merge #14, then #15, then #18.

This draft is intentionally stacked on #14 and #15 so raw colors are already verified with arbitrary opacity and scheme:outline-*. Until those PRs land, GitHub shows their commits here; the base diff reduces after each dependency merges.

Static and reactive contracts

  • Static twColor accepts one interpolation-free token and rejects runtime scheme: with an error directing callers to useTwColor.
  • Reactive helpers require direct static calls inside function components.
  • Unknown tokens, dynamic expressions, module-scope hooks, and rebinding compile-only helpers fail during Babel transformation.
  • Scheme hooks are injected before React Compiler analysis.

Type checking

The Babel plugin validates tokens against the actual consumer Tailwind config. Since a package declaration cannot automatically infer another project's Babel-loaded config, the base TypeScript signature remains string.

Applications can retain config-derived autocomplete and typo checking without wrappers:

type ThemeColor = keyof typeof tailwindConfig.theme.extend.colors;
type SchemeThemeColor = `scheme:${ThemeColor}`;

const card = useTwColor("scheme:card" satisfies SchemeThemeColor);

The compiler now unwraps satisfies, as, and type-assertion expressions around direct literals before compiling them.

Validation

  • bun run spec — 1,096 passed, 1 skipped
  • bun run check
  • bun run lint
  • bun run format:check
  • bun run build
  • git diff --check

@e-simpson
e-simpson force-pushed the codex/raw-color-utilities branch from 4a03217 to 6ba04fb Compare July 28, 2026 18:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant