fluent-classnames
v0.0.2
Published
Less verbose (and more fluent!) version of classnames
Downloads
7
Readme
fluent-classnames
fluent-classnames (short to fcn) is less verbose (and more fluent!) version of classnames.
It supports CSS modules out-of-box, and also give you fully-typed experience with vanilla-extract!
Installation
yarn add fluent-classnames
npm install fluent-classnames
Usage and side-to-side with classnames
Given such styles:
.simple {
background: blue;
cursor: pointer;
}
.active {
background: green;
}
.disabled {
background: none;
color: gray;
cursor: default;
}
There is simple react component with global styles:
import React from 'react'
import cn from 'classnames'
//simple auto-import! Just types fcn and IDE will find it for you
import {fcn} from 'fluent-classnames'
const SomeItem: React.FC<{isActive?: boolean, isDisabled?: boolean}> = ({isActive, isDisabled}) => <>
<div className={cn('simple', {active: isActive, disabled: isDisabled})}>classnames</div>
<div className={fcn(s => s.simple.active(isActive).disabled(isDisabled))}>Cooler classnames!</div>
</>
Less verbose, but not really shorter? So, let's look at CSS modules example:
import React from 'react'
import cn from 'classnames'
//simple auto-import! Just types fcn and IDE will find it for you
import {fcn} from 'fluent-classnames'
import S from './styles.module.css'
const SomeItem: React.FC<{isActive?: boolean, isDisabled?: boolean}> = ({isActive, isDisabled}) => <>
<div className={cn(S.simple, {[S.active]: isActive, [S.disabled]: isDisabled})}>classnames</div>
<div className={fcn(S, s => s.simple.active(isActive).disabled(isDisabled))}>Cooler classnames!</div>
</>
Ahh, much better, and it will be even better with longer classes chain!
Also, fcn will check for class existing in CSS module map and throws if it's not exists - no more undefined in class
.
There is curried form for simplicity (and some performance) sake:
import {fcn} from 'fluent-classnames'
import S from './styles.module.css'
const cn = fcn(S)
cn(s => s.simple.active(isActive).disabled(isDisabled))
cn(s => s.simple)
cn(s => s.simple.disabled)
And with vanilla-extract
whole selector function is fully-typed and even prevents classes duplication:
// styles.css.ts
import { style } from '@vanilla-extract/css'
export const simple = style({
background: 'blue',
cursor: 'pointer',
})
export const active = style({
background: 'green',
})
export const disabled = style({
background: 'none',
color: 'gray',
cursor: 'default',
})
import React from 'react'
import cn from 'classnames'
import { fcn } from 'fluent-classnames'
import * as S from './styles.css'
const SomeItem: React.FC<{isActive?: boolean, isDisabled?: boolean}> = ({isActive, isDisabled}) => <>
<div className={cn(S.simple, {[S.active]: isActive, [S.disabled]: isDisabled})}>classnames</div>
<div className={fcn(S, s => s.simple.active(isActive).disabled(isDisabled))}>Cooler classnames!</div>
</>
Browsers support
fcn
uses Proxy
when it is available, but fallback to simple getters on old environments with module classes.
It not works in global classes without proxy!
Gotchas
- Methods and attributes from
Function
prototype (such asname
,call
orapply
) can mess in typescript autocomplete (but it still works even if you have such classes). TS issue