UNPKG

@kit-data-manager/react-search-component

Version:

All-in-one component for rendering an elastic search UI for searching anything. Built-in support for visualizing related items in a graph and resolving unique identifiers.

67 lines 6.1 kB
"use client"; import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { ReactSearchComponentContextProvider } from "../components/ReactSearchComponentContextProvider"; import { RelationsGraphProvider } from "../components/graph/RelationsGraphProvider"; import { ClearFilters } from "../components/search/ClearFilters"; import { DefaultFacet } from "../components/search/DefaultFacet"; import { DefaultSearchBox } from "../components/search/DefaultSearchBox"; import { ErrorView } from "../components/search/ErrorView"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../components/ui/select"; import { SearchConfigBuilder } from "../lib/config/SearchConfigBuilder"; import { ErrorBoundary, Facet, Paging, PagingInfo, Results, ResultsPerPage, SearchBox, SearchProvider, WithSearch } from "@elastic/react-search-ui"; import { Layout } from "@elastic/react-search-ui-views"; import { LoaderCircle } from "lucide-react"; import { useCallback, useMemo } from "react"; import "../index.css"; import "../elastic-ui.css"; import { TooltipProvider } from "./ui/tooltip"; import { DefaultSorting } from "../components/search/DefaultSorting"; import { ResultViewSelector } from "../components/result/ResultViewSelector"; import { useAutoDarkMode } from "../lib/hooks"; /** * All-in-one component for rendering an elastic search UI based on the provided configuration. Includes * an interactive graph of related records. Pass in a config object ({@link SearchConfig}) to configure the search. * * #### ⚠️ Warning * * Make sure your configuration is memoized or defined outside any components * * * #### 🖌️ Customization * You can customize the default behaviour by overriding the default result view (resultView) or the views of the facet * options (facetOptionView). * * You can also specify your own graph nodes to dynamically render any relationships between objects. ([Package Docs](https://reactflow.dev/learn/customization/custom-nodes)) */ export function ReactSearchComponent({ config: rawConfig, resultView, resultViewPerIndex, facetOptionView, dark, graphNodeTypes }) { useAutoDarkMode(dark); const config = useMemo(() => { return new SearchConfigBuilder(rawConfig); }, [rawConfig]); const elasticConfig = useMemo(() => { return config.buildElasticSearchConfig(); }, [config]); const facetFields = useMemo(() => { return config.getFacetFields(); }, [config]); const actualResultView = useCallback((props) => { return _jsx(ResultViewSelector, { resultProps: props, resultView: resultView, resultViewPerIndex: resultViewPerIndex }); }, [resultView, resultViewPerIndex]); return (_jsx(SearchProvider, { config: elasticConfig, children: _jsx(ReactSearchComponentContextProvider, { config: rawConfig, children: _jsx(TooltipProvider, { children: _jsx(RelationsGraphProvider, { resultView: actualResultView, dark: dark, nodeTypes: graphNodeTypes, children: _jsx(WithSearch, { mapContextToProps: ({ wasSearched, isLoading }) => ({ wasSearched, isLoading }), children: ({ wasSearched, isLoading }) => { return (_jsx(ErrorBoundary, { view: ErrorView, children: _jsx(Layout, { header: _jsx(SearchBox, { autocompleteMinimumCharacters: 3, autocompleteResults: { linkTarget: "_blank", sectionTitle: "Results", titleField: "title", urlField: "url", shouldTrackClickThrough: true }, autocompleteSuggestions: true, debounceLength: 300, searchAsYouType: true, inputView: DefaultSearchBox }), sideContent: _jsxs("div", { children: [facetFields.map((field) => (_jsx(Facet, { field: field.key, label: field.label ? field.label : field.key.substring(0, 20), view: (props) => _jsx(DefaultFacet, { ...props, config: config, optionView: facetOptionView }), isFilterable: field.isFilterable, filterType: field.filterType }, field.key))), _jsx(ClearFilters, {})] }), bodyContent: _jsxs(_Fragment, { children: [isLoading && !wasSearched && (_jsx("div", { className: "rfs-flex rfs-justify-center", children: _jsx(LoaderCircle, { className: "rfs-size-6 rfs-animate-spin" }) })), _jsx(Results, { shouldTrackClickThrough: true, resultView: actualResultView })] }), bodyHeader: _jsxs("div", { className: "rfs-flex rfs-w-full rfs-items-center rfs-justify-between rfs-p-2", children: [wasSearched && (_jsx(PagingInfo, { view: (props) => (_jsxs("div", { children: ["Showing ", props.start, " -", props.end, " out of ", props.totalResults] })) })), wasSearched && _jsx(DefaultSorting, {})] }), bodyFooter: _jsxs("div", { className: "rfs-flex rfs-items-center rfs-flex-col rfs-gap-2 md:rfs-grid rfs-grid-cols-[1fr_auto_1fr] rfs-w-full rfs-p-2", children: [_jsx("div", {}), _jsx(Paging, {}), wasSearched && (_jsx(ResultsPerPage, { options: [20, 50, 100, 250], view: (props) => { return (_jsxs("div", { className: "rfs-flex rfs-h-full rfs-items-center rfs-gap-2 rfs-justify-self-end", children: [_jsx("div", { className: "rfs-text-xs rfs-text-muted-foreground", children: "Results per Page" }), _jsxs(Select, { value: `${props.value}`, onValueChange: (v) => props.onChange(Number.parseInt(v)), children: [_jsx(SelectTrigger, { className: "rfs-w-[80px]", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: props.options?.map((option) => { return (_jsx(SelectItem, { value: `${option}`, children: option }, option)); }) })] })] })); } }))] }) }) })); } }) }) }) }) })); } //# sourceMappingURL=ReactSearchComponent.js.map