mirror of
https://github.com/hanzoai/gui.git
synced 2026-10-25 02:31:41 +00:00
Internal renames so source matches the published @hanzogui/[email protected] dist (Gui.ts, createGui.ts, views/GuiProvider.mjs, views/GuiRoot.mjs). Renames applied: - Files: Hanzogui.ts -> Gui.ts, createHanzogui.ts -> createGui.ts, HanzoguiProvider.tsx -> GuiProvider.tsx, HanzoguiRoot[.native].tsx -> GuiRoot[.native].tsx, HanzoguiPlugin.ts -> GuiPlugin.ts, withHanzogui.ts -> withGui.ts, loadHanzogui.ts -> loadGui.ts, v4-hanzogui.ts -> v4-gui.ts, *.d.ts mirrors, hanzogui.config.ts -> gui.config.ts, hanzogui.build.ts -> gui.build.ts, hanzogui.css -> gui.css, hanzogui-build.js -> gui-build.js, etc. - Directories: pkgs/core/create-hanzogui -> pkgs/core/create-gui, apps/sandbox/config/hanzogui -> apps/sandbox/config/gui. - Identifiers: Hanzogui* -> Gui*, createHanzogui -> createGui, withHanzogui -> withGui, loadHanzogui -> loadGui, HANZOGUI_* env -> GUI_*, __hanzogui* globals -> __gui*, hanzoguiOptions/hanzoguiConfig/ hanzoguiPlugin etc. -> guiOptions/guiConfig/guiPlugin, CSS vars --hanzogui-* -> --gui-*, data-hanzogui-* -> data-gui-*, [hanzogui] log prefix -> [gui]. - Removed duplicate pkgs/packages/hanzogui-dev-config; the canonical pkgs/packages/gui-dev-config (@hanzogui/dev-config) already existed with the correct shape. apps/demos now consumes @hanzogui/dev-config. Preserved (public npm names): - "hanzogui" umbrella package (pkgs/ui/hanzogui/package.json) - "@hanzogui/*" namespace - "hanzogui-loader" package name (pkgs/compiler/loader) - "hanzogui-build-test-*" test fixture names - "hanzogui-publish-smoke" workflow id - pkgs/core/helpers-hanzogui dir (not on rename list) - apps/gui.hanzo.ai/ marketing site directory - AGENTS.md symlink restored after perl -i clobbered it Smoke build (turbo run build): 169/169 workspaces successful. Sample tests: pkgs/core/core-test getSplitStyles.android* + createGui.web all green.
274 lines
7.5 KiB
TypeScript
274 lines
7.5 KiB
TypeScript
/**
|
|
* Nested Media + Platform Query Tests
|
|
*
|
|
* Verifies that media queries and platform queries can be nested inside each other.
|
|
*
|
|
* Examples:
|
|
* $xs={{ "$platform-android": { bg: "yellow" } }} — platform inside media
|
|
* $platform-android={{ $xs: { bg: "red" } }} — media inside platform
|
|
*
|
|
* Both directions should work and the nested condition should be checked.
|
|
* The nested style should only apply when BOTH conditions are true.
|
|
*/
|
|
|
|
import { View, createGui } from '@hanzogui/core'
|
|
import { beforeAll, describe, expect, test } from 'vitest'
|
|
|
|
// Set GUI_TARGET before importing getSplitStyles
|
|
process.env.GUI_TARGET = 'native'
|
|
|
|
// Import directly from source so mocks apply
|
|
import { getSplitStyles } from '../web/src/helpers/getSplitStyles'
|
|
|
|
// Mock @hanzogui/constants to simulate Android environment
|
|
vi.mock('@hanzogui/constants', async () => {
|
|
const actual = await vi.importActual('@hanzogui/constants')
|
|
return {
|
|
...actual,
|
|
isAndroid: true,
|
|
isIos: false,
|
|
isTV: false,
|
|
isWeb: false,
|
|
isClient: true,
|
|
currentPlatform: 'android',
|
|
}
|
|
})
|
|
|
|
import config from '../config-default'
|
|
|
|
beforeAll(() => {
|
|
createGui(config.getDefaultGuiConfig('native'))
|
|
})
|
|
|
|
function getSplitStylesFor(
|
|
props: Record<string, any>,
|
|
Component = View,
|
|
mediaState?: Record<string, boolean>
|
|
) {
|
|
return getSplitStyles(
|
|
props,
|
|
Component.staticConfig,
|
|
{} as any,
|
|
'',
|
|
{
|
|
hover: false,
|
|
press: false,
|
|
pressIn: false,
|
|
focus: false,
|
|
unmounted: true,
|
|
disabled: false,
|
|
focusVisible: false,
|
|
},
|
|
{
|
|
isAnimated: false,
|
|
// provide media state so nested media queries can be checked
|
|
...(mediaState ? { mediaState } : {}),
|
|
},
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined
|
|
)!
|
|
}
|
|
|
|
describe('Nested media + platform queries', () => {
|
|
describe('platform query nested inside media query', () => {
|
|
test('$xs with nested $platform-android applies on Android when xs is active', () => {
|
|
const result = getSplitStylesFor(
|
|
{
|
|
$xs: {
|
|
backgroundColor: 'orange',
|
|
'$platform-android': {
|
|
backgroundColor: 'yellow',
|
|
},
|
|
},
|
|
},
|
|
View,
|
|
{ xs: true }
|
|
)
|
|
// Both conditions met: xs is active + we're on Android
|
|
// Nested platform overrides the outer value
|
|
expect(result.style?.backgroundColor).toBe('yellow')
|
|
})
|
|
|
|
test('$xs with nested $platform-ios does NOT apply on Android', () => {
|
|
const result = getSplitStylesFor(
|
|
{
|
|
$xs: {
|
|
backgroundColor: 'orange',
|
|
'$platform-ios': {
|
|
backgroundColor: 'yellow',
|
|
},
|
|
},
|
|
},
|
|
View,
|
|
{ xs: true }
|
|
)
|
|
// xs is active but $platform-ios doesn't match Android
|
|
// Only the outer $xs style applies
|
|
expect(result.style?.backgroundColor).toBe('orange')
|
|
})
|
|
|
|
test('$xs with nested $platform-android does NOT apply when xs is inactive', () => {
|
|
const result = getSplitStylesFor(
|
|
{
|
|
$xs: {
|
|
backgroundColor: 'orange',
|
|
'$platform-android': {
|
|
backgroundColor: 'yellow',
|
|
},
|
|
},
|
|
},
|
|
View,
|
|
{ xs: false }
|
|
)
|
|
// xs is not active, so neither the outer nor nested styles apply
|
|
expect(result.style?.backgroundColor).toBeUndefined()
|
|
})
|
|
})
|
|
|
|
describe('media query nested inside platform query', () => {
|
|
test('$platform-android with nested $xs applies on Android when xs is active', () => {
|
|
const result = getSplitStylesFor(
|
|
{
|
|
'$platform-android': {
|
|
backgroundColor: 'green',
|
|
$xs: {
|
|
backgroundColor: 'red',
|
|
},
|
|
},
|
|
},
|
|
View,
|
|
{ xs: true }
|
|
)
|
|
// Both conditions met: platform is Android + xs is active
|
|
// Nested media query overrides the outer value
|
|
expect(result.style?.backgroundColor).toBe('red')
|
|
})
|
|
|
|
test('$platform-android with nested $xs does NOT apply when xs is inactive', () => {
|
|
const result = getSplitStylesFor(
|
|
{
|
|
'$platform-android': {
|
|
backgroundColor: 'green',
|
|
$xs: {
|
|
backgroundColor: 'red',
|
|
},
|
|
},
|
|
},
|
|
View,
|
|
{ xs: false }
|
|
)
|
|
// Platform matches but xs is not active
|
|
// Only the outer $platform-android style applies
|
|
expect(result.style?.backgroundColor).toBe('green')
|
|
})
|
|
|
|
test('$platform-ios with nested $xs does NOT apply on Android', () => {
|
|
const result = getSplitStylesFor(
|
|
{
|
|
'$platform-ios': {
|
|
backgroundColor: 'green',
|
|
$xs: {
|
|
backgroundColor: 'red',
|
|
},
|
|
},
|
|
},
|
|
View,
|
|
{ xs: true }
|
|
)
|
|
// Platform doesn't match, nothing applies
|
|
expect(result.style?.backgroundColor).toBeUndefined()
|
|
})
|
|
})
|
|
|
|
describe('interchangeable nesting — both directions used together', () => {
|
|
test('last-declared nested style wins when both conditions are met', () => {
|
|
const result = getSplitStylesFor(
|
|
{
|
|
$xs: {
|
|
backgroundColor: 'orange',
|
|
'$platform-android': {
|
|
backgroundColor: 'yellow',
|
|
},
|
|
},
|
|
'$platform-android': {
|
|
backgroundColor: 'green',
|
|
$xs: {
|
|
backgroundColor: 'red',
|
|
},
|
|
},
|
|
},
|
|
View,
|
|
{ xs: true }
|
|
)
|
|
// Both nesting directions have their conditions met and produce
|
|
// identical importance (symmetric). Since $platform-android is declared
|
|
// last in the props object, its nested $xs wins by declaration order.
|
|
expect(result.style?.backgroundColor).toBe('red')
|
|
})
|
|
|
|
test('non-nested properties from both apply independently', () => {
|
|
const result = getSplitStylesFor(
|
|
{
|
|
$xs: {
|
|
opacity: 0.5,
|
|
'$platform-android': {
|
|
zIndex: 5,
|
|
},
|
|
},
|
|
'$platform-android': {
|
|
zIndex: 10,
|
|
$xs: {
|
|
flex: 1,
|
|
},
|
|
},
|
|
},
|
|
View,
|
|
{ xs: true }
|
|
)
|
|
// All conditions met — all properties should apply
|
|
expect(result.style?.opacity).toBe(0.5)
|
|
// zIndex is set in both nested contexts: $xs.$platform-android (5) and
|
|
// $platform-android non-nested (10). The nested value (5) has higher
|
|
// importance than the non-nested outer value, so 5 wins.
|
|
expect(result.style?.zIndex).toBe(5)
|
|
expect(result.style?.flex).toBe(1)
|
|
})
|
|
})
|
|
|
|
describe('shorthand expansion in nested queries', () => {
|
|
test('shorthands in nested platform query are expanded correctly', () => {
|
|
const result = getSplitStylesFor(
|
|
{
|
|
$xs: {
|
|
'$platform-android': {
|
|
bg: 'yellow',
|
|
},
|
|
},
|
|
},
|
|
View,
|
|
{ xs: true }
|
|
)
|
|
// 'bg' shorthand should be expanded to 'backgroundColor'
|
|
expect(result.style?.backgroundColor).toBe('yellow')
|
|
})
|
|
|
|
test('shorthands in nested media query are expanded correctly', () => {
|
|
const result = getSplitStylesFor(
|
|
{
|
|
'$platform-android': {
|
|
$xs: {
|
|
bg: 'red',
|
|
},
|
|
},
|
|
},
|
|
View,
|
|
{ xs: true }
|
|
)
|
|
// 'bg' shorthand should be expanded to 'backgroundColor'
|
|
expect(result.style?.backgroundColor).toBe('red')
|
|
})
|
|
})
|
|
})
|