@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.12 kB
JavaScript
"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, { className: "rfs-root", 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 rfs:md: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