TachUI Assets System
The Assets system provides a unified way to manage theme-adaptive resources including colors, images, and other design assets in TachUI. It's designed to be similar to SwiftUI's asset management system while leveraging TachUI's reactive architecture.
Features
- Theme-Adaptive Assets: Automatically adapt to light/dark mode
- Dot Notation Access: Clean, intuitive API (
Assets.primaryColor) - Explicit Theme Access: Force specific theme variants (
Assets.primaryColor.light) - Extensible: Support for custom asset types beyond colors and images
- TypeScript Support: Full type safety with proper interfaces
- Performance: Efficient proxy-based access with caching
Usage
Basic Usage
import { Assets, registerAsset, ColorAsset } from '@tachui/core/assets'
// Register custom assets - NEW simplified API (recommended)
registerAsset(ColorAsset.init({
default: '#007AFF',
light: '#007AFF',
dark: '#0A84FF',
name: 'primaryColor'
}))
registerAsset(ColorAsset.init({
default: '#FFFFFF',
light: '#FFFFFF',
dark: '#1a1a1a',
name: 'backgroundColor'
}))
// Use assets in components
import { Text } from '@tachui/core/components'
export function MyComponent() {
return Text('Hello World')
.modifier
.foregroundColor(Assets.primaryColor) // Auto-adapts to current theme
.backgroundColor(Assets.backgroundColor)
.build()
}Explicit Theme Access
// Always use light variant
Text('Always Light').modifier.foregroundColor(Assets.primaryColor.light)
// Always use dark variant
Text('Always Dark').modifier.foregroundColor(Assets.primaryColor.dark)Image Assets
import { ImageAsset } from '@tachui/core/assets'
// Register image assets - NEW simplified API (recommended)
registerAsset(ImageAsset.init({
default: '/logo-light.png',
light: '/logo-light.png',
dark: '/logo-dark.png',
name: 'logo'
}))
// Use in components
import { Image } from '@tachui/core/components'
export function LogoComponent() {
return Image(Assets.logo) // Auto-adapts to current theme
.modifier
.frame(100, 50)
.build()
}Built-in System Assets
TachUI provides built-in system colors that match SwiftUI's color system:
// System colors
Assets.systemBlue // #007AFF (light) / #0A84FF (dark)
Assets.systemGreen // #34C759 (light) / #30D158 (dark)
Assets.systemRed // #FF3B30 (light) / #FF453A (dark)
Assets.systemOrange // #FF9500 (light) / #FF9F0A (dark)
Assets.systemPurple // #5856D6 (light) / #5E5CE6 (dark)
Assets.systemPink // #FF2D55 (light) / #FF375F (dark)
Assets.systemGray // #8E8E93 (both)
Assets.systemBlack // #000000 (both)
Assets.systemWhite // #FFFFFF (both)Creating Custom Assets
Color Assets
import { ColorAsset } from '@tachui/core/assets'
// NEW simplified API (recommended)
registerAsset(ColorAsset.init({
default: '#FF6B35',
light: '#FF6B35',
dark: '#FF8E6B',
name: 'brandPrimary'
}))
// OR create and register separately (legacy approach)
const brandPrimary = ColorAsset.init({
default: '#FF6B35',
light: '#FF6B35',
dark: '#FF8E6B',
name: 'brandPrimary'
})
registerAsset(brandPrimary)
// Use it
Assets.brandPrimary // Auto-adapts
Assets.brandPrimary.light // Always light
Assets.brandPrimary.dark // Always darkImage Assets
import { ImageAsset } from '@tachui/core/assets'
// NEW simplified API (recommended)
registerAsset(ImageAsset.init({
default: '/hero-light.jpg',
light: '/hero-light.jpg',
dark: '/hero-dark.jpg',
name: 'heroImage',
options: {
alt: 'Hero banner image',
placeholder: '/placeholder.jpg'
}
}))
// OR create and register separately (legacy approach)
const heroImage = ImageAsset.init({
default: '/hero-light.jpg',
light: '/hero-light.jpg',
dark: '/hero-dark.jpg',
name: 'heroImage',
options: {
alt: 'Hero banner image',
placeholder: '/placeholder.jpg'
}
})
registerAsset(heroImage)
// Use it
Assets.heroImage // Auto-adapts
Assets.heroImage.lightSrc // Always light source
Assets.heroImage.darkSrc // Always dark sourceFont Assets
Font management is a crucial part of the Assets system. TachUI provides comprehensive font loading with FontAsset:
import { FontAsset, createGoogleFont } from '@tachui/core/assets'
// NEW simplified API (recommended)
registerAsset(FontAsset.init(
'MyFont',
['Arial', 'sans-serif'],
'myFont',
{ fontUrl: '/fonts/myfont.woff2' }
))
// Use Google Fonts - simplified
registerAsset(createGoogleFont('Inter', [400, 600, 700], 'inter'))
// OR create and register separately (legacy approach)
const customFont = FontAsset.init(
'MyFont',
['Arial', 'sans-serif'],
'myFont',
{ fontUrl: '/fonts/myfont.woff2' }
)
const inter = createGoogleFont('Inter', [400, 600, 700], 'inter')
registerAsset(customFont)
registerAsset(inter)
Text("Custom Typography")
.modifier
.font({ family: Assets.inter })
.build()For comprehensive font documentation, see the Font Assets Guide.
Integration with Modifiers
The Assets system seamlessly integrates with TachUI's modifier system:
import { appearanceModifiers } from '@tachui/core/modifiers/core'
// Use assets with modifiers
const colorModifier = appearanceModifiers.foregroundColor(Assets.primaryColor)
const backgroundModifier = appearanceModifiers.backgroundColor(Assets.backgroundColor)Advanced Usage
Asset Bundles
For better organization, you can create logical groupings of assets:
// Create semantic color bundles - NEW simplified API
registerAsset(ColorAsset.init({
default: '#1a1a1a',
light: '#1a1a1a',
dark: '#ffffff',
name: 'textPrimary'
}))
registerAsset(ColorAsset.init({
default: '#666666',
light: '#666666',
dark: '#cccccc',
name: 'textSecondary'
}))
registerAsset(ColorAsset.init({
default: '#FFFFFF',
light: '#FFFFFF',
dark: '#1a1a1a',
name: 'backgroundPrimary'
}))
registerAsset(ColorAsset.init({
default: '#f8f9fa',
light: '#f8f9fa',
dark: '#2a2a2a',
name: 'backgroundSecondary'
}))Custom Asset Types
You can extend the system with custom asset types:
import { Asset } from '@tachui/core/assets'
class GradientAsset extends Asset {
constructor(
public readonly lightGradient: string,
public readonly darkGradient: string,
name: string
) {
super(name)
}
resolve(): string {
return getCurrentTheme() === 'dark' ? this.darkGradient : this.lightGradient
}
}
// Register custom asset - NEW simplified API
registerAsset(new GradientAsset(
'linear-gradient(to right, #007AFF, #5856D6)',
'linear-gradient(to right, #0A84FF, #5E5CE6)',
'primaryGradient'
))API Improvements (v2.1)
Simplified Asset Registration
TachUI now supports a streamlined asset registration API that eliminates duplicate naming:
// ✅ NEW: Simplified - no duplicate name required
registerAsset(ColorAsset.init({
default: '#007AFF',
light: '#007AFF',
dark: '#0A84FF',
name: 'systemBlue' // Name specified once here
}))
// ✨ NEW: Override the asset's internal name
registerAsset(ColorAsset.init({
default: '#007AFF',
light: '#007AFF',
dark: '#0A84FF',
name: 'internalBlue'
}), 'customBlue') // Public name differs from internal name
// 🔄 OLD: Still supported for backward compatibility
registerAsset('systemBlue', ColorAsset.init({
default: '#007AFF',
light: '#007AFF',
dark: '#0A84FF',
name: 'systemBlue' // Name duplicated
}))Benefits:
- DRY Principle: No more duplicate name specification
- Less Error-Prone: Name mismatch between asset and registration is impossible
- Backward Compatible: Existing code continues to work
- Consistent: Works for ColorAsset, FontAsset, ImageAsset, and custom Asset types
Function Overloading: The registerAsset function now supports three signatures:
registerAsset(asset: Asset)- NEW: Uses asset.name automaticallyregisterAsset(asset: Asset, overrideName?: string)- NEW: Override the asset's internal nameregisterAsset(name: string, asset: Asset)- Legacy: Explicit name specification
Override Name Example:
const brandColor = ColorAsset.init({
default: '#FF6B35',
light: '#FF6B35',
dark: '#FF8E6B',
name: 'internalBrandName' // Internal name
})
// Register with a different public name
registerAsset(brandColor, 'primaryBrand')
// Now accessible via the override name
Assets.primaryBrand // ✅ Available
Assets.internalBrandName // ❌ Not availableBenefits
- SwiftUI Familiarity: Developers familiar with SwiftUI will feel at home
- Automatic Theme Adaptation: Colors automatically switch between light/dark modes
- Semantic Naming: Clear, purpose-driven asset names
- Global Access: Centralized asset definitions that can be imported anywhere
- Type Safety: Full TypeScript support with proper interfaces
- Performance: Reactive updates only when theme changes
- Flexibility: Developers can define custom palettes while using standard assets
Enhanced Features (v2.0)
Color Format Validation
TachUI now automatically validates color formats when creating ColorAssets, ensuring reliability:
import { ColorAsset } from '@tachui/core/assets'
// These will work fine
const validHex = ColorAsset.init('#FF0000', '#00FF00', 'validHex')
const validRgb = ColorAsset.init('rgb(255, 0, 0)', 'rgb(0, 255, 0)', 'validRgb')
const validHsl = ColorAsset.init('hsl(0, 100%, 50%)', 'hsl(120, 100%, 50%)', 'validHsl')
// This will throw an error
try {
const invalid = ColorAsset.init('invalid-color', '#000000', 'invalid')
} catch (error) {
console.log(error.message) // "Invalid light color format for asset 'invalid': Unsupported color format..."
}Supported color formats:
- Hex:
#FF0000,#F00,#FF000080(with alpha) - RGB:
rgb(255, 0, 0) - RGBA:
rgba(255, 0, 0, 0.5) - HSL:
hsl(360, 100%, 50%) - HSLA:
hsla(360, 100%, 50%, 0.8) - Named colors:
red,blue,transparent, etc. - CSS custom properties:
var(--primary-color)
Asset Discovery & Debugging
New debugging tools help you inspect registered assets:
import { getAssetInfo, listAssetNames } from '@tachui/core/assets'
// Get all asset names
const assetNames = listAssetNames()
console.log(assetNames) // ['systemBlue', 'systemGreen', 'myCustomColor', ...]
// Get detailed asset information
const assetInfos = getAssetInfo()
console.log(assetInfos)
// [
// { name: 'systemBlue', type: 'color', asset: ColorAsset {...} },
// { name: 'myLogo', type: 'image', asset: ImageAsset {...} },
// { name: 'customAsset', type: 'custom', asset: CustomAsset {...} }
// ]Enhanced TypeScript Support
Full type safety with proper interfaces:
import { Assets, AssetsInterface, ColorAssetProxy } from '@tachui/core/assets'
// Assets now has proper TypeScript typing
const color: ColorAssetProxy = Assets.systemBlue
// Type-safe access to all variants
color.light // string - always light variant
color.dark // string - always dark variant
color.resolve() // string - current theme variant
color.toString() // string - current theme variant (implicit conversion)Implementation Details
The Assets system uses JavaScript Proxies to enable the clean dot notation API while providing automatic theme adaptation. Assets are resolved reactively based on the current theme, ensuring consistent appearance across your application.
Color Validation Process
When creating ColorAssets, the system validates both light and dark color values using comprehensive regex patterns and value range checking. Invalid colors throw descriptive errors immediately, preventing runtime issues.
Asset Discovery Implementation
The discovery system provides both simple name listing and detailed asset information, making it easy to debug asset registration and understand what assets are available in your application.