From fa364d42a85cb68825bd04612363f10f788efd4f Mon Sep 17 00:00:00 2001 From: Salakhutdinov Salavat Date: Sat, 18 Mar 2023 19:24:44 +0300 Subject: [PATCH] update README.md --- .changeset/shiny-shirts-rhyme.md | 5 + README.md | 307 +++++++++++++++++++++++++++++-- 2 files changed, 293 insertions(+), 19 deletions(-) create mode 100644 .changeset/shiny-shirts-rhyme.md diff --git a/.changeset/shiny-shirts-rhyme.md b/.changeset/shiny-shirts-rhyme.md new file mode 100644 index 0000000..6b546ae --- /dev/null +++ b/.changeset/shiny-shirts-rhyme.md @@ -0,0 +1,5 @@ +--- +'react-tailwind-variants': patch +--- + +update README.md diff --git a/README.md b/README.md index c9e2d81..3ce5ef5 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,14 @@ npm install tailwind-merge react-tailwind-variants - [Components without variants](#components-without-variants) - [Polymorphic components](#polymorphic-components) - [Composing components](#composing-components) +- [Utilities](#utilities) + - [variants(config)](#variantsconfig) + - [variantProps(config)](#variantpropsconfig) + - [extractVariantsConfig(component)](#extractvariantsconfigcomponent) +- [Typescript utilities](#typescript-utilities) + - [VariantsConfigOf\](#variantsconfigofcomponent) + - [VariantPropsOf\](#variantpropsofcomponent) +- [Tailwind CSS IntelliSense](#tailwind-css-intellisense) ### Basics @@ -37,6 +45,8 @@ Let's assume we want to build a button component with Tailwind CSS that comes in It consists of some _base classes_ that are always present as well as some optional classes that need to be added depending on the desired _variants_. ```tsx +import { styled } from 'react-tailwind-variants'; + const Button = styled('button', { base: 'rounded text-white', variants: { @@ -55,7 +65,7 @@ const Button = styled('button', { The result is a react component: ```tsx - ``` @@ -65,17 +75,38 @@ Component will be rendered as: ```html ``` +As a value for classes, you can use a `"string"`, an `"array"` of strings, or `"null"`: + +```tsx +import { styled } from 'react-tailwind-variants'; + +const Button = styled('button', { + base: ['rounded', 'text-white'], + variants: { + color: { + none: null, + brand: 'bg-sky-500', + accent: 'bg-teal-500', + }, + }, +}); +``` + +--- + ### Boolean variants Variants can be of type `boolean` by using `"true"` or/and `"false"` as the key: -```ts +```tsx +import { styled } from 'react-tailwind-variants'; + const Button = styled('button', { base: 'text-white', variants: { @@ -86,41 +117,81 @@ const Button = styled('button', { }); ``` +--- + ### Compound variants The `compoundVariants` option can be used to apply class names based on a combination of other variants. ```tsx +import { styled } from 'react-tailwind-variants'; + const Button = styled('button', { + base: 'text-base' variants: { - color: { - neutral: 'bg-gray-200', - accent: 'bg-teal-400', + variant: { + none: null, + filled: 'bg-blue-500 text-white', + outlined: 'border border-blue-500 text-blue-500', + plain: 'bg-transparent text-blue-500', }, - outlined: { - true: 'border-2', + size: { + sm: 'px-3 py-1.5' + md: 'px-4 py-2' + lg: 'px-6 py-3' }, }, compoundVariants: [ { variants: { - color: 'accent', - outlined: true, + variant: ['filled', 'outlined'], + size: 'sm' + }, + className: 'text-sm' + }, + { + // `compoundVariants` className takes + // precedence over `variants`, + // so in this case the class `p-0` + // will override `padding` classes + variants: { + variant: 'none' }, - className: 'border-teal-500', + className: 'p-0' }, ], }); ``` +```tsx + + +``` + +will be rendered as: + +```html + + +``` + +--- + ### Default variants The `defaultVariants` option can be used to select a variant by default. -All variants for which no default values are specified are required. +All non-boolean variants for which no default values are specified are required. +If no default value is specified for boolean options, it evaluates to "false" Below is an example with a component that has a required `size` and an optional `color` variants -```ts +```tsx +import { styled } from 'react-tailwind-variants'; + const Button = styled('button', { variants: { color: { @@ -131,6 +202,9 @@ const Button = styled('button', { small: 'px-5 py-3 text-xs', large: 'px-6 py-4 text-base', }, + elevated: { + true: 'shadow', + }, }, defaultVariants: { color: 'neutral', @@ -138,19 +212,27 @@ const Button = styled('button', { }); ``` +--- + ### Components without variants If the component does not have any options, you can specify a string with classes instead of a configuration object ```tsx +import { styled } from 'react-tailwind-variants'; + const Button = styled('button', 'bg-blue-500 text-white px-4 py-2'); ``` +--- + ### Polymorphic components If you want to keep all the variants you have defined for a component but want to render a different HTML tag or a different custom component, you can use the `"asChild"` prop to do so: ```tsx +import { styled } from 'react-tailwind-variants'; + const Button = styled('button', { base: 'rounded text-white', variants: { @@ -169,7 +251,7 @@ const Button = styled('button', { ```tsx ``` @@ -181,10 +263,12 @@ will be rendered as: href="/test" className="rounded text-white bg-sky-500 px-6 py-4 text-base mt-4 mb-2" > - Link as button + Button as link ``` +--- + ### Composing components Composing one styled component into another. @@ -192,6 +276,8 @@ Composing one styled component into another. 1. Components can be composed via the `styled` function. ```tsx +import { styled } from 'react-tailwind-variants'; + const BaseButton = styled('button', { base: 'text-center bg-blue-500 text-white', variants: { @@ -215,7 +301,7 @@ const Button = styled(BaseButton, { ```tsx ``` @@ -226,13 +312,15 @@ will be rendered as: type="submit" className="text-center text-white px-6 py-4 text-base rounded text-white bg-sky-500" > - Link as button + Click me! ``` 2. You can also achieve the same result using `"asChild"` prop: ```tsx +import { styled } from 'react-tailwind-variants'; + const BaseButton = styled('button', { base: 'text-center bg-blue-500 text-white', variants: { @@ -257,7 +345,7 @@ const Button = styled('button', { ```tsx ``` @@ -269,10 +357,191 @@ will be rendered as: type="submit" className="text-center text-white px-6 py-4 text-base rounded text-white bg-sky-500" > - Link as button + Click me! ``` +--- + +### Utilities + +#### `variants(config)` + +The function accepts variants config as argument and returns a `className` builder function + +```ts +import { variants } from 'react-tailwind-variants'; + +const buttonVariants = variants({ + base: 'rounded text-white', + variants: { + color: { + brand: 'bg-sky-500', + accent: 'bg-teal-500', + }, + size: { + small: 'px-5 py-3 text-xs', + large: 'px-6 py-4 text-base', + }, + }, +}); + +console.log( + buttonVariants({ + color: 'brand', + size: 'small', + className: 'text-sky-900 px-8', + }) +); +// Console output: +// 'rounded bg-sky-500 py-3 text-xs text-sky-900 px-8' +``` + +#### `variantProps(config)` + +The function accepts variants config as argument and returns props builder function + +```ts +import { variantProps } from 'react-tailwind-variants'; + +const buttonVariantProps = variantProps({ + base: 'rounded text-white', + variants: { + color: { + brand: 'bg-sky-500', + accent: 'bg-teal-500', + }, + size: { + small: 'px-5 py-3 text-xs', + large: 'px-6 py-4 text-base', + }, + }, +}); + +console.log( + buttonVariantProps({ + color: 'brand', + size: 'small', + className: 'text-sky-900 px-8', + type: 'button', + onClick: e => { + // ... + }, + }) +); +// Console output: +// { +// className: 'rounded bg-sky-500 py-3 text-xs text-sky-900 px-8' +// type: "button", +// onClick: ... +// } +``` + +#### `extractVariantsConfig(component)` + +The function accepts a component from which it extracts the configuration of variants + +```ts +import { styled, extractVariantsConfig } from 'react-tailwind-variants'; + +const Button = styled('button', { + base: ['rounded', 'text-white'], + variants: { + color: { + none: null, + brand: 'bg-sky-500', + accent: 'bg-teal-500', + }, + }, +}); + +console.log(extractVariantsConfig(Button)); +// Console output: +// { +// base: ['rounded', 'text-white'], +// variants: { +// color: { +// none: null, +// brand: 'bg-sky-500', +// accent: 'bg-teal-500', +// }, +// }, +// } +``` + +### Typescript utilities + +#### `VariantsConfigOf` + +A utility that allows you to extract the configuration type from the component type + +```ts +import { type VariantsConfigOf, styled } from 'react-tailwind-variants'; + +const Button = styled('button', { + base: ['rounded', 'text-white'], + variants: { + color: { + none: null, + brand: 'bg-sky-500', + accent: 'bg-teal-500', + }, + }, +}); + +type ButtonVariantsConfig = VariantsConfigOf; +``` + +#### `VariantPropsOf` + +A utility that allows you to extract the variant props type from the component type + +```ts +import { type VariantPropsOf, styled } from 'react-tailwind-variants'; + +const Button = styled('button', { + base: ['rounded', 'text-white'], + variants: { + color: { + none: null, + brand: 'bg-sky-500', + accent: 'bg-teal-500', + }, + }, +}); + +type ButtonVariantProps = VariantPropsOf; +``` + +### Tailwind CSS IntelliSense + +In order to get auto-completion for the CSS classes themselves, you can use the [Tailwind CSS IntelliSense](https://github.com/tailwindlabs/tailwindcss-intellisense) plugin for VS Code. In order to make it recognize the strings inside your variants-config, you have to somehow mark them and configure the plugin accordingly. + +One way of doing so is by using tagged template literals: + +```ts +import { styled, tw } from 'react-tailwind-variants'; + +const Button = styled('button', { + base: tw`px-5 py-2 text-white`, + variants: { + color: { + neutral: tw`bg-slate-500 hover:bg-slate-400`, + accent: tw`bg-teal-500 hover:bg-teal-400`, + }, + }, +}); +``` + +You can then add the following line to your `settings.json`: + +``` +"tailwindCSS.experimental.classRegex": ["tw`(\\`|[^`]+?)`"] +``` + +> **Note** +> The `tw` helper function is just an alias for [`String.raw`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw). + [npm-img]: https://img.shields.io/npm/v/react-tailwind-variants [npm-url]: https://www.npmjs.com/package/react-tailwind-variants [bundle-size-img]: https://img.shields.io/bundlephobia/minzip/react-tailwind-variants