Skip to content

Utilities

Builds a CSS class string from mixed input types.

function classes(...args: (string | string[] | Record<string, boolean>)[]): string
TypeBehavior
stringSplit by spaces, validated, and appended
string[]Each string validated and appended
objectKeys with truthy values are validated and appended. Values can be booleans or functions returning booleans.
  • Validates CSS class names (alphanumeric, hyphens, underscores)
  • Deduplicates class names
  • Throws on invalid class names
import { classes } from 'sygnal'
classes('btn', 'primary')
// → 'btn primary'
classes('btn', { active: true, disabled: false })
// → 'btn active'
classes(['card', 'shadow'], { highlighted: isHighlighted })
// → 'card shadow highlighted' (when isHighlighted is truthy)
classes({ visible: () => checkVisibility() })
// → 'visible' (when checkVisibility() returns truthy)

Creates a typed state assertion function for TypeScript. Ensures state objects match the expected type exactly, with no extra properties.

function exactState<STATE>(): <ACTUAL extends STATE>(state: ExactShape<STATE, ACTUAL>) => STATE
import { exactState } from 'sygnal'
type AppState = { count: number; name: string }
const asAppState = exactState<AppState>()
App.model = {
UPDATE: (state) => asAppState({ count: 1, name: 'test' })
// TypeScript error: asAppState({ count: 1, name: 'test', extra: true })
}

Alternative HMR setup function (wraps the manual import.meta.hot / module.hot pattern).

function enableHMR(
app: SygnalApp,
hot: HotModuleAPI,
loadComponent?: () => Promise<AnyComponentModule> | AnyComponentModule,
acceptDependencies?: string | string[]
): SygnalApp
ParameterTypeDescription
appSygnalAppThe return value from run()
hotHotModuleAPIimport.meta.hot (Vite) or module.hot (Webpack)
loadComponentFunctionOptional function to load the updated component
acceptDependenciesstring | string[]Module paths to watch for changes

A special constant that, when returned from a state reducer, cancels the state update for that action.

const ABORT: unique symbol
import { ABORT } from 'sygnal'
MyComponent.model = {
MOVE: (state, data) => {
if (state.locked) return ABORT // No state change
return { ...state, position: data }
}
}