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! :-)")
}
}
}