mirror of
https://github.com/hanzoai/gui.git
synced 2026-10-25 02:31:41 +00:00
This repo could never sync. There was NO merge-base with tamagui — 372 commits
here against 15,791 there, unrelated histories — because it began as a
copy-paste rebrand with a flattened layout. Every "sync" since was a hand
re-application that drifted, which is why the tree sat on 7.3.1 while upstream
shipped fixes we then rediscovered by hand.
This commit's PARENT IS TAMAGUI. A future sync is `git merge tama/main` then
`node scripts/rebrand.mjs` — a real merge, because the history is now shared.
174 packages: 166 upstream, our 8 restored (chrome, shell, telemetry, recipes,
get, font-geist-{sans,mono}, @hanzo/booker), bento-get gained. 170/170 build.
Our patches to files UPSTREAM ALSO OWNS are carried, which the package-level
delta missed and which was where the value actually was:
- useMedia's server snapshot (`initState ?? getMedia()`). Upstream still
returns undefined there, so every Tamagui Dialog kills a prerender — the
exact crash hanzo.app spent a day on.
- data-slot on web host nodes, absent upstream entirely.
Both applied ONTO upstream's newer files (it rewrote useMedia +150/-63 and
createComponent +160/-55), marked `PATCH (ours, carried across the transplant)`.
Seven traps are encoded in scripts/rebrand.mjs, each found by a gate:
skip itself and lockfiles; special-case the double-branded names in BOTH scoped
and bare form; map path strings, not just paths; drop a level for the flattened
group; check disk rather than a stale index.
Rust build artifacts are NOT committed. An earlier draft of this commit swept
apps/desktop/src-tauri/target/debug in via `git add -A` — 3,859 files including
a 272MB .a, over GitHub's 100MB cap, so the push could never have landed. They
are gitignored now.
Co-Authored-By: Hanzo Dev <[email protected]>
372 lines
8.3 KiB
Plaintext
372 lines
8.3 KiB
Plaintext
Hanzo GUI is a style library `@hanzogui/core`, and a separate UI kit `@hanzo/gui`. 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 `@hanzo/gui` 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 Hanzo 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 Hanzo 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.HANZO_GUI_TARGET === 'web' && {
|
|
outlineColor: true,
|
|
caretColor: true,
|
|
}),
|
|
},
|
|
}
|
|
```
|
|
|
|
Hanzo 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 Hanzo GUIThemes = typeof generatedThemes
|
|
|
|
/**
|
|
* This is an optional production optimization: themes JS can get to 20Kb or more.
|
|
* Hanzo GUI has ~1Kb of logic to hydrate themes from CSS, so you can remove the JS.
|
|
* So long as you server render your Hanzo GUI CSS, this will save you bundle size:
|
|
*/
|
|
export const themes: Hanzo GUIThemes =
|
|
process.env.HANZO_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.
|