Skip to content

Commit 59a3d43

Browse files
fix(component-header-footer): fix footer clashing classes with bootstrap JS
1 parent cff832a commit 59a3d43

File tree

3 files changed

+65
-34
lines changed

3 files changed

+65
-34
lines changed

packages/component-header-footer/src/footer/components/ColumnSection/index.js

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,32 @@ import React, { useState, useEffect, useRef } from "react";
99
*/
1010

1111
/**
12-
* @param {{ columnIndex: number, column: Column }} props
12+
* @param {{ columnIndex: number, column: Column, isOpen?: boolean, onToggle?: () => void }} props
1313
* @returns {JSX.Element}
1414
*/
1515

16-
const ColumnSection = ({ columnIndex, column: { title, links } }) => {
17-
const [show, setShow] = useState(false);
16+
const ColumnSection = ({
17+
columnIndex,
18+
column: { title, links },
19+
isOpen = false,
20+
onToggle,
21+
}) => {
22+
const [show, setShow] = useState(isOpen);
1823
const isWindowDefined = typeof window !== "undefined";
1924
const initialMatches = isWindowDefined ? window.innerWidth >= 1260 : false;
2025
const [isLgDesktop, setIsLgDesktop] = useState(initialMatches);
2126

2227
/** @type {React.RefObject<HTMLDivElement> | null} */
2328
const accordionBodyRef = useRef(null);
2429

30+
// Update local state when prop changes
31+
useEffect(() => {
32+
if (!isLgDesktop && onToggle) {
33+
handleAnimation(isOpen);
34+
}
35+
setShow(isOpen);
36+
}, [isOpen, isLgDesktop, onToggle]);
37+
2538
useEffect(() => {
2639
const mediaWatcher = window.matchMedia("screen and (min-width: 1260px)");
2740
const handleMediaChange = e => setIsLgDesktop(e.matches);
@@ -33,27 +46,27 @@ const ColumnSection = ({ columnIndex, column: { title, links } }) => {
3346

3447
const handleAnimation = showingContent => {
3548
const accordionBody = accordionBodyRef?.current;
36-
if (!accordionBody) return;
37-
accordionBody.classList.add("collapsing");
49+
if (!accordionBody || !accordionBody.animate) return;
50+
accordionBody.classList.add("footer-collapsing");
3851
const animation = accordionBody.animate(
3952
[
4053
{
4154
maxHeight: showingContent ? `${accordionBody.scrollHeight}px` : "0px",
4255
},
4356
],
4457
{
45-
duration: 350,
58+
duration: 250,
4659
easing: "ease-in-out",
4760
fill: "forwards",
4861
}
4962
);
5063

5164
animation.onfinish = () => {
52-
accordionBody.classList.remove("collapsing");
65+
accordionBody.classList.remove("footer-collapsing");
5366
if (showingContent) {
54-
accordionBody.classList.add("show");
67+
accordionBody.classList.add("footer-column-show");
5568
} else {
56-
accordionBody.classList.remove("show");
69+
accordionBody.classList.remove("footer-column-show");
5770
}
5871
};
5972
};
@@ -64,24 +77,29 @@ const ColumnSection = ({ columnIndex, column: { title, links } }) => {
6477
return;
6578
}
6679

67-
setShow(prev => {
68-
const showingContent = !prev;
69-
handleAnimation(showingContent);
70-
return showingContent;
71-
});
80+
if (onToggle) {
81+
onToggle();
82+
} else {
83+
// Fallback for backward compatibility
84+
setShow(prev => {
85+
const showingContent = !prev;
86+
handleAnimation(showingContent);
87+
return showingContent;
88+
});
89+
}
7290
};
7391

7492
return (
7593
<div className="col-xl flex-footer testname-column">
7694
<div className="card accordion-item desktop-disable-xl">
77-
<div className="accordion-header">
95+
<div className="footer-accordion-header">
7896
<div className="h5">
7997
{isLgDesktop ? (
8098
<p className="accordion-button">{title}</p>
8199
) : (
82100
<button
83101
id={`footlink-header-${columnIndex}`}
84-
className="accordion-button"
102+
className="footer-accordion-button"
85103
aria-expanded={show || isLgDesktop}
86104
aria-controls={`footlink-${columnIndex}`}
87105
onClick={handleToggle}
@@ -90,7 +108,7 @@ const ColumnSection = ({ columnIndex, column: { title, links } }) => {
90108
>
91109
{title}
92110
<FontAwesomeIcon
93-
className={show || isLgDesktop ? "open" : ""}
111+
className={show || isLgDesktop ? "column-open" : ""}
94112
icon={faChevronDown}
95113
/>
96114
</button>
@@ -99,7 +117,7 @@ const ColumnSection = ({ columnIndex, column: { title, links } }) => {
99117
</div>
100118
<div
101119
id={`footlink-${columnIndex}`}
102-
className="accordion-body"
120+
className="footer-accordion-body"
103121
role="region"
104122
ref={accordionBodyRef}
105123
>
@@ -131,6 +149,8 @@ ColumnSection.propTypes = {
131149
})
132150
),
133151
}),
152+
isOpen: PropTypes.bool,
153+
onToggle: PropTypes.func,
134154
};
135155

136156
export { ColumnSection };

packages/component-header-footer/src/footer/components/Contact/index.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// @ts-check
22
import PropTypes, { shape, arrayOf } from "prop-types";
3-
import React from "react";
3+
import React, { useState } from "react";
44

55
import { Button } from "../../../header/components/Button";
66
import { ColumnSection } from "../ColumnSection";
@@ -14,6 +14,9 @@ import { ColumnSection } from "../ColumnSection";
1414
const ContactComponent = ({
1515
contact: { title = "", contactLink = "", contributionLink = "", columns },
1616
}) => {
17+
const [openAccordionIndex, setOpenAccordionIndex] = useState(
18+
/** @type {number | null} */ (null)
19+
);
1720
return (
1821
<div className="wrapper" id="wrapper-footer-columns" data-testid="contact">
1922
<div className="container" id="footer-columns">
@@ -46,6 +49,12 @@ const ContactComponent = ({
4649
key={`footlink-${column.title}`}
4750
columnIndex={columnIndex}
4851
column={column}
52+
isOpen={openAccordionIndex === columnIndex}
53+
onToggle={() => {
54+
setOpenAccordionIndex(
55+
openAccordionIndex === columnIndex ? null : columnIndex
56+
);
57+
}}
4958
/>
5059
))}
5160
</>

packages/component-header-footer/src/footer/index.styles.js

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,15 @@ const StyledFooter = styled.footer`
2525
// Base Styles
2626
* {
2727
box-sizing: border-box;
28-
font-family: Arial, Helvetica, "Nimbus Sans L", "Liberation Sans", FreeSans,
29-
sans-serif;
28+
font-family:
29+
Arial, Helvetica, "Nimbus Sans L", "Liberation Sans", FreeSans, sans-serif;
3030
line-height: 1.5rem;
3131
3232
a:focus,
3333
button:focus {
3434
outline: none;
35-
box-shadow: 0 0 0 2px var(--color-base-white),
35+
box-shadow:
36+
0 0 0 2px var(--color-base-white),
3637
0 0 0 4px var(--color-base-grey-7) !important;
3738
-webkit-tap-highlight-color: transparent;
3839
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
@@ -201,29 +202,29 @@ const StyledFooter = styled.footer`
201202
202203
.flex-footer {
203204
.accordion-item,
204-
.accordion-header,
205-
.accordion-body {
205+
.footer-accordion-header,
206+
.footer-accordion-body {
206207
background: var(--color-divider-darker);
207208
color: var(--color-base-white);
208209
border: 0;
209210
}
210211
211-
.accordion-header {
212+
.footer-accordion-header {
212213
border-top: 1px solid var(--color-divider-lighter);
213214
padding-left: 0;
214215
215216
h5,
216217
.h5 {
217218
margin: 0;
218219
a,
219-
.accordion-button {
220+
.footer-accordion-button {
220221
${flexCenter}
221222
justify-content: space-between;
222223
}
223224
}
224225
225226
a,
226-
.accordion-button {
227+
.footer-accordion-button {
227228
color: var(--color-base-grey-2);
228229
padding: 1.5rem 0;
229230
text-decoration: none;
@@ -234,6 +235,7 @@ const StyledFooter = styled.footer`
234235
cursor: pointer;
235236
text-align: inherit;
236237
width: 100%;
238+
transition: background-color 0.15s ease;
237239
238240
&:hover {
239241
background: var(--color-divider-darker);
@@ -242,11 +244,11 @@ const StyledFooter = styled.footer`
242244
svg,
243245
fa-chevron-up {
244246
margin-left: 1rem;
245-
transition: 0.5s cubic-bezier(0.19, 1, 0.19, 1);
247+
transition: 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
246248
margin-left: 0.5rem;
247249
font-size: 1rem;
248250
249-
&.open {
251+
&.column-open {
250252
transform: rotate(180deg);
251253
}
252254
}
@@ -256,7 +258,7 @@ const StyledFooter = styled.footer`
256258
border-top: 0;
257259
padding: 0;
258260
a,
259-
.accordion-button {
261+
.footer-accordion-button {
260262
padding: 0;
261263
cursor: default;
262264
}
@@ -267,16 +269,16 @@ const StyledFooter = styled.footer`
267269
}
268270
}
269271
270-
.accordion-body {
272+
.footer-accordion-body {
271273
display: none;
272274
overflow: hidden;
273275
padding: 0 0 0 1.5rem;
274276
275-
&.collapsing {
277+
&.footer-collapsing {
276278
display: block;
277279
max-height: 0px;
278280
}
279-
&.show {
281+
&.footer-column-show {
280282
display: block;
281283
max-height: 1000px;
282284
}
@@ -310,7 +312,7 @@ const StyledFooter = styled.footer`
310312
.h5 {
311313
margin: 0 0 1.5rem 0;
312314
}
313-
.accordion-header:has(.h5, h5) {
315+
.footer-accordion-header:has(.h5, h5) {
314316
h5,
315317
.h5 {
316318
margin: 0 0 1.5rem 0;

0 commit comments

Comments
 (0)