diff --git a/headless/src/jsMain/kotlin/dev/fritz2/headless/components/combobox.kt b/headless/src/jsMain/kotlin/dev/fritz2/headless/components/combobox.kt index a20750f10..11638cc29 100644 --- a/headless/src/jsMain/kotlin/dev/fritz2/headless/components/combobox.kt +++ b/headless/src/jsMain/kotlin/dev/fritz2/headless/components/combobox.kt @@ -281,7 +281,10 @@ class Combobox(tag: Tag, id: String?) : Tag by tag, Op * > be used with caution here. */ private fun buildItemListResult(query: String, itemSequence: Sequence): ItemList { - val (resultList, truncated) = itemSequence.mapIndexed(::Item).toListTruncating(maximumDisplayedItems) + val (resultList, truncated) = itemSequence + .mapIndexed(::Item) + .toListTruncating(maximumDisplayedItems) + return ItemList( query, resultList, @@ -401,7 +404,8 @@ class Combobox(tag: Tag, id: String?) : Tag by tag, Op private data class InternalState( val items: List = emptyList(), val query: String = "", - val opened: Boolean = false + val opened: Boolean = false, + val lastSelection: T? = null, ) @@ -484,12 +488,25 @@ class Combobox(tag: Tag, id: String?) : Tag by tag, Op current.copy(opened = false) } + + private fun InternalState.select(selection: T?): InternalState = + copy(query = "", opened = false, lastSelection = selection) + val select: EmittingHandler = handleAndEmit { current, selection -> - current.copy(query = "", opened = false).also { + current.select(selection).also { emit(selection) } } + val selectIfDifferent: EmittingHandler = handleAndEmit { current, selection -> + if (selection != current.lastSelection) { + emit(selection) + current.select(selection) + } else current + } + + val selections: Flow = merge(select, selectIfDifferent) + private fun computeQueryResult(items: List, query: String): QueryResult = filterBy @@ -620,8 +637,8 @@ class Combobox(tag: Tag, id: String?) : Tag by tag, Op fun render() { value( merge( - internalState.select.map { format(it) }, - value.data.flatMapLatest { value -> + internalState.selections.map { format(it) }, + internalState.data.map { it.lastSelection }.distinctUntilChanged().flatMapLatest { value -> internalState.resetQuery.transform { // Before the input's value can be reset to the previous one we need to set it to // the current typed value. This is needed because the underlying `mountSimple` function @@ -905,8 +922,8 @@ class Combobox(tag: Tag, id: String?) : Tag by tag, Op hook(items) - value.data handledBy internalState.select - value.handler?.invoke(this, internalState.select) + value.data handledBy internalState.selectIfDifferent + value.handler?.invoke(this, internalState.selections) opened handledBy internalState.setOpened openState.handler?.invoke(this, internalState.data.map { it.opened }.distinctUntilChanged())