@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.
Files changed (138) hide show
  1. package/Dockerfile +9 -0
  2. package/README.md +69 -0
  3. package/assets/Logo.png +0 -0
  4. package/assets/compass-card-image-2.png +0 -0
  5. package/assets/compass-card-image-3.png +0 -0
  6. package/assets/compass-card-image-4.png +0 -0
  7. package/assets/compass-card-image.png +0 -0
  8. package/assets/compass-logo.png +0 -0
  9. package/assets/compass-tech-hero-bg.png +0 -0
  10. package/assets/contact-image.png +0 -0
  11. package/assets/green-laptop.png +0 -0
  12. package/assets/heroImage.png +0 -0
  13. package/assets/placeholder-no-image-available.png +0 -0
  14. package/assets/team.png +0 -0
  15. package/declarations.d.ts +4 -0
  16. package/docker-compose.yml +22 -0
  17. package/global.css +4 -0
  18. package/index.js +4 -0
  19. package/nodemon.json +5 -0
  20. package/package.json +70 -0
  21. package/postcss.config.js +6 -0
  22. package/src/components/Badge/Badge.stories.tsx +284 -0
  23. package/src/components/Badge/Badge.test.tsx +185 -0
  24. package/src/components/Badge/Badge.tsx +137 -0
  25. package/src/components/Badge/Badge.types.tsx +28 -0
  26. package/src/components/Badge/badgeClassNames.tsx +152 -0
  27. package/src/components/Badge/index.ts +2 -0
  28. package/src/components/Card/Card.stories.tsx +91 -0
  29. package/src/components/Card/Card.test.tsx +53 -0
  30. package/src/components/Card/Card.tsx +30 -0
  31. package/src/components/Card/Card.types.ts +11 -0
  32. package/src/components/Card/DUMMYPRODUCTDATA.json +670 -0
  33. package/src/components/Card/cardClassNames.ts +49 -0
  34. package/src/components/Card/index.ts +3 -0
  35. package/src/components/Card/templates/CompassCardTemplate.tsx +58 -0
  36. package/src/components/Card/templates/HorizontalCardTemplate.tsx +184 -0
  37. package/src/components/Card/templates/VerticalCardTemplate.tsx +154 -0
  38. package/src/components/Footer/ContactInfoItem.tsx +20 -0
  39. package/src/components/Footer/DUMMYFOOTERDATA.json +132 -0
  40. package/src/components/Footer/Footer.stories.tsx +292 -0
  41. package/src/components/Footer/Footer.test.tsx +90 -0
  42. package/src/components/Footer/Footer.tsx +159 -0
  43. package/src/components/Footer/Footer.types.tsx +61 -0
  44. package/src/components/Footer/footerClassNames.tsx +57 -0
  45. package/src/components/FormButton/FormButton.stories.tsx +199 -0
  46. package/src/components/FormButton/FormButton.test.tsx +73 -0
  47. package/src/components/FormButton/FormButton.tsx +116 -0
  48. package/src/components/FormButton/FormButton.types.ts +32 -0
  49. package/src/components/FormButton/formButtonClassNames.tsx +153 -0
  50. package/src/components/FormButton/index.ts +2 -0
  51. package/src/components/GenericList/DUMMYLISTDATA.json +560 -0
  52. package/src/components/GenericList/GenericList.stories.tsx +104 -0
  53. package/src/components/GenericList/GenericList.test.tsx +29 -0
  54. package/src/components/GenericList/GenericList.tsx +146 -0
  55. package/src/components/GenericList/genericListClassNames.tsx +8 -0
  56. package/src/components/GenericList/templates/DummyDataList.tsx +23 -0
  57. package/src/components/GenericList/templates/DynamicIconList.tsx +74 -0
  58. package/src/components/HamburgerButton/HamburgerButton.tsx +68 -0
  59. package/src/components/HamburgerButton/HamburgerButton.types.tsx +6 -0
  60. package/src/components/HamburgerButton/index.ts +2 -0
  61. package/src/components/Header/DUMMYICONDATA.json +136 -0
  62. package/src/components/Header/Header.stories.tsx +521 -0
  63. package/src/components/Header/Header.test.tsx +323 -0
  64. package/src/components/Header/Header.tsx +289 -0
  65. package/src/components/Header/Header.types.ts +52 -0
  66. package/src/components/Header/headerClassNames.tsx +50 -0
  67. package/src/components/Header/headerContext.tsx +125 -0
  68. package/src/components/Header/index.ts +2 -0
  69. package/src/components/Hero/Hero.stories.tsx +69 -0
  70. package/src/components/Hero/Hero.test.tsx +109 -0
  71. package/src/components/Hero/Hero.tsx +58 -0
  72. package/src/components/Hero/Hero.types.ts +9 -0
  73. package/src/components/Hero/index.ts +2 -0
  74. package/src/components/Icon/Icon.stories.tsx +227 -0
  75. package/src/components/Icon/Icon.test.tsx +53 -0
  76. package/src/components/Icon/Icon.tsx +208 -0
  77. package/src/components/Icon/Icon.types.ts +24 -0
  78. package/src/components/Icon/iconClassNames.ts +79 -0
  79. package/src/components/Icon/index.ts +2 -0
  80. package/src/components/Image/Image.stories.tsx +79 -0
  81. package/src/components/Image/Image.test.tsx +87 -0
  82. package/src/components/Image/Image.tsx +49 -0
  83. package/src/components/Image/Image.types.ts +11 -0
  84. package/src/components/Image/index.ts +2 -0
  85. package/src/components/Input/Input.stories.tsx +651 -0
  86. package/src/components/Input/Input.test.tsx +90 -0
  87. package/src/components/Input/Input.tsx +226 -0
  88. package/src/components/Input/Input.types.ts +52 -0
  89. package/src/components/Input/InputMemoTypes.tsx +32 -0
  90. package/src/components/Input/index.ts +2 -0
  91. package/src/components/Input/inputClassNames.tsx +169 -0
  92. package/src/components/MobileMenu/MobileMenu.tsx +41 -0
  93. package/src/components/MobileMenu/MobileMenu.types.tsx +30 -0
  94. package/src/components/MobileMenu/index.ts +2 -0
  95. package/src/components/Nav/DUMMYNAVDATA.json +234 -0
  96. package/src/components/Nav/Nav.stories.tsx +181 -0
  97. package/src/components/Nav/Nav.test.tsx +89 -0
  98. package/src/components/Nav/Nav.tsx +242 -0
  99. package/src/components/Nav/Nav.types.tsx +35 -0
  100. package/src/components/Nav/index.ts +2 -0
  101. package/src/components/Nav/navClassNames.tsx +192 -0
  102. package/src/components/Page/TableDataDummy.tsx +216 -0
  103. package/src/components/Page/ViewPageTemplate.stories.tsx +546 -0
  104. package/src/components/Page/ViewPageTemplate.test.tsx +361 -0
  105. package/src/components/Page/ViewPageTemplate.tsx +10 -0
  106. package/src/components/Page/ViewPageTemplate.types.ts +6 -0
  107. package/src/components/Page/index.ts +2 -0
  108. package/src/components/PageSection/PageSection.stories.tsx +114 -0
  109. package/src/components/PageSection/PageSection.tsx +12 -0
  110. package/src/components/PageSection/PageSection.types.ts +6 -0
  111. package/src/components/PageSection/PageSections.test.tsx +88 -0
  112. package/src/components/PageSection/index.ts +2 -0
  113. package/src/components/Text/Text.stories.tsx +60 -0
  114. package/src/components/Text/Text.test.tsx +52 -0
  115. package/src/components/Text/Text.tsx +80 -0
  116. package/src/components/Text/Text.types.ts +12 -0
  117. package/src/components/Text/index.ts +2 -0
  118. package/src/components/Toaster/Toaster.stories.tsx +122 -0
  119. package/src/components/Toaster/Toaster.test.tsx +61 -0
  120. package/src/components/Toaster/Toaster.tsx +80 -0
  121. package/src/components/Toaster/Toaster.types.ts +12 -0
  122. package/src/components/Toaster/index.ts +2 -0
  123. package/src/hoc/index.ts +2 -0
  124. package/src/hoc/styling/withStoryBook.tsx +19 -0
  125. package/src/main.css +3 -0
  126. package/src/setupTests.ts +1 -0
  127. package/src/userHoc/index.ts +1 -0
  128. package/src/userHoc/withMemo.tsx +20 -0
  129. package/src/utils/assertTagName.tsx +7 -0
  130. package/src/utils/generateAccordionItem.tsx +102 -0
  131. package/src/utils/generateFooterContacts.tsx +75 -0
  132. package/src/utils/generateNavMenu.tsx +54 -0
  133. package/src/utils/generateSocialList.tsx +34 -0
  134. package/src/utils/getFontAwesomeIcon.tsx +25 -0
  135. package/src/utils/inputValidation.tsx +26 -0
  136. package/tailwind.config.js +32 -0
  137. package/tsconfig.json +25 -0
  138. package/vite.config.ts +33 -0
@@ -0,0 +1,323 @@
1
+ import "../../../dist/main.css";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { describe, test, expect, beforeEach } from "vitest";
4
+ import Header from "./Header";
5
+ import Image from "../Image/Image";
6
+ import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
7
+ import DUMMYICONDATA from "./DUMMYICONDATA.json";
8
+ import { DUMMYNAVDATA } from "../Nav/DUMMYNAVDATA.json";
9
+ import DynamicIconList from "../GenericList/templates/DynamicIconList";
10
+ import GenericList from "../GenericList/GenericList";
11
+ import Badge from "../Badge";
12
+ import Text from "../Text/Text";
13
+ import Nav from "../Nav";
14
+
15
+ describe("<Header /> with all props (badge, icons, input, logo)", () => {
16
+ beforeEach(() => {
17
+ render(
18
+ <Header
19
+ nav={
20
+ <Nav
21
+ navData={DUMMYNAVDATA}
22
+ navBackgroundColor={"#FFFFF"}
23
+ parentHoverBackground={"blue"}
24
+ parentHoverFontColor={"white"}
25
+ parentHoverUnderline={true}
26
+ parentHoverBorderColor={"none"}
27
+ parentShape={"cornered"}
28
+ parentBackground={"none"}
29
+ parentBorderColor={"none"}
30
+ submenuBackgroundColor={"blue"}
31
+ submenuHoverBackground={"white"}
32
+ submenuHoverBorderStyle={"bottom"}
33
+ submenuHoverBorderColor={"black"}
34
+ mobileBreakpoint={"extraLarge"}
35
+ accordionParentStyle={
36
+ "cornered p-2 w-full border-b-2 border-b-blue-700 text-black"
37
+ }
38
+ accordionExpandedStyle={"pl-2 py-3"}
39
+ />
40
+ }
41
+ logo={
42
+ <Image
43
+ src="../../../assets/Logo.png"
44
+ alt="Generic Company Logo."
45
+ background={false}
46
+ additionalClasses=" w-40 "
47
+ />
48
+ }
49
+ badge={
50
+ <Badge
51
+ type="href"
52
+ to="#"
53
+ color="green"
54
+ hoverColor="green"
55
+ borderColor="none"
56
+ tagStyle={false}
57
+ mobileIcon={getFontAwesomeIcon("phone")}
58
+ mobileIconLabel="Contact Us"
59
+ onClick={() => alert("Redirect to Contact Us page")}
60
+ image={
61
+ <Image
62
+ src="../../../assets/contact-image.png"
63
+ alt=""
64
+ background={false}
65
+ additionalClasses="flex justify-center w-8 h-8 max-md:hidden"
66
+ />
67
+ }
68
+ text={
69
+ <>
70
+ <Text
71
+ size="sm"
72
+ color="primary"
73
+ fontFamily="serif"
74
+ text="Contact Us"
75
+ tag="h2"
76
+ additionalClasses="pl-2 pb-0 font-bold"
77
+ />
78
+ <Text
79
+ size="xs"
80
+ color="primary"
81
+ fontFamily="serif"
82
+ text="1-800-800-8000"
83
+ tag="p"
84
+ additionalClasses="pl-2 pt-0"
85
+ />
86
+ </>
87
+ }
88
+ />
89
+ }
90
+ backgroundColor="gray"
91
+ mobileOpenIcon={getFontAwesomeIcon("hamburger")}
92
+ mobileCloseIcon={getFontAwesomeIcon("X")}
93
+ mobileLeft={true}
94
+ mobileRight={false}
95
+ logoHoverColor="blue"
96
+ logoBorderRadius={true}
97
+ hasIcons={true}
98
+ icons={
99
+ <GenericList
100
+ data={DUMMYICONDATA.DUMMYICONCOMPASSDATA}
101
+ renderItem={(item) => <DynamicIconList item={item} />}
102
+ itemHeight={20}
103
+ containerHeight={72}
104
+ listType="unordered"
105
+ containerClasses="bg-gray-100 w-36 border-2 border-teal-500"
106
+ listDirection="vertical"
107
+ hasVirtualization={false}
108
+ />
109
+ }
110
+ hasSearchBar={true}
111
+ hasNavItems={true}
112
+ hasBadge={true}
113
+ />
114
+ );
115
+ });
116
+
117
+ test("renders Header component", () => {
118
+ expect(screen.getByTestId("header")).toBeInTheDocument();
119
+ });
120
+
121
+ test("renders correct background color class", () => {
122
+ const header = screen.getByTestId("header");
123
+ expect(header).toHaveClass("bg-slate-200");
124
+ });
125
+
126
+ test("contains correct logo from Image component", () => {
127
+ const headerLogo = screen.getByTestId("header-logo");
128
+ const logoImage = headerLogo.querySelector("img");
129
+ expect(logoImage).toHaveAttribute("src", "../../../assets/Logo.png");
130
+ });
131
+
132
+ test("contains correct alt text from Image component", () => {
133
+ const headerLogo = screen.getByTestId("header-logo");
134
+ const logoImage = headerLogo.querySelector("img");
135
+ expect(logoImage).toHaveAttribute("alt", "Generic Company Logo.");
136
+ });
137
+
138
+ // TODO: refactor/expand test when nav is created
139
+ test("contains correct placeholder nav menus", () => {
140
+ expect(screen.getByTestId("nav")).toBeInTheDocument();
141
+ });
142
+
143
+ // TODO: refactor/expand test when input is added
144
+ test("contains correct placeholder input", () => {
145
+ expect(
146
+ screen.getByTestId("header-placeholder-input")
147
+ ).toBeInTheDocument();
148
+ });
149
+
150
+ test("contains correct badge", () => {
151
+ expect(screen.getByTestId("header-badge")).toBeInTheDocument();
152
+
153
+ const badge = screen.getByTestId("header-badge");
154
+ expect(badge).toHaveTextContent("Contact Us");
155
+ expect(badge).toHaveTextContent("1-800-800-8000");
156
+ });
157
+
158
+ test("contains correct icon images", () => {
159
+ expect(screen.getByTestId("user")).toBeInTheDocument();
160
+ expect(screen.getByTestId("circle-info")).toBeInTheDocument();
161
+ expect(screen.getByTestId("bell")).toBeInTheDocument();
162
+ expect(screen.getByTestId("cart-shopping")).toBeInTheDocument();
163
+ });
164
+ });
165
+
166
+ describe("<Header /> with logo and one icon", () => {
167
+ beforeEach(() => {
168
+ render(
169
+ <Header
170
+ logo={
171
+ <Image
172
+ src="../../../assets/Logo.png"
173
+ alt="Another Generic Company Logo."
174
+ background={false}
175
+ additionalClasses=" w-40 "
176
+ />
177
+ }
178
+ hasMobileMenu={true}
179
+ backgroundColor="gray"
180
+ mobileOpenIcon={getFontAwesomeIcon("hamburger")}
181
+ mobileCloseIcon={getFontAwesomeIcon("X")}
182
+ mobileLeft={false}
183
+ mobileRight={true}
184
+ logoHoverColor="blue"
185
+ logoBorderRadius={true}
186
+ hasIcons={true}
187
+ icons={
188
+ <GenericList
189
+ data={DUMMYICONDATA.DUMMYICONCOMPASSDATA}
190
+ renderItem={(item) => <DynamicIconList item={item} />}
191
+ itemHeight={20}
192
+ containerHeight={72}
193
+ listType="unordered"
194
+ containerClasses="bg-gray-100 w-36 border-2 border-teal-500"
195
+ listDirection="vertical"
196
+ hasVirtualization={false}
197
+ />
198
+ }
199
+ hasSearchBar={false}
200
+ hasNavItems={false}
201
+ hasBadge={false}
202
+ />
203
+ );
204
+ });
205
+
206
+ test("renders Header component", () => {
207
+ expect(screen.getByTestId("header")).toBeInTheDocument();
208
+ });
209
+
210
+ test("renders correct background color class", () => {
211
+ const header = screen.getByTestId("header");
212
+ expect(header).toHaveClass("bg-slate-200");
213
+ });
214
+
215
+ test("contains correct logo from Image component", () => {
216
+ const headerLogo = screen.getByTestId("header-logo");
217
+ const logoImage = headerLogo.querySelector("img");
218
+ expect(logoImage).toHaveAttribute("src", "../../../assets/Logo.png");
219
+ });
220
+
221
+ test("contains correct alt text from Image component", () => {
222
+ const headerLogo = screen.getByTestId("header-logo");
223
+ const logoImage = headerLogo.querySelector("img");
224
+ expect(logoImage).toHaveAttribute(
225
+ "alt",
226
+ "Another Generic Company Logo."
227
+ );
228
+ });
229
+
230
+ test("does not contain badge", () => {
231
+ expect(
232
+ document.querySelector('[data-testid="header-badge"]')
233
+ ).toBeNull();
234
+ });
235
+
236
+ test("contains correct icon images", () => {
237
+ const info = document.querySelector('[data-testid="circle-info"]');
238
+ expect(info).toBeInTheDocument();
239
+
240
+ const notifications = document.querySelector('[data-testid="bell"]');
241
+ expect(notifications).toBeInTheDocument();
242
+
243
+ const cart = document.querySelector('[data-testid="cart-shopping"]');
244
+ expect(cart).toBeInTheDocument();
245
+ });
246
+
247
+ test("does not contain placeholder input", () => {
248
+ expect(
249
+ document.querySelector('[data-testid="header-placeholder-input"]')
250
+ ).toBeNull();
251
+ });
252
+
253
+ test("does not contain nav items", () => {
254
+ expect(document.querySelector('[data-testid="nav"]')).toBeNull();
255
+ });
256
+
257
+ test("contains mobile open icon on right, not present on left", () => {
258
+ const rightMobileOpenIcon = document.querySelector(
259
+ '[data-testid="header-right-mobile-open-icon"]'
260
+ );
261
+ expect(rightMobileOpenIcon).not.toBeNull();
262
+
263
+ const leftMobileOpenIcon = document.querySelector(
264
+ '[data-testid="header-left-mobile-open-icon"]'
265
+ );
266
+ expect(leftMobileOpenIcon).toBeNull();
267
+ });
268
+ });
269
+
270
+ describe("<Header /> with both mobileLeft and mobileRight set to true, mobileRight is default", () => {
271
+ beforeEach(() => {
272
+ render(
273
+ <Header
274
+ logo={
275
+ <Image
276
+ src="../../../assets/Logo.png"
277
+ alt="Another Generic Company Logo."
278
+ background={false}
279
+ additionalClasses=" w-40 "
280
+ />
281
+ }
282
+ hasMobileMenu={true}
283
+ backgroundColor="red"
284
+ mobileOpenIcon={getFontAwesomeIcon("hamburger")}
285
+ mobileCloseIcon={getFontAwesomeIcon("X")}
286
+ mobileLeft={true}
287
+ mobileRight={true}
288
+ logoHoverColor="blue"
289
+ logoBorderRadius={true}
290
+ hasIcons={true}
291
+ icons={
292
+ <GenericList
293
+ data={DUMMYICONDATA.DUMMYICONTOGADATA}
294
+ renderItem={(item) => <DynamicIconList item={item} />}
295
+ itemHeight={20}
296
+ containerHeight={72}
297
+ listType="unordered"
298
+ containerClasses="bg-gray-100 w-36 border-2 border-teal-500"
299
+ listDirection="vertical"
300
+ hasVirtualization={false}
301
+ />
302
+ }
303
+ hasSearchBar={false}
304
+ hasNavItems={false}
305
+ hasBadge={false}
306
+ />
307
+ );
308
+ });
309
+
310
+ test("defaults to mobile open icon on right, not present on left", () => {
311
+ expect(
312
+ document.querySelector(
313
+ '[data-testid="header-right-mobile-open-icon"]'
314
+ )
315
+ ).not.toBeNull();
316
+
317
+ expect(
318
+ document.querySelector(
319
+ '[data-testid="header-left-mobile-open-icon"]'
320
+ )
321
+ ).toBeNull();
322
+ });
323
+ });
@@ -0,0 +1,289 @@
1
+ import React, { useState } from "react";
2
+ import { motion, AnimatePresence, MotionConfig } from "framer-motion";
3
+
4
+ import {
5
+ getLogoClasses,
6
+ getHeaderClasses,
7
+ getMobileMenuClasses,
8
+ } from "./headerClassNames";
9
+ import { HeaderTypes } from "./Header.types";
10
+ import MobileMenu from "../MobileMenu/MobileMenu";
11
+ import { HeaderProvider } from "./headerContext";
12
+ import HamburgerButton from "../HamburgerButton/HamburgerButton";
13
+ import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
14
+ const justifyMap = {
15
+ start: "justify-start",
16
+ center: "justify-center",
17
+ end: "justify-end",
18
+ between: "justify-between",
19
+ around: "justify-around",
20
+ };
21
+
22
+ const Header: React.FC<HeaderTypes> = ({
23
+ logo,
24
+ badge,
25
+ nav,
26
+ input,
27
+ icons,
28
+
29
+ backgroundColor,
30
+ bottomBorderColor,
31
+ hasGlass = false,
32
+
33
+ logoBorderRadius,
34
+ logoHoverColor,
35
+
36
+ hasAnimatedHamburgerButton = false,
37
+ hasMobileMenu,
38
+ mobileLeft = true,
39
+ mobileRight = false,
40
+ mobileMenuBackground,
41
+
42
+ iconsData,
43
+
44
+ hasIcons = false,
45
+ hasNavItems = false,
46
+ hasBadge = false,
47
+ hasSearchBar = false,
48
+
49
+ hasMobileIcons = true,
50
+ hasMobileNavItems = true,
51
+ hasMobileBadge = true,
52
+ hasMobileSearchBar = true,
53
+
54
+ justifyNav = "center",
55
+ justifyInput = "center",
56
+ justifyBadge = "center",
57
+ justifyIcons = "center",
58
+
59
+ logoOrder,
60
+ navOrder,
61
+ inputOrder,
62
+ badgeOrder,
63
+ iconsOrder,
64
+ }) => {
65
+ const [navSideMenuVisibility, setNavSideMenuVisibility] =
66
+ useState<boolean>(false);
67
+
68
+ const handleNav = () => {
69
+ setNavSideMenuVisibility(!navSideMenuVisibility);
70
+ };
71
+
72
+ const burgerAriaLabel = navSideMenuVisibility
73
+ ? "Select to close menu"
74
+ : "Select to open menu";
75
+ const burgerExpandedAlert = navSideMenuVisibility ? "True" : "False";
76
+
77
+ if (mobileRight) {
78
+ mobileLeft = false;
79
+ } else if (mobileLeft) {
80
+ mobileRight = false;
81
+ }
82
+
83
+ let logoClasses = getLogoClasses(logoBorderRadius, logoHoverColor);
84
+ let headerClasses = getHeaderClasses(backgroundColor, bottomBorderColor);
85
+ let mobileMenuClasses = getMobileMenuClasses(mobileMenuBackground);
86
+
87
+ justifyNav = justifyMap[justifyNav as keyof typeof justifyMap];
88
+ justifyInput = justifyMap[justifyInput as keyof typeof justifyMap];
89
+ justifyBadge = justifyMap[justifyBadge as keyof typeof justifyMap];
90
+ justifyIcons = justifyMap[justifyIcons as keyof typeof justifyMap];
91
+
92
+ return (
93
+ <HeaderProvider
94
+ hasMobileIcons={hasMobileIcons}
95
+ hasMobileNavItems={hasMobileNavItems}
96
+ hasMobileBadge={hasMobileBadge}
97
+ hasMobileSearchBar={hasMobileSearchBar}
98
+ iconsData={iconsData}
99
+ hasIcons={false}
100
+ hasNavItems={false}
101
+ hasBadge={false}
102
+ hasSearchBar={false}
103
+ mobileCloseIcon={null}
104
+ >
105
+ <header
106
+ data-testid="header"
107
+ className={`${headerClasses} border-b-2 h-20 z-[1000] top-0 w-full px-2 ${
108
+ hasGlass ? "glass" : "bg-white"
109
+ }`}
110
+ >
111
+ <div className="flex min-h-20">
112
+ {/* LEFT MOBILE OPEN ICON */}
113
+ {hasMobileMenu && mobileLeft && (
114
+ <div
115
+ className="pl-2 mx-auto my-auto hidden max-xl:flex"
116
+ data-testid="header-left-mobile-open-icon"
117
+ >
118
+ {hasAnimatedHamburgerButton ? (
119
+ <HamburgerButton
120
+ burgerAriaLabel={burgerAriaLabel}
121
+ burgerExpandedAlert={burgerExpandedAlert}
122
+ animateBoolean={navSideMenuVisibility}
123
+ handleNav={handleNav}
124
+ />
125
+ ) : (
126
+ <button
127
+ aria-label={burgerAriaLabel}
128
+ aria-expanded={
129
+ burgerExpandedAlert === "True"
130
+ ? true
131
+ : false
132
+ }
133
+ data-testid="hamburger-button"
134
+ onClick={handleNav}
135
+ className="flex flex-col space-y-1 relative z-10 p-2"
136
+ >
137
+ {burgerExpandedAlert === "True"
138
+ ? getFontAwesomeIcon("X")
139
+ : getFontAwesomeIcon("hamburger")}
140
+ </button>
141
+ )}
142
+ </div>
143
+ )}
144
+
145
+ {/* LOGO */}
146
+ <div
147
+ className={`flex flex-auto items-center pl-1 order-${logoOrder}`}
148
+ >
149
+ <a
150
+ className={logoClasses}
151
+ href=""
152
+ data-testid="header-logo"
153
+ >
154
+ {logo}
155
+ </a>
156
+ </div>
157
+
158
+ {/* NAV MENUS */}
159
+ <div
160
+ className={`flex flex-auto ${justifyNav} max-xl:hidden order-${navOrder}`}
161
+ >
162
+ {hasNavItems && nav}
163
+ </div>
164
+
165
+ {/* INPUT */}
166
+ {hasSearchBar && (
167
+ <div
168
+ className={`flex flex-auto items-center ${justifyInput} max-xl:hidden order-${inputOrder}`}
169
+ data-testid="header-placeholder-input"
170
+ >
171
+ <div className="2xl:flex w-full [&:has(:focus-visible)]:ring-2">
172
+ {input}
173
+ </div>
174
+ </div>
175
+ )}
176
+
177
+ {/* BADGE AND ICONS */}
178
+ {hasBadge && (
179
+ <div
180
+ className={`flex flex-auto items-center ${justifyBadge} max-xl:justify-end order-${badgeOrder}`}
181
+ data-testid="header-badge"
182
+ >
183
+ <div className="w-fit">{badge}</div>
184
+ </div>
185
+ )}
186
+ {hasIcons && (
187
+ <div
188
+ className={`flex flex-auto items-center ${justifyIcons} max-xl:hidden order-${iconsOrder}`}
189
+ data-testid="header-icons"
190
+ >
191
+ {/* FIXME: we need to find a way to keep the type tight for this and still deal with the error */}
192
+ {/* @ts-ignore */}
193
+ {icons}
194
+ </div>
195
+ )}
196
+
197
+ {/* RIGHT MOBILE OPEN ICON */}
198
+ {hasMobileMenu && mobileRight && (
199
+ <div
200
+ className="pr-2 mx-auto my-auto hidden max-xl:flex"
201
+ data-testid="header-right-mobile-open-icon"
202
+ >
203
+ {hasAnimatedHamburgerButton ? (
204
+ <HamburgerButton
205
+ burgerAriaLabel={burgerAriaLabel}
206
+ burgerExpandedAlert={burgerExpandedAlert}
207
+ animateBoolean={navSideMenuVisibility}
208
+ handleNav={handleNav}
209
+ />
210
+ ) : (
211
+ <button
212
+ aria-label={burgerAriaLabel}
213
+ aria-expanded={
214
+ burgerExpandedAlert === "True"
215
+ ? true
216
+ : false
217
+ }
218
+ data-testid="hamburger-button"
219
+ onClick={handleNav}
220
+ className="flex flex-col space-y-1 relative z-10 p-2"
221
+ >
222
+ {burgerExpandedAlert === "True"
223
+ ? getFontAwesomeIcon("X")
224
+ : getFontAwesomeIcon("hamburger")}
225
+ </button>
226
+ )}
227
+ </div>
228
+ )}
229
+ {/* MOBILE MENU */}
230
+ <AnimatePresence>
231
+ {hasMobileMenu && navSideMenuVisibility && (
232
+ <div>
233
+ <MotionConfig
234
+ transition={{
235
+ type: "spring",
236
+ bounce: 0.1,
237
+ }}
238
+ >
239
+ <motion.div
240
+ key="mobile-nav"
241
+ variants={{
242
+ hide: {
243
+ x: mobileRight
244
+ ? "100%"
245
+ : "-100%",
246
+ transition: {
247
+ type: "spring",
248
+ bounce: 0.1,
249
+ when: "afterChildren",
250
+ staggerChildren: 0.25,
251
+ },
252
+ },
253
+ show: {
254
+ x: "0%",
255
+ transition: {
256
+ type: "spring",
257
+ bounce: 0.1,
258
+ when: "beforeChildren",
259
+ staggerChildren: 0.25,
260
+ },
261
+ },
262
+ }}
263
+ initial="hide"
264
+ animate="show"
265
+ exit="hide"
266
+ className="fixed inset-0 flex flex-col justify-center space-y-10"
267
+ >
268
+ <MobileMenu
269
+ handleNav={handleNav}
270
+ badge={badge}
271
+ nav={nav}
272
+ input={input}
273
+ icons={icons}
274
+ mobileMenuClasses={
275
+ mobileMenuClasses
276
+ }
277
+ />
278
+ </motion.div>
279
+ </MotionConfig>
280
+ </div>
281
+ )}
282
+ </AnimatePresence>
283
+ </div>
284
+ </header>
285
+ </HeaderProvider>
286
+ );
287
+ };
288
+
289
+ export default Header;
@@ -0,0 +1,52 @@
1
+ import { DUMMYICONCOMPASSDATA, DUMMYICONTOGADATA } from "./DUMMYICONDATA.json";
2
+
3
+ export interface HeaderTypes {
4
+ onClick?: (
5
+ e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>
6
+ ) => void;
7
+ nav?: React.ReactNode;
8
+ logo?: React.ReactNode;
9
+ badge?: React.ReactNode;
10
+ icons?: React.ReactNode;
11
+ input?: React.ReactNode;
12
+ children?: React.ReactNode;
13
+
14
+ logoHoverColor?: string;
15
+ logoBorderRadius?: boolean;
16
+
17
+ backgroundColor?: string;
18
+ bottomBorderColor?: string;
19
+ hasGlass?: boolean;
20
+
21
+ hasAnimatedHamburgerButton?: boolean;
22
+ mobileOpenIcon?: JSX.Element | undefined | null;
23
+ mobileCloseIcon?: JSX.Element | null;
24
+ mobileLeft?: boolean;
25
+ mobileRight?: boolean;
26
+ mobileMenuBackground?: string;
27
+
28
+ iconsData?: typeof DUMMYICONCOMPASSDATA | typeof DUMMYICONTOGADATA;
29
+
30
+ hasIcons?: boolean;
31
+ hasSearchBar?: boolean;
32
+ hasNavItems?: boolean;
33
+ hasBadge?: boolean;
34
+
35
+ hasMobileMenu?: boolean;
36
+
37
+ hasMobileIcons?: boolean;
38
+ hasMobileNavItems?: boolean;
39
+ hasMobileBadge?: boolean;
40
+ hasMobileSearchBar?: boolean;
41
+
42
+ justifyNav?: string;
43
+ justifyInput?: string;
44
+ justifyBadge?: string;
45
+ justifyIcons?: string;
46
+
47
+ logoOrder?: number;
48
+ navOrder?: number;
49
+ inputOrder?: number;
50
+ badgeOrder?: number;
51
+ iconsOrder?: number;
52
+ }
@@ -0,0 +1,50 @@
1
+ import classNames from "classNames";
2
+
3
+
4
+ export const getLogoClasses = (logoBorderRadius: boolean | undefined, logoHoverColor: string | undefined) => {
5
+
6
+ return classNames(
7
+ "border-transparent",
8
+ "p-1",
9
+ {
10
+ "rounded-full": logoBorderRadius === true,
11
+ "rounded-none": logoBorderRadius === false,
12
+ },
13
+ {
14
+ "hover:bg-blue-300": logoHoverColor === "blue",
15
+ "hover:bg-red-300": logoHoverColor === "red",
16
+ "hover:bg-teal-100": logoHoverColor === "green",
17
+ }
18
+ );
19
+ };
20
+
21
+ export const getHeaderClasses = (backgroundColor: string | undefined, bottomBorderColor: string | undefined,) => {
22
+ return classNames(
23
+ {
24
+ "bg-teal-100": backgroundColor === "green",
25
+ "bg-blue-100": backgroundColor === "blue",
26
+ "bg-slate-200": backgroundColor === "gray",
27
+ "bg-transparent": backgroundColor === "none",
28
+ },
29
+ {
30
+ "border-teal-500": bottomBorderColor === "green",
31
+ "border-blue-500": bottomBorderColor === "blue",
32
+ "border-slate-950": bottomBorderColor === "black",
33
+ "border-transparent": bottomBorderColor === "none",
34
+ }
35
+ );
36
+ };
37
+
38
+ export const getMobileMenuClasses = (
39
+ mobileMenuBackground: string | undefined,
40
+ ) => {
41
+ return classNames(
42
+ {
43
+ "bg-teal-50": mobileMenuBackground === "green",
44
+ "bg-blue-50": mobileMenuBackground === "blue",
45
+ "bg-slate-100": mobileMenuBackground === "gray",
46
+ "bg-slate-50": mobileMenuBackground === "white",
47
+ "bg-transparent": mobileMenuBackground === "none",
48
+ }
49
+ );
50
+ };