@agilant/toga-blox 1.0.32 → 1.0.34

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 (144) hide show
  1. package/dist/components/Dropdown/Dropdown.d.ts +4 -0
  2. package/dist/components/Dropdown/Dropdown.js +20 -0
  3. package/dist/components/Dropdown/Dropdown.stories.d.ts +8 -0
  4. package/dist/components/Dropdown/Dropdown.stories.js +110 -0
  5. package/dist/components/Dropdown/Dropdown.test.d.ts +1 -0
  6. package/dist/components/Dropdown/Dropdown.test.js +43 -0
  7. package/dist/components/Dropdown/Dropdown.types.d.ts +15 -0
  8. package/dist/components/Dropdown/Dropdown.types.js +1 -0
  9. package/dist/components/GenericList/GenericList.d.ts +2 -15
  10. package/dist/components/GenericList/GenericList.js +64 -51
  11. package/dist/components/GenericList/GenericList.stories.d.ts +8 -35
  12. package/dist/components/GenericList/GenericList.stories.js +46 -78
  13. package/dist/components/GenericList/GenericList.test.d.ts +1 -1
  14. package/dist/components/GenericList/GenericList.test.js +112 -22
  15. package/dist/components/GenericList/index.d.ts +2 -0
  16. package/dist/components/GenericList/index.js +2 -0
  17. package/dist/components/GenericList/types.d.ts +16 -0
  18. package/dist/components/GenericList/types.js +1 -0
  19. package/dist/components/Header/Header.stories.js +2 -4
  20. package/dist/components/Input/Input.d.ts +30 -3
  21. package/dist/components/Input/Input.js +70 -48
  22. package/dist/components/Input/Input.stories.js +3 -4
  23. package/dist/components/Input/Input.test.js +74 -42
  24. package/dist/components/InputAndCheck/InputAndCheck.d.ts +47 -0
  25. package/dist/components/InputAndCheck/InputAndCheck.js +74 -0
  26. package/dist/components/InputAndCheck/InputAndCheck.stories.d.ts +9 -0
  27. package/dist/components/InputAndCheck/InputAndCheck.stories.js +201 -0
  28. package/dist/components/InputAndCheck/InputAndCheck.test.d.ts +1 -0
  29. package/dist/components/InputAndCheck/InputAndCheck.test.js +307 -0
  30. package/dist/components/InputAndCheck/index.d.ts +0 -0
  31. package/dist/components/InputAndCheck/index.js +0 -0
  32. package/dist/components/InputAndCheck/types.d.ts +35 -0
  33. package/dist/components/InputAndCheck/types.js +1 -0
  34. package/dist/components/MagnifyingIcon/MagnifyingIcon.d.ts +4 -0
  35. package/dist/components/MagnifyingIcon/MagnifyingIcon.js +60 -0
  36. package/dist/components/MagnifyingIcon/MagnifyingIcon.stories.d.ts +9 -0
  37. package/dist/components/MagnifyingIcon/MagnifyingIcon.stories.js +72 -0
  38. package/dist/components/MagnifyingIcon/MagnifyingIcon.test.d.ts +1 -0
  39. package/dist/components/MagnifyingIcon/MagnifyingIcon.test.js +101 -0
  40. package/dist/components/MagnifyingIcon/index.d.ts +2 -0
  41. package/dist/components/MagnifyingIcon/index.js +2 -0
  42. package/dist/components/MagnifyingIcon/types.d.ts +20 -0
  43. package/dist/components/MagnifyingIcon/types.js +2 -0
  44. package/dist/components/MultiSelect/MultiSelect.d.ts +4 -0
  45. package/dist/components/MultiSelect/MultiSelect.js +30 -0
  46. package/dist/components/MultiSelect/MultiSelect.stories.d.ts +10 -0
  47. package/dist/components/MultiSelect/MultiSelect.stories.js +162 -0
  48. package/dist/components/MultiSelect/MultiSelect.test.d.ts +1 -0
  49. package/dist/components/MultiSelect/MultiSelect.test.js +107 -0
  50. package/dist/components/MultiSelect/MultiSelect.types.d.ts +28 -0
  51. package/dist/components/MultiSelect/MultiSelect.types.js +1 -0
  52. package/dist/components/Page/ViewPageTemplate.stories.js +2 -3
  53. package/dist/components/PrimaryTableHeader/PrimaryTableHeader.d.ts +3 -0
  54. package/dist/components/PrimaryTableHeader/PrimaryTableHeader.js +72 -0
  55. package/dist/components/PrimaryTableHeader/PrimaryTableHeader.stories.d.ts +4 -0
  56. package/dist/components/PrimaryTableHeader/PrimaryTableHeader.stories.js +99 -0
  57. package/dist/components/PrimaryTableHeader/PrimaryTableHeader.test.d.ts +1 -0
  58. package/dist/components/PrimaryTableHeader/PrimaryTableHeader.test.js +124 -0
  59. package/dist/components/PrimaryTableHeader/index.d.ts +0 -0
  60. package/dist/components/PrimaryTableHeader/index.js +0 -0
  61. package/dist/components/PrimaryTableHeader/types.d.ts +35 -0
  62. package/dist/components/PrimaryTableHeader/types.js +2 -0
  63. package/dist/components/SearchInput/SearchInput.d.ts +1 -2
  64. package/dist/components/SearchInput/SearchInput.js +61 -11
  65. package/dist/components/SearchInput/SearchInput.stories.d.ts +2 -4
  66. package/dist/components/SearchInput/SearchInput.stories.js +80 -93
  67. package/dist/components/SearchInput/SearchInput.types.d.ts +37 -24
  68. package/dist/components/SearchInput/SearchNumberInput.d.ts +31 -0
  69. package/dist/components/SearchInput/SearchNumberInput.js +60 -0
  70. package/dist/components/SearchInput/SearchTextInput.d.ts +24 -0
  71. package/dist/components/SearchInput/SearchTextInput.js +65 -0
  72. package/dist/components/SortArrowIcon/SortArrowIcon.d.ts +4 -0
  73. package/dist/components/SortArrowIcon/SortArrowIcon.js +12 -0
  74. package/dist/components/SortArrowIcon/SortArrowIcon.stories.d.ts +17 -0
  75. package/dist/components/SortArrowIcon/SortArrowIcon.stories.js +77 -0
  76. package/dist/components/SortArrowIcon/SortArrowIcon.test.d.ts +1 -0
  77. package/dist/components/SortArrowIcon/SortArrowIcon.test.js +44 -0
  78. package/dist/components/SortArrowIcon/index.d.ts +2 -0
  79. package/dist/components/SortArrowIcon/index.js +2 -0
  80. package/dist/components/SortArrowIcon/types.d.ts +15 -0
  81. package/dist/components/SortArrowIcon/types.js +1 -0
  82. package/dist/components/SortArrows/SortArrows.d.ts +3 -0
  83. package/dist/components/SortArrows/SortArrows.js +33 -0
  84. package/dist/components/SortArrows/SortArrows.stories.d.ts +7 -0
  85. package/dist/components/SortArrows/SortArrows.stories.js +41 -0
  86. package/dist/components/SortArrows/SortArrows.test.d.ts +1 -0
  87. package/dist/components/SortArrows/SortArrows.test.js +150 -0
  88. package/dist/components/SortArrows/index.d.ts +2 -0
  89. package/dist/components/SortArrows/index.js +2 -0
  90. package/dist/components/SortArrows/types.d.ts +21 -0
  91. package/dist/components/SortArrows/types.js +1 -0
  92. package/dist/components/SortArrows/useSortArrowsViewModel.d.ts +30 -0
  93. package/dist/components/SortArrows/useSortArrowsViewModel.js +114 -0
  94. package/dist/components/SortArrows/useSortArrowsViewModel.test.d.ts +1 -0
  95. package/dist/components/SortArrows/useSortArrowsViewModel.test.js +100 -0
  96. package/dist/components/TableCell/TableCell.d.ts +3 -0
  97. package/dist/components/TableCell/TableCell.js +13 -0
  98. package/dist/components/TableCell/TableCell.stories.d.ts +16 -0
  99. package/dist/components/TableCell/TableCell.stories.js +99 -0
  100. package/dist/components/TableCell/TableCell.test.d.ts +1 -0
  101. package/dist/components/TableCell/TableCell.test.js +84 -0
  102. package/dist/components/TableCell/index.d.ts +2 -0
  103. package/dist/components/TableCell/index.js +2 -0
  104. package/dist/components/TableCell/types.d.ts +12 -0
  105. package/dist/components/TableCell/types.js +1 -0
  106. package/dist/components/TableHeaderContent/TableHeaderContent.d.ts +3 -0
  107. package/dist/components/TableHeaderContent/TableHeaderContent.js +5 -0
  108. package/dist/components/TableHeaderContent/TableHeaderContent.stories.d.ts +6 -0
  109. package/dist/components/TableHeaderContent/TableHeaderContent.stories.js +62 -0
  110. package/dist/components/TableHeaderContent/TableHeaderContent.test.d.ts +1 -0
  111. package/dist/components/TableHeaderContent/TableHeaderContent.test.js +41 -0
  112. package/dist/components/TableHeaderContent/index.d.ts +0 -0
  113. package/dist/components/TableHeaderContent/index.js +0 -0
  114. package/dist/components/TableHeaderContent/types.d.ts +5 -0
  115. package/dist/components/TableHeaderContent/types.js +1 -0
  116. package/dist/components/TableHeaderInput/TableHeaderInput.d.ts +3 -0
  117. package/dist/components/TableHeaderInput/TableHeaderInput.js +80 -0
  118. package/dist/components/TableHeaderInput/TableHeaderInput.stories.d.ts +10 -0
  119. package/dist/components/TableHeaderInput/TableHeaderInput.stories.js +82 -0
  120. package/dist/components/TableHeaderInput/TableHeaderInput.test.d.ts +1 -0
  121. package/dist/components/TableHeaderInput/TableHeaderInput.test.js +84 -0
  122. package/dist/components/TableHeaderInput/index.d.ts +1 -0
  123. package/dist/components/TableHeaderInput/index.js +1 -0
  124. package/dist/components/TableHeaderInput/types.d.ts +30 -0
  125. package/dist/components/TableHeaderInput/types.js +1 -0
  126. package/dist/components/TableRow/TableRow.d.ts +15 -0
  127. package/dist/components/TableRow/TableRow.js +21 -0
  128. package/dist/components/TableRow/TableRow.stories.d.ts +9 -0
  129. package/dist/components/TableRow/TableRow.stories.js +195 -0
  130. package/dist/components/TableRow/TableRow.test.d.ts +1 -0
  131. package/dist/components/TableRow/TableRow.test.js +44 -0
  132. package/dist/components/TableRow/index.d.ts +2 -0
  133. package/dist/components/TableRow/index.js +2 -0
  134. package/dist/components/TableRow/types.d.ts +11 -0
  135. package/dist/components/TableRow/types.js +1 -0
  136. package/dist/components/ToggleButton/ToggleButton.d.ts +4 -0
  137. package/dist/components/ToggleButton/ToggleButton.js +41 -0
  138. package/dist/components/ToggleButton/ToggleButton.stories.d.ts +11 -0
  139. package/dist/components/ToggleButton/ToggleButton.stories.js +111 -0
  140. package/dist/components/ToggleButton/ToggleButton.test.d.ts +1 -0
  141. package/dist/components/ToggleButton/ToggleButton.test.js +106 -0
  142. package/dist/components/ToggleButton/ToggleButton.types.d.ts +22 -0
  143. package/dist/components/ToggleButton/ToggleButton.types.js +1 -0
  144. package/package.json +11 -4
@@ -0,0 +1,74 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // src/components/InputAndCheck/InputAndCheck.tsx
3
+ import { useEffect, useRef, useState } from "react";
4
+ import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
5
+ import Badge from "../Badge";
6
+ import TableHeaderInput from "../TableHeaderInput";
7
+ /**
8
+ * Renders an input field for column-based searching,
9
+ * maintaining local text and updating searchCriteria on submit.
10
+ */
11
+ 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", }) {
12
+ const containerRef = useRef(null);
13
+ const [localSearchText, setLocalSearchText] = useState("");
14
+ // On mount/update, see if we already have a search criterion for this column
15
+ useEffect(() => {
16
+ const existing = searchCriteria.find((criterion) => criterion.searchColumn.id === column.id);
17
+ if (existing) {
18
+ setLocalSearchText(existing.submittedSearchText);
19
+ }
20
+ else {
21
+ setLocalSearchText("");
22
+ }
23
+ }, [searchCriteria, column.id]);
24
+ // Update local text as user types
25
+ const handleInputChange = (e) => {
26
+ setLocalSearchText(e.target.value);
27
+ };
28
+ // Submit the final text to searchCriteria
29
+ const handleSubmit = () => {
30
+ const trimmed = localSearchText.trim();
31
+ if (!trimmed) {
32
+ // Clear from search criteria if empty
33
+ setSearchCriteria((prev) => prev.filter((c) => c.searchColumn.id !== column.id));
34
+ }
35
+ else {
36
+ // Insert or update existing
37
+ setSearchCriteria((prev) => {
38
+ const existingIndex = prev.findIndex((c) => c.searchColumn.id === column.id);
39
+ if (existingIndex >= 0) {
40
+ const updated = [...prev];
41
+ updated[existingIndex] = {
42
+ searchColumn: column,
43
+ submittedSearchText: trimmed,
44
+ };
45
+ return updated;
46
+ }
47
+ else {
48
+ return [
49
+ ...prev,
50
+ { searchColumn: column, submittedSearchText: trimmed },
51
+ ];
52
+ }
53
+ });
54
+ }
55
+ // Close out
56
+ setEditingHeader(null);
57
+ };
58
+ // Clears search from parent's state
59
+ const handleClearSearch = () => {
60
+ setSearchCriteria((prev) => prev.filter((c) => c.searchColumn.id !== column.id));
61
+ setLocalSearchText("");
62
+ setResetSearch((prev) => !prev);
63
+ closeOutSearch(null);
64
+ };
65
+ // Let user press Enter
66
+ const handleKeyDown = (e) => {
67
+ if (e.key === "Enter") {
68
+ e.preventDefault();
69
+ handleSubmit();
70
+ }
71
+ };
72
+ return (_jsxs("div", { ref: containerRef, className: "relative", "data-testid": "icon-search-regular", children: [_jsxs("div", { className: "flex flex-col border rounded-md shadow-md", children: [_jsx("div", { className: "flex", children: _jsx(TableHeaderInput, { hasAutoFocus: true, value: localSearchText, onKeyDown: handleKeyDown, required: false, id: "", name: "", type: "text", onChange: handleInputChange, additionalClasses: additionalInputClasses, placeholder: "Search", hasIcons: true, firstIcon: localSearchText === "" ? (_jsx("span", { className: initialIconClasses, children: getFontAwesomeIcon(initialIcon.icon, initialIcon.weight) })) : undefined, iconPosition: "both", secondIcon: localSearchText !== "" && (_jsx("div", { className: secondIconClasses, onClick: handleClearSearch, children: getFontAwesomeIcon(cancelIcon.icon, cancelIcon.weight) })) }) }), localSearchText && (_jsx("div", { className: "bg-white flex flex-start px-2", children: _jsx(Badge, { text: localSearchText, type: "span", cursorPointer: true, onClick: handleClearSearch, hasRightIcon: true, backgroundColor: badgeColor, badgeContainerClasses: iconBadgeContainerClasses, icon: getFontAwesomeIcon(badgeIcon.icon, badgeIcon.weight) }) }))] }), localSearchText && (_jsx("div", { onClick: handleSubmit, className: searchIconClasses, children: getFontAwesomeIcon(searchIcon.icon, searchIcon.weight) }))] }));
73
+ }
74
+ export default InputAndCheck;
@@ -0,0 +1,9 @@
1
+ import { Meta } from "@storybook/react";
2
+ /**
3
+ * Default export for Storybook.
4
+ */
5
+ declare const _default: Meta;
6
+ export default _default;
7
+ export declare const Default: any;
8
+ export declare const WithInitialSearch: any;
9
+ export declare const UpdateLocalStorage: any;
@@ -0,0 +1,201 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // InputAndCheck.stories.tsx
3
+ import { useState, useEffect } from "react";
4
+ import InputAndCheck from "./InputAndCheck";
5
+ /**
6
+ * Mock column from react-table.
7
+ */
8
+ const mockColumn = {
9
+ id: "name",
10
+ // Add other ColumnInstance properties as needed
11
+ };
12
+ /**
13
+ * Default export for Storybook.
14
+ */
15
+ export default {
16
+ title: "Components/InputAndCheck",
17
+ component: InputAndCheck,
18
+ tags: ["autodocs"],
19
+ argTypes: {
20
+ pillColor: {
21
+ control: "text",
22
+ description: "Tailwind class(es) to set the pill background color.",
23
+ defaultValue: "bg-blue-600",
24
+ table: {
25
+ type: { summary: "string" },
26
+ defaultValue: { summary: "bg-blue-600" },
27
+ },
28
+ },
29
+ closeOutSearch: {
30
+ control: false,
31
+ description: "Callback triggered when search is closed/cleared.",
32
+ table: {
33
+ category: "Callbacks",
34
+ },
35
+ },
36
+ setResetSearch: {
37
+ control: false,
38
+ description: "Parent’s setter for toggling reset logic.",
39
+ table: {
40
+ category: "Callbacks",
41
+ },
42
+ },
43
+ setEditingHeader: {
44
+ control: false,
45
+ description: "Parent’s setter used to toggle input editing mode.",
46
+ table: {
47
+ category: "Callbacks",
48
+ },
49
+ },
50
+ column: {
51
+ control: false,
52
+ description: "A react-table ColumnInstance for identifying this input.",
53
+ table: {
54
+ category: "Data",
55
+ },
56
+ },
57
+ searchCriteria: {
58
+ control: false,
59
+ description: "Array of existing search criteria for this table.",
60
+ table: {
61
+ category: "Data",
62
+ },
63
+ },
64
+ setSearchCriteria: {
65
+ control: false,
66
+ description: "Setter to update the parent’s search criteria array.",
67
+ table: {
68
+ category: "Callbacks",
69
+ },
70
+ },
71
+ },
72
+ };
73
+ /**
74
+ * ----------------------------------------------------------------------------
75
+ * BASIC TEMPLATE WITH LOCAL STORAGE SYNC
76
+ * ----------------------------------------------------------------------------
77
+ */
78
+ const Template = (args) => {
79
+ const storageKey = "storybook-inputandcheck-search-criteria";
80
+ // Initialize searchCriteria from localStorage
81
+ const [searchCriteria, setSearchCriteria] = useState(() => {
82
+ try {
83
+ const saved = window.localStorage.getItem(storageKey);
84
+ return saved ? JSON.parse(saved) : [];
85
+ }
86
+ catch (error) {
87
+ console.error("Failed to parse search criteria from localStorage:", error);
88
+ return [];
89
+ }
90
+ });
91
+ const [resetSearch, setResetSearch] = useState(false);
92
+ const [editingHeader, setEditingHeader] = useState(null);
93
+ // Sync searchCriteria to localStorage
94
+ useEffect(() => {
95
+ try {
96
+ window.localStorage.setItem(storageKey, JSON.stringify(searchCriteria));
97
+ }
98
+ catch (error) {
99
+ console.error("Failed to save search criteria to localStorage:", error);
100
+ }
101
+ }, [searchCriteria, storageKey]);
102
+ // Optionally, clear localStorage when the story unmounts to prevent side effects
103
+ useEffect(() => {
104
+ return () => {
105
+ window.localStorage.removeItem(storageKey);
106
+ };
107
+ }, [storageKey]);
108
+ const handleCloseOutSearch = (val) => {
109
+ console.log("closeOutSearch called with:", val);
110
+ // Implement any additional logic here
111
+ };
112
+ return (_jsxs("div", { style: { width: 300 }, children: [_jsx(InputAndCheck, { ...args, closeOutSearch: handleCloseOutSearch, setResetSearch: setResetSearch, setEditingHeader: setEditingHeader, column: mockColumn, searchCriteria: searchCriteria, setSearchCriteria: setSearchCriteria }), _jsxs("div", { style: { marginTop: 10 }, children: [_jsx("strong", { children: "Current State:" }), _jsxs("pre", { children: ["searchCriteria: ", JSON.stringify(searchCriteria, null, 2)] }), _jsxs("p", { children: ["resetSearch: ", String(resetSearch)] }), _jsxs("p", { children: ["editingHeader: ", String(editingHeader)] })] })] }));
113
+ };
114
+ export const Default = Template.bind({});
115
+ Default.args = {
116
+ pillColor: "bg-blue-600",
117
+ };
118
+ /**
119
+ * ----------------------------------------------------------------------------
120
+ * WITH INITIAL SEARCH
121
+ * ----------------------------------------------------------------------------
122
+ * Demonstrates having an initial search text for the column.
123
+ * We'll define a separate template that sets the state up front.
124
+ */
125
+ const TemplateWithInitialSearch = (args) => {
126
+ const storageKey = "storybook-inputandcheck-search-criteria-initial";
127
+ const [searchCriteria, setSearchCriteria] = useState([
128
+ {
129
+ searchColumn: mockColumn,
130
+ submittedSearchText: "Initial text",
131
+ },
132
+ ]);
133
+ const [resetSearch, setResetSearch] = useState(false);
134
+ const [editingHeader, setEditingHeader] = useState(null);
135
+ // Sync searchCriteria to localStorage
136
+ useEffect(() => {
137
+ try {
138
+ window.localStorage.setItem(storageKey, JSON.stringify(searchCriteria));
139
+ }
140
+ catch (error) {
141
+ console.error("Failed to save search criteria to localStorage:", error);
142
+ }
143
+ }, [searchCriteria, storageKey]);
144
+ // Optionally, clear localStorage when the story unmounts
145
+ useEffect(() => {
146
+ return () => {
147
+ window.localStorage.removeItem(storageKey);
148
+ };
149
+ }, [storageKey]);
150
+ const handleCloseOutSearch = (val) => {
151
+ console.log("closeOutSearch called with:", val);
152
+ // Implement any additional logic here
153
+ };
154
+ return (_jsxs("div", { style: { width: 300 }, children: [_jsx(InputAndCheck, { ...args, closeOutSearch: handleCloseOutSearch, setResetSearch: setResetSearch, setEditingHeader: setEditingHeader, column: mockColumn, searchCriteria: searchCriteria, setSearchCriteria: setSearchCriteria }), _jsxs("div", { style: { marginTop: 10 }, children: [_jsx("strong", { children: "Current State:" }), _jsxs("pre", { children: ["searchCriteria: ", JSON.stringify(searchCriteria, null, 2)] }), _jsxs("p", { children: ["resetSearch: ", String(resetSearch)] }), _jsxs("p", { children: ["editingHeader: ", String(editingHeader)] })] })] }));
155
+ };
156
+ export const WithInitialSearch = TemplateWithInitialSearch.bind({});
157
+ WithInitialSearch.args = {
158
+ pillColor: "bg-blue-600",
159
+ };
160
+ /**
161
+ * ----------------------------------------------------------------------------
162
+ * UPDATE LOCAL STORAGE EXAMPLE
163
+ * ----------------------------------------------------------------------------
164
+ * Demonstrates updating search criteria and syncing it with localStorage.
165
+ */
166
+ const TemplateUpdateLocalStorage = (args) => {
167
+ const storageKey = "storybook-inputandcheck-update-localstorage";
168
+ // Initialize searchCriteria from localStorage
169
+ const [searchCriteria, setSearchCriteria] = useState(() => {
170
+ try {
171
+ const saved = window.localStorage.getItem(storageKey);
172
+ return saved ? JSON.parse(saved) : [];
173
+ }
174
+ catch (error) {
175
+ console.error("Failed to parse search criteria from localStorage:", error);
176
+ return [];
177
+ }
178
+ });
179
+ const [resetSearch, setResetSearch] = useState(false);
180
+ const [editingHeader, setEditingHeader] = useState(null);
181
+ // Sync searchCriteria to localStorage
182
+ useEffect(() => {
183
+ try {
184
+ window.localStorage.setItem(storageKey, JSON.stringify(searchCriteria));
185
+ }
186
+ catch (error) {
187
+ console.error("Failed to save search criteria to localStorage:", error);
188
+ }
189
+ }, [searchCriteria, storageKey]);
190
+ useEffect(() => {
191
+ return () => {
192
+ window.localStorage.removeItem(storageKey);
193
+ };
194
+ }, [storageKey]);
195
+ const handleCloseOutSearch = (val) => {
196
+ console.log("closeOutSearch called with:", val);
197
+ };
198
+ return (_jsxs("div", { style: { width: 300 }, children: [_jsx(InputAndCheck, { ...args, closeOutSearch: handleCloseOutSearch, setResetSearch: setResetSearch, setEditingHeader: setEditingHeader, column: mockColumn, searchCriteria: searchCriteria, setSearchCriteria: setSearchCriteria }), _jsxs("div", { style: { marginTop: 10 }, children: [_jsx("strong", { children: "Current State:" }), _jsxs("pre", { children: ["searchCriteria: ", JSON.stringify(searchCriteria, null, 2)] }), _jsxs("p", { children: ["resetSearch: ", String(resetSearch)] }), _jsxs("p", { children: ["editingHeader: ", String(editingHeader)] })] })] }));
199
+ };
200
+ export const UpdateLocalStorage = TemplateUpdateLocalStorage.bind({});
201
+ UpdateLocalStorage.storyName = "Update Local Storage (inspect localStorage)";
@@ -0,0 +1,307 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { render, screen, fireEvent } from "@testing-library/react";
3
+ import InputAndCheck from "./InputAndCheck";
4
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
5
+ // Mock the getFontAwesomeIcon utility
6
+ vi.mock("../../utils/getFontAwesomeIcon", () => ({
7
+ getFontAwesomeIcon: (iconName, style) => (_jsx("span", { "data-testid": `icon-${iconName}-${style}`, children: iconName })),
8
+ }));
9
+ // Mock Badge component
10
+ vi.mock("../Badge", () => ({
11
+ default: ({ text, onClick }) => (_jsxs("span", { "data-testid": "badge", onClick: onClick, children: [text, _jsx("span", { "data-testid": "badge-clear", children: "x" })] })),
12
+ }));
13
+ // Mock TableHeaderInput component
14
+ vi.mock("../TableHeaderInput", () => ({
15
+ default: ({ value, onChange, onKeyDown, onClick, placeholder, }) => (_jsx("input", { "data-testid": "table-header-input", value: value, onChange: onChange, onKeyDown: onKeyDown, placeholder: placeholder, onClick: onClick })),
16
+ }));
17
+ describe("InputAndCheck Component", () => {
18
+ // @ts-ignore
19
+ let mockCloseOutSearch;
20
+ // @ts-ignore
21
+ let mockSetResetSearch;
22
+ // @ts-ignore
23
+ let mockSetEditingHeader;
24
+ // @ts-ignore
25
+ let mockSetSearchCriteria;
26
+ let mockColumn;
27
+ beforeEach(() => {
28
+ // Reset mocks before each test
29
+ mockCloseOutSearch = vi.fn();
30
+ mockSetResetSearch = vi.fn();
31
+ mockSetEditingHeader = vi.fn();
32
+ mockSetSearchCriteria = vi.fn();
33
+ mockColumn = {
34
+ id: "name",
35
+ // Add other necessary properties if required
36
+ };
37
+ });
38
+ afterEach(() => {
39
+ vi.resetAllMocks();
40
+ window.localStorage.clear(); // Clear localStorage after each test
41
+ });
42
+ it("renders correctly with no initial search criteria", () => {
43
+ render(_jsx(InputAndCheck, { closeOutSearch: mockCloseOutSearch, setResetSearch: mockSetResetSearch, setEditingHeader: mockSetEditingHeader, column: mockColumn, searchCriteria: [], setSearchCriteria: mockSetSearchCriteria }));
44
+ // Check if input is rendered and empty
45
+ const input = screen.getByTestId("table-header-input");
46
+ expect(input).toBeInTheDocument();
47
+ expect(input.value).toBe("");
48
+ // Check that badge is not rendered
49
+ const badge = screen.queryByTestId("badge");
50
+ expect(badge).not.toBeInTheDocument();
51
+ // Check that the first icon (search icon) is rendered
52
+ const searchIcon = screen.getByTestId("icon-search-regular");
53
+ expect(searchIcon).toBeInTheDocument();
54
+ });
55
+ it("renders correctly with initial search criteria", () => {
56
+ const initialCriteria = [
57
+ {
58
+ searchColumn: mockColumn,
59
+ submittedSearchText: "Initial search",
60
+ },
61
+ ];
62
+ render(_jsx(InputAndCheck, { closeOutSearch: mockCloseOutSearch, setResetSearch: mockSetResetSearch, setEditingHeader: mockSetEditingHeader, column: mockColumn, searchCriteria: initialCriteria, setSearchCriteria: mockSetSearchCriteria }));
63
+ // Check if input has the initial search text
64
+ const input = screen.getByTestId("table-header-input");
65
+ expect(input.value).toBe("Initial search");
66
+ // Check that badge is rendered with the initial search text
67
+ const badge = screen.getByTestId("badge");
68
+ expect(badge).toBeInTheDocument();
69
+ expect(badge).toHaveTextContent("Initial search");
70
+ // Check that the badge's clear button is rendered
71
+ const badgeClear = screen.getByTestId("badge-clear");
72
+ expect(badgeClear).toBeInTheDocument();
73
+ });
74
+ it("updates localSearchText when searchCriteria prop changes", () => {
75
+ const { rerender } = render(_jsx(InputAndCheck, { closeOutSearch: mockCloseOutSearch, setResetSearch: mockSetResetSearch, setEditingHeader: mockSetEditingHeader, column: mockColumn, searchCriteria: [], setSearchCriteria: mockSetSearchCriteria }));
76
+ const input = screen.getByTestId("table-header-input");
77
+ expect(input.value).toBe("");
78
+ // Update searchCriteria prop
79
+ const updatedCriteria = [
80
+ {
81
+ searchColumn: mockColumn,
82
+ submittedSearchText: "Updated search",
83
+ },
84
+ ];
85
+ rerender(_jsx(InputAndCheck, { closeOutSearch: mockCloseOutSearch, setResetSearch: mockSetResetSearch, setEditingHeader: mockSetEditingHeader, column: mockColumn, searchCriteria: updatedCriteria, setSearchCriteria: mockSetSearchCriteria }));
86
+ // Check if input value updated
87
+ expect(input.value).toBe("Updated search");
88
+ // Check that badge is rendered
89
+ const badge = screen.getByTestId("badge");
90
+ expect(badge).toBeInTheDocument();
91
+ expect(badge).toHaveTextContent("Updated search");
92
+ });
93
+ it("handles input change correctly", () => {
94
+ render(_jsx(InputAndCheck, { closeOutSearch: mockCloseOutSearch, setResetSearch: mockSetResetSearch, setEditingHeader: mockSetEditingHeader, column: mockColumn, searchCriteria: [], setSearchCriteria: mockSetSearchCriteria }));
95
+ const input = screen.getByTestId("table-header-input");
96
+ // Simulate typing
97
+ fireEvent.change(input, { target: { value: "Test search" } });
98
+ expect(input.value).toBe("Test search");
99
+ // Verify that badge appears
100
+ const badge = screen.getByTestId("badge");
101
+ expect(badge).toBeInTheDocument();
102
+ expect(badge).toHaveTextContent("Test search");
103
+ });
104
+ it("submits search via Enter key", () => {
105
+ render(_jsx(InputAndCheck, { closeOutSearch: mockCloseOutSearch, setResetSearch: mockSetResetSearch, setEditingHeader: mockSetEditingHeader, column: mockColumn, searchCriteria: [], setSearchCriteria: mockSetSearchCriteria }));
106
+ const input = screen.getByTestId("table-header-input");
107
+ // Simulate typing
108
+ fireEvent.change(input, { target: { value: "Enter search" } });
109
+ expect(input.value).toBe("Enter search");
110
+ // Simulate pressing Enter
111
+ fireEvent.keyDown(input, { key: "Enter", code: "Enter" });
112
+ // Verify that setSearchCriteria was called to add the new criterion
113
+ expect(mockSetSearchCriteria).toHaveBeenCalledWith(expect.any(Function));
114
+ // Simulate the updater function behavior
115
+ const updaterFn = mockSetSearchCriteria.mock.calls[0][0];
116
+ const newSearchCriteria = updaterFn([]);
117
+ expect(newSearchCriteria).toEqual([
118
+ {
119
+ searchColumn: mockColumn,
120
+ submittedSearchText: "Enter search",
121
+ },
122
+ ]);
123
+ // Verify that setEditingHeader was called with null
124
+ expect(mockSetEditingHeader).toHaveBeenCalledWith(null);
125
+ });
126
+ // it("submits search via search icon click", () => {
127
+ // render(
128
+ // <InputAndCheck<MyDataType>
129
+ // closeOutSearch={mockCloseOutSearch}
130
+ // setResetSearch={mockSetResetSearch}
131
+ // setEditingHeader={mockSetEditingHeader}
132
+ // column={mockColumn}
133
+ // searchCriteria={[]}
134
+ // setSearchCriteria={mockSetSearchCriteria}
135
+ // />
136
+ // );
137
+ // const input = screen.getByTestId(
138
+ // "table-header-input"
139
+ // ) as HTMLInputElement;
140
+ // // Simulate typing
141
+ // fireEvent.change(input, { target: { value: "Icon search" } });
142
+ // expect(input.value).toBe("Icon search");
143
+ // // Find the search icon (assuming it's rendered as a span with a data-testid)
144
+ // const searchIcon = screen.getByTestId("icon-search-solid");
145
+ // // Simulate clicking the search icon
146
+ // fireEvent.click(searchIcon);
147
+ // // Verify that setSearchCriteria was called to add the new criterion
148
+ // expect(mockSetSearchCriteria).toHaveBeenCalledWith(
149
+ // expect.any(Function)
150
+ // );
151
+ // // Simulate the updater function behavior
152
+ // const updaterFn = mockSetSearchCriteria.mock.calls[0][0];
153
+ // const newSearchCriteria = updaterFn([]);
154
+ // expect(newSearchCriteria).toEqual([
155
+ // {
156
+ // searchColumn: mockColumn,
157
+ // submittedSearchText: "Icon search",
158
+ // },
159
+ // ]);
160
+ // // Verify that setEditingHeader was called with null
161
+ // expect(mockSetEditingHeader).toHaveBeenCalledWith(null);
162
+ // });
163
+ it('clears search via "X" icon click', () => {
164
+ const initialCriteria = [
165
+ {
166
+ searchColumn: mockColumn,
167
+ submittedSearchText: "Initial search",
168
+ },
169
+ ];
170
+ render(_jsx(InputAndCheck, { closeOutSearch: mockCloseOutSearch, setResetSearch: mockSetResetSearch, setEditingHeader: mockSetEditingHeader, column: mockColumn, searchCriteria: initialCriteria, setSearchCriteria: mockSetSearchCriteria }));
171
+ // Check that the badge is rendered
172
+ const badge = screen.getByTestId("badge");
173
+ expect(badge).toBeInTheDocument();
174
+ // Find the badge's clear button
175
+ const badgeClear = screen.getByTestId("badge-clear");
176
+ // Simulate clicking the clear button
177
+ fireEvent.click(badgeClear);
178
+ // Verify that setSearchCriteria was called to remove the criterion
179
+ expect(mockSetSearchCriteria).toHaveBeenCalledWith(expect.any(Function));
180
+ // Simulate the updater function behavior
181
+ const updaterFn = mockSetSearchCriteria.mock.calls[0][0];
182
+ const newSearchCriteria = updaterFn(initialCriteria);
183
+ expect(newSearchCriteria).toEqual([]);
184
+ // Verify that setResetSearch was called
185
+ expect(mockSetResetSearch).toHaveBeenCalledWith(expect.any(Function));
186
+ // Simulate the updater function behavior for setResetSearch
187
+ const resetFn = mockSetResetSearch.mock.calls[0][0];
188
+ const newResetSearch = resetFn(false);
189
+ expect(newResetSearch).toBe(true);
190
+ // Verify that closeOutSearch was called with null
191
+ expect(mockCloseOutSearch).toHaveBeenCalledWith(null);
192
+ });
193
+ it("clears search via badge click", () => {
194
+ const initialCriteria = [
195
+ {
196
+ searchColumn: mockColumn,
197
+ submittedSearchText: "Badge search",
198
+ },
199
+ ];
200
+ render(_jsx(InputAndCheck, { closeOutSearch: mockCloseOutSearch, setResetSearch: mockSetResetSearch, setEditingHeader: mockSetEditingHeader, column: mockColumn, searchCriteria: initialCriteria, setSearchCriteria: mockSetSearchCriteria }));
201
+ // Check that the badge is rendered
202
+ const badge = screen.getByTestId("badge");
203
+ expect(badge).toBeInTheDocument();
204
+ // Simulate clicking the badge to clear the search
205
+ fireEvent.click(badge);
206
+ // Verify that setSearchCriteria was called to remove the criterion
207
+ expect(mockSetSearchCriteria).toHaveBeenCalledWith(expect.any(Function));
208
+ // Simulate the updater function behavior
209
+ const updaterFn = mockSetSearchCriteria.mock.calls[0][0];
210
+ const newSearchCriteria = updaterFn(initialCriteria);
211
+ expect(newSearchCriteria).toEqual([]);
212
+ // Verify that setResetSearch was called
213
+ expect(mockSetResetSearch).toHaveBeenCalledWith(expect.any(Function));
214
+ // Simulate the updater function behavior for setResetSearch
215
+ const resetFn = mockSetResetSearch.mock.calls[0][0];
216
+ const newResetSearch = resetFn(false);
217
+ expect(newResetSearch).toBe(true);
218
+ // Verify that closeOutSearch was called with null
219
+ expect(mockCloseOutSearch).toHaveBeenCalledWith(null);
220
+ });
221
+ it("removes search criterion when submitting empty text", () => {
222
+ const initialCriteria = [
223
+ {
224
+ searchColumn: mockColumn,
225
+ submittedSearchText: "Initial search",
226
+ },
227
+ ];
228
+ render(_jsx(InputAndCheck, { closeOutSearch: mockCloseOutSearch, setResetSearch: mockSetResetSearch, setEditingHeader: mockSetEditingHeader, column: mockColumn, searchCriteria: initialCriteria, setSearchCriteria: mockSetSearchCriteria }));
229
+ const input = screen.getByTestId("table-header-input");
230
+ // Simulate clearing the input
231
+ fireEvent.change(input, { target: { value: " " } }); // Spaces to trim to empty
232
+ // Simulate pressing Enter to submit
233
+ fireEvent.keyDown(input, { key: "Enter", code: "Enter" });
234
+ // Verify that setSearchCriteria was called to remove the criterion
235
+ expect(mockSetSearchCriteria).toHaveBeenCalledWith(expect.any(Function));
236
+ // Simulate the updater function behavior
237
+ const updaterFn = mockSetSearchCriteria.mock.calls[0][0];
238
+ const newSearchCriteria = updaterFn(initialCriteria);
239
+ expect(newSearchCriteria).toEqual([]);
240
+ // Verify that setEditingHeader was called with null
241
+ expect(mockSetEditingHeader).toHaveBeenCalledWith(null);
242
+ });
243
+ it("does not add duplicate search criteria", () => {
244
+ const initialCriteria = [
245
+ {
246
+ searchColumn: mockColumn,
247
+ submittedSearchText: "Initial search",
248
+ },
249
+ ];
250
+ render(_jsx(InputAndCheck, { closeOutSearch: mockCloseOutSearch, setResetSearch: mockSetResetSearch, setEditingHeader: mockSetEditingHeader, column: mockColumn, searchCriteria: initialCriteria, setSearchCriteria: mockSetSearchCriteria }));
251
+ const input = screen.getByTestId("table-header-input");
252
+ // Simulate changing the input to a new search term
253
+ fireEvent.change(input, { target: { value: "Updated search" } });
254
+ expect(input.value).toBe("Updated search");
255
+ // Simulate pressing Enter to submit
256
+ fireEvent.keyDown(input, { key: "Enter", code: "Enter" });
257
+ // Verify that setSearchCriteria was called to update the existing criterion
258
+ expect(mockSetSearchCriteria).toHaveBeenCalledWith(expect.any(Function));
259
+ // Simulate the updater function behavior
260
+ const updaterFn = mockSetSearchCriteria.mock.calls[0][0];
261
+ const newSearchCriteria = updaterFn(initialCriteria);
262
+ expect(newSearchCriteria).toEqual([
263
+ {
264
+ searchColumn: mockColumn,
265
+ submittedSearchText: "Updated search",
266
+ },
267
+ ]);
268
+ });
269
+ it("handles multiple search criteria correctly", () => {
270
+ const anotherColumn = {
271
+ id: "id",
272
+ // Add other properties as needed
273
+ };
274
+ const initialCriteria = [
275
+ {
276
+ searchColumn: mockColumn,
277
+ submittedSearchText: "Name search",
278
+ },
279
+ {
280
+ searchColumn: anotherColumn,
281
+ submittedSearchText: "ID search",
282
+ },
283
+ ];
284
+ render(_jsx(InputAndCheck, { closeOutSearch: mockCloseOutSearch, setResetSearch: mockSetResetSearch, setEditingHeader: mockSetEditingHeader, column: mockColumn, searchCriteria: initialCriteria, setSearchCriteria: mockSetSearchCriteria }));
285
+ const input = screen.getByTestId("table-header-input");
286
+ // Simulate changing the input to update the existing criterion
287
+ fireEvent.change(input, { target: { value: "Updated name search" } });
288
+ expect(input.value).toBe("Updated name search");
289
+ // Simulate pressing Enter to submit
290
+ fireEvent.keyDown(input, { key: "Enter", code: "Enter" });
291
+ // Verify that setSearchCriteria was called to update the existing name search
292
+ expect(mockSetSearchCriteria).toHaveBeenCalledWith(expect.any(Function));
293
+ // Simulate the updater function behavior
294
+ const updaterFn = mockSetSearchCriteria.mock.calls[0][0];
295
+ const newSearchCriteria = updaterFn(initialCriteria);
296
+ expect(newSearchCriteria).toEqual([
297
+ {
298
+ searchColumn: mockColumn,
299
+ submittedSearchText: "Updated name search",
300
+ },
301
+ {
302
+ searchColumn: anotherColumn,
303
+ submittedSearchText: "ID search",
304
+ },
305
+ ]);
306
+ });
307
+ });
File without changes
File without changes
@@ -0,0 +1,35 @@
1
+ import { ColumnInstance } from "react-table";
2
+ export type SearchCriterion<T extends object> = {
3
+ searchColumn: ColumnInstance<T>;
4
+ submittedSearchText: string;
5
+ };
6
+ export type InputAndCheckProps<T extends object> = {
7
+ closeOutSearch: (value: number | null) => void;
8
+ setResetSearch: React.Dispatch<React.SetStateAction<boolean>>;
9
+ setEditingHeader: (value: number | null) => void;
10
+ column: ColumnInstance<T>;
11
+ searchCriteria: SearchCriterion<T>[];
12
+ setSearchCriteria: React.Dispatch<React.SetStateAction<SearchCriterion<T>[]>>;
13
+ badgeColor?: string;
14
+ badgeIcon?: {
15
+ icon: string;
16
+ weight: string;
17
+ };
18
+ iconBadgeContainerClasses?: string;
19
+ searchIcon?: {
20
+ icon: string;
21
+ weight: string;
22
+ };
23
+ cancelIcon?: {
24
+ icon: string;
25
+ weight: string;
26
+ };
27
+ initialIcon?: {
28
+ icon: string;
29
+ weight: string;
30
+ };
31
+ initialIconClasses?: string;
32
+ searchIconClasses?: string;
33
+ additionalInputClasses?: string;
34
+ secondIconClasses?: string;
35
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import { MagnifyingIconProps } from "./types";
3
+ declare const MagnifyingIcon: React.ForwardRefExoticComponent<MagnifyingIconProps<any> & React.RefAttributes<HTMLDivElement>>;
4
+ export default MagnifyingIcon;