2

我想稍微修改一下 Kotlin Compose for Web。在我过去的一些 Web 项目中,我使用了Clarity Design System (CDS)的一些 Web 组件。

在 JavaScript 或 TypeScript 项目中,您首先需要安装 npm 包@cds/core@cds/city. 其次,您必须包含一些全局样式表,例如通过 HTML 或 sass-import。对于您要使用的每个组件,您需要导入相应的register.js. 最后,您可以像任何其他标记一样在 HTML 中包含该组件:

<cds-button>Click me!</cds-button>

我尝试使用 Kotlin Compose for Web 复制这些步骤,但无法使其正常工作。任何帮助表示赞赏!

4

1 回答 1

2

好的,我现在已经开始工作了,其中包括几个步骤。

  1. 安装 npm 依赖项
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"))
            }
        }
        ...
    }
}

  1. 启用 css 支持
    这似乎是必需的,以便包含全局样式表。
kotlin {
    js(IR) {
        browser {
            ... 
            commonWebpackConfig {
                cssSupport.enabled = true
            }
        }
        ...
    }
    ...
}

  1. 添加对.woff2Clarity
    样式表中包含的文件的支持 CDS 的样式表包含 type 的字体文件,.woff2必须配置其在 webpack 中的支持。这可以通过webpack.config.d/support-fonts.js 在项目根目录创建具有以下内容的文件来实现:
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/'
        }
    }]
});
  1. 包括全局样式表
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")
    
    ...
}
  1. 导入register.js所需的 Web 组件
external fun require(module: String): dynamic

fun main() {
    ...
    
    require("@cds/core/button/register.js")

    ...
}
  1. 为 Web 组件创建 @Composable
    遗憾的是,此解决方案使用标记为 的 API @OptIn(ComposeWebInternalApi::class),它代表“此 API 是内部的,将来可能会更改”。任何关于如何在不依赖内部 API 的情况下实现这一点的提示都值得赞赏。
@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"
        ...
    }
  1. 让我们成为你的@Composable
fun main() {
    ...
    
    renderComposable(rootElementId = "root") {
        CdsButton(
            status = CdsButtonStatus.Success
        ) {
            Text("It works! :-)")
        }
    }
}
于 2021-12-05T16:39:53.710 回答