All Downloads are FREE. Search and download functionalities are using the official Maven repository.

main.styled.StyledComponents.kt Maven / Gradle / Ivy

There is a newer version: 5.3.11-pre.717
Show newest version
package styled

import csstype.ClassName
import kotlinx.browser.window
import kotlinx.css.CssBuilder
import kotlinx.css.CssDsl
import kotlinx.css.RuleSet
import kotlinx.html.*
import kotlinx.js.jso
import org.w3c.dom.Element
import react.*
import react.dom.DOMProps
import react.dom.RDOMBuilder
import react.dom.RDOMBuilderImpl
import react.dom.render
import kotlin.js.Promise

typealias AnyTagStyledBuilder = StyledDOMBuilder
typealias AnyBuilder = AnyTagStyledBuilder.() -> Unit

typealias HTMLTagBuilder = StyledDOMBuilder.() -> Unit

typealias ABuilder = StyledDOMBuilder.() -> Unit
typealias DIVBuilder = StyledDOMBuilder
.() -> Unit typealias SPANBuilder = StyledDOMBuilder.() -> Unit typealias INPUTBuilder = StyledDOMBuilder.() -> Unit external interface CustomStyledProps : Props { var css: ArrayList? } inline fun CustomStyledProps.forwardCss(builder: CssBuilder) { css?.forEach { it(builder) } } inline fun CustomStyledProps.forwardCss(props: CustomStyledProps) { css?.forEach { c -> if (props.css == null) { props.css = ArrayList() } props.css!!.add(c) } } @CssDsl interface StyledBuilder

{ val css: CssBuilder val type: Any } inline fun StyledBuilder<*>.css(handler: RuleSet) = css.handler() interface StyledElementBuilder

: RElementBuilder

, StyledBuilder

{ fun create(): ReactElement<*> companion object { operator fun

invoke( type: ElementType

, attrs: P = jso(), ): StyledElementBuilder

= StyledElementBuilderImpl(type, attrs) } } class StyledElementBuilderImpl

( override val type: ElementType

, attrs: P = jso(), ) : StyledElementBuilder

, RElementBuilderImpl

(attrs) { override val css = CssBuilder(isStyledComponent = true) override fun create() = Styled.createElement(type, css, attrs, childList) } @ReactDsl interface StyledDOMBuilder : RDOMBuilder, StyledBuilder { override val type get() = attrs.tagName override fun create() = Styled.createElement(type, css, domProps, childList) companion object { operator fun invoke(factory: (TagConsumer) -> T): StyledDOMBuilder = StyledDOMBuilderImpl(factory) } } class StyledDOMBuilderImpl(factory: (TagConsumer) -> T) : StyledDOMBuilder, RDOMBuilderImpl(factory) { override val css = CssBuilder(isStyledComponent = true) } typealias StyledHandler

= StyledElementBuilder

.() -> Unit fun

styled(type: ElementType

): RBuilder.(StyledHandler

) -> Unit = { handler -> child(with(StyledElementBuilder(type)) { handler() create() }) } inline fun CustomStyledProps.css(noinline handler: RuleSet) { if (css == null) { css = ArrayList() } css!!.add(handler) } @Suppress("NOTHING_TO_INLINE") inline fun

RElementBuilder

.css(noinline handler: RuleSet) = attrs.css(handler) /** * @deprecated Use [keyframes] and [css] instead */ fun keyframesName(string: String): String { val keyframes = keyframes(string) val keyframesInternal = css(keyframes.rules).asDynamic() val name = keyframes.getName() when { keyframesInternal is String -> injectGlobalKeyframeStyle(name, keyframesInternal) keyframesInternal is Array -> injectGlobalKeyframeStyle(name, keyframesInternal[0]) else -> injectGlobals(keyframesInternal) } return keyframes.getName() } private fun injectGlobalKeyframeStyle(name: String, style: String) { if (style.startsWith("@-webkit-keyframes") || style.startsWith("@keyframes")) { injectGlobal(style) } else { injectGlobals(arrayOf( "@-webkit-keyframes $name {$style}", "@keyframes $name {$style}" )) } } private fun injectGlobals(strings: Array) { val globalStyle = devOverrideUseRef { createGlobalStyle(strings) } Promise.resolve(Unit).then { GlobalStyles.add(globalStyle) } } private external interface GlobalStylesComponentProps : Props { var globalStyles: List> } private object GlobalStyles { private val component = fc { props -> props.globalStyles.forEach { child(it) } } private val root by kotlin.lazy { val element = window.document.body!!.appendChild(window.document.createElement("div")) as Element element.setAttribute("id", "sc-global-styles") element } private val styles = mutableListOf>() fun add(globalStyle: ComponentType<*>) { styles.add(globalStyle) val reactElement = createElement(component, jso { this.globalStyles = styles }) @Suppress("DEPRECATION") render(reactElement, root) } } fun injectGlobal(css: CssBuilder) { injectGlobal(css.toString()) } /** * @deprecated Use [createGlobalStyle] instead */ fun injectGlobal(string: String) { val globalStyle = devOverrideUseRef { createGlobalStyle(string) } Promise.resolve(Unit).then { GlobalStyles.add(globalStyle) } } @JsModule("react") @JsNonModule external object ReactModule private fun devOverrideUseRef(action: () -> T): T { return if (js("process.env.NODE_ENV !== 'production'")) { // (Very) dirty hack: styled-components calls useRef() in development mode to check if a component // has been created dynamically. We can't allow this call to happen because it breaks rendering, so // we temporarily redefine useRef. val useRef = ReactModule.asDynamic().useRef ReactModule.asDynamic().useRef = { throw Error("invalid hook call") } val result = action() ReactModule.asDynamic().useRef = useRef result } else action() } /** * @deprecated Use [createGlobalStyle] instead */ fun injectGlobal(handler: CssBuilder.() -> Unit) { injectGlobal(CssBuilder(isStyledComponent = true).apply { handler() }.toString()) } object Styled { private val cache = mutableMapOf() private fun wrap(type: T): T = cache.getOrPut(type) { devOverrideUseRef { rawStyled(type)({ it.css }) } } private fun

buildStyledProps(css: CssBuilder, props: P): P { val styledProps = props.unsafeCast() if (css.rules.isNotEmpty() || css.multiRules.isNotEmpty() || css.declarations.isNotEmpty()) { styledProps.css = css.toString() } if (css.classes.isNotEmpty()) { styledProps.className = ClassName(css.classes.joinToString(separator = " ")) } if (css.styleName.isNotEmpty()) { styledProps.asDynamic()["data-style"] = css.styleName.joinToString(separator = " ") } return styledProps.unsafeCast

() } fun createElement( type: String, css: CssBuilder, props: PropsWithClassName, children: List, ): ReactElement<*> { val wrappedType = wrap(type) val styledProps = buildStyledProps(css, props) return createElement( type = IntrinsicType(wrappedType), props = styledProps, children = children.toTypedArray(), ) } fun

createElement( type: ElementType

, css: CssBuilder, props: P, children: List, ): ReactElement

{ val wrappedType = wrap(type) val styledProps = buildStyledProps(css, props) return createElement(wrappedType, styledProps, *children.toTypedArray()) } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy