Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question on custom classes and CLI #58

Closed
tcarac opened this issue Oct 13, 2020 · 12 comments
Closed

Question on custom classes and CLI #58

tcarac opened this issue Oct 13, 2020 · 12 comments
Labels
good first issue Good for newcomers

Comments

@tcarac
Copy link

tcarac commented Oct 13, 2020

I've been trying to get to include custom classes generated with cli but still can't get around it.
My setup:
tsconfig.json
{ ..., "typeRoots": [ "./src/@types", "./node_modules/@types" ] }
src/@types/css-types.d.ts
... | 'text-pink-600' | 'text-pink-700' | 'text-pink-800' | 'text-pink-900' | 'text-primary' | 'text-nermin' | 'text-ribbon-200';

button.tsx
Screen Shot 2020-10-13 at 07 54 20

@muhammadsammy muhammadsammy added the good first issue Good for newcomers label Oct 15, 2020
@muhammadsammy
Copy link
Owner

Hello @sarodspirit,
classnames should be imported from the generated file, because the npm package only contains types for default tailwindcss classes.

@AdrienLemaire
Copy link

@sarodspirit you want to do something like this

{
  "scripts": {
        "generate-css-types": "tailwindcss-classnames --classesFile css-types --typeName ClassNames --config path/to/tailwind.config.js -o src/@types/tailwind.ts"
  }
}

Your css-types.ts file should look like this:

export type ClassNames = 'text-pink-600' | 'text-pink-700' | 'text-pink-800' | 'text-pink-900' | 'text-primary' | 'text-nermin' | 'text-ribbon-200';

@muhammadsammy
Copy link
Owner

Closing due to inactivity. Please feel free to reopen if you have more questions!

@Hahlh
Copy link

Hahlh commented Mar 12, 2021

I am new to typescript in general so please excuse, if that's an superficial question.

So the basic workflow would be to generate types based on my tailwind.config.js and then:

import { classnames ] from "path/to/generated/file"

const buttonStyling = (isAddedToCart: boolean, colorScheme: string) =>
    classnames({
      // Base style
      // blue
      "bg-gb-600 text-white focus:outline-none":
        isAddedToCart && colorScheme === "blue",
      "bg-gb-400 hover:bg-gb-600 text-white focus:outline-none":
        !isAddedToCart && colorScheme === "blue", })

What am I misunderstanding here? Or would I simply import the generated file additionally, giving access to the types?

@muhammadsammy
Copy link
Owner

Hi, @Hahlh!
Everything seems right except for passing multiple classnames in a single string.
A working version of the same code would be something like this:

import { classnames } from "path/to/generated/file"

const buttonStyling = (isAddedToCart: boolean, colorScheme: string) => 
classnames(
	  // These are always added
	  "text-white",
	  "focus:outline-none",
	  
	  // One is selected based on the condition
	  isAddedToCart && colorScheme === "blue" 
	      ? "bg-gb-600" 
	      : "bg-gb-400",
	  
	  // Only added for certain condition
	  { ["hover:bg-gb-600"]: isAddedToCart && colorScheme === "blue" }

)

or even better:

classnames(
	  // These are always added
	  "text-white",
	  "focus:outline-none",
	  
	  // One is selected based on the condition
	  isAddedToCart && colorScheme === "blue" 
	      ? "bg-gb-600" 
--        : "bg-gb-400",
++  	  : classnames("bg-gb-400", "hover:bg-gb-600"),

--    // Only added for certain condition
--	  { ["hover:bg-gb-600"]: isAddedToCart && colorScheme === "blue" }
)

@Hahlh
Copy link

Hahlh commented Mar 12, 2021

Hey @muhammadsammy !

Thank you for your answer. I would really like to avoid ternaries with single classNames as this would lead to the same conditional mess I have been in before. Why is passing multiple classNames considered problematic?

This seems to work fine:

const buttonBaseStyle = classnames(
    "flex items-center flex-shrink-0 justify-center px-5 lg:px-3  focus:outline-none rounded-md transform transform-colors duration-150 text-sm lg:text-xl roboto tracking-wider"
  )
  const buttonStyling = (
    isAddedToCart: boolean,
    colorScheme: string,
    isMobileFullWidth: boolean
  ) =>
    classnames(
      [buttonBaseStyle],
      {
        // Layout
        "w-full lg:max-w-max py-3 lg:py-1": isMobileFullWidth,
        "py-2 lg:py-1 max-w-max": !isMobileFullWidth,
      },
      {
        // Color Schemes
        // blue
        "bg-gb-600 text-white focus:outline-none":
          isAddedToCart && colorScheme === "blue",
        "bg-gb-400 hover:bg-gb-600 text-white focus:outline-none":
          !isAddedToCart && colorScheme === "blue",
        // red
        "!bg-epRed-800 text-white focus:outline-none":
          isAddedToCart &&
          (colorScheme === "red" || colorScheme === "explorer"),
        "bg-epRed-600 hover:bg-epRed-800 text-white focus:outline-none":
          !isAddedToCart &&
          (colorScheme === "red" || colorScheme === "explorer"),
        // explorer
        //  "!bg-epRed-800 text-white focus:outline-none":
        // isAddedToCart && colorScheme === "explorer" ,

        // "bg-epRed-600 hover:bg-epRed-800 text-white focus:outline-none": !isAddedToCart && colorScheme === "explorer",
        // late-summer
        "!bg-lsRed-700 text-white focus:outline-none":
          isAddedToCart && colorScheme === "late-summer",
        "bg-lsRed-500 hover:bg-lsRed-700 text-white focus:outline-none":
          !isAddedToCart && colorScheme === "late-summer",
        // flashlight
        "!bg-flYellow-700 text-white focus:outline-none":
          isAddedToCart && colorScheme === "flashlight",
        "bg-flYellow-500 hover:bg-flYellow-700 text-white focus:outline-none":
          !isAddedToCart && colorScheme === "flashlight",
        // verry-berry
        "!bg-vbViolett-900 text-white focus:outline-none":
          isAddedToCart && colorScheme === "verry-berry",
        "bg-vbViolett-700 hover:bg-vbViolett-900 text-white focus:outline-none":
          !isAddedToCart && colorScheme === "verry-berry",
        // high-seas
        "!bg-hsBlue2-300 text-white focus:outline-none":
          isAddedToCart && colorScheme === "high-seas",
        "bg-hsBlue2-500 hover:bg-hsBlue2-300 text-white focus:outline-none":
          !isAddedToCart && colorScheme === "high-seas",
        // eat-my-style
        "!bg-emsBlue-900 text-white focus:outline-none":
          isAddedToCart && colorScheme === "eat-my-style",
        "bg-emsBlue-700 hover:bg-emsBlue-900 text-white focus:outline-none":
          !isAddedToCart && colorScheme === "eat-my-style",
      }
    )
...
return (
    <button
      className={buttonStyling(isAddedToCart, colorScheme, isMobileFullWidth)}
      onClick={() => handleAddtoCart(1)}
    >
....

And I feel that it is easy to understand, easy to change and easy to write. Would you disagree?

Using ternaries and single classNames would simply move what I am trying to avoid into a different place while not allowing me to use Headwind and Tailwind Intellisense (but adding of course the awesome typescript support).

Am I missing something here or am I approaching this the wrong way?
Also using single classNames would lead to an incredible amount of statements; you surely must mean that another way, correct?

@muhammadsammy
Copy link
Owner

muhammadsammy commented Mar 12, 2021

Hey @muhammadsammy !

Thank you for your answer. I would really like to avoid ternaries with single classNames as this would lead to the same conditional mess I have been in before. Why is passing multiple classNames considered problematic?

It would work but it won't give you the typescript support or validation, for me I tried your example and It gave me errors
See TS Playground

image

@Hahlh
Copy link

Hahlh commented Mar 12, 2021

I see. That's a shame. I will have to try to find a hybrid solution or to drop the typescript support / validation for this for the moment. My main goal atm is finding a clean solution for all the complex conditional styling. After that I will work to put validation on top.

But it should be possible to pass the in wrapped in an additional classnames(...) and gets validation etc back, correct?

@muhammadsammy
Copy link
Owner

muhammadsammy commented Mar 12, 2021

But it should be possible to pass the in wrapped in an additional classnames(...) and gets validation etc back, correct?

If I understood you correctly, yes.
You could use nested classnames() inside another classnames instead of doing multiple classes into one string

Also I think doing something like should be fine:

classnames(
    [buttonBaseStyle],
    {
      // Layout
      [classnames('w-full', 'lg:max-w-max', 'py-3', 'lg:py-1')]: isMobileWidth,
	  ....
    },
....
)

@Hahlh
Copy link

Hahlh commented Mar 12, 2021

That's exactly what I settled on for the moment :)

This should be a great middle ground for the moment.

Tooltips that show in what css the classes result are not to be expected in general, correct?

@Hahlh
Copy link

Hahlh commented Mar 12, 2021

I am still somewhat confused about how to get my custom classes in. I will need to learn more about Typescript and come back to this.

Thank you for the help @muhammadsammy, much appreciated!

@muhammadsammy
Copy link
Owner

Tooltips that show in what css the classes result are not to be expected in general, correct?

That is correct. the issue for tracking this is here: #10. But it's not supported yet in TS (microsoft/TypeScript#38106).

I am still somewhat confused about how to get my custom classes in. I will need to learn more about Typescript and come back to this.

Thank you for the help @muhammadsammy, much appreciated!

You are welcome. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

4 participants