Releases: varabyte/kobweb
v0.12.3
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
orAnchor
.
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 findMETA-INF
resources to work. Before, Kobweb would fail to load any such services.
- For example, this is particularly helpful if you are using a library that uses
v0.12.2
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
.
- There are many libraries a user might use in their Kobweb server code which use reflection under the hood, such as database libraries like
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
)
)
),
)
)
v0.12.1
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:
- 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
}
- Remove
kotlin-js-store
from your project root's.gitignore
file - If
kobweb run
results in a build error related to youryarn.lock
file, quit Kobweb and then run./gradlew kotlinUpgradeYarnLock
. Once finished, runkobweb 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
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 visitsslug/
, or you registerslug/
and the user visitsslug
, Kobweb will now send you to the right destination instead of giving you a 404 error.
- i.e. if you register
- 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
- Added type-safe versions of all the background modifiers.
- Added
Modifier.resize
- Added
Modifier.caretColor
- Add a handful of common fontweight constants to the
FontWeight
class. - Fix logic issues with Popup placement not working.
- Move init annotations under their own subpackage.
v0.11.11
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 themain.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
andComponentVariant
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.
- The lambda is marked
- Fixed a bug with the box shadow API where if you only specified the
spreadRadius
, it actually set theblurRadius
.- 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)
- If you notice any of your box shadows acting strangely after updating, make sure you don't have a call that looks like
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
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.
- Before:
- You can now set
margin
andpadding
modifiers onTooltip
s, 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.
- 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
Backend
v0.12.0
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:
- In your build script, update your kobweb block:
kobweb {
yarn.lockChangedStrategy.set(YarnLockChangedStrategy.Fail)
}
- Remove
kotlin-js-store
from your project root's.gitignore
file - If
kobweb run
results in a build error related to youryarn.lock
file, quit Kobweb and then run./gradlew kotlinUpgradeYarnLock
. Once finished, runkobweb 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
Frontend
- Add modifiers for
filter
andbackdropFilter
styles.
Silk
- You can now declare
ComponentStyle
andComponentVariant
instances usingby
delegation.- e.g. replacing
val ExampleStyle = ComponentStyle("example")
withval ExampleStyle by ComponentStyle
- e.g. replacing
- Provide access to
colorMode
inKeyframes
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
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
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 callingctx.stylesheet.registerKeyframes(...)
- You can also declare keyframes manually using an
- (Potentially backwards incompatible) The
Button#onClick
callback parameter now provides aSyntheticMouseEvent
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 thisonClick = { clickHandler() }
- If you get a compile error, change code like this:
- Added more options for
width
andheight
modifiers via the newWidth
andHeight
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!") }
- For example, you can now show a tooltip in response to clicking on a button:
- 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.