Skip to content

swiss-ui/utils

Repository files navigation

@swiss-ui/utils

JavaScript/TypeScript utilities for Swiss UI design system.

Installation

npm install @swiss-ui/utils

Modules

cn — Class name merging

Merges CSS class names with support for strings, conditional objects, arrays, and falsy values.

import { cn } from '@swiss-ui/utils/cn'

cn('btn', 'btn--primary')
// 'btn btn--primary'

cn('btn', { 'btn--active': isActive, 'btn--disabled': false })
// 'btn btn--active'  (if isActive is true)

cn('btn', ['btn--sm', undefined, false])
// 'btn btn--sm'

tokens — CSS Custom Properties helpers

Read, write, and generate overrides for design tokens.

import { getCssVar, setCssVar, createThemeVars } from '@swiss-ui/utils/tokens'
import type { SwissToken } from '@swiss-ui/utils/tokens'

// Read computed value at runtime
const primary = getCssVar('--color-text-primary')

// Set on :root
setCssVar('--color-background-primary', '#ffffff')

// Set on a specific element
setCssVar('--color-text-primary', '#000000', myElement)

// Generate inline styles for token overrides
const style = createThemeVars({
  '--color-text-primary': '#1a1a1a',
  '--color-background-primary': '#f5f5f5',
})
// Use as: <div style={style}>...</div>

variants — Component variant resolver

CVA-inspired helper for building type-safe component variants. No dependencies.

import { swiss } from '@swiss-ui/utils/variants'

const button = swiss({
  base: 'swiss-button',
  variants: {
    size: {
      sm: 'swiss-button--sm',
      md: 'swiss-button--md',
      lg: 'swiss-button--lg',
    },
    variant: {
      primary: 'swiss-button--primary',
      ghost: 'swiss-button--ghost',
    },
  },
  compoundVariants: [
    { size: 'sm', variant: 'ghost', class: 'swiss-button--sm-ghost' },
  ],
  defaultVariants: { size: 'md', variant: 'primary' },
})

button()                              // 'swiss-button swiss-button--md swiss-button--primary'
button({ size: 'sm' })               // 'swiss-button swiss-button--sm swiss-button--primary'
button({ size: 'sm', variant: 'ghost' }) // includes 'swiss-button--sm-ghost'

responsive — Breakpoint utilities

Framework-agnostic media query helpers. SSR-safe.

import {
  createMediaQuery,
  matchesBreakpoint,
  onBreakpointChange,
} from '@swiss-ui/utils/responsive'
import type { SwissBreakpoint } from '@swiss-ui/utils/responsive'

// Get a media query string
createMediaQuery('md') // '(min-width: 768px)'

// Synchronous viewport check
if (matchesBreakpoint('lg')) {
  // desktop layout
}

// Subscribe to breakpoint changes
const unsubscribe = onBreakpointChange('md', (matches) => {
  console.log('md breakpoint active:', matches)
})

// Later:
unsubscribe()

Available breakpoints: sm (640px), md (768px), lg (1024px), xl (1280px), 2xl (1536px).

a11y — Accessibility utilities

import {
  generateId,
  getFocusableElements,
  focusTrap,
  isReducedMotion,
} from '@swiss-ui/utils/a11y'

// Generate unique IDs for aria attributes
const labelId = generateId('dialog')  // 'dialog-1'
const descId = generateId()           // 'swiss-2'

// Get all focusable elements inside a container
const focusable = getFocusableElements(modalElement)

// Trap focus inside a modal
const trap = focusTrap(modalElement)
trap.activate()   // moves focus to first focusable element
trap.deactivate() // returns focus to previously focused element

// Respect user motion preferences
if (!isReducedMotion()) {
  startAnimation()
}

dom — DOM helpers

import { setDataTheme, getDataTheme, toggleDataTheme } from '@swiss-ui/utils/dom'

// Set theme
setDataTheme('dark')             // sets data-theme="dark" on :root
setDataTheme('light', myElement) // sets on a specific element

// Read current theme
getDataTheme()         // 'dark' | 'light' | null
getDataTheme(myElement)

// Toggle theme
const newTheme = toggleDataTheme()  // returns 'light' | 'dark'

Tree-shaking

Each module is a separate entry point. Import only what you use:

import { cn } from '@swiss-ui/utils/cn'
import { swiss } from '@swiss-ui/utils/variants'
import { getCssVar } from '@swiss-ui/utils/tokens'

Or import everything from the main entry (bundlers will tree-shake unused exports):

import { cn, swiss, getCssVar } from '@swiss-ui/utils'

License

AGPL-3.0-only

About

JavaScript/TypeScript utilities for Swiss UI design system.

Topics

Resources

License

Stars

Watchers

Forks

Contributors