classed-components
Advanced tools
Comparing version 0.5.1 to 1.0.0-beta.1
{ | ||
"url": "https://github.com/mephju/classed-components", | ||
"homepage": "https://github.com/mephju/classed-components", | ||
"repository": { | ||
"type": "git", | ||
"url": "git@github.com:mephju/classed-components.git" | ||
}, | ||
"name": "classed-components", | ||
"version": "1.0.0-beta.1", | ||
"description": "CSS Classes for the component age. Apply your Css with the power of Javascript.", | ||
"keywords": [ | ||
"classNames", | ||
"react", | ||
"components", | ||
"classed", | ||
"class", | ||
"styled" | ||
], | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"repository": "https://github.com/mathieutu/classed-components.git", | ||
"author": "Mathieu TUDISCO <oss@mathieutu.dev>", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/mephju/classed-components/issues" | ||
"url": "https://github.com/mathieutu/classed-components/issues" | ||
}, | ||
"email": "mephju@gmail.com", | ||
"name": "classed-components", | ||
"version": "0.5.1", | ||
"description": "Like styled-components but for classes. Quickly create components based on CSS classes.", | ||
"main": "lib/main.js", | ||
"homepage": "https://github.com/mathieutu/classed-components", | ||
"files": [ | ||
"dist/**/*" | ||
], | ||
"scripts": { | ||
"test": "jest", | ||
"build": "NODE_ENV=production webpack --color --progress", | ||
"watch": "NODE_ENV=production webpack --color --progress --watch", | ||
"build:dev": "NODE_ENV=development webpack --color --progress", | ||
"watch:dev": "NODE_ENV=development webpack --color --progress --watch" | ||
"build": "rm -rf dist && tsc", | ||
"watch": "yarn build -- -w", | ||
"lint": "tslint -p tsconfig.json", | ||
"pretty": "lint --fix", | ||
"test": "yarn lint & tsc --noEmit && jest", | ||
"coverage": "yarn test --coverage --coverageReporters=text-lcov | coveralls", | ||
"test-watch": "jest --watch", | ||
"prepare": "yarn build", | ||
"prepublishOnly": "yarn test && yarn lint", | ||
"changelog": "gitmoji-changelog" | ||
}, | ||
"author": "Kolja Kirchner", | ||
"license": "MIT", | ||
"devDependencies": { | ||
"babel": "^6.5.2", | ||
"babel-cli": "^6.22.2", | ||
"babel-core": "^6.22.1", | ||
"babel-jest": "^18.0.0", | ||
"babel-loader": "^6.4.1", | ||
"babel-plugin-transform-class-properties": "^6.22.0", | ||
"babel-plugin-transform-flow-strip-types": "^6.22.0", | ||
"babel-plugin-transform-object-rest-spread": "^6.22.0", | ||
"babel-preset-env": "^1.3.3", | ||
"babel-preset-es2015": "^6.22.0", | ||
"babel-preset-latest": "^6.16.0", | ||
"babel-preset-react": "^6.22.0", | ||
"babel-preset-stage-0": "^6.22.0", | ||
"compression-webpack-plugin": "^0.4.0", | ||
"enzyme": "^2.7.1", | ||
"jest": "^18.1.0", | ||
"react": "^15.4.1", | ||
"react-addons-test-utils": "^15.4.2", | ||
"react-test-renderer": "^15.4.2", | ||
"webpack": "^2.3.3" | ||
"@types/classnames": "^2.2.7", | ||
"@types/jest": "^24.0.13", | ||
"@types/react": "^16.8.17", | ||
"@types/react-test-renderer": "^16.8.1", | ||
"coveralls": "^3.0.3", | ||
"gitmoji-changelog": "^1.1.0", | ||
"jest": "^24.8.0", | ||
"react-test-renderer": "^16.8.6", | ||
"ts-jest": "^24.0.2", | ||
"tslint": "^5.16.0", | ||
"tslint-config-airbnb": "^5.11.1", | ||
"typescript": "^3.4.5" | ||
}, | ||
"dependencies": { | ||
"classnames": "^2.2.6" | ||
}, | ||
"peerDependencies": { | ||
"react": "^0.14.0 || ^15.0.0-0", | ||
"prop-types": "^15.5.6" | ||
"react": "*" | ||
}, | ||
"dependencies": {} | ||
"engines": { | ||
"node": ">=6.0.0" | ||
} | ||
} |
319
README.md
@@ -1,92 +0,311 @@ | ||
# classed-components | ||
Like [styled-components](https://github.com/styled-components/styled-components) but for classes. | ||
# classed-components <!-- omit in toc --> | ||
## Why | ||
When using CSS Frameworks such as [MaterializeCSS](http://materializecss.com/) it is nice to create components out of existing classes from that framework. | ||
[![npm](https://img.shields.io/npm/v/classed-components.svg)](https://www.npmjs.com/package/classed-components) | ||
[![npm](https://img.shields.io/npm/dt/classed-components.svg)](https://www.npmjs.com/package/classed-components) | ||
[![Coverage Status](https://coveralls.io/repos/github/mathieutu/classed-components/badge.svg?branch=master)](https://coveralls.io/github/mathieutu/classed-components?branch=master) | ||
[![Build Status](https://travis-ci.org/mathieutu/classed-components.svg?branch=master)](https://travis-ci.org/mathieutu/classed-components) | ||
classed-components helps you do that in a convenient way. | ||
Plus, it just comes at `4.26kB` and has no dependencies! | ||
**💅 CSS Classes for the component age.** | ||
## How to get started | ||
This package allows you to add a your css classes to your component with the power of Javascript, and with Css-in-JS style. | ||
![screenshot](./screenshot.png) | ||
**✨ Features:** | ||
Add you CSS classes in a fluent way to your React components, with: | ||
- Template string. | ||
- Array notation. | ||
- Object notation. | ||
And all of that with: | ||
- Infinite recursivity, | ||
- Functions receiving your components props to manage your classes. | ||
- Top developer experience: deep Typescript typing. | ||
## Table of contents <!-- omit in toc --> | ||
- [Installation](#installation) | ||
- [Usage](#usage) | ||
- [Object syntax](#object-syntax) | ||
- [Array Syntax](#array-syntax) | ||
- [Template string](#template-string) | ||
- [Functions](#functions) | ||
- [Nesting](#nesting) | ||
- [Remaining className prop on classed components](#remaining-classname-prop-on-classed-components) | ||
- [Typings](#typings) | ||
- [Examples](#examples) | ||
- [A bug, a question?](#a-bug-a-question) | ||
- [License](#license) | ||
- [Contributing](#contributing) | ||
------ | ||
## Installation | ||
```bash | ||
npm i --save classed-components | ||
yarn add classed-components | ||
``` | ||
```javascript | ||
## Usage | ||
You can create classed components with the `classed` method exported from `classed-components`, and passing your class to it. There are many way of doing that. We will try to document of all them in this section, but feel free to look at the [tests](./tests/classed.test.tsx) to see all the features and the whole API. | ||
You can create any standard Html `X` classed component by using `classed.X`, `classed[X]` or `classed(X)` method: | ||
```jsx | ||
import classed from 'classed-components' | ||
const Header = classed.div` | ||
header | ||
green | ||
const Link = classed.a('all my classes') | ||
<Link href="#">foo</Link> // <a href="#" className="all my classes">foo</a> | ||
``` | ||
But you can also class any custom component as long it accepts a `className` prop: | ||
```jsx | ||
import classed from 'classed-components' | ||
const BlogLink = ({ className }) => ( | ||
<a className={className} href="https://mathieutu.dev">Blog</a> | ||
) | ||
const MenuLink = classed(BlogLink)('all my classes') | ||
<MenuLink/> // <a className="all my classes" href="https://mathieutu.dev">Blog</a> | ||
``` | ||
Several advanced syntaxes are allowed: | ||
### Object syntax | ||
You can pass an object to the method to dynamically toggle classes: | ||
``` jsx | ||
import classed from 'classed-components' | ||
const hasError = true | ||
const Input = classed.input({ 'text-danger': hasError }) | ||
<Input/> // <input className="text-danger"/> | ||
``` | ||
The above syntax means the presence of the `text-danger` class will be determined by the [truthiness](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) of the constant `hasError`. | ||
### Array Syntax | ||
We can pass an array to the method to apply a list of classes: | ||
``` jsx | ||
import classed from 'classed-components' | ||
const inputClass = 'input' | ||
const errorClass = 'text-danger' | ||
const Input = classed.input([inputClass, errorClass]) | ||
<Input/> // <input className="input text-danger"/> | ||
``` | ||
If you would like to also toggle a class in the list conditionally, you can do it with a ternary expression: | ||
``` jsx | ||
import classed from 'classed-components' | ||
const hasError = true | ||
const Input = classed.input(['input', hasError ? 'text-danger' : '']) | ||
<Input/> // <input className="input text-danger"/> | ||
``` | ||
This will always apply the `input` class, but will only apply `text-danger` when `hasError` is truthy. | ||
However, this can be a bit verbose if you have multiple conditional classes. That's why it's also possible to use the array and object syntax inside array syntax: | ||
``` jsx | ||
import classed from 'classed-components' | ||
const hasError = true | ||
const Input = classed.input(['input', { 'text-danger': hasError }]) | ||
<Input/> // <input className="input text-danger"/> | ||
``` | ||
### Template string | ||
You can use [tagged template string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates) to set your classes: | ||
``` jsx | ||
import classed from 'classed-components' | ||
const Input = classed.input` | ||
input | ||
text-danger | ||
` | ||
const App = props => { | ||
return <Header /> | ||
} | ||
<Input/> // <input className="input text-danger"/> | ||
``` | ||
## Features | ||
- Create any HTML tag and associate it with classes. | ||
- Overwrite existing *classed componentes* with even more classes. | ||
- Conditional classes: Include or exclude classes based on your props. | ||
- Generate classes via interpolation functions also based on your props. | ||
The placeholders are processed, and allow any type of other syntax: | ||
### Overwrite existing *classed components* | ||
```javascript | ||
``` jsx | ||
import classed from 'classed-components' | ||
const hasError = true | ||
const Header = classed.div` | ||
header | ||
green | ||
const Input = classed.input` | ||
input | ||
${{ 'text-danger': hasError }} | ||
` | ||
const HeaderBlack = classed(Header)`black col s12` | ||
<Input/> // <input className="input text-danger"/> | ||
``` | ||
### Conditional classes | ||
You can use include or exclude certain classes based on props or other variables in the current scope. This is a feature you might know from the [classnames module](https://github.com/JedWatson/classnames). | ||
Whenever an embedding/interpolition within the template string returns a boolean it is interpreted as a condition on the preceeding classname. | ||
### Functions | ||
```javascript | ||
You can directly pass a function to the method, which will received the props of the component. | ||
The return type of this function can be any of other syntax. | ||
``` jsx | ||
import classed from 'classed-components' | ||
const large = true | ||
const Input = classed.input(({ hasError }) => ['input', { 'text-danger': hasError }]) | ||
const MyComponent = classed.div` | ||
header ${props => props.needsHeader} | ||
green | ||
large ${large} | ||
<Input hasError/> // <input className="input text-danger"/> | ||
``` | ||
Functions can also be used directly nested in arrays and template strings: | ||
``` jsx | ||
import classed from 'classed-components' | ||
const Input = classed.input(['input', ({ hasError }) => { 'text-danger': hasError }]) | ||
<Input hasError/> // <input className="input text-danger"/> | ||
``` | ||
``` jsx | ||
import classed from 'classed-components' | ||
const Input = classed.input` | ||
input | ||
${({ hasError }) => hasError && 'text-danger'} | ||
${({ isRequired }) => isRequired && 'required'} | ||
` | ||
<Input hasError/> // <input className="input text-danger"/> | ||
``` | ||
### Generate classes via interpolation functions | ||
```javascript | ||
### Nesting | ||
All the syntaxes work together and could be infinetly nested, so this example will work: | ||
``` jsx | ||
import classed from 'classed-components' | ||
const extra = 'col s12 m6' | ||
const Header = classed.div` | ||
${props => props.needsHeader ? 'header' : 'box'} | ||
green | ||
${extra} | ||
const Input = classed.input` | ||
input | ||
${({ hasError, isRequired, errorClass }) => [{ [errorClass]: hasError }, isRequired && 'required']} | ||
` | ||
<Input hasError errorClass="text-danger"/> // <input className="input text-danger"/> | ||
``` | ||
### className prop | ||
Please note that adding the className prop to a classed component will overwrite its class names. | ||
### Remaining className prop on classed components | ||
```javascript | ||
const Header = classed.div` | ||
test-class | ||
The generated component will keep a `className` prop, and will merge all the classes you will pass through it. | ||
It will so allow you to manage inheritance in your classed components, and compose easily your style. | ||
``` jsx | ||
import classed from 'classed-components' | ||
const BaseInput = classed.input(({ hasError }) => ['input', { 'text-danger': hasError }]) | ||
const RequirableInput = classed(BaseInput)(({isRequired}) => ({ 'required': isRequired }) | ||
<Input hasError isRequired className="form-contact"/> // <input className="input text-danger required form-contact"/> | ||
``` | ||
### Typings | ||
classed-components is highly typed. | ||
When using with Typescript, you will have all the available props of your original component in functions, and in the generated classed component. | ||
If you want to add some props to manage your styling, you can type them by setting the first generic of the function. | ||
```tsx | ||
const Nav = classed.nav<{ isShown: boolean }>([ | ||
'header', | ||
({ isShown }) => ({ 'bg-blue-500': isShown }), | ||
]) | ||
``` | ||
That way, the original props and the ones you add will be merged, and you will have a high quality auto-completion: | ||
![Typescript: Autocompletion in function](docs/ts_function.png) | ||
![Typescript: Autocompletion in JSX](docs/ts_jsx.png) | ||
![Typescript: Adding props: Autocompletion in function](docs/ts_add_props_function.png) | ||
![Typescript: Adding props: Autocompletion in JSX](docs/ts_add_props_jsx.png) | ||
## Examples | ||
Soon: a code sandbox full example. | ||
Here some components styled with [TailwindCss](http://tailwindcss.com/) | ||
```tsx | ||
import { classed } from 'classed-components' | ||
import { Link } from '../Link' | ||
const Nav = classed.nav<{ isShown: boolean }>([ | ||
'flex', | ||
'items-center', | ||
'justify-between', | ||
'flex-wrap', | ||
({ isShown }) => ({ 'bg-blue-500': isShown }), | ||
'p-6', | ||
]) | ||
const MenuLink = classed(Link)<{ isBlue: boolean }>` | ||
block | ||
mt-4 | ||
lg:inline-block | ||
lg:mt-0 | ||
text-blue-200 | ||
hover:text-${({ isBlue }) => isBlue ? 'blue-500' : 'white'} | ||
mr-4 | ||
` | ||
// ... | ||
// Do not do this: | ||
<Header className='will-overwrite-test-class' /> | ||
const BtnLink = classed(Link)<{ isBlue: boolean }>(({ isBlue }) => { | ||
const color = isBlue ? 'blue-500' : 'white' | ||
return [ | ||
'inline-block', | ||
'text-sm', | ||
'px-4', | ||
'py-2', | ||
'leading-none', | ||
'border', | ||
'rounded', | ||
`text-${color}`, | ||
`border-${color}`, | ||
'hover:border-transparent', | ||
`hover:text-${color}`, | ||
`hover:bg-${color}`, | ||
'mt-4', | ||
'lg:mt-0', | ||
] | ||
}) | ||
``` | ||
## A bug, a question? | ||
Please feel free to [tell me](https://github.com/mathieutu/classed-components/issues/new)! | ||
## License | ||
This package is an open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT). | ||
## Contributing | ||
Issues and PRs are obviously welcomed and encouraged, for new features as well as documentation. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
12
1
312
26695
12
363
1
2
+ Addedclassnames@^2.2.6
+ Addedclassnames@2.5.1(transitive)
+ Addedreact@18.3.1(transitive)
- Removedasap@2.0.6(transitive)
- Removedcore-js@1.2.7(transitive)
- Removedcreate-react-class@15.7.0(transitive)
- Removedencoding@0.1.13(transitive)
- Removedfbjs@0.8.18(transitive)
- Removediconv-lite@0.6.3(transitive)
- Removedis-stream@1.1.0(transitive)
- Removedisomorphic-fetch@2.2.1(transitive)
- Removednode-fetch@1.7.3(transitive)
- Removedobject-assign@4.1.1(transitive)
- Removedpromise@7.3.1(transitive)
- Removedprop-types@15.8.1(transitive)
- Removedreact@15.7.0(transitive)
- Removedreact-is@16.13.1(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsetimmediate@1.0.5(transitive)
- Removedua-parser-js@0.7.39(transitive)
- Removedwhatwg-fetch@3.6.20(transitive)