mirror of
https://github.com/hanzoai/gui.git
synced 2026-10-25 02:31:41 +00:00
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]>
756 lines
23 KiB
Plaintext
756 lines
23 KiB
Plaintext
---
|
|
title: 'Config v5'
|
|
description: Modern config and themes with @hanzogui/config/v5
|
|
---
|
|
|
|
<IntroParagraph>
|
|
The recommended Gui configuration gives you a complete design system, flexible theme
|
|
generation, Tailwind aligned shorthands, multiple animation drivers, and easy
|
|
customization.
|
|
</IntroParagraph>
|
|
|
|
V5 builds on v4 with more colors, theme helpers, and expanded media queries.
|
|
Migration from v4 is straightforward - see
|
|
[what's changed](#whats-different-from-v4).
|
|
|
|
First install the config package:
|
|
|
|
```bash
|
|
npm install @hanzogui/config
|
|
```
|
|
|
|
### Changes from v4
|
|
|
|
- **Animations not bundled** - Import separately from `v5-css`, `v5-rn`,
|
|
`v5-reanimated`, or `v5-motion`. See
|
|
[Choosing an Animation Driver](#choosing-an-animation-driver).
|
|
- **Media query naming** - `2xl`/`2xs` → `xxl`/`xxs`/`xxxs`. Max queries use
|
|
kebab-case: `max2Xl` → `max-xxl`.
|
|
- **`styleCompat: 'react-native'`** - `flex` now uses `flexBasis: 0` by default
|
|
(v4 used `'legacy'` with `flexBasis: auto`).
|
|
- **`defaultPosition` not set** - Defaults to browser `static` instead of v4's
|
|
`'relative'`. You can still set it in your config.
|
|
|
|
### New Features
|
|
|
|
- **More color themes**: gray, blue, red, yellow, green, orange, pink, purple,
|
|
teal, neutral (v4 had blue, red, yellow, green, black, white)
|
|
- **More theme colors**: `shadow1`-`shadow8`, `highlight1`-`highlight8`,
|
|
`background01`/`background001` through `background08`, `color01`/`color001`,
|
|
`white0`/`white02`-`white08`, `black0`/`black02`-`black08`, and more
|
|
- **More animation values**: timing presets from `0ms` to `500ms`, plus named
|
|
springs like `quick`, `bouncy`, `lazy`, and variants like `quickLessBouncy`
|
|
- **`createV5Theme` helper** for easy theme customization and swapping colors
|
|
- **`getTheme` callback** in `createV5Theme` for computing custom values across
|
|
every theme automatically based on each theme's palette and scheme
|
|
- **Easier theme swapping**: pass only the `childrenThemes` you want to
|
|
`createV5Theme` to replace or extend the default color set
|
|
- **Height-based media queries**: `height-sm`, `height-md`, `height-lg` and max variants
|
|
- **`touch`** and **`hoverable`** media queries for device capability detection
|
|
- **Color utilities**: `adjustPalette`, `adjustPalettes` for transforming
|
|
palettes
|
|
- **Radix Colors v3** with improved accessibility (v4 used legacy Radix)
|
|
|
|
### Migrating from v4
|
|
|
|
To restore v4 behavior while using v5:
|
|
|
|
```tsx fileName="hanzogui.config.ts"
|
|
import { defaultConfig } from '@hanzogui/config/v5'
|
|
import { animations } from '@hanzogui/config/v5-css'
|
|
import { createGui } from '@hanzo/gui'
|
|
|
|
export const config = createGui({
|
|
...defaultConfig,
|
|
animations,
|
|
settings: {
|
|
...defaultConfig.settings,
|
|
styleCompat: 'legacy',
|
|
defaultPosition: 'relative',
|
|
},
|
|
})
|
|
```
|
|
|
|
Update media query names in your code: `$2xl` → `$xxl`, `$2xs` → `$xxs`,
|
|
`$max2Xl` → `$max-xxl`.
|
|
|
|
---
|
|
|
|
## Choosing an Animation Driver
|
|
|
|
V5 provides separate entry points for different animation drivers, so you only
|
|
bundle what you need:
|
|
|
|
```tsx fileName="hanzogui.config.ts"
|
|
import { defaultConfig } from '@hanzogui/config/v5'
|
|
import { animations } from '@hanzogui/config/v5-css'
|
|
import { createGui } from '@hanzo/gui'
|
|
|
|
export const config = createGui({
|
|
...defaultConfig,
|
|
animations,
|
|
})
|
|
```
|
|
|
|
Available animation drivers:
|
|
|
|
- **`@hanzogui/config/v5-css`** - CSS animations (smallest bundle, great for web)
|
|
- **`@hanzogui/config/v5-motion`** - Motion animations (spring physics, smooth)
|
|
- **`@hanzogui/config/v5-rn`** - React Native Animated API
|
|
- **`@hanzogui/config/v5-reanimated`** - Reanimated (best native performance)
|
|
|
|
<Notice>
|
|
The base `@hanzogui/config/v5` export includes no animations. Import animations
|
|
separately from one of the driver entry points above.
|
|
</Notice>
|
|
|
|
### Cross-Platform Animation Setup
|
|
|
|
For apps targeting both web and native, you can use different animation drivers
|
|
per platform:
|
|
|
|
```tsx fileName="hanzogui.config.ts"
|
|
import { defaultConfig } from '@hanzogui/config/v5'
|
|
import { animations as animationsCSS } from '@hanzogui/config/v5-css'
|
|
import { animations as animationsReanimated } from '@hanzogui/config/v5-reanimated'
|
|
import { createGui, isWeb } from '@hanzo/gui'
|
|
|
|
export const config = createGui({
|
|
...defaultConfig,
|
|
animations: isWeb ? animationsCSS : animationsReanimated,
|
|
})
|
|
```
|
|
|
|
This gives you CSS animations on web (smaller bundle, better performance) and
|
|
Reanimated on native (smooth 60fps animations).
|
|
|
|
### Available Animations
|
|
|
|
All v5 animation drivers include these preset animations:
|
|
|
|
**Timing animations** (fixed duration):
|
|
|
|
<PropsTable
|
|
data={[
|
|
{ name: '0ms', description: 'Instant (0ms)' },
|
|
{ name: '50ms', description: '50 milliseconds' },
|
|
{ name: '75ms', description: '75 milliseconds' },
|
|
{ name: '100ms', description: '100 milliseconds' },
|
|
{ name: '200ms', description: '200 milliseconds' },
|
|
{ name: '250ms', description: '250 milliseconds' },
|
|
{ name: '300ms', description: '300 milliseconds' },
|
|
{ name: '400ms', description: '400 milliseconds' },
|
|
{ name: '500ms', description: '500 milliseconds' },
|
|
]}
|
|
/>
|
|
|
|
**Spring animations** (physics-based):
|
|
|
|
<PropsTable
|
|
data={[
|
|
{ name: 'superBouncy', description: 'Very bouncy, playful spring' },
|
|
{ name: 'bouncy', description: 'Bouncy spring with natural feel' },
|
|
{ name: 'superLazy', description: 'Very slow, heavy spring' },
|
|
{ name: 'lazy', description: 'Slow, relaxed spring' },
|
|
{ name: 'medium', description: 'Balanced spring for general use' },
|
|
{ name: 'slowest', description: 'Slowest spring animation' },
|
|
{ name: 'slow', description: 'Slow spring animation' },
|
|
{ name: 'quick', description: 'Fast, responsive spring' },
|
|
{ name: 'quickLessBouncy', description: 'Quick with minimal overshoot' },
|
|
{ name: 'quicker', description: 'Faster spring' },
|
|
{ name: 'quickerLessBouncy', description: 'Faster with minimal overshoot' },
|
|
{ name: 'quickest', description: 'Fastest spring' },
|
|
{
|
|
name: 'quickestLessBouncy',
|
|
description: 'Fastest with minimal overshoot',
|
|
},
|
|
]}
|
|
/>
|
|
|
|
---
|
|
|
|
## Customizing Themes with createV5Theme
|
|
|
|
The `createV5Theme` function lets you customize the default v5 themes. The
|
|
easiest way to add or change colors is using `@hanzogui/colors` which provides
|
|
Radix color palettes:
|
|
|
|
```tsx fileName="hanzogui.config.ts"
|
|
import { createV5Theme, defaultChildrenThemes, defaultConfig } from '@hanzogui/config/v5'
|
|
import { cyan, cyanDark, amber, amberDark } from '@hanzogui/colors'
|
|
import { createGui } from '@hanzo/gui'
|
|
|
|
const themes = createV5Theme({
|
|
childrenThemes: {
|
|
// include defaults (blue, red, green, yellow, etc.)
|
|
...defaultChildrenThemes,
|
|
// add new colors
|
|
cyan: { light: cyan, dark: cyanDark },
|
|
amber: { light: amber, dark: amberDark },
|
|
},
|
|
})
|
|
|
|
export const config = createGui({
|
|
...defaultConfig,
|
|
themes,
|
|
})
|
|
```
|
|
|
|
Or use only the colors you need:
|
|
|
|
```tsx fileName="hanzogui.config.ts"
|
|
import { createV5Theme } from '@hanzogui/config/v5'
|
|
import { blue, blueDark, gray, grayDark } from '@hanzogui/colors'
|
|
|
|
// minimal theme with just blue and gray
|
|
const themes = createV5Theme({
|
|
childrenThemes: {
|
|
blue: { light: blue, dark: blueDark },
|
|
gray: { light: gray, dark: grayDark },
|
|
},
|
|
})
|
|
```
|
|
|
|
### createV5Theme Options
|
|
|
|
<PropsTable
|
|
data={[
|
|
{
|
|
name: 'childrenThemes',
|
|
type: 'Record<string, { light: ColorObject, dark: ColorObject }>',
|
|
description:
|
|
'Color themes to include. Use defaultChildrenThemes to include defaults, or pass only the colors you need. Works directly with @hanzogui/colors.',
|
|
},
|
|
{
|
|
name: 'darkPalette',
|
|
type: 'string[]',
|
|
description: 'Override the dark base palette (12 colors from darkest to lightest)',
|
|
},
|
|
{
|
|
name: 'lightPalette',
|
|
type: 'string[]',
|
|
description: 'Override the light base palette (12 colors from lightest to darkest)',
|
|
},
|
|
{
|
|
name: 'grandChildrenThemes',
|
|
type: 'Record<string, { template: string }>',
|
|
description: 'Override grandChildren themes (alt1, alt2, surface1, etc.)',
|
|
},
|
|
{
|
|
name: 'componentThemes',
|
|
type: 'false | ComponentThemes',
|
|
default: 'false',
|
|
description:
|
|
'Component themes (defaults to false in v5). We recommend using defaultProps instead.',
|
|
},
|
|
{
|
|
name: 'getTheme',
|
|
type: '(info: { palette: string[], scheme: "light" | "dark" }) => Record<string, string>',
|
|
description:
|
|
"Callback that runs for every generated theme, letting you compute custom values based on each theme's palette and color scheme. The default uses this to generate opacity variants like color01, background001, etc.",
|
|
},
|
|
]}
|
|
/>
|
|
|
|
### Customizing Every Theme with getTheme
|
|
|
|
The `getTheme` option lets you add computed colors to every generated theme. It
|
|
receives each theme's palette and scheme, so your custom values automatically
|
|
adapt to every color and light/dark variant:
|
|
|
|
```tsx fileName="hanzogui.config.ts"
|
|
import { createV5Theme, opacify } from '@hanzogui/config/v5'
|
|
|
|
const themes = createV5Theme({
|
|
getTheme: ({ palette, scheme }) => {
|
|
const bg = palette[7]
|
|
const fg = palette[palette.length - 2]
|
|
return {
|
|
// add your own computed theme values
|
|
myOverlay: opacify(bg, 0.5),
|
|
mySubtleText: opacify(fg, 0.6),
|
|
}
|
|
},
|
|
})
|
|
```
|
|
|
|
This is how v5 generates its built-in opacity tokens (`background01`,
|
|
`color001`, etc.) — your custom `getTheme` merges on top of the defaults.
|
|
|
|
### Subtle Theme Variant
|
|
|
|
For a more muted look, use the subtle variant which has desaturated colors:
|
|
|
|
```tsx fileName="hanzogui.config.ts"
|
|
import { defaultConfig, themes } from '@hanzogui/config/v5-subtle'
|
|
import { createGui } from '@hanzo/gui'
|
|
|
|
export const config = createGui({
|
|
...defaultConfig,
|
|
themes,
|
|
})
|
|
```
|
|
|
|
### Custom Color Adjustments
|
|
|
|
Use `adjustPalette` to transform colors with a callback function. The callback
|
|
receives each color's HSL values and its 1-based index (1-12):
|
|
|
|
```tsx fileName="hanzogui.config.ts"
|
|
import {
|
|
adjustPalette,
|
|
adjustPalettes,
|
|
defaultChildrenThemes,
|
|
createV5Theme,
|
|
} from '@hanzogui/config/v5'
|
|
|
|
// adjust a single palette - desaturate and lighten
|
|
const mutedBlue = adjustPalette(blue, (hsl, i) => ({
|
|
...hsl,
|
|
s: hsl.s * 0.7,
|
|
l: Math.min(100, hsl.l * 1.1),
|
|
}))
|
|
|
|
// adjust multiple palettes at once with adjustPalettes
|
|
const mutedThemes = adjustPalettes(defaultChildrenThemes, {
|
|
// 'default' applies to all colors not explicitly listed
|
|
default: {
|
|
light: (hsl, i) => ({ ...hsl, s: hsl.s * 0.8 }),
|
|
dark: (hsl, i) => ({ ...hsl, s: hsl.s * 0.6, l: hsl.l * 0.9 }),
|
|
},
|
|
// override specific colors
|
|
yellow: {
|
|
light: (hsl) => ({ ...hsl, s: hsl.s * 0.5 }),
|
|
dark: (hsl, i) => ({ ...hsl, s: hsl.s * (i <= 4 ? 0.3 : 0.8) }),
|
|
},
|
|
// skip adjustment for specific colors
|
|
gray: undefined,
|
|
})
|
|
|
|
const themes = createV5Theme({ childrenThemes: mutedThemes })
|
|
```
|
|
|
|
The callback receives:
|
|
|
|
- `hsl` - object with `h` (hue 0-360), `s` (saturation 0-100), `l` (lightness
|
|
0-100)
|
|
- `i` - 1-based index in the palette (1-12)
|
|
|
|
Use the index to apply different adjustments to background colors (1-4),
|
|
mid-tones (5-8), and foreground colors (9-12).
|
|
|
|
---
|
|
|
|
## Theme Values
|
|
|
|
V5 themes include a rich set of color values accessible via `$theme-*` tokens.
|
|
|
|
### Base Colors (color1-12)
|
|
|
|
Every theme includes 12 base colors that shift based on the theme:
|
|
|
|
```tsx
|
|
<View bg="$color1" /> // Lightest in light mode, darkest in dark mode
|
|
<View bg="$color6" /> // Mid-range
|
|
<View bg="$color12" /> // Darkest in light mode, lightest in dark mode
|
|
```
|
|
|
|
### Semantic Colors
|
|
|
|
Standard semantic values that adapt to each theme:
|
|
|
|
- `background`, `backgroundHover`, `backgroundPress`, `backgroundFocus`
|
|
- `color`, `colorHover`, `colorPress`, `colorFocus`
|
|
- `borderColor`, `borderColorHover`, `borderColorPress`, `borderColorFocus`
|
|
- `placeholderColor`, `outlineColor`
|
|
|
|
### Opacity Variants
|
|
|
|
Foreground and background colors with opacity variants. The naming uses the
|
|
opacity value without the decimal point (e.g., `01` = 10%, `0025` = 2.5%).
|
|
|
|
- `color01` (10%), `color0075` (7.5%), `color005` (5%), `color0025` (2.5%),
|
|
`color002` (2%), `color001` (1%)
|
|
- `background01` (10%), `background0075` (7.5%), `background005` (5%),
|
|
`background0025` (2.5%), `background002` (2%), `background001` (1%)
|
|
- `background02` (20%), `background04` (40%), `background06` (60%),
|
|
`background08` (80%)
|
|
|
|
### White & Black (Fixed)
|
|
|
|
Always available regardless of theme, with opacity variants:
|
|
|
|
- `white`, `white0` (transparent), `white02`, `white04`, `white06`, `white08`
|
|
- `black`, `black0` (transparent), `black02`, `black04`, `black06`, `black08`
|
|
- `white1`-`white12`, `black1`-`black12` (12-step scales)
|
|
|
|
### Shadow & Highlight Colors
|
|
|
|
Pre-tuned shadow opacities (black) for light and dark modes:
|
|
|
|
- `shadow1` through `shadow8` (light shadows are subtler, dark are stronger)
|
|
- `shadowColor` - Default shadow color for the theme
|
|
|
|
Pre-tuned highlight opacities (white) for light and dark modes:
|
|
|
|
- `highlight1` through `highlight8` (matching shadow scale, useful for glows/overlays)
|
|
|
|
### Radix Color Scales
|
|
|
|
All color themes expose their full 12-step scale:
|
|
|
|
```tsx
|
|
<View bg="$blue5" />
|
|
<Text color="$red11" />
|
|
<View borderColor="$green7" />
|
|
```
|
|
|
|
Available scales: `gray1-12`, `blue1-12`, `red1-12`, `green1-12`, `yellow1-12`,
|
|
`orange1-12`, `pink1-12`, `purple1-12`, `teal1-12`
|
|
|
|
### Neutral Colors
|
|
|
|
The `neutral` scale maintains sufficient contrast on both light and dark
|
|
backgrounds - useful for text or UI that needs to work regardless of theme:
|
|
|
|
- `neutral1`-`neutral12`
|
|
|
|
### Accent Colors
|
|
|
|
Every theme includes an inverted accent scale for contrast elements:
|
|
|
|
- `accent1`-`accent12` - Inverted palette (light colors in dark mode, vice
|
|
versa)
|
|
- `accentBackground`, `accentColor` - Quick access to accent bg/fg
|
|
|
|
```tsx
|
|
<Button theme="accent">Primary Action</Button>
|
|
<View bg="$accentBackground" color="$accentColor" />
|
|
```
|
|
|
|
---
|
|
|
|
## Color Themes
|
|
|
|
V5 includes these color themes by default:
|
|
|
|
- **Grayscale**: gray, neutral
|
|
- **Colors**: blue, green, red, yellow, orange, pink, purple, teal
|
|
- **Fixed**: black, white (generated from base palettes, don't change between
|
|
light/dark)
|
|
|
|
Each color theme has 12 steps following the
|
|
[Radix Colors](https://www.radix-ui.com/colors) pattern.
|
|
|
|
Use any color theme with the `theme` prop:
|
|
|
|
```tsx
|
|
<Button theme="blue">Blue button</Button>
|
|
<Card theme="purple">Purple card</Card>
|
|
```
|
|
|
|
Access individual color values in any theme:
|
|
|
|
```tsx
|
|
<View bg="$orange5" borderColor="$teal7" />
|
|
<Text color="$pink11" />
|
|
```
|
|
|
|
---
|
|
|
|
## Templates
|
|
|
|
V5 includes default templates that control how theme values map to palette
|
|
indices. Available templates: `base`, `surface1`, `surface2`, `surface3`,
|
|
`alt1`, `alt2`, `inverse`.
|
|
|
|
For more details on how templates work, see the
|
|
[Creating Custom Themes Guide](/docs/guides/theme-builder).
|
|
|
|
## Component Themes
|
|
|
|
V5 keeps component themes because they solve a hard problem — how do you change
|
|
the theme of an entire area (like from `dark` to `dark_green`) but have the
|
|
components inside it still keep their relative shades?
|
|
|
|
One of the great things in Gui is being able to set component themes, and
|
|
sub-themes, and have an entire area of your UI re-theme and look perfect.
|
|
|
|
We'd exported just having the ability to set a default theme, like "surface1 =>
|
|
4", but then if you try and re-theme a component to `green`, that would
|
|
conflict. For example, if you made your default `<Button theme="surface3" />`,
|
|
then if someone uses it `<Button theme="green" />` now it's green, but not the
|
|
Button green that is typically stronger than your base green.
|
|
|
|
So for now we've left them on! We do want to move away from component themes in
|
|
general as they can be tricky to understand. But the benefits are also strong,
|
|
and until we find a great solution we're leaving them. You can always set
|
|
`componentThemes: false` in your `createV5Themes` function to turn it off.
|
|
|
|
---
|
|
|
|
## Settings
|
|
|
|
V5 config includes these default settings:
|
|
|
|
<PropsTable
|
|
data={[
|
|
{ name: 'defaultFont', description: '"body"' },
|
|
{
|
|
name: 'fastSchemeChange',
|
|
description:
|
|
'true - Uses DynamicColorIOS on iOS for fast light/dark theme changes.',
|
|
},
|
|
{
|
|
name: 'shouldAddPrefersColorThemes',
|
|
description: 'true - Generates CSS for prefers-color-scheme.',
|
|
},
|
|
{
|
|
name: 'allowedStyleValues',
|
|
description: '"somewhat-strict-web" - Allows web-only values like vh, vw.',
|
|
},
|
|
{
|
|
name: 'addThemeClassName',
|
|
description: '"html" - Adds theme className to html tag for CSS variable access.',
|
|
},
|
|
{
|
|
name: 'onlyAllowShorthands',
|
|
description: 'true - Removes types for longhand versions of shorthands.',
|
|
},
|
|
{
|
|
name: 'styleCompat',
|
|
description:
|
|
'"react-native" - Aligns flex defaults to React Native (flexBasis: 0).',
|
|
},
|
|
]}
|
|
/>
|
|
|
|
---
|
|
|
|
## Media Queries
|
|
|
|
V5 includes an expanded set of media queries with height-based, max-width, and
|
|
min-width variants.
|
|
|
|
The `$sm` through `$xxl` breakpoints match Tailwind CSS exactly (640, 768, 1024,
|
|
1280, 1536), making it easy to work across both ecosystems. The smaller
|
|
breakpoints (`$xxxs`, `$xxs`, `$xs`) provide finer control below 640px, which is
|
|
especially useful for container queries where you need granularity at smaller
|
|
sizes.
|
|
|
|
### Min-Width (Mobile-First)
|
|
|
|
<PropsTable
|
|
data={[
|
|
{ name: 'xxxs', description: 'minWidth: 260' },
|
|
{ name: 'xxs', description: 'minWidth: 340' },
|
|
{ name: 'xs', description: 'minWidth: 460' },
|
|
{ name: 'sm', description: 'minWidth: 640' },
|
|
{ name: 'md', description: 'minWidth: 768' },
|
|
{ name: 'lg', description: 'minWidth: 1024' },
|
|
{ name: 'xl', description: 'minWidth: 1280' },
|
|
{ name: 'xxl', description: 'minWidth: 1536' },
|
|
]}
|
|
/>
|
|
|
|
### Max-Width (Desktop-First)
|
|
|
|
<PropsTable
|
|
data={[
|
|
{ name: 'max-xxxs', description: 'maxWidth: 260' },
|
|
{ name: 'max-xxs', description: 'maxWidth: 340' },
|
|
{ name: 'max-xs', description: 'maxWidth: 460' },
|
|
{ name: 'max-sm', description: 'maxWidth: 640' },
|
|
{ name: 'max-md', description: 'maxWidth: 768' },
|
|
{ name: 'max-lg', description: 'maxWidth: 1024' },
|
|
{ name: 'max-xl', description: 'maxWidth: 1280' },
|
|
{ name: 'max-xxl', description: 'maxWidth: 1536' },
|
|
]}
|
|
/>
|
|
|
|
### Height Min (Mobile-First)
|
|
|
|
<PropsTable
|
|
data={[
|
|
{ name: 'height-sm', description: 'minHeight: 640' },
|
|
{ name: 'height-md', description: 'minHeight: 768' },
|
|
{ name: 'height-lg', description: 'minHeight: 1024' },
|
|
]}
|
|
/>
|
|
|
|
### Height Max (Desktop-First)
|
|
|
|
<PropsTable
|
|
data={[
|
|
{ name: 'max-height-sm', description: 'maxHeight: 640' },
|
|
{ name: 'max-height-md', description: 'maxHeight: 768' },
|
|
{ name: 'max-height-lg', description: 'maxHeight: 1024' },
|
|
]}
|
|
/>
|
|
|
|
<Notice>
|
|
Height queries have higher CSS specificity than width queries. When both match, height
|
|
wins.
|
|
</Notice>
|
|
|
|
### Device Capability
|
|
|
|
<PropsTable
|
|
data={[
|
|
{ name: 'touchable', description: 'pointer: coarse (touch devices)' },
|
|
{ name: 'hoverable', description: 'hover: hover (devices with hover capability)' },
|
|
]}
|
|
/>
|
|
|
|
These names describe intent rather than CSS implementation details — you're thinking
|
|
"is this a touch device?" not "what's the pointer media query name?" They also read
|
|
naturally in code:
|
|
|
|
```tsx
|
|
<Button
|
|
$touchable={{ p: '$4', minH: 44 }}
|
|
$hoverable={{ hoverStyle: { bg: '$color5' } }}
|
|
/>
|
|
```
|
|
|
|
On web, these aren't exact opposites. A laptop with a touchscreen might have
|
|
`pointer: fine` (trackpad as primary input) but still support touch. Having both
|
|
lets you target exactly what you mean.
|
|
|
|
<Notice>
|
|
On native, `touch` is always true and `hoverable` is always false since you can't hover
|
|
on a touchscreen.
|
|
</Notice>
|
|
|
|
---
|
|
|
|
## Shorthands
|
|
|
|
V5 includes Tailwind-aligned shorthands. With `onlyAllowShorthands: true` (the
|
|
default), only the short forms are available in types.
|
|
|
|
To restore longhand props while extending `defaultConfig`, override
|
|
`onlyAllowShorthands`:
|
|
|
|
```tsx
|
|
const config = createGui({
|
|
...defaultConfig,
|
|
settings: {
|
|
...defaultConfig.settings,
|
|
onlyAllowShorthands: false,
|
|
},
|
|
})
|
|
```
|
|
|
|
`onlyShorthandStyleProps` is a separate, narrower setting for border, outline, and
|
|
shadow style props. Setting it to `false` does not override `onlyAllowShorthands`.
|
|
|
|
### Text
|
|
|
|
<PropsTable data={[{ name: 'text', description: 'textAlign' }]} />
|
|
|
|
### Layout & Spacing
|
|
|
|
<PropsTable
|
|
data={[
|
|
{ name: 'p', description: 'padding' },
|
|
{ name: 'pt', description: 'paddingTop' },
|
|
{ name: 'pb', description: 'paddingBottom' },
|
|
{ name: 'pl', description: 'paddingLeft' },
|
|
{ name: 'pr', description: 'paddingRight' },
|
|
{ name: 'px', description: 'paddingHorizontal' },
|
|
{ name: 'py', description: 'paddingVertical' },
|
|
{ name: 'm', description: 'margin' },
|
|
{ name: 'mt', description: 'marginTop' },
|
|
{ name: 'mb', description: 'marginBottom' },
|
|
{ name: 'ml', description: 'marginLeft' },
|
|
{ name: 'mr', description: 'marginRight' },
|
|
{ name: 'mx', description: 'marginHorizontal' },
|
|
{ name: 'my', description: 'marginVertical' },
|
|
]}
|
|
/>
|
|
|
|
### Position & Size
|
|
|
|
<PropsTable
|
|
data={[
|
|
{ name: 't', description: 'top' },
|
|
{ name: 'b', description: 'bottom' },
|
|
{ name: 'l', description: 'left' },
|
|
{ name: 'r', description: 'right' },
|
|
{ name: 'minW', description: 'minWidth' },
|
|
{ name: 'maxW', description: 'maxWidth' },
|
|
{ name: 'minH', description: 'minHeight' },
|
|
{ name: 'maxH', description: 'maxHeight' },
|
|
{ name: 'z', description: 'zIndex' },
|
|
]}
|
|
/>
|
|
|
|
### Flex & Alignment
|
|
|
|
<PropsTable
|
|
data={[
|
|
{ name: 'grow', description: 'flexGrow' },
|
|
{ name: 'shrink', description: 'flexShrink' },
|
|
{ name: 'items', description: 'alignItems' },
|
|
{ name: 'self', description: 'alignSelf' },
|
|
{ name: 'content', description: 'alignContent' },
|
|
{ name: 'justify', description: 'justifyContent' },
|
|
]}
|
|
/>
|
|
|
|
### Other
|
|
|
|
<PropsTable
|
|
data={[
|
|
{ name: 'bg', description: 'backgroundColor' },
|
|
{ name: 'rounded', description: 'borderRadius' },
|
|
{ name: 'select', description: 'userSelect' },
|
|
]}
|
|
/>
|
|
|
|
---
|
|
|
|
## Tree Shaking Themes
|
|
|
|
**Production Optimization** - Theme JS can grow to 20KB or more. Since Gui can hydrate themes from CSS variables, you can remove the themes JS from your client bundle for better Lighthouse scores.
|
|
|
|
This works because Gui generates CSS variables for all theme values. On the
|
|
client, it reads these from the DOM instead of needing the JS object.
|
|
|
|
### Setup
|
|
|
|
```tsx fileName="hanzogui.config.ts"
|
|
import { defaultConfig, themes } from '@hanzogui/config/v5'
|
|
import { createGui } from '@hanzo/gui'
|
|
|
|
export const config = createGui({
|
|
...defaultConfig,
|
|
// only load themes on server - client hydrates from CSS
|
|
// for non-One Vite apps, use import.meta.env.SSR instead
|
|
themes: process.env.VITE_ENVIRONMENT === 'client' ? ({} as typeof themes) : themes,
|
|
})
|
|
```
|
|
|
|
<Notice theme="green">
|
|
This optimization requires server-side rendering. The CSS must be rendered on the server
|
|
for the client to hydrate from it. Make sure you're using `config.getCSS()` or the
|
|
bundler plugin's `outputCSS` option.
|
|
</Notice>
|
|
|
|
---
|
|
|
|
## Summary: v4 to v5 Migration Checklist
|
|
|
|
1. **Add animations import** - v5 doesn't bundle animations:
|
|
```tsx
|
|
import { animations } from '@hanzogui/config/v5-css'
|
|
```
|
|
2. **Update media query names** - `2xl` → `xxl`, `2xs` → `xxs`, `max2Xl` →
|
|
`max-xxl`
|
|
3. **Review flex behavior** - v5 uses `flexBasis: 0` by default (React Native
|
|
style)
|
|
4. **Review position** - v5 doesn't set `defaultPosition` (defaults to `static`)
|
|
5. **Review theme colors** - v5 uses Radix Colors v3 with slightly different
|
|
values
|