Files
zeekayandHanzo Dev 6370fee218 Converge on Hanzo 8.x: @hanzo/gui, no Tailwind, one compiler
The 8.x refactor happened upstream; this package was still pinned to the
102.0.0-rc line and importing the pre-rename `hanzogui`. Two of its barrels
exported names that no longer existed (`createHanzoguiConfig`,
`HanzoguiConfigOptions`) and `src/tg/index.ts` re-exported files that were not
in its directory, so `tsc` could not have passed on `main`.

Packages
  [email protected] → @hanzo/gui@^8.0.1, and the four @hanzogui/* peers to
  ^8.0.0. Dropped @hanzogui/config-default and @hanzogui/animations-react-native
  entirely: the config package was consulted for exactly three static maps
  (tokens.radius, tokens.zIndex, media) and dragged react-native into a web
  theming package to get them. Those maps now live beside the size and space
  scales they belong with, in src/gui/defaults/. Verified against @hanzo/gui
  8.0.1 that the produced config is unchanged — radius $4 = 9, zIndex $3 = 300,
  all fourteen media keys, 280 themes.

Tailwind, shadcn, Radix
  The generated stylesheets emitted `@theme` and `@theme inline` blocks to
  register colors as Tailwind utilities. Those blocks are gone; what remains is
  `:root` / `.dark` custom properties, the same shape and the same dark selector
  as @hanzo/ui/theme.css. The semantic token map had drifted into two homes — a
  hand-edited shadcn-semantic-colors.css and a TS map that disagreed with it
  about `--primary` (step 9 vs step 10) — so the CSS file is deleted and
  dist/css/semantic.css is emitted from the map at build time. The dark block
  now carries only the roles whose step actually changes.

TypeScript 7
  tsgo for both typecheck and emit (~0.5s). It needs types: ["node", "react"]
  spelled out in tsconfig or it fails to find @types/node. tsup is gone with it:
  it and tsc were both writing dist/css/generate-palettes.js, and tsc's own ESM
  output is a perfectly good bin. One compiler, one output format — the package
  is now "type": "module" with explicit .js extensions, so Node resolves it
  rather than relying on a bundler to forgive extensionless ESM.

Also
  Export paths follow the rename (/gui, /gui/components, /gui/defaults, /css,
  /semantic.css) and a new root export carries the dependency-free color math.
  LLM.md was a tracked symlink to a gitignored file, dangling in every clone;
  it is a real file now. README described a differently-named package with
  export paths that did not exist.

Verified: pnpm build green, tsgo and tsc 5.9 both clean, CLI exercised on a real
brand.json, all six export subpaths resolved and imported from a linked dist.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-03 17:55:59 -07:00

2.2 KiB

@hanzo/theming — working notes

Seeds in, design system out. A hex seed becomes a 12-step palette; the palettes become a @hanzo/gui config, a set of CSS custom properties, and a handful of themed components.

Layout — three layers, each usable without the ones above it

Layer Entry Depends on
Core src/types.ts, src/palette-utils.ts, src/index.ts nothing
CSS src/css/ core
GUI src/gui/ core, @hanzo/gui

Import the core to do color math, ./css to emit stylesheets, ./gui only when you actually need @hanzo/gui. Nothing in core or css pulls React.

Rules that keep biting

  • One home per fact. The semantic token map lives in src/css/semantic.ts and nowhere else; dist/css/semantic.css is emitted from it by scripts/prepare-dist.mjs. It used to also exist as a hand-edited .css file, and the two drifted (--primary was step 9 in one and step 10 in the other). Do not reintroduce a checked-in copy.
  • No Tailwind, no shadcn, no Radix. The stylesheets are plain :root / .dark custom properties. If you find yourself typing @theme, stop.
  • .dark is the dark selector, matching @hanzo/ui/theme.css. It is exported as DARK_SELECTOR — read it, don't retype it.
  • Default token scales live in src/gui/defaults/. Size, space, radius, zIndex, media, fonts and seeds are all there. createGuiConfig passes raw numbers; createGui runs them through createVariables itself, which is why no config package is needed to build them.

Build

pnpm build = tsgo (TypeScript 7 native, ~0.5s) + scripts/prepare-dist.mjs. One compiler, one output format (ESM — the package is "type": "module", and relative imports carry explicit .js extensions so Node resolves them).

tsgo needs types: ["node", "react"] in tsconfig.json; without it, it fails to pick up @types/node and reports Cannot find name 'node:fs'.

Verifying a change

@hanzo/gui imports react-native-web without declaring it, so importing ./gui in bare Node fails unless react-native-web is installed. For a runtime check, pnpm add -D react-native-web, exercise it, then remove it. The core and css layers need no such thing.