@comicrelief/component-library 8.54.0 → 8.55.0

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 (76) hide show
  1. package/dist/components/Atoms/Logo/Logo.js +0 -5
  2. package/dist/components/Atoms/Logo/Logo.test.js +1 -1
  3. package/dist/components/Atoms/LogoNav2026/LogoNav2026.test.js +94 -0
  4. package/dist/components/Atoms/LogoNav2026/_LogoNav2026.js +63 -0
  5. package/dist/components/Atoms/LogoNav2026/assets/cr-logo-mob.svg +14 -0
  6. package/dist/components/Atoms/LogoNav2026/assets/cr-logo.svg +14 -0
  7. package/dist/components/Molecules/CTA/CTAMultiCard/__snapshots__/CTAMultiCard.test.js.snap +12 -12
  8. package/dist/components/Molecules/CTA/CTASingleCard/CTASingleCard.md +2 -2
  9. package/dist/components/Molecules/CTA/CTASingleCard/__snapshots__/CTASingleCard.test.js.snap +2 -2
  10. package/dist/components/Molecules/CTA/shared/CTACard.style.js +1 -1
  11. package/dist/components/Molecules/LogoLinked/LogoLinked.md +6 -1
  12. package/dist/components/Organisms/Header/HeaderNav/HeaderNav.style.js +3 -3
  13. package/dist/components/Organisms/Header2025/Header2025.md +1 -1
  14. package/dist/components/Organisms/Header2025/HeaderNav2025/HeaderNav2025.js +1 -1
  15. package/dist/components/Organisms/Header2025/HeaderNav2025/HeaderNav2025.style.js +3 -3
  16. package/dist/components/Organisms/Header2026/Burger/BurgerMenu.js +25 -0
  17. package/dist/components/Organisms/Header2026/Burger/BurgerMenu.style.js +58 -0
  18. package/dist/components/Organisms/Header2026/Header2026.js +148 -0
  19. package/dist/components/Organisms/Header2026/Header2026.md +14 -0
  20. package/dist/components/Organisms/Header2026/Header2026.style.js +129 -0
  21. package/dist/components/Organisms/Header2026/Navs/Navs.js +209 -0
  22. package/dist/components/Organisms/Header2026/Navs/Navs.style.js +104 -0
  23. package/dist/components/Organisms/Header2026/Navs/PrimaryNavItem.js +227 -0
  24. package/dist/components/Organisms/Header2026/Navs/PrimaryNavItem.style.js +401 -0
  25. package/dist/components/Organisms/Header2026/Navs/arrow-right.png +0 -0
  26. package/dist/components/Organisms/Header2026/Navs/arrow.svg +6 -0
  27. package/dist/components/Organisms/Header2026/Navs/chevron-down.svg +3 -0
  28. package/dist/components/Organisms/Header2026/assets/arrow-icon.svg +3 -0
  29. package/dist/components/Organisms/Header2026/assets/chevron-icon.svg +3 -0
  30. package/dist/components/Organisms/Header2026/assets/search-icon.svg +10 -0
  31. package/dist/components/Organisms/Header2026/header2026.test.js +24 -0
  32. package/dist/components/Organisms/Header2026/mockData/mockData.json +569 -0
  33. package/dist/components/Organisms/Header2026/mockData/query.graphql +64 -0
  34. package/dist/theme/shared/animations.js +6 -1
  35. package/dist/utils/navHelper.js +75 -3
  36. package/dist/utils/remove-extra-styles-in-preview.css +14 -0
  37. package/dist/utils/urlHelper.js +30 -0
  38. package/package.json +1 -1
  39. package/src/components/Atoms/Logo/Logo.js +0 -4
  40. package/src/components/Atoms/Logo/Logo.test.js +5 -5
  41. package/src/components/Atoms/LogoNav2026/LogoNav2026.test.js +91 -0
  42. package/src/components/Atoms/LogoNav2026/_LogoNav2026.js +75 -0
  43. package/src/components/Atoms/LogoNav2026/assets/cr-logo-mob.svg +14 -0
  44. package/src/components/Atoms/LogoNav2026/assets/cr-logo.svg +14 -0
  45. package/src/components/Molecules/CTA/CTAMultiCard/__snapshots__/CTAMultiCard.test.js.snap +12 -12
  46. package/src/components/Molecules/CTA/CTASingleCard/CTASingleCard.md +2 -2
  47. package/src/components/Molecules/CTA/CTASingleCard/__snapshots__/CTASingleCard.test.js.snap +2 -2
  48. package/src/components/Molecules/CTA/shared/CTACard.style.js +1 -1
  49. package/src/components/Molecules/LogoLinked/LogoLinked.md +6 -1
  50. package/src/components/Organisms/Header/HeaderNav/HeaderNav.style.js +2 -2
  51. package/src/components/Organisms/Header2025/Header2025.md +1 -1
  52. package/src/components/Organisms/Header2025/HeaderNav2025/HeaderNav2025.js +1 -1
  53. package/src/components/Organisms/Header2025/HeaderNav2025/HeaderNav2025.style.js +2 -2
  54. package/src/components/Organisms/Header2026/Burger/BurgerMenu.js +26 -0
  55. package/src/components/Organisms/Header2026/Burger/BurgerMenu.style.js +104 -0
  56. package/src/components/Organisms/Header2026/Header2026.js +215 -0
  57. package/src/components/Organisms/Header2026/Header2026.md +14 -0
  58. package/src/components/Organisms/Header2026/Header2026.style.js +195 -0
  59. package/src/components/Organisms/Header2026/Navs/Navs.js +251 -0
  60. package/src/components/Organisms/Header2026/Navs/Navs.style.js +168 -0
  61. package/src/components/Organisms/Header2026/Navs/PrimaryNavItem.js +354 -0
  62. package/src/components/Organisms/Header2026/Navs/PrimaryNavItem.style.js +658 -0
  63. package/src/components/Organisms/Header2026/Navs/arrow-right.png +0 -0
  64. package/src/components/Organisms/Header2026/Navs/arrow.svg +6 -0
  65. package/src/components/Organisms/Header2026/Navs/chevron-down.svg +3 -0
  66. package/src/components/Organisms/Header2026/assets/arrow-icon.svg +3 -0
  67. package/src/components/Organisms/Header2026/assets/chevron-icon.svg +3 -0
  68. package/src/components/Organisms/Header2026/assets/search-icon.svg +10 -0
  69. package/src/components/Organisms/Header2026/header2026.test.js +22 -0
  70. package/src/components/Organisms/Header2026/mockData/mockData.json +569 -0
  71. package/src/components/Organisms/Header2026/mockData/query.graphql +64 -0
  72. package/src/theme/crTheme/theme.js +0 -1
  73. package/src/theme/shared/animations.js +43 -2
  74. package/src/utils/navHelper.js +82 -2
  75. package/src/utils/remove-extra-styles-in-preview.css +14 -0
  76. package/src/utils/urlHelper.js +27 -0
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.pageLinksPropTypes = exports.default = void 0;
9
+ require("../../../utils/remove-extra-styles-in-preview.css");
10
+ var _react = _interopRequireWildcard(require("react"));
11
+ var _propTypes = _interopRequireDefault(require("prop-types"));
12
+ var _LogoNav = _interopRequireDefault(require("../../Atoms/LogoNav2026/_LogoNav2026"));
13
+ var _Navs = _interopRequireDefault(require("./Navs/Navs"));
14
+ var _Link = _interopRequireDefault(require("../../Atoms/Link/Link"));
15
+ var _Header = require("./Header2026.style");
16
+ var _searchIcon = _interopRequireDefault(require("./assets/search-icon.svg"));
17
+ var _chevronIcon = _interopRequireDefault(require("./assets/chevron-icon.svg"));
18
+ var _Icon = _interopRequireDefault(require("../../Atoms/SocialIcons/Icon/Icon"));
19
+ var _urlHelper = _interopRequireDefault(require("../../../utils/urlHelper"));
20
+ var _breakpoints = require("../../../theme/shared/breakpoints2026");
21
+ const Header2026 = _ref => {
22
+ let {
23
+ data = {},
24
+ characterLimit = 60,
25
+ devMode = false,
26
+ ...rest
27
+ } = _ref;
28
+ const [isMenuOpen, setIsMenuOpen] = (0, _react.useState)(false);
29
+ const [isSubMenuOpen, setIsSubMenuOpen] = (0, _react.useState)(false);
30
+ const [isTertiaryMenuOpen, setIsTertiaryMenuOpen] = (0, _react.useState)(false);
31
+ const [tertiaryParentName, setTertiaryParentName] = (0, _react.useState)(null);
32
+ const closeSubMenusRef = (0, _react.useRef)(null);
33
+ const closeTertiaryRef = (0, _react.useRef)(null);
34
+ const handleSubMenuChange = (0, _react.useCallback)((isOpen, closeFunction) => {
35
+ setIsSubMenuOpen(isOpen);
36
+ closeSubMenusRef.current = closeFunction;
37
+ }, []);
38
+ const handleTertiaryMenuChange = (0, _react.useCallback)((isOpen, parentName, closeFunction) => {
39
+ setIsTertiaryMenuOpen(isOpen);
40
+ setTertiaryParentName(parentName);
41
+ closeTertiaryRef.current = closeFunction;
42
+ }, []);
43
+
44
+ // Prevent body scroll when mobile menu is open
45
+ (0, _react.useEffect)(() => {
46
+ document.body.style.overflow = isMenuOpen ? 'hidden' : '';
47
+ return () => {
48
+ document.body.style.overflow = '';
49
+ };
50
+ }, [isMenuOpen]);
51
+
52
+ // Reset mobile nav state when resizing to desktop
53
+ (0, _react.useEffect)(() => {
54
+ let timeoutId;
55
+ const handleResize = () => {
56
+ clearTimeout(timeoutId);
57
+ timeoutId = setTimeout(() => {
58
+ if (window.innerWidth >= _breakpoints.breakpointValues2026.L) {
59
+ setIsMenuOpen(false);
60
+ setIsSubMenuOpen(false);
61
+ setIsTertiaryMenuOpen(false);
62
+ setTertiaryParentName(null);
63
+ }
64
+ }, 150);
65
+ };
66
+ window.addEventListener('resize', handleResize);
67
+ return () => {
68
+ window.removeEventListener('resize', handleResize);
69
+ clearTimeout(timeoutId);
70
+ };
71
+ }, []);
72
+ const handleBackClick = () => {
73
+ if (isTertiaryMenuOpen && closeTertiaryRef.current) {
74
+ closeTertiaryRef.current();
75
+ setIsTertiaryMenuOpen(false);
76
+ setTertiaryParentName(null);
77
+ } else if (closeSubMenusRef.current) {
78
+ closeSubMenusRef.current();
79
+ }
80
+ };
81
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_Header.MobileMenuOverlay, {
82
+ isVisible: isMenuOpen
83
+ }), /*#__PURE__*/_react.default.createElement(_Header.Header2026Wrapper, Object.assign({
84
+ "data-testid": "Header2026Wrapper",
85
+ role: "banner"
86
+ }, rest), /*#__PURE__*/_react.default.createElement(_Header.InnerWrapper, {
87
+ "data-testid": "InnerWrapper"
88
+ }, isSubMenuOpen || isTertiaryMenuOpen ? /*#__PURE__*/_react.default.createElement(_Header.MobileBackHeader, {
89
+ "data-testid": "MobileBackHeader",
90
+ onClick: handleBackClick,
91
+ type: "button",
92
+ "aria-label": isTertiaryMenuOpen ? `Go back to ${tertiaryParentName}` : 'Go back to main menu'
93
+ }, /*#__PURE__*/_react.default.createElement(_Header.BackChevron, null, /*#__PURE__*/_react.default.createElement("img", {
94
+ src: _chevronIcon.default,
95
+ alt: "chevron icon"
96
+ })), isTertiaryMenuOpen ? tertiaryParentName : 'Main menu') : /*#__PURE__*/_react.default.createElement(_Header.Brand, {
97
+ "data-testid": "Brand"
98
+ }, /*#__PURE__*/_react.default.createElement(_LogoNav.default, {
99
+ "data-testid": "LogoNav2026"
100
+ })), /*#__PURE__*/_react.default.createElement(_Navs.default, {
101
+ "data-testid": "Navs",
102
+ navItems: data,
103
+ characterLimit: characterLimit,
104
+ isMenuOpen: isMenuOpen,
105
+ setIsMenuOpen: setIsMenuOpen,
106
+ devMode: devMode,
107
+ onSubMenuChange: handleSubMenuChange,
108
+ onTertiaryMenuChange: handleTertiaryMenuChange
109
+ }), /*#__PURE__*/_react.default.createElement(_Header.ButtonsAndIcons, {
110
+ "data-testid": "ButtonsAndIcons"
111
+ }, /*#__PURE__*/_react.default.createElement(_Header.SearchIconWrapperDesktop, {
112
+ "data-testid": "SearchIconWrapperDesktop"
113
+ }, /*#__PURE__*/_react.default.createElement(_Icon.default, {
114
+ icon: _searchIcon.default,
115
+ title: "Search",
116
+ target: "self",
117
+ role: "button",
118
+ href: (0, _urlHelper.default)('/search', devMode),
119
+ brand: "comicrelief",
120
+ tabIndex: "0",
121
+ id: "search"
122
+ })), !isMenuOpen && /*#__PURE__*/_react.default.createElement(_Header.DonateButtonTopBarWrapper, {
123
+ "data-testid": "DonateButtonTopBarWrapper"
124
+ }, /*#__PURE__*/_react.default.createElement(_Link.default, {
125
+ color: "red",
126
+ type: "button",
127
+ href: "https://donation.comicrelief.com/"
128
+ }, "Donate"))))));
129
+ };
130
+ const pageLinksPropTypes = exports.pageLinksPropTypes = _propTypes.default.arrayOf(_propTypes.default.shape({
131
+ pageName: _propTypes.default.string.isRequired,
132
+ pageUrlIfExternal: _propTypes.default.string,
133
+ pageLevel: _propTypes.default.bool.isRequired,
134
+ pageSelector: _propTypes.default.shape({
135
+ title: _propTypes.default.string,
136
+ path: _propTypes.default.string,
137
+ header_page_link: _propTypes.default.arrayOf(_propTypes.default.shape({
138
+ pageName: _propTypes.default.string.isRequired,
139
+ pageSelector: _propTypes.default.shape({
140
+ path: _propTypes.default.string.isRequired,
141
+ title: _propTypes.default.string.isRequired
142
+ }).isRequired,
143
+ pageUrlIfExternal: _propTypes.default.string,
144
+ pageLevel: _propTypes.default.bool.isRequired
145
+ }))
146
+ })
147
+ }));
148
+ var _default = exports.default = Header2026;
@@ -0,0 +1,14 @@
1
+ # Header 2026 - Comic Relief
2
+
3
+ #### Dev Mode - prepends `https://www.comicrelief.com` to page links
4
+
5
+ ```js
6
+ import mockData from './mockData/mockData.json';
7
+
8
+ const headerMenuNode = mockData.data.allContentfulHeaderMenu.edges[0].node;
9
+
10
+ <Header2026
11
+ data={headerMenuNode}
12
+ devMode
13
+ />;
14
+ ```
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.SearchIconWrapperDesktop = exports.MobileMenuOverlay = exports.MobileBackHeader = exports.InnerWrapper = exports.Header2026Wrapper = exports.DonateButtonTopBarWrapper = exports.ButtonsAndIcons = exports.Brand = exports.BackChevron = void 0;
8
+ var _styledComponents = _interopRequireDefault(require("styled-components"));
9
+ var _zIndex = _interopRequireDefault(require("../../../theme/shared/zIndex"));
10
+ var _containers = _interopRequireDefault(require("../../../theme/shared/containers"));
11
+ var _animations = require("../../../theme/shared/animations");
12
+ const Header2026Wrapper = exports.Header2026Wrapper = _styledComponents.default.header.withConfig({
13
+ displayName: "Header2026style__Header2026Wrapper",
14
+ componentId: "sc-1do20kd-0"
15
+ })(["position:relative;z-index:2;background-color:", ";border:1px solid ", ";box-shadow:0 5px 20px 0 rgba(0,0,0,0.05);border-radius:16px;@media ", "{height:66px;margin-top:18px;&:has(li:hover),&:has(li:focus-within){border-radius:16px 16px 0 0;}}"], _ref => {
16
+ let {
17
+ theme
18
+ } = _ref;
19
+ return theme.color('white');
20
+ }, _ref2 => {
21
+ let {
22
+ theme
23
+ } = _ref2;
24
+ return theme.color('grey_light');
25
+ }, _ref3 => {
26
+ let {
27
+ theme
28
+ } = _ref3;
29
+ return theme.breakpoints2026('L');
30
+ });
31
+ const InnerWrapper = exports.InnerWrapper = _styledComponents.default.div.withConfig({
32
+ displayName: "Header2026style__InnerWrapper",
33
+ componentId: "sc-1do20kd-1"
34
+ })(["display:flex;align-items:center;height:100%;cursor:pointer;max-width:", ";padding:10px;position:relative;z-index:2;@media ", "{padding:10px 16px 10px 14px;}@media ", "{padding:10px 16px;}@media ", "{margin:0 auto;gap:24px;}"], _containers.default.large, _ref4 => {
35
+ let {
36
+ theme
37
+ } = _ref4;
38
+ return theme.breakpoints2026('S');
39
+ }, _ref5 => {
40
+ let {
41
+ theme
42
+ } = _ref5;
43
+ return theme.breakpoints2026('M');
44
+ }, _ref6 => {
45
+ let {
46
+ theme
47
+ } = _ref6;
48
+ return theme.breakpoints2026('L');
49
+ });
50
+
51
+ // size of "Comic Relief" logo is set with props on LogoLinked2026
52
+ const Brand = exports.Brand = _styledComponents.default.div.withConfig({
53
+ displayName: "Header2026style__Brand",
54
+ componentId: "sc-1do20kd-2"
55
+ })(["", ";margin-right:auto;display:flex;align-items:center;a{border:0;color:transparent;:hover{border:0;}}@media ", "{margin-right:0}"], (0, _zIndex.default)('high'), _ref7 => {
56
+ let {
57
+ theme
58
+ } = _ref7;
59
+ return theme.breakpoints2026('L');
60
+ });
61
+ const ButtonsAndIcons = exports.ButtonsAndIcons = _styledComponents.default.div.withConfig({
62
+ displayName: "Header2026style__ButtonsAndIcons",
63
+ componentId: "sc-1do20kd-3"
64
+ })(["margin-left:auto;display:flex;"]);
65
+ const DonateButtonTopBarWrapper = exports.DonateButtonTopBarWrapper = _styledComponents.default.div.withConfig({
66
+ displayName: "Header2026style__DonateButtonTopBarWrapper",
67
+ componentId: "sc-1do20kd-4"
68
+ })(["display:flex;justify-content:center;a{", ";padding:8px;border-radius:8px;font-family:Montserrat;font-size:0.875rem;width:100%;height:inherit;transition:width 0.4s cubic-bezier(0.5,1.5,0.5,0.80);&:hover,&:focus{width:100%;box-shadow:0 5px 20px 0 rgba(0,0,0,0.05);", ";}@media ", "{padding:8px 12px;}@media ", "{font-size:1rem;padding:10px 16px;}}"], _animations.pulseOutAnimation, _animations.pulseInAnimation, _ref8 => {
69
+ let {
70
+ theme
71
+ } = _ref8;
72
+ return theme.breakpoints2026('S');
73
+ }, _ref9 => {
74
+ let {
75
+ theme
76
+ } = _ref9;
77
+ return theme.breakpoints2026('L');
78
+ });
79
+ const SearchIconWrapperDesktop = exports.SearchIconWrapperDesktop = _styledComponents.default.div.withConfig({
80
+ displayName: "Header2026style__SearchIconWrapperDesktop",
81
+ componentId: "sc-1do20kd-5"
82
+ })(["display:none;@media ", "{position:relative;display:flex;align-items:center;width:auto;margin-right:0px;right:0px;background-color:", ";img{margin-right:24px;width:18px;height:18px;transition:transform 0.2s ease;transform-origin:center;}a{overflow:visible;display:block;}&:hover img,&:focus-within img{transform:scale(1.33);}}"], _ref10 => {
83
+ let {
84
+ theme
85
+ } = _ref10;
86
+ return theme.breakpoints2026('L');
87
+ }, _ref11 => {
88
+ let {
89
+ theme
90
+ } = _ref11;
91
+ return theme.color('white');
92
+ });
93
+ const MobileBackHeader = exports.MobileBackHeader = _styledComponents.default.button.withConfig({
94
+ displayName: "Header2026style__MobileBackHeader",
95
+ componentId: "sc-1do20kd-6"
96
+ })(["display:flex;align-items:center;gap:12px;background:transparent;border:none;padding:0;cursor:pointer;font-family:Montserrat;font-size:16px;font-style:normal;font-weight:600;line-height:normal;color:", ";@media ", "{display:none;}"], _ref12 => {
97
+ let {
98
+ theme
99
+ } = _ref12;
100
+ return theme.color('black');
101
+ }, _ref13 => {
102
+ let {
103
+ theme
104
+ } = _ref13;
105
+ return theme.breakpoints2026('L');
106
+ });
107
+ const BackChevron = exports.BackChevron = _styledComponents.default.span.withConfig({
108
+ displayName: "Header2026style__BackChevron",
109
+ componentId: "sc-1do20kd-7"
110
+ })(["display:flex;align-items:center;justify-content:center;width:8px;transform:rotate(180deg);img{width:100%;height:auto;display:block;}"]);
111
+ const MobileMenuOverlay = exports.MobileMenuOverlay = _styledComponents.default.div.withConfig({
112
+ displayName: "Header2026style__MobileMenuOverlay",
113
+ componentId: "sc-1do20kd-8"
114
+ })(["display:", ";position:fixed;top:0;left:0;right:0;bottom:0;background-color:", ";z-index:1;@media ", "{display:none;}"], _ref14 => {
115
+ let {
116
+ isVisible
117
+ } = _ref14;
118
+ return isVisible ? 'block' : 'none';
119
+ }, _ref15 => {
120
+ let {
121
+ theme
122
+ } = _ref15;
123
+ return theme.color('grey_medium');
124
+ }, _ref16 => {
125
+ let {
126
+ theme
127
+ } = _ref16;
128
+ return theme.breakpoints2026('L');
129
+ });
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = void 0;
9
+ var _react = _interopRequireWildcard(require("react"));
10
+ var _Link = _interopRequireDefault(require("../../../Atoms/Link/Link"));
11
+ var _Text = _interopRequireDefault(require("../../../Atoms/Text/Text"));
12
+ var _BurgerMenu = _interopRequireDefault(require("../Burger/BurgerMenu"));
13
+ var _Icon = _interopRequireDefault(require("../../../Atoms/SocialIcons/Icon/Icon"));
14
+ var _breakpoints = require("../../../../theme/shared/breakpoints2026");
15
+ var _navHelper = require("../../../../utils/navHelper");
16
+ var _internalLinkHelper = require("../../../../utils/internalLinkHelper");
17
+ var _allowListed = _interopRequireDefault(require("../../../../utils/allowListed"));
18
+ var _PrimaryNavItem = _interopRequireDefault(require("./PrimaryNavItem"));
19
+ var _searchIcon = _interopRequireDefault(require("../assets/search-icon.svg"));
20
+ var _urlHelper = _interopRequireDefault(require("../../../../utils/urlHelper"));
21
+ var _Navs = require("./Navs.style");
22
+ const Navs = _ref => {
23
+ let {
24
+ navItems = {},
25
+ characterLimit,
26
+ isMenuOpen,
27
+ setIsMenuOpen,
28
+ devMode = false,
29
+ onSubMenuChange = () => {},
30
+ onTertiaryMenuChange = () => {}
31
+ } = _ref;
32
+ const {
33
+ headerPageGroups
34
+ } = navItems;
35
+ const [openedSubMenu, setOpenedSubMenu] = (0, _react.useState)({});
36
+ const [isNotDesktop, setIsNotDesktop] = (0, _react.useState)(() => {
37
+ if (typeof window !== 'undefined') {
38
+ return window.innerWidth < _breakpoints.breakpointValues2026.L;
39
+ }
40
+ return false;
41
+ });
42
+ const [processedItems, setProcessedItems] = (0, _react.useState)(null);
43
+ const [isTertiaryOpen, setIsTertiaryOpen] = (0, _react.useState)(false);
44
+ let theseGroups = null;
45
+
46
+ // Check if any submenu is currently open
47
+ const isSubMenuOpen = Object.values(openedSubMenu).some(v => v);
48
+
49
+ // Close all submenus (used by back button in header)
50
+ const closeSubMenus = (0, _react.useCallback)(() => {
51
+ setOpenedSubMenu({});
52
+ }, []);
53
+
54
+ // Handle tertiary menu changes from PrimaryNavItem
55
+ const handleTertiaryMenuChange = (0, _react.useCallback)((isOpen, parentName, closeFunction) => {
56
+ setIsTertiaryOpen(isOpen);
57
+ onTertiaryMenuChange(isOpen && isNotDesktop, parentName, closeFunction);
58
+ }, [isNotDesktop, onTertiaryMenuChange]);
59
+
60
+ // Notify parent when submenu state changes, passing close function
61
+ (0, _react.useEffect)(() => {
62
+ onSubMenuChange(isSubMenuOpen && isNotDesktop, closeSubMenus);
63
+ }, [isSubMenuOpen, isNotDesktop, onSubMenuChange, closeSubMenus]);
64
+ const toggleBurgerMenu = e => {
65
+ e.preventDefault();
66
+ setIsMenuOpen(!isMenuOpen);
67
+
68
+ // If we've just closed the nav, collapse any open submenus and reset tertiary state:
69
+ if (isMenuOpen) {
70
+ setOpenedSubMenu({});
71
+ setIsTertiaryOpen(false);
72
+ onTertiaryMenuChange(false, null, null);
73
+ }
74
+ };
75
+
76
+ // Toggle the open/not-open value of the specific submenu passed
77
+ const toggleSubMenu = (e, item) => {
78
+ e.preventDefault();
79
+ setOpenedSubMenu({
80
+ [item]: !openedSubMenu[item]
81
+ });
82
+ };
83
+
84
+ // Called by eventHandler to reset the nav on a specific mouse interaction
85
+ const resetMoreNavMouse = () => {
86
+ // Remove active 'opened' state for any open More Nav submenus
87
+ setOpenedSubMenu({});
88
+ // And also remove the focus state so the 'focus-within' nav rules don't apply:
89
+ document.activeElement.blur();
90
+ };
91
+
92
+ // Process the nav items on initial mount:
93
+ (0, _react.useMemo)(() => {
94
+ if (!headerPageGroups) return;
95
+ // Divide up nav items accordingly
96
+ const theseItems = (0, _navHelper.MoreNavPreProcessNew)(headerPageGroups, characterLimit);
97
+ setProcessedItems(theseItems);
98
+ }, [headerPageGroups, characterLimit]);
99
+
100
+ // Custom function to let us update the nav dynamically:
101
+ const screenResizeNav = (0, _react.useCallback)(() => {
102
+ // Grab the current width:
103
+ const currentScreenWidth = typeof window !== 'undefined' ? window.innerWidth : null;
104
+
105
+ // Compare to our breakpoint:
106
+ const isCurrentlyNotDesktop = currentScreenWidth < _breakpoints.breakpointValues2026.L;
107
+
108
+ // Only if the screen size has *changed*, update the state:
109
+ if (currentScreenWidth !== null && isNotDesktop !== isCurrentlyNotDesktop) {
110
+ // listeners, BEFORE we update the flag that'd remove the elements from the DOM:
111
+ if (isCurrentlyNotDesktop && processedItems.moreNavGroups.length) {
112
+ document.getElementById('more-nav-ul').removeEventListener('mouseleave', resetMoreNavMouse);
113
+ }
114
+
115
+ // Update our desktop flag to prevent any further calls:
116
+ setIsNotDesktop(isCurrentlyNotDesktop);
117
+ }
118
+ }, [isNotDesktop, processedItems]);
119
+
120
+ // Hook into browser's own onresize event to call our custom wrapper function:
121
+ (0, _react.useEffect)(() => {
122
+ if (typeof window !== 'undefined') window.onresize = screenResizeNav;
123
+ }, [screenResizeNav]);
124
+
125
+ // Once we've processed the items, assign according to breakpoint; sub-desktop 'Nav'
126
+ // breakpoints use 'raw' unprocessed header page groups, Desktop ('Nav' breakpoint and up)
127
+ // uses the divided-up versions:
128
+ if (processedItems) theseGroups = isNotDesktop ? headerPageGroups : processedItems.standardGroups;
129
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_Navs.Navigation, {
130
+ "data-testid": "Nav",
131
+ "aria-label": "main-menu",
132
+ isMenuOpen: isMenuOpen,
133
+ role: "navigation",
134
+ id: "main-nav"
135
+ }, /*#__PURE__*/_react.default.createElement(_Text.default, {
136
+ id: "main-menu",
137
+ tag: "h2"
138
+ }, "Main navigation"), /*#__PURE__*/_react.default.createElement(_Navs.PrimaryMenuWrapper, {
139
+ "data-testid": "PrimaryMenuWrapper"
140
+ }, processedItems &&
141
+ /*#__PURE__*/
142
+ // First level of the navigation (ul tag): Parent
143
+ _react.default.createElement(_Navs.PrimaryMenu, {
144
+ "data-testid": "PrimaryMenu",
145
+ role: "menubar"
146
+ }, theseGroups.map((group, index) => {
147
+ /* Generate an ID from the primary page name */
148
+ const thisID = group.primaryPageName.toLowerCase().replace(/\s+/g, '-');
149
+ /* Determine which field represents our url path */
150
+ let thisUrl = (0, _navHelper.NavHelperPrimary)(group);
151
+ const relNoopener = !(0, _allowListed.default)(thisUrl) && 'noopener' || undefined;
152
+ /* Get all column links for submenu */
153
+ const columnLinks = (0, _navHelper.getColumnLinks)(group);
154
+ const hasSubMenu = columnLinks.length > 0;
155
+ const hasPopUp = hasSubMenu ? 'true' : null;
156
+ thisUrl = (0, _internalLinkHelper.InternalLinkHelper)(thisUrl);
157
+
158
+ // Renders the primary page as the parent; a button for the dropdown
159
+ // on mobile, a clickable LINK on desktop but hover to reveal the submenu:
160
+ return (
161
+ /*#__PURE__*/
162
+ // Secondary Menu is nested inside PrimaryNavItem
163
+ _react.default.createElement(_PrimaryNavItem.default, {
164
+ thisID: thisID,
165
+ key: group.id,
166
+ index: index,
167
+ hasSubMenu: hasSubMenu,
168
+ openedSubMenu: openedSubMenu,
169
+ toggleSubMenu: toggleSubMenu,
170
+ hasPopUp: hasPopUp,
171
+ isNotDesktop: isNotDesktop,
172
+ thisUrl: thisUrl,
173
+ group: group,
174
+ navHelperNew: _navHelper.NavHelperNew,
175
+ internalLinkHelper: _internalLinkHelper.InternalLinkHelper,
176
+ relNoopener: relNoopener,
177
+ devMode: devMode,
178
+ onTertiaryMenuChange: handleTertiaryMenuChange,
179
+ isTertiaryOpenGlobal: isTertiaryOpen,
180
+ isSubMenuOpenGlobal: isSubMenuOpen
181
+ })
182
+ );
183
+ }), !isSubMenuOpen && !isTertiaryOpen && /*#__PURE__*/_react.default.createElement(_Navs.SearchWrapperMobile, null, /*#__PURE__*/_react.default.createElement(_Navs.SearchLinkMobile, {
184
+ href: (0, _urlHelper.default)('/search', devMode)
185
+ }, "Search", /*#__PURE__*/_react.default.createElement(_Navs.SearchIconWrapperMobile, {
186
+ "data-testid": "SearchIconWrapperMobile"
187
+ }, /*#__PURE__*/_react.default.createElement(_Icon.default, {
188
+ icon: _searchIcon.default,
189
+ title: "Search",
190
+ target: "self",
191
+ role: "button",
192
+ href: (0, _urlHelper.default)('/search', devMode),
193
+ brand: "comicrelief",
194
+ tabIndex: "0",
195
+ id: "search",
196
+ isHeader: true
197
+ })))))), isMenuOpen && !isTertiaryOpen && /*#__PURE__*/_react.default.createElement(_Navs.DonateButtonMobileModalWrapper, {
198
+ "data-testid": "donate-button--mobile"
199
+ }, /*#__PURE__*/_react.default.createElement(_Link.default, {
200
+ color: "red",
201
+ type: "button",
202
+ href: "https://donation.comicrelief.com/"
203
+ }, "Donate"))), /*#__PURE__*/_react.default.createElement(_BurgerMenu.default, {
204
+ "data-testid": "BurgerMenu",
205
+ toggle: toggleBurgerMenu,
206
+ isMenuOpen: isMenuOpen
207
+ }));
208
+ };
209
+ var _default = exports.default = Navs;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.SearchWrapperMobile = exports.SearchLinkMobile = exports.SearchIconWrapperMobile = exports.PrimaryMenuWrapper = exports.PrimaryMenu = exports.Navigation = exports.DonateButtonMobileModalWrapper = void 0;
8
+ var _styledComponents = _interopRequireDefault(require("styled-components"));
9
+ var _Link = _interopRequireDefault(require("../../../Atoms/Link/Link"));
10
+ var _hideVisually = _interopRequireDefault(require("../../../../theme/shared/hideVisually"));
11
+ var _zIndex = _interopRequireDefault(require("../../../../theme/shared/zIndex"));
12
+ const Navigation = exports.Navigation = _styledComponents.default.nav.withConfig({
13
+ displayName: "Navsstyle__Navigation",
14
+ componentId: "sc-1hd9a50-0"
15
+ })(["display:", ";width:100%;position:absolute;top:75px;left:0;", ";@media ", "{", ";position:static;top:0;display:block;margin:0;width:100%;height:100%;box-shadow:none;}> h2{", ";}"], _ref => {
16
+ let {
17
+ isMenuOpen
18
+ } = _ref;
19
+ return isMenuOpen ? 'block' : 'none';
20
+ }, (0, _zIndex.default)('higher'), _ref2 => {
21
+ let {
22
+ theme
23
+ } = _ref2;
24
+ return theme.breakpoints2026('L');
25
+ }, (0, _zIndex.default)('medium'), _hideVisually.default);
26
+ const PrimaryMenuWrapper = exports.PrimaryMenuWrapper = _styledComponents.default.div.withConfig({
27
+ displayName: "Navsstyle__PrimaryMenuWrapper",
28
+ componentId: "sc-1hd9a50-1"
29
+ })(["background-color:", ";box-shadow:0 5px 20px 0 rgba(0,0,0,0.05);border-radius:16px;overflow:hidden;position:static;@media ", "{box-shadow:none;border-radius:0;height:100%;display:flex;justify-content:center;align-items:center;overflow:visible;}"], _ref3 => {
30
+ let {
31
+ theme
32
+ } = _ref3;
33
+ return theme.color('white');
34
+ }, _ref4 => {
35
+ let {
36
+ theme
37
+ } = _ref4;
38
+ return theme.breakpoints2026('L');
39
+ });
40
+ const PrimaryMenu = exports.PrimaryMenu = _styledComponents.default.ul.withConfig({
41
+ displayName: "Navsstyle__PrimaryMenu",
42
+ componentId: "sc-1hd9a50-2"
43
+ })(["background-color:transparent;list-style:none outside;padding:0;margin:0;width:100%;height:100%;position:relative border:1px solid green;@media ", "{position:static;display:flex;justify-content:center;align-items:center;gap:24px;width:100%;height:100%;background-color:", ";}"], _ref5 => {
44
+ let {
45
+ theme
46
+ } = _ref5;
47
+ return theme.breakpoints2026('L');
48
+ }, _ref6 => {
49
+ let {
50
+ theme
51
+ } = _ref6;
52
+ return theme.color('white');
53
+ });
54
+ const DonateButtonMobileModalWrapper = exports.DonateButtonMobileModalWrapper = _styledComponents.default.div.withConfig({
55
+ displayName: "Navsstyle__DonateButtonMobileModalWrapper",
56
+ componentId: "sc-1hd9a50-3"
57
+ })(["display:block;background-color:inherit;margin-top:48px;width:100%;a{box-sizing:border-box;display:block;text-align:center;border-radius:16px;width:100%;margin:0;font-family:Montserrat;height:auto;padding:18px 0;&:hover,&:focus{width:100%;box-shadow:0 5px 20px 0 rgba(0,0,0,0.05);}}@media ", "{display:none;}"], _ref7 => {
58
+ let {
59
+ theme
60
+ } = _ref7;
61
+ return theme.breakpoints2026('L');
62
+ });
63
+ const SearchWrapperMobile = exports.SearchWrapperMobile = _styledComponents.default.div.withConfig({
64
+ displayName: "Navsstyle__SearchWrapperMobile",
65
+ componentId: "sc-1hd9a50-4"
66
+ })(["display:block;width:100%;border-top:1px solid ", ";@media ", "{display:none;}"], _ref8 => {
67
+ let {
68
+ theme
69
+ } = _ref8;
70
+ return theme.color('grey_medium');
71
+ }, _ref9 => {
72
+ let {
73
+ theme
74
+ } = _ref9;
75
+ return theme.breakpoints2026('L');
76
+ });
77
+ const SearchLinkMobile = exports.SearchLinkMobile = (0, _styledComponents.default)(_Link.default).withConfig({
78
+ displayName: "Navsstyle__SearchLinkMobile",
79
+ componentId: "sc-1hd9a50-5"
80
+ })(["display:flex;align-items:center;justify-content:space-between;padding:25px;width:100%;text-decoration:none;font-family:Montserrat;font-weight:600;color:", ";transition:color 0.2s ease;outline-offset:-3px;&:hover,&:focus{color:", ";background-color:", ";}"], _ref10 => {
81
+ let {
82
+ theme
83
+ } = _ref10;
84
+ return theme.color('black');
85
+ }, _ref11 => {
86
+ let {
87
+ theme
88
+ } = _ref11;
89
+ return theme.color('red');
90
+ }, _ref12 => {
91
+ let {
92
+ theme
93
+ } = _ref12;
94
+ return theme.color('grey_extra_light');
95
+ });
96
+ const SearchIconWrapperMobile = exports.SearchIconWrapperMobile = _styledComponents.default.div.withConfig({
97
+ displayName: "Navsstyle__SearchIconWrapperMobile",
98
+ componentId: "sc-1hd9a50-6"
99
+ })(["overflow:visible;img{width:18px;height:18px;transition:transform 0.2s ease;transform-origin:center;}a{overflow:visible;display:block;}&:hover img,&:focus-within img{transform:scale(1.33);}@media ", "{display:none;}"], _ref13 => {
100
+ let {
101
+ theme
102
+ } = _ref13;
103
+ return theme.breakpoints2026('L');
104
+ });