:spider_web: Latest Kobweb v0.18.0 :spider_web: <h...
# kobweb
d
🕸️ Latest Kobweb v0.18.0 🕸️ https://github.com/varabyte/kobweb/releases/tag/v0.18.0 This release is a long time coming and is one of the most widespread changes we've made to Kobweb in its history. Essentially, we've migrated Kobweb from the
ComponentStyle
concept to the
CssStyle
concept. In many cases, it's the same feature with a different name; but in other ways, it is a refactoring which has allowed us to correct longstanding issues with the original feature. I wrote a lot more about this in the release notes, so please do check them out. This is a release that everyone with an active Kobweb codebase should upgrade to sooner than later, but do not upgrade to it blindly. We're genuinely hoping the migration is smooth for almost everybody, but if you do upgrade and have issues, feel free to respond in this post's thread.
🎉 2
K 2
K 1
As a quick aside, we are aware that compose 1.6.10 has been released. Normally, we would rush out a v0.18.1 release to add compatbility to it. However, we are probably going to wait a little bit to see what gets announced at KotlinConf as we expect the K2 compiler to get stabilized, which could affect how we release the next version of Kobweb.
👀 1
r
Hi David, congrats on this new release! I'm happy to see the project growing this way! After upgrading to 0.18.0, I noticed some issues. I have a few issues with the styles related to the layers. For instance, I needed to wrap my base styles, registered within
@InitSilk
within a
layer("reset")
, however, there are other issues that will take a while to figure out why they are happening. Is there any guidance explaining how the new CssStyle is layered, so I could have a better picture of where to look?
d
Hey @Rafael Tonholo wow I did not expect anyone to get caught up in our introduction of layers. Sorry about that. I thought what we had was strictly better than before. Starting in 0.18.0, Kobweb now uses the following layering order:
reset
,
component-styles
,
component-variants
,
restricted-styles
, and
general-styles
(least precedence to most). I assume you are familiar with layers based on how you wrote your last message, but for any style you define that is not in an explicit layer, they will take precedence over all of those. If you are seeing weird style selector priority issues, that means you are defining styles in your own code that you expected to have less precedence to Silk styles? As you might expect, declaring styles using the
CssStyle
method results in the following layers:
CssStyle { ... }
->
general-styles
CssStyle<ComponentKind> { ... }
->
component-styles
SomeStyle.addVariant { ... }
->
comonent-variants
class SomeClass : CssStyle.Restricted(...)
->
restricted-styles
while in
@InitSilk
doing something like
ctx.stylesheet.registerStyle("a") { ... }
is unlayered by default.
The declaration of layer orders can be seen here. While the layer feature is not something we're not making noise about yet, we do have a relevant header document here.
r
Thanks for the feedback! I believe I was able to fix the issues I was getting. From what I understood was happening: 1. The
registerStyleBase
, as you stated, is not being layered, and for that reason, it is taking precedence over all the other styles. To fix that I just put them under the reset layer. I'm just not sure if that should be the expected behaviour. When I create a base style, I expect all my other styles to override it as I create new styles, but the way it is now is the opposite. 2. The rest of the issues were related to Silk components. I was doing some overrides on foundation components (Row, Column) to lay them out differently when mobile/desktop or even hiding it. As these components' classes are not layered, they were taking precedence over the custom style I've created. The fix was basically moving out from them to
Div
instead. Also, thank you for explaining how the layers are being chosen, that will facilitate me in the future. And I need to say, the
kobwebMigrateToCssStyle
task did a very good job during the migration 🙂
d
When I create a base style, I expect all my other styles to override it as I create new styles, but the way it is now is the opposite.
Thanks for the feedback. I will think about that today. Using the
reset
layer will indeed work and should be safe to do so, although I can appreciate maybe you want another category name you can use (something I wedge between "reset" and "component-styles"). (The reset name comes from the idea of a CSS reset, as in how people reset inconsistent styles introduced by different browsers and also to make up mistakes due to legacy decisions; and that's not really what your styles are, here)
I was doing some overrides on foundation components
Just curious, how were you overriding them?
And I need to say, the
kobwebMigrateToCssStyle
task did a very good job during the migration 🙂
Glad to hear a positive data point, thanks! It's one thing to write and test it on our end, another thing entirely to run it out in the wild across everyone's projects...
@Rafael Tonholo I just uploaded 0.18.1-SNAPSHOT which updates the logic for
registerStyle
and
registerStyleBase
methods, which by default now applies them to a
base
layer which sits between
reset
and
component-styles
. (In other words, you should be able to remove your reset layer hack and not specify any layer actually and things should work as before). If you try it and it works for you, let me know!
👀 1
r
Just curious, how were you overriding them?
Just adding a style. Here is an example of what I was doing:
Copy code
val AppBarActionButtonsStyle = CssStyle {
    base {
        Modifier.display(DisplayStyle.None)
    }
    Breakpoint.MD {
        Modifier
            .display(DisplayStyle.Flex)
            .gap(10.dp)
    }
}

@Composable
fun AppBar() {
        // another stuff
        Row(
            modifier = AppBarActionButtonsStyle.toModifier(),
        ) {
            ColorModeButton(
                modifier = Modifier.alignSelf(AlignSelf.FlexEnd),
            )
            LanguageChanger(
                selected = selectedLanguage,
                onLocaleChange = onLocaleChange,
            )
        }
}
In the above example, I hide the row when it is on mobile because these action items show inside a dialog in that case. In another case, I was creating an adaptive layout where on Desktop it shows as a row and on mobile shows as a column:
Copy code
val AdaptiveLayoutStyles = CssStyle {
    base {
        Modifier
            .display(DisplayStyle.Flex)
            .flexDirection(FlexDirection.Column)
    }

    Breakpoint.LG {
        Modifier
            .flexDirection(FlexDirection.Row)
    }
}
@Composable
actual fun AdaptiveLayout(
    modifier: Modifier,
    listPanel: @Composable () -> Unit,
    detailPanel: @Composable () -> Unit,
) {
    val adaptiveLayoutModifier = AdaptiveLayoutStyles.toModifier()
    val responsiveAlignment by responsiveStateOf(ResponsiveValues(base = Alignment.Center, lg = Alignment.TopStart))
    Box(
        modifier = adaptiveLayoutModifier then modifier,
        contentAlignment = responsiveAlignment,
    ) {
        listPanel()
        detailPanel()
    }
}
As Box uses the
display: grid
, the
flex-direction
never works and gets overridden because Box is not under a layer. Probably I should not have used
Box
in this case, but I came up with the idea of the
Box
from Compose and that is why I chose it 😛
The reset name comes from the idea of a CSS reset
That is exactly what I was expecting for that layer, which is why I used the same layer when I fixed it in my end using 0.18.0. BTW, with 0.18.1-SNAPSHOT, the base styles work as I was expecting!! Thanks for adding the
base
layer, that makes it even better. Now I can separate what is a reset and what is just the base style
d
Great! Thanks for your feedback, as once you mentioned it it totally made sense.
Appreciate the row/col example. I wonder if those elements (
.kobweb-box
etc.) should be part of the base layer (or some new layer either with slightly more or less precedence than
base
). But switching over to a Div seems like a reasonable choice to avoid worrying about it for now!
I'm thinking if I wanted to toggle something to switch from a row to a col based on some condition, I would either use an if/else, or I would create two styles, one for rows and one for cols, and then compose both of them but with one of them set to hidden.
Copy code
Row(Modifier.thenUnless(useRows) { Modifier.display(None) })
Column(Modifier.thenIf(useRows) { Modifier.display(None) }}
BTW I don't think it's relevant here actually, but FYI there's a special Alignment / Arrangement value called
FromStyle
you can use: https://github.com/varabyte/kobweb/blob/ca7e45d7b102120ee6998c6d31fdf68e47af0ee4/f[…]e/src/jsMain/kotlin/com/varabyte/kobweb/compose/ui/Alignment.kt It doesn't prevent Box, Row, and Col from being grids, but it will prevent them from setting alignment / justification values, in case that ever matters to you, since you're more comfortable getting in there and setting styles yourself.