@agilant/toga-blox 1.0.60 → 1.0.62
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.
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import SearchInput from "./SearchInput";
|
|
3
3
|
import { useState } from "react";
|
|
4
|
+
// Mock data for column
|
|
5
|
+
const mockColumn = {
|
|
6
|
+
id: "mockColumn",
|
|
7
|
+
Header: "Mock Column",
|
|
8
|
+
};
|
|
4
9
|
export default {
|
|
5
10
|
title: "Components/SearchInput",
|
|
6
11
|
component: SearchInput,
|
|
@@ -24,10 +29,6 @@ export default {
|
|
|
24
29
|
control: "text",
|
|
25
30
|
description: "Currently selected dropdown option",
|
|
26
31
|
},
|
|
27
|
-
onDropdownOptionSelect: {
|
|
28
|
-
action: "selected",
|
|
29
|
-
description: "Callback when dropdown option is selected",
|
|
30
|
-
},
|
|
31
32
|
searchItems: {
|
|
32
33
|
control: "array",
|
|
33
34
|
description: "Array of search items",
|
|
@@ -39,35 +40,35 @@ export default {
|
|
|
39
40
|
},
|
|
40
41
|
parameters: { layout: "centered" },
|
|
41
42
|
};
|
|
42
|
-
//
|
|
43
|
-
const mockColumn = {
|
|
44
|
-
id: "mockColumn",
|
|
45
|
-
Header: "Mock Column",
|
|
46
|
-
};
|
|
43
|
+
// Updated Template with state for searchCriteria and editingHeader
|
|
47
44
|
const Template = (args) => {
|
|
48
45
|
const [selectedOption, setSelectedOption] = useState(args.selectedDropdownOption);
|
|
49
46
|
const [searchItems, setSearchItems] = useState([]);
|
|
50
47
|
const [toggleStatus, setToggleStatus] = useState(false);
|
|
51
|
-
const [minValue, setMinValue] = useState();
|
|
52
|
-
const [maxValue, setMaxValue] = useState();
|
|
48
|
+
const [minValue, setMinValue] = useState(undefined);
|
|
49
|
+
const [maxValue, setMaxValue] = useState(undefined);
|
|
53
50
|
const [selectedValue, setSelectedValue] = useState(args.selectedValue || []);
|
|
54
51
|
// NEW: State for date control
|
|
55
52
|
const [selectedDate, setSelectedDate] = useState(args.selectedDate);
|
|
56
53
|
const [selectedStartDate, setSelectedStartDate] = useState(args.selectedStartDate);
|
|
57
54
|
const [selectedEndDate, setSelectedEndDate] = useState(args.selectedEndDate);
|
|
55
|
+
// NEW: State for searchCriteria and editingHeader
|
|
56
|
+
const [searchCriteria, setSearchCriteria] = useState([]);
|
|
57
|
+
const [editingHeader, setEditingHeader] = useState(null);
|
|
58
58
|
// Handle onChange from the multi-select
|
|
59
59
|
const handleOnChange = (newSelected) => {
|
|
60
60
|
setSelectedValue(newSelected);
|
|
61
|
-
// Call the original onChange if provided in the story args
|
|
62
61
|
args.onChange?.(newSelected);
|
|
63
62
|
console.log("Selected items:", newSelected);
|
|
64
63
|
};
|
|
65
|
-
return (_jsx(SearchInput, { ...args, selectedDropdownOption: selectedOption, onDropdownOptionSelect: (option) => setSelectedOption(option), searchItems: searchItems, setSearchItems: setSearchItems, toggleStatus: toggleStatus, setToggleStatus: setToggleStatus, minValue: minValue, maxValue: maxValue, setMinValue: setMinValue, setMaxValue: setMaxValue, onChange: handleOnChange, selectedValue: selectedValue, selectedDate: selectedDate, onDateSelect: setSelectedDate, selectedStartDate: selectedStartDate, onStartDateSelect: setSelectedStartDate, selectedEndDate: selectedEndDate, onEndDateSelect: setSelectedEndDate
|
|
64
|
+
return (_jsx(SearchInput, { ...args, column: mockColumn, selectedDropdownOption: selectedOption, onDropdownOptionSelect: (option) => setSelectedOption(option), searchItems: searchItems, setSearchItems: setSearchItems, toggleStatus: toggleStatus, setToggleStatus: setToggleStatus, minValue: minValue, maxValue: maxValue, setMinValue: setMinValue, setMaxValue: setMaxValue, onChange: handleOnChange, selectedValue: selectedValue, selectedDate: selectedDate, onDateSelect: setSelectedDate, selectedStartDate: selectedStartDate, onStartDateSelect: setSelectedStartDate, selectedEndDate: selectedEndDate, onEndDateSelect: setSelectedEndDate, setSearchCriteria: setSearchCriteria, setEditingHeader: setEditingHeader,
|
|
65
|
+
// Optionally pass in handleFilter, or use the default from args
|
|
66
|
+
handleFilter: args.handleFilter }));
|
|
66
67
|
};
|
|
67
68
|
export const Default = Template.bind({});
|
|
68
69
|
Default.args = {
|
|
69
70
|
inputType: "text",
|
|
70
|
-
handleFilter: () => console.log(
|
|
71
|
+
handleFilter: () => console.log("Filter applied"),
|
|
71
72
|
dropdownOptions: [
|
|
72
73
|
"Starts with",
|
|
73
74
|
"Ends with",
|
|
@@ -80,7 +81,7 @@ Default.args = {
|
|
|
80
81
|
export const TextInput = Template.bind({});
|
|
81
82
|
TextInput.args = {
|
|
82
83
|
inputType: "text",
|
|
83
|
-
handleFilter: () => console.log(
|
|
84
|
+
handleFilter: () => console.log("Filter applied"),
|
|
84
85
|
pillColor: "bg-sky-500",
|
|
85
86
|
textHighlight: "text-sky-500",
|
|
86
87
|
dropdownIconProp: {
|
|
@@ -100,7 +101,7 @@ TextInput.args = {
|
|
|
100
101
|
export const NumberInput = Template.bind({});
|
|
101
102
|
NumberInput.args = {
|
|
102
103
|
inputType: "number",
|
|
103
|
-
handleFilter: () => console.log(
|
|
104
|
+
handleFilter: () => console.log("Filter applied"),
|
|
104
105
|
dropdownIconProp: {
|
|
105
106
|
iconClasses: "text-sky-500",
|
|
106
107
|
name: "chevronDown",
|
|
@@ -112,7 +113,7 @@ NumberInput.args = {
|
|
|
112
113
|
export const DropdownInput = Template.bind({});
|
|
113
114
|
DropdownInput.args = {
|
|
114
115
|
inputType: "multiSelect",
|
|
115
|
-
handleFilter: () => console.log(
|
|
116
|
+
handleFilter: () => console.log("Filter applied"),
|
|
116
117
|
placeholder: "Search",
|
|
117
118
|
dropdownOptions: [
|
|
118
119
|
{ uuid: "1", name: "Option 1", value: "option1" },
|
|
@@ -129,7 +130,7 @@ DropdownInput.args = {
|
|
|
129
130
|
export const BooleanInput = Template.bind({});
|
|
130
131
|
BooleanInput.args = {
|
|
131
132
|
inputType: "multiSelect",
|
|
132
|
-
handleFilter: () => console.log(
|
|
133
|
+
handleFilter: () => console.log("Filter applied"),
|
|
133
134
|
placeholder: "Search",
|
|
134
135
|
dropdownOptions: [
|
|
135
136
|
{ uuid: "1", name: "True", value: "true" },
|
|
@@ -145,7 +146,7 @@ BooleanInput.args = {
|
|
|
145
146
|
export const DatePickerInput = Template.bind({});
|
|
146
147
|
DatePickerInput.args = {
|
|
147
148
|
inputType: "date",
|
|
148
|
-
handleFilter: () => console.log(
|
|
149
|
+
handleFilter: () => console.log("Filter applied"),
|
|
149
150
|
textHighlight: "text-sky-500",
|
|
150
151
|
dropdownOptions: ["Exactly", "Before", "After"],
|
|
151
152
|
selectedDropdownOption: "Exactly",
|
|
@@ -10,9 +10,10 @@ type SearchTextInputProps<T extends object> = {
|
|
|
10
10
|
searchItems?: string[];
|
|
11
11
|
setSearchItems?: React.Dispatch<React.SetStateAction<string[]>>;
|
|
12
12
|
handleFilter?: () => void;
|
|
13
|
-
setSearchCriteria: any
|
|
13
|
+
setSearchCriteria: React.Dispatch<React.SetStateAction<any[]>>;
|
|
14
14
|
column: any;
|
|
15
|
-
setEditingHeader: any
|
|
15
|
+
setEditingHeader: React.Dispatch<React.SetStateAction<any>>;
|
|
16
|
+
localStorageKey?: string;
|
|
16
17
|
};
|
|
17
|
-
declare const SearchTextInput: <T extends object>({ pillColor, textHighlight, dropdownIconProp, dropdownOptions, selectedDropdownOption, onDropdownOptionSelect, searchItems, setSearchItems, handleFilter, setSearchCriteria, column, setEditingHeader, }: SearchTextInputProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
declare const SearchTextInput: <T extends object>({ pillColor, textHighlight, dropdownIconProp, dropdownOptions, selectedDropdownOption, onDropdownOptionSelect, searchItems, setSearchItems, handleFilter, setSearchCriteria, column, setEditingHeader, localStorageKey, }: SearchTextInputProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
18
19
|
export default SearchTextInput;
|
|
@@ -10,67 +10,81 @@ const SearchTextInput = ({ pillColor = "bg-sky-500", textHighlight = "text-sky-5
|
|
|
10
10
|
iconClasses: textHighlight,
|
|
11
11
|
name: "chevronDown",
|
|
12
12
|
weight: "solid",
|
|
13
|
-
}, dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, searchItems = [], setSearchItems, handleFilter, setSearchCriteria, column, setEditingHeader, }) => {
|
|
13
|
+
}, dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, searchItems = [], setSearchItems, handleFilter, setSearchCriteria, column, setEditingHeader, localStorageKey = "searchCriteria", }) => {
|
|
14
14
|
const containerRef = useRef(null);
|
|
15
15
|
const [localSearchText, setLocalSearchText] = useState("");
|
|
16
16
|
const inputRef = useRef(null);
|
|
17
|
-
// Focus
|
|
17
|
+
// Focus on mount and load persisted search criteria for this column.
|
|
18
18
|
useEffect(() => {
|
|
19
19
|
inputRef.current?.focus();
|
|
20
|
-
|
|
20
|
+
const stored = localStorage.getItem(localStorageKey);
|
|
21
|
+
if (stored) {
|
|
22
|
+
try {
|
|
23
|
+
const parsed = JSON.parse(stored);
|
|
24
|
+
const existing = parsed.find((criterion) => criterion.searchColumn.id === column.id);
|
|
25
|
+
if (existing) {
|
|
26
|
+
setLocalSearchText(existing.submittedSearchText);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error("Error parsing stored search criteria:", error);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}, [column.id, localStorageKey]);
|
|
34
|
+
const updateLocalStorage = (criteria) => {
|
|
35
|
+
localStorage.setItem(localStorageKey, JSON.stringify(criteria));
|
|
36
|
+
};
|
|
21
37
|
const handleInputChange = (event) => {
|
|
22
38
|
setLocalSearchText(event.target.value);
|
|
23
39
|
};
|
|
24
40
|
const handleSearchBadgeClick = (item) => {
|
|
25
|
-
// Remove criterion
|
|
26
41
|
const filteredItems = searchItems.filter((ele) => ele !== item);
|
|
27
|
-
setSearchItems(filteredItems);
|
|
42
|
+
setSearchItems && setSearchItems(filteredItems);
|
|
28
43
|
};
|
|
29
44
|
const handleKeyDown = (e) => {
|
|
30
45
|
if (e.key === "Enter" && localSearchText.length > 0) {
|
|
31
46
|
e.preventDefault();
|
|
32
|
-
setSearchItems([...searchItems, localSearchText]);
|
|
33
|
-
|
|
34
|
-
handleFilter();
|
|
47
|
+
setSearchItems && setSearchItems([...searchItems, localSearchText]);
|
|
48
|
+
handleFilter && handleFilter();
|
|
35
49
|
handleSubmit();
|
|
36
50
|
}
|
|
37
51
|
};
|
|
38
52
|
const handleSubmit = () => {
|
|
39
53
|
const trimmed = localSearchText.trim();
|
|
40
54
|
if (!trimmed) {
|
|
41
|
-
setSearchCriteria((prev) =>
|
|
55
|
+
setSearchCriteria((prev) => {
|
|
56
|
+
const updated = prev.filter((c) => c.searchColumn.id !== column.id);
|
|
57
|
+
updateLocalStorage(updated);
|
|
58
|
+
return updated;
|
|
59
|
+
});
|
|
42
60
|
}
|
|
43
61
|
else {
|
|
44
62
|
setSearchCriteria((prev) => {
|
|
45
63
|
const existingIndex = prev.findIndex((c) => c.searchColumn.id === column.id);
|
|
64
|
+
let updated;
|
|
46
65
|
if (existingIndex >= 0) {
|
|
47
|
-
|
|
48
|
-
|
|
66
|
+
updated = [...prev];
|
|
67
|
+
updated[existingIndex] = {
|
|
49
68
|
searchColumn: column,
|
|
50
69
|
submittedSearchText: trimmed,
|
|
51
70
|
};
|
|
52
|
-
return clone;
|
|
53
71
|
}
|
|
54
72
|
else {
|
|
55
|
-
|
|
73
|
+
updated = [
|
|
56
74
|
...prev,
|
|
57
|
-
{
|
|
58
|
-
searchColumn: column,
|
|
59
|
-
submittedSearchText: trimmed,
|
|
60
|
-
},
|
|
75
|
+
{ searchColumn: column, submittedSearchText: trimmed },
|
|
61
76
|
];
|
|
62
77
|
}
|
|
78
|
+
updateLocalStorage(updated);
|
|
79
|
+
return updated;
|
|
63
80
|
});
|
|
64
81
|
}
|
|
65
82
|
setEditingHeader(null);
|
|
66
83
|
};
|
|
67
|
-
|
|
68
|
-
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 ${searchItems.length ? "border-b-2" : ""} 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, { 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", children: [_jsx("div", { className: "bg-navy-50 pr-2 pl-1 text-gray-500", onClick: () => {
|
|
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 ${searchItems.length ? "border-b-2" : ""} 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, { 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", children: [_jsx("div", { className: "bg-navy-50 pr-2 pl-1 text-gray-500", onClick: () => {
|
|
69
85
|
setLocalSearchText("");
|
|
70
86
|
}, "data-testid": "clear-icon", children: getFontAwesomeIcon("xmark", "regular") }), _jsx("div", { className: `${textHighlight} text-sm hover:text-primary`, children: getFontAwesomeIcon("search", "solid") })] })) }) }), onIconClick: () => {
|
|
71
87
|
setLocalSearchText("");
|
|
72
|
-
} })] }), searchItems?.length ? (_jsx("div", { className: "
|
|
73
|
-
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: () => handleSearchBadgeClick(item), text: _jsx(Text, { color: "text-white", fontFamily: "font-serif", size: "text-sm", tag: "span", text: item }), badgeContainerClasses: pillClassnames, type: "span" }));
|
|
74
|
-
}) })) : null] }) }));
|
|
88
|
+
} })] }), searchItems?.length ? (_jsx("div", { className: "flex flex-wrap bg-white py-2 px-2 rounded-md", children: searchItems.map((item, 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: item, onClick: () => handleSearchBadgeClick(item), text: _jsx(Text, { color: "text-white", fontFamily: "font-serif", size: "text-sm", tag: "span", text: item }), badgeContainerClasses: `${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`, type: "span" }, index))) })) : null] }) }));
|
|
75
89
|
};
|
|
76
90
|
export default SearchTextInput;
|