diff --git a/readme.md b/readme.md index b4b5209..d6c0722 100644 --- a/readme.md +++ b/readme.md @@ -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, @@ -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( @@ -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 +
+
+ Head of alert +
+
+ Body of alert +
+
+``` + +## 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 @@ -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| + config.process_classes_with do |classes| + TailwindMerge::Merger.new.merge(classes) + end +end +``` + ### Output ![](sample.jpg)