npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fluixi-ui/fx

v0.1.0-alpha.3

Published

Token-aware style objects for the Fluixi UI ecosystem — the `fx` prop engine

Readme

@fluixi-ui/fx

Token-aware style objects for Fluixi UI — the engine behind the fx prop.

<Box fx={{ p: 4, bg: 'bgSubtle', radius: 'lg', _hover: { bg: 'bgMuted' } }} />

No CSS-in-JS runtime, no dependencies. Values resolve to the --flx-ui-* custom properties @fluixi-ui/tokens defines, so anything written with fx follows the theme, the accent, and the skin — including a theme driven from @fluixi-css.

Values

A property's scale decides both which tokens a string key resolves against and what a bare number means:

p: 3          // padding: var(--flx-ui-space-3)   — space scale
m: -2         // margin: calc(var(--flx-ui-space-2) * -1)
width: 240    // width: 240px                     — sizing is pixels
zIndex: 3     // z-index: 3                       — unitless stays bare
radius: 'lg'  // border-radius: var(--flx-ui-radius-lg)
bg: 'primary' // background-color: var(--flx-ui-color-primary)
bg: 'accent-9'// background-color: var(--flx-ui-accent-9)
bg: '#ff0000' // background-color: #ff0000        — raw CSS always allowed

Aliases are deliberately few — p px py m mx my bg radius shadow. Everything else is the real CSS property name (paddingTop, not pt), so there's no table to learn. px/py map to the logical properties and follow writing direction.

Selectors

A closed set of _-prefixed keys. They expand to the library's real conventions, not just the CSS pseudo — headless parts signal state through data-*/ARIA:

_disabled: { opacity: 'disabled' }
// :disabled, [disabled], [data-disabled]

State: _hover _active _focus _focusVisible _focusWithin _disabled _checked _selected _expanded _open _invalid Pseudo-elements: _before _after _placeholder _selection Structural: _first _last _odd _even _notFirst _notLast _children Environment: _dark _light _hc _rtl _motionReduce _motionSafe

_dark targets [data-theme='dark'] — the axis createTheme drives — and matches the element itself as well as a themed ancestor, so scoped theming works.

The set being closed is the point: fx can't reach an app's class names, so a component can never couple itself to consumer CSS.

Nesting composes:

_dark: { _hover: { bg: 'primaryHover' } }

Responsive

Mobile-first objects keyed by breakpoint. base carries no media query:

fx={{ p: { base: 3, md: 5 } }}

Container queries

Respond to the space a component is actually given rather than the viewport. The container is an ancestor — an element can't query itself:

<Card fx={{ containerType: 'inline-size' }}>
  <Stack fx={{ _container: { md: { flexDirection: 'row' } } }} />
</Card>

Keys are a breakpoint name or a raw condition. Element-relative sizes often don't line up with the page scale, so raw conditions are first-class:

_container: { '(min-width: 30rem)': { gap: 4 } }

Name a container when the nearest one isn't the one you mean:

<aside fx={{ containerType: 'inline-size', containerName: 'panel' }}>
  <div fx={{ _container: { name: 'panel', lg: { p: 6 } } }} />
</aside>

At-rules nest rather than combine, so a container query and a media query can wrap the same declarations.

Colour

Helpers emit CSS; they never compute a colour in JS. That matters here: tokens are custom properties that re-resolve against data-theme / data-accent, so a value computed at render would freeze whichever theme happened to be active. color-mix() and relative colour syntax re-resolve on their own, so a derived colour keeps following the theme, the accent and the skin.

import { alpha, mix, lighten, darken } from '@fluixi-ui/fx';

alpha('primary', 12)      // color-mix(in oklab, var(--flx-ui-color-primary) 12%, transparent)
mix('primary', 'bg', 20)  // 20% primary over the page background
lighten('primary', 8)     // oklch(from … calc(l + 0.08) c h / alpha)
darken('border', 10)

Every amount is a percentage, 0–100. lighten/darken shift lightness in OKLCH, which keeps chroma and hue — a tint stays the same colour instead of drifting grey the way mixing with white or black does. They need relative colour syntax (Chrome 119+, Safari 16.4+, Firefox 128+); for a wider floor use mix(color, 'white', n).

How it lands on the page

Flat declarations and every base value go to the style attribute — most fx usage never touches the stylesheet. Only selector keys and non-base breakpoints need a rule; those are hashed, deduped, and inserted under [data-fx="…"] into @layer flx.fx, which sits above components and skins so fx wins, and below unlayered consumer CSS so an app can still override it.

Server rendering

Inline declarations need nothing. For the rule tier, emit what was collected:

const { css, tokens } = collectFx();
`<style data-fx-sheet data-fx-tokens="${tokens}">${css}</style>`;

The client adopts that sheet instead of re-inserting its rules.

Composing

mergeFx folds a component's own styling, its sp entries, and the consumer's fx into one object — later wins per property, selector blocks and breakpoint records merge rather than replace:

resolveFx(mergeFx(componentOwn, sp.body?.fx, props.fx));

A compound component reaches its parts with slot, which takes both channels: the part's own sp entry, and the styles a caller addressed to it through fx.sp.

<PageBody {...slot('body', local.fx, local.sp)} />

Binding it to an element

const [local, others] = splitProps(props, ['fx', 'style']);
return <div {...fxProps(() => local.fx, () => local.style)} {...others} />;

Pass accessors, not values. The resolve runs inside a memo, so a reactive fx updates without re-rendering. A style prop is merged last and stays raw CSS — no token resolution — so it remains the lowest-level escape hatch.

License

MIT