I want to use a bootstrap Card component in a react website created with kotlin-js. The app uses kotlin-react wrapper and react-bootstrap library.
react-bootstrap documentation says use <Card.Body> to put content.
<Card> <Card.Body>This is some text within a card body.</Card.Body> </Card>
So far I managed to import the Card JavaScript module into kotlin-js.
@file:JsModule("react-bootstrap/Card") import react.RClass import react.RProps @JsName("default") external val Card: RClass<RProps>
With this I could use the Card within a RComponent.
class Content : RComponent<RProps, RState>() { override fun RBuilder.render() { Card { +"Hello World" } } }
What renders to:
<div class="card"> Hello World </div>
What I additionally need is the CardBody component.
Something like this:
class Content : RComponent<RProps, RState>() { override fun RBuilder.render() { Card { CardBody { + "Hello World" } } } }
But the CardBody is not a separate react-bootstrap component which could be imported like the Card component. It is a value inside the Card component.
The typescript definition file Card.d.ts looks like this:
import CardImg from './CardImg'; import { BsPrefixPropsWithChildren, BsPrefixRefForwardingComponent } from './helpers'; import { Color, Variant } from './types'; declare const CardBody: BsPrefixRefForwardingComponent<any, {}>; declare const CardTitle: BsPrefixRefForwardingComponent<any, {}>; declare const CardSubtitle: BsPrefixRefForwardingComponent<any, {}>; declare const CardLink: BsPrefixRefForwardingComponent<any, {}>; declare const CardText: BsPrefixRefForwardingComponent<any, {}>; declare const CardHeader: BsPrefixRefForwardingComponent<any, {}>; declare const CardFooter: BsPrefixRefForwardingComponent<any, {}>; declare const CardImgOverlay: BsPrefixRefForwardingComponent<any, {}>; export interface CardProps extends BsPrefixPropsWithChildren { bg?: Variant; text?: Color; border?: Variant; body?: boolean; } declare type Card = BsPrefixRefForwardingComponent<'div', CardProps> & { Img: typeof CardImg; Title: typeof CardTitle; Subtitle: typeof CardSubtitle; Body: typeof CardBody; Link: typeof CardLink; Text: typeof CardText; Header: typeof CardHeader; Footer: typeof CardFooter; ImgOverlay: typeof CardImgOverlay; }; declare const Card: Card; export default Card;
If I use dukat to convert the TypeScript definition files to Kotlin declarations. It puts out a Card.module_react-bootstrap.kt file
@file:JsModule("react-bootstrap") @file:JsNonModule @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS") import kotlin.js.* import kotlin.js.Json import org.khronos.webgl.* import org.w3c.dom.* import org.w3c.dom.events.* import org.w3c.dom.parsing.* import org.w3c.dom.svg.* import org.w3c.dom.url.* import org.w3c.fetch.* import org.w3c.files.* import org.w3c.notifications.* import org.w3c.performance.* import org.w3c.workers.* import org.w3c.xhr.* external var CardBody: BsPrefixRefForwardingComponent<Any, Any> external var CardTitle: BsPrefixRefForwardingComponent<Any, Any> external var CardSubtitle: BsPrefixRefForwardingComponent<Any, Any> external var CardLink: BsPrefixRefForwardingComponent<Any, Any> external var CardText: BsPrefixRefForwardingComponent<Any, Any> external var CardHeader: BsPrefixRefForwardingComponent<Any, Any> external var CardFooter: BsPrefixRefForwardingComponent<Any, Any> external var CardImgOverlay: BsPrefixRefForwardingComponent<Any, Any> external interface CardProps : BsPrefixPropsWithChildren { var bg: dynamic /* String | String | String | String | String | String | String | String | String? */ get() = definedExternally set(value) = definedExternally var text: String? /* 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'dark' | 'light' | 'white' | 'muted' */ get() = definedExternally set(value) = definedExternally var border: dynamic /* String | String | String | String | String | String | String | String | String? */ get() = definedExternally set(value) = definedExternally var body: Boolean? get() = definedExternally set(value) = definedExternally } external interface `T$0` { var Img: Any var Title: Any var Subtitle: Any var Body: Any var Link: Any var Text: Any var Header: Any var Footer: Any var ImgOverlay: Any } @JsName("default") external var Card: BsPrefixRefForwardingComponent<String /* 'div' */, CardProps> /* BsPrefixRefForwardingComponent<String /* 'div' */, CardProps> & `T$0` */
But this doesn’t compile.
- How to write a kotlin declaration file for a component which has components children inside and not as separate component file?
- How to use this component in the RBuilder.render() method?
Advertisement
Answer
Reading the Typescript declerations, it seems
file: Card.kt
@file:JsModule("react-bootstrap/Card") package bootstrap import react.RClass import react.RProps @JsName("default") external val Card: RClass<RProps>
file: Card.ktx.kt (Since you can’t have non external declarations in a JsModule)
package bootstrap import react.RClass import react.RProps val CardBody : RClass<RProps> = Card.asDynamic().Body val CardLink : RClass<RProps> = Card.asDynamic().Link
Usage
fun RBuilder.MyComp(){ Card { CardBody {+"Card body goes here" } } }
should work.