@agilant/toga-blox 1.0.60 → 1.0.61

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
- // Mock data for column
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(`Filter applied`),
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(`Filter applied`),
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(`Filter applied`),
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(`Filter applied`),
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(`Filter applied`),
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(`Filter applied`),
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,49 +10,69 @@ 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 the input when editing starts (if needed)
17
+ // On mount, load any persisted search criteria from local storage using the provided key
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
+ // Helper to update local storage using the dynamic key
35
+ const updateLocalStorage = (criteria) => {
36
+ localStorage.setItem(localStorageKey, JSON.stringify(criteria));
37
+ };
21
38
  const handleInputChange = (event) => {
22
39
  setLocalSearchText(event.target.value);
23
40
  };
24
41
  const handleSearchBadgeClick = (item) => {
25
42
  // Remove criterion
26
43
  const filteredItems = searchItems.filter((ele) => ele !== item);
27
- setSearchItems(filteredItems);
44
+ setSearchItems && setSearchItems(filteredItems);
28
45
  };
29
46
  const handleKeyDown = (e) => {
30
47
  if (e.key === "Enter" && localSearchText.length > 0) {
31
48
  e.preventDefault();
32
- setSearchItems([...searchItems, localSearchText]);
33
- setLocalSearchText("");
34
- handleFilter();
49
+ setSearchItems && setSearchItems([...searchItems, localSearchText]);
50
+ handleFilter && handleFilter();
35
51
  handleSubmit();
36
52
  }
37
53
  };
38
54
  const handleSubmit = () => {
39
55
  const trimmed = localSearchText.trim();
40
56
  if (!trimmed) {
41
- setSearchCriteria((prev) => prev.filter((c) => c.searchColumn.id !== column.id));
57
+ setSearchCriteria((prev) => {
58
+ const updated = prev.filter((c) => c.searchColumn.id !== column.id);
59
+ updateLocalStorage(updated);
60
+ return updated;
61
+ });
42
62
  }
43
63
  else {
44
64
  setSearchCriteria((prev) => {
45
65
  const existingIndex = prev.findIndex((c) => c.searchColumn.id === column.id);
66
+ let updated;
46
67
  if (existingIndex >= 0) {
47
- const clone = [...prev];
48
- clone[existingIndex] = {
68
+ updated = [...prev];
69
+ updated[existingIndex] = {
49
70
  searchColumn: column,
50
71
  submittedSearchText: trimmed,
51
72
  };
52
- return clone;
53
73
  }
54
74
  else {
55
- return [
75
+ updated = [
56
76
  ...prev,
57
77
  {
58
78
  searchColumn: column,
@@ -60,17 +80,16 @@ const SearchTextInput = ({ pillColor = "bg-sky-500", textHighlight = "text-sky-5
60
80
  },
61
81
  ];
62
82
  }
83
+ updateLocalStorage(updated);
84
+ return updated;
63
85
  });
64
86
  }
65
87
  setEditingHeader(null);
66
88
  };
67
- 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`;
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: () => {
89
+ 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
90
  setLocalSearchText("");
70
91
  }, "data-testid": "clear-icon", children: getFontAwesomeIcon("xmark", "regular") }), _jsx("div", { className: `${textHighlight} text-sm hover:text-primary`, children: getFontAwesomeIcon("search", "solid") })] })) }) }), onIconClick: () => {
71
92
  setLocalSearchText("");
72
- } })] }), searchItems?.length ? (_jsx("div", { className: " flex flex-wrap bg-white py-2 px-2 rounded-md ", children: searchItems?.map((item, index) => {
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] }) }));
93
+ } })] }), 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
94
  };
76
95
  export default SearchTextInput;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agilant/toga-blox",
3
3
  "private": false,
4
- "version": "1.0.60",
4
+ "version": "1.0.61",
5
5
  "description": "",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",