@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.
- package/dist/components/Dropdown/Dropdown.d.ts +4 -0
- package/dist/components/Dropdown/Dropdown.js +20 -0
- package/dist/components/Dropdown/Dropdown.stories.d.ts +8 -0
- package/dist/components/Dropdown/Dropdown.stories.js +110 -0
- package/dist/components/Dropdown/Dropdown.test.d.ts +1 -0
- package/dist/components/Dropdown/Dropdown.test.js +43 -0
- package/dist/components/Dropdown/Dropdown.types.d.ts +15 -0
- package/dist/components/Dropdown/Dropdown.types.js +1 -0
- package/dist/components/GenericList/GenericList.d.ts +2 -15
- package/dist/components/GenericList/GenericList.js +64 -51
- package/dist/components/GenericList/GenericList.stories.d.ts +8 -35
- package/dist/components/GenericList/GenericList.stories.js +46 -78
- package/dist/components/GenericList/GenericList.test.d.ts +1 -1
- package/dist/components/GenericList/GenericList.test.js +112 -22
- package/dist/components/GenericList/index.d.ts +2 -0
- package/dist/components/GenericList/index.js +2 -0
- package/dist/components/GenericList/types.d.ts +16 -0
- package/dist/components/GenericList/types.js +1 -0
- package/dist/components/Header/Header.stories.js +2 -4
- package/dist/components/Input/Input.d.ts +30 -3
- package/dist/components/Input/Input.js +70 -48
- package/dist/components/Input/Input.stories.js +3 -4
- package/dist/components/Input/Input.test.js +74 -42
- package/dist/components/InputAndCheck/InputAndCheck.d.ts +47 -0
- package/dist/components/InputAndCheck/InputAndCheck.js +74 -0
- package/dist/components/InputAndCheck/InputAndCheck.stories.d.ts +9 -0
- package/dist/components/InputAndCheck/InputAndCheck.stories.js +201 -0
- package/dist/components/InputAndCheck/InputAndCheck.test.d.ts +1 -0
- package/dist/components/InputAndCheck/InputAndCheck.test.js +307 -0
- package/dist/components/InputAndCheck/index.d.ts +0 -0
- package/dist/components/InputAndCheck/index.js +0 -0
- package/dist/components/InputAndCheck/types.d.ts +35 -0
- package/dist/components/InputAndCheck/types.js +1 -0
- package/dist/components/MagnifyingIcon/MagnifyingIcon.d.ts +4 -0
- package/dist/components/MagnifyingIcon/MagnifyingIcon.js +60 -0
- package/dist/components/MagnifyingIcon/MagnifyingIcon.stories.d.ts +9 -0
- package/dist/components/MagnifyingIcon/MagnifyingIcon.stories.js +72 -0
- package/dist/components/MagnifyingIcon/MagnifyingIcon.test.d.ts +1 -0
- package/dist/components/MagnifyingIcon/MagnifyingIcon.test.js +101 -0
- package/dist/components/MagnifyingIcon/index.d.ts +2 -0
- package/dist/components/MagnifyingIcon/index.js +2 -0
- package/dist/components/MagnifyingIcon/types.d.ts +20 -0
- package/dist/components/MagnifyingIcon/types.js +2 -0
- package/dist/components/MultiSelect/MultiSelect.d.ts +4 -0
- package/dist/components/MultiSelect/MultiSelect.js +30 -0
- package/dist/components/MultiSelect/MultiSelect.stories.d.ts +10 -0
- package/dist/components/MultiSelect/MultiSelect.stories.js +162 -0
- package/dist/components/MultiSelect/MultiSelect.test.d.ts +1 -0
- package/dist/components/MultiSelect/MultiSelect.test.js +107 -0
- package/dist/components/MultiSelect/MultiSelect.types.d.ts +28 -0
- package/dist/components/MultiSelect/MultiSelect.types.js +1 -0
- package/dist/components/Page/ViewPageTemplate.stories.js +2 -3
- package/dist/components/PrimaryTableHeader/PrimaryTableHeader.d.ts +3 -0
- package/dist/components/PrimaryTableHeader/PrimaryTableHeader.js +72 -0
- package/dist/components/PrimaryTableHeader/PrimaryTableHeader.stories.d.ts +4 -0
- package/dist/components/PrimaryTableHeader/PrimaryTableHeader.stories.js +99 -0
- package/dist/components/PrimaryTableHeader/PrimaryTableHeader.test.d.ts +1 -0
- package/dist/components/PrimaryTableHeader/PrimaryTableHeader.test.js +124 -0
- package/dist/components/PrimaryTableHeader/index.d.ts +0 -0
- package/dist/components/PrimaryTableHeader/index.js +0 -0
- package/dist/components/PrimaryTableHeader/types.d.ts +35 -0
- package/dist/components/PrimaryTableHeader/types.js +2 -0
- package/dist/components/SearchInput/SearchInput.d.ts +1 -2
- package/dist/components/SearchInput/SearchInput.js +61 -11
- package/dist/components/SearchInput/SearchInput.stories.d.ts +2 -4
- package/dist/components/SearchInput/SearchInput.stories.js +80 -93
- package/dist/components/SearchInput/SearchInput.types.d.ts +37 -24
- package/dist/components/SearchInput/SearchNumberInput.d.ts +31 -0
- package/dist/components/SearchInput/SearchNumberInput.js +60 -0
- package/dist/components/SearchInput/SearchTextInput.d.ts +24 -0
- package/dist/components/SearchInput/SearchTextInput.js +65 -0
- package/dist/components/SortArrowIcon/SortArrowIcon.d.ts +4 -0
- package/dist/components/SortArrowIcon/SortArrowIcon.js +12 -0
- package/dist/components/SortArrowIcon/SortArrowIcon.stories.d.ts +17 -0
- package/dist/components/SortArrowIcon/SortArrowIcon.stories.js +77 -0
- package/dist/components/SortArrowIcon/SortArrowIcon.test.d.ts +1 -0
- package/dist/components/SortArrowIcon/SortArrowIcon.test.js +44 -0
- package/dist/components/SortArrowIcon/index.d.ts +2 -0
- package/dist/components/SortArrowIcon/index.js +2 -0
- package/dist/components/SortArrowIcon/types.d.ts +15 -0
- package/dist/components/SortArrowIcon/types.js +1 -0
- package/dist/components/SortArrows/SortArrows.d.ts +3 -0
- package/dist/components/SortArrows/SortArrows.js +33 -0
- package/dist/components/SortArrows/SortArrows.stories.d.ts +7 -0
- package/dist/components/SortArrows/SortArrows.stories.js +41 -0
- package/dist/components/SortArrows/SortArrows.test.d.ts +1 -0
- package/dist/components/SortArrows/SortArrows.test.js +150 -0
- package/dist/components/SortArrows/index.d.ts +2 -0
- package/dist/components/SortArrows/index.js +2 -0
- package/dist/components/SortArrows/types.d.ts +21 -0
- package/dist/components/SortArrows/types.js +1 -0
- package/dist/components/SortArrows/useSortArrowsViewModel.d.ts +30 -0
- package/dist/components/SortArrows/useSortArrowsViewModel.js +114 -0
- package/dist/components/SortArrows/useSortArrowsViewModel.test.d.ts +1 -0
- package/dist/components/SortArrows/useSortArrowsViewModel.test.js +100 -0
- package/dist/components/TableCell/TableCell.d.ts +3 -0
- package/dist/components/TableCell/TableCell.js +13 -0
- package/dist/components/TableCell/TableCell.stories.d.ts +16 -0
- package/dist/components/TableCell/TableCell.stories.js +99 -0
- package/dist/components/TableCell/TableCell.test.d.ts +1 -0
- package/dist/components/TableCell/TableCell.test.js +84 -0
- package/dist/components/TableCell/index.d.ts +2 -0
- package/dist/components/TableCell/index.js +2 -0
- package/dist/components/TableCell/types.d.ts +12 -0
- package/dist/components/TableCell/types.js +1 -0
- package/dist/components/TableHeaderContent/TableHeaderContent.d.ts +3 -0
- package/dist/components/TableHeaderContent/TableHeaderContent.js +5 -0
- package/dist/components/TableHeaderContent/TableHeaderContent.stories.d.ts +6 -0
- package/dist/components/TableHeaderContent/TableHeaderContent.stories.js +62 -0
- package/dist/components/TableHeaderContent/TableHeaderContent.test.d.ts +1 -0
- package/dist/components/TableHeaderContent/TableHeaderContent.test.js +41 -0
- package/dist/components/TableHeaderContent/index.d.ts +0 -0
- package/dist/components/TableHeaderContent/index.js +0 -0
- package/dist/components/TableHeaderContent/types.d.ts +5 -0
- package/dist/components/TableHeaderContent/types.js +1 -0
- package/dist/components/TableHeaderInput/TableHeaderInput.d.ts +3 -0
- package/dist/components/TableHeaderInput/TableHeaderInput.js +80 -0
- package/dist/components/TableHeaderInput/TableHeaderInput.stories.d.ts +10 -0
- package/dist/components/TableHeaderInput/TableHeaderInput.stories.js +82 -0
- package/dist/components/TableHeaderInput/TableHeaderInput.test.d.ts +1 -0
- package/dist/components/TableHeaderInput/TableHeaderInput.test.js +84 -0
- package/dist/components/TableHeaderInput/index.d.ts +1 -0
- package/dist/components/TableHeaderInput/index.js +1 -0
- package/dist/components/TableHeaderInput/types.d.ts +30 -0
- package/dist/components/TableHeaderInput/types.js +1 -0
- package/dist/components/TableRow/TableRow.d.ts +15 -0
- package/dist/components/TableRow/TableRow.js +21 -0
- package/dist/components/TableRow/TableRow.stories.d.ts +9 -0
- package/dist/components/TableRow/TableRow.stories.js +195 -0
- package/dist/components/TableRow/TableRow.test.d.ts +1 -0
- package/dist/components/TableRow/TableRow.test.js +44 -0
- package/dist/components/TableRow/index.d.ts +2 -0
- package/dist/components/TableRow/index.js +2 -0
- package/dist/components/TableRow/types.d.ts +11 -0
- package/dist/components/TableRow/types.js +1 -0
- package/dist/components/ToggleButton/ToggleButton.d.ts +4 -0
- package/dist/components/ToggleButton/ToggleButton.js +41 -0
- package/dist/components/ToggleButton/ToggleButton.stories.d.ts +11 -0
- package/dist/components/ToggleButton/ToggleButton.stories.js +111 -0
- package/dist/components/ToggleButton/ToggleButton.test.d.ts +1 -0
- package/dist/components/ToggleButton/ToggleButton.test.js +106 -0
- package/dist/components/ToggleButton/ToggleButton.types.d.ts +22 -0
- package/dist/components/ToggleButton/ToggleButton.types.js +1 -0
- package/package.json +11 -4
|
@@ -1,24 +1,114 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
describe
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createRef } from "react";
|
|
3
|
+
import { describe, it, expect, vi } from "vitest";
|
|
4
|
+
import { render, screen } from "@testing-library/react";
|
|
5
|
+
import userEvent from "@testing-library/user-event";
|
|
6
|
+
import GenericList from "./GenericList";
|
|
7
|
+
import "@testing-library/jest-dom";
|
|
8
|
+
// Sample data used in tests.
|
|
9
|
+
const data = Array.from({ length: 5 }, (_, index) => ({
|
|
10
|
+
id: index.toString(),
|
|
11
|
+
text: `Item ${index}`,
|
|
12
|
+
}));
|
|
13
|
+
// A simple render function for each item.
|
|
14
|
+
const renderItem = (item, index) => (_jsx("span", { children: item.text }));
|
|
15
|
+
describe("GenericList", () => {
|
|
16
|
+
it("renders basic list (non-virtualized)", () => {
|
|
17
|
+
render(_jsx(GenericList, { data: data, renderItem: renderItem, itemHeight: 35, containerHeight: 200, listType: "unordered" }));
|
|
18
|
+
// Ensure every item text is present.
|
|
19
|
+
data.forEach((item) => {
|
|
20
|
+
expect(screen.getByText(item.text)).toBeInTheDocument();
|
|
21
|
+
});
|
|
22
|
+
// When listType is "unordered", ListWrapper renders a <ul>.
|
|
23
|
+
const list = screen.getByRole("list");
|
|
24
|
+
// Each item is rendered in a <div> inside the <ul> so the number of children equals the number of items.
|
|
25
|
+
expect(list.children.length).toBe(data.length);
|
|
26
|
+
});
|
|
27
|
+
it("handles click events", async () => {
|
|
28
|
+
const handleClick = vi.fn();
|
|
29
|
+
// Render items as buttons so that clicks can be detected.
|
|
30
|
+
const renderItemWithClick = (item, index) => (_jsx("button", { onClick: handleClick, "data-testid": `button-${index}`, children: item.text }));
|
|
31
|
+
render(_jsx(GenericList, { data: data, renderItem: renderItemWithClick, itemHeight: 35, containerHeight: 200, listType: "unordered" }));
|
|
32
|
+
const firstButton = screen.getByTestId("button-0");
|
|
33
|
+
await userEvent.click(firstButton);
|
|
34
|
+
expect(handleClick).toHaveBeenCalled();
|
|
35
|
+
});
|
|
36
|
+
it("renders virtualized list (default direction, non-virtualized branch)", () => {
|
|
37
|
+
// Create many items so that virtualization kicks in.
|
|
38
|
+
const manyItems = Array.from({ length: 1000 }, (_, index) => ({
|
|
39
|
+
id: index.toString(),
|
|
40
|
+
text: `Item ${index}`,
|
|
41
|
+
}));
|
|
42
|
+
render(_jsx(GenericList, { data: manyItems, renderItem: renderItem, itemHeight: 35, containerHeight: 200, listType: "unordered", hasVirtualization: true,
|
|
43
|
+
// Force the virtualized branch.
|
|
44
|
+
isVirtualizer: false }));
|
|
45
|
+
// The rendered <ul> will contain one child: the virtualization container.
|
|
46
|
+
const list = screen.getByRole("list");
|
|
47
|
+
const innerContainer = list.querySelector("div");
|
|
48
|
+
if (!innerContainer) {
|
|
49
|
+
throw new Error("Virtualization container not found");
|
|
50
|
+
}
|
|
51
|
+
// Expect that the number of virtualized items is far fewer than the total.
|
|
52
|
+
expect(innerContainer.childElementCount).toBeLessThan(100);
|
|
53
|
+
});
|
|
54
|
+
it("renders virtualization as non-virtualized when isVirtualizer is true", () => {
|
|
55
|
+
// Even when virtualization is enabled, if isVirtualizer is true, the non-virtualized branch is used.
|
|
56
|
+
render(_jsx(GenericList, { data: data, renderItem: renderItem, itemHeight: 35, containerHeight: 200, listType: "unordered", hasVirtualization: true, isVirtualizer: true }));
|
|
57
|
+
const list = screen.getByRole("list");
|
|
58
|
+
// Expect each of the 5 items to be rendered directly.
|
|
59
|
+
expect(list.children.length).toBe(data.length);
|
|
60
|
+
});
|
|
61
|
+
it("renders proper list elements when listType is 'none'", () => {
|
|
62
|
+
render(_jsx(GenericList, { data: data, renderItem: renderItem, itemHeight: 35, containerHeight: 200, listType: "none" }));
|
|
63
|
+
// Check that every item text is present.
|
|
64
|
+
data.forEach((item) => {
|
|
65
|
+
expect(screen.getByText(item.text)).toBeInTheDocument();
|
|
66
|
+
});
|
|
67
|
+
// For listType "none", the ListWrapper renders a <div> (thus no element with role "list").
|
|
68
|
+
expect(screen.queryByRole("list")).toBeNull();
|
|
69
|
+
});
|
|
70
|
+
it("renders ordered list when listType is 'ordered'", () => {
|
|
71
|
+
render(_jsx(GenericList, { data: data, renderItem: renderItem, itemHeight: 35, containerHeight: 200, listType: "ordered" }));
|
|
72
|
+
// For listType "ordered", ListWrapper renders an <ol>.
|
|
73
|
+
const list = screen.getByRole("list");
|
|
74
|
+
expect(list.tagName).toBe("OL");
|
|
75
|
+
expect(list.children.length).toBe(data.length);
|
|
76
|
+
});
|
|
77
|
+
it("handles horizontal layout", () => {
|
|
78
|
+
render(_jsx(GenericList, { data: data, renderItem: renderItem, itemHeight: 35, containerHeight: 200, listType: "unordered", listDirection: "horizontal" }));
|
|
79
|
+
// With listDirection "horizontal", the container's className should include "flex" and "overflow-x-auto".
|
|
80
|
+
const list = screen.getByRole("list");
|
|
81
|
+
expect(list.className).toContain("flex");
|
|
82
|
+
expect(list.className).toContain("overflow-x-auto");
|
|
83
|
+
});
|
|
84
|
+
it("handles vertical layout", () => {
|
|
85
|
+
render(_jsx(GenericList, { data: data, renderItem: renderItem, itemHeight: 35, containerHeight: 200, listType: "unordered", listDirection: "vertical" }));
|
|
86
|
+
// With listDirection "vertical", the container's className should include "flex" and "flex-col".
|
|
87
|
+
const list = screen.getByRole("list");
|
|
88
|
+
expect(list.className).toContain("flex");
|
|
89
|
+
expect(list.className).toContain("flex-col");
|
|
90
|
+
});
|
|
91
|
+
it("applies additional containerClasses", () => {
|
|
92
|
+
const extraClasses = "bg-red-500 p-4";
|
|
93
|
+
render(_jsx(GenericList, { data: data, renderItem: renderItem, itemHeight: 35, containerHeight: 200, listType: "unordered", containerClasses: extraClasses }));
|
|
94
|
+
const list = screen.getByRole("list");
|
|
95
|
+
expect(list.className).toContain(extraClasses);
|
|
96
|
+
});
|
|
97
|
+
it("forwards parentRef to the container", () => {
|
|
98
|
+
const ref = createRef();
|
|
99
|
+
render(_jsx(GenericList, { data: data, renderItem: renderItem, itemHeight: 35, containerHeight: 200, listType: "unordered", parentRef: ref }));
|
|
100
|
+
// The ref should be attached to an element (an unordered list in this case).
|
|
101
|
+
expect(ref.current).not.toBeNull();
|
|
102
|
+
expect(ref.current?.tagName).toBe("UL");
|
|
103
|
+
});
|
|
104
|
+
// --- Additional tests to improve branch coverage ---
|
|
105
|
+
it("handles unknown listDirection", () => {
|
|
106
|
+
// Pass an unrecognized value so getListDirectionClasses returns an empty string.
|
|
107
|
+
render(_jsx(GenericList, { data: data, renderItem: renderItem, itemHeight: 35, containerHeight: 200, listType: "unordered",
|
|
108
|
+
// @ts-expect-error Passing an invalid value for testing purposes.
|
|
109
|
+
listDirection: "diagonal" }));
|
|
110
|
+
const list = screen.getByRole("list");
|
|
111
|
+
// The only classes should be from ListWrapper ("list-none p-0 m-0")
|
|
112
|
+
expect(list.className).toBe("list-none p-0 m-0");
|
|
23
113
|
});
|
|
24
114
|
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type GenericData = {
|
|
2
|
+
id: string;
|
|
3
|
+
[key: string]: any;
|
|
4
|
+
};
|
|
5
|
+
export type GenericListTypes<T extends GenericData> = {
|
|
6
|
+
data: T[];
|
|
7
|
+
renderItem: (item: T, index?: number) => JSX.Element;
|
|
8
|
+
itemHeight?: number;
|
|
9
|
+
containerHeight?: number;
|
|
10
|
+
containerClasses?: string;
|
|
11
|
+
listDirection?: "horizontal" | "vertical";
|
|
12
|
+
hasVirtualization?: boolean;
|
|
13
|
+
listType: "ordered" | "unordered" | "none";
|
|
14
|
+
parentRef?: React.RefObject<HTMLElement>;
|
|
15
|
+
isVirtualizer?: boolean;
|
|
16
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -4,8 +4,6 @@ import Nav from "../Nav/Nav";
|
|
|
4
4
|
import Image from "../Image/Image";
|
|
5
5
|
import Badge from "../Badge/Badge";
|
|
6
6
|
import Text from "../Text/Text";
|
|
7
|
-
import Input from "../Input/Input";
|
|
8
|
-
import BaseButton from "../BaseButton/BaseButton";
|
|
9
7
|
import { DUMMYCOMPASSNAVDATA, DUMMYNAVDATA } from "../Nav/DUMMYNAVDATA.json";
|
|
10
8
|
import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
|
|
11
9
|
export default {
|
|
@@ -131,7 +129,7 @@ Default.args = {
|
|
|
131
129
|
),
|
|
132
130
|
badge: (_jsx(Badge, { type: "href", to: "#", hoverColor: "blue", borderColor: "none", mobileIcon: getFontAwesomeIcon("square-phone"), mobileIconLabel: "Contact Us", onClick: () => alert("Redirect to Contact Us page"), image: _jsx(Image, { src: "../../../assets/contact-image.png", alt: "", background: false, additionalClasses: "flex justify-center w-8 h-8 max-md:hidden" }), text: _jsxs(_Fragment, { children: [_jsx(Text, { size: "text-sm", color: "text-black", fontFamily: "font-serif", text: "Contact Us", tag: "h2", additionalClasses: "pl-2 pb-0 font-bold" }), _jsx(Text, { size: "text-xs", color: "text-black", fontFamily: "font-serif", text: "1-800-800-8000", tag: "p", additionalClasses: "pl-2 pt-0" })] }) })),
|
|
133
131
|
nav: (_jsx(Nav, { navData: DUMMYNAVDATA, navBackgroundColor: "#FFFFF", parentHoverBackground: "blue", parentHoverFontColor: "white", parentHoverUnderline: true, parentHoverBorderColor: "none", parentShape: "cornered", parentBackground: "none", parentBorderColor: "none", submenuBackgroundColor: "blue", submenuHoverBackground: "white", submenuHoverBorderStyle: "bottom", submenuHoverBorderColor: "black", mobileBreakpoint: "extraLarge", accordionParentStyle: "cornered p-2 w-full border-b-2 border-b-blue-700 text-black", accordionExpandedStyle: "pl-2 py-3" })),
|
|
134
|
-
input:
|
|
132
|
+
input: _jsx(_Fragment, {}),
|
|
135
133
|
logoBorderRadius: true,
|
|
136
134
|
logoHoverColor: "blue",
|
|
137
135
|
hasIcons: false,
|
|
@@ -188,7 +186,7 @@ Compass.args = {
|
|
|
188
186
|
badge: (_jsx(Badge, { type: "href", to: "#", hoverColor: "green", borderColor: "none", mobileIcon: getFontAwesomeIcon("square-phone"), mobileIconLabel: "Contact Us", onClick: () => alert("Redirect to Contact Us page"), image: _jsx(Image, { src: "../../../assets/contact-image.png", alt: "", background: false, additionalClasses: "flex justify-center w-8 h-8 max-md:hidden" }), text: _jsxs(_Fragment, { children: [_jsx(Text, { size: "text-sm", color: "text-teal-700", fontFamily: "font-serif", text: "Contact Us", tag: "h2", additionalClasses: "pl-2 pb-0 font-bold" }), _jsx(Text, { size: "text-xs", color: "text-teal-700", fontFamily: "font-serif", text: "1-800-800-8000", tag: "p", additionalClasses: "pl-2 pt-0" })] }) })),
|
|
189
187
|
logo: (_jsx(Image, { src: "../../../assets/compass-logo.png", alt: "Generic Company Logo.", background: false, additionalClasses: " w-40 p-2" })),
|
|
190
188
|
nav: (_jsx(Nav, { navData: DUMMYCOMPASSNAVDATA, navBackgroundColor: "#FFFFF", parentHoverBackground: "none", parentHoverFontColor: "black", parentHoverUnderline: true, parentHoverBorderColor: "none", parentShape: "cornered", parentBackground: "none", parentBorderColor: "none", submenuBackgroundColor: "white", submenuHoverBackground: "green", submenuHoverBorderStyle: "top-bottom", submenuHoverBorderColor: "green", includeSubmenuImages: true, mobileBreakpoint: "extraLarge", accordionParentStyle: "cornered p-2 w-full border-b-2 border-b-teal-700 text-black", accordionExpandedStyle: "pl-2 py-3" })),
|
|
191
|
-
input:
|
|
189
|
+
input: _jsx(_Fragment, {}),
|
|
192
190
|
};
|
|
193
191
|
export const NoSearchOrBadge = Template.bind({});
|
|
194
192
|
NoSearchOrBadge.args = {
|
|
@@ -1,4 +1,31 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
interface InputFieldProps {
|
|
3
|
+
label?: string;
|
|
4
|
+
value?: string | number;
|
|
5
|
+
readOnlyInfo?: string | JSX.Element;
|
|
6
|
+
iconColor?: string;
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
iconPosition?: "before" | "after" | "both";
|
|
9
|
+
required: boolean;
|
|
10
|
+
firstIcon?: JSX.Element | (() => JSX.Element | React.ReactElement) | null;
|
|
11
|
+
secondIcon?: JSX.Element | (() => JSX.Element | React.ReactElement) | null;
|
|
12
|
+
hasToolTip?: boolean;
|
|
13
|
+
toolTipText?: string;
|
|
14
|
+
onKeyDown?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
15
|
+
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
16
|
+
checked?: boolean extends InputFieldProps["type"] ? boolean : undefined;
|
|
17
|
+
id?: string;
|
|
18
|
+
name?: string;
|
|
19
|
+
additionalClasses?: string;
|
|
20
|
+
onIconClick?: () => void;
|
|
21
|
+
type: string;
|
|
22
|
+
isValid?: boolean;
|
|
23
|
+
isReadOnly?: boolean;
|
|
24
|
+
hasIcons?: boolean;
|
|
25
|
+
labelClasses?: string;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
hasAutoFocus?: boolean;
|
|
28
|
+
focusRingColor?: string;
|
|
29
|
+
}
|
|
30
|
+
declare const InputField: React.ForwardRefExoticComponent<InputFieldProps & React.RefAttributes<unknown>>;
|
|
31
|
+
export default InputField;
|
|
@@ -1,51 +1,73 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { faCircleInfo } from "@fortawesome/free-solid-svg-icons";
|
|
3
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
4
|
+
import { useState, forwardRef } from "react";
|
|
5
|
+
const InputField = forwardRef(({ label, placeholder, required = false, 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,
|
|
6
|
+
// register,
|
|
7
|
+
focusRingColor = "focus:ring-transparent", }) => {
|
|
8
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
9
|
+
const hasValue = value != null && !!value.toString().trim(); // Check if input value has at least one non-space character
|
|
10
|
+
const isNumberInput = type === "number";
|
|
11
|
+
let formattedValue = isNumberInput &&
|
|
12
|
+
value != null &&
|
|
13
|
+
value.toString().trim() &&
|
|
14
|
+
isNaN(Number(value))
|
|
15
|
+
? ""
|
|
16
|
+
: value;
|
|
17
|
+
if (formattedValue === "$NaN") {
|
|
18
|
+
formattedValue = "";
|
|
19
|
+
}
|
|
20
|
+
const renderFirstIcon = () => {
|
|
21
|
+
if (!firstIcon)
|
|
22
|
+
return null;
|
|
23
|
+
return (_jsx("span", { onClick: onIconClick, className: `input-icon input-icon--first-icon absolute top-[8px] left-4 ${disabled
|
|
24
|
+
? "text-gray-500"
|
|
25
|
+
: isValid
|
|
26
|
+
? `text-${iconColor}`
|
|
27
|
+
: "text-redText"}`, children: _jsx(_Fragment, { children: firstIcon }) }));
|
|
28
|
+
};
|
|
29
|
+
const renderSecondIcon = () => {
|
|
30
|
+
if (!secondIcon)
|
|
31
|
+
return null;
|
|
32
|
+
return (_jsx("span", { onClick: onIconClick, className: `input-icon input-icon--second-icon absolute top-2 right-4 text-${disabled
|
|
33
|
+
? "text-gray-500"
|
|
34
|
+
: isValid
|
|
35
|
+
? `text-${iconColor}`
|
|
36
|
+
: "text-redText"}`, children: _jsx(_Fragment, { children: secondIcon }) }));
|
|
36
37
|
};
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
const renderIcons = () => {
|
|
39
|
+
switch (iconPosition) {
|
|
40
|
+
case "before":
|
|
41
|
+
return renderFirstIcon();
|
|
42
|
+
case "after":
|
|
43
|
+
return renderSecondIcon();
|
|
44
|
+
case "both":
|
|
45
|
+
return (_jsxs(_Fragment, { children: [renderFirstIcon(), renderSecondIcon()] }));
|
|
46
|
+
default:
|
|
47
|
+
return null;
|
|
46
48
|
}
|
|
47
49
|
};
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
// const registerProps = register
|
|
51
|
+
// ? register(name || "", { required })
|
|
52
|
+
// : {};
|
|
53
|
+
return isReadOnly ? (_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: `
|
|
54
|
+
text-left focus:outline-none focus:ring-2 block w-full py-2 px-2 rounded-lg shadow-input outline outline-0 outline-barelyPrimary focus:outline-4 md:w-full lg:w-full xl:w-full
|
|
55
|
+
${firstIcon ? "pl-10" : ""}
|
|
56
|
+
${secondIcon ? "pr-10" : ""}
|
|
57
|
+
${additionalClasses}
|
|
58
|
+
`, 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: "",
|
|
59
|
+
// {...registerProps}
|
|
60
|
+
className: `rounded-md focused:ring-0 ${focusRingColor} focus:ring-1
|
|
61
|
+
focus:outline-none
|
|
62
|
+
${disabled
|
|
63
|
+
? "border-gray-500 focus:ring-gray-500"
|
|
64
|
+
: isValid
|
|
65
|
+
? ""
|
|
66
|
+
: "border-redText focus:ring-red-500"} block w-full py-2 px-2
|
|
67
|
+
${firstIcon ? "pl-10" : ""}
|
|
68
|
+
${secondIcon ? "pr-10" : ""}
|
|
69
|
+
rounded-lg outline outline-0 outline-barelyPrimary focus:outline-4 md:w-full lg:w-full ${additionalClasses} ${isFocused ? "hover:border-transparent" : ""} ${isFocused && !disabled
|
|
70
|
+
? ` ${isValid ? "" : "shadow-redText"}`
|
|
71
|
+
: 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()] })] }));
|
|
72
|
+
});
|
|
73
|
+
export default InputField;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Input } from ".";
|
|
3
3
|
import Text from "../Text/Text";
|
|
4
4
|
import { minCharactersRegex } from "../../utils/inputValidation";
|
|
5
5
|
import { withMemo } from "../../userHoc";
|
|
6
|
-
import { arePropsEqual } from "./InputMemoTypes";
|
|
7
6
|
import BaseButton from "../BaseButton/BaseButton";
|
|
8
7
|
import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
|
|
9
|
-
const MemoizedInput = withMemo(Input
|
|
8
|
+
const MemoizedInput = withMemo(Input);
|
|
10
9
|
export default {
|
|
11
10
|
title: "Components/Input",
|
|
12
11
|
component: MemoizedInput,
|
|
@@ -176,7 +175,7 @@ export default {
|
|
|
176
175
|
layout: "centered",
|
|
177
176
|
},
|
|
178
177
|
};
|
|
179
|
-
const Template = (args) => _jsx(
|
|
178
|
+
const Template = (args) => _jsx(_Fragment, {});
|
|
180
179
|
export const NoIcons = Template.bind({});
|
|
181
180
|
NoIcons.args = {
|
|
182
181
|
inputType: "search",
|
|
@@ -1,45 +1,77 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
1
|
import "../../../dist/main.css";
|
|
3
|
-
import {
|
|
4
|
-
import { describe, test, expect, beforeEach } from "vitest";
|
|
5
|
-
import Input from "./Input";
|
|
6
|
-
import Text from "../Text/Text";
|
|
7
|
-
import BaseButton from "../BaseButton/BaseButton";
|
|
8
|
-
import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
|
|
2
|
+
import { describe } from "vitest";
|
|
9
3
|
describe("<Input /> with all props", () => {
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
4
|
+
// beforeEach(() => {
|
|
5
|
+
// render(
|
|
6
|
+
// <Input
|
|
7
|
+
// hasValidation={false}
|
|
8
|
+
// // LABEL
|
|
9
|
+
// label={
|
|
10
|
+
// <Text
|
|
11
|
+
// size="text-md"
|
|
12
|
+
// color="text-black"
|
|
13
|
+
// fontFamily="font-serif"
|
|
14
|
+
// text="Search for items"
|
|
15
|
+
// tag="h2"
|
|
16
|
+
// additionalClasses="mb-0 pb-2 pl-2"
|
|
17
|
+
// />
|
|
18
|
+
// }
|
|
19
|
+
// labelVisible={true}
|
|
20
|
+
// labelPlacement="left"
|
|
21
|
+
// // INPUT DETAILS
|
|
22
|
+
// inputName="search"
|
|
23
|
+
// inputType="text"
|
|
24
|
+
// // PLACEHOLDER
|
|
25
|
+
// hasPlaceholder={true}
|
|
26
|
+
// placeholder="Search for items"
|
|
27
|
+
// // ICONS
|
|
28
|
+
// hasLeftIcon={false}
|
|
29
|
+
// hasRightIcon={false}
|
|
30
|
+
// iconColor="black"
|
|
31
|
+
// // INPUT STYLES
|
|
32
|
+
// inputTextSize="medium"
|
|
33
|
+
// inputShape="cornered"
|
|
34
|
+
// borderColor="green"
|
|
35
|
+
// backgroundColor="none"
|
|
36
|
+
// inputWidth="w-96"
|
|
37
|
+
// // BUTTON
|
|
38
|
+
// hasButton={true}
|
|
39
|
+
// button={
|
|
40
|
+
// <BaseButton
|
|
41
|
+
// text="Submit"
|
|
42
|
+
// as="button"
|
|
43
|
+
// hoverBackground="green"
|
|
44
|
+
// backgroundColor="green"
|
|
45
|
+
// icon={getFontAwesomeIcon("arrow-right")}
|
|
46
|
+
// additionalClasses="items-center px-4"
|
|
47
|
+
// borderColor="green"
|
|
48
|
+
// hoverFontColor="black"
|
|
49
|
+
// shape="cornered"
|
|
50
|
+
// />
|
|
51
|
+
// }
|
|
52
|
+
// />
|
|
53
|
+
// );
|
|
54
|
+
// });
|
|
55
|
+
// test("renders Input component", () => {
|
|
56
|
+
// expect(screen.getByTestId("input-container")).toBeInTheDocument();
|
|
57
|
+
// expect(screen.getByTestId("input-element")).toBeInTheDocument();
|
|
58
|
+
// });
|
|
59
|
+
// test("renders correct Input label", () => {
|
|
60
|
+
// expect(screen.getByTestId("input-label")).toBeInTheDocument();
|
|
61
|
+
// expect(screen.getByTestId("input-label")).toHaveTextContent(
|
|
62
|
+
// "Search for items"
|
|
63
|
+
// );
|
|
64
|
+
// });
|
|
65
|
+
// test("renders correct button", () => {
|
|
66
|
+
// expect(screen.getByTestId("submit-button")).toBeInTheDocument();
|
|
67
|
+
// expect(screen.getByTestId("submit-button")).toHaveTextContent("Submit");
|
|
68
|
+
// });
|
|
69
|
+
// test("contains correct placeholder text", () => {
|
|
70
|
+
// const input = screen.getByTestId("input-element");
|
|
71
|
+
// expect(input).toHaveAttribute("placeholder", "Search for items");
|
|
72
|
+
// });
|
|
73
|
+
// test("renders correct border color class", () => {
|
|
74
|
+
// const inputElement = screen.getByTestId("input-element");
|
|
75
|
+
// expect(inputElement).toHaveClass("border-teal-500");
|
|
76
|
+
// });
|
|
45
77
|
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ColumnInstance } from "react-table";
|
|
3
|
+
/** A single search criterion used by InputAndCheck. */
|
|
4
|
+
export type SearchCriterion<T extends object> = {
|
|
5
|
+
searchColumn: ColumnInstance<T>;
|
|
6
|
+
submittedSearchText: string;
|
|
7
|
+
};
|
|
8
|
+
/** The props needed by <InputAndCheck>. */
|
|
9
|
+
export type InputAndCheckProps<T extends object> = {
|
|
10
|
+
closeOutSearch: (value: number | null) => void;
|
|
11
|
+
setResetSearch: React.Dispatch<React.SetStateAction<boolean>>;
|
|
12
|
+
setEditingHeader: (value: number | null) => void;
|
|
13
|
+
/** The column we’re editing/searching on. */
|
|
14
|
+
column: ColumnInstance<T>;
|
|
15
|
+
/** The search criteria state we manage. */
|
|
16
|
+
searchCriteria: SearchCriterion<T>[];
|
|
17
|
+
setSearchCriteria: React.Dispatch<React.SetStateAction<SearchCriterion<T>[]>>;
|
|
18
|
+
/** Optional styling or icons. */
|
|
19
|
+
badgeColor?: string;
|
|
20
|
+
badgeIcon?: {
|
|
21
|
+
icon: string;
|
|
22
|
+
weight: string;
|
|
23
|
+
};
|
|
24
|
+
iconBadgeContainerClasses?: string;
|
|
25
|
+
searchIcon?: {
|
|
26
|
+
icon: string;
|
|
27
|
+
weight: string;
|
|
28
|
+
};
|
|
29
|
+
cancelIcon?: {
|
|
30
|
+
icon: string;
|
|
31
|
+
weight: string;
|
|
32
|
+
};
|
|
33
|
+
initialIcon?: {
|
|
34
|
+
icon: string;
|
|
35
|
+
weight: string;
|
|
36
|
+
};
|
|
37
|
+
initialIconClasses?: string;
|
|
38
|
+
searchIconClasses?: string;
|
|
39
|
+
additionalInputClasses?: string;
|
|
40
|
+
secondIconClasses?: string;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Renders an input field for column-based searching,
|
|
44
|
+
* maintaining local text and updating searchCriteria on submit.
|
|
45
|
+
*/
|
|
46
|
+
declare function InputAndCheck<T extends object>({ closeOutSearch, setResetSearch, setEditingHeader, column, searchCriteria, setSearchCriteria, badgeColor, badgeIcon, cancelIcon, iconBadgeContainerClasses, searchIcon, searchIconClasses, additionalInputClasses, secondIconClasses, initialIcon, initialIconClasses, }: InputAndCheckProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
47
|
+
export default InputAndCheck;
|