Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combobox: Only accept distinct values via data-binding #913

Merged
merged 1 commit into from
Nov 6, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,10 @@ class Combobox<E : HTMLElement, T>(tag: Tag<E>, id: String?) : Tag<E> by tag, Op
* > be used with caution here.
*/
private fun buildItemListResult(query: String, itemSequence: Sequence<T>): ItemList<T> {
val (resultList, truncated) = itemSequence.mapIndexed(::Item).toListTruncating(maximumDisplayedItems)
val (resultList, truncated) = itemSequence
.mapIndexed(::Item)
.toListTruncating(maximumDisplayedItems)

return ItemList(
query,
resultList,
Expand Down Expand Up @@ -401,7 +404,8 @@ class Combobox<E : HTMLElement, T>(tag: Tag<E>, id: String?) : Tag<E> by tag, Op
private data class InternalState<T>(
val items: List<T> = emptyList(),
val query: String = "",
val opened: Boolean = false
val opened: Boolean = false,
val lastSelection: T? = null,
)


Expand Down Expand Up @@ -484,12 +488,25 @@ class Combobox<E : HTMLElement, T>(tag: Tag<E>, id: String?) : Tag<E> by tag, Op
current.copy(opened = false)
}


private fun InternalState<T>.select(selection: T?): InternalState<T> =
copy(query = "", opened = false, lastSelection = selection)

val select: EmittingHandler<T?, T?> = handleAndEmit { current, selection ->
current.copy(query = "", opened = false).also {
current.select(selection).also {
emit(selection)
}
}

val selectIfDifferent: EmittingHandler<T?, T?> = handleAndEmit { current, selection ->
if (selection != current.lastSelection) {
emit(selection)
current.select(selection)
} else current
}

val selections: Flow<T?> = merge(select, selectIfDifferent)


private fun computeQueryResult(items: List<T>, query: String): QueryResult<T> =
filterBy
Expand Down Expand Up @@ -620,8 +637,8 @@ class Combobox<E : HTMLElement, T>(tag: Tag<E>, id: String?) : Tag<E> 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
Expand Down Expand Up @@ -905,8 +922,8 @@ class Combobox<E : HTMLElement, T>(tag: Tag<E>, id: String?) : Tag<E> 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())
Expand Down
Loading