Skip to content

v0.18.0

Compare
Choose a tag to compare
@bitspittle bitspittle released this 20 May 16:06

This release introduces the new CssStyle concept, which supersedes and obsoletes the previous ComponentStyle concept.

Important

Planning to upgrade? Review instructions in the README.

This release is one of the most significant changes we've made since we've started Kobweb development. These changes have been in discussion and development in the background for over eight months(!!!).

Caution

This release will likely introduce many deprecation warnings to your project. Please don't skip over the next section!

⚠️ Migrating your project

As authors of the framework, we're very excited about this release (and relieved to be finally getting it out there), but users should be prepared to hit anywhere from a handful to a bunch of warnings after upgrading. We've done everything we could to make the migration process as easy for users to do as possible, but we want to minimize surprise, which is why we're mentioning this up front.

If you are in the middle of a large change to your site, you probably want to hold off on upgrading until you can get your changes in.

After upgrading to Kobweb 0.18.0, users are encouraged to run ./gradlew kobwebMigrateToCssStyle in a clean git branch.

For most projects, the automigration task should just work; in rare cases, some projects using more advanced features may run into errors which should be easily resolvable.

Users can read the full story about Cssstyle here, including detailed migration support at the end of it.

A brief CssStyle overview

The short version is, this old pattern:

val ExampleStyle by ComponentStyle {
   /* ... */
}

has been replaced with

val ExampleStyle = CssStyle {
   /* ... */
}

"That's it?" you might be thinking. "You're so excited about a name change?"

Well, getting rid of the by keyword (a source of confusion for many new users) is already a nice win. But more importantly, we wrangled with a feature that organically grew out the constraints of its original design and fixed some of the longstanding issues with it.

Originally, ComponentStyle was meant to be a mechanism just for Silk to use internally when defining widgets, but it became the common and recommended approach for Kobweb users everywhere to create styles, even if the styles they were creating had nothing to do with any specific component. (For example, Silk even did this itself! It provides the SmoothColorStyle for smooth background color transitions; that's not really something that should be called a "component" style).

Note

In the context of Kobweb Silk, a style is Kotlin code that ultimately gets converted into / registered as a CSS stylesheet entry. Not too familiar with CSS stylesheet entries or why you should care about them? You can review the README section about them.

Moving forward, Kobweb now supports three broad categories of styles that we've identified across many users' projects: general styles, component styles, restricted styles.

General Styles

General styles are the most common type, and if you've been using ComponentStyle in your codebase, probably 95-100% of those declarations fall into this category. This case is just a block of related, open-ended, useful style values.

val HeaderTextStyle = CssStyle.base {
   Modifier.fontSize(32.px).fontWeight(FontWeight.Bold)
}

Starting in 0.18.0, you can now extend styles, which generate a new style that wraps its source style:

val TextStyle = CssStyle.base { Modifier.fontFamily("customfont") }

val HeaderTextStyle = TextStyle.extendedByBase {
   Modifier.fontSize(32.px).fontWeight(FontWeight.Bold)
}

val LoudHeaderTextStyle = HeaderTextStyle.extendedByBase {
   Modifier.color(Colors.Red).backgroundColor(Colors.Yellow)
}

With the above declared, LoudHeaderTextStyle.toModifier() would apply itself and its dependent styles, setting font family, font size, and colors all in a single invocation.

Component Styles

Component styles are the ones we originally designed -- styles with a niche purpose to back some widget and allow users to generates variants (i.e. style tweaks) on top of them.

As a bonus, starting in 0.18.0, they are now typed, so that you can no longer use a variant created by one of these styles with another style.

sealed interface ProgressKind : ComponentKind
val ProgressStyle = CssStyle<ProgressKind> { /* ... */ }
val IndeterminiteProgressVariant = ProgressStyle.addVariant { /* ... */ }

@Composable
fun Progress(
   modifier: Modifier = Modifier
   variant: CssStyleVariant<ProgressKind>? = null
) {
   val finalModifier = ProgressStyle.toModifier(variant).then(modifier)
   Box(finalModifier) { /* ... */ }
}

Restricted Styles

Restricted styles, the final category, are a way to create a class that exposes a limited set of constructor parameters, generating a style behind the scenes. We call it restricted because, unlike the other types of style declarations which are totally open-ended, these styles are constrained by the handful of constructor parameters that the class owner exposes.

class ProgressSize(size: CSSLengthNumericValue) :
   CssStyle.Restricted.Base(Modifier.size(size)) {
   companion object {
      val SM = ProgressSize(0.5.cssRem)
      val MD = ProgressSize(1.cssRem)
      val LG = ProgressSize(1.5.cssRem)
   }
}

CssStyle document

This concludes a brief overview of the new feature, but to see more details, read this document.


Thanks

I'd like to take a moment to express an incalculable amount of thanks to @DennisTsar, without whom this feature wouldn't exist. He did a ton of foundational exploration and work, but more than that, he identifyied and raised concerns about ComponentStyle in the first place.

I hope everyone working in open source is lucky enough to get to work with a core contributor of his generosity, good sense, and ability.


A final note

As library authors, we'd in general like very much not to make drastic changes like this, because we understand how disruptive it can be to our users who are just trying to get their work done.

Of course, it has been thanks to exposure from two years of some of the amazing projects that our users have created that has helped us improve our understanding of the domain. Normally, we can make incremental fixes here and there, but in this case, there was no way around ripping out the floor and installing a new one.

Still, we wanted to thank our users for their patience and understanding. We hope moving forward that people find CssStyle more convenient to use, due to its shorter name (easier to type!), improved type-safety, and extended feature set.


Full Changelog: v0.17.3...v0.18.0