@agilant/toga-blox 1.0.50 → 1.0.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/SearchInput/SearchDropdownInput.d.ts +1 -1
- package/dist/components/SearchInput/SearchDropdownInput.js +1 -1
- package/dist/components/SearchInput/SearchInput.js +2 -1
- package/dist/components/SearchInput/SearchTextInput.d.ts +10 -1
- package/dist/components/SearchInput/SearchTextInput.js +63 -19
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import MultiSelectInput from "../MultiSelect/MultiSelect";
|
|
3
|
-
import "./
|
|
3
|
+
import "./SearchDropdown.scss";
|
|
4
4
|
/**
|
|
5
5
|
* A wrapper around MultiSelectInput that appends a special "__footer__" option
|
|
6
6
|
* and uses a custom item renderer to display "Clear" and "Filter" buttons.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// SearchInput.tsx
|
|
2
3
|
import { useEffect, useRef } from "react";
|
|
3
4
|
import SearchTextInput from "./SearchTextInput";
|
|
4
5
|
import SearchNumberInput from "./SearchNumberInput";
|
|
@@ -17,7 +18,7 @@ const SearchInput = ({ bgColor = "bg-sky-500", textHighlight = "text-sky-500", i
|
|
|
17
18
|
return (_jsx("div", { ref: containerRef, className: "", children: (() => {
|
|
18
19
|
switch (inputType) {
|
|
19
20
|
case "text":
|
|
20
|
-
return (_jsx(SearchTextInput, { dropdownIconProp: dropdownIconProp, dropdownOptions: dropdownOptions, selectedDropdownOption: selectedDropdownOption, onDropdownOptionSelect: onDropdownOptionSelect, searchItems: searchItems, setSearchItems: setSearchItems, handleFilter: handleFilter }));
|
|
21
|
+
return (_jsx(SearchTextInput, { dropdownIconProp: dropdownIconProp, dropdownOptions: dropdownOptions, selectedDropdownOption: selectedDropdownOption, onDropdownOptionSelect: onDropdownOptionSelect, searchItems: searchItems, setSearchItems: setSearchItems, handleFilter: handleFilter, column: undefined }));
|
|
21
22
|
case "number":
|
|
22
23
|
return (_jsx(SearchNumberInput, { dropdownIconProp: dropdownIconProp, dropdownOptions: dropdownOptions, selectedDropdownOption: selectedDropdownOption, onDropdownOptionSelect: onDropdownOptionSelect, toggleStatus: toggleStatus, setToggleStatus: setToggleStatus, minValue: minValue, maxValue: maxValue, setMinValue: setMinValue, setMaxValue: setMaxValue, handleFilter: handleFilter }));
|
|
23
24
|
case "multiSelect":
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { ColumnInstance } from "react-table";
|
|
2
3
|
import { searchDropdownIconProps } from "./SearchInput.types";
|
|
4
|
+
export type SearchCriterion<T extends object> = {
|
|
5
|
+
searchColumn: ColumnInstance<T>;
|
|
6
|
+
submittedSearchText: string;
|
|
7
|
+
};
|
|
3
8
|
type SearchTextInputProps<T extends object> = {
|
|
4
9
|
pillColor?: string;
|
|
5
10
|
textHighlight?: string;
|
|
@@ -9,7 +14,11 @@ type SearchTextInputProps<T extends object> = {
|
|
|
9
14
|
dropdownOptions?: string[];
|
|
10
15
|
searchItems?: string[];
|
|
11
16
|
setSearchItems?: React.Dispatch<React.SetStateAction<string[]>>;
|
|
17
|
+
searchCriteria?: SearchCriterion<T>[];
|
|
18
|
+
setSearchCriteria?: React.Dispatch<React.SetStateAction<SearchCriterion<T>[]>>;
|
|
19
|
+
column: ColumnInstance<T>;
|
|
12
20
|
handleFilter?: () => void;
|
|
21
|
+
localStorageKey?: string;
|
|
13
22
|
};
|
|
14
|
-
declare const SearchTextInput: <T extends object>({ pillColor, textHighlight, dropdownIconProp, dropdownOptions, selectedDropdownOption, onDropdownOptionSelect,
|
|
23
|
+
declare const SearchTextInput: <T extends object>({ pillColor, textHighlight, dropdownIconProp, dropdownOptions, selectedDropdownOption, onDropdownOptionSelect, searchCriteria, setSearchCriteria, column, handleFilter, localStorageKey, }: SearchTextInputProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
15
24
|
export default SearchTextInput;
|
|
@@ -2,45 +2,89 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useEffect, useRef, useState } from "react";
|
|
3
3
|
import { AnimatePresence, motion } from "framer-motion";
|
|
4
4
|
import { Input } from "../Input";
|
|
5
|
-
import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
|
|
6
5
|
import Dropdown from "../Dropdown/Dropdown";
|
|
7
6
|
import Badge from "../Badge/Badge";
|
|
8
7
|
import Text from "../Text";
|
|
8
|
+
import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
|
|
9
9
|
const SearchTextInput = ({ pillColor = "bg-sky-500", textHighlight = "text-sky-500", dropdownIconProp = {
|
|
10
10
|
iconClasses: textHighlight,
|
|
11
11
|
name: "chevronDown",
|
|
12
12
|
weight: "solid",
|
|
13
|
-
}, dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect,
|
|
13
|
+
}, dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, searchCriteria = [], setSearchCriteria, column, handleFilter, localStorageKey = "zu-table-store", }) => {
|
|
14
14
|
const containerRef = useRef(null);
|
|
15
15
|
const [localSearchText, setLocalSearchText] = useState("");
|
|
16
16
|
const inputRef = useRef(null);
|
|
17
|
-
//
|
|
17
|
+
// On mount, focus input and optionally load criteria from local storage.
|
|
18
18
|
useEffect(() => {
|
|
19
19
|
inputRef.current?.focus();
|
|
20
|
-
|
|
20
|
+
const stored = localStorage.getItem(localStorageKey);
|
|
21
|
+
if (stored && setSearchCriteria) {
|
|
22
|
+
try {
|
|
23
|
+
const parsed = JSON.parse(stored);
|
|
24
|
+
if (parsed?.state?.searchCriteria) {
|
|
25
|
+
setSearchCriteria(parsed.state.searchCriteria);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
console.error("Error parsing local storage data:", e);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}, [localStorageKey, setSearchCriteria]);
|
|
21
33
|
const handleInputChange = (event) => {
|
|
22
34
|
setLocalSearchText(event.target.value);
|
|
23
35
|
};
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
// Update local storage in the format used in your working app.
|
|
37
|
+
const updateLocalStorage = (criteria) => {
|
|
38
|
+
localStorage.setItem(localStorageKey, JSON.stringify({
|
|
39
|
+
state: { searchCriteria: criteria },
|
|
40
|
+
version: 0,
|
|
41
|
+
}));
|
|
42
|
+
};
|
|
43
|
+
const handleSubmit = () => {
|
|
44
|
+
const trimmed = localSearchText.trim();
|
|
45
|
+
if (!trimmed)
|
|
46
|
+
return;
|
|
47
|
+
let newCriteria;
|
|
48
|
+
if (searchCriteria.some((c) => c.searchColumn.id === column.id)) {
|
|
49
|
+
newCriteria = searchCriteria.map((c) => c.searchColumn.id === column.id
|
|
50
|
+
? { searchColumn: column, submittedSearchText: trimmed }
|
|
51
|
+
: c);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
newCriteria = [
|
|
55
|
+
...searchCriteria,
|
|
56
|
+
{ searchColumn: column, submittedSearchText: trimmed },
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
if (setSearchCriteria) {
|
|
60
|
+
setSearchCriteria(newCriteria);
|
|
61
|
+
}
|
|
62
|
+
updateLocalStorage(newCriteria);
|
|
63
|
+
setLocalSearchText("");
|
|
64
|
+
if (handleFilter) {
|
|
65
|
+
handleFilter();
|
|
66
|
+
}
|
|
28
67
|
};
|
|
29
68
|
const handleKeyDown = (e) => {
|
|
30
|
-
if (e.key === "Enter"
|
|
69
|
+
if (e.key === "Enter") {
|
|
31
70
|
e.preventDefault();
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
71
|
+
handleSubmit();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
// Clear the criterion for this column.
|
|
75
|
+
const handleClearCriterion = () => {
|
|
76
|
+
const newCriteria = searchCriteria.filter((c) => c.searchColumn.id !== column.id);
|
|
77
|
+
if (setSearchCriteria) {
|
|
78
|
+
setSearchCriteria(newCriteria);
|
|
35
79
|
}
|
|
80
|
+
updateLocalStorage(newCriteria);
|
|
81
|
+
setLocalSearchText("");
|
|
36
82
|
};
|
|
37
83
|
const pillClassnames = `${pillColor} p-1 max-w-fit min-w-20 rounded-full flex justify-between items-center text-white text-xs px-4 border-none mr-4 mb-1`;
|
|
38
|
-
return (_jsx("div", { ref: containerRef, className: "w-[425px]", children: _jsxs("div", { className: "flex flex-col border-2 border-navy-200 rounded-md", children: [_jsxs("div", { className: `flex ${
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return (_jsx(Badge, { backgroundColor: pillColor, borderRadius: "rounded-full", hasRightIcon: true, icon: _jsx("div", { className: "text-white text-xxs", "data-testid": "item-clear-icon", children: getFontAwesomeIcon("xmark", "solid") }), iconSize: "text-sm", mobileIconLabel: item, onClick: () => handleIconClick(item), text: _jsx(Text, { color: "text-white", fontFamily: "font-serif", size: "text-sm", tag: "span", text: item }), badgeContainerClasses: pillClassnames, type: "span" }));
|
|
44
|
-
}) })) : null] }) }));
|
|
84
|
+
return (_jsx("div", { ref: containerRef, className: "w-[425px]", children: _jsxs("div", { className: "flex flex-col border-2 border-navy-200 rounded-md", children: [_jsxs("div", { className: `flex ${searchCriteria.some((c) => c.searchColumn.id === column.id)
|
|
85
|
+
? "border-b-2"
|
|
86
|
+
: ""} h-full`, children: [_jsx(Dropdown, { options: dropdownOptions, selectedOption: selectedDropdownOption, onOptionSelect: onDropdownOptionSelect, optionClasses: "px-4 py-1 h-full flex items-center", menuClasses: "bg-white min-w-32", icon: dropdownIconProp, dropdownClasses: "border-0 border-r-2 w-auto" }), _jsx(Input, { ref: inputRef, focusRingColor: "focus:ring-transparent", hasAutoFocus: true, value: localSearchText, iconColor: "text-navy-400", onKeyDown: handleKeyDown, required: false, id: "", name: "", type: "text", onChange: handleInputChange, additionalClasses: "min-w-[250px] min-h-full text-gray flex", placeholder: "Search", hasIcons: true, firstIcon: localSearchText === "" ? (_jsx(AnimatePresence, { children: _jsx(motion.div, { initial: "initial", animate: "animate", exit: "exit", className: "text-navy-400", children: getFontAwesomeIcon("search", "regular") }) })) : undefined, iconPosition: "both", secondIcon: _jsx("div", { className: "border-transparent text-white min-w-9", children: _jsx(AnimatePresence, { children: localSearchText !== "" && (_jsxs(motion.div, { className: "flex justify-between items-center min-w-4 text-navy-400 hover:cursor-pointer hover:text-primary", initial: "initial", animate: "animate", exit: "exit", onClick: handleSubmit, children: [_jsx("div", { className: "bg-navy-50 pr-2 pl-1 text-gray-500", onClick: handleClearCriterion, "data-testid": "clear-icon", children: getFontAwesomeIcon("xmark", "regular") }), _jsx("div", { className: `${textHighlight} text-sm hover:text-primary`, children: getFontAwesomeIcon("search", "solid") })] })) }) }), onIconClick: handleClearCriterion })] }), searchCriteria.some((c) => c.searchColumn.id === column.id) && (_jsx("div", { className: "flex flex-wrap bg-white py-2 px-2 rounded-md", children: searchCriteria
|
|
87
|
+
.filter((c) => c.searchColumn.id === column.id)
|
|
88
|
+
.map((criterion, index) => (_jsx(Badge, { backgroundColor: pillColor, borderRadius: "rounded-full", hasRightIcon: true, icon: _jsx("div", { className: "text-white text-xxs", "data-testid": "item-clear-icon", children: getFontAwesomeIcon("xmark", "solid") }), iconSize: "text-sm", mobileIconLabel: criterion.submittedSearchText, onClick: handleClearCriterion, text: _jsx(Text, { color: "text-white", fontFamily: "font-serif", size: "text-sm", tag: "span", text: criterion.submittedSearchText }), badgeContainerClasses: pillClassnames, type: "span" }, index))) }))] }) }));
|
|
45
89
|
};
|
|
46
90
|
export default SearchTextInput;
|