diff --git a/muirwik-components/src/main/kotlin/com/ccfraser/muirwik/components/Icon.kt b/muirwik-components/src/main/kotlin/com/ccfraser/muirwik/components/Icon.kt index 8746f00..6d7aea3 100644 --- a/muirwik-components/src/main/kotlin/com/ccfraser/muirwik/components/Icon.kt +++ b/muirwik-components/src/main/kotlin/com/ccfraser/muirwik/components/Icon.kt @@ -28,7 +28,7 @@ interface MIconProps : StyledProps { var component: String? } -var MIconProps.color by EnumPropToString(MIconColor.values()) +var MIconProps.color by EnumPropToStringNullable(MIconColor.values()) var MIconProps.fontSize by EnumPropToString(MIconFontSize.values()) fun RBuilder.mIcon( diff --git a/muirwik-components/src/main/kotlin/com/ccfraser/muirwik/components/lab/Rating.kt b/muirwik-components/src/main/kotlin/com/ccfraser/muirwik/components/lab/Rating.kt new file mode 100644 index 0000000..4a6b4c7 --- /dev/null +++ b/muirwik-components/src/main/kotlin/com/ccfraser/muirwik/components/lab/Rating.kt @@ -0,0 +1,77 @@ +package com.ccfraser.muirwik.components.lab + +import com.ccfraser.muirwik.components.EnumPropToString +import com.ccfraser.muirwik.components.StyledPropsWithCommonAttributes +import com.ccfraser.muirwik.components.createStyled +import com.ccfraser.muirwik.components.setStyledPropsAndRunHandler +import kotlinext.js.Object +import react.* +import styled.StyledHandler + +@JsModule("@material-ui/lab/Rating") +private external val module: dynamic + +@Suppress("UnsafeCastFromDynamic") +private val component: RComponent = module.default + +@Suppress("EnumEntryName") +enum class MRatingSize { + large, medium, small +} + +interface MRatingProps : StyledPropsWithCommonAttributes { + var defaultValue: Number + var disabled: Boolean + var emptyIcon: ReactElement + var emptyLabelText: String + var getLabelText: (value: Number) -> String + var icon: ReactElement + @JsName("IconContainerComponent") + var iconContainerComponent: FunctionalComponent + var max: Number + var name: String + var onChange: (event: Object, newValue: Number) -> Unit + var onChangeActive: (event: Object, hoverValue: Number) -> Unit + var precision: Number + var readOnly: Boolean + var value: Number? +} +var MRatingProps.size by EnumPropToString(MRatingSize.values()) + +interface MIconContainerProps : StyledPropsWithCommonAttributes { + var value: Int +} + +fun RBuilder.mRating( + name: String, + value: Number? = null, + max: Number = 5, + precision: Number = 1, + onChange: ((event: Object, newValue: Number) -> Unit)? = null, + defaultValue: Number? = null, + readOnly: Boolean = false, + disabled: Boolean = false, + icon: ReactElement? = null, + emptyIcon: ReactElement? = null, + emptyLabelText: String = "Empty", + size: MRatingSize = MRatingSize.medium, + + addAsChild: Boolean = true, + className: String? = null, + handler: StyledHandler? = null +) = createStyled(component, addAsChild) { + defaultValue?.let { attrs.defaultValue = it } + attrs.disabled = disabled + emptyIcon?.let { attrs.emptyIcon = it } + attrs.emptyLabelText = emptyLabelText + icon?.let { attrs.icon = icon } + attrs.max = max + attrs.name = name + onChange?.let { attrs.onChange = it } + attrs.precision = precision + attrs.readOnly = readOnly + attrs.size = size + value?.let { attrs.value = it } + + setStyledPropsAndRunHandler(className, handler) +} diff --git a/muirwik-components/src/main/kotlin/com/ccfraser/muirwik/components/lab/alert/Alert.kt b/muirwik-components/src/main/kotlin/com/ccfraser/muirwik/components/lab/alert/Alert.kt index 43bc818..cd0d28a 100644 --- a/muirwik-components/src/main/kotlin/com/ccfraser/muirwik/components/lab/alert/Alert.kt +++ b/muirwik-components/src/main/kotlin/com/ccfraser/muirwik/components/lab/alert/Alert.kt @@ -19,19 +19,19 @@ private val component: RComponent = module.default @Suppress("EnumEntryName") enum class MAlertVariant { - filled, outlined, standard + filled, outlined, standard } @Suppress("EnumEntryName") enum class MAlertSeverity { - error, info, success, warning + error, info, success, warning } interface MAlertProps : StyledPropsWithCommonAttributes { - var action: ReactElement - var icon: ReactElement - var onClose: (Event) -> Unit - var closeText: String + var action: ReactElement + var icon: ReactElement + var onClose: (Event) -> Unit + var closeText: String } var MAlertProps.variant by EnumPropToStringNullable(MAlertVariant.values()) @@ -47,13 +47,13 @@ fun RBuilder.mAlert( className: String? = null, handler: StyledHandler? = null) = createStyled(component, addAsChild) { - message?.let { +message } - attrs.variant = variant - attrs.severity = severity - attrs.closeText = closeText - onClose?.let { attrs.onClose = onClose } + message?.let { +message } + attrs.variant = variant + attrs.severity = severity + attrs.closeText = closeText + onClose?.let { attrs.onClose = onClose } - setStyledPropsAndRunHandler(className, handler) + setStyledPropsAndRunHandler(className, handler) } fun RBuilder.mAlert( @@ -67,13 +67,13 @@ fun RBuilder.mAlert( className: String? = null, handler: StyledHandler? = null) = createStyled(component, addAsChild) { - attrs.variant = variant - attrs.severity = severity - attrs.closeText = closeText - onClose?.let { attrs.onClose = onClose } + attrs.variant = variant + attrs.severity = severity + attrs.closeText = closeText + onClose?.let { attrs.onClose = onClose } - +mAlertTitle(title, false) - message?.let { +message } + +mAlertTitle(title, false) + message?.let { +message } - setStyledPropsAndRunHandler(className, handler) + setStyledPropsAndRunHandler(className, handler) } diff --git a/muirwik-testapp/src/main/kotlin/com/ccfraser/muirwik/testapp/MainFrame.kt b/muirwik-testapp/src/main/kotlin/com/ccfraser/muirwik/testapp/MainFrame.kt index 2b9ccd4..ccbca2d 100644 --- a/muirwik-testapp/src/main/kotlin/com/ccfraser/muirwik/testapp/MainFrame.kt +++ b/muirwik-testapp/src/main/kotlin/com/ccfraser/muirwik/testapp/MainFrame.kt @@ -59,6 +59,7 @@ class MainFrame(props: MainFrameProps) : RComponent { props -> + styledDiv { + var value: Number? by useState(2) + css(margin) + mTypography("Simple Rating", MTypographyVariant.h4) + styledDiv { + css(margin) + mTypography("Controlled", component = "legend") + mRating("simple-controlled", value, onChange = { _, newValue -> value = newValue }) + } + styledDiv { + css(margin) + mTypography("Read Only", component = "legend") + mRating("read-only", value, readOnly = true) + + } + styledDiv { + css(margin) + mTypography("Disabled", component = "legend") + mRating("disabled", value, disabled = true) + } + styledDiv { + css(margin) + mTypography("Pristine", component = "legend") + mRating("pristine") + } + } + styledDiv { + var value: Number? by useState(2) + css(margin) + mTypography("Customized Rating", MTypographyVariant.h4) + styledDiv { + css(margin) + mTypography("Custom empty icon", component = "legend") + mRating("customized-empty", value, precision = 0.5, onChange = { _, newValue -> value = newValue }) { + attrs.emptyIcon = mIcon("star_border", fontSize = MIconFontSize.inherit, addAsChild = false) + } + } + styledDiv { + css(margin) + // TODO: Not sure how to apply the color styles as in the original demo + mTypography("Custom icon and color (color is still a WIP)", component = "legend") + mRating("customized-empty", value, precision = 0.5, onChange = { _, newValue -> value = newValue }, + icon = mIcon("favorite", fontSize = MIconFontSize.inherit, addAsChild = false)) + } + styledDiv { + css(margin) + mTypography("Custom icon set", component = "legend") + mRating("customized-icons", value, onChange = { _, newValue -> value = newValue }) { + attrs.iconContainerComponent = iconContainer + } + + } + styledDiv { + css(margin) + mTypography("10 Starts", component = "legend") + mRating("customized-10", null, max = 10) + } + } + styledDiv { + var value: Number? by useState(2) + css(margin) + mTypography("Hover Feedback", MTypographyVariant.h4) + styledDiv { + css { + +ComponentStyles.margin + display = Display.flex + alignItems = Align.center + } + var hover: Number by useState(-1) + mRating("hover-feedback", value, precision = 0.5) { + attrs.onChange = { _, newValue -> value = newValue } + attrs.onChangeActive = { _, hoverValue -> hover = hoverValue } + } + styledDiv { + css { marginLeft = 2.spacingUnits } + value?.let { +labelForValue(if (hover != -1) hover else it) } + } + } + } + styledDiv { + css(margin) + mTypography("Sizes", MTypographyVariant.h4) + styledDiv { + css { + +ComponentStyles.margin + display = Display.flex + flexDirection = FlexDirection.column + } + mRating("size-s", null, size = MRatingSize.small) + mRating("size-m", null, size = MRatingSize.medium) + mRating("size-l", null, size = MRatingSize.large) + } + } +} + +private fun labelForValue(value: Number) = when(value) { + 0.5 -> "Useless" + 1 -> "Useless+" + 1.5 -> "Poor" + 2 -> "Poor+" + 2.5 -> "Ok" + 3 -> "Ok+" + 3.5 -> "Good" + 4 -> "Good+" + 4.5 -> "Excellent" + 5 -> "Excellent+" + else -> "Unknown" +} + +private val iconContainer = functionalComponent { props -> + createElement("span", props, when (props.value) { + 1 -> mIcon("sentiment_very_dissatisfied", className = props.className) + 2 -> mIcon("sentiment_dissatisfied", className = props.className) + 3 -> mIcon("sentiment_satisfied", className = props.className) + 4 -> mIcon("sentiment_satisfied_alt", className = props.className) + else -> mIcon("sentiment_very_satisfied", className = props.className) + } + ) +} + +fun RBuilder.testRatings() = child(testRatings) { +}