@agilant/toga-blox 1.0.5
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/Dockerfile +9 -0
- package/README.md +69 -0
- package/assets/Logo.png +0 -0
- package/assets/compass-card-image-2.png +0 -0
- package/assets/compass-card-image-3.png +0 -0
- package/assets/compass-card-image-4.png +0 -0
- package/assets/compass-card-image.png +0 -0
- package/assets/compass-logo.png +0 -0
- package/assets/compass-tech-hero-bg.png +0 -0
- package/assets/contact-image.png +0 -0
- package/assets/green-laptop.png +0 -0
- package/assets/heroImage.png +0 -0
- package/assets/placeholder-no-image-available.png +0 -0
- package/assets/team.png +0 -0
- package/declarations.d.ts +4 -0
- package/docker-compose.yml +22 -0
- package/global.css +4 -0
- package/index.js +4 -0
- package/nodemon.json +5 -0
- package/package.json +70 -0
- package/postcss.config.js +6 -0
- package/src/components/Badge/Badge.stories.tsx +284 -0
- package/src/components/Badge/Badge.test.tsx +185 -0
- package/src/components/Badge/Badge.tsx +137 -0
- package/src/components/Badge/Badge.types.tsx +28 -0
- package/src/components/Badge/badgeClassNames.tsx +152 -0
- package/src/components/Badge/index.ts +2 -0
- package/src/components/Card/Card.stories.tsx +91 -0
- package/src/components/Card/Card.test.tsx +53 -0
- package/src/components/Card/Card.tsx +30 -0
- package/src/components/Card/Card.types.ts +11 -0
- package/src/components/Card/DUMMYPRODUCTDATA.json +670 -0
- package/src/components/Card/cardClassNames.ts +49 -0
- package/src/components/Card/index.ts +3 -0
- package/src/components/Card/templates/CompassCardTemplate.tsx +58 -0
- package/src/components/Card/templates/HorizontalCardTemplate.tsx +184 -0
- package/src/components/Card/templates/VerticalCardTemplate.tsx +154 -0
- package/src/components/Footer/ContactInfoItem.tsx +20 -0
- package/src/components/Footer/DUMMYFOOTERDATA.json +132 -0
- package/src/components/Footer/Footer.stories.tsx +292 -0
- package/src/components/Footer/Footer.test.tsx +90 -0
- package/src/components/Footer/Footer.tsx +159 -0
- package/src/components/Footer/Footer.types.tsx +61 -0
- package/src/components/Footer/footerClassNames.tsx +57 -0
- package/src/components/FormButton/FormButton.stories.tsx +199 -0
- package/src/components/FormButton/FormButton.test.tsx +73 -0
- package/src/components/FormButton/FormButton.tsx +116 -0
- package/src/components/FormButton/FormButton.types.ts +32 -0
- package/src/components/FormButton/formButtonClassNames.tsx +153 -0
- package/src/components/FormButton/index.ts +2 -0
- package/src/components/GenericList/DUMMYLISTDATA.json +560 -0
- package/src/components/GenericList/GenericList.stories.tsx +104 -0
- package/src/components/GenericList/GenericList.test.tsx +29 -0
- package/src/components/GenericList/GenericList.tsx +146 -0
- package/src/components/GenericList/genericListClassNames.tsx +8 -0
- package/src/components/GenericList/templates/DummyDataList.tsx +23 -0
- package/src/components/GenericList/templates/DynamicIconList.tsx +74 -0
- package/src/components/HamburgerButton/HamburgerButton.tsx +68 -0
- package/src/components/HamburgerButton/HamburgerButton.types.tsx +6 -0
- package/src/components/HamburgerButton/index.ts +2 -0
- package/src/components/Header/DUMMYICONDATA.json +136 -0
- package/src/components/Header/Header.stories.tsx +521 -0
- package/src/components/Header/Header.test.tsx +323 -0
- package/src/components/Header/Header.tsx +289 -0
- package/src/components/Header/Header.types.ts +52 -0
- package/src/components/Header/headerClassNames.tsx +50 -0
- package/src/components/Header/headerContext.tsx +125 -0
- package/src/components/Header/index.ts +2 -0
- package/src/components/Hero/Hero.stories.tsx +69 -0
- package/src/components/Hero/Hero.test.tsx +109 -0
- package/src/components/Hero/Hero.tsx +58 -0
- package/src/components/Hero/Hero.types.ts +9 -0
- package/src/components/Hero/index.ts +2 -0
- package/src/components/Icon/Icon.stories.tsx +227 -0
- package/src/components/Icon/Icon.test.tsx +53 -0
- package/src/components/Icon/Icon.tsx +208 -0
- package/src/components/Icon/Icon.types.ts +24 -0
- package/src/components/Icon/iconClassNames.ts +79 -0
- package/src/components/Icon/index.ts +2 -0
- package/src/components/Image/Image.stories.tsx +79 -0
- package/src/components/Image/Image.test.tsx +87 -0
- package/src/components/Image/Image.tsx +49 -0
- package/src/components/Image/Image.types.ts +11 -0
- package/src/components/Image/index.ts +2 -0
- package/src/components/Input/Input.stories.tsx +651 -0
- package/src/components/Input/Input.test.tsx +90 -0
- package/src/components/Input/Input.tsx +226 -0
- package/src/components/Input/Input.types.ts +52 -0
- package/src/components/Input/InputMemoTypes.tsx +32 -0
- package/src/components/Input/index.ts +2 -0
- package/src/components/Input/inputClassNames.tsx +169 -0
- package/src/components/MobileMenu/MobileMenu.tsx +41 -0
- package/src/components/MobileMenu/MobileMenu.types.tsx +30 -0
- package/src/components/MobileMenu/index.ts +2 -0
- package/src/components/Nav/DUMMYNAVDATA.json +234 -0
- package/src/components/Nav/Nav.stories.tsx +181 -0
- package/src/components/Nav/Nav.test.tsx +89 -0
- package/src/components/Nav/Nav.tsx +242 -0
- package/src/components/Nav/Nav.types.tsx +35 -0
- package/src/components/Nav/index.ts +2 -0
- package/src/components/Nav/navClassNames.tsx +192 -0
- package/src/components/Page/TableDataDummy.tsx +216 -0
- package/src/components/Page/ViewPageTemplate.stories.tsx +546 -0
- package/src/components/Page/ViewPageTemplate.test.tsx +361 -0
- package/src/components/Page/ViewPageTemplate.tsx +10 -0
- package/src/components/Page/ViewPageTemplate.types.ts +6 -0
- package/src/components/Page/index.ts +2 -0
- package/src/components/PageSection/PageSection.stories.tsx +114 -0
- package/src/components/PageSection/PageSection.tsx +12 -0
- package/src/components/PageSection/PageSection.types.ts +6 -0
- package/src/components/PageSection/PageSections.test.tsx +88 -0
- package/src/components/PageSection/index.ts +2 -0
- package/src/components/Text/Text.stories.tsx +60 -0
- package/src/components/Text/Text.test.tsx +52 -0
- package/src/components/Text/Text.tsx +80 -0
- package/src/components/Text/Text.types.ts +12 -0
- package/src/components/Text/index.ts +2 -0
- package/src/components/Toaster/Toaster.stories.tsx +122 -0
- package/src/components/Toaster/Toaster.test.tsx +61 -0
- package/src/components/Toaster/Toaster.tsx +80 -0
- package/src/components/Toaster/Toaster.types.ts +12 -0
- package/src/components/Toaster/index.ts +2 -0
- package/src/hoc/index.ts +2 -0
- package/src/hoc/styling/withStoryBook.tsx +19 -0
- package/src/main.css +3 -0
- package/src/setupTests.ts +1 -0
- package/src/userHoc/index.ts +1 -0
- package/src/userHoc/withMemo.tsx +20 -0
- package/src/utils/assertTagName.tsx +7 -0
- package/src/utils/generateAccordionItem.tsx +102 -0
- package/src/utils/generateFooterContacts.tsx +75 -0
- package/src/utils/generateNavMenu.tsx +54 -0
- package/src/utils/generateSocialList.tsx +34 -0
- package/src/utils/getFontAwesomeIcon.tsx +25 -0
- package/src/utils/inputValidation.tsx +26 -0
- package/tailwind.config.js +32 -0
- package/tsconfig.json +25 -0
- package/vite.config.ts +33 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import "../../../dist/main.css";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import { describe, test, expect, beforeEach } from "vitest";
|
|
4
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
5
|
+
import { faCircleArrowRight } from "@fortawesome/free-solid-svg-icons";
|
|
6
|
+
import Input from "./Input";
|
|
7
|
+
import Text from "../Text/Text";
|
|
8
|
+
import FormButton from "../FormButton/FormButton";
|
|
9
|
+
|
|
10
|
+
describe("<Input /> with all props", () => {
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
render(
|
|
13
|
+
<Input
|
|
14
|
+
hasValidation={false}
|
|
15
|
+
// LABEL
|
|
16
|
+
label={
|
|
17
|
+
<Text
|
|
18
|
+
size="md"
|
|
19
|
+
color="primary"
|
|
20
|
+
fontFamily="serif"
|
|
21
|
+
text="Search for items"
|
|
22
|
+
tag="h2"
|
|
23
|
+
additionalClasses="mb-0 pb-2 pl-2"
|
|
24
|
+
/>
|
|
25
|
+
}
|
|
26
|
+
labelVisible={true}
|
|
27
|
+
labelPlacement="left"
|
|
28
|
+
// INPUT DETAILS
|
|
29
|
+
inputName="search"
|
|
30
|
+
inputType="text"
|
|
31
|
+
// PLACEHOLDER
|
|
32
|
+
hasPlaceholder={true}
|
|
33
|
+
placeholder="Search for items"
|
|
34
|
+
// ICONS
|
|
35
|
+
hasLeftIcon={false}
|
|
36
|
+
hasRightIcon={false}
|
|
37
|
+
iconColor="black"
|
|
38
|
+
// INPUT STYLES
|
|
39
|
+
inputTextSize="medium"
|
|
40
|
+
inputShape="cornered"
|
|
41
|
+
borderColor="green"
|
|
42
|
+
backgroundColor="none"
|
|
43
|
+
inputWidth="w-96"
|
|
44
|
+
// BUTTON
|
|
45
|
+
hasButton={true}
|
|
46
|
+
button={
|
|
47
|
+
<FormButton
|
|
48
|
+
text="Submit"
|
|
49
|
+
as="button"
|
|
50
|
+
hoverBackground="green"
|
|
51
|
+
color="green"
|
|
52
|
+
icon={<FontAwesomeIcon icon={faCircleArrowRight} />}
|
|
53
|
+
fontColor="white"
|
|
54
|
+
additionalClasses="items-center px-4"
|
|
55
|
+
borderColor="green"
|
|
56
|
+
hoverFontColor="black"
|
|
57
|
+
shape="cornered"
|
|
58
|
+
/>
|
|
59
|
+
}
|
|
60
|
+
/>
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("renders Input component", () => {
|
|
65
|
+
expect(screen.getByTestId("input-container")).toBeInTheDocument();
|
|
66
|
+
expect(screen.getByTestId("input-element")).toBeInTheDocument();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("renders correct Input label", () => {
|
|
70
|
+
expect(screen.getByTestId("input-label")).toBeInTheDocument();
|
|
71
|
+
expect(screen.getByTestId("input-label")).toHaveTextContent(
|
|
72
|
+
"Search for items"
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("renders correct button", () => {
|
|
77
|
+
expect(screen.getByTestId("submit-button")).toBeInTheDocument();
|
|
78
|
+
expect(screen.getByTestId("submit-button")).toHaveTextContent("Submit");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("contains correct placeholder text", () => {
|
|
82
|
+
const input = screen.getByTestId("input-element");
|
|
83
|
+
expect(input).toHaveAttribute("placeholder", "Search for items");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("renders correct border color class", () => {
|
|
87
|
+
const inputElement = screen.getByTestId("input-element");
|
|
88
|
+
expect(inputElement).toHaveClass("border-teal-500");
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
3
|
+
import { faCircleArrowRight } from "@fortawesome/free-solid-svg-icons";
|
|
4
|
+
import FormButton from "../FormButton/FormButton";
|
|
5
|
+
import { InputTypes } from ".";
|
|
6
|
+
import { validateInput } from "../../utils/inputValidation";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
getInputBorderClassNames,
|
|
10
|
+
getInputPaddingClassNames,
|
|
11
|
+
getInputBackgroundClassNames,
|
|
12
|
+
getInputTextClasses,
|
|
13
|
+
getInputShape,
|
|
14
|
+
getLabelPlacement,
|
|
15
|
+
getLabelVisibility,
|
|
16
|
+
getSuccessColorClasses,
|
|
17
|
+
getErrorColorClasses,
|
|
18
|
+
getIconClasses,
|
|
19
|
+
inputButtonWithClasses,
|
|
20
|
+
} from "./inputClassNames";
|
|
21
|
+
|
|
22
|
+
const Input: React.FC<InputTypes> = ({
|
|
23
|
+
// FUNCTIONALITY
|
|
24
|
+
hasValidation = false,
|
|
25
|
+
errorMessage,
|
|
26
|
+
regex,
|
|
27
|
+
setControlledState,
|
|
28
|
+
controlledState,
|
|
29
|
+
// LABEL
|
|
30
|
+
label,
|
|
31
|
+
labelVisible = true,
|
|
32
|
+
labelPlacement,
|
|
33
|
+
|
|
34
|
+
// INPUT DETAILS
|
|
35
|
+
inputName,
|
|
36
|
+
inputType,
|
|
37
|
+
|
|
38
|
+
// PLACEHOLDER
|
|
39
|
+
hasPlaceholder = true,
|
|
40
|
+
placeholder,
|
|
41
|
+
|
|
42
|
+
// ICONS
|
|
43
|
+
hasLeftIcon,
|
|
44
|
+
hasRightIcon,
|
|
45
|
+
leftIcon,
|
|
46
|
+
rightIcon,
|
|
47
|
+
iconColor,
|
|
48
|
+
iconBackgroundColor,
|
|
49
|
+
|
|
50
|
+
// INPUT STYLES
|
|
51
|
+
inputTextSize,
|
|
52
|
+
inputShape,
|
|
53
|
+
borderColor = "primary",
|
|
54
|
+
backgroundColor,
|
|
55
|
+
inputWidth,
|
|
56
|
+
errorBorder,
|
|
57
|
+
successBorder,
|
|
58
|
+
|
|
59
|
+
// BUTTON
|
|
60
|
+
hasButton,
|
|
61
|
+
button = (
|
|
62
|
+
<FormButton
|
|
63
|
+
text="Submit"
|
|
64
|
+
as="button"
|
|
65
|
+
hoverBackground="green"
|
|
66
|
+
color="red"
|
|
67
|
+
icon={<FontAwesomeIcon icon={faCircleArrowRight} />}
|
|
68
|
+
fontColor="white"
|
|
69
|
+
borderColor="green"
|
|
70
|
+
hoverFontColor="black"
|
|
71
|
+
shape="cornered"
|
|
72
|
+
additionalClasses="h-full"
|
|
73
|
+
/>
|
|
74
|
+
),
|
|
75
|
+
}) => {
|
|
76
|
+
const [isValid, setIsValid] = useState<string>("");
|
|
77
|
+
const [termInternal, setTermInternal] = useState<string>("");
|
|
78
|
+
const [inputBorderClasses, setInputBorderClasses] = useState<string>(
|
|
79
|
+
getInputBorderClassNames(borderColor)
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
let iconClasses = getIconClasses(
|
|
83
|
+
iconColor,
|
|
84
|
+
iconBackgroundColor,
|
|
85
|
+
inputShape
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
let errorColor = getErrorColorClasses(errorBorder);
|
|
89
|
+
let successColor = getSuccessColorClasses(successBorder);
|
|
90
|
+
let inputPaddingClasses = getInputPaddingClassNames(
|
|
91
|
+
hasButton,
|
|
92
|
+
hasLeftIcon,
|
|
93
|
+
hasRightIcon
|
|
94
|
+
);
|
|
95
|
+
let inputBackgroundClasses = getInputBackgroundClassNames(backgroundColor);
|
|
96
|
+
let inputShapeClasses = getInputShape(inputShape);
|
|
97
|
+
let inputWithButtonClasses = inputButtonWithClasses(inputShape);
|
|
98
|
+
let labelVisibility = getLabelVisibility(labelVisible);
|
|
99
|
+
let labelPlacementClasses = getLabelPlacement(labelPlacement);
|
|
100
|
+
let inputTextClasses = getInputTextClasses(inputTextSize);
|
|
101
|
+
let inputBorderColor = getInputBorderClassNames(borderColor);
|
|
102
|
+
const inputValue = termInternal || controlledState || "";
|
|
103
|
+
const setTerm = setControlledState || setTermInternal;
|
|
104
|
+
|
|
105
|
+
const handleBorderStyles = () => {
|
|
106
|
+
if (isValid !== "Success" && isValid !== "") {
|
|
107
|
+
setInputBorderClasses(errorColor);
|
|
108
|
+
} else if (isValid === "Success") {
|
|
109
|
+
setInputBorderClasses(successColor);
|
|
110
|
+
} else if (isValid === "") {
|
|
111
|
+
setInputBorderClasses(getInputBorderClassNames(borderColor));
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
116
|
+
setTerm(e.target.value);
|
|
117
|
+
|
|
118
|
+
if (hasValidation) {
|
|
119
|
+
let validation =
|
|
120
|
+
validateInput &&
|
|
121
|
+
regex &&
|
|
122
|
+
errorMessage &&
|
|
123
|
+
validateInput(inputValue, regex, errorMessage);
|
|
124
|
+
setIsValid(validation || "");
|
|
125
|
+
handleBorderStyles();
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<div
|
|
131
|
+
className={`${labelPlacementClasses} w-full`}
|
|
132
|
+
data-testid="input-container"
|
|
133
|
+
>
|
|
134
|
+
<label
|
|
135
|
+
htmlFor={`pb-1 pl-1 ${inputName}`}
|
|
136
|
+
className={`${labelVisibility}`}
|
|
137
|
+
data-testid="input-label"
|
|
138
|
+
>
|
|
139
|
+
{label}
|
|
140
|
+
</label>
|
|
141
|
+
{hasButton ? (
|
|
142
|
+
<div className={`relative ${inputWidth} flex`}>
|
|
143
|
+
<div className="flex-1">
|
|
144
|
+
{hasLeftIcon && (
|
|
145
|
+
<div
|
|
146
|
+
className={`absolute bottom-1 flex items-center justify-center size-10 pointer-events-none ${iconClasses} `}
|
|
147
|
+
>
|
|
148
|
+
{leftIcon}
|
|
149
|
+
</div>
|
|
150
|
+
)}
|
|
151
|
+
<input
|
|
152
|
+
type={inputType}
|
|
153
|
+
placeholder={
|
|
154
|
+
hasPlaceholder ? placeholder : undefined
|
|
155
|
+
}
|
|
156
|
+
name={inputName}
|
|
157
|
+
id={inputName}
|
|
158
|
+
onChange={handleChange}
|
|
159
|
+
value={inputValue}
|
|
160
|
+
data-testid="input-element"
|
|
161
|
+
className={`block w-full border-2 p-2 ${inputTextClasses} ${inputWithButtonClasses} ${inputBackgroundClasses} ${inputPaddingClasses} ${
|
|
162
|
+
!hasValidation
|
|
163
|
+
? inputBorderColor
|
|
164
|
+
: inputBorderClasses
|
|
165
|
+
}`}
|
|
166
|
+
/>
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
<div>
|
|
170
|
+
{hasButton && (
|
|
171
|
+
<div
|
|
172
|
+
className={`${inputShape} flex items-center justify-center h-full`}
|
|
173
|
+
data-testid="submit-button"
|
|
174
|
+
>
|
|
175
|
+
<div className="h-full bg-red-500">
|
|
176
|
+
{button}
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
)}
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
) : (
|
|
183
|
+
<div className={`relative ${inputWidth} flex`}>
|
|
184
|
+
{hasLeftIcon && (
|
|
185
|
+
<div
|
|
186
|
+
className={`absolute top-[1px] flex items-center justify-center size-10 pointer-events-none ${iconClasses} `}
|
|
187
|
+
>
|
|
188
|
+
{leftIcon}
|
|
189
|
+
</div>
|
|
190
|
+
)}
|
|
191
|
+
<input
|
|
192
|
+
type={inputType}
|
|
193
|
+
placeholder={hasPlaceholder ? placeholder : undefined}
|
|
194
|
+
name={inputName}
|
|
195
|
+
id={inputName}
|
|
196
|
+
onChange={handleChange}
|
|
197
|
+
value={inputValue}
|
|
198
|
+
data-testid="input-element"
|
|
199
|
+
className={`block w-full border-2 ${inputTextClasses} ${inputShapeClasses} ${inputBackgroundClasses} ${inputPaddingClasses} ${
|
|
200
|
+
!hasValidation
|
|
201
|
+
? inputBorderColor
|
|
202
|
+
: inputBorderClasses
|
|
203
|
+
}`}
|
|
204
|
+
/>
|
|
205
|
+
{hasRightIcon && (
|
|
206
|
+
<div
|
|
207
|
+
className={`absolute end-1 flex items-center justify-center size-10 pointer-events-none ${iconClasses}`}
|
|
208
|
+
>
|
|
209
|
+
{rightIcon}
|
|
210
|
+
</div>
|
|
211
|
+
)}
|
|
212
|
+
{hasButton && (
|
|
213
|
+
<div
|
|
214
|
+
className={`${inputShape} flex items-center inset-y-0 end-1.5`}
|
|
215
|
+
data-testid="submit-button"
|
|
216
|
+
>
|
|
217
|
+
{button}
|
|
218
|
+
</div>
|
|
219
|
+
)}
|
|
220
|
+
</div>
|
|
221
|
+
)}
|
|
222
|
+
</div>
|
|
223
|
+
);
|
|
224
|
+
};
|
|
225
|
+
Input.displayName = "Memo(Input)";
|
|
226
|
+
export default Input;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
export interface InputTypes {
|
|
4
|
+
// FUNCTIONALITY
|
|
5
|
+
onChange?: (
|
|
6
|
+
e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>
|
|
7
|
+
) => void;
|
|
8
|
+
value?: string;
|
|
9
|
+
hasValidation?: boolean;
|
|
10
|
+
validateInput?: (inputValue: string | number, inputType: string) => string;
|
|
11
|
+
hasErrorMessage?: boolean;
|
|
12
|
+
errorMessage?: string;
|
|
13
|
+
regex?: RegExp;
|
|
14
|
+
setControlledState?: (value: string) => void;
|
|
15
|
+
controlledState?: string;
|
|
16
|
+
// LABEL
|
|
17
|
+
labelVisible: boolean;
|
|
18
|
+
label: React.ReactNode; // text that is displayed as the label, required bc it's either shown or only shown to screen readers
|
|
19
|
+
labelPlacement?: "top" | "left";
|
|
20
|
+
// INPUT DETAILS
|
|
21
|
+
inputType: string;
|
|
22
|
+
inputName: string; // required bc connects the label to the input
|
|
23
|
+
// PLACEHOLDER
|
|
24
|
+
hasPlaceholder: boolean;
|
|
25
|
+
placeholder: string;
|
|
26
|
+
// ICONS
|
|
27
|
+
hasLeftIcon?: boolean;
|
|
28
|
+
hasRightIcon?: boolean;
|
|
29
|
+
leftIcon?: React.ReactNode;
|
|
30
|
+
rightIcon?: React.ReactNode;
|
|
31
|
+
iconColor?: "green" | "blue" | "black" | string;
|
|
32
|
+
iconBackgroundColor?:
|
|
33
|
+
| "green"
|
|
34
|
+
| "white"
|
|
35
|
+
| "blue"
|
|
36
|
+
| "green"
|
|
37
|
+
| "none"
|
|
38
|
+
| string;
|
|
39
|
+
// INPUT STYLE
|
|
40
|
+
inputTextSize?: "small" | "medium" | "large" | string;
|
|
41
|
+
inputWidth?: string;
|
|
42
|
+
inputShape?: "cornered" | "semiRounded" | "rounded" | string;
|
|
43
|
+
borderColor?: "green" | "blue" | "grey" | "black" | "none" | string;
|
|
44
|
+
backgroundColor?: "white" | "blue" | "green" | "none" | string;
|
|
45
|
+
additionalClasses?: string | undefined;
|
|
46
|
+
errorBorder?: "red" | "orange" | string;
|
|
47
|
+
successBorder?: "green" | "blue" | "grey" | "black" | string;
|
|
48
|
+
// BUTTON
|
|
49
|
+
hasButton?: boolean;
|
|
50
|
+
button?: React.ReactNode;
|
|
51
|
+
onButtonClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
|
52
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { InputTypes } from ".";
|
|
2
|
+
|
|
3
|
+
export const arePropsEqual = (prevProps: InputTypes, nextProps: InputTypes) => {
|
|
4
|
+
return (
|
|
5
|
+
prevProps.hasValidation === nextProps.hasValidation &&
|
|
6
|
+
prevProps.errorMessage === nextProps.errorMessage &&
|
|
7
|
+
prevProps.regex === nextProps.regex &&
|
|
8
|
+
prevProps.label === nextProps.label &&
|
|
9
|
+
prevProps.labelVisible === nextProps.labelVisible &&
|
|
10
|
+
prevProps.labelPlacement === nextProps.labelPlacement &&
|
|
11
|
+
prevProps.inputName === nextProps.inputName &&
|
|
12
|
+
prevProps.inputType === nextProps.inputType &&
|
|
13
|
+
prevProps.hasPlaceholder === nextProps.hasPlaceholder &&
|
|
14
|
+
prevProps.placeholder === nextProps.placeholder &&
|
|
15
|
+
prevProps.hasLeftIcon === nextProps.hasLeftIcon &&
|
|
16
|
+
prevProps.hasRightIcon === nextProps.hasRightIcon &&
|
|
17
|
+
prevProps.leftIcon === nextProps.leftIcon &&
|
|
18
|
+
prevProps.rightIcon === nextProps.rightIcon &&
|
|
19
|
+
prevProps.iconColor === nextProps.iconColor &&
|
|
20
|
+
prevProps.iconBackgroundColor === nextProps.iconBackgroundColor &&
|
|
21
|
+
prevProps.inputTextSize === nextProps.inputTextSize &&
|
|
22
|
+
prevProps.inputShape === nextProps.inputShape &&
|
|
23
|
+
prevProps.borderColor === nextProps.borderColor &&
|
|
24
|
+
prevProps.backgroundColor === nextProps.backgroundColor &&
|
|
25
|
+
prevProps.inputWidth === nextProps.inputWidth &&
|
|
26
|
+
prevProps.errorBorder === nextProps.errorBorder &&
|
|
27
|
+
prevProps.successBorder === nextProps.successBorder &&
|
|
28
|
+
prevProps.additionalClasses === nextProps.additionalClasses &&
|
|
29
|
+
prevProps.hasButton === nextProps.hasButton &&
|
|
30
|
+
prevProps.button === nextProps.button
|
|
31
|
+
);
|
|
32
|
+
};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import classNames from "classNames";
|
|
2
|
+
|
|
3
|
+
// edits the input container border color & focus outline color
|
|
4
|
+
export const getInputBorderClassNames = (borderColor: string | undefined) =>
|
|
5
|
+
classNames({
|
|
6
|
+
"border-teal-500 focus-within:outline-teal-500 focus-within:outline focus-within:outline-2 focus-within:outline-offset-1":
|
|
7
|
+
borderColor === "green",
|
|
8
|
+
"border-blue-500 focus-within:outline-blue-500 focus-within:outline focus-within:outline-2 focus-within:outline-offset-1":
|
|
9
|
+
borderColor === "blue",
|
|
10
|
+
"border-slate-400 focus-within:outline-slate-400 focus-within:outline focus-within:outline-2 focus-within:outline-offset-1":
|
|
11
|
+
borderColor === "grey",
|
|
12
|
+
"border-black focus-within:outline-black focus-within:outline focus-within:outline-2 focus-within:outline-offset-1":
|
|
13
|
+
borderColor === "black",
|
|
14
|
+
"border-transparent focus-within:outline-transparent focus-within:outline focus-within:outline-2 focus-within:outline-offset-1":
|
|
15
|
+
borderColor === "none",
|
|
16
|
+
[`border-${borderColor} focus-within:outline-${borderColor} focus-within:outline focus-within:outline-2 focus-within:outline-offset-1`]:
|
|
17
|
+
borderColor !== undefined,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export const getSuccessColorClasses = (successBorder: string | undefined) =>
|
|
21
|
+
classNames({
|
|
22
|
+
"focus-within:outline-green-500 border-green-500 focus-within:outline focus-within:outline-2 focus-within:outline-offset-1":
|
|
23
|
+
successBorder === "green",
|
|
24
|
+
"focus-within:outline-blue-500 border-blue-500 focus-within:outline focus-within:outline-2 focus-within:outline-offset-1":
|
|
25
|
+
successBorder === "blue",
|
|
26
|
+
"focus-within:outline-grey-500 border-grey-500 focus-within:outline focus-within:outline-2 focus-within:outline-offset-1":
|
|
27
|
+
successBorder === "grey",
|
|
28
|
+
"focus-within:outline-black border-black focus-within:outline focus-within:outline-2 focus-within:outline-offset-1":
|
|
29
|
+
successBorder === "black",
|
|
30
|
+
[`focus-within:outline-${successBorder} border-${successBorder} focus-within:outline focus-within:outline-2 focus-within:outline-offset-1`]:
|
|
31
|
+
successBorder !== undefined,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export const getErrorColorClasses = (errorBorder: string | undefined) =>
|
|
35
|
+
classNames({
|
|
36
|
+
"focus-within:outline-red-500 border-red-500 focus-within:outline focus-within:outline-2 focus-within:outline-offset-1":
|
|
37
|
+
errorBorder === "red",
|
|
38
|
+
"focus-within:outline-orange-500 border-orange-500 focus-within:outline focus-within:outline-2 focus-within:outline-offset-1":
|
|
39
|
+
errorBorder === "orange",
|
|
40
|
+
"focus-within:outline-black border-black focus-within:outline focus-within:outline-2 focus-within:outline-offset-1":
|
|
41
|
+
errorBorder === "black",
|
|
42
|
+
[`focus-within:outline-${errorBorder} border-${errorBorder} focus-within:outline focus-within:outline-2 focus-within:outline-offset-1`]:
|
|
43
|
+
errorBorder !== undefined,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export const getInputPaddingClassNames = (
|
|
47
|
+
hasButton: boolean | undefined,
|
|
48
|
+
hasLeftIcon: boolean | undefined,
|
|
49
|
+
hasRightIcon: boolean | undefined
|
|
50
|
+
) =>
|
|
51
|
+
classNames({
|
|
52
|
+
// NO ICONS OR BUTTON
|
|
53
|
+
"py-2 px-3":
|
|
54
|
+
hasButton === false &&
|
|
55
|
+
hasLeftIcon === false &&
|
|
56
|
+
hasRightIcon === false,
|
|
57
|
+
|
|
58
|
+
// LEFT ICON AND BUTTON
|
|
59
|
+
"py-3 pl-14":
|
|
60
|
+
hasButton === true &&
|
|
61
|
+
hasLeftIcon === true &&
|
|
62
|
+
hasRightIcon === false,
|
|
63
|
+
|
|
64
|
+
// BUTTON ONLY
|
|
65
|
+
"py-3 px-3":
|
|
66
|
+
hasButton === true &&
|
|
67
|
+
hasLeftIcon === false &&
|
|
68
|
+
hasRightIcon === false,
|
|
69
|
+
|
|
70
|
+
// LEFT ICON ONLY
|
|
71
|
+
"pl-12 py-2":
|
|
72
|
+
hasLeftIcon === true &&
|
|
73
|
+
hasRightIcon === false &&
|
|
74
|
+
hasButton === false,
|
|
75
|
+
|
|
76
|
+
// RIGHT ICON ONLY
|
|
77
|
+
"pr-10 py-2 pl-3":
|
|
78
|
+
hasRightIcon === true &&
|
|
79
|
+
hasLeftIcon === false &&
|
|
80
|
+
hasButton === false,
|
|
81
|
+
|
|
82
|
+
// DUAL ICONS ONLY
|
|
83
|
+
"py-2 pl-12":
|
|
84
|
+
hasRightIcon === true &&
|
|
85
|
+
hasLeftIcon === true &&
|
|
86
|
+
hasButton === false,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// edits the background color of the input element
|
|
90
|
+
export const getInputBackgroundClassNames = (
|
|
91
|
+
backgroundColor: string | undefined
|
|
92
|
+
) =>
|
|
93
|
+
classNames({
|
|
94
|
+
"bg-white": backgroundColor === "white",
|
|
95
|
+
"bg-blue-100": backgroundColor === "blue",
|
|
96
|
+
"bg-slate-100": backgroundColor === "grey",
|
|
97
|
+
"bg-transparent": backgroundColor === "none",
|
|
98
|
+
[`bg-${backgroundColor}`]: backgroundColor !== undefined,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// edits text styles of the input element
|
|
102
|
+
export const getInputTextClasses = (inputTextSize: string | undefined) => {
|
|
103
|
+
return classNames({
|
|
104
|
+
"text-sm": inputTextSize === "small",
|
|
105
|
+
"text-md": inputTextSize === "medium",
|
|
106
|
+
"text-lg": inputTextSize === "large",
|
|
107
|
+
[`text-${inputTextSize}`]: inputTextSize !== undefined,
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// manages the border radius of the input
|
|
112
|
+
export const getInputShape = (inputShape: string | undefined) =>
|
|
113
|
+
classNames({
|
|
114
|
+
"rounded-none": inputShape === "cornered",
|
|
115
|
+
"rounded-md": inputShape === "semiRounded",
|
|
116
|
+
"rounded-full": inputShape === "rounded",
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// manages the border radius of the input when the input has a button with it
|
|
120
|
+
export const inputButtonWithClasses = (inputShape: string | undefined) =>
|
|
121
|
+
classNames({
|
|
122
|
+
"rounded-tl-none rounded-bl-none": true,
|
|
123
|
+
"rounded-tr-none rounded-br-none": inputShape === "cornered",
|
|
124
|
+
"rounded-tr-md rounded-br-md": inputShape === "semiRounded",
|
|
125
|
+
"rounded-tr-full rounded-br-full": inputShape === "rounded",
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// manages the placement of the label
|
|
129
|
+
export const getLabelPlacement = (labelPlacement: string | undefined) =>
|
|
130
|
+
classNames({
|
|
131
|
+
"flex items-center pr-3": labelPlacement === "left",
|
|
132
|
+
"": labelPlacement === "top",
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// toggles whether label is visible or not
|
|
136
|
+
export const getLabelVisibility = (labelVisible: boolean | undefined) =>
|
|
137
|
+
classNames({
|
|
138
|
+
"sr-only": labelVisible === false,
|
|
139
|
+
"": labelVisible === true,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
export const getIconClasses = (
|
|
143
|
+
iconColor: string | undefined,
|
|
144
|
+
iconBackgroundColor: string | undefined,
|
|
145
|
+
inputShape: string | undefined
|
|
146
|
+
) => {
|
|
147
|
+
return classNames(
|
|
148
|
+
{
|
|
149
|
+
"text-blue-500": iconColor === "blue",
|
|
150
|
+
"text-teal-500": iconColor === "green",
|
|
151
|
+
"text-black": iconColor === "black",
|
|
152
|
+
"text-white": iconColor === "white",
|
|
153
|
+
[`text-${iconColor}`]: iconColor !== undefined,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"bg-blue-200": iconBackgroundColor === "blue",
|
|
157
|
+
"bg-slate-200": iconBackgroundColor === "grey",
|
|
158
|
+
"bg-teal-100": iconBackgroundColor === "green",
|
|
159
|
+
"bg-black": iconBackgroundColor === "black",
|
|
160
|
+
"bg-transparent": iconBackgroundColor === "none",
|
|
161
|
+
[`bg-${iconBackgroundColor}`]: iconBackgroundColor !== undefined,
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"rounded-none": inputShape === "cornered",
|
|
165
|
+
"rounded-md": inputShape === "semiRounded",
|
|
166
|
+
"rounded-full": inputShape === "rounded",
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
|
|
2
|
+
import { MobileMenuTypes } from "./MobileMenu.types";
|
|
3
|
+
import { useHeaderContext } from "../Header/headerContext";
|
|
4
|
+
|
|
5
|
+
const MobileMenu: React.FC<MobileMenuTypes> = ({
|
|
6
|
+
badge,
|
|
7
|
+
nav,
|
|
8
|
+
input,
|
|
9
|
+
icons,
|
|
10
|
+
mobileMenuClasses,
|
|
11
|
+
}) => {
|
|
12
|
+
const {
|
|
13
|
+
hasMobileIcons,
|
|
14
|
+
hasMobileNavItems,
|
|
15
|
+
hasMobileBadge,
|
|
16
|
+
hasMobileSearchBar,
|
|
17
|
+
} = useHeaderContext();
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<nav
|
|
21
|
+
data-testid="secondary-nav"
|
|
22
|
+
aria-label="Secondary navigation"
|
|
23
|
+
className={`flex flex-col justify-start z-[1000] top-0 w-full h-full pt-16 pb-12 px-4 overflow-scroll ${mobileMenuClasses}`}
|
|
24
|
+
>
|
|
25
|
+
{hasMobileNavItems && <div className="mb-12">{nav}</div>}
|
|
26
|
+
{hasMobileBadge && (
|
|
27
|
+
<div className="flex w-1/2 mb-12 mx-auto">{badge}</div>
|
|
28
|
+
)}
|
|
29
|
+
{hasMobileIcons && icons && (
|
|
30
|
+
<div className="flex justify-around w-full mb-12">{icons}</div>
|
|
31
|
+
)}
|
|
32
|
+
{hasMobileSearchBar && (
|
|
33
|
+
<div className="flex w-full [&:has(:focus-visible)]:ring-2">
|
|
34
|
+
{input}
|
|
35
|
+
</div>
|
|
36
|
+
)}
|
|
37
|
+
</nav>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default MobileMenu;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { DUMMYICONCOMPASSDATA, DUMMYICONTOGADATA } from "../Header/DUMMYICONDATA.json";
|
|
2
|
+
import { TagName } from "../Text";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export interface MobileMenuTypes {
|
|
6
|
+
onClick?: (
|
|
7
|
+
e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>
|
|
8
|
+
) => void;
|
|
9
|
+
handleNav?: () => void;
|
|
10
|
+
hasSearchBar?: boolean;
|
|
11
|
+
hasNavItems?: boolean;
|
|
12
|
+
hasBadge?: boolean;
|
|
13
|
+
hasIcons?: boolean;
|
|
14
|
+
|
|
15
|
+
hasMobileIcons?: boolean;
|
|
16
|
+
hasMobileNavItems?: boolean;
|
|
17
|
+
hasMobileBadge?: boolean;
|
|
18
|
+
hasMobileSearchBar?: boolean;
|
|
19
|
+
mobileMenuClasses?: string;
|
|
20
|
+
|
|
21
|
+
hasGlass?: boolean;
|
|
22
|
+
backgroundColor?: string;
|
|
23
|
+
|
|
24
|
+
nav?: React.ReactNode;
|
|
25
|
+
badge?: React.ReactNode;
|
|
26
|
+
input?: React.ReactNode;
|
|
27
|
+
icons?: React.ReactNode;
|
|
28
|
+
|
|
29
|
+
mobileCloseIcon?: JSX.Element | undefined | null;
|
|
30
|
+
}
|