svelte-multiselect
Version:
Svelte multi-select component
172 lines (171 loc) • 5.29 kB
TypeScript
import type { FlipParams } from 'svelte/animate';
import type { Snippet } from 'svelte';
import type { HTMLAttributes, HTMLInputAttributes } from 'svelte/elements';
export type Option = string | number | ObjectOption;
export type OptionStyle = string | {
option: string;
selected: string;
};
export type ObjectOption = {
label: string | number;
value?: unknown;
title?: string;
disabled?: boolean;
preselected?: boolean;
disabledTitle?: string;
selectedTitle?: string;
style?: OptionStyle;
[key: string]: unknown;
};
export type PlaceholderConfig = {
text: string;
persistent?: boolean;
};
export interface MultiSelectEvents<T extends Option = Option> {
onadd?: (data: {
option: T;
}) => unknown;
oncreate?: (data: {
option: T;
}) => unknown;
onremove?: (data: {
option: T;
}) => unknown;
onremoveAll?: (data: {
options: T[];
}) => unknown;
onselectAll?: (data: {
options: T[];
}) => unknown;
onchange?: (data: {
option?: T;
options?: T[];
type: `add` | `remove` | `removeAll` | `selectAll`;
}) => unknown;
onopen?: (data: {
event: Event;
}) => unknown;
onclose?: (data: {
event: Event;
}) => unknown;
}
export interface LoadOptionsParams {
search: string;
offset: number;
limit: number;
}
export interface LoadOptionsResult<T extends Option = Option> {
options: T[];
hasMore: boolean;
}
export type LoadOptionsFn<T extends Option = Option> = (params: LoadOptionsParams) => Promise<LoadOptionsResult<T>>;
export interface LoadOptionsConfig<T extends Option = Option> {
fetch: LoadOptionsFn<T>;
debounceMs?: number;
batchSize?: number;
onOpen?: boolean;
}
export type LoadOptions<T extends Option = Option> = LoadOptionsFn<T> | LoadOptionsConfig<T>;
type AfterInputProps = Pick<MultiSelectProps, `selected` | `disabled` | `invalid` | `id` | `placeholder` | `open` | `required`>;
type UserMsgProps = {
searchText: string;
msgType: false | `dupe` | `create` | `no-match`;
msg: null | string;
};
export interface MultiSelectSnippets<T extends Option = Option> {
expandIcon?: Snippet<[{
open: boolean;
}]>;
selectedItem?: Snippet<[{
option: T;
idx: number;
}]>;
children?: Snippet<[{
option: T;
idx: number;
}]>;
removeIcon?: Snippet;
afterInput?: Snippet<[AfterInputProps]>;
spinner?: Snippet;
disabledIcon?: Snippet;
option?: Snippet<[{
option: T;
idx: number;
}]>;
userMsg?: Snippet<[UserMsgProps]>;
}
export interface PortalParams {
target_node?: HTMLElement | null;
active?: boolean;
}
export interface MultiSelectProps<T extends Option = Option> extends MultiSelectEvents<T>, MultiSelectSnippets<T>, Omit<HTMLAttributes<HTMLDivElement>, `children` | `onchange` | `onclose` | `placeholder`> {
activeIndex?: number | null;
activeOption?: T | null;
createOptionMsg?: string | null;
allowUserOptions?: boolean | `append`;
allowEmpty?: boolean;
autocomplete?: HTMLInputAttributes[`autocomplete`];
autoScroll?: boolean;
breakpoint?: number;
defaultDisabledTitle?: string;
disabled?: boolean;
disabledInputTitle?: string;
duplicateOptionMsg?: string;
duplicates?: boolean;
keepSelectedInDropdown?: false | `plain` | `checkboxes`;
key?: (opt: T) => unknown;
filterFunc?: (opt: T, searchText: string) => boolean;
fuzzy?: boolean;
closeDropdownOnSelect?: boolean | `if-mobile` | `retain-focus`;
form_input?: HTMLInputElement | null;
highlightMatches?: boolean;
id?: string | null;
input?: HTMLInputElement | null;
inputClass?: string;
inputStyle?: string | null;
inputmode?: HTMLInputAttributes[`inputmode`] | null;
invalid?: boolean;
liActiveOptionClass?: string;
liActiveUserMsgClass?: string;
liOptionClass?: string;
liOptionStyle?: string | null;
liSelectedClass?: string;
liSelectedStyle?: string | null;
liUserMsgClass?: string;
loading?: boolean;
matchingOptions?: T[];
maxOptions?: number | undefined;
maxSelect?: number | null;
maxSelectMsg?: ((current: number, max: number) => string) | null;
maxSelectMsgClass?: string;
name?: string | null;
noMatchingOptionsMsg?: string;
open?: boolean;
options?: T[];
outerDiv?: HTMLDivElement | null;
outerDivClass?: string;
parseLabelsAsHtml?: boolean;
pattern?: string | null;
placeholder?: string | PlaceholderConfig | null;
removeAllTitle?: string;
removeBtnTitle?: string;
minSelect?: number | null;
required?: boolean | number;
resetFilterOnAdd?: boolean;
searchText?: string;
selected?: T[];
sortSelected?: boolean | ((op1: T, op2: T) => number);
selectedOptionsDraggable?: boolean;
style?: string | null;
ulOptionsClass?: string;
ulSelectedClass?: string;
ulSelectedStyle?: string | null;
ulOptionsStyle?: string | null;
value?: T | T[] | null;
portal?: PortalParams;
selectAllOption?: boolean | string;
liSelectAllClass?: string;
loadOptions?: LoadOptions<T>;
selectedFlipParams?: FlipParams;
}
export {};