Skip to content

Releases: varabyte/kobweb

v0.12.3

24 Mar 17:56
Compare
Choose a tag to compare
v0.12.3 Pre-release
Pre-release

A relatively small but solid update -- and critical if your project used the routePrefix feature.

Frontend

  • Fixed an issue that broke the routePrefix feature.
    • Most users probably aren't using it, but if you are, this is a critical fix. See this blog post and search "routePrefix" for more information.
  • Simplified the API around the OpenLinkStrategy enumeration.
    • Before, several options were actually useless, essentially ignored by browsers. They have been removed.
    • Added the ability to configure default open link strategies for internal and external links (currently, internal site links are opened in place by default, while external site links are opened in a new tab). This could be potentially useful if you don't like Kobweb's external link default strategy and found yourself overloading it in every call to Link or Anchor.

Backend

  • Fixed Kobweb servers so they can now find resources.
    • For example, this is particularly helpful if you are using a library that uses ServiceLoader under the hood, which needs to find META-INF resources to work. Before, Kobweb would fail to load any such services.

v0.12.2

19 Mar 21:37
Compare
Choose a tag to compare
v0.12.2 Pre-release
Pre-release

This release saw a focus on fixing some issues with Kobweb's backend code, but radial gradients / CSS position support is also a potentially useful feature.

Frontend

  • Added support for radial gradients. (See below)
  • Added a CSSPosition for providing a Kotlin-idiomatic way for declaring a CSS position data type
    • (This should not be confused with the CSS position property, used for making elements relative, absolute, fixed, etc.)
  • Fixed an internal issue that was causing Router.navigateTo to not work with custom open link strategies.

Backend

  • Improved error reporting message by including "caused by" chain if your server route crashes in dev mode.
  • Stop stripping reflection support from the server jar (this was happening unintentionally by a minimize build step).
    • There are many libraries a user might use in their Kobweb server code which use reflection under the hood, such as database libraries like KMongo.

Gradle

  • Fix exception that could get thrown if you included an npm dependency in your JS dependencies block.
    • Previously, code assumed that a runtime dependency would either be a folder or a jar, based on tons of existing Gradle samples out in the wild. However, in JS, dependencies can be JS files apparently, which triggered an exception in Kobweb Gradle code.
  • Fixed an issue with Kobweb library resources not being discovered correctly when building on Windows machines.
    • Backslash path issues strike again...

Radial Gradients

The following code demonstrates Kobweb implementations for examples taken from the official docs:

// Example 1: Planet
val darkGray = Color.rgb(0x333333)
val lightGray = Color.rgb(0xeeeeee)
Box(
    Modifier.width(333.px).height(268.px)
        .backgroundImage(
            radialGradient(Circle, CSSPosition(x = 100.percent)) {
                add(darkGray, 0.percent, 50.percent)
                add(lightGray, 75.percent)
                add(darkGray, 75.percent)
            }
        )
)

// Example 2: Overlapping gradients
Box(
    Modifier.width(333.px).height(268.px)
        .background(
            CSSBackground(
                image = BackgroundImage.of(
                    radialGradient(
                        Ellipse,
                        Color.rgb(0xe66465),
                        Colors.Transparent,
                        CSSPosition.Top
                    )
                )
            ),
            CSSBackground(
                image = BackgroundImage.of(
                    radialGradient(
                        Ellipse,
                        Color.rgb(0x4d9f0c),
                        Colors.Transparent,
                        CSSPosition.Bottom
                    )
                )
            ),
        )
)

radial-gradient-demo

v0.12.1

11 Mar 21:56
Compare
Choose a tag to compare
v0.12.1 Pre-release
Pre-release

This release is feature-wise identical to v0.11.12 but targets Compose 1.3.1 / Kotlin 1.8.10.

Unfortunately, release v0.12.0 was dead out of the gate due to a major JS issue introduced in Kotlin 1.8.0, and users were recommended to skip it.

Therefore, users upgrading now may have missed the following information from the v0.12.0 release, which we are repeating here:


Note: Kobweb v0.12.0 is making some opinionated decisions around yarn locking. Most people will probably be OK not worrying about it, but you may wish to read on to decide if you want to override Kobweb's default behavior in your own project.

Since Kotlin 1.8.0, the Kotlin/JS Gradle plugin is a bit more strict about yarn.lock files, now expecting users to check kotlin-js-store/yarn.lock into source control as a best practice. By default, normal Kotlin/JS builds now fail if you had an old yarn.lock file that is about to get updated with some new values, requiring explicit user action to continue.

For Kobweb, however, we're currently taking the opinion that failing the build is probably too harsh for most simple, single-owner projects, and that most users can get away with regenerating the lock file every time.

As a result, the Kobweb plugin configures things to auto-regenerate the lock file by default, rather than failing. (This would be equivalent to you creating a new Kobweb project from scratch, at which point a new lock file would be generated with the latest values anyway)

If for your project you want to opt-in to failing the build if the lock file has changed, then I recommend taking the following steps:

  1. In your build script, update your kobweb block:
kobweb {
  yarn.lockChangedStrategy.set(YarnLockChangedStrategy.Fail)
 // or, yarn.lockChangedStrategy.set(YarnLockChangedStrategy.Ignore)
 // if you want to intentionally keep an older version of your yarn.lock file around
}
  1. Remove kotlin-js-store from your project root's .gitignore file
  2. If kobweb run results in a build error related to your yarn.lock file, quit Kobweb and then run ./gradlew kotlinUpgradeYarnLock. Once finished, run kobweb run again, which should now work without hitting that failure.

For more information, please read the official Kotlin docs discussing this feature and the official Yarn docs talking about yarn.lock files.

Also, you may wish to confer with the header docs in YarnBlock.kt.

v0.11.12

11 Mar 19:14
Compare
Choose a tag to compare
v0.11.12 Pre-release
Pre-release

A bunch of miscellaneous changes in this one.

Frontend

  • Add hsl factory methods for Color
  • Add argb factory methods for Color.
    • Before, there were rgba methods, which is very web, but Android developers are more familiar with the opposite order.
  • Add fallback routing behavior for missing / extra slashes.
    • i.e. if you register slug and the user visits slug/, or you register slug/ and the user visits slug, Kobweb will now send you to the right destination instead of giving you a 404 error.
  • Add Router.addRouteInterceptor, in case you need to add special case handling for one-off URL redirects, for example maybe an old page was renamed due a spelling error, or a legacy path has been migrated to a new location.

Silk

v0.11.11

26 Feb 04:17
Compare
Choose a tag to compare
v0.11.11 Pre-release
Pre-release

The biggest change in v0.11.11 is support for CSS variables. See its section in the README for more details.

Frontend

  • Fixed an issue where really long titles in the kobweb.conf file would cause a compile error (due to how the main.kt file was getting generated in that case)

Silk

  • CSSVariables are now supported using the new StyleVariable class.
  • Introduced a new common SmoothColorStyle as a safer way to get smoother color transitions when you change your site's color mode (see below for more info).
  • (Potentially backwards incompatible) You now override SilkPalette settings in place (see below for more info).
  • Added additional versions for specifying extra modifiers when creating ComponentStyle and ComponentVariant instances, where you can pass in a lambda to produce some modifier lazily.
    • The lambda is marked @Composable, so you can call composable methods in there if you need to, which is useful for example since Silk color aware methods are composable.
  • Fixed a bug with the box shadow API where if you only specified the spreadRadius, it actually set the blurRadius.
    • If you notice any of your box shadows acting strangely after updating, make sure you don't have a call that looks like boxShadow(spreadRadius = 10.px, color = ...).
    • If you do, change it to boxShadow(blurRadius = 10.px, color = ...).
    • If you're on an older version of Kobweb and can't upgrade but want to set spread radius intentionally, use boxShadow(blurRadius = 0.px, spreadRadius = 10.px)

Applying SmoothColorStyle

Background (feel free to skip)

I tried to be smart with Surface, really, I did!

First, I made its background color change smoothly when the site's color mode changed (which looks better than snapping colors). That worked except children elements which set their own background colors would ruin the illusion by popping when the rest of the site animated smoothly.

So, next, I tried to make surface force all of its children to also transition their background colors. This seemed to work at first, but it prevented users from defining their own transition on their own elements, as the surface transition would take precedence. Instead of additive behavior, the surface transition would replace the user transition.

As a compromise, instead of applying this style automatically, I let people opt-in with a variant. However, even with that approach, I kept running into cases in my own code where too often I would try to create some cool transition only to shake my fist at the fact that the surface once again took precedence. The variant enabled a cool effect but it was a landmine that would explode in your face eventually.

So, at last, I've given up. No more attempts at inheriting transitions. Instead, opt-in as you need to. It actually doesn't take a lot of work for it to feel pretty good.

How to migrate your code

////// Before

Surface(variant = AnimatedColorSurfaceVariant) { ... }

////// After

// Step 1 [REQUIRED]
// Use `SmoothColorStyle` wherever you declare your root surface
Surface(SmoothColorStyle.toModifier()) {
   ...
   SiteHeader()
}

// Step 2: [OPTIONAL]
// Any children you declare which further modify their background color may want
// to add SmoothColorStyle as well.
// One way to do this is via `extraModifiers` when defining a `ComponentStyle`
val SiteHeaderStyle by ComponentStyle(extraModifiers = { SmoothColorStyle.toModifier() }) {
   base {
       Modifier
           .backgroundColor(SiteAccents[colorMode])
           .otherStuff(...)
   }
}

@Composable
private fun SiteHeader() {
   Box(SiteHeaderStyle.toModifier()) { ... }

   // This would also work, if you prefer it over using `extraModifiers`:
   // Box(listOf(SmoothColorStyle, SiteHeaderStyle).toModifier()) { ... }
}

Overriding the SilkPalette

Before, Silk Palettes were data objects, and you would modify the default Silk theme by doing some crazy copying. Now, the InitSilk function gives you access to a mutable structure which will be frozen after init time.

////// Before

@InitSilk
fun initSilk(ctx: InitSilkContext) {
   ctx.theme.palettes = SilkPalettes(
       light = ctx.theme.palettes.light.copy(
          background = themeBright,
          color = themeDark,
          button = ctx.theme.palettes.button.copy(hover = Colors.DarkPink)
        ),
       dark = ctx.theme.palettes.dark.copy(
           background = themeDark,
           color = themeBright,
           button = ctx.theme.palettes.button.copy(hover = Colors.Pink)
        )
    )
}

////// After

@InitSilk
fun initSilk(ctx: InitSilkContext) {
   ctx.theme.palettes.apply {
       light.background = themeBright
       light.color = themeDark
       light.button.hover = Colors.DarkPink
       dark.background = themeDark
       dark.color = themeBright
       dark.button.hover = Colors.Pink
   }
}

////// After (option 2)

// If you liked the way things were before (as it forced you to specify everything without missing anything),
// you can still do that too. Just add "Mutable":

@InitSilk
fun initSilk(ctx: InitSilkContext) {
   ctx.theme.palettes = MutableSilkPalettes(
       light = ctx.theme.palettes.light.copy(
          background = themeBright,
          color = themeDark,
          button = ctx.theme.palettes.button.copy(hover = Colors.DarkPink)
        ),
       dark = ctx.theme.palettes.dark.copy(
           background = themeDark,
           color = themeBright,
           button = ctx.theme.palettes.button.copy(hover = Colors.Pink)
        )
    )
}

v0.11.10

12 Feb 02:02
Compare
Choose a tag to compare
v0.11.10 Pre-release
Pre-release

This is a fairly small collection of miscellaneous, quality of life features and fixes.

Silk

  • Add missing modifiers for all remaining events (e.g. touch events, clipboard events)
  • Add a strongly-typed API for transitions
    • Before: transition("opacity 1s, color 2s"), after: transition(CSSTransition("opacity", 1.s), CSSTransition("color", 2.s))
    • Also, you can create a transition group: transition(*CSSTransition.group(listOf("opacity", "color", "background-color"), 1.s, Ease) if you want to apply the same transition values to multiple properties.
    • The provided API is now very similar to animations.
  • You can now set margin and padding modifiers on Tooltips, and the tooltip arrow will no longer be separated from the shifting content.
  • Tweaked the AnimatedColorSurfaceVariant recursive CSS logic to work just as well (as far as initial tests indicate) while being more selective in which children they affect.
    • This variant would previously interfere with users who were trying to use transitions on their own elements. It could still happen if you're adding a transition to a div, but all other elements are now excluded.

Backend

  • If any API route throws any sort of exception when a server is running in dev mode, it will be sent to and printed on the client in the console window.
    kobweb-server-crash-message

v0.12.0

04 Feb 00:17
Compare
Choose a tag to compare
v0.12.0 Pre-release
Pre-release
⚠️ ⚠️ ⚠️ IMPORTANT⚠️ ⚠️ ⚠️
There is a major issue (likely in Kotlin 1.8.0) that's affecting building release artifacts for some Kotlin/JS users. As a result, using v0.12.0 is not recommended at this point. Instead, please stick to the latest v0.11.x release for now.

v0.12.1 will be released as soon as the upstream issue is remedied.

This release is feature-wise the same as 0.11.9, except it targets Compose 1.3.0 and Kotlin 1.8.0.


Note: Kobweb v0.12.0 is making some opinionated decisions around yarn locking. Most people will probably be OK not worrying about it, but you may wish to read on to decide if you want to override Kobweb's default behavior in your own project.

In Kotlin 1.8.0, the Kotlin/JS Gradle plugin is a bit more strict about yarn.lock files, starting to expect users to check kotlin-js-store/yarn.lock into source control as a best practice. By default, normal Kotlin/JS builds now fail if you had an old yarn.lock file that is about to get updated with some new values, requiring explicit user action to continue.

For Kobweb, however, we're currently taking the opinion that failing the build is probably too harsh for most simple, single-owner projects and that most users can get away with regenerating the lock file every time. As a result, the Kobweb plugin configures things to auto-regenerate the lock file by default, rather than failing.

If for your project you want to opt-in to failing the build if the lock file has changed, then I recommend taking the following steps:

  1. In your build script, update your kobweb block:
kobweb {
  yarn.lockChangedStrategy.set(YarnLockChangedStrategy.Fail)
}
  1. Remove kotlin-js-store from your project root's .gitignore file
  2. If kobweb run results in a build error related to your yarn.lock file, quit Kobweb and then run ./gradlew kotlinUpgradeYarnLock. Once finished, run kobweb run again, which should now work without hitting that failure.

For more information, please read the official Kotlin docs discussing this feature and the official Yarn docs talking about yarn.lock files.

Also, you may wish to confer with the header docs in YarnBlock.kt.

v0.11.9

03 Feb 00:31
Compare
Choose a tag to compare
v0.11.9 Pre-release
Pre-release

Frontend

  • Add modifiers for filter and backdropFilter styles.

Silk

  • You can now declare ComponentStyle and ComponentVariant instances using by delegation.
    • e.g. replacing val ExampleStyle = ComponentStyle("example") with val ExampleStyle by ComponentStyle
  • Provide access to colorMode in Keyframes builders, allowing you to create theme-dependent animations.
  • Fix bug with Button and Link with not preventing default behavior, which could end with both you and the browser triggering behavior on the same click

Backend

  • Fixed API routes not working on Windows.

cli-v0.9.11

01 Feb 17:54
Compare
Choose a tag to compare
cli-v0.9.11 Pre-release
Pre-release

With this release, we focused on testing the Kobweb CLI heavily on Windows.

Changes

  • Kobweb CLI now shutdowns correctly on Windows (i.e. when you press Q)
  • You can now press CTRL-C even on Windows (this used to only work on *nix systems)
  • You can now call kobweb create without any arguments and be shown a list of projects to choose from.

v0.11.8

24 Jan 18:09
Compare
Choose a tag to compare
v0.11.8 Pre-release
Pre-release

The biggest feature in this new release is support for animation keyframes using Kobweb's Modifier concept. For example, you can now do this:

val Bounce by keyframes {
  from { Modifier.translateX((-50).percent) }
  to { Modifier.translateX((50).percent) }
}

// Later
Box(
  Modifier
    .animation(Bounce.toAnimation(
      duration = 2.s,
      timingFunction = AnimationTimingFunction.EaseIn,
      direction = AnimationDirection.Alternate,
      iterationCount = AnimationIterationCount.Infinite
  )
) { ... }

Silk

  • Add support for defining keyframes and declaring animations via Modifier.
    • You can also declare keyframes manually using an @InitSilk annotated method and calling ctx.stylesheet.registerKeyframes(...)
  • (Potentially backwards incompatible) The Button#onClick callback parameter now provides a SyntheticMouseEvent argument. This lets you check if any modifier keys (e.g. ctrl/alt/shift) are being pressed.
    • If you get a compile error, change code like this: onClick = ::clickHandler to this onClick = { clickHandler() }
  • Added more options for width and height modifiers via the new Width and Height css classes, e.g. Modifier.width(Width.FitContent)
  • Tweaked Popup implementation so you can now create a popup with the mouse already over the element that triggers the popup.
    • For example, you can now show a tooltip in response to clicking on a button:
      var showTooltip by remember { mutableStateOf(false) }
      Button(
         onClick = { handleCopy(); showTooltip = true },
         Modifier.onMouseLeave { showTooltip = false }
      ) { Text("Copy") }
      if (showTooltip) {
         Tooltip(ElementTarget.PreviousSibling, "Copied!")
      }
      
  • Refactored the location of where Silk initialization code lives, e.g. the InitSilk annotation. Old code should still work for now but you may get deprecation warnings suggesting you change your import locations.

Gradle

  • Fixed an issue with export sometimes causing OOM events when building a Kobweb project.
    • This was because dev and prod builds could happen at the same time before. After preventing this, exports take a bit longer, but it feels a lot safer to not have two related compiles happening at the same time.