Advertisement
Husi012

TailwindCSS like styled-components

Aug 30th, 2021 (edited)
1,653
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { forwardRef } from "react"
  2.  
  3. function combine(...classNames: string[]) {
  4.   return classNames.filter((className) => !!className).join(" ")
  5. }
  6.  
  7. type TagName = keyof JSX.IntrinsicElements
  8.  
  9. type NormalFn<T extends TagName> = (...classNames: string[]) => GetTheirRefType<T>
  10.  
  11. type TemplateFn<T extends TagName> = (
  12.   strings: TemplateStringsArray,
  13.   ...values: string[]
  14. ) => GetTheirRefType<T>
  15.  
  16. type GetTheirRefType<T extends TagName> = JSX.IntrinsicElements[T] extends React.DetailedHTMLProps<infer X, infer Y> ? Y : never
  17.  
  18. type TailwindFn = {
  19.   [tagName in TagName]: NormalFn<tagName>
  20. }
  21.  
  22. type TailwindTemplate = {
  23.   [tagName in TagName]: TemplateFn<tagName>
  24. }
  25.  
  26. export const tailwind_fn = new Proxy(
  27.   {},
  28.   {
  29.     get<T extends TagName>(target: any, tagName: T) {
  30.       const Element = tagName as any // FIXME: will have a type error if it's not any (probably an edge case with a specific tag name)
  31.  
  32.       return (...classNames: string[]) =>
  33.         forwardRef<GetTheirRefType<T>, JSX.IntrinsicElements[T]>(
  34.           ({ className = "", ...props }, ref) => (
  35.             <Element className={combine(className, ...classNames)} {...props} ref={ref} />
  36.           )
  37.         )
  38.     },
  39.   }
  40. ) as TailwindFn
  41.  
  42. export const tailwind = new Proxy(
  43.   {},
  44.   {
  45.     get<T extends TagName>(target: any, tagName: T) {
  46.       return (literals: TemplateStringsArray, ...placeholders: string[]) =>
  47.         tailwind_fn[tagName](...literals, ...placeholders)
  48.     },
  49.   }
  50. ) as TailwindTemplate
  51.  
  52. /* How to use:
  53.  * const Button = tailwind.button`px-2 py-1 m-5 bg-green-500 rounded-md`
  54.  * const Button2 = tailwind_fn.button("px-2 py-1 m-5", "bg-green-500", "rounded-md") // <- insert variables with class names
  55.  */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement