diff --git a/core/src/main/kotlin/materialui/components/MaterialElementBuilder.kt b/core/src/main/kotlin/materialui/components/MaterialElementBuilder.kt index 8bdf5a2e..983634a5 100644 --- a/core/src/main/kotlin/materialui/components/MaterialElementBuilder.kt +++ b/core/src/main/kotlin/materialui/components/MaterialElementBuilder.kt @@ -48,7 +48,7 @@ abstract class MaterialElementBuilder( var Tag.classes: Any? by materialProps var Tag.className: String? by materialProps - var Tag.component: String? by materialProps + var Tag.component: Any? by materialProps init { attrs.classes(classMap) diff --git a/core/src/main/kotlin/materialui/components/StandardProps.kt b/core/src/main/kotlin/materialui/components/StandardProps.kt index c8c53680..0d9c9099 100644 --- a/core/src/main/kotlin/materialui/components/StandardProps.kt +++ b/core/src/main/kotlin/materialui/components/StandardProps.kt @@ -1,5 +1,7 @@ package materialui.components +import kotlinx.css.StyledElement +import materialui.reacttransiton.RTransitionGroupProps import react.dom.DOMProps import kotlin.reflect.KProperty @@ -10,6 +12,22 @@ external interface StandardProps : DOMProps { operator fun StandardProps.get(key: String): Any? = asDynamic()[key] +inline operator fun > StandardProps.get(key: String): E?{ + val value = asDynamic()[key] + return when (value) { + null -> null + undefined -> null + else -> enumValueOf(value.toString()) + } +} + +inline operator fun > StandardProps.set(key: String,value: E?) { + asDynamic()[key] = when (value) { + null -> undefined + else -> value.toString() + } +} + operator fun StandardProps.getValue(thisRef: Any?, property: KProperty<*>): dynamic = asDynamic()[property.name] @@ -17,9 +35,19 @@ operator fun StandardProps.setValue(thisRef: Any?, property: KProperty<*>, value asDynamic()[property.name] = value } -inline operator fun > StandardProps.getValue(thisRef: Any?, property: KProperty<*>): T? - = (asDynamic()[property.name] as String?)?.let { name -> enumValues().find { it.toString() == name } } +//issue:problem with type argument ?> its not bounds enumValueOf +inline operator fun > StandardProps.getValue(thisRef: Any?, property: KProperty<*>): T?{ + val value = asDynamic()[property.name] + return when (value) { + null -> null + undefined -> null + else -> enumValueOf(value.toString()) + } +} inline operator fun > StandardProps.setValue(thisRef: Any?, property: KProperty<*>, value: T?) { - asDynamic()[property.name] = value?.toString() + asDynamic()[property.name] = when (value) { + null -> undefined + else -> value.toString() + } } diff --git a/core/src/main/kotlin/materialui/components/dialog/DialogElementBuilder.kt b/core/src/main/kotlin/materialui/components/dialog/DialogElementBuilder.kt index aaa5ab14..3a56b301 100644 --- a/core/src/main/kotlin/materialui/components/dialog/DialogElementBuilder.kt +++ b/core/src/main/kotlin/materialui/components/dialog/DialogElementBuilder.kt @@ -15,10 +15,7 @@ import materialui.components.paper.PaperProps import materialui.components.paper.paper import materialui.components.setValue import materialui.reacttransiton.RTransitionProps -import react.Component -import react.RBuilder -import react.RClass -import react.RProps +import react.* import kotlin.reflect.KClass class DialogElementBuilder internal constructor( @@ -37,10 +34,13 @@ class DialogElementBuilder internal constructor( var Tag.TransitionProps: RProps? by materialProps fun > Tag.paperComponent(kClass: KClass) { - @Suppress("UNCHECKED_CAST_TO_EXTERNAL_INTERFACE") - @Suppress("UNCHECKED_CAST") - materialProps.PaperComponent = kClass.js as RClass

+ materialProps.PaperComponent = kClass.rClass } + + fun Tag.paperComponent(component: FunctionalComponent

) { + materialProps.PaperComponent = component + } + fun Tag.paperComponent(tagName: String) { materialProps.PaperComponent = tagName } fun Tag.paperProps(block: PaperElementBuilder.() -> Unit) { PaperProps = RBuilder().paper(block = block).props diff --git a/core/src/main/kotlin/materialui/components/textfield/TextFieldElementBuilder.kt b/core/src/main/kotlin/materialui/components/textfield/TextFieldElementBuilder.kt index 925c9ac5..2b96e194 100644 --- a/core/src/main/kotlin/materialui/components/textfield/TextFieldElementBuilder.kt +++ b/core/src/main/kotlin/materialui/components/textfield/TextFieldElementBuilder.kt @@ -5,6 +5,7 @@ import kotlinx.css.Color import kotlinx.html.* import kotlinx.html.stream.createHTML import materialui.components.formcontrol.FormControlElementBuilder +import materialui.components.get import materialui.components.getValue import materialui.components.input.InputElementBuilder import materialui.components.input.InputProps @@ -13,7 +14,9 @@ import materialui.components.inputlabel.InputLabelElementBuilder import materialui.components.inputlabel.inputLabel import materialui.components.select.SelectElementBuilder import materialui.components.select.select +import materialui.components.set import materialui.components.setValue +import materialui.components.textfield.enums.TextFieldSize import react.* import kotlin.js.Date @@ -45,6 +48,9 @@ class TextFieldElementBuilder internal constructor( var Tag.rowsMax: Any? by materialProps var Tag.select: Boolean? by materialProps var Tag.SelectProps: RProps? by materialProps + var Tag.size: TextFieldSize? // issue: Enum? problem with > StandardProps.getValue() + get() = materialProps.get("size") + set(value) { materialProps.set("size",value) } var Tag.type: InputType? by materialProps var Tag.value: Any? by materialProps diff --git a/core/src/main/kotlin/materialui/components/textfield/enums/TextFieldSize.kt b/core/src/main/kotlin/materialui/components/textfield/enums/TextFieldSize.kt new file mode 100644 index 00000000..7219314a --- /dev/null +++ b/core/src/main/kotlin/materialui/components/textfield/enums/TextFieldSize.kt @@ -0,0 +1,6 @@ +package materialui.components.textfield.enums + +@Suppress("EnumEntryName") +enum class TextFieldSize{ + small,medium +} \ No newline at end of file diff --git a/core/src/main/kotlin/materialui/components/textfield/textField.kt b/core/src/main/kotlin/materialui/components/textfield/textField.kt index 749bf030..2e5541a1 100644 --- a/core/src/main/kotlin/materialui/components/textfield/textField.kt +++ b/core/src/main/kotlin/materialui/components/textfield/textField.kt @@ -30,6 +30,7 @@ external interface TextFieldProps : FormControlProps { var rowsMax: Any? var select: Boolean? var SelectProps: SelectProps? + var size: String? var type: String? var value: Any? } diff --git a/core/src/main/kotlin/materialui/imports.kt b/core/src/main/kotlin/materialui/imports.kt index 784a49f3..2f9531ce 100644 --- a/core/src/main/kotlin/materialui/imports.kt +++ b/core/src/main/kotlin/materialui/imports.kt @@ -112,6 +112,8 @@ import materialui.components.toolbar.ToolbarProps import materialui.components.tooltip.TooltipProps import materialui.components.typography.TypographyProps import materialui.components.zoom.ZoomProps +import materialui.styles.GenerateClassNameOptions +import materialui.styles.JssOptions import materialui.styles.breakpoint.Breakpoints import materialui.styles.breakpoint.options.BreakpointsOptions import materialui.styles.mixins.Mixins @@ -120,6 +122,8 @@ import materialui.styles.muitheme.MuiTheme import materialui.styles.muitheme.options.MuiThemeOptions import materialui.styles.palette.Palette import materialui.styles.palette.options.PaletteOptions +import materialui.styles.stylesprovider.GenerateId +import materialui.styles.stylesprovider.StylesProviderProps import materialui.styles.typography.Typography import react.RClass import react.RComponent @@ -237,6 +241,8 @@ internal external val Typography: RClass internal external val Zoom: RClass internal external val ThemeProvider: RComponent +internal external val StylesProvider: RComponent + @JsName("createBreakpoints") internal external fun rawCreateBreakpoints(breakpoints: BreakpointsOptions): Breakpoints @@ -251,6 +257,9 @@ internal external fun rawMakeStyles(styles: dynamic, option: dynamic): MakeStyle @JsName("withStyles") internal external fun rawWithStyles(styles: dynamic, option: dynamic): WithStyles +external fun jssPreset(): JssOptions +external fun createGenerateClassName(option: GenerateClassNameOptions): GenerateId + external fun createMixins(breakpoints: Breakpoints, spacing: dynamic, mixins: MixinsOptions): Mixins external fun useTheme(): MuiTheme diff --git a/core/src/main/kotlin/materialui/styles/JssPreset.kt b/core/src/main/kotlin/materialui/styles/JssPreset.kt new file mode 100644 index 00000000..5fecded5 --- /dev/null +++ b/core/src/main/kotlin/materialui/styles/JssPreset.kt @@ -0,0 +1,5 @@ +package materialui.styles + +external interface JssOptions { + var plugins: Array +} \ No newline at end of file diff --git a/core/src/main/kotlin/materialui/styles/StylesBuilder.kt b/core/src/main/kotlin/materialui/styles/StylesBuilder.kt index 6a4f155d..451aa315 100644 --- a/core/src/main/kotlin/materialui/styles/StylesBuilder.kt +++ b/core/src/main/kotlin/materialui/styles/StylesBuilder.kt @@ -17,8 +17,8 @@ class StylesBuilder internal constructor( css["@global"] = CSSBuilder().apply(block).toDynamic } - operator fun String.invoke(block: CSSBuilder.(P) -> Unit): String { - css[this] = { props: P -> CSSBuilder().apply { block(props) }.toDynamic } + operator fun String.invoke(block: CSSBuilder.() ->Unit): String { + css[this] = CSSBuilder().apply(block).toDynamic return this } @@ -26,6 +26,20 @@ class StylesBuilder internal constructor( css[this] = builder.toDynamic return this } + + fun String.staticStyle(block: CSSBuilder.() ->Unit): String { + css[this] = CSSBuilder().apply(block).toDynamic + return this + } + + fun String.dynamicStyle(block: CSSBuilder.(P) ->Unit): String { + css[this] = { props: P -> CSSBuilder().apply { block(props) }.toDynamic } + return this + } + + fun CSSBuilder.flip(enable: Boolean) { + declarations["flip"] = enable + } } internal val CSSBuilder.toDynamic: Any @@ -35,8 +49,9 @@ internal val CSSBuilder.toDynamic: Any } declarations.forEach { (key, value) -> - this[key.hyphenize()] = when (value) { - is CSSBuilder -> value.toDynamic + this[key.hyphenize()] = when { + key == "flip" -> value //keep boolean value parse in jss + value is CSSBuilder -> value.toDynamic else -> value.toString() } } diff --git a/core/src/main/kotlin/materialui/styles/createGenerateClassName.kt b/core/src/main/kotlin/materialui/styles/createGenerateClassName.kt new file mode 100644 index 00000000..6e421951 --- /dev/null +++ b/core/src/main/kotlin/materialui/styles/createGenerateClassName.kt @@ -0,0 +1,23 @@ +package materialui.styles + +import kotlinext.js.jsObject +import materialui.createGenerateClassName +import materialui.styles.stylesprovider.GenerateId + +external interface GenerateClassNameOptions { + var disableGlobal: Boolean? + var productionPrefix: String? + var seed: String? +} + +fun createGenerateClassName( + disableGlobal: Boolean? = null, + productionPrefix: String? = null, + seed: String? = null +): GenerateId{ + return createGenerateClassName(jsObject{ + disableGlobal?.let {this.disableGlobal = it } + productionPrefix?.let { this.productionPrefix = it } + seed?. let { this.seed = it } + }) +} \ No newline at end of file diff --git a/core/src/main/kotlin/materialui/styles/muitheme/options/MuiThemeOptions.kt b/core/src/main/kotlin/materialui/styles/muitheme/options/MuiThemeOptions.kt index 401e3207..34c3d579 100644 --- a/core/src/main/kotlin/materialui/styles/muitheme/options/MuiThemeOptions.kt +++ b/core/src/main/kotlin/materialui/styles/muitheme/options/MuiThemeOptions.kt @@ -1,5 +1,6 @@ package materialui.styles.muitheme.options +import kotlinext.js.Object import kotlinext.js.jsObject import kotlinx.css.Direction import kotlinx.css.properties.BoxShadows @@ -19,9 +20,10 @@ external interface MuiThemeOptions { var palette: PaletteOptions? var typography: TypographyOptions? var shape: ShapeOptions? - var spacing: dynamic? + var spacing: dynamic var transitions: TransitionsOptions? var zIndex: ZIndexOptions? + var overrides: Object? } var MuiThemeOptions.direction: Direction? by DirectionDelegate @@ -42,3 +44,4 @@ fun MuiThemeOptions.typography(block: TypographyOptions.() -> Unit) { typography fun MuiThemeOptions.shape(block: ShapeOptions.() -> Unit) { shape = (shape ?: jsObject { }).apply(block) } fun MuiThemeOptions.transitions(block: TransitionsOptions.() -> Unit) { transitions = (transitions ?: jsObject { }).apply(block) } fun MuiThemeOptions.zIndex(block: ZIndexOptions.() -> Unit) { zIndex = (zIndex ?: jsObject { }).apply(block) } +fun MuiThemeOptions.overrides(block: dynamic.() -> Unit) { overrides = (overrides ?: jsObject { }).apply(block) } diff --git a/core/src/main/kotlin/materialui/styles/stylesprovider/StyleProviderBuilder.kt b/core/src/main/kotlin/materialui/styles/stylesprovider/StyleProviderBuilder.kt new file mode 100644 index 00000000..a5cb3343 --- /dev/null +++ b/core/src/main/kotlin/materialui/styles/stylesprovider/StyleProviderBuilder.kt @@ -0,0 +1,16 @@ +package materialui.styles.stylesprovider + +import kotlinext.js.jsObject +import materialui.styles.muitheme.MuiTheme +import react.* + +class StyleProviderBuilder internal constructor( + val type: RComponent, + private val props: StylesProviderProps = jsObject { } +) : RBuilder() { + fun attrs(handler: StylesProviderProps.() -> Unit) { + props.handler() + } + + fun create() = createElement(type, props, *childList.toTypedArray()) +} \ No newline at end of file diff --git a/core/src/main/kotlin/materialui/styles/stylesprovider/StylesProvider.kt b/core/src/main/kotlin/materialui/styles/stylesprovider/StylesProvider.kt new file mode 100644 index 00000000..84e76f62 --- /dev/null +++ b/core/src/main/kotlin/materialui/styles/stylesprovider/StylesProvider.kt @@ -0,0 +1,25 @@ +package materialui.styles.stylesprovider + +import kotlinext.js.Object +import materialui.StylesProvider +import materialui.ThemeProvider +import materialui.styles.muitheme.MuiTheme +import materialui.styles.themeprovider.ThemeProviderBuilder +import react.RBuilder +import react.RProps + +typealias GenerateId = Object +typealias Jss = Object + +external interface StylesProviderProps: RProps{ + var disableGeneration: Boolean? + var generateClassName: GenerateId? + var injectFirst: Boolean? + var jss: Jss + var sheetsCache: dynamic + var sheetsManager: dynamic + var sheetsRegistry: dynamic +} + +fun RBuilder.styleProvider(block: StyleProviderBuilder.() -> Unit) = + child(StyleProviderBuilder(StylesProvider).apply(block).create()) \ No newline at end of file diff --git a/core/src/main/kotlin/materialui/styles/themeprovider/ThemeProviderBuilder.kt b/core/src/main/kotlin/materialui/styles/themeprovider/ThemeProviderBuilder.kt index cb1e7ee3..a7870656 100644 --- a/core/src/main/kotlin/materialui/styles/themeprovider/ThemeProviderBuilder.kt +++ b/core/src/main/kotlin/materialui/styles/themeprovider/ThemeProviderBuilder.kt @@ -18,14 +18,4 @@ class ThemeProviderBuilder internal constructor( } fun create() = createElement(type, props, *childList.toTypedArray()) - - var RProps.disableStylesGeneration: Boolean - get() = @Suppress("UnsafeCastFromDynamic") props.asDynamic()["disableStylesGeneration"] - set(value) { props.asDynamic()["disableStylesGeneration"] = value } - var RProps.sheetsCache: Any - get() = @Suppress("UnsafeCastFromDynamic") props.asDynamic()["sheetsCache"] - set(value) { props.asDynamic()["sheetsCache"] = value } - var RProps.sheetsManager: Any - get() = @Suppress("UnsafeCastFromDynamic") props.asDynamic()["sheetsManager"] - set(value) { props.asDynamic()["sheetsManager"] = value } } diff --git a/lab/src/main/kotlin/materialui/lab/components/autocomplete/AutocompleteElementBuilder.kt b/lab/src/main/kotlin/materialui/lab/components/autocomplete/AutocompleteElementBuilder.kt new file mode 100644 index 00000000..4a14577d --- /dev/null +++ b/lab/src/main/kotlin/materialui/lab/components/autocomplete/AutocompleteElementBuilder.kt @@ -0,0 +1,159 @@ +package materialui.lab.components.autocomplete + +import kotlinext.js.jsObject +import kotlinx.css.Color +import kotlinx.html.DIV +import kotlinx.html.Tag +import kotlinx.html.TagConsumer +import materialui.components.* +import materialui.components.chip.ChipElementBuilder +import materialui.components.chip.chip +import materialui.components.popper.PopperProps +import materialui.components.textfield.enums.TextFieldSize +import materialui.lab.components.autocomplete.enums.AutocompleteForcePopupIcon +import materialui.lab.components.autocomplete.enums.AutocompleteStyle +import materialui.lab.components.useautocomplete.* +import materialui.lab.components.useautocomplete.enums.AutocompleteBlurOnSelect +import org.w3c.dom.events.Event +import react.* +import kotlin.js.Date +import kotlin.reflect.KClass + +class AutocompleteElementBuilder internal constructor( + type: RClass>, + classMap: List, String>>, + factory: (TagConsumer) -> T +) : MaterialElementBuilder>(type, classMap, factory) { + fun Tag.classes(vararg classMap: Pair) { + classes(classMap.map { it.first to it.second }) + } + + var Tag.autoComplete: Boolean? by materialProps + var Tag.autoHighlight: Boolean? by materialProps + var Tag.autoSelect: Boolean? by materialProps + var Tag.clearOnBlur: Boolean? by materialProps + var Tag.clearOnEscape: Boolean? by materialProps + var Tag.componentName: String? by materialProps + var Tag.debug: Boolean? by materialProps + var Tag.disableClearable: Boolean? by materialProps + var Tag.disableCloseOnSelect: Boolean? by materialProps + var Tag.disabledItemsFocusable: Boolean? by materialProps + var Tag.disableListWrap: Boolean? by materialProps + var Tag.filterOptions: FilterOptions? by materialProps + var Tag.filterSelectedOptions: Boolean? by materialProps + var Tag.freeSolo: Boolean? by materialProps + var Tag.getOptionDisabled: ((option: O) -> Boolean)? by materialProps + var Tag.getOptionLabel: ((option: O) -> String)? by materialProps + var Tag.getOptionSelected: ((option: O, value: O) -> Boolean)? by materialProps + var Tag.groupBy: ((option: O) -> String)? by materialProps + var Tag.handleHomeEndKeys: Boolean? by materialProps + var Tag.id: String? by materialProps + var Tag.includeInputInList: Boolean? by materialProps + var Tag.inputValue: String? by materialProps + var Tag.onClose: ((event: Event, reason: AutocompleteCloseReason) -> Unit)? by materialProps + var Tag.onInputChange: ((event: Event, value: String, reason: AutocompleteInputChangeReason) -> Unit)? by materialProps + var Tag.onOpen: ((event: Event) -> Unit)? by materialProps + var Tag.onHighlightChange: ((event: Event, option: O?, reason: AutocompleteHighlightChangeReason) -> Unit)? by materialProps + var Tag.open: Boolean? by materialProps + var Tag.openOnFocus: Boolean? by materialProps + var Tag.options: Array by materialProps + var Tag.selectOnFocus: Boolean? by materialProps + var Tag.multiple: Boolean? by materialProps + var Tag.value: Any? by materialProps + var Tag.defaultValue: Any? by materialProps + var Tag.onChange: ((event: Event, value: dynamic, reason: AutocompleteChangeReason, details: AutocompleteChangeDetails) -> Unit)? by materialProps + + var Tag.ChipProps: RProps? by materialProps + var Tag.closeIcon: ReactElement by materialProps + var Tag.clearText: String? by materialProps + var Tag.closeText: String? by materialProps + var Tag.disabled: Boolean? by materialProps + var Tag.disablePortal: Boolean? by materialProps + var Tag.fullWidth: Boolean? by materialProps + var Tag.getLimitTagsText: ((more: Number) -> dynamic)? by materialProps + var Tag.loading: Boolean? by materialProps + var Tag.loadingText: ReactElement by materialProps + var Tag.limitTags: Number? by materialProps + var Tag.noOptionsText: ReactElement by materialProps + var Tag.openText: String? by materialProps + var Tag.popupIcon: ReactElement by materialProps + var Tag.renderGroup: ((params: AutocompleteRenderGroupParams) -> dynamic)? by materialProps + var Tag.renderInput: (params: AutocompleteRenderInputParams) -> dynamic by materialProps + var Tag.renderOption: ((option: T, state: AutocompleteRenderOptionState) -> dynamic)? by materialProps + var Tag.renderTags: ((value: Array, (Int) -> RProps) -> dynamic)? by materialProps + var Tag.size: TextFieldSize? // issue: Enum? problem with > StandardProps.getValue() + get() = materialProps.get("size") + set(value) { materialProps.set("size",value) } + + fun Tag.blurOnSelect(value: AutocompleteBlurOnSelect){ + materialProps.blurOnSelect = when (value.name) { + "true" -> true + "false" -> false + else -> value.toString() + } + } + fun Tag.forcePopupIcon(value: AutocompleteForcePopupIcon){ + materialProps.forcePopupIcon = when (value.name) { + "true" -> true + "false" -> false + else -> value.toString() + } + } + fun Tag.chipProps(block: ChipElementBuilder

.() -> Unit){ + ChipProps = RBuilder().chip(block = block).props + } + fun Tag.chipProps(factory: (TagConsumer) -> T2,block: ChipElementBuilder.() -> Unit){ + ChipProps = RBuilder().chip(factory = factory,block = block).props + } + + fun Tag.closeIcon(block: RBuilder.()->Unit) { closeIcon = buildElement(block) } + + fun Tag.listBoxComponent(kClass: KClass>) { + materialProps.ListboxComponent = kClass.rClass + } + + fun Tag.listBoxComponent(fc: FunctionalComponent

) { + materialProps.ListboxComponent = fc + } + fun Tag.listBoxComponent(tagName: String) { + materialProps.ListboxComponent = tagName + } + fun Tag.listBoxProps(builder: dynamic.()->Unit) { + materialProps.ListboxProps = jsObject(builder) + } + + fun Tag.loadingText(block: RBuilder.()->Unit) { loadingText = buildElement(block) } + fun Tag.noOptionsText(block: RBuilder.()->Unit) { noOptionsText = buildElement(block) } + + fun Tag.paperComponent(kClass: KClass>) { + materialProps.PaperComponent = kClass.rClass + } + + fun Tag.paperComponent(fc: FunctionalComponent

) { + materialProps.PaperComponent = fc + } + + fun Tag.paperComponent(tagName: String) { + materialProps.PaperComponent = tagName + } + fun Tag.popperComponent(kClass: KClass>) { + materialProps.PopperComponent = kClass.rClass + } + + fun Tag.popperComponent(fc: FunctionalComponent

) { + materialProps.PopperComponent = fc + } + + fun Tag.popperComponent(tagName: String) { + materialProps.PopperComponent = tagName + } + + fun Tag.popupIcon(block: RBuilder.()->Unit) { popupIcon = buildElement(block) } + + fun Tag.value(v: String) { value = v } + fun Tag.value(v: Number) { value = v } + fun Tag.value(v: Boolean) { value = v } + fun Tag.value(v: Date) { value = v } + fun Tag.value(v: Color) { value = v.toString() } + +} \ No newline at end of file diff --git a/lab/src/main/kotlin/materialui/lab/components/autocomplete/autoComplete.kt b/lab/src/main/kotlin/materialui/lab/components/autocomplete/autoComplete.kt new file mode 100644 index 00000000..b806a0cd --- /dev/null +++ b/lab/src/main/kotlin/materialui/lab/components/autocomplete/autoComplete.kt @@ -0,0 +1,85 @@ +package materialui.lab.components.autocomplete + +import kotlinext.js.Object +import kotlinext.js.jsObject +import kotlinx.html.DIV +import kotlinx.html.Tag +import kotlinx.html.TagConsumer +import materialui.components.StandardProps +import materialui.components.textfield.TextFieldProps +import materialui.lab.components.autocomplete.enums.AutocompleteStyle +import materialui.lab.components.useautocomplete.UseAutocompleteProps +import react.* + +@JsModule("@material-ui/lab/AutoComplete") +@JsNonModule +private external val autocompleteModule: dynamic + +typealias ReactNode = Any? /* ReactElement | String | Number | Any | ReactNodeArray | ReactPortal | Boolean */ + +external interface AutocompleteProps : UseAutocompleteProps, StandardProps { + var ChipProps: Any? + var closeIcon: ReactNode + var clearText: String? + var closeText: String? + var disabled: Boolean? + var disablePortal: Boolean? + var forcePopupIcon: dynamic /* Boolean? | String */ + var fullWidth: Boolean? + var getLimitTagsText: ((more: Number) -> dynamic)? + var ListboxComponent: dynamic + var ListboxProps: dynamic + var loading: Boolean? + var loadingText: ReactNode + var limitTags: Number? + var noOptionsText: ReactNode + var openText: String? + var PaperComponent: dynamic + var PopperComponent: dynamic + var popupIcon: dynamic + var renderGroup: ((params: AutocompleteRenderGroupParams) -> dynamic)? + var renderInput: (params: AutocompleteRenderInputParams) -> dynamic + var renderOption: ((option: T, state: AutocompleteRenderOptionState) -> dynamic)? + var renderTags: ((value: Array, (Int) -> RProps) -> dynamic)? + var size: String? /* 'small' | 'medium' */ +} + +external interface AutocompleteRenderGroupParams { + var key: String + var group: String + var children: ReactNode +} + +external interface AutocompleteRenderInputParams { + var id: String + var disabled: Boolean + var fullWidth: Boolean + var size: String? + var InputLabelProps: RProps? + var InputProps: AutocompleteInputProps + var inputProps: RProps +} + +external interface AutocompleteInputProps: RProps{ + val ref: RRef + var className: String + var startAdornment: ReactElement + var endAdornment: ReactElement +} + +external interface AutocompleteRenderOptionState { + var inputValue: String + var selected: Boolean +} + +@Suppress("UnsafeCastFromDynamic") +private val autocompleteComponent: RClass> = autocompleteModule.default + +fun RBuilder.autoComplete(vararg classMap: Pair, block: AutocompleteElementBuilder

.() -> Unit) + = child(AutocompleteElementBuilder
(autocompleteComponent, classMap.toList()) { DIV(mapOf(), it) }.apply(block).create()) + +fun RBuilder.autoComplete(vararg classMap: Pair, factory: (TagConsumer) -> T, block: AutocompleteElementBuilder.() -> Unit) + = child(AutocompleteElementBuilder(autocompleteComponent, classMap.toList(), factory).apply(block).create()) + +fun AutocompleteRenderInputParams.getTextFieldProps():TextFieldProps = + Object.assign(jsObject {},this) diff --git a/lab/src/main/kotlin/materialui/lab/components/autocomplete/enums/AutocompleteForcePopupIcon.kt b/lab/src/main/kotlin/materialui/lab/components/autocomplete/enums/AutocompleteForcePopupIcon.kt new file mode 100644 index 00000000..100b5b74 --- /dev/null +++ b/lab/src/main/kotlin/materialui/lab/components/autocomplete/enums/AutocompleteForcePopupIcon.kt @@ -0,0 +1,6 @@ +package materialui.lab.components.autocomplete.enums + +@Suppress("EnumEntryName") +enum class AutocompleteForcePopupIcon { + auto,`true`,`false` +} diff --git a/lab/src/main/kotlin/materialui/lab/components/autocomplete/enums/AutocompleteStyle.kt b/lab/src/main/kotlin/materialui/lab/components/autocomplete/enums/AutocompleteStyle.kt new file mode 100644 index 00000000..5bb3371e --- /dev/null +++ b/lab/src/main/kotlin/materialui/lab/components/autocomplete/enums/AutocompleteStyle.kt @@ -0,0 +1,26 @@ +package materialui.lab.components.autocomplete.enums + +@Suppress("EnumEntryName") +enum class AutocompleteStyle { + root, + focused, + tag, + tagSizeSmall, + inputRoot, + input, + inputFocused, + endAdornment, + clearIndicator, + clearIndicatorDirty, + popupIndicator, + popupIndicatorOpen, + popper, + popperDisablePortal, + paper, + listbox, + loading, + noOptions, + option, + groupLabel, + groupUl, +} \ No newline at end of file diff --git a/lab/src/main/kotlin/materialui/lab/components/useautocomplete/enums/AutocompleteBlurOnSelect.kt b/lab/src/main/kotlin/materialui/lab/components/useautocomplete/enums/AutocompleteBlurOnSelect.kt new file mode 100644 index 00000000..1506f8d3 --- /dev/null +++ b/lab/src/main/kotlin/materialui/lab/components/useautocomplete/enums/AutocompleteBlurOnSelect.kt @@ -0,0 +1,6 @@ +package materialui.lab.components.useautocomplete.enums + +@Suppress("EnumEntryName") +enum class AutocompleteBlurOnSelect { + touch ,mouse, `true` , `false`; +} \ No newline at end of file diff --git a/lab/src/main/kotlin/materialui/lab/components/useautocomplete/import.kt b/lab/src/main/kotlin/materialui/lab/components/useautocomplete/import.kt new file mode 100644 index 00000000..39cbf740 --- /dev/null +++ b/lab/src/main/kotlin/materialui/lab/components/useautocomplete/import.kt @@ -0,0 +1,10 @@ +@file:JsModule("@material-ui/lab/useAutocomplete") +@file:JsNonModule + +package materialui.lab.components.useautocomplete + +@JsName("default") +external fun useAutocomplete(props: UseAutocompleteProps): UseAutocompleteInterface + +@JsName("createFilterOptions") +external fun createFilterOptions(config: CreateFilterOptionsConfig = definedExternally): FilterOptions diff --git a/lab/src/main/kotlin/materialui/lab/components/useautocomplete/useAutocomplete.kt b/lab/src/main/kotlin/materialui/lab/components/useautocomplete/useAutocomplete.kt new file mode 100644 index 00000000..d361fd50 --- /dev/null +++ b/lab/src/main/kotlin/materialui/lab/components/useautocomplete/useAutocomplete.kt @@ -0,0 +1,123 @@ +package materialui.lab.components.useautocomplete + +import kotlinext.js.jsObject +import org.w3c.dom.HTMLElement +import org.w3c.dom.events.Event +import react.RProps + +external interface UseAutocompleteProps: RProps { + var autoComplete: Boolean? + var autoHighlight: Boolean? + var autoSelect: Boolean? + var blurOnSelect: dynamic /* 'touch' | 'mouse' | Boolean */ + var clearOnBlur: Boolean? + var clearOnEscape: Boolean? + var componentName: String? + var debug: Boolean? + var disableClearable: Boolean? + var disableCloseOnSelect: Boolean? + var disabledItemsFocusable: Boolean? + var disableListWrap: Boolean? + var filterOptions: FilterOptions? + var filterSelectedOptions: Boolean? + var freeSolo: Boolean? + var getOptionDisabled: ((option: T) -> Boolean)? + var getOptionLabel: ((option: T) -> String)? + var getOptionSelected: ((option: T, value: T) -> Boolean)? + var groupBy: ((option: T) -> String)? + var handleHomeEndKeys: Boolean? + var id: String? + var includeInputInList: Boolean? + var inputValue: String? + var onClose: ((event: Event, reason: AutocompleteCloseReason) -> Unit)? + var onInputChange: ((event: Event, value: String, reason: AutocompleteInputChangeReason) -> Unit)? + var onOpen: ((event: Event) -> Unit)? + var onHighlightChange: ((event: Event, option: T?, reason: AutocompleteHighlightChangeReason) -> Unit)? + var open: Boolean? + var openOnFocus: Boolean? + var options: Array + var selectOnFocus: Boolean? + var multiple: Boolean? + var value: dynamic + var defaultValue: dynamic + var onChange: ((event: Event, value: dynamic, reason: AutocompleteChangeReason, details: AutocompleteChangeDetails) -> Unit)? +} + +typealias AutocompleteChangeReason = String /* 'create-option' | 'select-option' | 'remove-option' | 'clear' | 'blur' */ +typealias AutocompleteCloseReason = String /* 'toggleInput' | 'escape' | 'select-option' | 'blur' */ +typealias AutocompleteInputChangeReason = String /* 'input' | 'reset' | 'clear' */ +typealias AutocompleteHighlightChangeReason = String /* 'keyboard' | 'mouse' | 'auto' */ + +external interface AutocompleteChangeDetails { + var option: T +} + +external interface FilterOptionsState { + var inputValue: String + var getOptionLabel: (option: T) -> String +} + +typealias FilterOptions = (options: Array, state: FilterOptionsState) -> Array + +external interface CreateFilterOptionsConfig { + var ignoreAccents: Boolean? + var ignoreCase: Boolean? + var limit: Number? + var matchFrom: String?// 'any' | 'start'; + var stringify: ((option: T) -> String)? + var trim: Boolean? +} + +external interface GetTagPropsParams { + var index: Number +} + +external interface GetOptionPropsParams { + var option: T + var index: Number +} + +external interface UseAutocompleteInterface { + fun getRootProps(): RProps + fun getInputProps(): RProps + fun getInputLabelProps(): RProps + fun getClearProps(): RProps + fun getPopupIndicatorProps(): RProps + fun getTagProps(params: GetTagPropsParams): RProps + fun getListboxProps(): RProps + fun getOptionProps(params: GetOptionPropsParams): RProps + val id: String + val inputValue: String + val value: dynamic + val dirty: Boolean + val popupOpen: Boolean + val focused: Boolean + val anchorEl: HTMLElement? + fun setAnchorEl() + val focusedTag: Int + val groupedOptions: Array +} + +fun UseAutocompleteInterface<*>.getTagProps(index: Int){ + this.getTagProps(jsObject { + this.index = index + }) +} + +fun UseAutocompleteInterface.getOptionProps(option: T, index: Int){ + this.getOptionProps(jsObject { + this.option = option + this.index = index + } + ) +} + +fun useAutocomplete(builder: UseAutocompleteProps.() -> Unit):UseAutocompleteInterface{ + return useAutocomplete(jsObject>().apply(builder)) +} + +/* +fun useAutoComplete(builder: UseAutocompletePropsBuilder.()->Unit){ + useAutocomplete(UseAutocompletePropsBuilder().apply(builder).build()) +} +*/ diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index 6589300f..526303b0 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -31,6 +31,7 @@ kotlin { val main by getting { dependencies { implementation(project(":core")) + implementation(project(":lab")) // implementation(project(":lab")) // implementation(project(":pickers")) // implementation(project(":pickers:date-io:date-fns")) diff --git a/sample/src/main/kotlin/demo/components/InputAdornmentsDemo.kt b/sample/src/main/kotlin/demo/components/InputAdornmentsDemo.kt index b6c1dcbd..0bd1a0c1 100644 --- a/sample/src/main/kotlin/demo/components/InputAdornmentsDemo.kt +++ b/sample/src/main/kotlin/demo/components/InputAdornmentsDemo.kt @@ -1,15 +1,21 @@ package demo.components +import kotlinext.js.jsObject import kotlinx.css.* import kotlinx.html.DIV import kotlinx.html.js.onChangeFunction +import materialui.components.formcontrol.enums.FormControlVariant import materialui.components.formcontrol.formControl +import materialui.components.icon.icon import materialui.components.input.input import materialui.components.inputadornment.InputAdornmentElementBuilder import materialui.components.inputadornment.enums.InputAdornmentPosition +import materialui.components.inputadornment.inputAdornment import materialui.components.inputlabel.inputLabel import materialui.components.menuitem.menuItem import materialui.components.textfield.textField +import materialui.lab.components.autocomplete.autoComplete +import materialui.lab.components.autocomplete.getTextFieldProps import materialui.styles.withStyles import org.w3c.dom.events.Event import react.* @@ -25,6 +31,15 @@ val ranges: List> "51-100" to "51 to 100" ) +external interface Person{ + var name: String + var age: Int +} +val DATA: Array = arrayOf( + jsObject { name = "Mizuki Makabe"; age = 17 }, + jsObject { name = "Madoka Higuchi"; age = 17 }, +) + class InputAdornmentsDemo : RComponent() { override fun InputAdornmentsState.init() { amount = "" @@ -124,6 +139,25 @@ class InputAdornmentsDemo : RComponent() { } } } + + autoComplete { + attrs.options = DATA + attrs.getOptionLabel = { it.name } + attrs.fullWidth = true + attrs.renderInput = { + it.InputProps.startAdornment = buildElement { + inputAdornment { + icon { +"person" } + } + } + textField { + props(it.getTextFieldProps()) + attrs.classes("$marginStyle $textFieldStyle") + attrs.label { +"Autocomplete Person" } + attrs.variant = FormControlVariant.outlined + } + } + } } } }