ui/search: add loading state
This commit is contained in:
@@ -117,6 +117,27 @@ export const Default: Story = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const Loading: Story = {
|
||||||
|
args: {
|
||||||
|
// Test with lots of modules
|
||||||
|
loading: true,
|
||||||
|
options: [],
|
||||||
|
renderItem: () => <span></span>,
|
||||||
|
},
|
||||||
|
render: (args: SearchProps<Module>) => {
|
||||||
|
return (
|
||||||
|
<div class="absolute bottom-1/3 w-3/4 px-3">
|
||||||
|
<Search<Module>
|
||||||
|
{...args}
|
||||||
|
onChange={(module) => {
|
||||||
|
// Go to the module configuration
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
type MachineOrTag =
|
type MachineOrTag =
|
||||||
| {
|
| {
|
||||||
value: string;
|
value: string;
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ import Icon from "../Icon/Icon";
|
|||||||
import { Button } from "../Button/Button";
|
import { Button } from "../Button/Button";
|
||||||
import styles from "./Search.module.css";
|
import styles from "./Search.module.css";
|
||||||
import { Combobox } from "@kobalte/core/combobox";
|
import { Combobox } from "@kobalte/core/combobox";
|
||||||
import { createMemo, createSignal, For, JSX } from "solid-js";
|
import { createMemo, createSignal, For, JSX, Match, Switch } from "solid-js";
|
||||||
import { createVirtualizer } from "@tanstack/solid-virtual";
|
import { createVirtualizer } from "@tanstack/solid-virtual";
|
||||||
import { CollectionNode } from "@kobalte/core/*";
|
import { CollectionNode } from "@kobalte/core/*";
|
||||||
|
import { Loader } from "../Loader/Loader";
|
||||||
|
|
||||||
export interface Option {
|
export interface Option {
|
||||||
value: string;
|
value: string;
|
||||||
@@ -15,6 +16,8 @@ export interface SearchProps<T> {
|
|||||||
onChange: (value: T | null) => void;
|
onChange: (value: T | null) => void;
|
||||||
options: T[];
|
options: T[];
|
||||||
renderItem: (item: T) => JSX.Element;
|
renderItem: (item: T) => JSX.Element;
|
||||||
|
loading?: boolean;
|
||||||
|
loadingComponent?: JSX.Element;
|
||||||
}
|
}
|
||||||
export function Search<T extends Option>(props: SearchProps<T>) {
|
export function Search<T extends Option>(props: SearchProps<T>) {
|
||||||
// Controlled input value, to allow resetting the input itself
|
// Controlled input value, to allow resetting the input itself
|
||||||
@@ -136,6 +139,15 @@ export function Search<T extends Option>(props: SearchProps<T>) {
|
|||||||
setComboboxItems(arr);
|
setComboboxItems(arr);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Switch>
|
||||||
|
<Match when={props.loading}>
|
||||||
|
{props.loadingComponent ?? (
|
||||||
|
<div class="flex w-full justify-center py-2">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Match>
|
||||||
|
<Match when={!props.loading}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
height: `${virtualizer().getTotalSize()}px`,
|
height: `${virtualizer().getTotalSize()}px`,
|
||||||
@@ -149,7 +161,10 @@ export function Search<T extends Option>(props: SearchProps<T>) {
|
|||||||
items().getItem(virtualRow.key as string);
|
items().getItem(virtualRow.key as string);
|
||||||
|
|
||||||
if (!item) {
|
if (!item) {
|
||||||
console.warn("Item not found for key:", virtualRow.key);
|
console.warn(
|
||||||
|
"Item not found for key:",
|
||||||
|
virtualRow.key,
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
@@ -171,6 +186,8 @@ export function Search<T extends Option>(props: SearchProps<T>) {
|
|||||||
}}
|
}}
|
||||||
</For>
|
</For>
|
||||||
</div>
|
</div>
|
||||||
|
</Match>
|
||||||
|
</Switch>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Combobox.Listbox>
|
</Combobox.Listbox>
|
||||||
|
|||||||
Reference in New Issue
Block a user