gaucho-labs/tailwind-fuse

Add `merge_class` and `build` (or similar) methods to builder.

Closed this issue · 4 comments

Imo 2 features missing from variant() builders:

  • A way to add custom classes (via merge (like with_class but outputs the builder) without converting to string.
  • build() on the builder to output the main TwClass struct.

Why?

I started thinking about this when there's a component with 2 layers (e.g. div inside div). I need to apply one of the variant's classes to the inner div, and the others to the outer. If I could supply the TwClass struct to the component, it would be able to render variants and decompose as needed. Hence the need to build() the builder into the TwClass and allow the external code to override classes on the builder, without actually converting to a string yet, as the component handles that part.

If there's a better way to solve the use case, that would be fine too!

Update: I solved this with nested specifiers.

Feel free to close if that's how you want to support this use case but could still be useful in more complex cases. :)

I think this is reasonable, thank you for the suggestion. Makes me re-think the API a bit.

  • Add add_class() method to Builder struct, that will write to an Option<String> field.
  • Rename variant() method to builder() for the sake of clarity
#[derive(TwClass)]
struct Btn {
    size: BtnSize,
    color: BtnColor,
}

#[derive(TwVariant)]
enum BtnSize {
    #[tw(default, class = "h-9 px-4 py-2")]
    Default,
    #[tw(class = "h-8 px-3")]
    Sm,
    #[tw(class = "h-10 px-8")]
    Lg,
}

#[derive(TwVariant)]
enum BtnColor {
    #[tw(default, class = "bg-blue-500 text-blue-100")]
    Blue,
    #[tw(class = "bg-red-500 text-red-100")]
    Red,
}

let builder1 = Btn::builder().add_class("flex");
// Now you can clone the builder.
let builder2 = builder1.clone()

let class1 = builder1.to_class()
// more that one add_class call would append to end of string. 
let class2 = builder2.add_class("items-center").to_class()

The build method also makes sense. I will probably implement From<BtnBuilder> for Btn and vice-versa, and just invoke these conversions from the appropriately named methods.

Let me know what you think @zakstucke @friendlymatthew

closed by #17

elected to not have string field in builder because that would prevent it from implementing Copy

@nicoburniske thanks for this! The build() is great, it allows ways of getting around the custom classes thing too.

Main pattern I'm normally using now is accepting the fuse class (after build()), then any class string overrides (usually just for the main class struct, but sometimes for variants too) that can be all managed internally in the component if needed.