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]>
174 lines
4.9 KiB
TypeScript
174 lines
4.9 KiB
TypeScript
process.env.GUI_TARGET = 'native'
|
|
|
|
import { getDefaultGuiConfig } from '@hanzogui/config-default'
|
|
import {
|
|
View,
|
|
createGui,
|
|
getSplitStyles,
|
|
getStyleTokenProvenance,
|
|
styled,
|
|
} from '../web/src'
|
|
import { describe, expect, test } from 'vitest'
|
|
|
|
// config-default themes used here:
|
|
// light → { background: '#fff', color: '#000' }
|
|
// dark → { background: '#000', color: '#fff' }
|
|
// dark_blue → { background: 'blue', color: 'white' }
|
|
const config = createGui(getDefaultGuiConfig('native'))
|
|
const provenanceEnabled =
|
|
process.env.NODE_ENV === 'development' &&
|
|
process.env.GUI_ENABLE_STYLE_TOKEN_PROVENANCE === '1'
|
|
|
|
const componentState = {
|
|
hover: false,
|
|
press: false,
|
|
pressIn: false,
|
|
focus: false,
|
|
unmounted: true,
|
|
disabled: false,
|
|
focusVisible: false,
|
|
}
|
|
|
|
function splitInspect(
|
|
themeName: string,
|
|
props: Record<string, any>,
|
|
Component: typeof View = View
|
|
) {
|
|
const result = getSplitStyles(
|
|
props,
|
|
Component.staticConfig,
|
|
config.themes[themeName] ?? {},
|
|
themeName,
|
|
componentState,
|
|
{ isAnimated: false, resolveValues: 'auto' },
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined
|
|
)!
|
|
return {
|
|
resolved: result.style,
|
|
provenance: getStyleTokenProvenance(result.style),
|
|
}
|
|
}
|
|
|
|
describe.runIf(provenanceEnabled)('getSplitStyles token provenance', () => {
|
|
test('a direct color token resolves to a real color and records its token + theme', () => {
|
|
const { resolved, provenance } = splitInspect('light', {
|
|
backgroundColor: '$background',
|
|
width: 10,
|
|
height: 10,
|
|
})
|
|
expect(resolved.backgroundColor).toBe('#fff')
|
|
expect(provenance).toEqual({
|
|
backgroundColor: { token: '$background', theme: 'light' },
|
|
})
|
|
})
|
|
|
|
test('a shorthand token records against the expanded style key', () => {
|
|
const { resolved, provenance } = splitInspect('dark', {
|
|
bg: '$background',
|
|
width: 10,
|
|
height: 10,
|
|
})
|
|
expect(resolved.backgroundColor).toBe('#000')
|
|
expect(provenance).toEqual({
|
|
backgroundColor: { token: '$background', theme: 'dark' },
|
|
})
|
|
})
|
|
|
|
test('a variant-supplied token is recorded on the winning style', () => {
|
|
const Toned = styled(View, {
|
|
variants: {
|
|
toned: {
|
|
true: { backgroundColor: '$background', color: '$color' },
|
|
},
|
|
} as const,
|
|
})
|
|
const { provenance } = splitInspect(
|
|
'light',
|
|
{ toned: true, width: 10, height: 10 },
|
|
Toned
|
|
)
|
|
expect(provenance).toEqual({
|
|
backgroundColor: { token: '$background', theme: 'light' },
|
|
color: { token: '$color', theme: 'light' },
|
|
})
|
|
})
|
|
|
|
test('a nested theme name rides along with the token', () => {
|
|
const { resolved, provenance } = splitInspect('dark_blue', {
|
|
backgroundColor: '$background',
|
|
width: 10,
|
|
height: 10,
|
|
})
|
|
expect(resolved.backgroundColor).toBe('blue')
|
|
expect(provenance).toEqual({
|
|
backgroundColor: { token: '$background', theme: 'dark_blue' },
|
|
})
|
|
})
|
|
|
|
test('a literal style-prop override stays a literal even when it equals the token value', () => {
|
|
// in `dark`, $color resolves to #fff — the same value the literal supplies.
|
|
const { resolved, provenance } = splitInspect('dark', {
|
|
color: '$color',
|
|
style: { color: '#fff' },
|
|
width: 10,
|
|
height: 10,
|
|
})
|
|
expect(resolved.color).toBe('#fff')
|
|
// the literal wins, so there is NO token binding for color: identity is
|
|
// preserved even though the token would have resolved to the same color.
|
|
expect(provenance?.color).toBeUndefined()
|
|
})
|
|
|
|
test('a purely literal style carries no provenance', () => {
|
|
const { provenance } = splitInspect('light', {
|
|
backgroundColor: '#abcdef',
|
|
width: 10,
|
|
height: 10,
|
|
})
|
|
expect(provenance).toBeUndefined()
|
|
})
|
|
|
|
test('a media-selected token overrides the base token in provenance', () => {
|
|
// media state is easiest to force through the low-level splitter.
|
|
const result = getSplitStyles(
|
|
{ backgroundColor: '$background', $sm: { backgroundColor: '$color' } },
|
|
View.staticConfig,
|
|
{} as any,
|
|
'dark',
|
|
{
|
|
hover: false,
|
|
press: false,
|
|
pressIn: false,
|
|
focus: false,
|
|
unmounted: true,
|
|
disabled: false,
|
|
focusVisible: false,
|
|
},
|
|
{ isAnimated: false, mediaState: { sm: true } },
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined
|
|
)!
|
|
expect(getStyleTokenProvenance(result.style)).toEqual({
|
|
backgroundColor: { token: '$color', theme: 'dark' },
|
|
})
|
|
})
|
|
})
|
|
|
|
describe.runIf(!provenanceEnabled)('getSplitStyles token provenance disabled', () => {
|
|
test('does not track tokens without both development mode and the opt-in flag', () => {
|
|
const { provenance } = splitInspect('light', {
|
|
backgroundColor: '$background',
|
|
width: 10,
|
|
height: 10,
|
|
})
|
|
expect(provenance).toBeUndefined()
|
|
})
|
|
})
|