classnames
Advanced tools
Comparing version 2.3.2 to 2.3.3
@@ -7,4 +7,12 @@ import { ArgumentArray } from './index.js'; | ||
declare function classNames(this: classNames.Binding | undefined, ...args: ArgumentArray): string; | ||
interface ClassNames { | ||
(this: classNames.Binding | undefined, ...args: ArgumentArray): string; | ||
default: ClassNames; | ||
} | ||
declare const classNames: ClassNames; | ||
export as namespace classNames; | ||
export = classNames; |
import classNames = require('./index.js'); | ||
export as namespace classNames; | ||
export = classNames; |
# Changelog | ||
## v2.3.3 / 2023-12-21 | ||
- Fix default export, thanks [Remco Haszing](https://github.com/remcohaszing) ([#301](https://github.com/JedWatson/classnames/pull/301)) | ||
- Fix types for read-only arrays, thanks [Ben Thompson](https://github.com/BenGearset) ([#307](https://github.com/JedWatson/classnames/pull/307)) | ||
- Replace README examples with functional-style components, thanks [JoeDGit](https://github.com/JoeDGit) ([#303](https://github.com/JedWatson/classnames/pull/303)) | ||
## v2.3.2 / 2022-09-13 | ||
@@ -4,0 +10,0 @@ |
@@ -15,10 +15,19 @@ // LICENSE is MIT | ||
interface ArgumentArray extends Array<Argument> {} | ||
type Argument = Value | Mapping | ArgumentArray; | ||
interface ReadonlyArgumentArray extends ReadonlyArray<Argument> {} | ||
type Argument = Value | Mapping | ArgumentArray | ReadonlyArgumentArray; | ||
} | ||
interface ClassNames { | ||
(...args: classNames.ArgumentArray): string; | ||
default: ClassNames; | ||
} | ||
/** | ||
* A simple JavaScript utility for conditionally joining classNames together. | ||
*/ | ||
declare function classNames(...args: classNames.ArgumentArray): string; | ||
declare const classNames: ClassNames; | ||
export as namespace classNames; | ||
export = classNames; |
@@ -12,3 +12,2 @@ /*! | ||
var hasOwn = {}.hasOwnProperty; | ||
var nativeCodeString = '[native code]'; | ||
@@ -15,0 +14,0 @@ function classNames() { |
{ | ||
"name": "classnames", | ||
"version": "2.3.2", | ||
"version": "2.3.3", | ||
"description": "A simple utility for conditionally joining classNames together", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
157
README.md
@@ -1,23 +0,21 @@ | ||
Classnames | ||
=========== | ||
# Classnames | ||
[![NPM version](https://badgen.net/npm/v/classnames)](https://www.npmjs.com/package/classnames) | ||
![Node.js CI](https://github.com/JedWatson/classnames/workflows/Node.js%20CI/badge.svg) | ||
[![NPM Weekly Downloads](https://badgen.net/npm/dw/classnames)](https://www.npmjs.com/package/classnames) | ||
[![License](https://badgen.net/npm/license/classnames)](https://www.npmjs.com/package/classnames) | ||
[![Supported by Thinkmill](https://thinkmill.github.io/badge/heart.svg)](https://thinkmill.com.au/?utm_source=github&utm_medium=badge&utm_campaign=classnames) | ||
> A simple JavaScript utility for conditionally joining classNames together. | ||
A simple JavaScript utility for conditionally joining classNames together. | ||
<p> | ||
<a aria-label="NPM version" href="https://www.npmjs.com/package/classnames"> | ||
<img alt="" src="https://img.shields.io/npm/v/classnames.svg?style=for-the-badge&labelColor=0869B8"> | ||
</a> | ||
<a aria-label="License" href="#"> | ||
<img alt="" src="https://img.shields.io/npm/l/classnames.svg?style=for-the-badge&labelColor=579805"> | ||
</a> | ||
<a aria-label="Thinkmill Logo" href="https://www.thinkmill.com.au/open-source?utm_campaign=github-classnames"> | ||
<img src="https://img.shields.io/badge/Sponsored%20BY%20Thinkmill-ed0000.svg?style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTg2IiBoZWlnaHQ9IjU4NiIgdmlld0JveD0iMCAwIDU4NiA1ODYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF8xOTk2XzQwNikiPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTU4NiAyOTNDNTg2IDQ1NC44MTkgNDU0LjgxOSA1ODYgMjkzIDU4NkMxMzEuMTgxIDU4NiAwIDQ1NC44MTkgMCAyOTNDMCAxMzEuMTgxIDEzMS4xODEgMCAyOTMgMEM0NTQuODE5IDAgNTg2IDEzMS4xODEgNTg2IDI5M1pNMjA1Ljc3NiAzNTguOTQ0QzE5MS4zNzYgMzU4Ljk0NCAxODUuOTA0IDM1Mi4zMiAxODUuOTA0IDMzNS45MDRWMjYyLjc1MkgyMTQuNDE2VjIzNy42OTZIMTg1LjkwNFYyMDEuMTJIMTUzLjA3MlYyMzcuNjk2SDEyOC41OTJWMjYyLjc1MkgxNTMuMDcyVjM0MC44QzE1My4wNzIgMzcyLjc2OCAxNjYuNjA4IDM4NS43MjggMTk3LjQyNCAzODUuNzI4QzIwMy40NzIgMzg1LjcyOCAyMTAuOTYgMzg0LjU3NiAyMTUuODU2IDM4My4xMzZWMzU3LjUwNEMyMTMuNTUyIDM1OC4zNjggMjA5LjUyIDM1OC45NDQgMjA1Ljc3NiAzNTguOTQ0Wk00MDcuMzc2IDIzNC4yNEMzODUuMiAyMzQuMjQgMzcxLjA4OCAyNDQuMDMyIDM2MC40MzIgMjYwLjczNkMzNTIuOTQ0IDI0My40NTYgMzM3LjM5MiAyMzQuMjQgMzE3LjIzMiAyMzQuMjRDMjk5Ljk1MiAyMzQuMjQgMjg2Ljk5MiAyNDEuMTUyIDI3Ni42MjQgMjU1LjI2NEgyNzYuMDQ4VjIzNy42OTZIMjQ0LjY1NlYzODRIMjc3LjQ4OFYzMDUuNjY0QzI3Ny40ODggMjc3LjQ0IDI4OC43MiAyNjAuNzM2IDMwOC4zMDQgMjYwLjczNkMzMjUuMjk2IDI2MC43MzYgMzM0LjUxMiAyNzIuODMyIDMzNC41MTIgMjkzLjU2OFYzODRIMzY3LjM0NFYzMDUuMDg4QzM2Ny4zNDQgMjc3LjE1MiAzNzguODY0IDI2MC43MzYgMzk4LjE2IDI2MC43MzZDNDE0LjU3NiAyNjAuNzM2IDQyNC42NTYgMjcxLjEwNCA0MjQuNjU2IDI5Ny4wMjRWMzg0SDQ1Ny40ODhWMjkzLjg1NkM0NTcuNDg4IDI1NC40IDQzOC40OCAyMzQuMjQgNDA3LjM3NiAyMzQuMjRaIiBmaWxsPSJ3aGl0ZSIvPgo8L2c+CjxkZWZzPgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzE5OTZfNDA2Ij4KPHJlY3Qgd2lkdGg9IjU4NiIgaGVpZ2h0PSI1ODYiIGZpbGw9IndoaXRlIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg==&labelColor=C60200&locoColor=white&logoWidth=0"> | ||
</a> | ||
Install with [npm](https://www.npmjs.com/), [Bower](https://bower.io/), or [Yarn](https://yarnpkg.com/): | ||
</p> | ||
Install from the [npm registry](https://www.npmjs.com/) with your package manager: | ||
```bash | ||
# via npm | ||
npm install classnames | ||
# via Bower | ||
bower install classnames | ||
# or Yarn (note that it will automatically save the package to your `dependencies` in `package.json`) | ||
yarn add classnames | ||
``` | ||
@@ -28,3 +26,3 @@ | ||
```js | ||
var classNames = require('classnames'); | ||
const classNames = require('classnames'); | ||
classNames('foo', 'bar'); // => 'foo bar' | ||
@@ -37,3 +35,3 @@ ``` | ||
We take the stability and performance of this package seriously, because it is run millions of times a day in browsers all around the world. Updates are thoroughly reviewed for performance impacts before being released, and we have a comprehensive test suite. | ||
We take the stability and performance of this package seriously, because it is run millions of times a day in browsers all around the world. Updates are thoroughly reviewed for performance implications before being released, and we have a comprehensive test suite. | ||
@@ -67,3 +65,3 @@ Classnames follows the [SemVer](https://semver.org/) standard for versioning. | ||
```js | ||
var arr = ['b', { c: true, d: false }]; | ||
const arr = ['b', { c: true, d: false }]; | ||
classNames('a', arr); // => 'a b c' | ||
@@ -88,10 +86,23 @@ ``` | ||
```js | ||
class Button extends React.Component { | ||
// ... | ||
render () { | ||
var btnClass = 'btn'; | ||
if (this.state.isPressed) btnClass += ' btn-pressed'; | ||
else if (this.state.isHovered) btnClass += ' btn-over'; | ||
return <button className={btnClass}>{this.props.label}</button>; | ||
} | ||
import React, { useState } from 'react'; | ||
export default function Button (props) { | ||
const [isPressed, setIsPressed] = useState(false); | ||
const [isHovered, setIsHovered] = useState(false); | ||
let btnClass = 'btn'; | ||
if (isPressed) btnClass += ' btn-pressed'; | ||
else if (isHovered) btnClass += ' btn-over'; | ||
return ( | ||
<button | ||
className={btnClass} | ||
onMouseDown={() => setIsPressed(true)} | ||
onMouseUp={() => setIsPressed(false)} | ||
onMouseEnter={() => setIsHovered(true)} | ||
onMouseLeave={() => setIsHovered(false)} | ||
> | ||
{props.label} | ||
</button> | ||
); | ||
} | ||
@@ -103,14 +114,26 @@ ``` | ||
```js | ||
var classNames = require('classnames'); | ||
import React, { useState } from 'react'; | ||
import classNames from 'classnames'; | ||
class Button extends React.Component { | ||
// ... | ||
render () { | ||
var btnClass = classNames({ | ||
btn: true, | ||
'btn-pressed': this.state.isPressed, | ||
'btn-over': !this.state.isPressed && this.state.isHovered | ||
}); | ||
return <button className={btnClass}>{this.props.label}</button>; | ||
} | ||
export default function Button (props) { | ||
const [isPressed, setIsPressed] = useState(false); | ||
const [isHovered, setIsHovered] = useState(false); | ||
const btnClass = classNames({ | ||
btn: true, | ||
'btn-pressed': isPressed, | ||
'btn-over': !isPressed && isHovered, | ||
}); | ||
return ( | ||
<button | ||
className={btnClass} | ||
onMouseDown={() => setIsPressed(true)} | ||
onMouseUp={() => setIsPressed(false)} | ||
onMouseEnter={() => setIsHovered(true)} | ||
onMouseLeave={() => setIsHovered(false)} | ||
> | ||
{props.label} | ||
</button> | ||
); | ||
} | ||
@@ -122,9 +145,8 @@ ``` | ||
```js | ||
var btnClass = classNames('btn', this.props.className, { | ||
'btn-pressed': this.state.isPressed, | ||
'btn-over': !this.state.isPressed && this.state.isHovered | ||
const btnClass = classNames('btn', this.props.className, { | ||
'btn-pressed': isPressed, | ||
'btn-over': !isPressed && isHovered, | ||
}); | ||
``` | ||
### Alternate `dedupe` version | ||
@@ -139,3 +161,3 @@ | ||
```js | ||
var classNames = require('classnames/dedupe'); | ||
const classNames = require('classnames/dedupe'); | ||
@@ -148,6 +170,5 @@ classNames('foo', 'foo', 'bar'); // => 'foo bar' | ||
### Alternate `bind` version (for [css-modules](https://github.com/css-modules/css-modules)) | ||
If you are using [css-modules](https://github.com/css-modules/css-modules), or a similar approach to abstract class "names" and the real `className` values that are actually output to the DOM, you may want to use the `bind` variant. | ||
If you are using [css-modules](https://github.com/css-modules/css-modules), or a similar approach to abstract class 'names' and the real `className` values that are actually output to the DOM, you may want to use the `bind` variant. | ||
@@ -157,13 +178,13 @@ _Note that in ES2015 environments, it may be better to use the "dynamic class names" approach documented above._ | ||
```js | ||
var classNames = require('classnames/bind'); | ||
const classNames = require('classnames/bind'); | ||
var styles = { | ||
foo: 'abc', | ||
bar: 'def', | ||
baz: 'xyz' | ||
const styles = { | ||
foo: 'abc', | ||
bar: 'def', | ||
baz: 'xyz', | ||
}; | ||
var cx = classNames.bind(styles); | ||
const cx = classNames.bind(styles); | ||
var className = cx('foo', ['bar'], { baz: true }); // => "abc def xyz" | ||
const className = cx('foo', ['bar'], { baz: true }); // => 'abc def xyz' | ||
``` | ||
@@ -175,24 +196,25 @@ | ||
/* components/submit-button.js */ | ||
import { Component } from 'react'; | ||
import { useState } from 'react'; | ||
import classNames from 'classnames/bind'; | ||
import styles from './submit-button.css'; | ||
let cx = classNames.bind(styles); | ||
const cx = classNames.bind(styles); | ||
export default class SubmitButton extends Component { | ||
render () { | ||
let text = this.props.store.submissionInProgress ? 'Processing...' : 'Submit'; | ||
let className = cx({ | ||
base: true, | ||
inProgress: this.props.store.submissionInProgress, | ||
error: this.props.store.errorOccurred, | ||
disabled: this.props.form.valid, | ||
}); | ||
return <button className={className}>{text}</button>; | ||
} | ||
}; | ||
export default function SubmitButton ({ store, form }) { | ||
const [submissionInProgress, setSubmissionInProgress] = useState(store.submissionInProgress); | ||
const [errorOccurred, setErrorOccurred] = useState(store.errorOccurred); | ||
const [valid, setValid] = useState(form.valid); | ||
const text = submissionInProgress ? 'Processing...' : 'Submit'; | ||
const className = cx({ | ||
base: true, | ||
inProgress: submissionInProgress, | ||
error: errorOccurred, | ||
disabled: valid, | ||
}); | ||
return <button className={className}>{text}</button>; | ||
} | ||
``` | ||
## Polyfills needed to support older browsers | ||
@@ -204,3 +226,2 @@ | ||
## LICENSE [MIT](LICENSE) | ||
@@ -207,0 +228,0 @@ |
21731
228
220