Files
zeekayandHanzo Dev 751ef5c778 rename the framework to @hanzo/gui and the loader to @hanzogui/loader
Both old names are owned by a different npm account (artemis-prime), so
publishing them returns 403 — which is how this surfaced: the 8.0.0 run
shipped @hanzogui/logo and @hanzogui/demos depending on [email protected], a
version that cannot be published and therefore does not exist. Those two
were uninstallable.

@hanzo/gui and @hanzogui/* are ours, so the framework now carries the name
it is imported by everywhere downstream, and the loader moves under the
scope we control.

The rewrite is limited to package references. `DEBUG?.startsWith('hanzogui')`
is a log-namespace filter and join(dir, 'hanzogui') is a path — rewriting
either would change behaviour, so both are untouched.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-30 20:23:18 -07:00

372 lines
8.2 KiB
Plaintext

Gui is a style library `@hanzogui/core`, and a separate UI kit `hanzogui`. It
also has an optional optimizing compiler `@hanzogui/static` that generally you
only use through it's bundler plugins like `@hanzogui/vite-plugin` or
`@hanzogui/babel-plugin` for Metro.
Note `hanzogui` is a superset of `@hanzogui/core`, so you can use that in general
for code generation.
For the core style library you can do inline styles:
```tsx
import { View, Text } from '@hanzo/gui'
export default () => (
<>
<View backgroundColor="red" />
<Text fontSize={16} color="$colorToken" />
</>
)
```
Or you can use `styled()`:
```tsx
import { styled, View } from '@hanzo/gui'
const CustomView = styled(View, {
margin: 10,
variants: {
spaced: {
true: {
margin: 20,
},
},
} as const,
})
```
For more on styled, there's a doc `styled.mdx` you can look up. Variants
generally can do a lot:
```tsx
import { View, styled } from '@hanzogui/core'
export const RoundedSquare = styled(View, {
borderRadius: 20,
variants: {
pin: {
// string values
top: {
position: 'absolute',
top: 0,
},
},
centered: {
// boolean
true: {
alignItems: 'center',
justifyContent: 'center',
},
false: {
alignItems: 'flex-start',
},
},
size: {
// functional that take all "size" tokens, so <View size="$sm" /> passes into here
'...size': (size, { tokens }) => {
return {
width: tokens.size[size] ?? size,
height: tokens.size[size] ?? size,
}
},
},
} as const,
})
```
You can define your configuration for Gui using `createGui`, and it lets
you define things, there's a readme in the docs called `configuration.mdx` you
can look up for more on this:
```tsx
import { createGui, getConfig } from '@hanzogui/core'
export const config = createGui({
// act like CSS variables at your root
tokens: {
// width="$sm"
size: { sm: 8, md: 12, lg: 20 },
// margin="$-sm"
space: { '-sm': 8 },
// radius="$none"
radius: { none: 0, sm: 3 },
color: { white: '#fff', black: '#000' },
},
themes: {
light: {
bg: '#f2f2f2',
color: '#fff',
},
dark: {
bg: '#111',
color: '#000',
},
},
// media query definitions can be used to style,
// but also can be used with "groups" to do container queries by size:
media: {
sm: { maxWidth: 860 },
gtSm: { minWidth: 860 + 1 },
short: { maxHeight: 820 },
hoverNone: { hover: 'none' },
touch: { pointer: 'coarse' },
},
shorthands: {
// <View px={20} />
px: 'paddingHorizontal',
},
settings: {
disableSSR: true, // for client-side apps gains a bit of performance
allowedStyleValues: 'somewhat-strict-web', // if targeting only web
},
})
// in other files use this:
console.log(`config is`, getConfig())
// get typescript types on @hanzogui/core imports:
type AppConfig = typeof config
declare module '@hanzogui/core' {
interface GuiCustomConfig extends AppConfig {}
}
```
Note that Gui maps tokens to style props using some logic, so if you use
`<View margin="$sm />` it looks for
`createGui({ tokens: { space: { sm: 10 } } })`:
```ts
// if not specified it defaults to `space`
export const tokenCategories = {
radius: {
borderRadius: true,
borderTopLeftRadius: true,
borderTopRightRadius: true,
borderBottomLeftRadius: true,
borderBottomRightRadius: true,
borderStartStartRadius: true,
borderStartEndRadius: true,
borderEndStartRadius: true,
borderEndEndRadius: true,
},
size: {
width: true,
height: true,
minWidth: true,
minHeight: true,
maxWidth: true,
maxHeight: true,
blockSize: true,
minBlockSize: true,
maxBlockSize: true,
inlineSize: true,
minInlineSize: true,
maxInlineSize: true,
},
zIndex: {
zIndex: true,
},
color: {
backgroundColor: true,
borderColor: true,
borderBlockStartColor: true,
borderBlockEndColor: true,
borderBlockColor: true,
borderBottomColor: true,
borderInlineColor: true,
borderInlineStartColor: true,
borderInlineEndColor: true,
borderTopColor: true,
borderLeftColor: true,
borderRightColor: true,
borderEndColor: true,
borderStartColor: true,
shadowColor: true,
...textColors,
...(process.env.GUI_TARGET === 'web' && {
outlineColor: true,
caretColor: true,
}),
},
}
```
Gui themes are special and can do a lot, just know that you can generate
them a few ways.
Simply just like above, or using our new `createThemes` from
`@hanzogui/config/v5`.
It's done like this:
```tsx fileName=themes.ts
import * as Colors from '@hanzogui/colors'
import { createThemes, defaultComponentThemes } from '@hanzogui/config/v5'
const darkPalette = [
'#050505',
'#151515',
'#191919',
'#232323',
'#282828',
'#323232',
'#424242',
'#494949',
'#545454',
'#626262',
'#a5a5a5',
'#fff',
]
const lightPalette = [
'#fff',
'#f8f8f8',
'hsl(0, 0%, 96.3%)',
'hsl(0, 0%, 94.1%)',
'hsl(0, 0%, 92.0%)',
'hsl(0, 0%, 90.0%)',
'hsl(0, 0%, 88.5%)',
'hsl(0, 0%, 81.0%)',
'hsl(0, 0%, 56.1%)',
'hsl(0, 0%, 50.3%)',
'hsl(0, 0%, 42.5%)',
'hsl(0, 0%, 9.0%)',
]
const lightShadows = {
shadow1: 'rgba(0,0,0,0.04)',
shadow2: 'rgba(0,0,0,0.08)',
shadow3: 'rgba(0,0,0,0.16)',
shadow4: 'rgba(0,0,0,0.24)',
shadow5: 'rgba(0,0,0,0.32)',
shadow6: 'rgba(0,0,0,0.4)',
}
const darkShadows = {
shadow1: 'rgba(0,0,0,0.2)',
shadow2: 'rgba(0,0,0,0.3)',
shadow3: 'rgba(0,0,0,0.4)',
shadow4: 'rgba(0,0,0,0.5)',
shadow5: 'rgba(0,0,0,0.6)',
shadow6: 'rgba(0,0,0,0.7)',
}
const extraColors = {
black1: darkPalette[0],
black2: darkPalette[1],
black3: darkPalette[2],
black4: darkPalette[3],
black5: darkPalette[4],
black6: darkPalette[5],
black7: darkPalette[6],
black8: darkPalette[7],
black9: darkPalette[8],
black10: darkPalette[9],
black11: darkPalette[10],
black12: darkPalette[11],
white1: lightPalette[0],
white2: lightPalette[1],
white3: lightPalette[2],
white4: lightPalette[3],
white5: lightPalette[4],
white6: lightPalette[5],
white7: lightPalette[6],
white8: lightPalette[7],
white9: lightPalette[8],
white10: lightPalette[9],
white11: lightPalette[10],
white12: lightPalette[11],
}
const generatedThemes = createThemes({
componentThemes: defaultComponentThemes,
base: {
palette: {
dark: darkPalette,
light: lightPalette,
},
// for values we don't want being inherited onto sub-themes
extra: {
light: {
...Colors.blue,
...Colors.green,
...Colors.red,
...Colors.yellow,
...lightShadows,
...extraColors,
shadowColor: lightShadows.shadow1,
},
dark: {
...Colors.blueDark,
...Colors.greenDark,
...Colors.redDark,
...Colors.yellowDark,
...darkShadows,
...extraColors,
shadowColor: darkShadows.shadow1,
},
},
},
// inverse accent theme
accent: {
palette: {
dark: lightPalette,
light: darkPalette,
},
},
childrenThemes: {
blue: {
palette: {
dark: Object.values(Colors.blueDark),
light: Object.values(Colors.blue),
},
},
red: {
palette: {
dark: Object.values(Colors.redDark),
light: Object.values(Colors.red),
},
},
yellow: {
palette: {
dark: Object.values(Colors.yellowDark),
light: Object.values(Colors.yellow),
},
},
green: {
palette: {
dark: Object.values(Colors.greenDark),
light: Object.values(Colors.green),
},
},
},
})
export type GuiThemes = typeof generatedThemes
/**
* This is an optional production optimization: themes JS can get to 20Kb or more.
* Gui has ~1Kb of logic to hydrate themes from CSS, so you can remove the JS.
* So long as you server render your Gui CSS, this will save you bundle size:
*/
export const themes: GuiThemes =
process.env.GUI_ENVIRONMENT === 'client' && process.env.NODE_ENV === 'production'
? {}
: (generatedThemes as any)
```
And it generates a whole bunch of themes for you that are very nice like `light`, `light_accent`, `light_accent_Button`, etc. For more, see the `config-v4.mdx` file in search.