0.0.2 • Published 3 years ago

fluent-classnames v0.0.2

Weekly downloads
-
License
MIT
Repository
github
Last release
3 years ago

fluent-classnames

NPM version NPM Weekly Downloads License

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>
</>

Peek 2021-04-27 20-42

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 as name, call or apply) can mess in typescript autocomplete (but it still works even if you have such classes). TS issue
0.0.2

3 years ago

0.0.1

3 years ago