Okay, I've got it to work now, which included several steps.
- Install npm dependencies
kotlin {
...
sourceSets {
val jsMain by getting {
dependencies {
// dependencies for Compose for Web
implementation(compose.web.core)
implementation(compose.runtime)
// dependencies for Clarity Design System
implementation(npm("@cds/core", "5.6.0"))
implementation(npm("@cds/city", "1.1.0"))
// dependency for webpack - see step 3
implementation(npm("file-loader", "6.2.0"))
}
}
...
}
}
- Enable css support
This seems to be required, in order to include the global stylesheets.
kotlin {
js(IR) {
browser {
...
commonWebpackConfig {
cssSupport.enabled = true
}
}
...
}
...
}
- Add support for
.woff2
files included in stylesheet of Clarity
The stylesheet of CDS include font files of type .woff2
, whose support in webpack must be configured.
This can be achieved by creating the file webpack.config.d/support-fonts.js
at the project root with the following content:
config.module.rules.push({
test: /\.(woff(2)?|ttf|eot|svg|gif|png|jpe?g)(\?v=\d+\.\d+\.\d+)?$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
}
}]
});
- Include global stylesheets
external fun require(module: String): dynamic
fun main() {
require("modern-normalize/modern-normalize.css")
require("@cds/core/global.min.css")
require("@cds/core/styles/module.shims.min.css")
require("@cds/city/css/bundles/default.min.css")
...
}
- Import
register.js
for desired web component
external fun require(module: String): dynamic
fun main() {
...
require("@cds/core/button/register.js")
...
}
- Create @Composable for the web component
Sadly this solution makes use of APIs marked as @OptIn(ComposeWebInternalApi::class)
,
which stands for "This API is internal and is likely to change in the future".
Any hints on how this may be implemented without relying on internal APIs are appreciated.
@Composable
fun CdsButton(
status: CdsButtonStatus = CdsButtonStatus.Primary,
attrs: AttrBuilderContext<HTMLElement>? = null,
content: ContentBuilder<HTMLElement>? = null
) = TagElement(
elementBuilder = CdsElementBuilder("cds-button"),
applyAttrs = {
if (attrs != null) apply(attrs)
attr("status", status.attributeValue)
},
content = content
)
/**
* This is a copy of the private class org.jetbrains.compose.web.dom.ElementBuilderImplementation
*/
internal class CdsElementBuilder<TElement : Element>(private val tagName: String) : ElementBuilder<TElement> {
private val element: Element by lazy {
document.createElement(tagName)
}
override fun create(): TElement = element.cloneNode() as TElement
}
sealed interface CdsButtonStatus {
object Primary : CdsButtonStatus
...
}
internal val CdsButtonStatus.attributeValue
get() = when (this) {
CdsButtonStatus.Primary -> "primary"
...
}
- Make us of your
@Composable
!
fun main() {
...
renderComposable(rootElementId = "root") {
CdsButton(
status = CdsButtonStatus.Success
) {
Text("It works! :-)")
}
}
}