@agilant/toga-blox 1.0.109 → 1.0.111
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 +0 -1
- package/dist/components/Input/Input.d.ts +6 -2
- package/dist/components/Input/Input.js +42 -27
- package/dist/components/MultiSelect/MultiSelect.js +37 -3
- package/dist/components/MultiSelect/MultiSelect.types.d.ts +1 -0
- package/dist/components/SearchInput/SearchDropdownInput.d.ts +4 -3
- package/dist/components/SearchInput/SearchDropdownInput.js +33 -14
- package/dist/components/SearchInput/SearchInput.js +3 -3
- package/dist/components/SearchInput/SearchInput.stories.d.ts +3 -0
- package/dist/components/SearchInput/SearchInput.stories.js +49 -42
- package/dist/components/SearchInput/SearchNumberInput.d.ts +3 -1
- package/dist/components/SearchInput/SearchNumberInput.js +22 -5
- package/dist/components/SearchInput/SearchTextInput.js +1 -3
- package/package.json +1 -1
|
@@ -9,7 +9,6 @@ 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
|
-
console.log(options, "DROP DOWN OPTIONS");
|
|
13
12
|
return (_jsxs("div", { className: `flex items-center justify-between relative min-w-40 ${dropdownClasses}`, children: [_jsxs("div", { onClick: toggleMenu, className: "flex cursor-pointer items-center group h-full", children: [_jsx("div", { className: `font-bold ${optionClasses} bg-white`, children: selectedOption.label }), _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((option) => (_jsxs("li", { className: `text-left px-4 py-2 cursor-pointer border-b bg-white ${option.value ===
|
|
14
13
|
selectedOption.value
|
|
15
14
|
? `${selectedOptionBgColor} font-semibold`
|
|
@@ -14,7 +14,7 @@ interface InputFieldProps {
|
|
|
14
14
|
toolTipText?: string;
|
|
15
15
|
onKeyDown?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
16
16
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
17
|
-
checked?: boolean
|
|
17
|
+
checked?: boolean;
|
|
18
18
|
id?: string;
|
|
19
19
|
name?: string;
|
|
20
20
|
additionalClasses?: string;
|
|
@@ -30,5 +30,9 @@ interface InputFieldProps {
|
|
|
30
30
|
focusRingColor?: string;
|
|
31
31
|
firstIconClasses?: string;
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
/**
|
|
34
|
+
* A properly formed forwardRef component: exactly two parameters:
|
|
35
|
+
* (props, ref). We pass `ref` to the <input ref={ref} ...>.
|
|
36
|
+
*/
|
|
37
|
+
declare const InputField: React.ForwardRefExoticComponent<InputFieldProps & React.RefAttributes<HTMLInputElement>>;
|
|
34
38
|
export default InputField;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useState } from "react";
|
|
2
3
|
import { faCircleInfo } from "@fortawesome/free-solid-svg-icons";
|
|
3
4
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* A properly formed forwardRef component: exactly two parameters:
|
|
7
|
+
* (props, ref). We pass `ref` to the <input ref={ref} ...>.
|
|
8
|
+
*/
|
|
9
|
+
const InputField = forwardRef(function InputField({ label, placeholder, required, checked, id, name, type = "text", firstIcon, secondIcon, iconPosition = "before", iconColor = "primary", isValid = true, isReadOnly = false, onChange, value, readOnlyInfo = "", toolTipText = "", hasToolTip = false, additionalClasses = "", labelClasses = "", hasAutoFocus, onIconClick, onKeyDown, disabled, register, focusRingColor = "focus:ring-transparent", firstIconClasses, }, ref) {
|
|
6
10
|
const [isFocused, setIsFocused] = useState(false);
|
|
7
|
-
const hasValue = value != null && !!value.toString().trim();
|
|
11
|
+
const hasValue = value != null && !!value.toString().trim();
|
|
8
12
|
const isNumberInput = type === "number";
|
|
9
13
|
let formattedValue = isNumberInput &&
|
|
10
14
|
value != null &&
|
|
@@ -12,9 +16,14 @@ const InputField = forwardRef(({ label, placeholder, required = false, checked,
|
|
|
12
16
|
isNaN(Number(value))
|
|
13
17
|
? ""
|
|
14
18
|
: value;
|
|
19
|
+
// Example: sometimes number formatting can produce "NaN":
|
|
15
20
|
if (formattedValue === "$NaN") {
|
|
16
21
|
formattedValue = "";
|
|
17
22
|
}
|
|
23
|
+
const registerProps = register
|
|
24
|
+
? register(name || "", { required })
|
|
25
|
+
: {};
|
|
26
|
+
// Render icons
|
|
18
27
|
const renderFirstIcon = () => {
|
|
19
28
|
if (!firstIcon)
|
|
20
29
|
return null;
|
|
@@ -22,16 +31,18 @@ const InputField = forwardRef(({ label, placeholder, required = false, checked,
|
|
|
22
31
|
? "text-gray-500"
|
|
23
32
|
: isValid
|
|
24
33
|
? `text-${iconColor}`
|
|
25
|
-
: "text-redText"}`, children:
|
|
34
|
+
: "text-redText"}`, children: typeof firstIcon === "function" ? firstIcon() : firstIcon }));
|
|
26
35
|
};
|
|
27
36
|
const renderSecondIcon = () => {
|
|
28
37
|
if (!secondIcon)
|
|
29
38
|
return null;
|
|
30
|
-
return (_jsx("span", { onClick: onIconClick, className: `input-icon input-icon--second-icon absolute top-2 right-4
|
|
39
|
+
return (_jsx("span", { onClick: onIconClick, className: `input-icon input-icon--second-icon absolute top-2 right-4 ${disabled
|
|
31
40
|
? "text-gray-500"
|
|
32
41
|
: isValid
|
|
33
42
|
? `text-${iconColor}`
|
|
34
|
-
: "text-redText"}`, children:
|
|
43
|
+
: "text-redText"}`, children: typeof secondIcon === "function"
|
|
44
|
+
? secondIcon()
|
|
45
|
+
: secondIcon }));
|
|
35
46
|
};
|
|
36
47
|
const renderIcons = () => {
|
|
37
48
|
switch (iconPosition) {
|
|
@@ -45,25 +56,29 @@ const InputField = forwardRef(({ label, placeholder, required = false, checked,
|
|
|
45
56
|
return null;
|
|
46
57
|
}
|
|
47
58
|
};
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
: {}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
59
|
+
// If it's read-only, we show readOnlyInfo instead of an actual <input>
|
|
60
|
+
if (isReadOnly) {
|
|
61
|
+
return (_jsxs("div", { className: "input-wrapper relative", children: [renderIcons(), _jsxs("label", { htmlFor: id, className: `block font-light text-left mb-1 ${labelClasses}`, children: [label, hasToolTip && (_jsxs("span", { className: "pl-4 group", children: [_jsx(FontAwesomeIcon, { icon: faCircleInfo, className: "text-primary group-hover:text-blue-600" }), _jsx("span", { className: "opacity-0 group-hover:opacity-100 bg-gray-800 text-white text-sm rounded-md px-2 py-1 absolute top-[-14px]", children: toolTipText })] }))] }), _jsx("div", { className: `
|
|
62
|
+
text-left focus:outline-none focus:ring-2 block w-full py-2 px-2 rounded-lg
|
|
63
|
+
${firstIcon ? "pl-10" : ""}
|
|
64
|
+
${secondIcon ? "pr-10" : ""}
|
|
65
|
+
${additionalClasses}
|
|
66
|
+
`, children: readOnlyInfo })] }));
|
|
67
|
+
}
|
|
68
|
+
// Normal input mode
|
|
69
|
+
return (_jsxs(_Fragment, { children: [label && (_jsxs("label", { htmlFor: id, className: `block font-light text-left mb-1 ${labelClasses}`, children: [label, hasToolTip && (_jsxs("span", { className: "pl-4 group", children: [_jsx(FontAwesomeIcon, { icon: faCircleInfo, className: "text-primary group-hover:text-blue-600" }), _jsx("span", { className: "opacity-0 group-hover:opacity-100 bg-gray-800 text-white text-sm rounded-md px-2 py-1 absolute top-[-14px]", children: toolTipText })] }))] })), _jsxs("div", { className: "input-wrapper relative", children: [renderIcons(), _jsx("input", { ref: ref, autoComplete: "", ...registerProps, className: `
|
|
70
|
+
${focusRingColor}
|
|
71
|
+
focus:ring-1
|
|
72
|
+
focus:outline-none
|
|
73
|
+
block w-full py-2 px-2
|
|
74
|
+
outline outline-0
|
|
75
|
+
md:w-full
|
|
76
|
+
${disabled ? "border-gray-500 focus:ring-gray-500" : ""}
|
|
77
|
+
${isValid ? "" : "border-redText focus:ring-red-500"}
|
|
78
|
+
${firstIcon ? "pl-10" : ""}
|
|
79
|
+
${secondIcon ? "pr-10" : ""}
|
|
80
|
+
${isFocused ? "hover:border-transparent" : ""}
|
|
81
|
+
${additionalClasses}
|
|
82
|
+
`, autoFocus: hasAutoFocus, placeholder: placeholder, type: type, id: id, value: formattedValue, name: name, checked: type === "checkbox" ? checked : undefined, onChange: onChange, onKeyDown: onKeyDown, onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false), disabled: disabled, required: required && !hasValue })] })] }));
|
|
68
83
|
});
|
|
69
84
|
export default InputField;
|
|
@@ -5,15 +5,48 @@ const MultiSelectInput = ({ id, name, options = [], selectedValue = [], onChange
|
|
|
5
5
|
text: "Select...",
|
|
6
6
|
icon: "",
|
|
7
7
|
iconStyle: "regular",
|
|
8
|
-
}, isSearchable = true, isOpen, hasSelectAll = false, disabled = false, isLoading = false, onMenuToggle, overrideStrings, className, width = "w-72", isBoolean = false, otherProps, }) => {
|
|
8
|
+
}, isSearchable = true, isOpen, hasSelectAll = false, disabled = false, isLoading = false, onMenuToggle, overrideStrings, className, width = "w-72", isBoolean = false, otherProps, setInputSearchValue, }) => {
|
|
9
|
+
// Convert your incoming options to the shape expected by react-multi-select-component
|
|
9
10
|
const multiSelectOptions = options.map((option) => ({
|
|
10
11
|
label: option.name,
|
|
11
12
|
value: option.value,
|
|
12
13
|
}));
|
|
14
|
+
// Convert the "selectedValue" prop similarly
|
|
13
15
|
const multiSelectValue = selectedValue.map((item) => ({
|
|
14
16
|
label: item.name,
|
|
15
17
|
value: item.value,
|
|
16
18
|
}));
|
|
19
|
+
function filterOptions(baseOptions, searchText) {
|
|
20
|
+
const footer = baseOptions.find((option) => option.value === "__footer__");
|
|
21
|
+
if (!searchText) {
|
|
22
|
+
// If the parent is already 0, don't set it again
|
|
23
|
+
setInputSearchValue?.((prevCount) => {
|
|
24
|
+
if (prevCount !== 0)
|
|
25
|
+
return 0;
|
|
26
|
+
return prevCount; // no change => no re-render
|
|
27
|
+
});
|
|
28
|
+
return baseOptions;
|
|
29
|
+
}
|
|
30
|
+
// Normal filter
|
|
31
|
+
const filtered = baseOptions.filter((option) => {
|
|
32
|
+
if (option.value === "__footer__")
|
|
33
|
+
return false;
|
|
34
|
+
return option.label
|
|
35
|
+
.toLowerCase()
|
|
36
|
+
.includes(searchText.toLowerCase());
|
|
37
|
+
});
|
|
38
|
+
// Only update if it's different from current
|
|
39
|
+
setInputSearchValue?.((prevCount) => {
|
|
40
|
+
const newCount = filtered.length;
|
|
41
|
+
if (newCount !== prevCount)
|
|
42
|
+
return newCount;
|
|
43
|
+
return prevCount;
|
|
44
|
+
});
|
|
45
|
+
if (footer) {
|
|
46
|
+
return [...filtered, footer];
|
|
47
|
+
}
|
|
48
|
+
return filtered;
|
|
49
|
+
}
|
|
17
50
|
const valueRenderer = (selected, _options) => {
|
|
18
51
|
if (!selected || selected.length === 0) {
|
|
19
52
|
return (_jsxs("span", { className: "flex items-center gap-2 text-gray-500", children: [placeholder?.icon
|
|
@@ -28,6 +61,7 @@ const MultiSelectInput = ({ id, name, options = [], selectedValue = [], onChange
|
|
|
28
61
|
const handleSelectionChange = (selectedOptions) => {
|
|
29
62
|
let finalSelection = selectedOptions;
|
|
30
63
|
if (isBoolean && selectedOptions.length > 0) {
|
|
64
|
+
// If isBoolean is true, only allow one selection (last one clicked)
|
|
31
65
|
finalSelection = [selectedOptions[selectedOptions.length - 1]];
|
|
32
66
|
}
|
|
33
67
|
const mapped = finalSelection.map((opt) => ({
|
|
@@ -36,8 +70,8 @@ const MultiSelectInput = ({ id, name, options = [], selectedValue = [], onChange
|
|
|
36
70
|
}));
|
|
37
71
|
onChange(mapped);
|
|
38
72
|
};
|
|
39
|
-
return (_jsx("div", { className: width
|
|
73
|
+
return (_jsx("div", { className: `${width} `, children: _jsx(MultiSelect, { id: id, name: name, className: className, options: multiSelectOptions, value: multiSelectValue, onChange: handleSelectionChange, disableSearch: !isSearchable || isBoolean, isOpen: isOpen, hasSelectAll: hasSelectAll, disabled: disabled, isLoading: isLoading, onMenuToggle: onMenuToggle, overrideStrings: {
|
|
40
74
|
...overrideStrings,
|
|
41
|
-
}, labelledBy: "Select", valueRenderer: valueRenderer, ...otherProps }) }));
|
|
75
|
+
}, labelledBy: "Select", valueRenderer: valueRenderer, filterOptions: filterOptions, ...otherProps }) }));
|
|
42
76
|
};
|
|
43
77
|
export default MultiSelectInput;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { OptionType } from "../MultiSelect/MultiSelect.types";
|
|
3
3
|
interface SearchDropdownInputProps {
|
|
4
4
|
options?: OptionType[];
|
|
5
5
|
selectedValue?: OptionType[];
|
|
@@ -18,9 +18,8 @@ interface SearchDropdownInputProps {
|
|
|
18
18
|
[key: string]: any;
|
|
19
19
|
};
|
|
20
20
|
setEditingHeader?: React.Dispatch<React.SetStateAction<any>>;
|
|
21
|
-
/** localStorage key used to store the entire “searchCriteria” array */
|
|
22
21
|
localStorageKey?: string;
|
|
23
|
-
otherProps?:
|
|
22
|
+
otherProps?: any;
|
|
24
23
|
additionalClasses?: string;
|
|
25
24
|
clearText?: string;
|
|
26
25
|
clearTextColor?: string;
|
|
@@ -28,6 +27,8 @@ interface SearchDropdownInputProps {
|
|
|
28
27
|
buttonColor?: string;
|
|
29
28
|
isBoolean?: boolean;
|
|
30
29
|
isSearchable?: boolean;
|
|
30
|
+
fontFamily?: string;
|
|
31
|
+
pillColor?: string;
|
|
31
32
|
}
|
|
32
33
|
declare const SearchDropdownInput: React.FC<SearchDropdownInputProps>;
|
|
33
34
|
export default SearchDropdownInput;
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect } from "react";
|
|
3
|
-
import MultiSelectInput from "../MultiSelect/MultiSelect";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import MultiSelectInput from "../MultiSelect/MultiSelect"; // Adjust path as needed
|
|
4
4
|
import updateLocalStorage from "../../utils/updateLocalStorage";
|
|
5
|
+
import Badge from "../Badge";
|
|
6
|
+
import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
|
|
7
|
+
import Text from "../Text";
|
|
5
8
|
const DEFAULT_STORAGE_KEY = "searchCriteria";
|
|
6
|
-
const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, placeholder = "Select", disabled = false, hasSelectAll = true, bgColor = "bg-sky-500", textHighlight = "text-sky-700", handleFilter, searchItems = [], setSearchItems, setSearchCriteria, column, setEditingHeader, clearText = "Clear", clearTextColor = "text-sky-500", buttonText = "Filter", buttonColor = "bg-sky-500", localStorageKey = DEFAULT_STORAGE_KEY, isBoolean = false, isSearchable, ...rest }) => {
|
|
7
|
-
// Are we able to store filters for this column?
|
|
9
|
+
const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, placeholder = "Select", disabled = false, hasSelectAll = true, bgColor = "bg-sky-500", textHighlight = "text-sky-700", handleFilter, searchItems = [], setSearchItems, setSearchCriteria, column, setEditingHeader, clearText = "Clear", clearTextColor = "text-sky-500", buttonText = "Filter", buttonColor = "bg-sky-500", localStorageKey = DEFAULT_STORAGE_KEY, isBoolean = false, isSearchable, fontFamily, pillColor, ...rest }) => {
|
|
8
10
|
const canStore = !!column?.id && !!setSearchCriteria;
|
|
11
|
+
// IMPORTANT: Start at 0, not options.length.
|
|
12
|
+
// This is the # of items matched by the child's filter, updated live.
|
|
13
|
+
const [filteredCount, setFilteredCount] = useState(0);
|
|
14
|
+
// On mount, read localStorage if we have a stored selection for this column
|
|
9
15
|
useEffect(() => {
|
|
10
16
|
if (!canStore)
|
|
11
17
|
return;
|
|
@@ -14,7 +20,7 @@ const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, place
|
|
|
14
20
|
return;
|
|
15
21
|
try {
|
|
16
22
|
const parsed = JSON.parse(stored);
|
|
17
|
-
const existing = parsed.find((c) => c.searchColumn?.id === column
|
|
23
|
+
const existing = parsed.find((c) => c.searchColumn?.id === column?.id);
|
|
18
24
|
if (existing && setSearchItems) {
|
|
19
25
|
const raw = existing.submittedSearchText;
|
|
20
26
|
setSearchItems([raw]);
|
|
@@ -36,6 +42,7 @@ const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, place
|
|
|
36
42
|
onChange,
|
|
37
43
|
options,
|
|
38
44
|
]);
|
|
45
|
+
// Called when user clicks the "Filter" button in the footer
|
|
39
46
|
const handleFooterFilter = () => {
|
|
40
47
|
const actualSelections = selectedValue.filter((opt) => opt.value !== "__footer__" && opt.label !== "Select All");
|
|
41
48
|
const selectedLabels = actualSelections
|
|
@@ -47,15 +54,17 @@ const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, place
|
|
|
47
54
|
return;
|
|
48
55
|
}
|
|
49
56
|
if (isEmpty) {
|
|
57
|
+
// Remove from local storage
|
|
50
58
|
setSearchCriteria?.((prev) => {
|
|
51
|
-
const newCriteria = prev.filter((c) => c.searchColumn.id !== column
|
|
59
|
+
const newCriteria = prev.filter((c) => c.searchColumn.id !== column?.id);
|
|
52
60
|
updateLocalStorage(newCriteria, localStorageKey);
|
|
53
61
|
return newCriteria;
|
|
54
62
|
});
|
|
55
63
|
}
|
|
56
64
|
else {
|
|
65
|
+
// Store to local storage
|
|
57
66
|
setSearchCriteria?.((prev) => {
|
|
58
|
-
const filtered = prev.filter((c) => c.searchColumn.id !== column
|
|
67
|
+
const filtered = prev.filter((c) => c.searchColumn.id !== column?.id);
|
|
59
68
|
const newCriteria = [
|
|
60
69
|
...filtered,
|
|
61
70
|
{
|
|
@@ -70,11 +79,12 @@ const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, place
|
|
|
70
79
|
setEditingHeader?.(null);
|
|
71
80
|
handleFilter?.();
|
|
72
81
|
};
|
|
82
|
+
// Called when user clicks Clear
|
|
73
83
|
const handleClear = () => {
|
|
74
84
|
onChange([]);
|
|
75
85
|
if (canStore) {
|
|
76
86
|
setSearchCriteria?.((prev) => {
|
|
77
|
-
const newCriteria = prev.filter((c) => c.searchColumn.id !== column
|
|
87
|
+
const newCriteria = prev.filter((c) => c.searchColumn.id !== column?.id);
|
|
78
88
|
updateLocalStorage(newCriteria, localStorageKey);
|
|
79
89
|
return newCriteria;
|
|
80
90
|
});
|
|
@@ -82,18 +92,20 @@ const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, place
|
|
|
82
92
|
setEditingHeader?.(null);
|
|
83
93
|
}
|
|
84
94
|
};
|
|
95
|
+
// We add a “footer” item to place a Filter button, etc., at the bottom
|
|
85
96
|
const footerOption = [{ name: "", value: "__footer__" }];
|
|
86
97
|
const extendedOptions = [...options, ...footerOption];
|
|
98
|
+
// Custom item renderer referencing the parent's filteredCount
|
|
87
99
|
const itemRenderer = ({ option, checked, disabled, onClick }) => {
|
|
88
100
|
if (option.value === "__footer__") {
|
|
89
|
-
return (_jsxs("div", { className: "footer
|
|
101
|
+
return (_jsxs("div", { className: "\n footer\n px-4 py-2\n flex justify-between items-center\n text-gray-300\n border-t border-gray-300\n ", children: [filteredCount === 0 ? (_jsx("div", { onClick: handleClear, className: `${textHighlight} cursor-pointer`, children: clearText })) : (_jsxs("div", { children: [filteredCount, " Results"] })), _jsx("button", { type: "button", className: `${bgColor} ${fontFamily} text-white px-3 py-1 rounded-full`, onClick: (e) => {
|
|
90
102
|
e.stopPropagation();
|
|
91
103
|
handleFooterFilter();
|
|
92
104
|
}, children: buttonText })] }));
|
|
93
105
|
}
|
|
94
|
-
// If it's the "Select All" item
|
|
106
|
+
// If it's the "Select All" item => do something special here
|
|
95
107
|
if (option.label === "Select All") {
|
|
96
|
-
return (_jsxs("label", { className: "select-all-item", style: {
|
|
108
|
+
return (_jsxs("label", { className: "select-all-item flex justify-between items-center px-4 cursor-pointer", style: {
|
|
97
109
|
display: "flex",
|
|
98
110
|
alignItems: "center",
|
|
99
111
|
padding: "0.5rem 1rem",
|
|
@@ -104,17 +116,24 @@ const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, place
|
|
|
104
116
|
}, onClick: (e) => {
|
|
105
117
|
e.stopPropagation();
|
|
106
118
|
onClick(e);
|
|
107
|
-
}, children: [_jsx("input", { type: "checkbox", checked: checked, readOnly: true, disabled: disabled }), _jsx("span", { style: { marginLeft: "0.5rem" }, children: option.label })] })
|
|
119
|
+
}, children: [_jsxs("div", { children: [_jsx("input", { type: "checkbox", checked: checked, readOnly: true, disabled: disabled }), _jsx("span", { style: { marginLeft: "0.5rem" }, children: option.label })] }), selectedValue.length > 0 && (
|
|
120
|
+
// Example badge if you want a count
|
|
121
|
+
_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", onClick: () => console.log("Select All Badge clicked"), text: _jsx(Text, { color: "text-white", fontFamily: fontFamily, size: "text-sm", tag: "span", text: `${selectedValue.length} picked` }), badgeContainerClasses: `${pillColor} p-1 max-w-fit rounded-full flex justify-between items-center text-white text-xs px-4 border-none`, type: "span" }, option.value))] }));
|
|
108
122
|
}
|
|
123
|
+
// Normal item
|
|
109
124
|
return (_jsxs("div", { className: "item px-4 py-1 cursor-pointer flex items-center", onClick: (e) => onClick(option, e), children: [_jsx("input", { type: "checkbox", checked: checked, readOnly: true, disabled: disabled }), _jsx("span", { className: "ml-2", children: option.label })] }));
|
|
110
125
|
};
|
|
111
126
|
return (_jsx(MultiSelectInput, { options: extendedOptions, selectedValue: selectedValue, onChange: onChange, placeholder: {
|
|
112
127
|
text: placeholder,
|
|
113
128
|
icon: "magnifyingGlass",
|
|
114
129
|
iconStyle: "regular",
|
|
115
|
-
}, disabled: disabled, hasSelectAll: isBoolean ? false :
|
|
130
|
+
}, disabled: disabled, hasSelectAll: isBoolean ? false : hasSelectAll,
|
|
131
|
+
// Provide our custom item renderer
|
|
132
|
+
otherProps: {
|
|
116
133
|
ItemRenderer: itemRenderer,
|
|
117
134
|
...rest.otherProps,
|
|
118
|
-
}, isBoolean: isBoolean, isSearchable: isSearchable,
|
|
135
|
+
}, isBoolean: isBoolean, isSearchable: isSearchable,
|
|
136
|
+
// The child calls this to update how many items are matched by the current search
|
|
137
|
+
setInputSearchValue: setFilteredCount, ...rest }));
|
|
119
138
|
};
|
|
120
139
|
export default SearchDropdownInput;
|
|
@@ -8,7 +8,7 @@ const SearchInput = ({ textHighlight = "text-sky-500", inputType = "text", dropd
|
|
|
8
8
|
name: "chevronDown",
|
|
9
9
|
weight: "bold",
|
|
10
10
|
iconClasses: "text-black",
|
|
11
|
-
}, dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, searchItems = [], setSearchItems, toggleStatus = false, setToggleStatus, minValue, setMinValue, maxValue, setMaxValue, onChange, selectedValue, selectedDate, onDateSelect, selectedStartDate, onStartDateSelect, selectedEndDate, onEndDateSelect, handleFilter, column, setSearchCriteria, setEditingHeader, pillColor, firstIconClasses, dataPickerThemeColor, dataPickerThemeColorAccent, isBoolean = false, toggleColor = "bg-sky-500", toggleTextColor = "text-black", fontFamily, removePattern
|
|
11
|
+
}, dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, searchItems = [], setSearchItems, toggleStatus = false, setToggleStatus, minValue, setMinValue, maxValue, setMaxValue, onChange, selectedValue, selectedDate, onDateSelect, selectedStartDate, onStartDateSelect, selectedEndDate, onEndDateSelect, handleFilter, column, setSearchCriteria, setEditingHeader, pillColor, firstIconClasses, dataPickerThemeColor, dataPickerThemeColorAccent, isBoolean = false, toggleColor = "bg-sky-500", toggleTextColor = "text-black", fontFamily, removePattern = /^[^:]*:/, isSearchable = false, }) => {
|
|
12
12
|
const containerRef = useRef(null);
|
|
13
13
|
const inputRef = useRef(null);
|
|
14
14
|
useEffect(() => {
|
|
@@ -21,9 +21,9 @@ const SearchInput = ({ textHighlight = "text-sky-500", inputType = "text", dropd
|
|
|
21
21
|
//will remove the filter options from the badge shown in the input
|
|
22
22
|
removePattern: removePattern, textHighlight: textHighlight }));
|
|
23
23
|
case "number":
|
|
24
|
-
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, setSearchCriteria: setSearchCriteria, column: column, themeBgColor: dataPickerThemeColor, toggleColor: toggleColor, toggleTextColor: toggleTextColor }));
|
|
24
|
+
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, setSearchCriteria: setSearchCriteria, column: column, themeBgColor: dataPickerThemeColor, toggleColor: toggleColor, toggleTextColor: toggleTextColor, searchItems: searchItems, setSearchItems: setSearchItems, removePattern: removePattern, pillColor: pillColor }));
|
|
25
25
|
case "multiSelect":
|
|
26
|
-
return (_jsx(SearchDropdownInput, { options: dropdownOptions, placeholder: "Search", additionalClasses: "", onChange: onChange, selectedValue: selectedValue, bgColor: dataPickerThemeColor, clearText: "Clear", clearTextColor: "text-sky-500", buttonText: "Filter", handleFilter: handleFilter, column: column, setSearchCriteria: setSearchCriteria, textHighlight: textHighlight, isBoolean: isBoolean, isSearchable: isSearchable }));
|
|
26
|
+
return (_jsx(SearchDropdownInput, { options: dropdownOptions, placeholder: "Search", additionalClasses: "", onChange: onChange, selectedValue: selectedValue, bgColor: dataPickerThemeColor, clearText: "Clear", clearTextColor: "text-sky-500", buttonText: "Filter", handleFilter: handleFilter, column: column, setSearchCriteria: setSearchCriteria, textHighlight: textHighlight, isBoolean: isBoolean, isSearchable: isSearchable, setSearchItems: setSearchItems, fontFamily: fontFamily, pillColor: pillColor }));
|
|
27
27
|
case "date":
|
|
28
28
|
return (_jsx(SearchDatePickerInput, { textHighlight: textHighlight, dropdownOptions: dropdownOptions, toggleStatus: toggleStatus, setToggleStatus: setToggleStatus, selectedDate: selectedDate, onDateSelect: onDateSelect, selectedStartDate: selectedStartDate, onStartDateSelect: onStartDateSelect, selectedEndDate: selectedEndDate, onEndDateSelect: onEndDateSelect, handleFilter: handleFilter, themeBgColor: dataPickerThemeColor, lightThemeBg: dataPickerThemeColorAccent, setSearchCriteria: setSearchCriteria, column: column, setEditingHeader: setEditingHeader, searchItems: searchItems, setSearchItems: setSearchItems, pillColor: pillColor, toggleColor: toggleColor, toggleTextColor: toggleTextColor, fontFamily: fontFamily, removePattern: removePattern, dropdownIconProp: dropdownIconProp }));
|
|
29
29
|
default:
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Meta } from "@storybook/react";
|
|
2
2
|
declare const _default: Meta;
|
|
3
3
|
export default _default;
|
|
4
|
+
/**
|
|
5
|
+
* 5) Create different stories from the template.
|
|
6
|
+
*/
|
|
4
7
|
export declare const Default: any;
|
|
5
8
|
export declare const TextInput: any;
|
|
6
9
|
export declare const NumberInput: any;
|
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import SearchInput from "./SearchInput";
|
|
3
|
-
import { useState } from "react";
|
|
3
|
+
import { useState, useCallback, useMemo } from "react";
|
|
4
|
+
// 1) Provide a stable "mock column"
|
|
4
5
|
const mockColumn = {
|
|
5
6
|
id: "mockColumn",
|
|
6
7
|
Header: "Mock Column",
|
|
7
8
|
};
|
|
9
|
+
// 2) We define stable arrays for the controls to avoid re-creating them
|
|
10
|
+
const textDropdownOptions = [
|
|
11
|
+
{ label: "Starts with", value: "startsWith" },
|
|
12
|
+
{ label: "Ends with", value: "endsWith" },
|
|
13
|
+
{ label: "Exactly", value: "exactly" },
|
|
14
|
+
{ label: "Includes", value: "includes" },
|
|
15
|
+
{ label: "Excludes", value: "excludes" },
|
|
16
|
+
];
|
|
17
|
+
const multiSelectOptions = [
|
|
18
|
+
{ uuid: "1", name: "Option 1", value: "option1" },
|
|
19
|
+
{ uuid: "2", name: "Option 2", value: "option2" },
|
|
20
|
+
{ uuid: "3", name: "Option 3", value: "option3" },
|
|
21
|
+
];
|
|
22
|
+
// 3) Standard default export
|
|
8
23
|
export default {
|
|
9
24
|
title: "Components/SearchInput",
|
|
10
25
|
component: SearchInput,
|
|
@@ -39,7 +54,13 @@ export default {
|
|
|
39
54
|
},
|
|
40
55
|
parameters: { layout: "centered" },
|
|
41
56
|
};
|
|
57
|
+
/**
|
|
58
|
+
* 4) Our template story
|
|
59
|
+
* - We store state for things like selectedValue, searchItems, etc.
|
|
60
|
+
* - We memoize certain arrays & callbacks to avoid re-creating them every render.
|
|
61
|
+
*/
|
|
42
62
|
const Template = (args) => {
|
|
63
|
+
// 4A) State for various input behaviors
|
|
43
64
|
const [selectedOption, setSelectedOption] = useState(args.selectedDropdownOption);
|
|
44
65
|
const [searchItems, setSearchItems] = useState([]);
|
|
45
66
|
const [toggleStatus, setToggleStatus] = useState(false);
|
|
@@ -55,39 +76,44 @@ const Template = (args) => {
|
|
|
55
76
|
const [searchCriteria, setSearchCriteria] = useState([]);
|
|
56
77
|
// For controlling "editingHeader"
|
|
57
78
|
const [editingHeader, setEditingHeader] = useState(0);
|
|
58
|
-
//
|
|
79
|
+
// Just for debugging. Remove if it triggers too many logs:
|
|
59
80
|
console.log("Template render: editingHeader =", editingHeader);
|
|
60
81
|
console.log("Template render: searchCriteria =", searchCriteria);
|
|
61
|
-
|
|
62
|
-
|
|
82
|
+
/**
|
|
83
|
+
* 4B) Memoize your arrays & callbacks
|
|
84
|
+
* If the user passes them in as story args, that might be stable enough,
|
|
85
|
+
* but we can do it again here just in case.
|
|
86
|
+
*/
|
|
87
|
+
const stableDropdownOptions = useMemo(() => args.dropdownOptions || [], [args.dropdownOptions]);
|
|
88
|
+
const handleOnChange = useCallback((newSelected) => {
|
|
63
89
|
setSelectedValue(newSelected);
|
|
90
|
+
// If the story user provided an onChange, call it
|
|
64
91
|
args.onChange?.(newSelected);
|
|
65
92
|
console.log("Selected items:", newSelected);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// Our local states
|
|
69
|
-
selectedDropdownOption: selectedOption, onDropdownOptionSelect: (option) =>
|
|
93
|
+
}, [args]);
|
|
94
|
+
const handleDropdownOptionSelect = useCallback((option) => {
|
|
70
95
|
// Transform the received object into an OptionType.
|
|
71
96
|
setSelectedOption({
|
|
72
97
|
uuid: "dummy-id", // You can generate or pass a real uuid here.
|
|
73
98
|
label: option.label,
|
|
74
99
|
value: option.value,
|
|
75
100
|
name: "dummy-name",
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
|
|
101
|
+
});
|
|
102
|
+
}, []);
|
|
103
|
+
return (_jsx(SearchInput, { ...args, column: mockColumn,
|
|
104
|
+
// States from the story
|
|
105
|
+
selectedDropdownOption: selectedOption, onDropdownOptionSelect: handleDropdownOptionSelect, 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, removePattern: /^[^:]*:/, pillColor: "bg-sky-500",
|
|
106
|
+
// Overwrite the dropdownOptions with our memoized version
|
|
107
|
+
dropdownOptions: stableDropdownOptions }));
|
|
79
108
|
};
|
|
109
|
+
/**
|
|
110
|
+
* 5) Create different stories from the template.
|
|
111
|
+
*/
|
|
80
112
|
export const Default = Template.bind({});
|
|
81
113
|
Default.args = {
|
|
82
114
|
inputType: "text",
|
|
83
115
|
handleFilter: () => console.log("Filter applied"),
|
|
84
|
-
dropdownOptions:
|
|
85
|
-
{ label: "Starts with", value: "startsWith" },
|
|
86
|
-
{ label: "Ends with", value: "endsWith" },
|
|
87
|
-
{ label: "Exactly", value: "exactly" },
|
|
88
|
-
{ label: "Includes", value: "includes" },
|
|
89
|
-
{ label: "Excludes", value: "excludes" },
|
|
90
|
-
],
|
|
116
|
+
dropdownOptions: textDropdownOptions,
|
|
91
117
|
selectedDropdownOption: { label: "Starts with", value: "startsWith" },
|
|
92
118
|
};
|
|
93
119
|
export const TextInput = Template.bind({});
|
|
@@ -101,13 +127,8 @@ TextInput.args = {
|
|
|
101
127
|
name: "chevronDown",
|
|
102
128
|
weight: "solid",
|
|
103
129
|
},
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
"Ends with",
|
|
107
|
-
"Exactly",
|
|
108
|
-
"Includes",
|
|
109
|
-
"Excludes",
|
|
110
|
-
],
|
|
130
|
+
// Use a stable array for the story
|
|
131
|
+
dropdownOptions: textDropdownOptions,
|
|
111
132
|
selectedDropdownOption: { label: "Starts with", value: "startsWith" },
|
|
112
133
|
};
|
|
113
134
|
export const NumberInput = Template.bind({});
|
|
@@ -133,11 +154,8 @@ DropdownInput.args = {
|
|
|
133
154
|
inputType: "multiSelect",
|
|
134
155
|
handleFilter: () => console.log("Filter applied"),
|
|
135
156
|
placeholder: "Search",
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
{ uuid: "2", name: "Option 2", value: "option2" },
|
|
139
|
-
{ uuid: "3", name: "Option 3", value: "option3" },
|
|
140
|
-
],
|
|
157
|
+
// Provide stable array of multiSelect items
|
|
158
|
+
dropdownOptions: multiSelectOptions,
|
|
141
159
|
selectedValue: [],
|
|
142
160
|
isSearchable: true,
|
|
143
161
|
hasSelectAll: true,
|
|
@@ -178,20 +196,9 @@ DatePickerInput.args = {
|
|
|
178
196
|
],
|
|
179
197
|
selectedDropdownOption: { label: "Starts with", value: "startsWith" },
|
|
180
198
|
onDropdownOptionSelect: (option) => console.log(`Option selected: ${option}`),
|
|
181
|
-
/**
|
|
182
|
-
* IMPORTANT:
|
|
183
|
-
* DO NOT override 'searchItems' or 'setSearchItems' with no-ops
|
|
184
|
-
* or you lose the local state from the Template.
|
|
185
|
-
*
|
|
186
|
-
* DO NOT pass toggleStatus, setToggleStatus as no-ops, or you won't see range toggling.
|
|
187
|
-
*
|
|
188
|
-
* Keep them out so we use the Template's state-based hooking.
|
|
189
|
-
*/
|
|
190
|
-
// Theming for DayPicker
|
|
191
199
|
themeBgColor: "bg-sky-500",
|
|
192
200
|
lightThemeBg: "bg-sky-100",
|
|
193
201
|
toggleTextColor: "text-green-500",
|
|
194
202
|
toggleColor: "bg-green-500",
|
|
195
|
-
|
|
196
|
-
column: { id: "dateColumn" }, // real or mock
|
|
203
|
+
column: { id: "dateColumn" },
|
|
197
204
|
};
|
|
@@ -40,6 +40,8 @@ type SearchNumberInputProps<T extends object> = {
|
|
|
40
40
|
themeBgColor?: string;
|
|
41
41
|
toggleColor?: string;
|
|
42
42
|
toggleTextColor?: string;
|
|
43
|
+
removePattern?: RegExp | string;
|
|
44
|
+
fontFamily?: string;
|
|
43
45
|
};
|
|
44
46
|
/**
|
|
45
47
|
* A numeric filter component that:
|
|
@@ -47,5 +49,5 @@ type SearchNumberInputProps<T extends object> = {
|
|
|
47
49
|
* 2. On Filter => either remove or store a string in localStorage
|
|
48
50
|
* 3. On mount => read any existing filter for this column, parse, and set min/max
|
|
49
51
|
*/
|
|
50
|
-
declare const SearchNumberInput: <T extends object>({ textHighlight, dropdownIconProp, dropdownOptions, selectedDropdownOption, onDropdownOptionSelect, toggleStatus, setToggleStatus, minValue, setMinValue, maxValue, setMaxValue, handleFilter, searchItems, setSearchItems, setSearchCriteria, column, setEditingHeader, localStorageKey, themeBgColor, toggleColor, toggleTextColor, }: SearchNumberInputProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
52
|
+
declare const SearchNumberInput: <T extends object>({ textHighlight, dropdownIconProp, dropdownOptions, selectedDropdownOption, onDropdownOptionSelect, toggleStatus, setToggleStatus, minValue, setMinValue, maxValue, setMaxValue, handleFilter, searchItems, setSearchItems, setSearchCriteria, column, setEditingHeader, localStorageKey, themeBgColor, toggleColor, toggleTextColor, pillColor, fontFamily, removePattern, }: SearchNumberInputProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
51
53
|
export default SearchNumberInput;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useCallback } from "react";
|
|
3
3
|
import { Input } from "../Input";
|
|
4
4
|
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
|
+
import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
|
|
9
|
+
import { getCleanedText } from "../../utils/getCleanedText";
|
|
10
|
+
import Badge from "../Badge";
|
|
11
|
+
import updateLocalStorage from "../../utils/updateLocalStorage";
|
|
8
12
|
const DEFAULT_STORAGE_KEY = "searchCriteria";
|
|
9
13
|
/**
|
|
10
14
|
* A numeric filter component that:
|
|
@@ -18,7 +22,7 @@ const SearchNumberInput = ({ textHighlight = "text-sky-500", dropdownIconProp =
|
|
|
18
22
|
weight: "solid",
|
|
19
23
|
}, dropdownOptions = [], selectedDropdownOption = { label: "", value: "" }, onDropdownOptionSelect, toggleStatus = false, setToggleStatus, minValue = "", setMinValue, maxValue = "", setMaxValue, handleFilter,
|
|
20
24
|
// local-storage
|
|
21
|
-
searchItems = [], setSearchItems, setSearchCriteria, column, setEditingHeader, localStorageKey = DEFAULT_STORAGE_KEY, themeBgColor = "bg-sky-500", toggleColor = "bg-sky-500", toggleTextColor = "text-black", }) => {
|
|
25
|
+
searchItems = [], setSearchItems, setSearchCriteria, column, setEditingHeader, localStorageKey = DEFAULT_STORAGE_KEY, themeBgColor = "bg-sky-500", toggleColor = "bg-sky-500", toggleTextColor = "text-black", pillColor, fontFamily, removePattern, }) => {
|
|
22
26
|
const containerRef = useRef(null);
|
|
23
27
|
const inputRef = useRef(null);
|
|
24
28
|
/** Decide if we can store for this column */
|
|
@@ -147,12 +151,25 @@ searchItems = [], setSearchItems, setSearchCriteria, column, setEditingHeader, l
|
|
|
147
151
|
// Let the parent know a filter was applied
|
|
148
152
|
handleFilter?.();
|
|
149
153
|
};
|
|
150
|
-
|
|
151
|
-
|
|
154
|
+
const handleSearchBadgeClick = (item) => {
|
|
155
|
+
const newSearchItems = searchItems.filter((ele) => ele !== item);
|
|
156
|
+
setSearchItems && setSearchItems(newSearchItems);
|
|
157
|
+
setSearchCriteria((prev) => {
|
|
158
|
+
const newCriteria = prev.filter((crit) => crit.submittedSearchText !== item);
|
|
159
|
+
updateLocalStorage(newCriteria, localStorageKey);
|
|
160
|
+
console.log("Removed badge criterion, newCriteria:", newCriteria);
|
|
161
|
+
return newCriteria;
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
return (_jsx("div", { ref: containerRef, className: "w-[425px]", children: _jsxs("div", { className: "flex flex-col pt-4 p pb-1 border-2 border-navy-200 rounded-md", children: [_jsx("div", { className: `flex flex-[1] mx-4 ${toggleStatus ? "" : "border-2"}
|
|
165
|
+
h-full max-h-11 items-center justify-around`, children: toggleStatus ? (_jsxs("div", { className: "flex items-center", children: [_jsx(Input, { focusRingColor: "focus:ring-2 ", hasAutoFocus: true, value: minValue, iconColor: "text-navy-400", required: false, id: "", name: "", type: "number", onChange: (e) => setMinValue?.(e.target.value), additionalClasses: "min-w-[180px] max-w-[180px] h-10 text-gray flex focus:border-l-2 border-2", 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", required: false, id: "", name: "", type: "number", onChange: (e) => setMaxValue?.(e.target.value), additionalClasses: "min-w-[180px] max-w-[180px] h-10 text-gray flex border-2 focus:border-l-2 ", placeholder: "Max" })] })) : (
|
|
152
166
|
// Single value mode
|
|
153
167
|
_jsxs(_Fragment, { children: [_jsx(Dropdown, { options: dropdownOptions, selectedOption: selectedDropdownOption || {
|
|
154
168
|
label: "",
|
|
155
169
|
value: "",
|
|
156
|
-
}, 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, { ref: inputRef, focusRingColor: "focus:ring-transparent", hasAutoFocus: true, value: minValue, iconColor: "text-navy-400", required: false, id: "", name: "", type: "number", onChange: (e) => setMinValue?.(e.target.value), 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
|
|
170
|
+
}, 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, { ref: inputRef, focusRingColor: "focus:ring-transparent", hasAutoFocus: true, value: minValue, iconColor: "text-navy-400", required: false, id: "", name: "", type: "number", onChange: (e) => setMinValue?.(e.target.value), 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 py-1 px-4", children: [_jsx(ToggleButton, { initialStatus: toggleStatus, onClick: () => setToggleStatus?.(!toggleStatus), activeColorBackground: toggleColor, activeColorBorder: "border-sky-500", activeLabel: "Range", activeTextColor: toggleTextColor, 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: themeBgColor, additionalClasses: "py-1.5 px-6 text-white", borderColor: "border-none", onClick: handleFilterClick, shape: "rounded-full" })] }), searchItems?.length ? (_jsx("div", { className: "border-t border-gray-300 ", children: _jsx("div", { className: "flex flex-wrap bg-white pt-2 px-4 rounded-md", children: searchItems.map((item, index) => {
|
|
171
|
+
const cleanedText = getCleanedText(item, removePattern);
|
|
172
|
+
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: fontFamily, size: "text-sm", tag: "span", text: cleanedText }), badgeContainerClasses: `${pillColor} cursor-pointer 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));
|
|
173
|
+
}) }) })) : null] }) }));
|
|
157
174
|
};
|
|
158
175
|
export default SearchNumberInput;
|
|
@@ -91,9 +91,7 @@ const SearchTextInput = ({ pillColor = "bg-sky-500", textHighlight = "text-sky-5
|
|
|
91
91
|
};
|
|
92
92
|
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 || { label: "", value: "" }, onOptionSelect: onDropdownOptionSelect, optionClasses: "px-4 py-1 h-full flex items-center", menuClasses: "bg-white min-w-32xw rounded-md shadow-md", icon: dropdownIconProp, dropdownClasses: "border-0 border-r-2 w-auto " }), _jsx(Input, { focusRingColor: "focus:ring-transparent", hasAutoFocus: true, value: getCleanedText(localSearchText, removePattern), iconColor: "text-navy-400", onKeyDown: handleKeyDown, required: false, id: "", name: "", type: "text", firstIconClasses: firstIconClasses, 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: () => setLocalSearchText(""), "data-testid": "clear-icon", children: getFontAwesomeIcon("xmark", "regular") }), _jsx("div", { className: `${textHighlight} text-sm hover:text-primary`, children: getFontAwesomeIcon("search", "solid") })] })) }) }), onIconClick: () => setLocalSearchText("") })] }), searchItems?.length ? (_jsx("div", { className: "flex flex-wrap bg-white py-2 px-2 rounded-md", children: searchItems.map((item, index) => {
|
|
93
93
|
const cleanedText = getCleanedText(item, removePattern);
|
|
94
|
-
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: fontFamily, size: "text-sm", tag: "span",
|
|
95
|
-
// Render only the cleaned text
|
|
96
|
-
text: cleanedText }), 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));
|
|
94
|
+
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: fontFamily, size: "text-sm", tag: "span", text: cleanedText }), 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));
|
|
97
95
|
}) })) : null] }) }));
|
|
98
96
|
};
|
|
99
97
|
export default SearchTextInput;
|