In my design language I have a `Badge` component l...
# compose
u
In my design language I have a
Badge
component like this Should I model the variants as
NoteBadge, AttentionBadge etc
i.e. a dedicated composable or a
Badge(variant = Note/Attention/etc)
? I did the first, but badge often represents a status of something -> i.e. it transitions between different variants of the badge if I have a
Copy code
when (status) {
   is Foo -> SuccessBadge()
   is Bar -> ErrorBadge()
}
that "breaks" structured identity right?
a
If you were to follow material guidelines you should be doing something like BadgeDefaults
so colors = BadgeDefaults.dangerColors() and so on
u
yea but I dont like having a color parameter, that opens it up to anything, I only have the 6 variants
or rather the color is a detail of the type variant
a
for scaling defaults are better
if you feel like this solution does not for for you than you can have separate variants
u
yea I want to close it down, only have finite number of variants
but my question is rather should that be a enum parameter on a single composable, or six composables (without param) ?
a
Personally I would use interfaces for this
u
interfaces? like kotlin
interface
?
a
yes
u
how, not sure what you mean
u
not sure if I see the
interface
are you referring to the
Copy code
class ButtonColors(
    backgroundColor: Color,
    disabledBackgroundColor: Color,
    contentColor: Color,
    disabledContentColor: Color
) {
    fun backgroundColor(enabled: Boolean): Color { ... }

    fun contentColor(enabled: Boolean): Color { ... }
}

object ButtonDefaults {
    // default factory for the class
    // can be @Composable to access the theme composition locals
    fun colors(
        backgroundColor: Color = ...,
        disabledBackgroundColor: Color = ...,
        contentColor: Color = ...,
        disabledContentColor: Color = ...
    ): ButtonColors { ... }
}
?
a
The whole section has what you asked about, I personally would use interaface instead of class there but both are fine
u
but why do you want to "open" the composable?
a
its not open
you can optionally open it, but its not open
u
how is it not open, you can pass in `
Copy code
colors: ButtonColors
which then can be anything (Pink, Yellow, .. )
this pattern is fine but for a library, i.e. a generic components concrete app design languages only have x variants, not inifinite
a
Then you can close it down.
You can do whatever you want
Defaults are good for scaling in case you need another style
u
I know, but then again if you analogize with buttons, you have
FilledButton
OutlinedButton
a
yes and still you can pass the same color tokes to both using defaults
u
and from what I've seen people wrap those inside say
PrimaryButton() SecondaryButton()
i.e. not
MyButton(variant = Primary/Secondary)
a
If you think that works better for you
go with that aproach
u
both "work", my question whether is that a good idea, since that breaks structured concurrency when whening over a status
with buttons, you rarelly transition primary to secondary
a
This way, while not introducing the overhead and complexities of the “styles” pattern, we isolate the configuration of a specific part of the component. Additionally, unlike plain default expression,
ComponentColors
or
ComponentElevation
classes allow for more granular control, where the user can specify the enabled and disabled colors/elevation separately.
u
I believe those are guidelenss for libraries, like material your design languange implementation should not allow for inifinite variantion, but rather a closed down set of lego bricks for "feature" people to use otherwise people will override and you'll lose control
same like
Typography
a
It depends on whether they have different designs, or they share the same design but have some different presets. Also I don’t think this has anything to do with whether you are creating a library. You always expose the parameters that you want to allow customization of, be it a library or not.
u
right, I dont want any customization on callsite's part, only to pick badge level "semantically"
s
I'd personally prefer passing an enum as a parameter, seems cleaner to me, since all these badges have the same design.
for transitions, i'm not sure if you want to "animate" it, but if that's what you want, you can either: 1. animate from the outside, with a
AnimatedContent
or something like that, but it may not look super smooth. 2. animate from the inside, e.g. by adding a
Modifier.animateSizeChanges
to the inner text, or making the color an animated state derived from the badge status, but i'm not sure if that's very idiomatic
there's many approaches, basically choose what works best for you the suggestions by @Arsildo Murati would be useful when you want even more customization to the badges. if 6 modes (with pre-specified colors) are all you need, just make an enum. when you need more, then you can consider a more scalable approach in due time. don't overcomplicate it just because "future-proofing"
u
yea transition would be in text+color (i.e. inactive > active)
but youre right, anim needs to have support from inside, guess then there is only one option i suppose
👌 1
a
I don’t know about your design systems requirements, but for me, an animation from error to success for example would look weird if the color and text just change, but the badge stays. In my mind the badge is a kind of “chip” like a little card that does not morph - it would make more intuitive sense if the card (badge) gets switched out to another badge in an animation, where for example one badge turns around to reveal the second one (or something else) So I would go for a separate composable for each badge. But it also depends on how the code is structured on the inside of your composable. For instance if the enum leads to a lot of
if/else
or large
when
statements, then from a clean code perspective different, smaller, more focused composables (i.e. one for each badge) make more sense too.
u
yea you're probably right, I haven't tested how interpolating from red to green looks, probably shit
s
yeah, that's also an option since the ui is the same, you could make a
BadgeImpl
composable, and reuse it in every variant
i'm not sure, but i guess compose's color interpolation avoids that problem (through hsl or something, i forgot)
u
that's what I do now yes,
NoteBadge(text) etc
👍 1