TriFrost

TriFrost 0.26.0

|peterver

News

This release brings deeper composition and sharper ergonomics to the css engine. css.mix and css.use now apply a union-style deep merge, preserving media queries and nested overrides across layers — perfect for atom/molecule composition in JSX.

Selector normalization gets even smarter: combinators, HTML tags, and pseudo-prefixed selectors now auto-space with better contextual awareness. If you’ve used the spacing behavior before, this update makes it even more intelligent, reducing friction in complex nesting scenarios.

We're also bumping the valkyrie utils to 12.40.0 (valkyrie utils is also created by the creator of TriFrost), this version brings meaningful performance improvements for omit/merge/formdata conversion, all of which are used in core parts of TriFrost.

Improved

  • feat: Further enhanced selector normalization with intelligent auto-spacing. Selectors that begin with combinators (>, +, ~), known HTML tags (e.g. div, section) or known HTML tags followed by : (pseudo), . (class), or space . Are now automatically prefixed with a space during normalization. This ensures correct contextual matching in nested style blocks, safer output in deeply composed rules, less manual effort and cleaner style declarations. For Example:
css({
  section: {padding: '1rem'}, // auto-space => ' section'
  div:hover: {color: 'red'},   // auto-space => ' div:hover'
  'a.active' {textDecoration: 'underline'}, // auto-space => ' a.active'
  'ul li': {fontSize: '1.6rem'}, // auto-space => ' ul li'
  '#hero': {fontWeight: 'bold'}, // NOT auto-spaced => '#hero'
});
  • feat: Enhanced css.mix and css.use to support union-style deep merges. This change enables more powerful style composition patterns, particularly beneficial for JSX-based atomic/molecular components. Nested structures like responsive breakpoints or selector-based overrides are now preserved during merging. For example:
import {css} from './css'; /* Your css factory instance */

type ButtonProps = {
  title: string;
  style?: Record<string, unknown>;
};

export function Button({title, style = {}}: ButtonProps) {
  return (<button
    type="button"
    className={css.use(
        css.mix({
          padding: '1rem 1.5rem',
          borderRadius: css.$v.rad_m,
          fontSize: css.$v.font_s_button,
          border: 'none',
          [css.media.mobile]: {
            padding: '.5rem 1rem',
            borderRadius: css.$v.rad_s,
          },
        },
        style
    ))}
  >{title}</button>);
}

export function SmallButton({title, style = {}}: ButtonProps) {
  return (<Button
    title={title}
    style={css.mix({
      fontSize: `calc(${css.$v.font_s_button} - .2rem)`,
      [css.media.mobile]: {
        padding: '.5rem',
      },
    }, style)}
  />);
}

export function BlueSmallButton({title, style = {}}: ButtonProps) {
  /**
   * Eventual Styles
   * {
   *  padding: '1rem 1.5rem',
   *  borderRadius: '12px',
   *  fontSize: 'calc(1rem - .2rem)',
   *  border: 'none',
   *  background: 'blue',
   *  color: 'white',
   *   [css.media.mobile]: {
   *     padding: '.5rem',
   *     borderRadius: '8px',
   *   },
   * }
   */
  return (<SmallButton
    title={title}
    style={css.mix({
      background: 'blue',
      color: 'white',
    }, style)}
  />);
}

export function RedSmallButton({title, style = {}}: ButtonProps) {
  /**
   * Eventual Styles
   * {
   *  padding: '1rem 1.5rem',
   *  borderRadius: '12px',
   *  fontSize: 'calc(1rem - .2rem)',
   *  border: 'none',
   *  background: 'red',
   *  color: 'white',
   *  [css.media.mobile]: {
   *    padding: '.5rem',
   *    borderRadius: '8px',
   *  },
   * }
   */
  return (<SmallButton
    title={title}
    style={css.mix({
      background: 'red',
      color: 'white',
    }, style)}
  />);
}
  • deps: Upgrade @cloudflare/workers-types to 4.20250605.0
  • deps: Upgrade @valkyriestudios/utils to 12.40.0

Smarter styles. Still frosty. ❄️

Loved the read? Share it with others