Dirk Hoffmann
01/04/2021, 1:33 PMpublic render() {
const buttonText = this.state.film.title;
return (
<Example header="Select Sandbox">
<FilmSelect
items={Films.TOP_100_FILMS}
itemPredicate={Films.filterFilm}
itemRenderer={Films.renderFilm}
noResults={<MenuItem disabled={true} text="No results." />}
onItemSelect={this.handleValueChange}
>
<Button text={buttonText} rightIcon="caret-down" />
</FilmSelect>
</Example>
);
}
my try is:
val FilmSelect = Select.ofType<Film>()
val exampleSelect = functionalComponent <SelectExampleProps> { props ->
val (selectExampleState, setSelectExampleState) = useState(SelectExampleState(TOP_100_FILMS[0]))
child(genericCard("Select Sandbox")) {
child(FilmSelect::class) {
attrs.items = TOP_100_FILMS
attrs.itemPredicate = filterFilm
attrs.itemRenderer = renderFilm
attrs.noResults = noResultsFunc
attrs.onItemSelect = handleValueChange
child(Button::class) {
attrs.text = selectExampleState.selectedFilm.title
attrs.rightIcon = "caret-down"
}
}
}
val handleValueChange = { film: Film, event: SyntheticEvent__1<HTMLElement> ->
setSelectExampleState(SelectExampleState(film))
}
}
so itemRenderer is
typealias ItemRenderer<T> = (item: T, itemProps: IItemRendererProps) -> ReactElement?
how can I implement such a funtion returning a ReactElement but not being "in scope" ??
my try so far is:
val renderFilm: ItemRenderer<Film> = { film: Film, itemProps: IItemRendererProps ->
if (!itemProps.modifiers.matchesPredicate) {
null;
}
val text = "${film.rank}. ${film.title}"
child(MenuItem::class) {
attrs.key = film.rank
attrs.active = itemProps.modifiers.active
attrs.disabled = itemProps.modifiers.disabled
attrs.label = film.year.toString()
attrs.onClick = itemProps.handleClick
attrs.text = highlightText(text, itemProps.query)
}
}
val filterFilm : ItemPredicate<Film> = { query: String, film: Film, index: Number, exactMatch: Boolean ->
"${film.rank}. ${film.title.toLowerCase()} ${film.year}".indexOf(query.toLowerCase()) >= 0
}
but obviously the lambda has no `child(MenuItem::class
)` method I can use ...
how would I implement an ItemRenderer which returns the ReactElement ??Joffrey
01/04/2021, 2:19 PMbuildElement
function, which takes a lambda that is run on a RBuilder
receiver, so you can effectively build your element independently of a hierarchy.Dirk Hoffmann
01/04/2021, 2:20 PMJoffrey
01/04/2021, 2:20 PMbuildElement
does it for you:
import react.buildElement
val elt = buildElement { // this: RBuilder
// code can use RBuilder receiver here
}
This function is defined like this:
inline fun buildElement(handler: RBuilder.() -> Unit): ReactElement =
RBuilder().apply(handler)
.childList.first()
.unsafeCast<ReactElement>()
So you can see it creates the RBuilder
on its own.Joffrey
01/04/2021, 2:26 PMDirk Hoffmann
01/04/2021, 2:28 PMJoffrey
01/04/2021, 2:28 PMJoffrey
01/04/2021, 2:29 PMval renderFilm: ItemRenderer<Film> = { film: Film, itemProps: IItemRendererProps ->
if (!itemProps.modifiers.matchesPredicate) {
null;
}
val text = "${film.rank}. ${film.title}"
buildElement {
child(MenuItem::class) {
attrs.key = film.rank
attrs.active = itemProps.modifiers.active
attrs.disabled = itemProps.modifiers.disabled
attrs.label = film.year.toString()
attrs.onClick = itemProps.handleClick
attrs.text = highlightText(text, itemProps.query)
}
}
}
Dirk Hoffmann
01/04/2021, 2:29 PM