@agilant/toga-blox 1.0.47 → 1.0.48
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/Dropdown/Dropdown.js +1 -1
- package/dist/components/MagnifyingIcon/MagnifyingIcon.js +1 -1
- package/dist/components/MagnifyingIcon/MagnifyingIcon.stories.js +1 -0
- package/dist/components/SearchInput/SearchDropdownInput.d.ts +1 -0
- package/dist/components/SearchInput/SearchDropdownInput.js +2 -3
- package/dist/components/SearchInput/SearchInput.d.ts +1 -1
- package/dist/components/SearchInput/SearchInput.js +9 -51
- package/dist/components/SearchInput/SearchInput.stories.d.ts +1 -1
- package/dist/components/SearchInput/SearchInput.stories.js +32 -53
- package/dist/components/SearchInput/SearchInput.test.d.ts +1 -0
- package/dist/components/SearchInput/SearchInput.test.js +519 -0
- package/dist/components/SearchInput/SearchInput.types.d.ts +8 -12
- package/dist/components/SearchInput/SearchInputDatePicker.d.ts +23 -0
- package/dist/components/SearchInput/SearchInputDatePicker.js +72 -0
- package/dist/components/SearchInput/SearchNumberInput.d.ts +2 -14
- package/dist/components/SearchInput/SearchNumberInput.js +16 -35
- package/dist/components/SearchInput/SearchTextInput.d.ts +2 -11
- package/dist/components/SearchInput/SearchTextInput.js +5 -24
- package/package.json +2 -1
|
@@ -9,7 +9,7 @@ const Dropdown = ({ options, selectedOption, onOptionSelect, optionClasses = "fl
|
|
|
9
9
|
}, selectedOptionBgColor = "bg-gray-50", optionHoverBgColor = "hover:bg-gray-50", }) => {
|
|
10
10
|
const [showMenu, setShowMenu] = useState(false);
|
|
11
11
|
const toggleMenu = () => setShowMenu(!showMenu);
|
|
12
|
-
return (_jsxs("div", { className: `flex items-center justify-between relative min-w-32
|
|
12
|
+
return (_jsxs("div", { className: `flex items-center justify-between relative min-w-32 ${dropdownClasses}`, children: [_jsxs("div", { onClick: toggleMenu, className: `flex cursor-pointer items-center group h-full `, children: [_jsx("div", { className: `font-bold ${optionClasses}`, children: selectedOption }), _jsx("div", { className: `transform transition-transform duration-200 mx-1 px-1 rounded-full relative ${icon.iconClasses} ${showMenu ? "rotate-180" : "rotate-0"}`, "data-testid": "dropdown-icon", children: getFontAwesomeIcon(icon.name) })] }), showMenu && (_jsx(AnimatePresence, { children: showMenu && (_jsx(motion.div, { initial: { opacity: 0, y: -10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -10 }, className: `absolute top-0 z-10 right-0 left-0 ${menuClasses}`, children: _jsx("ul", { children: options.map((action) => (_jsxs("li", { className: `text-left px-4 py-2 cursor-pointer border-b ${action === selectedOption
|
|
13
13
|
? `{${selectedOptionBgColor} font-semibold}`
|
|
14
14
|
: `${optionHoverBgColor} text-black`}`, onClick: () => {
|
|
15
15
|
onOptionSelect(action);
|
|
@@ -53,6 +53,6 @@ const MagnifyingIcon = forwardRef(({ columnIndex, editingHeader, setEditingHeade
|
|
|
53
53
|
};
|
|
54
54
|
return (_jsx("div", { ref: ref, "data-testid": "magnifying-icon-test-id", className: `flex items-center cursor-pointer size-[18px] rounded relative ml-1 ${iconColor} ${showActiveStyles
|
|
55
55
|
? `${iconActiveBackgroundColor} hover:bg-blue-500 still-active`
|
|
56
|
-
: "hover:bg-white"}`, onClick: handleClick, children: _jsx("div", { className: `text-xs w-full ${additionalIconClasses}
|
|
56
|
+
: "hover:bg-white"}`, onClick: handleClick, children: _jsx("div", { className: `text-xs w-full ${additionalIconClasses} `, children: getFontAwesomeIcon("magnifyingGlass", "solid") }) }));
|
|
57
57
|
});
|
|
58
58
|
export default MagnifyingIcon;
|
|
@@ -5,7 +5,7 @@ import "./SearchDrowpdown.scss";
|
|
|
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.
|
|
7
7
|
*/
|
|
8
|
-
const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, placeholder = "Select
|
|
8
|
+
const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, placeholder = "Select", disabled = false, hasSelectAll = true, bgColor, textHighlight, handleFilter, ...rest }) => {
|
|
9
9
|
const footerOption = [{ name: "", value: "__footer__" }];
|
|
10
10
|
const extendedOptions = [...options, ...footerOption];
|
|
11
11
|
const itemRenderer = ({ option, checked, disabled, onClick }) => {
|
|
@@ -16,8 +16,7 @@ const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, place
|
|
|
16
16
|
onChange([]); // Clear all selections
|
|
17
17
|
}, children: "Clear" }), _jsx("button", { type: "button", className: `${bgColor} text-white px-3 py-1 rounded`, onClick: (e) => {
|
|
18
18
|
e.stopPropagation();
|
|
19
|
-
|
|
20
|
-
// ...your custom filter logic
|
|
19
|
+
handleFilter();
|
|
21
20
|
}, children: "Filter" })] }));
|
|
22
21
|
}
|
|
23
22
|
else if (option.label === "Select All") {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { SearchInputProps } from "./SearchInput.types";
|
|
2
|
-
declare const SearchInput: <T extends object>({
|
|
2
|
+
declare const SearchInput: <T extends object>({ bgColor, textHighlight, inputType, dropdownIconProp, dropdownOptions, selectedDropdownOption, onDropdownOptionSelect, searchItems, setSearchItems, toggleStatus, setToggleStatus, minValue, setMinValue, maxValue, setMaxValue, onChange, selectedValue, selectedDate, onDateSelect, selectedStartDate, onStartDateSelect, selectedEndDate, onEndDateSelect, handleFilter, }: SearchInputProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
3
3
|
export default SearchInput;
|
|
@@ -1,71 +1,29 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import { useEffect, useRef
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
3
|
import SearchTextInput from "./SearchTextInput";
|
|
4
4
|
import SearchNumberInput from "./SearchNumberInput";
|
|
5
|
-
import { Controller } from "react-hook-form";
|
|
6
5
|
import SearchDropdownInput from "./SearchDropdownInput";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (typeof dynamicDefaultValue !== "undefined") {
|
|
10
|
-
return dynamicDefaultValue;
|
|
11
|
-
}
|
|
12
|
-
return "";
|
|
13
|
-
}
|
|
14
|
-
const SearchInput = ({ closeOutSearch, setResetSearch, setEditingHeader, bgColor = "bg-sky-500", textHighlight = "text-sky-500", column, inputType = "text", dropdownIconProp = {
|
|
6
|
+
import SearchDatePickerInput from "./SearchInputDatePicker";
|
|
7
|
+
const SearchInput = ({ bgColor = "bg-sky-500", textHighlight = "text-sky-500", inputType = "text", dropdownIconProp = {
|
|
15
8
|
name: "chevronDown",
|
|
16
9
|
weight: "bold",
|
|
17
10
|
iconClasses: "text-black",
|
|
18
|
-
}, dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, searchItems = [], setSearchItems, toggleStatus = false, setToggleStatus, minValue, setMinValue, maxValue, setMaxValue,
|
|
11
|
+
}, dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, searchItems = [], setSearchItems, toggleStatus = false, setToggleStatus, minValue, setMinValue, maxValue, setMaxValue, onChange, selectedValue, selectedDate, onDateSelect, selectedStartDate, onStartDateSelect, selectedEndDate, onEndDateSelect, handleFilter, }) => {
|
|
19
12
|
const containerRef = useRef(null);
|
|
20
|
-
const [localSearchText, setLocalSearchText] = useState("");
|
|
21
13
|
const inputRef = useRef(null);
|
|
22
14
|
useEffect(() => {
|
|
23
15
|
inputRef.current?.focus();
|
|
24
16
|
}, []);
|
|
25
|
-
const handleInputChange = (event) => {
|
|
26
|
-
setLocalSearchText(event.target.value);
|
|
27
|
-
};
|
|
28
|
-
const handleSubmitClick = () => {
|
|
29
|
-
const trimmedSearchText = localSearchText.trim();
|
|
30
|
-
let safeHeader;
|
|
31
|
-
if (typeof column.Header === "string") {
|
|
32
|
-
safeHeader = column.Header;
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
safeHeader = column.accessor || "Unnamed Column";
|
|
36
|
-
}
|
|
37
|
-
if (trimmedSearchText === "") {
|
|
38
|
-
// Remove criterion if text is empty
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
// Update or add criterion
|
|
42
|
-
}
|
|
43
|
-
setEditingHeader(null);
|
|
44
|
-
};
|
|
45
17
|
return (_jsx("div", { ref: containerRef, className: "", children: (() => {
|
|
46
18
|
switch (inputType) {
|
|
47
19
|
case "text":
|
|
48
|
-
return (_jsx(SearchTextInput, {
|
|
20
|
+
return (_jsx(SearchTextInput, { dropdownIconProp: dropdownIconProp, dropdownOptions: dropdownOptions, selectedDropdownOption: selectedDropdownOption, onDropdownOptionSelect: onDropdownOptionSelect, searchItems: searchItems, setSearchItems: setSearchItems, handleFilter: handleFilter }));
|
|
49
21
|
case "number":
|
|
50
|
-
return (_jsx(SearchNumberInput, {
|
|
22
|
+
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 }));
|
|
51
23
|
case "multiSelect":
|
|
52
|
-
{
|
|
53
|
-
console.log(dropdownOptions, "dropdownOptions");
|
|
54
|
-
}
|
|
55
|
-
return (_jsx(SearchDropdownInput, { options: dropdownOptions, isSearchable: true, placeholder: "Search", isMulti: true, hideSelectedOptions: true, closeMenuOnSelect: false, inputWidth: "w-full", inputTextSize: "text-sm", additionalClasses: "", customClassNames: {}, onChange: onChange, value: [], selectedValue: selectedValue, bgColor: bgColor, textHighlight: textHighlight }));
|
|
56
|
-
case "boolean":
|
|
24
|
+
return (_jsx(SearchDropdownInput, { options: dropdownOptions, isSearchable: true, placeholder: "Search", isMulti: true, hideSelectedOptions: true, closeMenuOnSelect: false, inputWidth: "w-full", inputTextSize: "text-sm", additionalClasses: "", customClassNames: {}, onChange: onChange, value: [], selectedValue: selectedValue, bgColor: bgColor, textHighlight: textHighlight, handleFilter: handleFilter }));
|
|
57
25
|
case "date":
|
|
58
|
-
|
|
59
|
-
if (!control || !valueKey) {
|
|
60
|
-
return (_jsxs("div", { className: "text-red-500", children: ["Missing ", _jsx("code", { children: "control" }), " or", " ", _jsx("code", { children: "valueKey" }), " prop for React Hook Form"] }));
|
|
61
|
-
}
|
|
62
|
-
return (_jsx(Controller, { name: valueKey, control: control, defaultValue: getDefaultValue(dynamicDefaultValue, valueKey), render: ({ field }) => (_jsx("div", { className: "inline-flex items-center", children: _jsxs("label", { className: "flex items-center cursor-pointer relative", children: [_jsx("input", { type: "checkbox", className: "peer h-5 w-5 cursor-pointer transition-all appearance-none rounded border border-stroke", id: valueKey, checked: !!field.value, onChange: (e) => {
|
|
63
|
-
// You can log the value here:
|
|
64
|
-
console.log("Checkbox changed to:", e.target.checked);
|
|
65
|
-
field.onChange(e.target.checked);
|
|
66
|
-
} }), _jsx("span", { className: "absolute text-white opacity-0 peer-checked:opacity-100 top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2", children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-3.5 w-3.5", viewBox: "0 0 20 20", fill: "currentColor", stroke: "currentColor", strokeWidth: "1", children: _jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) })] }) })) }));
|
|
67
|
-
default:
|
|
68
|
-
return null;
|
|
26
|
+
return (_jsx(SearchDatePickerInput, { textHighlight: textHighlight, dropdownOptions: dropdownOptions, selectedDropdownOption: selectedDropdownOption, onDropdownOptionSelect: onDropdownOptionSelect, toggleStatus: toggleStatus, setToggleStatus: setToggleStatus, selectedDate: selectedDate, onDateSelect: onDateSelect, selectedStartDate: selectedStartDate, onStartDateSelect: onStartDateSelect, selectedEndDate: selectedEndDate, onEndDateSelect: onEndDateSelect, handleFilter: handleFilter }));
|
|
69
27
|
}
|
|
70
28
|
})() }));
|
|
71
29
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import SearchInput from "./SearchInput";
|
|
3
|
-
import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
|
|
4
3
|
import { useState } from "react";
|
|
5
4
|
export default {
|
|
6
5
|
title: "Components/SearchInput",
|
|
@@ -13,10 +12,6 @@ export default {
|
|
|
13
12
|
options: ["text", "number", "boolean", "date", "multiSelect"],
|
|
14
13
|
},
|
|
15
14
|
},
|
|
16
|
-
closeOutSearch: { control: "none", table: { disable: true } },
|
|
17
|
-
setResetSearch: { control: "none", table: { disable: true } },
|
|
18
|
-
column: { control: "none", table: { disable: true } },
|
|
19
|
-
setEditingHeader: { control: "none", table: { disable: true } },
|
|
20
15
|
dropdownIconProp: {
|
|
21
16
|
control: "object",
|
|
22
17
|
description: "Icon configuration for dropdown",
|
|
@@ -56,6 +51,10 @@ const Template = (args) => {
|
|
|
56
51
|
const [minValue, setMinValue] = useState();
|
|
57
52
|
const [maxValue, setMaxValue] = useState();
|
|
58
53
|
const [selectedValue, setSelectedValue] = useState(args.selectedValue || []);
|
|
54
|
+
// NEW: State for date control
|
|
55
|
+
const [selectedDate, setSelectedDate] = useState(args.selectedDate);
|
|
56
|
+
const [selectedStartDate, setSelectedStartDate] = useState(args.selectedStartDate);
|
|
57
|
+
const [selectedEndDate, setSelectedEndDate] = useState(args.selectedEndDate);
|
|
59
58
|
// Handle onChange from the multi-select
|
|
60
59
|
const handleOnChange = (newSelected) => {
|
|
61
60
|
setSelectedValue(newSelected);
|
|
@@ -63,23 +62,25 @@ const Template = (args) => {
|
|
|
63
62
|
args.onChange?.(newSelected);
|
|
64
63
|
console.log("Selected items:", newSelected);
|
|
65
64
|
};
|
|
66
|
-
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 }));
|
|
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 }));
|
|
67
66
|
};
|
|
68
67
|
export const Default = Template.bind({});
|
|
69
68
|
Default.args = {
|
|
70
69
|
inputType: "text",
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
handleFilter: () => console.log(`Filter applied`),
|
|
71
|
+
dropdownOptions: [
|
|
72
|
+
"Starts with",
|
|
73
|
+
"Ends with",
|
|
74
|
+
"Exactly",
|
|
75
|
+
"Includes",
|
|
76
|
+
"Excludes",
|
|
77
|
+
],
|
|
78
|
+
selectedDropdownOption: "Starts with",
|
|
75
79
|
};
|
|
76
80
|
export const TextInput = Template.bind({});
|
|
77
81
|
TextInput.args = {
|
|
78
82
|
inputType: "text",
|
|
79
|
-
|
|
80
|
-
closeOutSearch: (value) => console.log(`Search cleared: ${value}`),
|
|
81
|
-
setResetSearch: () => console.log("Reset search triggered"),
|
|
82
|
-
setEditingHeader: (value) => console.log(`Editing header: ${value}`),
|
|
83
|
+
handleFilter: () => console.log(`Filter applied`),
|
|
83
84
|
pillColor: "bg-sky-500",
|
|
84
85
|
textHighlight: "text-sky-500",
|
|
85
86
|
dropdownIconProp: {
|
|
@@ -99,10 +100,7 @@ TextInput.args = {
|
|
|
99
100
|
export const NumberInput = Template.bind({});
|
|
100
101
|
NumberInput.args = {
|
|
101
102
|
inputType: "number",
|
|
102
|
-
|
|
103
|
-
closeOutSearch: (value) => console.log(`Search cleared: ${value}`),
|
|
104
|
-
setResetSearch: () => console.log("Reset search triggered"),
|
|
105
|
-
setEditingHeader: (value) => console.log(`Editing header: ${value}`),
|
|
103
|
+
handleFilter: () => console.log(`Filter applied`),
|
|
106
104
|
dropdownIconProp: {
|
|
107
105
|
iconClasses: "text-sky-500",
|
|
108
106
|
name: "chevronDown",
|
|
@@ -114,67 +112,48 @@ NumberInput.args = {
|
|
|
114
112
|
export const DropdownInput = Template.bind({});
|
|
115
113
|
DropdownInput.args = {
|
|
116
114
|
inputType: "multiSelect",
|
|
117
|
-
|
|
118
|
-
closeOutSearch: (value) => console.log(`Search cleared: ${value}`),
|
|
119
|
-
setResetSearch: () => console.log("Reset search triggered"),
|
|
120
|
-
setEditingHeader: (value) => console.log(`Editing header: ${value}`),
|
|
115
|
+
handleFilter: () => console.log(`Filter applied`),
|
|
121
116
|
placeholder: "Search",
|
|
122
117
|
dropdownOptions: [
|
|
123
118
|
{ uuid: "1", name: "Option 1", value: "option1" },
|
|
124
119
|
{ uuid: "2", name: "Option 2", value: "option2" },
|
|
125
120
|
{ uuid: "3", name: "Option 3", value: "option3" },
|
|
126
121
|
],
|
|
127
|
-
/** For multi-select, `value` is typically an array */
|
|
128
122
|
selectedValue: [],
|
|
129
|
-
// onChange: (selected: OptionType[]) => {
|
|
130
|
-
// console.log("Selected items:", selected);
|
|
131
|
-
// },
|
|
132
|
-
/** Additional props you might want to set */
|
|
133
123
|
isSearchable: true,
|
|
134
124
|
hasSelectAll: true,
|
|
135
125
|
disabled: false,
|
|
136
126
|
isLoading: false,
|
|
137
127
|
type: "multiSelect",
|
|
138
|
-
// etc...
|
|
139
128
|
};
|
|
140
129
|
export const BooleanInput = Template.bind({});
|
|
141
130
|
BooleanInput.args = {
|
|
142
131
|
inputType: "multiSelect",
|
|
143
|
-
|
|
144
|
-
closeOutSearch: (value) => console.log(`Search cleared: ${value}`),
|
|
145
|
-
setResetSearch: () => console.log("Reset search triggered"),
|
|
146
|
-
setEditingHeader: (value) => console.log(`Editing header: ${value}`),
|
|
132
|
+
handleFilter: () => console.log(`Filter applied`),
|
|
147
133
|
placeholder: "Search",
|
|
148
134
|
dropdownOptions: [
|
|
149
135
|
{ uuid: "1", name: "True", value: "true" },
|
|
150
136
|
{ uuid: "2", name: "False", value: "false" },
|
|
151
137
|
],
|
|
152
138
|
selectedValue: [],
|
|
153
|
-
// onChange: (selected: OptionType[]) => {
|
|
154
|
-
// console.log("Selected items:", selected);
|
|
155
|
-
// },
|
|
156
139
|
isSearchable: true,
|
|
157
140
|
hasSelectAll: true,
|
|
158
141
|
disabled: false,
|
|
159
142
|
isLoading: false,
|
|
160
143
|
type: "multiSelect",
|
|
161
|
-
// etc...
|
|
162
144
|
};
|
|
163
|
-
export const
|
|
164
|
-
|
|
165
|
-
inputType: "
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
buttonIconClasses: "text-gray-400",
|
|
178
|
-
containerClasses: "flex items-center",
|
|
179
|
-
onButtonClick: () => alert("Button is disabled."),
|
|
145
|
+
export const DatePickerInput = Template.bind({});
|
|
146
|
+
DatePickerInput.args = {
|
|
147
|
+
inputType: "date",
|
|
148
|
+
handleFilter: () => console.log(`Filter applied`),
|
|
149
|
+
textHighlight: "text-sky-500",
|
|
150
|
+
dropdownOptions: ["Exactly", "Before", "After"],
|
|
151
|
+
selectedDropdownOption: "Exactly",
|
|
152
|
+
onDropdownOptionSelect: (option) => console.log(`Option selected: ${option}`),
|
|
153
|
+
searchItems: [],
|
|
154
|
+
setSearchItems: () => { },
|
|
155
|
+
toggleStatus: false,
|
|
156
|
+
setToggleStatus: () => { },
|
|
157
|
+
themeBgColor: "bg-sky-500",
|
|
158
|
+
lightThemeBg: "bg-sky-100",
|
|
180
159
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { render, screen, fireEvent } from "@testing-library/react";
|
|
3
|
+
import { describe, expect, test, vi } from "vitest";
|
|
4
|
+
import SearchInput from "./SearchInput";
|
|
5
|
+
const mockOnDropdownOptionSelect = vi.fn();
|
|
6
|
+
const mockSetSearchItems = vi.fn();
|
|
7
|
+
const mockSetToggleStatus = vi.fn();
|
|
8
|
+
const mockSetMinValue = vi.fn();
|
|
9
|
+
const mockSetMaxValue = vi.fn();
|
|
10
|
+
const mockOnDateSelect = vi.fn();
|
|
11
|
+
const mockOnStartDateSelect = vi.fn();
|
|
12
|
+
const mockOnEndDateSelect = vi.fn();
|
|
13
|
+
const mockOnChange = vi.fn();
|
|
14
|
+
const mockHandleIconClick = vi.fn();
|
|
15
|
+
const mockHandleFilter = vi.fn();
|
|
16
|
+
const defaultProps = {
|
|
17
|
+
handleFilter: mockHandleFilter,
|
|
18
|
+
inputType: "text",
|
|
19
|
+
dropdownOptions: ["Option 1", "Option 2"],
|
|
20
|
+
selectedDropdownOption: "Option 1",
|
|
21
|
+
onDropdownOptionSelect: mockOnDropdownOptionSelect,
|
|
22
|
+
searchItems: [],
|
|
23
|
+
setSearchItems: mockSetSearchItems,
|
|
24
|
+
toggleStatus: false,
|
|
25
|
+
setToggleStatus: mockSetToggleStatus,
|
|
26
|
+
minValue: "",
|
|
27
|
+
maxValue: "",
|
|
28
|
+
setMinValue: mockSetMinValue,
|
|
29
|
+
setMaxValue: mockSetMaxValue,
|
|
30
|
+
selectedDate: null,
|
|
31
|
+
onDateSelect: mockOnDateSelect,
|
|
32
|
+
selectedStartDate: null,
|
|
33
|
+
onStartDateSelect: mockOnStartDateSelect,
|
|
34
|
+
selectedEndDate: null,
|
|
35
|
+
onEndDateSelect: mockOnEndDateSelect,
|
|
36
|
+
onChange: mockOnChange,
|
|
37
|
+
selectedValue: [],
|
|
38
|
+
value: [],
|
|
39
|
+
handleIconClick: mockHandleIconClick,
|
|
40
|
+
};
|
|
41
|
+
describe("SearchInput Component", () => {
|
|
42
|
+
describe("Text Input", () => {
|
|
43
|
+
test("renders search input field", () => {
|
|
44
|
+
render(_jsx(SearchInput, { ...defaultProps }));
|
|
45
|
+
expect(screen.getByPlaceholderText("Search")).toBeInTheDocument();
|
|
46
|
+
});
|
|
47
|
+
test("updates input value on change", () => {
|
|
48
|
+
render(_jsx(SearchInput, { ...defaultProps }));
|
|
49
|
+
const input = screen.getByPlaceholderText("Search");
|
|
50
|
+
fireEvent.change(input, { target: { value: "Test Input" } });
|
|
51
|
+
expect(input).toHaveValue("Test Input");
|
|
52
|
+
});
|
|
53
|
+
test("does not add empty search input to search items on enter press", () => {
|
|
54
|
+
render(_jsx(SearchInput, { ...defaultProps }));
|
|
55
|
+
const input = screen.getByPlaceholderText("Search");
|
|
56
|
+
fireEvent.keyDown(input, { key: "Enter", code: "Enter" });
|
|
57
|
+
expect(mockSetSearchItems).toHaveBeenCalled();
|
|
58
|
+
});
|
|
59
|
+
test("adds valid input to search items on enter press", () => {
|
|
60
|
+
render(_jsx(SearchInput, { ...defaultProps }));
|
|
61
|
+
const input = screen.getByPlaceholderText("Search");
|
|
62
|
+
fireEvent.change(input, { target: { value: "New Search" } });
|
|
63
|
+
fireEvent.keyDown(input, { key: "Enter", code: "Enter" });
|
|
64
|
+
expect(mockSetSearchItems).toHaveBeenCalledWith(["New Search"]);
|
|
65
|
+
});
|
|
66
|
+
test("clears input when clear icon is clicked", () => {
|
|
67
|
+
render(_jsx(SearchInput, { ...defaultProps }));
|
|
68
|
+
const input = screen.getByPlaceholderText("Search");
|
|
69
|
+
fireEvent.change(input, { target: { value: "Clear me" } });
|
|
70
|
+
const clearIcon = screen.getByTestId("clear-icon");
|
|
71
|
+
fireEvent.click(clearIcon);
|
|
72
|
+
expect(input).toHaveValue("");
|
|
73
|
+
});
|
|
74
|
+
test("removes search criterion when delete icon is clicked", () => {
|
|
75
|
+
render(_jsx(SearchInput, { ...defaultProps, searchItems: ["Test Item"] }));
|
|
76
|
+
fireEvent.click(screen.getByText("Test Item")); // Assuming clicking the item removes it
|
|
77
|
+
expect(mockSetSearchItems).toHaveBeenCalledWith([]);
|
|
78
|
+
});
|
|
79
|
+
test("renders dropdown with options", () => {
|
|
80
|
+
render(_jsx(SearchInput, { ...defaultProps }));
|
|
81
|
+
const dropdownTrigger = screen.getByText("Option 1"); // Default selected option
|
|
82
|
+
fireEvent.click(dropdownTrigger);
|
|
83
|
+
expect(screen.getByText("Option 2")).toBeInTheDocument();
|
|
84
|
+
});
|
|
85
|
+
test("calls dropdown selection handler when an option is clicked", () => {
|
|
86
|
+
render(_jsx(SearchInput, { ...defaultProps }));
|
|
87
|
+
const dropdownTrigger = screen.getByText("Option 1");
|
|
88
|
+
fireEvent.click(dropdownTrigger);
|
|
89
|
+
const option = screen.getByText("Option 2");
|
|
90
|
+
expect(option).toBeInTheDocument();
|
|
91
|
+
fireEvent.click(option);
|
|
92
|
+
expect(mockOnDropdownOptionSelect).toHaveBeenCalledWith("Option 2");
|
|
93
|
+
});
|
|
94
|
+
test("handles multiple items in search field", () => {
|
|
95
|
+
render(_jsx(SearchInput, { ...defaultProps, searchItems: ["Item 1", "Item 2"] }));
|
|
96
|
+
expect(screen.getByText("Item 1")).toBeInTheDocument();
|
|
97
|
+
expect(screen.getByText("Item 2")).toBeInTheDocument();
|
|
98
|
+
});
|
|
99
|
+
test("removes individual search item when close icon is clicked", () => {
|
|
100
|
+
render(_jsx(SearchInput, { ...defaultProps, searchItems: ["Item 1", "Item 2"] }));
|
|
101
|
+
const item1 = screen.getByText("Item 1");
|
|
102
|
+
fireEvent.click(item1);
|
|
103
|
+
expect(mockSetSearchItems).toHaveBeenCalledWith(["Item 2"]);
|
|
104
|
+
});
|
|
105
|
+
test("clears all search items when clicking on clear button", () => {
|
|
106
|
+
render(_jsx(SearchInput, { ...defaultProps, searchItems: ["Item 1", "Item 2"] }));
|
|
107
|
+
const clearIcons = screen.getAllByTestId("item-clear-icon");
|
|
108
|
+
expect(clearIcons).toHaveLength(2);
|
|
109
|
+
clearIcons.forEach((icon) => fireEvent.click(icon));
|
|
110
|
+
expect(mockSetSearchItems).toHaveBeenCalled();
|
|
111
|
+
});
|
|
112
|
+
test("renders a different dropdown icon when dropdownIconProp is provided", () => {
|
|
113
|
+
render(_jsx(SearchInput, { ...defaultProps, dropdownIconProp: {
|
|
114
|
+
iconClasses: "text-red-500",
|
|
115
|
+
name: "arrowDown",
|
|
116
|
+
weight: "bold",
|
|
117
|
+
} }));
|
|
118
|
+
const dropdownIconContainer = screen.getByTestId("dropdown-icon");
|
|
119
|
+
expect(dropdownIconContainer).toHaveClass("text-red-500");
|
|
120
|
+
console.log(dropdownIconContainer.classList);
|
|
121
|
+
});
|
|
122
|
+
test("does not add input text to search items when non-Enter key is pressed", () => {
|
|
123
|
+
render(_jsx(SearchInput, { ...defaultProps }));
|
|
124
|
+
const input = screen.getByPlaceholderText("Search");
|
|
125
|
+
fireEvent.change(input, { target: { value: "Test Input" } });
|
|
126
|
+
const initialCallCount = mockSetSearchItems.mock.calls.length;
|
|
127
|
+
fireEvent.keyDown(input, { key: "Escape", code: "Escape" });
|
|
128
|
+
expect(mockSetSearchItems.mock.calls.length).toBe(initialCallCount);
|
|
129
|
+
expect(input).toHaveValue("Test Input");
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
describe("Number Input", () => {
|
|
133
|
+
test("renders number input fields", () => {
|
|
134
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "number" }));
|
|
135
|
+
expect(screen.getByPlaceholderText("Amount")).toBeInTheDocument();
|
|
136
|
+
});
|
|
137
|
+
test("shows min and max fields only when toggle is clicked", () => {
|
|
138
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "number", toggleStatus: false }));
|
|
139
|
+
const toggleCheckbox = screen.getByRole("checkbox");
|
|
140
|
+
expect(toggleCheckbox).toBeInTheDocument();
|
|
141
|
+
fireEvent.click(toggleCheckbox);
|
|
142
|
+
expect(mockSetToggleStatus).toHaveBeenCalledWith(true);
|
|
143
|
+
// Re-render the component with the updated state
|
|
144
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "number", toggleStatus: true }));
|
|
145
|
+
expect(screen.getByPlaceholderText("Min")).toBeInTheDocument();
|
|
146
|
+
expect(screen.getByPlaceholderText("Max")).toBeInTheDocument();
|
|
147
|
+
});
|
|
148
|
+
test("updates min value on change after toggle is clicked", () => {
|
|
149
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "number", toggleStatus: true }));
|
|
150
|
+
const minInput = screen.getByPlaceholderText("Min");
|
|
151
|
+
fireEvent.change(minInput, { target: { value: "10" } });
|
|
152
|
+
expect(mockSetMinValue).toHaveBeenCalledWith("10");
|
|
153
|
+
});
|
|
154
|
+
test("updates max value on change after toggle is clicked", () => {
|
|
155
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "number", toggleStatus: true }));
|
|
156
|
+
const maxInput = screen.getByPlaceholderText("Max");
|
|
157
|
+
fireEvent.change(maxInput, { target: { value: "100" } });
|
|
158
|
+
expect(mockSetMaxValue).toHaveBeenCalledWith("100");
|
|
159
|
+
});
|
|
160
|
+
test("Filter button should be present", () => {
|
|
161
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "number" }));
|
|
162
|
+
const filterButton = screen.getByText("Filter");
|
|
163
|
+
expect(filterButton).toBeInTheDocument();
|
|
164
|
+
});
|
|
165
|
+
test("updates min value on input change", () => {
|
|
166
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "number", toggleStatus: true }));
|
|
167
|
+
const minInput = screen.getByPlaceholderText("Min");
|
|
168
|
+
fireEvent.change(minInput, { target: { value: "25" } });
|
|
169
|
+
expect(mockSetMinValue).toHaveBeenCalledWith("25");
|
|
170
|
+
});
|
|
171
|
+
test("renders a different dropdown icon when dropdownIconProp is provided", () => {
|
|
172
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "number", dropdownIconProp: {
|
|
173
|
+
iconClasses: "text-red-500",
|
|
174
|
+
name: "arrowDown",
|
|
175
|
+
weight: "bold",
|
|
176
|
+
} }));
|
|
177
|
+
const dropdownIconContainer = screen.getByTestId("dropdown-icon");
|
|
178
|
+
expect(dropdownIconContainer).toHaveClass("text-red-500");
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
describe("Dropdown Input", () => {
|
|
182
|
+
test("renders dropdown input with placeholder", () => {
|
|
183
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect" }));
|
|
184
|
+
// Ensure the dropdown renders with the placeholder "Search"
|
|
185
|
+
expect(screen.getByText("Search")).toBeInTheDocument();
|
|
186
|
+
});
|
|
187
|
+
test("opens dropdown and selects an option", async () => {
|
|
188
|
+
const mockOnChange = vi.fn();
|
|
189
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect", onChange: mockOnChange, dropdownOptions: [
|
|
190
|
+
{
|
|
191
|
+
uuid: "1",
|
|
192
|
+
name: "Option 1",
|
|
193
|
+
value: "option1",
|
|
194
|
+
label: "Option 1",
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
uuid: "2",
|
|
198
|
+
name: "Option 2",
|
|
199
|
+
value: "option2",
|
|
200
|
+
label: "Option 2",
|
|
201
|
+
},
|
|
202
|
+
] }));
|
|
203
|
+
// Open dropdown
|
|
204
|
+
const dropdown = screen.getByText(/Search/i);
|
|
205
|
+
fireEvent.click(dropdown);
|
|
206
|
+
// Wait for "Select All" option to appear
|
|
207
|
+
const option = await screen.findByText("Select All");
|
|
208
|
+
fireEvent.click(option);
|
|
209
|
+
// Assert that onChange received the correct selection
|
|
210
|
+
expect(mockOnChange).toHaveBeenCalled();
|
|
211
|
+
});
|
|
212
|
+
test("clears all selections when Clear button is clicked", () => {
|
|
213
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect", selectedValue: [{ name: "Option 1", value: "option1" }] }));
|
|
214
|
+
const clearButton = screen.getByRole("button", { name: /clear/i });
|
|
215
|
+
fireEvent.click(clearButton);
|
|
216
|
+
expect(mockOnChange).toHaveBeenCalledWith([]);
|
|
217
|
+
});
|
|
218
|
+
test("Clears when Clear button is clicked", async () => {
|
|
219
|
+
const mockOnChange = vi.fn();
|
|
220
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect", onChange: mockOnChange, dropdownOptions: [
|
|
221
|
+
{
|
|
222
|
+
uuid: "1",
|
|
223
|
+
name: "Option 1",
|
|
224
|
+
value: "option1",
|
|
225
|
+
label: "Option 1",
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
uuid: "2",
|
|
229
|
+
name: "Option 2",
|
|
230
|
+
value: "option2",
|
|
231
|
+
label: "Option 2",
|
|
232
|
+
},
|
|
233
|
+
] }));
|
|
234
|
+
const dropdown = screen.getByText(/Search/i);
|
|
235
|
+
fireEvent.click(dropdown);
|
|
236
|
+
const ClearButton = await screen.findByText("Clear");
|
|
237
|
+
fireEvent.click(ClearButton);
|
|
238
|
+
expect(mockOnChange).toHaveBeenCalled();
|
|
239
|
+
});
|
|
240
|
+
test("calls handleFilter on Filter button click and stops propagation", async () => {
|
|
241
|
+
const mockHandleFilter = vi.fn();
|
|
242
|
+
const mockStopPropagation = vi.fn();
|
|
243
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect", handleFilter: mockHandleFilter, dropdownOptions: [
|
|
244
|
+
{
|
|
245
|
+
uuid: "1",
|
|
246
|
+
name: "Option 1",
|
|
247
|
+
value: "option1",
|
|
248
|
+
label: "Option 1",
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
uuid: "2",
|
|
252
|
+
name: "Option 2",
|
|
253
|
+
value: "option2",
|
|
254
|
+
label: "Option 2",
|
|
255
|
+
},
|
|
256
|
+
] }));
|
|
257
|
+
const dropdown = screen.getByText(/Search/i);
|
|
258
|
+
fireEvent.click(dropdown);
|
|
259
|
+
const ClearButton = await screen.findByText("Filter");
|
|
260
|
+
fireEvent.click(ClearButton);
|
|
261
|
+
expect(mockHandleFilter).toHaveBeenCalled();
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
describe("Boolean Input", () => {
|
|
265
|
+
const mockOnChange = vi.fn();
|
|
266
|
+
test("renders boolean input with placeholder", () => {
|
|
267
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect", dropdownOptions: [
|
|
268
|
+
{
|
|
269
|
+
uuid: "1",
|
|
270
|
+
name: "True",
|
|
271
|
+
value: "true",
|
|
272
|
+
label: "True",
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
uuid: "2",
|
|
276
|
+
name: "False",
|
|
277
|
+
value: "false",
|
|
278
|
+
label: "False",
|
|
279
|
+
},
|
|
280
|
+
] }));
|
|
281
|
+
expect(screen.getByText(/Search/i)).toBeInTheDocument();
|
|
282
|
+
});
|
|
283
|
+
test("opens boolean dropdown and selects an option", async () => {
|
|
284
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect", onChange: mockOnChange, dropdownOptions: [
|
|
285
|
+
{
|
|
286
|
+
uuid: "1",
|
|
287
|
+
name: "True",
|
|
288
|
+
value: "true",
|
|
289
|
+
label: "True",
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
uuid: "2",
|
|
293
|
+
name: "False",
|
|
294
|
+
value: "false",
|
|
295
|
+
label: "False",
|
|
296
|
+
},
|
|
297
|
+
] }));
|
|
298
|
+
// Open dropdown
|
|
299
|
+
const dropdown = screen.getByText(/Search/i);
|
|
300
|
+
fireEvent.click(dropdown);
|
|
301
|
+
const option = await screen.findByText("True");
|
|
302
|
+
fireEvent.click(option);
|
|
303
|
+
expect(mockOnChange).toHaveBeenCalledWith(expect.arrayContaining([{ name: "True", value: "true" }]));
|
|
304
|
+
});
|
|
305
|
+
test("clears all selections when Clear button is clicked", async () => {
|
|
306
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect", selectedValue: [{ uuid: "1", name: "True", value: "true" }], onChange: mockOnChange, dropdownOptions: [
|
|
307
|
+
{
|
|
308
|
+
uuid: "1",
|
|
309
|
+
name: "True",
|
|
310
|
+
value: "true",
|
|
311
|
+
label: "True",
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
uuid: "2",
|
|
315
|
+
name: "False",
|
|
316
|
+
value: "false",
|
|
317
|
+
label: "False",
|
|
318
|
+
},
|
|
319
|
+
] }));
|
|
320
|
+
// Open dropdown
|
|
321
|
+
const dropdown = screen.getByText("True");
|
|
322
|
+
fireEvent.click(dropdown);
|
|
323
|
+
// Find and click "Clear" button
|
|
324
|
+
const clearButton = await screen.findByText("Clear");
|
|
325
|
+
fireEvent.click(clearButton);
|
|
326
|
+
// Verify clearing of selections
|
|
327
|
+
expect(mockOnChange).toHaveBeenCalledWith([]);
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
describe("DateTimePicker Input", () => {
|
|
331
|
+
const mockOnDateSelect = vi.fn();
|
|
332
|
+
const mockOnStartDateSelect = vi.fn();
|
|
333
|
+
const mockOnEndDateSelect = vi.fn();
|
|
334
|
+
const mockSetToggleStatus = vi.fn();
|
|
335
|
+
const mockSetEditingHeader = vi.fn();
|
|
336
|
+
const mockCloseOutSearch = vi.fn();
|
|
337
|
+
const mockSetResetSearch = vi.fn();
|
|
338
|
+
const mockHandleFilter = vi.fn();
|
|
339
|
+
// Mock scrollIntoView to prevent errors in test execution
|
|
340
|
+
Element.prototype.scrollIntoView = vi.fn();
|
|
341
|
+
const defaultProps = {
|
|
342
|
+
handleFilter: mockHandleFilter,
|
|
343
|
+
closeOutSearch: mockCloseOutSearch,
|
|
344
|
+
setResetSearch: mockSetResetSearch,
|
|
345
|
+
setEditingHeader: mockSetEditingHeader,
|
|
346
|
+
toggleStatus: false,
|
|
347
|
+
setToggleStatus: mockSetToggleStatus,
|
|
348
|
+
selectedDate: null,
|
|
349
|
+
onDateSelect: mockOnDateSelect,
|
|
350
|
+
selectedStartDate: null,
|
|
351
|
+
onStartDateSelect: mockOnStartDateSelect,
|
|
352
|
+
selectedEndDate: null,
|
|
353
|
+
onEndDateSelect: mockOnEndDateSelect,
|
|
354
|
+
dropdownOptions: ["Option 1", "Option 2"],
|
|
355
|
+
selectedDropdownOption: "Option 1",
|
|
356
|
+
onDropdownOptionSelect: vi.fn(),
|
|
357
|
+
onChange: mockOnChange,
|
|
358
|
+
selectedValue: [],
|
|
359
|
+
value: [],
|
|
360
|
+
};
|
|
361
|
+
test("renders single date picker input inside SearchInput", () => {
|
|
362
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
|
|
363
|
+
expect(screen.getByText("Select Date")).toBeInTheDocument();
|
|
364
|
+
});
|
|
365
|
+
test("opens date picker when input is clicked", () => {
|
|
366
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
|
|
367
|
+
const dateInput = screen.getByText("Select Date");
|
|
368
|
+
fireEvent.click(dateInput);
|
|
369
|
+
expect(screen.getByRole("grid")).toBeInTheDocument(); // DayPicker should appear
|
|
370
|
+
});
|
|
371
|
+
test("selects a single date from the picker", () => {
|
|
372
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
|
|
373
|
+
fireEvent.click(screen.getByText("Select Date"));
|
|
374
|
+
const today = new Date().getDate();
|
|
375
|
+
fireEvent.click(screen.getByText(today.toString()));
|
|
376
|
+
expect(mockOnDateSelect).toHaveBeenCalled();
|
|
377
|
+
});
|
|
378
|
+
test("renders range date picker inputs when toggle is clicked", () => {
|
|
379
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
|
|
380
|
+
expect(screen.getByText("Start Date")).toBeInTheDocument();
|
|
381
|
+
expect(screen.getByText("End Date")).toBeInTheDocument();
|
|
382
|
+
});
|
|
383
|
+
test("opens start date picker when Start Date is clicked", () => {
|
|
384
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
|
|
385
|
+
const startDateInput = screen.getByText("Start Date");
|
|
386
|
+
fireEvent.click(startDateInput);
|
|
387
|
+
expect(screen.getByRole("grid")).toBeInTheDocument();
|
|
388
|
+
});
|
|
389
|
+
test("opens end date picker when End Date is clicked", () => {
|
|
390
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
|
|
391
|
+
const endDateInput = screen.getByText("End Date");
|
|
392
|
+
fireEvent.click(endDateInput);
|
|
393
|
+
expect(screen.getByRole("grid")).toBeInTheDocument();
|
|
394
|
+
});
|
|
395
|
+
test("selects a start date from the picker", () => {
|
|
396
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
|
|
397
|
+
fireEvent.click(screen.getByText("Start Date"));
|
|
398
|
+
const today = new Date().getDate();
|
|
399
|
+
fireEvent.click(screen.getByText(today.toString()));
|
|
400
|
+
expect(mockOnStartDateSelect).toHaveBeenCalled();
|
|
401
|
+
});
|
|
402
|
+
test("selects an end date from the picker", () => {
|
|
403
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
|
|
404
|
+
fireEvent.click(screen.getByText("End Date"));
|
|
405
|
+
const tomorrow = new Date();
|
|
406
|
+
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
407
|
+
fireEvent.click(screen.getByText(tomorrow.getDate().toString()));
|
|
408
|
+
expect(mockOnEndDateSelect).toHaveBeenCalled();
|
|
409
|
+
});
|
|
410
|
+
test("closes date picker when clicking outside", () => {
|
|
411
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
|
|
412
|
+
const dateInput = screen.getByText("Select Date");
|
|
413
|
+
fireEvent.click(dateInput);
|
|
414
|
+
expect(screen.getByRole("grid")).toBeInTheDocument(); // Calendar is open
|
|
415
|
+
// Simulate clicking outside
|
|
416
|
+
fireEvent.mouseDown(document.body);
|
|
417
|
+
expect(screen.queryByRole("grid")).not.toBeInTheDocument(); // Calendar should be closed
|
|
418
|
+
});
|
|
419
|
+
test("calls handleSubmitClick and closes date picker when Filter button is clicked", () => {
|
|
420
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
|
|
421
|
+
fireEvent.click(screen.getByText("Select Date")); // Open the calendar
|
|
422
|
+
expect(screen.getByRole("grid")).toBeInTheDocument();
|
|
423
|
+
fireEvent.click(screen.getByText("Filter")); // Click the filter button
|
|
424
|
+
expect(mockHandleFilter).toHaveBeenCalled();
|
|
425
|
+
expect(screen.queryByRole("grid")).not.toBeInTheDocument(); // Ensure picker is closed
|
|
426
|
+
});
|
|
427
|
+
test("does not close date picker if clicking inside", () => {
|
|
428
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
|
|
429
|
+
fireEvent.click(screen.getByText("Select Date")); // Open the calendar
|
|
430
|
+
expect(screen.getByRole("grid")).toBeInTheDocument();
|
|
431
|
+
// Simulate clicking inside
|
|
432
|
+
fireEvent.mouseDown(screen.getByRole("grid"));
|
|
433
|
+
expect(screen.getByRole("grid")).toBeInTheDocument(); // Calendar should remain open
|
|
434
|
+
});
|
|
435
|
+
test("ensures handleSubmitClick closes the date picker and resets active input", () => {
|
|
436
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
|
|
437
|
+
fireEvent.click(screen.getByText("Select Date"));
|
|
438
|
+
expect(screen.getByRole("grid")).toBeInTheDocument();
|
|
439
|
+
fireEvent.click(screen.getByText("Filter"));
|
|
440
|
+
expect(mockHandleFilter).toHaveBeenCalled();
|
|
441
|
+
expect(screen.queryByRole("grid")).not.toBeInTheDocument();
|
|
442
|
+
});
|
|
443
|
+
test("ensures clicking on dropdown opens dropdown options", () => {
|
|
444
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
|
|
445
|
+
const dropdownTrigger = screen.getByText("Option 1");
|
|
446
|
+
fireEvent.click(dropdownTrigger);
|
|
447
|
+
expect(screen.getByText("Option 2")).toBeInTheDocument();
|
|
448
|
+
});
|
|
449
|
+
test("ensures clicking on an option in dropdown selects it", () => {
|
|
450
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
|
|
451
|
+
const dropdownTrigger = screen.getByText("Option 1");
|
|
452
|
+
fireEvent.click(dropdownTrigger);
|
|
453
|
+
const option = screen.getByText("Option 2");
|
|
454
|
+
fireEvent.click(option);
|
|
455
|
+
expect(defaultProps.onDropdownOptionSelect).toHaveBeenCalledWith("Option 2");
|
|
456
|
+
});
|
|
457
|
+
test("ensures toggle button switches mode correctly", () => {
|
|
458
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
|
|
459
|
+
const toggleCheckbox = screen.getByRole("checkbox");
|
|
460
|
+
fireEvent.click(toggleCheckbox);
|
|
461
|
+
expect(mockSetToggleStatus).toHaveBeenCalledWith(true);
|
|
462
|
+
});
|
|
463
|
+
test("ensures selecting a start and end date updates state", () => {
|
|
464
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
|
|
465
|
+
fireEvent.click(screen.getByText("Start Date"));
|
|
466
|
+
fireEvent.click(screen.getByText(new Date().getDate().toString()));
|
|
467
|
+
expect(mockOnStartDateSelect).toHaveBeenCalled();
|
|
468
|
+
fireEvent.click(screen.getByText("End Date"));
|
|
469
|
+
fireEvent.click(screen.getByText(new Date().getDate().toString()));
|
|
470
|
+
expect(mockOnEndDateSelect).toHaveBeenCalled();
|
|
471
|
+
});
|
|
472
|
+
test("toggles range mode when toggle button is clicked", () => {
|
|
473
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
|
|
474
|
+
const toggleCheckbox = screen.getByRole("checkbox");
|
|
475
|
+
fireEvent.click(toggleCheckbox);
|
|
476
|
+
expect(mockSetToggleStatus).toHaveBeenCalledWith(true);
|
|
477
|
+
});
|
|
478
|
+
test("renders selectedStartDate if provided, otherwise shows default text", () => {
|
|
479
|
+
const mockStartDate = new Date(2023, 5, 15); // June 15, 2023
|
|
480
|
+
const { rerender } = render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true, selectedStartDate: null }));
|
|
481
|
+
expect(screen.getByText("Start Date")).toBeInTheDocument();
|
|
482
|
+
rerender(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true, selectedStartDate: mockStartDate }));
|
|
483
|
+
expect(screen.getByText(mockStartDate.toLocaleDateString())).toBeInTheDocument();
|
|
484
|
+
});
|
|
485
|
+
test("calls onStartDateSelect when a start date is selected", () => {
|
|
486
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
|
|
487
|
+
// Open the Start Date Picker
|
|
488
|
+
fireEvent.click(screen.getByText("Start Date"));
|
|
489
|
+
// Pick a date (e.g., today's date)
|
|
490
|
+
const today = new Date().getDate();
|
|
491
|
+
fireEvent.click(screen.getByText(today.toString()));
|
|
492
|
+
// Expect the handler to be called
|
|
493
|
+
expect(mockOnStartDateSelect).toHaveBeenCalled();
|
|
494
|
+
});
|
|
495
|
+
test("calls onEndDateSelect when an end date is selected", () => {
|
|
496
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
|
|
497
|
+
// Open the End Date Picker
|
|
498
|
+
fireEvent.click(screen.getByText("End Date"));
|
|
499
|
+
const tomorrow = new Date();
|
|
500
|
+
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
501
|
+
fireEvent.click(screen.getByText(tomorrow.getDate().toString()));
|
|
502
|
+
// Expect the handler to be called
|
|
503
|
+
expect(mockOnEndDateSelect).toHaveBeenCalled();
|
|
504
|
+
});
|
|
505
|
+
test("calls onDateSelect when a single date is selected", () => {
|
|
506
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
|
|
507
|
+
// Open the Date Picker
|
|
508
|
+
fireEvent.click(screen.getByText("Select Date"));
|
|
509
|
+
const today = new Date().getDate();
|
|
510
|
+
fireEvent.click(screen.getByText(today.toString()));
|
|
511
|
+
// Expect the handler to be called
|
|
512
|
+
expect(mockOnDateSelect).toHaveBeenCalled();
|
|
513
|
+
});
|
|
514
|
+
test("shows placeholder text when no date is selected", () => {
|
|
515
|
+
render(_jsx(SearchInput, { ...defaultProps, inputType: "date", selectedDate: null }));
|
|
516
|
+
expect(screen.getByText("Select Date")).toBeInTheDocument();
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
});
|
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Control } from "react-hook-form";
|
|
3
|
-
import { Accessor, ColumnInstance } from "react-table";
|
|
4
|
-
type ColumnWithAccessor<T extends object> = ColumnInstance<T> & {
|
|
5
|
-
accessor?: string | number | symbol | Accessor<T>;
|
|
6
|
-
};
|
|
7
3
|
export type SearchInputProps<T extends object> = {
|
|
8
4
|
onChange(newSelected: OptionType[]): unknown;
|
|
9
5
|
selectedValue: any[];
|
|
10
6
|
value: any[];
|
|
11
|
-
|
|
12
|
-
setResetSearch: React.Dispatch<React.SetStateAction<boolean>>;
|
|
13
|
-
columHeader?: any;
|
|
14
|
-
column: ColumnWithAccessor<T>;
|
|
15
|
-
parentIndex?: number;
|
|
16
|
-
setEditingHeader: (value: number | null) => void;
|
|
7
|
+
handleFilter: () => void;
|
|
17
8
|
bgColor?: string;
|
|
18
9
|
textHighlight?: string;
|
|
19
|
-
inputType?:
|
|
10
|
+
inputType?: 'text' | 'number' | 'date' | 'boolean' | 'multiSelect';
|
|
20
11
|
dropdownOptions?: string[] | OptionType[] | number[];
|
|
21
12
|
selectedDropdownOption?: string | OptionType | number;
|
|
22
13
|
onDropdownOptionSelect?: (option: string) => void;
|
|
@@ -32,6 +23,12 @@ export type SearchInputProps<T extends object> = {
|
|
|
32
23
|
control?: Control<any>;
|
|
33
24
|
valueKey?: string;
|
|
34
25
|
dynamicDefaultValue?: any;
|
|
26
|
+
selectedDate?: Date;
|
|
27
|
+
onDateSelect?: (date: Date) => void;
|
|
28
|
+
selectedStartDate?: Date;
|
|
29
|
+
onStartDateSelect?: (date: Date) => void;
|
|
30
|
+
selectedEndDate?: Date;
|
|
31
|
+
onEndDateSelect?: (date: Date) => void;
|
|
35
32
|
};
|
|
36
33
|
export interface OptionType {
|
|
37
34
|
uuid: string;
|
|
@@ -44,4 +41,3 @@ export type searchDropdownIconProps = {
|
|
|
44
41
|
weight: string;
|
|
45
42
|
iconClasses: string;
|
|
46
43
|
};
|
|
47
|
-
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import "react-day-picker/dist/style.css";
|
|
3
|
+
import { searchDropdownIconProps } from "./SearchInput.types";
|
|
4
|
+
type SearchDatePickerInputProps<T extends object> = {
|
|
5
|
+
textHighlight?: string;
|
|
6
|
+
dropdownOptions?: string[];
|
|
7
|
+
selectedDropdownOption?: string;
|
|
8
|
+
onDropdownOptionSelect?: (option: string) => void;
|
|
9
|
+
dropdownIconProp?: searchDropdownIconProps;
|
|
10
|
+
toggleStatus?: boolean;
|
|
11
|
+
setToggleStatus?: React.Dispatch<React.SetStateAction<boolean>>;
|
|
12
|
+
themeBgColor?: string;
|
|
13
|
+
lightThemeBg?: string;
|
|
14
|
+
selectedDate?: Date;
|
|
15
|
+
onDateSelect?: (date: Date) => void;
|
|
16
|
+
selectedStartDate?: Date;
|
|
17
|
+
onStartDateSelect?: (date: Date) => void;
|
|
18
|
+
selectedEndDate?: Date;
|
|
19
|
+
onEndDateSelect?: (date: Date) => void;
|
|
20
|
+
handleFilter?: () => void;
|
|
21
|
+
};
|
|
22
|
+
declare function SearchDatePickerInput<T extends object>({ textHighlight, dropdownOptions, selectedDropdownOption, onDropdownOptionSelect, dropdownIconProp, toggleStatus, setToggleStatus, themeBgColor, lightThemeBg, selectedDate, onDateSelect, selectedStartDate, onStartDateSelect, selectedEndDate, onEndDateSelect, handleFilter, }: SearchDatePickerInputProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
export default SearchDatePickerInput;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { DayPicker } from "react-day-picker";
|
|
4
|
+
import "react-day-picker/dist/style.css";
|
|
5
|
+
import Dropdown from "../Dropdown/Dropdown";
|
|
6
|
+
import ToggleButton from "../ToggleButton/ToggleButton";
|
|
7
|
+
import BaseButton from "../BaseButton";
|
|
8
|
+
function SearchDatePickerInput({ textHighlight = "text-sky-700", dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, dropdownIconProp = {
|
|
9
|
+
iconClasses: "text-sky-500",
|
|
10
|
+
name: "chevronDown",
|
|
11
|
+
weight: "solid",
|
|
12
|
+
}, toggleStatus = false, setToggleStatus, themeBgColor = "bg-sky-500", lightThemeBg = "bg-sky-100", selectedDate, onDateSelect, selectedStartDate, onStartDateSelect, selectedEndDate, onEndDateSelect, handleFilter, }) {
|
|
13
|
+
const containerRef = useRef(null);
|
|
14
|
+
// Remove internal state for the date values (they come from props)
|
|
15
|
+
// Internal UI state for showing the calendar and active input remains:
|
|
16
|
+
const [isDatePickerOpen, setIsDatePickerOpen] = useState(false);
|
|
17
|
+
const [activeInput, setActiveInput] = useState(null);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
containerRef.current?.scrollIntoView();
|
|
20
|
+
}, []);
|
|
21
|
+
// Close calendar(s) when clicking outside the container
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
function handleClickOutside(event) {
|
|
24
|
+
if (containerRef.current &&
|
|
25
|
+
!containerRef.current.contains(event.target)) {
|
|
26
|
+
setIsDatePickerOpen(false);
|
|
27
|
+
setActiveInput(null);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
31
|
+
return () => {
|
|
32
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
33
|
+
};
|
|
34
|
+
}, []);
|
|
35
|
+
// Handler for the Filter button remains similar,
|
|
36
|
+
// but it now uses the values from props.
|
|
37
|
+
const handleSubmitClick = () => {
|
|
38
|
+
// Close the calendar(s) after filtering
|
|
39
|
+
setIsDatePickerOpen(false);
|
|
40
|
+
setActiveInput(null);
|
|
41
|
+
handleFilter();
|
|
42
|
+
};
|
|
43
|
+
const modifiersClassNames = {
|
|
44
|
+
selected: `${themeBgColor} text-white rounded-full`,
|
|
45
|
+
today: `${lightThemeBg} ${textHighlight}`,
|
|
46
|
+
};
|
|
47
|
+
return (_jsxs("div", { ref: containerRef, className: "relative w-[425px] border-2 p-4", children: [_jsx("div", { className: "flex items-center justify-between h-12", children: toggleStatus ? (
|
|
48
|
+
// Toggle mode: two separate inputs with a "to" between them
|
|
49
|
+
_jsxs("div", { className: "flex items-center w-full", children: [_jsx("button", { onClick: () => setActiveInput("start"), className: "border-2 px-3 py-2 flex-1 h-10 text-left", children: selectedStartDate
|
|
50
|
+
? selectedStartDate.toLocaleDateString()
|
|
51
|
+
: "Start Date" }), _jsx("span", { className: "mx-2", children: "to" }), _jsx("button", { onClick: () => setActiveInput("end"), className: "border-2 px-3 py-2 flex-1 h-10 text-left", children: selectedEndDate
|
|
52
|
+
? selectedEndDate.toLocaleDateString()
|
|
53
|
+
: "End Date" })] })) : (
|
|
54
|
+
// Non-toggle mode: Dropdown and a single date input
|
|
55
|
+
_jsxs(_Fragment, { children: [_jsx(Dropdown, { options: dropdownOptions, selectedOption: selectedDropdownOption, onOptionSelect: onDropdownOptionSelect, optionClasses: "px-4 h-full flex items-center", menuClasses: "bg-white min-w-[150px] top-[-8px] left-[-2px]", dropdownClasses: "border-2 border-r-0 flex-[1] h-10 w-auto", icon: dropdownIconProp }), _jsx("button", { onClick: () => setIsDatePickerOpen((prev) => !prev), className: "border-2 px-3 py-2 flex-[2] h-10 text-left", children: selectedDate
|
|
56
|
+
? selectedDate.toLocaleDateString()
|
|
57
|
+
: "Select Date" })] })) }), toggleStatus
|
|
58
|
+
? activeInput && (_jsx("div", { className: "absolute p-4 top-16 w-auto z-50 shadow-lg bg-white", children: activeInput === "start" ? (_jsx(DayPicker, { mode: "single", selected: selectedStartDate, onSelect: (date) => {
|
|
59
|
+
if (onStartDateSelect)
|
|
60
|
+
onStartDateSelect(date);
|
|
61
|
+
setActiveInput(null); // close calendar after selection
|
|
62
|
+
}, modifiersClassNames: modifiersClassNames })) : (_jsx(DayPicker, { mode: "single", selected: selectedEndDate, onSelect: (date) => {
|
|
63
|
+
if (onEndDateSelect)
|
|
64
|
+
onEndDateSelect(date);
|
|
65
|
+
setActiveInput(null); // close calendar after selection
|
|
66
|
+
}, modifiersClassNames: modifiersClassNames })) }))
|
|
67
|
+
: isDatePickerOpen && (_jsx("div", { className: "absolute p-4 top-16 w-auto z-50 shadow-lg bg-white", children: _jsx(DayPicker, { mode: "single", selected: selectedDate, onSelect: (date) => {
|
|
68
|
+
if (onDateSelect)
|
|
69
|
+
onDateSelect(date);
|
|
70
|
+
}, modifiersClassNames: modifiersClassNames }) })), _jsxs("div", { className: "flex justify-between items-end bg-white px-2 rounded-md mt-4", children: [_jsx(ToggleButton, { initialStatus: toggleStatus, onClick: () => setToggleStatus?.(!toggleStatus), activeColorBackground: "bg-sky-500", activeColorBorder: "border-sky-500", activeLabel: "Range", activeTextColor: "text-sky-500", additionalClasses: "flex items-center", inactiveColorBackground: "bg-gray-300", inactiveColorBorder: "border-gray-300", inactiveLabel: "Range", inactiveTextColor: "text-gray-500", pillHeight: "h-8", textPosition: "right", textSize: "text-sm", smallToggle: false, borderStyle: false }), _jsx(BaseButton, { text: "Filter", backgroundColor: "bg-sky-500", additionalClasses: "py-1.5 px-6 text-white", borderColor: "border-none", onClick: handleSubmitClick, shape: "rounded-full" })] })] }));
|
|
71
|
+
}
|
|
72
|
+
export default SearchDatePickerInput;
|
|
@@ -1,31 +1,19 @@
|
|
|
1
|
-
import { Accessor } from "react-table";
|
|
2
1
|
import React from "react";
|
|
3
|
-
import { ColumnInstance } from "react-table";
|
|
4
2
|
import { searchDropdownIconProps } from "./SearchInput.types";
|
|
5
|
-
type ColumnWithAccessor<T extends object> = ColumnInstance<T> & {
|
|
6
|
-
accessor?: string | number | symbol | Accessor<T>;
|
|
7
|
-
};
|
|
8
3
|
type SearchNumberInputProps<T extends object> = {
|
|
9
|
-
closeOutSearch: (value: number | null) => void;
|
|
10
|
-
setResetSearch: React.Dispatch<React.SetStateAction<boolean>>;
|
|
11
|
-
columHeader?: any;
|
|
12
|
-
parentIndex?: number;
|
|
13
4
|
pillColor?: string;
|
|
14
5
|
textHighlight?: string;
|
|
15
|
-
column: ColumnWithAccessor<T>;
|
|
16
|
-
setEditingHeader: (value: number | null) => void;
|
|
17
6
|
dropdownOptions?: string[];
|
|
18
7
|
selectedDropdownOption?: string;
|
|
19
8
|
onDropdownOptionSelect?: (option: string) => void;
|
|
20
9
|
dropdownIconProp?: searchDropdownIconProps;
|
|
21
|
-
searchItems?: string[];
|
|
22
|
-
setSearchItems?: React.Dispatch<React.SetStateAction<string[]>>;
|
|
23
10
|
toggleStatus?: boolean;
|
|
24
11
|
setToggleStatus?: React.Dispatch<React.SetStateAction<boolean>>;
|
|
25
12
|
minValue?: string;
|
|
26
13
|
setMinValue?: React.Dispatch<React.SetStateAction<string>>;
|
|
27
14
|
maxValue?: string;
|
|
28
15
|
setMaxValue?: React.Dispatch<React.SetStateAction<string>>;
|
|
16
|
+
handleFilter?: () => void;
|
|
29
17
|
};
|
|
30
|
-
declare const SearchNumberInput: <T extends object>({
|
|
18
|
+
declare const SearchNumberInput: <T extends object>({ textHighlight, dropdownIconProp, dropdownOptions, selectedDropdownOption, onDropdownOptionSelect, toggleStatus, setToggleStatus, minValue, setMinValue, maxValue, setMaxValue, handleFilter, }: SearchNumberInputProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
31
19
|
export default SearchNumberInput;
|
|
@@ -5,11 +5,11 @@ import Dropdown from "../Dropdown/Dropdown";
|
|
|
5
5
|
import ToggleButton from "../ToggleButton/ToggleButton";
|
|
6
6
|
import BaseButton from "../BaseButton";
|
|
7
7
|
import Text from "../Text";
|
|
8
|
-
const SearchNumberInput = ({
|
|
8
|
+
const SearchNumberInput = ({ textHighlight = "text-sky-500", dropdownIconProp = {
|
|
9
9
|
iconClasses: textHighlight,
|
|
10
10
|
name: "chevronDown",
|
|
11
11
|
weight: "solid",
|
|
12
|
-
}, dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect,
|
|
12
|
+
}, dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, toggleStatus, setToggleStatus, minValue, setMinValue, maxValue, setMaxValue, handleFilter, }) => {
|
|
13
13
|
const containerRef = useRef(null);
|
|
14
14
|
const inputRef = useRef(null);
|
|
15
15
|
// Focus the input when editing starts (if needed)
|
|
@@ -22,39 +22,20 @@ const SearchNumberInput = ({ closeOutSearch, setResetSearch, setEditingHeader, t
|
|
|
22
22
|
const handleMaximumInputChange = (event) => {
|
|
23
23
|
setMaxValue(event.target.value);
|
|
24
24
|
};
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
setEditingHeader(null);
|
|
40
|
-
};
|
|
41
|
-
const handleIconClick = (item) => {
|
|
42
|
-
// Remove criterion
|
|
43
|
-
const filteredItems = searchItems.filter((ele) => ele !== item);
|
|
44
|
-
setSearchItems(filteredItems);
|
|
45
|
-
setResetSearch((prevResetSearch) => !prevResetSearch);
|
|
46
|
-
closeOutSearch(null);
|
|
47
|
-
};
|
|
48
|
-
const handleKeyDown = (e) => {
|
|
49
|
-
if (e.key === "Enter") {
|
|
50
|
-
e.preventDefault();
|
|
51
|
-
// setSearchItems([...searchItems, localSearchText]);
|
|
52
|
-
// setLocalSearchText("");
|
|
53
|
-
handleSubmitClick();
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
return (_jsx("div", { ref: containerRef, className: "w-[425px]", children: _jsxs("div", { className: `flex flex-col p-4 h-[130px] border-2 border-navy-200 rounded-md`, children: [_jsx("div", { className: `flex flex-[1] ${toggleStatus ? "" : "border-2"} h-full max-h-11 items-center justify-around`, children: toggleStatus ? (_jsxs(_Fragment, { children: [_jsx(Input, { focusRingColor: "focus:ring-2", hasAutoFocus: true, value: minValue, iconColor: "text-navy-400", onKeyDown: handleKeyDown, required: false, id: "", name: "", type: "number", onChange: handleInputChange, additionalClasses: "min-w-[180px] max-w-[180px] h-10 text-gray flex border-2 focus:border-transparent ", placeholder: "Min" }), _jsx(Text, { size: "text-md", tag: "span", text: "to", additionalClasses: "px-2" }), _jsx(Input, { focusRingColor: "focus:ring-2", value: maxValue, iconColor: "text-navy-400", onKeyDown: handleKeyDown, required: false, id: "", name: "", type: "number", onChange: handleMaximumInputChange, additionalClasses: "min-w-[180px] max-w-[180px] h-10 text-gray flex border-2 focus:border-transparent ", placeholder: "Max", hasIcons: true, iconPosition: "both" })] })) : (_jsxs(_Fragment, { children: [_jsx(Dropdown, { options: dropdownOptions, selectedOption: selectedDropdownOption, onOptionSelect: onDropdownOptionSelect, optionClasses: "px-4 h-full flex items-center", menuClasses: "bg-white w-min-[150px] top-[-8px] left-[-2px]", dropdownClasses: "border-0 border-r-2 w-auto", icon: dropdownIconProp }), _jsx(Input, { focusRingColor: "focus:ring-transparent", hasAutoFocus: true, value: minValue, iconColor: "text-navy-400", onKeyDown: handleKeyDown, required: false, id: "", name: "", type: "number", onChange: handleInputChange, additionalClasses: "min-w-[200px] h-10 text-gray flex ", placeholder: "Amount", hasIcons: true, iconPosition: "both" })] })) }), _jsxs("div", { className: "flex flex-[1] justify-between items-end bg-white px-2 rounded-md ", children: [_jsx(ToggleButton, { initialStatus: toggleStatus, onClick: () => {
|
|
25
|
+
// const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
26
|
+
// console.log("Key Pressed:", e.key);
|
|
27
|
+
// if (e.key === "Enter") {
|
|
28
|
+
// e.preventDefault();
|
|
29
|
+
// }
|
|
30
|
+
// };
|
|
31
|
+
return (_jsx("div", { ref: containerRef, className: "w-[425px]", children: _jsxs("div", { className: `flex flex-col p-4 h-[130px] border-2 border-navy-200 rounded-md`, children: [_jsx("div", { className: `flex flex-[1] ${toggleStatus ? "" : "border-2"} h-full max-h-11 items-center justify-around`, children: toggleStatus ? (_jsxs(_Fragment, { children: [_jsx(Input, { focusRingColor: "focus:ring-2", hasAutoFocus: true, value: minValue, iconColor: "text-navy-400",
|
|
32
|
+
// onKeyDown={handleKeyDown}
|
|
33
|
+
required: false, id: "", name: "", type: "number", onChange: handleInputChange, additionalClasses: "min-w-[180px] max-w-[180px] h-10 text-gray flex border-2 focus:border-transparent ", placeholder: "Min" }), _jsx(Text, { size: "text-md", tag: "span", text: "to", additionalClasses: "px-2" }), _jsx(Input, { focusRingColor: "focus:ring-2", value: maxValue, iconColor: "text-navy-400",
|
|
34
|
+
// onKeyDown={handleKeyDown}
|
|
35
|
+
required: false, id: "", name: "", type: "number", onChange: handleMaximumInputChange, additionalClasses: "min-w-[180px] max-w-[180px] h-10 text-gray flex border-2 focus:border-transparent ", placeholder: "Max", hasIcons: true, iconPosition: "both" })] })) : (_jsxs(_Fragment, { children: [_jsx(Dropdown, { options: dropdownOptions, selectedOption: selectedDropdownOption, onOptionSelect: onDropdownOptionSelect, optionClasses: "px-4 h-full flex items-center", menuClasses: "bg-white w-min-[150px] top-[-8px] left-[-2px]", dropdownClasses: "border-0 w-auto", icon: dropdownIconProp }), _jsx(Input, { focusRingColor: "focus:ring-transparent", hasAutoFocus: true, value: minValue, iconColor: "text-navy-400",
|
|
36
|
+
// onKeyDown={handleKeyDown}
|
|
37
|
+
required: false, id: "", name: "", type: "number", onChange: handleInputChange, additionalClasses: "min-w-[200px] h-10 text-gray flex border-l-2 ", placeholder: "Amount", hasIcons: true, iconPosition: "both" })] })) }), _jsxs("div", { className: "flex flex-[1] justify-between items-end bg-white px-2 rounded-md ", children: [_jsx(ToggleButton, { initialStatus: toggleStatus, onClick: () => {
|
|
57
38
|
setToggleStatus(!toggleStatus);
|
|
58
|
-
}, activeColorBackground: "bg-sky-500", activeColorBorder: "border-sky-500", activeLabel: "Range", activeTextColor: "text-sky-500", additionalClasses: "flex items-center", inactiveColorBackground: "bg-gray-300", inactiveColorBorder: "border-gray-300", inactiveLabel: "Range", inactiveTextColor: "text-gray-500", pillHeight: "h-8", textPosition: "right", textSize: "text-sm", smallToggle: false, borderStyle: false }), _jsx(BaseButton, { text: "Filter", backgroundColor: "bg-sky-500", additionalClasses: "py-1.5 px-6 text-white", borderColor: "border-none", onClick:
|
|
39
|
+
}, activeColorBackground: "bg-sky-500", activeColorBorder: "border-sky-500", activeLabel: "Range", activeTextColor: "text-sky-500", additionalClasses: "flex items-center", inactiveColorBackground: "bg-gray-300", inactiveColorBorder: "border-gray-300", inactiveLabel: "Range", inactiveTextColor: "text-gray-500", pillHeight: "h-8", textPosition: "right", textSize: "text-sm", smallToggle: false, borderStyle: false }), _jsx(BaseButton, { text: "Filter", backgroundColor: "bg-sky-500", additionalClasses: "py-1.5 px-6 text-white", borderColor: "border-none", onClick: handleFilter, shape: "rounded-full" })] })] }) }));
|
|
59
40
|
};
|
|
60
41
|
export default SearchNumberInput;
|
|
@@ -1,24 +1,15 @@
|
|
|
1
|
-
import { Accessor } from "react-table";
|
|
2
1
|
import React from "react";
|
|
3
|
-
import { ColumnInstance } from "react-table";
|
|
4
2
|
import { searchDropdownIconProps } from "./SearchInput.types";
|
|
5
|
-
type ColumnWithAccessor<T extends object> = ColumnInstance<T> & {
|
|
6
|
-
accessor?: string | number | symbol | Accessor<T>;
|
|
7
|
-
};
|
|
8
3
|
type SearchTextInputProps<T extends object> = {
|
|
9
|
-
closeOutSearch: (value: number | null) => void;
|
|
10
|
-
setResetSearch: React.Dispatch<React.SetStateAction<boolean>>;
|
|
11
|
-
columHeader?: any;
|
|
12
4
|
pillColor?: string;
|
|
13
5
|
textHighlight?: string;
|
|
14
|
-
column: ColumnWithAccessor<T>;
|
|
15
|
-
setEditingHeader: (value: number | null) => void;
|
|
16
6
|
dropdownIconProp?: searchDropdownIconProps;
|
|
17
7
|
selectedDropdownOption?: string;
|
|
18
8
|
onDropdownOptionSelect?: (option: string) => void;
|
|
19
9
|
dropdownOptions?: string[];
|
|
20
10
|
searchItems?: string[];
|
|
21
11
|
setSearchItems?: React.Dispatch<React.SetStateAction<string[]>>;
|
|
12
|
+
handleFilter?: () => void;
|
|
22
13
|
};
|
|
23
|
-
declare const SearchTextInput: <T extends object>({
|
|
14
|
+
declare const SearchTextInput: <T extends object>({ pillColor, textHighlight, dropdownIconProp, dropdownOptions, selectedDropdownOption, onDropdownOptionSelect, searchItems, setSearchItems, handleFilter, }: SearchTextInputProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
24
15
|
export default SearchTextInput;
|
|
@@ -6,11 +6,11 @@ import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
|
|
|
6
6
|
import Dropdown from "../Dropdown/Dropdown";
|
|
7
7
|
import Badge from "../Badge/Badge";
|
|
8
8
|
import Text from "../Text";
|
|
9
|
-
const SearchTextInput = ({
|
|
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, searchItems = [], setSearchItems, }) => {
|
|
13
|
+
}, dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, searchItems = [], setSearchItems, handleFilter, }) => {
|
|
14
14
|
const containerRef = useRef(null);
|
|
15
15
|
const [localSearchText, setLocalSearchText] = useState("");
|
|
16
16
|
const inputRef = useRef(null);
|
|
@@ -21,45 +21,26 @@ const SearchTextInput = ({ closeOutSearch, setResetSearch, setEditingHeader, pil
|
|
|
21
21
|
const handleInputChange = (event) => {
|
|
22
22
|
setLocalSearchText(event.target.value);
|
|
23
23
|
};
|
|
24
|
-
const handleSubmitClick = () => {
|
|
25
|
-
const trimmedSearchText = localSearchText.trim();
|
|
26
|
-
let safeHeader;
|
|
27
|
-
if (typeof column.Header === "string") {
|
|
28
|
-
safeHeader = column.Header;
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
safeHeader = column.accessor || "Unnamed Column";
|
|
32
|
-
}
|
|
33
|
-
if (trimmedSearchText === "") {
|
|
34
|
-
// Remove criterion if text is empty
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
// Update or add criterion
|
|
38
|
-
}
|
|
39
|
-
setEditingHeader(null);
|
|
40
|
-
};
|
|
41
24
|
const handleIconClick = (item) => {
|
|
42
25
|
// Remove criterion
|
|
43
26
|
const filteredItems = searchItems.filter((ele) => ele !== item);
|
|
44
27
|
setSearchItems(filteredItems);
|
|
45
|
-
setResetSearch((prevResetSearch) => !prevResetSearch);
|
|
46
|
-
closeOutSearch(null);
|
|
47
28
|
};
|
|
48
29
|
const handleKeyDown = (e) => {
|
|
49
30
|
if (e.key === "Enter") {
|
|
50
31
|
e.preventDefault();
|
|
51
32
|
setSearchItems([...searchItems, localSearchText]);
|
|
52
33
|
setLocalSearchText("");
|
|
53
|
-
|
|
34
|
+
handleFilter();
|
|
54
35
|
}
|
|
55
36
|
};
|
|
56
37
|
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`;
|
|
57
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 ${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: () => {
|
|
58
39
|
setLocalSearchText("");
|
|
59
|
-
}, children: getFontAwesomeIcon("xmark", "regular") }), _jsx("div", { className: `${textHighlight} text-sm hover:text-primary`, children: getFontAwesomeIcon("search", "solid") })] })) }) }), onIconClick: () => {
|
|
40
|
+
}, "data-testid": "clear-icon", children: getFontAwesomeIcon("xmark", "regular") }), _jsx("div", { className: `${textHighlight} text-sm hover:text-primary`, children: getFontAwesomeIcon("search", "solid") })] })) }) }), onIconClick: () => {
|
|
60
41
|
setLocalSearchText("");
|
|
61
42
|
} })] }), searchItems?.length ? (_jsx("div", { className: " flex bg-white py-2 px-2 rounded-md ", children: searchItems?.map((item, index) => {
|
|
62
|
-
return (_jsx(Badge, { backgroundColor: pillColor, borderRadius: "rounded-full", hasMobileStyle: true, hasRightIcon: true, icon: _jsx("div", { className: "text-white text-xxs", 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" }));
|
|
43
|
+
return (_jsx(Badge, { backgroundColor: pillColor, borderRadius: "rounded-full", hasMobileStyle: true, 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" }));
|
|
63
44
|
}) })) : null] }) }));
|
|
64
45
|
};
|
|
65
46
|
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.
|
|
4
|
+
"version": "1.0.48",
|
|
5
5
|
"description": "",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"framer-motion": "^11.0.8",
|
|
35
35
|
"nouislider": "^15.8.1",
|
|
36
36
|
"react": "^18.2.0",
|
|
37
|
+
"react-day-picker": "^9.5.1",
|
|
37
38
|
"react-dom": "^18.2.0",
|
|
38
39
|
"react-multi-select-component": "^4.3.4",
|
|
39
40
|
"react-router-dom": "^6.16.0",
|