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

chore: update readme for v1 #22

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 209 additions & 11 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,32 +38,34 @@ We create an object from the class or helper where we define the configuration u
1. The `compound_variants` keyword argument where we declare the compound variants with their conditions and classes
1. The `defaults` keyword argument (optional) where we declare the default value for each variant.

## Example

Below we implement the [button component](https://tailwindui.com/components/application-ui/elements/buttons) from Tailwind UI.
Below we'll implement the [button component](https://tailwindui.com/components/application-ui/elements/buttons) from Tailwind UI.

```ruby
# Define the variants and defaults
button_classes = ClassVariants.build(
base: "inline-flex items-center rounded border border-transparent font-medium text-white hover:text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2",
variants: {
color: {
indigo: "bg-indigo-600 hover:bg-indigo-700 focus:ring-indigo-500",
red: "bg-red-600 hover:bg-red-700 focus:ring-red-500",
blue: "bg-blue-600 hover:bg-blue-700 focus:ring-blue-500",
},
size: {
sm: "px-2.5 py-1.5 text-xs",
md: "px-3 py-2 text-sm",
lg: "px-4 py-2 text-sm",
xl: "px-4 py-2 text-base",
},
color: {
indigo: "bg-indigo-600 hover:bg-indigo-700 focus:ring-indigo-500",
red: "bg-red-600 hover:bg-red-700 focus:ring-red-500",
blue: "bg-blue-600 hover:bg-blue-700 focus:ring-blue-500",
},
compound_variants: [
{ color: :red, border: true, class: "border-red-800" },
{ color: :blue, border: true, class: "border-blue-800" }
]
# A variant whose value is a string will be expanded into a hash that looks
# like { true => "classes" }
block: "w-full justify-center",
icon: "w-full justify-center",
# Unless the key starts with !, in which case it will expand into
# { false => "classes" }
"!block": "w-auto",
"!icon": "w-auto",
},
defaults: {
size: :md,
Expand All @@ -78,7 +80,7 @@ button_classes.render
button_classes.render(color: :red, size: :xl, icon: true)
```

### Compound Variants
## Compound Variants

```ruby
button_classes = ClassVariants.build(
Expand All @@ -100,6 +102,172 @@ button_classes.render(color: :red) # => "inline-flex items-center rounded bg-red
button_classes.render(color: :red, border: true) # => "inline-flex items-center rounded bg-red-600 border border-red-600"
```

## Override classes with `render`

We can also override the builder classes in the `render` method.

```ruby
button_classes = ClassVariants.build(
base: "inline-flex items-center rounded",
variants: { ... },
)

button_classes.render(color: :red, class: "block")
```

Now, the `block` class will be appended to the classes bus.

If you're using the [`tailwind_merge`](#tailwind_merge) plugin it will override the `inline-flex` class.

## Block configurations

You might have scenarios where you have more advanced conditionals and you'd like to configure the classes using the block notation.

```ruby
alert_classes = ClassVariants.build do
# base
base "..."

# variant
variant color: :red, class: "..."

# compound variant
variant type: :button, color: :red, class: "..."

# defaults
defaults color: :red, type: :button
end

# usage
alert_classes.render(color: :red, type: :button)
```

## Slots

You might have components which have multiple slots or places where you'd like to use conditional classes.
`class_variants` supports that through slots.

```ruby
# Example

alert_classes = ClassVariants.build do
# base with slots
base do
slot :head, class: "..."
slot :body, class: "..."
end

# variant with slots
variant color: :red do
slot :head, class: "..."
slot :body, class: "..."
end

# compound variant with slots
variant type: :button, color: :red do
slot :head, class: "..."
slot :body, class: "..."
end

# set defaults
defaults color: :red, type: :button
end
```

```erb
<div>
<div class="<%= alert_classes.render(:head) %>">
Head of alert
</div>
<div class="<%= alert_classes.render(:body) %>">
Body of alert
</div>
</div>
```

## Full API

```ruby
# Configuration
alert_classes = ClassVariants.build(
base: "...",
variants: {
color: {
red: "...",
black: "..."
},
type: {
button: "...",
link: "..."
}
},
compound_variants: [],
defaults: {
color: :red,
type: :button
}
) do
# base without slots
base "..."

# base with slots
base do
slot :head, class: "..."
slot :body, class: "..."
end

# variant without slots
variant color: :red, class: "..."

# variant with slots
variant color: :red do
slot :head, class: "..."
slot :body, class: "..."
end

# compound variant without slots
variant type: :button, color: :red, class: "..."

# compound variant with slots
variant type: :button, color: :red do
slot :head, class: "..."
slot :body, class: "..."
end

# option 1 (my favorite)
defaults color: :red, type: :button

# option 2
defaults do
color :red
type :button
end
end

# Usage

# renders the defaults
alert_classes.render

# render default slot with custom variants
alert_classes.render(color: :red)

# render slot with defaults variants
alert_classes.render(:body)

# render slot with custom variants
alert_classes.render(:body, color: :red)

# if slot not exist, throw error? return empty classes?
alert_classes.render(:non_existent_slot, color: :red)

# render default slot with custom class (will be merged)
alert_classes.render(class: "...")

# render slot with custom class (will be merged)
alert_classes.render(:body, class: "...")
```

## Use with Rails

```ruby
Expand Down Expand Up @@ -135,6 +303,36 @@ end
<%= link_to :Avo, "https://avohq.io", class: button_classes.render(color: :red, size: :xl) %>
```

## Helper module

If you're developing something more complex you might want to use composition more. You might want to use the helper module for that.

```ruby
class MyClass
include ClassVariants::Helper

class_variants {
base: {},
variants: {}
}
end

MyClass.new.class_variants(:container, color: :red, class: "shadow")
```

## `tailwind_merge`

By default, the classes are merged using `concat`, but you can use the awesome [TailwindMerge](https://github.com/gjtorikian/tailwind_merge) gem.
Install the gem using `bundle add tailwind_merge` and use this configuration to enable it.

```ruby
ClassVariants.configure do |config|
adrianthedev marked this conversation as resolved.
Show resolved Hide resolved
config.process_classes_with do |classes|
TailwindMerge::Merger.new.merge(classes)
end
end
```

### Output

![](sample.jpg)
Expand Down