@agilant/toga-blox 1.0.47 → 1.0.49

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.
Files changed (33) hide show
  1. package/dist/components/Badge/Badge.js +1 -1
  2. package/dist/components/Dropdown/Dropdown.js +1 -1
  3. package/dist/components/HeaderFilterIcon/HeaderFilterIcon.d.ts +4 -0
  4. package/dist/components/HeaderFilterIcon/HeaderFilterIcon.js +60 -0
  5. package/dist/components/HeaderFilterIcon/HeaderFilterIcon.stories.d.ts +9 -0
  6. package/dist/components/HeaderFilterIcon/HeaderFilterIcon.stories.js +76 -0
  7. package/dist/components/HeaderFilterIcon/HeaderFilterIcon.test.d.ts +1 -0
  8. package/dist/components/HeaderFilterIcon/HeaderFilterIcon.test.js +104 -0
  9. package/dist/components/HeaderFilterIcon/index.d.ts +2 -0
  10. package/dist/components/HeaderFilterIcon/index.js +2 -0
  11. package/dist/components/HeaderFilterIcon/types.d.ts +22 -0
  12. package/dist/components/HeaderFilterIcon/types.js +1 -0
  13. package/dist/components/Input/Input.js +3 -3
  14. package/dist/components/InputAndCheck/InputAndCheck.js +0 -9
  15. package/dist/components/MagnifyingIcon/MagnifyingIcon.js +1 -1
  16. package/dist/components/MagnifyingIcon/MagnifyingIcon.stories.js +1 -0
  17. package/dist/components/PrimaryTableHeader/PrimaryTableHeader.js +2 -2
  18. package/dist/components/SearchInput/SearchDropdownInput.d.ts +1 -0
  19. package/dist/components/SearchInput/SearchDropdownInput.js +2 -3
  20. package/dist/components/SearchInput/SearchInput.d.ts +1 -1
  21. package/dist/components/SearchInput/SearchInput.js +9 -51
  22. package/dist/components/SearchInput/SearchInput.stories.d.ts +1 -1
  23. package/dist/components/SearchInput/SearchInput.stories.js +32 -53
  24. package/dist/components/SearchInput/SearchInput.test.d.ts +1 -0
  25. package/dist/components/SearchInput/SearchInput.test.js +519 -0
  26. package/dist/components/SearchInput/SearchInput.types.d.ts +8 -12
  27. package/dist/components/SearchInput/SearchInputDatePicker.d.ts +23 -0
  28. package/dist/components/SearchInput/SearchInputDatePicker.js +72 -0
  29. package/dist/components/SearchInput/SearchNumberInput.d.ts +2 -14
  30. package/dist/components/SearchInput/SearchNumberInput.js +16 -35
  31. package/dist/components/SearchInput/SearchTextInput.d.ts +2 -11
  32. package/dist/components/SearchInput/SearchTextInput.js +8 -27
  33. package/package.json +2 -1
@@ -4,6 +4,6 @@ const Badge = ({ borderColor, borderWidth, borderRadius, backgroundColor, hasMob
4
4
  const badgeBackgroundClasses = `${backgroundColor}`;
5
5
  const badgeBorderClasses = `${borderWidth} ${borderColor} ${borderRadius}`;
6
6
  const badgeClasses = `inline-flex items-center ${badgeBorderClasses} ${badgeBackgroundClasses} ${badgeContainerClasses}`;
7
- return (_jsxs("span", { onClick: onClick, "data-testid": "badge-test-id", className: badgeClasses, style: styles, children: [image && _jsx("span", { className: "mr-2", children: image }), icon && hasLeftIcon && (_jsx("span", { className: `${iconClasses} max-md:hidden mr-2`, children: icon })), mobileIcon && hasMobileStyle && (_jsx("span", { className: `${iconClasses} hidden max-md:flex max-md:p-0 mr-2`, "aria-hidden": "false", "aria-label": mobileIconLabel, children: mobileIcon })), _jsx("div", { className: `${hasMobileStyle ? "max-md:hidden" : ""}`, children: text }), icon && hasRightIcon && (_jsx("span", { className: `${iconClasses} max-md:hidden ml-2`, children: icon }))] }));
7
+ return (_jsxs("span", { onClick: onClick, "data-testid": "badge-test-id", className: badgeClasses, style: styles, children: [image && _jsx("span", { className: "mr-2", children: image }), icon && hasLeftIcon && (_jsx("span", { className: `${iconClasses} max-md:hidden mr-2`, children: icon })), mobileIcon && hasMobileStyle && (_jsx("span", { className: `${iconClasses} hidden max-md:flex max-md:p-0 mr-2`, "aria-hidden": "false", "aria-label": mobileIconLabel, children: mobileIcon })), _jsx("div", { className: `${hasMobileStyle ? "max-md:hidden" : ""}`, children: text }), icon && hasRightIcon && (_jsx("span", { className: `${iconClasses} ${hasMobileStyle ? "max-md:hidden" : ""} ml-2`, children: icon }))] }));
8
8
  };
9
9
  export default Badge;
@@ -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 border-2 ${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"}`, children: _jsx("span", { 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
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);
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import { HeaderFilterIconProps } from "./types";
3
+ declare const HeaderFilterIcon: React.ForwardRefExoticComponent<HeaderFilterIconProps<any> & React.RefAttributes<HTMLDivElement>>;
4
+ export default HeaderFilterIcon;
@@ -0,0 +1,60 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef, useEffect, useState } from "react";
3
+ import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
4
+ const HeaderFilterIcon = forwardRef(({ columnIndex, editingHeader, setEditingHeader, setHeaderValue, column, setActiveColumn, iconColor = "text-blue-500", iconActiveColor = "text-green-500", iconActiveBackgroundColor = "bg-red-500", isActive, additionalIconClasses, setSearchText, searchText, isSearchOpen, icon = {
5
+ icon: "magnifyingGlass",
6
+ weight: "regular",
7
+ }, }, ref) => {
8
+ const [showActiveStyles, setShowActiveStyles] = useState(false);
9
+ useEffect(() => {
10
+ if (isActive !== undefined) {
11
+ setShowActiveStyles(isActive);
12
+ }
13
+ else {
14
+ const checkSearchCriteria = () => {
15
+ const searchCriteriaRaw = localStorage.getItem("searchCriteria");
16
+ let searchCriteria = [];
17
+ try {
18
+ if (searchCriteriaRaw) {
19
+ searchCriteria = JSON.parse(searchCriteriaRaw);
20
+ }
21
+ }
22
+ catch (e) {
23
+ console.error("Failed to parse searchCriteria from localStorage:", e);
24
+ searchCriteria = [];
25
+ }
26
+ const hasSearchValue = searchCriteria.some((item) => String(item.searchColumn.id) ===
27
+ String(column.id) &&
28
+ item.submittedSearchText &&
29
+ item.submittedSearchText.trim() !== "");
30
+ setShowActiveStyles(hasSearchValue || editingHeader === columnIndex);
31
+ };
32
+ checkSearchCriteria();
33
+ const handleStorageEvent = () => {
34
+ checkSearchCriteria();
35
+ };
36
+ window.addEventListener("localStorageUpdate", handleStorageEvent);
37
+ return () => {
38
+ window.removeEventListener("localStorageUpdate", handleStorageEvent);
39
+ };
40
+ }
41
+ }, [isActive, editingHeader, column.id, columnIndex]);
42
+ useEffect(() => {
43
+ if (isSearchOpen) {
44
+ console.log("Search is open with text:", searchText);
45
+ }
46
+ }, [isSearchOpen, searchText]);
47
+ const handleClick = (event) => {
48
+ event.stopPropagation();
49
+ if (!isSearchOpen) {
50
+ setSearchText?.("");
51
+ }
52
+ setEditingHeader(columnIndex);
53
+ setHeaderValue(column.Header);
54
+ setActiveColumn(columnIndex);
55
+ };
56
+ 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
57
+ ? `${iconActiveBackgroundColor} hover:bg-blue-500 still-active`
58
+ : "hover:bg-white"}`, onClick: handleClick, children: _jsx("div", { className: `text-xs w-full ${additionalIconClasses} `, children: getFontAwesomeIcon(icon.icon, icon.weight) }) }));
59
+ });
60
+ export default HeaderFilterIcon;
@@ -0,0 +1,9 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import HeaderFilterIcon from "./HeaderFilterIcon";
3
+ declare const meta: Meta<typeof HeaderFilterIcon>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof HeaderFilterIcon>;
6
+ export declare const Default: Story;
7
+ export declare const WithActiveClass: Story;
8
+ export declare const WithClickAlert: Story;
9
+ export declare const WithMockLocalStorage: Story;
@@ -0,0 +1,76 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import HeaderFilterIcon from "./HeaderFilterIcon";
3
+ const meta = {
4
+ title: "Table/HeaderFilterIcon",
5
+ component: HeaderFilterIcon,
6
+ tags: ["autodocs"],
7
+ argTypes: {
8
+ columnIndex: { control: "number" },
9
+ editingHeader: { control: "number" },
10
+ isActive: { control: "boolean" },
11
+ additionalIconClasses: { control: "text" },
12
+ icon: { icon: "x", weight: "regular" },
13
+ },
14
+ // Add a decorator to wrap all stories in a div
15
+ decorators: [
16
+ (Story) => (_jsx("div", { style: {
17
+ padding: "20px",
18
+ borderRadius: "8px",
19
+ width: "fit-content",
20
+ }, children: _jsx(Story, {}) })),
21
+ ],
22
+ };
23
+ export default meta;
24
+ const mockColumnInstance = {
25
+ id: "exampleColumn",
26
+ Header: "Example Column",
27
+ isVisible: true,
28
+ render: () => _jsx("div", { children: "Mock Column" }),
29
+ };
30
+ // Default story (without active class)
31
+ export const Default = {
32
+ args: {
33
+ columnIndex: 0,
34
+ editingHeader: null,
35
+ setEditingHeader: () => { },
36
+ setHeaderValue: () => { },
37
+ additionalIconClasses: "p-4",
38
+ column: mockColumnInstance,
39
+ setActiveColumn: () => { },
40
+ isActive: false,
41
+ },
42
+ };
43
+ // Story with active class
44
+ export const WithActiveClass = {
45
+ args: {
46
+ ...Default.args,
47
+ isActive: true,
48
+ additionalIconClasses: "text-green-500",
49
+ icon: { icon: "x", weight: "regular" },
50
+ },
51
+ };
52
+ export const WithClickAlert = {
53
+ args: {
54
+ ...Default.args,
55
+ setEditingHeader: (columnIndex) => {
56
+ alert(`the column index and data have been updated! Column Index =` +
57
+ columnIndex);
58
+ },
59
+ },
60
+ };
61
+ export const WithMockLocalStorage = {
62
+ args: {
63
+ ...Default.args,
64
+ },
65
+ decorators: [
66
+ (Story) => {
67
+ localStorage.setItem("searchCriteria", JSON.stringify([
68
+ {
69
+ searchColumn: { id: "exampleColumn" },
70
+ submittedSearchText: "test",
71
+ },
72
+ ]));
73
+ return _jsx(Story, {});
74
+ },
75
+ ],
76
+ };
@@ -0,0 +1,104 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, it, expect, vi, beforeEach } from "vitest";
3
+ import { render, fireEvent, screen, waitFor } from "@testing-library/react";
4
+ import HeaderFilterIcon from "./HeaderFilterIcon";
5
+ describe("HeaderFilterIcon", () => {
6
+ const mockSetEditingHeader = vi.fn();
7
+ const mockSetHeaderValue = vi.fn();
8
+ const mockSetSearchColumn = vi.fn();
9
+ const mockSetActiveColumnFromSearch = vi.fn();
10
+ const mockSetActiveColumn = vi.fn();
11
+ const mockColumn = {
12
+ id: "exampleColumn",
13
+ Header: "Example Column",
14
+ isVisible: true,
15
+ render: vi.fn(),
16
+ };
17
+ const defaultProps = {
18
+ columnIndex: 2,
19
+ editingHeader: null,
20
+ setEditingHeader: mockSetEditingHeader,
21
+ setHeaderValue: mockSetHeaderValue,
22
+ column: mockColumn,
23
+ setSearchColumn: mockSetSearchColumn,
24
+ setActiveColumnFromSearch: mockSetActiveColumnFromSearch,
25
+ setActiveColumn: mockSetActiveColumn,
26
+ };
27
+ beforeEach(() => {
28
+ vi.clearAllMocks();
29
+ localStorage.clear();
30
+ });
31
+ it("renders without crashing", () => {
32
+ render(_jsx(HeaderFilterIcon, { ...defaultProps }));
33
+ const iconDiv = screen.getByTestId("magnifying-icon-test-id");
34
+ expect(iconDiv).toBeInTheDocument();
35
+ });
36
+ it("calls the appropriate props on click", () => {
37
+ render(_jsx(HeaderFilterIcon, { ...defaultProps }));
38
+ const iconDiv = screen.getByTestId("magnifying-icon-test-id");
39
+ fireEvent.click(iconDiv);
40
+ // Because setEditingHeader, setHeaderValue, and setActiveColumn
41
+ // are all called synchronously, we can just do normal expects:
42
+ expect(mockSetEditingHeader).toHaveBeenCalledWith(2);
43
+ expect(mockSetHeaderValue).toHaveBeenCalledWith("Example Column");
44
+ expect(mockSetActiveColumn).toHaveBeenCalledWith(2);
45
+ });
46
+ it("applies active styles if localStorage has matching search criteria", () => {
47
+ const fakeCriteria = [
48
+ {
49
+ searchColumn: { id: "exampleColumn" },
50
+ submittedSearchText: "Hello World",
51
+ },
52
+ ];
53
+ localStorage.setItem("searchCriteria", JSON.stringify(fakeCriteria));
54
+ render(_jsx(HeaderFilterIcon, { ...defaultProps }));
55
+ const iconDiv = screen.getByTestId("magnifying-icon-test-id");
56
+ // Now "active" means we expect "bg-red-500" & "still-active"
57
+ expect(iconDiv.className).toContain("bg-red-500");
58
+ expect(iconDiv.className).toContain("still-active");
59
+ // Optionally also check the hover state:
60
+ expect(iconDiv.className).toContain("hover:bg-blue-500");
61
+ });
62
+ it("doesn't apply active styles if localStorage is empty", () => {
63
+ render(_jsx(HeaderFilterIcon, { ...defaultProps }));
64
+ const iconDiv = screen.getByTestId("magnifying-icon-test-id");
65
+ // Not active => no "bg-red-500"
66
+ expect(iconDiv.className).not.toContain("bg-red-500");
67
+ // By default, we see "hover:bg-white"
68
+ expect(iconDiv.className).toContain("hover:bg-white");
69
+ });
70
+ it("applies active styles if the column is being edited (editingHeader === columnIndex)", () => {
71
+ render(_jsx(HeaderFilterIcon, { ...defaultProps, editingHeader: 2 }));
72
+ const iconDiv = screen.getByTestId("magnifying-icon-test-id");
73
+ // Being edited => active => "bg-red-500"
74
+ expect(iconDiv.className).toContain("bg-red-500");
75
+ expect(iconDiv.className).toContain("still-active");
76
+ expect(iconDiv.className).toContain("hover:bg-blue-500");
77
+ });
78
+ it("handles invalid JSON in localStorage gracefully", () => {
79
+ localStorage.setItem("searchCriteria", "{ invalid json }");
80
+ const spy = vi.spyOn(console, "error").mockImplementation(() => { });
81
+ render(_jsx(HeaderFilterIcon, { ...defaultProps }));
82
+ // We expect the parse error to have been caught:
83
+ expect(spy).toHaveBeenCalled();
84
+ spy.mockRestore();
85
+ });
86
+ it("updates active state when receiving a 'localStorageUpdate' event", async () => {
87
+ render(_jsx(HeaderFilterIcon, { ...defaultProps }));
88
+ const iconDiv = screen.getByTestId("magnifying-icon-test-id");
89
+ expect(iconDiv.className).not.toContain("bg-red-500");
90
+ // Set localStorage and dispatch the event
91
+ localStorage.setItem("searchCriteria", JSON.stringify([
92
+ {
93
+ searchColumn: { id: "exampleColumn" },
94
+ submittedSearchText: "some text",
95
+ },
96
+ ]));
97
+ window.dispatchEvent(new Event("localStorageUpdate"));
98
+ // now wait for the re-render
99
+ await waitFor(() => {
100
+ expect(iconDiv.className).toContain("bg-red-500");
101
+ expect(iconDiv.className).toContain("still-active");
102
+ });
103
+ });
104
+ });
@@ -0,0 +1,2 @@
1
+ export { default } from "./HeaderFilterIcon";
2
+ export * from "./types";
@@ -0,0 +1,2 @@
1
+ export { default } from "./HeaderFilterIcon";
2
+ export * from "./types";
@@ -0,0 +1,22 @@
1
+ import { ColumnInstance } from "react-table";
2
+ export interface HeaderFilterIconProps<T extends object> {
3
+ columnIndex: number;
4
+ editingHeader: number | null;
5
+ setEditingHeader: (index: number | null) => void;
6
+ setHeaderValue: (value: string) => void;
7
+ column: ColumnInstance<T>;
8
+ setActiveColumn: (index: number) => void;
9
+ iconColor?: string;
10
+ iconBackgroundColor?: string;
11
+ iconActiveColor?: string;
12
+ iconActiveBackgroundColor?: string;
13
+ isActive?: boolean;
14
+ additionalIconClasses?: string;
15
+ setSearchText?: (text: string) => void;
16
+ searchText?: string;
17
+ isSearchOpen?: boolean;
18
+ icon?: {
19
+ icon: string;
20
+ weight: "regular" | "solid" | "light";
21
+ };
22
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -53,7 +53,7 @@ const InputField = forwardRef(({ label, placeholder, required = false, checked,
53
53
  ${firstIcon ? "pl-10" : ""}
54
54
  ${secondIcon ? "pr-10" : ""}
55
55
  ${additionalClasses}
56
- `, children: readOnlyInfo }), iconPosition === "after" && renderSecondIcon()] })) : (_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", { autoComplete: "", ...registerProps, className: `rounded-md focused:ring-0 ${focusRingColor} focus:ring-1
56
+ `, children: readOnlyInfo }), iconPosition === "after" && renderSecondIcon()] })) : (_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", { autoComplete: "", ...registerProps, className: `focused:ring-0 ${focusRingColor} focus:ring-1
57
57
  focus:outline-none
58
58
  ${disabled
59
59
  ? "border-gray-500 focus:ring-gray-500"
@@ -62,8 +62,8 @@ const InputField = forwardRef(({ label, placeholder, required = false, checked,
62
62
  : "border-redText focus:ring-red-500"} block w-full py-2 px-2
63
63
  ${firstIcon ? "pl-10" : ""}
64
64
  ${secondIcon ? "pr-10" : ""}
65
- rounded-lg outline outline-0 outline-barelyPrimary focus:outline-4 md:w-full lg:w-full ${additionalClasses} ${isFocused ? "hover:border-transparent" : ""} ${isFocused && !disabled
65
+ outline outline-0 outline-barelyPrimary focus:outline-4 md:w-full lg:w-full ${isFocused ? "hover:border-transparent" : ""} ${isFocused && !disabled
66
66
  ? ` ${isValid ? "" : "shadow-redText"}`
67
- : disabled}`, autoFocus: hasAutoFocus, placeholder: placeholder, type: type, id: id, value: formattedValue, name: name, onChange: onChange, checked: type === "checkbox" ? checked : undefined, onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false), disabled: disabled, required: required && !hasValue, onKeyDown: onKeyDown }), iconPosition === "after" && renderSecondIcon()] })] }));
67
+ : disabled} ${additionalClasses}`, autoFocus: hasAutoFocus, placeholder: placeholder, type: type, id: id, value: formattedValue, name: name, onChange: onChange, checked: type === "checkbox" ? checked : undefined, onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false), disabled: disabled, required: required && !hasValue, onKeyDown: onKeyDown }), iconPosition === "after" && renderSecondIcon()] })] }));
68
68
  });
69
69
  export default InputField;
@@ -1,6 +1,4 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // In your NPM library @agilant/toga-blox/dist/components/InputAndCheck/InputAndCheck
3
- // EXACTLY as you showed (with Badge, TableHeaderInput, etc.):
4
2
  import { useEffect, useRef, useState } from "react";
5
3
  import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
6
4
  import Badge from "../Badge";
@@ -8,7 +6,6 @@ import TableHeaderInput from "../TableHeaderInput";
8
6
  function InputAndCheck({ closeOutSearch, setResetSearch, setEditingHeader, column, searchCriteria, setSearchCriteria, badgeColor = "bg-blue-400", badgeIcon = { icon: "x", weight: "regular" }, cancelIcon = { icon: "xmark", weight: "regular" }, iconBadgeContainerClasses = "mr-2 rounded-full p-2 text-white cursor-pointer my-2 text-sm", searchIcon = { icon: "search", weight: "regular" }, searchIconClasses = " text-md absolute right-3 top-2 text-gray-400 hover:cursor-pointer hover:text-blue-500 ", additionalInputClasses = "min-w-[300px] max-w-[250px] border-b border-t-0 border-r-0 rounded-tl-none rounded-tr-lg bg-gray-50 text-gray-800 flex", secondIconClasses = "flex absolute right-6 top-0.5 items-center text-gray-400 hover:cursor-pointer hover:text-blue-400", initialIcon = { icon: "search", weight: "regular" }, initialIconClasses = "text-gray-400", }) {
9
7
  const containerRef = useRef(null);
10
8
  const [localSearchText, setLocalSearchText] = useState("");
11
- // Load initial text from searchCriteria:
12
9
  useEffect(() => {
13
10
  const existing = searchCriteria.find((criterion) => criterion.searchColumn.id === column.id);
14
11
  if (existing) {
@@ -18,19 +15,15 @@ function InputAndCheck({ closeOutSearch, setResetSearch, setEditingHeader, colum
18
15
  setLocalSearchText("");
19
16
  }
20
17
  }, [searchCriteria, column.id]);
21
- // Handle changes
22
18
  const handleInputChange = (e) => {
23
19
  setLocalSearchText(e.target.value);
24
20
  };
25
- // Submit
26
21
  const handleSubmit = () => {
27
22
  const trimmed = localSearchText.trim();
28
23
  if (!trimmed) {
29
- // remove criterion
30
24
  setSearchCriteria((prev) => prev.filter((c) => c.searchColumn.id !== column.id));
31
25
  }
32
26
  else {
33
- // add or update
34
27
  setSearchCriteria((prev) => {
35
28
  const existingIndex = prev.findIndex((c) => c.searchColumn.id === column.id);
36
29
  if (existingIndex >= 0) {
@@ -51,14 +44,12 @@ function InputAndCheck({ closeOutSearch, setResetSearch, setEditingHeader, colum
51
44
  }
52
45
  setEditingHeader(null);
53
46
  };
54
- // Clear
55
47
  const handleClearSearch = () => {
56
48
  setSearchCriteria((prev) => prev.filter((c) => c.searchColumn.id !== column.id));
57
49
  setLocalSearchText("");
58
50
  setResetSearch((prev) => !prev);
59
51
  closeOutSearch(null);
60
52
  };
61
- // Let user press Enter
62
53
  const handleKeyDown = (e) => {
63
54
  if (e.key === "Enter") {
64
55
  e.preventDefault();
@@ -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} ${showActiveStyles ? "text-white" : iconActiveColor}`, children: getFontAwesomeIcon("magnifyingGlass", "solid") }) }));
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;
@@ -44,6 +44,7 @@ export const WithActiveClass = {
44
44
  args: {
45
45
  ...Default.args,
46
46
  isActive: true,
47
+ additionalIconClasses: "text-green-500",
47
48
  },
48
49
  };
49
50
  export const WithClickAlert = {
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { createElement as _createElement } from "react";
3
3
  import { useRef, useState, useMemo } from "react";
4
- import MagnifyingIcon from "../MagnifyingIcon";
4
+ import HeaderFilterIcon from "../HeaderFilterIcon";
5
5
  import TableHeaderContent from "../TableHeaderContent/TableHeaderContent";
6
6
  import InputAndCheck from "../InputAndCheck/InputAndCheck";
7
7
  import SortArrows from "../SortArrows";
@@ -66,7 +66,7 @@ const PrimaryTableHeader = ({ headerGroups, editingHeader, searchText, setSearch
66
66
  })()] }) }), PortalComponent] })) : (_jsx(TableHeaderContent, { column: updatedColumn })), _jsx("div", { className: "ml-1", children: _jsx(SortArrows, { slug: mappingField || "", parentIndex: parentIndex, isNested: isNested, column: {
67
67
  ...updatedColumn,
68
68
  accessor: updatedColumn.id,
69
- }, setSortColumn: setSortColumn, onSortChange: handleSortChange }) }), shouldRenderMagnifyingIcon && (_jsx(MagnifyingIcon, { ref: magnifyingIconRef, column: updatedColumn, editingHeader: editingHeader, columnIndex: columnIndex, setEditingHeader: setEditingHeader, setHeaderValue: setHeaderValue, isActive: activeColumn === columnIndex, setActiveColumn: setActiveColumn, setSearchText: setSearchText, searchText: searchText, isSearchOpen: editingHeader !== null }))] })));
69
+ }, setSortColumn: setSortColumn, onSortChange: handleSortChange }) }), shouldRenderMagnifyingIcon && (_jsx(HeaderFilterIcon, { ref: magnifyingIconRef, column: updatedColumn, editingHeader: editingHeader, columnIndex: columnIndex, setEditingHeader: setEditingHeader, setHeaderValue: setHeaderValue, isActive: activeColumn === columnIndex, setActiveColumn: setActiveColumn, setSearchText: setSearchText, searchText: searchText, isSearchOpen: editingHeader !== null }))] })));
70
70
  })))) }));
71
71
  };
72
72
  export default PrimaryTableHeader;
@@ -11,6 +11,7 @@ interface SearchDropdownInputProps {
11
11
  bgColor?: string;
12
12
  textHighlight?: string;
13
13
  [key: string]: any;
14
+ handleFilter?: () => void;
14
15
  }
15
16
  /**
16
17
  * A wrapper around MultiSelectInput that appends a special "__footer__" option
@@ -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...", disabled = false, hasSelectAll = true, bgColor, textHighlight, ...rest }) => {
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
- console.log("Filter clicked!", selectedValue);
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>({ closeOutSearch, setResetSearch, setEditingHeader, bgColor, textHighlight, column, inputType, dropdownIconProp, dropdownOptions, selectedDropdownOption, onDropdownOptionSelect, searchItems, setSearchItems, toggleStatus, setToggleStatus, minValue, setMinValue, maxValue, setMaxValue, control, valueKey, dynamicDefaultValue, onChange, selectedValue, }: SearchInputProps<T>) => import("react/jsx-runtime").JSX.Element;
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, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useRef, useState } from "react";
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
- // A simple helper function for default values
8
- function getDefaultValue(dynamicDefaultValue, valueKey) {
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, control, valueKey, dynamicDefaultValue, onChange, selectedValue, }) => {
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, { closeOutSearch: () => { }, setResetSearch: () => { }, setEditingHeader: () => { }, column: undefined, dropdownIconProp: dropdownIconProp, dropdownOptions: dropdownOptions, selectedDropdownOption: selectedDropdownOption, onDropdownOptionSelect: onDropdownOptionSelect, searchItems: searchItems, setSearchItems: setSearchItems }));
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, { closeOutSearch: () => { }, setResetSearch: () => { }, setEditingHeader: () => { }, column: undefined, dropdownIconProp: dropdownIconProp, dropdownOptions: dropdownOptions, selectedDropdownOption: selectedDropdownOption, onDropdownOptionSelect: onDropdownOptionSelect, toggleStatus: toggleStatus, setToggleStatus: setToggleStatus, minValue: minValue, maxValue: maxValue, setMinValue: setMinValue, setMaxValue: setMaxValue }));
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
- // Make sure control & valueKey exist before using them
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
  };
@@ -6,4 +6,4 @@ export declare const TextInput: any;
6
6
  export declare const NumberInput: any;
7
7
  export declare const DropdownInput: any;
8
8
  export declare const BooleanInput: any;
9
- export declare const DisabledInput: any;
9
+ export declare const DatePickerInput: any;