@kobalte/core
Version:
Unstyled components and primitives for building accessible web apps and design systems with SolidJS.
177 lines (170 loc) • 5.95 kB
JavaScript
import { ComboboxContent, ComboboxControl, ComboboxHiddenSelect, ComboboxIcon, ComboboxInput, ComboboxListbox, ComboboxPortal, ComboboxBase } from '../chunk/DYCE77BF.js';
export { ComboboxContent as Content, ComboboxControl as Control, ComboboxHiddenSelect as HiddenSelect, ComboboxIcon as Icon, ComboboxInput as Input, ComboboxListbox as Listbox, ComboboxPortal as Portal } from '../chunk/DYCE77BF.js';
import { ListboxItem, ListboxItemDescription, ListboxItemLabel, ListboxSection } from '../chunk/MJSKFKQK.js';
export { ListboxItem as Item, ListboxItemDescription as ItemDescription, ListboxItemLabel as ItemLabel, ListboxSection as Section } from '../chunk/MJSKFKQK.js';
import { PopperArrow } from '../chunk/LMWVDFW6.js';
export { PopperArrow as Arrow } from '../chunk/LMWVDFW6.js';
import { FormControlLabel } from '../chunk/7ZHN3PYD.js';
export { FormControlLabel as Label } from '../chunk/7ZHN3PYD.js';
import { FormControlDescription } from '../chunk/YKGT7A57.js';
export { FormControlDescription as Description } from '../chunk/YKGT7A57.js';
import { Polymorphic } from '../chunk/6Y7B2NEO.js';
import { createComponent, mergeProps } from 'solid-js/web';
import { createContext, useContext, splitProps, Show, createSignal, createEffect, createMemo } from 'solid-js';
var SearchContext = createContext();
function useSearchContext() {
const context = useContext(SearchContext);
if (context === void 0) {
throw new Error("[kobalte]: `useSearchContext` must be used within a `Search` component");
}
return context;
}
// src/search/search-indicator.tsx
function SearchIndicator(props) {
const [local, other] = splitProps(props, ["loadingComponent"]);
const context = useSearchContext();
return createComponent(Polymorphic, mergeProps({
as: "span",
"aria-hidden": "true"
}, other, {
get children() {
return createComponent(Show, {
get when() {
return context.isLoadingSuggestions() === false || !local.loadingComponent;
},
get fallback() {
return local.loadingComponent;
},
get children() {
return props.children;
}
});
}
}));
}
function SearchNoResult(props) {
const context = useSearchContext();
return createComponent(Show, {
get when() {
return context.noResult();
},
get children() {
return createComponent(Polymorphic, mergeProps({
as: "div"
}, props));
}
});
}
// src/search/utils.ts
var DebouncerTimeout = () => {
let _debounceMillisecond = 0;
let lastCallbackTime = 0;
let timeout;
return {
debounce: (callback) => {
if (lastCallbackTime > Date.now() - _debounceMillisecond)
clearTimeout(timeout);
timeout = setTimeout(callback, _debounceMillisecond);
lastCallbackTime = Date.now();
return timeout;
},
setDebounceMillisecond: (debounceMillisecond = 0) => {
_debounceMillisecond = debounceMillisecond;
}
};
};
// src/search/search-root.tsx
function SearchRoot(props) {
const [local, omit, others] = splitProps(
props,
["options", "value", "defaultValue", "onChange", "multiple", "onInputChange", "debounceOptionsMillisecond"],
// @ts-expect-error filter is handled externally, so it's omitted
["defaultFilter"]
);
const [isLoadingSuggestions, setIsLoadingSuggestions] = createSignal(false);
const [suggestionTimeout, setSuggestionTimeout] = createSignal();
const inputChangeDebouncer = DebouncerTimeout();
createEffect(() => inputChangeDebouncer.setDebounceMillisecond(local.debounceOptionsMillisecond));
const onInputChange = (value2) => {
if (local.onInputChange === void 0)
return;
setIsLoadingSuggestions(true);
const timeout = inputChangeDebouncer.debounce(async () => {
await local.onInputChange(value2);
setIsLoadingSuggestions(false);
});
setSuggestionTimeout(timeout);
};
const value = createMemo(() => {
if (local.value != null) {
return local.multiple ? local.value : [local.value];
}
return local.value;
});
const defaultValue = createMemo(() => {
if (local.defaultValue != null) {
return local.multiple ? local.defaultValue : [local.defaultValue];
}
return local.defaultValue;
});
const onChange = (value2) => {
clearTimeout(suggestionTimeout());
setIsLoadingSuggestions(false);
if (local.multiple) {
local.onChange?.(value2 ?? []);
} else {
local.onChange?.(value2[0] ?? null);
}
};
const noResult = () => local.options.length === 0;
const context = {
noResult,
isLoadingSuggestions
};
return createComponent(SearchContext.Provider, {
value: context,
get children() {
return createComponent(ComboboxBase, mergeProps({
closeOnSelection: true,
shouldFocusWrap: true,
noResetInputOnBlur: true,
allowsEmptyCollection: true,
get options() {
return local.options;
},
get value() {
return value();
},
get defaultValue() {
return defaultValue();
},
onInputChange,
defaultFilter: () => true,
onChange,
get selectionMode() {
return local.multiple ? "multiple" : "single";
}
}, others));
}
});
}
// src/search/index.tsx
var Search = Object.assign(SearchRoot, {
Arrow: PopperArrow,
Content: ComboboxContent,
Control: ComboboxControl,
Description: FormControlDescription,
HiddenSelect: ComboboxHiddenSelect,
Icon: ComboboxIcon,
Input: ComboboxInput,
Item: ListboxItem,
ItemDescription: ListboxItemDescription,
ItemLabel: ListboxItemLabel,
Label: FormControlLabel,
Listbox: ComboboxListbox,
Portal: ComboboxPortal,
Section: ListboxSection,
NoResult: SearchNoResult,
Indicator: SearchIndicator
});
export { SearchIndicator as Indicator, SearchNoResult as NoResult, SearchRoot as Root, Search, useSearchContext };