gatsby-core-theme 44.4.41 → 44.4.43
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/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
## [44.4.43](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.4.42...v44.4.43) (2025-08-29)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* voting ([2c38c8f](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/2c38c8ff3e2ee8b9aadeceb2e2318b47359d11b5))
|
|
7
|
+
|
|
8
|
+
## [44.4.42](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.4.41...v44.4.42) (2025-08-29)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* outside click ([8b88022](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/8b88022dafe14a4c7c7d3d8efe08207a76659724))
|
|
14
|
+
* test collapse ([a5dc747](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/a5dc7471eae5df4ab4b3eda3e91856a2e728476c))
|
|
15
|
+
* test coverage ([bbd1138](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/bbd1138c1c668e745923917ddc5b08c5d994f64d))
|
|
16
|
+
* test outside click ([c616f66](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/c616f66192927bc53366f5ede49827614dcdf847))
|
|
17
|
+
* voting ([2f2eb5c](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/2f2eb5c696d96c591af536a81f45bc7d4484e632))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
* Merge branch 'collapse-outside-click' into 'master' ([ade0483](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/ade0483aef0a470638e1b3132e11c850db0662b2))
|
|
21
|
+
|
|
1
22
|
## [44.4.41](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.4.40...v44.4.41) (2025-08-28)
|
|
2
23
|
|
|
3
24
|
|
package/package.json
CHANGED
|
@@ -1,50 +1,137 @@
|
|
|
1
1
|
/* eslint-disable no-underscore-dangle */
|
|
2
|
-
|
|
3
2
|
import React from 'react';
|
|
4
|
-
import { render, cleanup, fireEvent } from '@testing-library/react';
|
|
3
|
+
import { render, cleanup, fireEvent, waitFor } from '@testing-library/react';
|
|
5
4
|
import '@testing-library/jest-dom/extend-expect';
|
|
6
5
|
import Collapse from '.';
|
|
7
6
|
|
|
8
7
|
describe('Collapse Component', () => {
|
|
9
|
-
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
cleanup();
|
|
10
|
+
jest.restoreAllMocks();
|
|
11
|
+
delete HTMLElement.prototype.scrollHeight;
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const setup = (props = {}) =>
|
|
15
|
+
render(
|
|
16
|
+
<Collapse
|
|
17
|
+
buttonText="Toggle"
|
|
18
|
+
contentText="Test Content"
|
|
19
|
+
{...props}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
test('renders with button and string content', () => {
|
|
24
|
+
const { getByText } = setup();
|
|
25
|
+
expect(getByText('Toggle')).toBeInTheDocument();
|
|
26
|
+
expect(getByText('Test Content')).toBeInTheDocument();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('renders with React element as contentText', () => {
|
|
30
|
+
const { getByText } = render(
|
|
31
|
+
<Collapse
|
|
32
|
+
buttonText="Toggle"
|
|
33
|
+
contentText={<p>JSX Content</p>}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
expect(getByText('JSX Content')).toBeInTheDocument();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('opens when initOpen is true', async () => {
|
|
40
|
+
const scrollHeightMock = 200;
|
|
41
|
+
Object.defineProperty(HTMLElement.prototype, 'scrollHeight', {
|
|
42
|
+
configurable: true,
|
|
43
|
+
get: () => scrollHeightMock,
|
|
44
|
+
});
|
|
45
|
+
|
|
10
46
|
const { container } = render(
|
|
11
|
-
<Collapse
|
|
47
|
+
<Collapse
|
|
48
|
+
buttonText="Toggle"
|
|
49
|
+
contentText="Test Content"
|
|
50
|
+
initOpen
|
|
51
|
+
onlyMobile
|
|
52
|
+
/>
|
|
12
53
|
);
|
|
13
54
|
|
|
14
|
-
const
|
|
15
|
-
|
|
55
|
+
const contentDiv = container.querySelector('div[style]');
|
|
56
|
+
expect(contentDiv).toBeInTheDocument();
|
|
16
57
|
|
|
17
|
-
|
|
18
|
-
|
|
58
|
+
await waitFor(() => {
|
|
59
|
+
expect(contentDiv.style.maxHeight).toBe(`${scrollHeightMock}px`);
|
|
60
|
+
});
|
|
19
61
|
});
|
|
20
62
|
|
|
21
|
-
test('
|
|
22
|
-
const
|
|
63
|
+
test('toggles open/close on click', () => {
|
|
64
|
+
const scrollHeightMock = 300;
|
|
65
|
+
|
|
66
|
+
Object.defineProperty(HTMLElement.prototype, 'scrollHeight', {
|
|
67
|
+
configurable: true,
|
|
68
|
+
get: () => scrollHeightMock,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const { container, getByText } = setup({ onlyMobile: true });
|
|
72
|
+
|
|
73
|
+
const contentDiv = container.querySelector('div[style]');
|
|
74
|
+
expect(contentDiv).not.toBeNull();
|
|
75
|
+
|
|
76
|
+
const button = getByText('Toggle');
|
|
23
77
|
|
|
24
|
-
const button = container.querySelector('button');
|
|
25
|
-
expect(button.classList.contains('active')).toBeFalsy();
|
|
26
78
|
fireEvent.click(button);
|
|
27
|
-
|
|
79
|
+
expect(contentDiv.style.maxHeight).toBe(`${scrollHeightMock}px`);
|
|
80
|
+
|
|
81
|
+
fireEvent.click(button);
|
|
82
|
+
expect(['0', '0px']).toContain(contentDiv.style.maxHeight);
|
|
28
83
|
});
|
|
29
84
|
|
|
30
|
-
test('
|
|
31
|
-
const {
|
|
32
|
-
|
|
33
|
-
);
|
|
85
|
+
test('renders correctly with onlyMobile and onlyDesktop props', () => {
|
|
86
|
+
const { getByText } = setup({ onlyMobile: true });
|
|
87
|
+
expect(getByText('Toggle')).toBeInTheDocument();
|
|
34
88
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
89
|
+
cleanup();
|
|
90
|
+
|
|
91
|
+
const { getByText: getByText2 } = setup({ onlyDesktop: true });
|
|
92
|
+
expect(getByText2('Toggle')).toBeInTheDocument();
|
|
38
93
|
});
|
|
39
94
|
|
|
40
|
-
test('
|
|
95
|
+
test('closes on outside click when closeOnOutsideClick is true', async () => {
|
|
96
|
+
const scrollHeightMock = 100;
|
|
97
|
+
|
|
98
|
+
Object.defineProperty(HTMLElement.prototype, 'scrollHeight', {
|
|
99
|
+
configurable: true,
|
|
100
|
+
get: () => scrollHeightMock,
|
|
101
|
+
});
|
|
102
|
+
|
|
41
103
|
const { container } = render(
|
|
42
|
-
<
|
|
104
|
+
<div>
|
|
105
|
+
<Collapse
|
|
106
|
+
buttonText="Toggle"
|
|
107
|
+
contentText="Test Content"
|
|
108
|
+
initOpen
|
|
109
|
+
closeOnOutsideClick
|
|
110
|
+
onlyMobile
|
|
111
|
+
/>
|
|
112
|
+
<div data-testid="outside">Outside</div>
|
|
113
|
+
</div>
|
|
43
114
|
);
|
|
44
115
|
|
|
45
|
-
|
|
116
|
+
const contentDiv = container.querySelector('div[style]');
|
|
117
|
+
expect(contentDiv).not.toBeNull();
|
|
118
|
+
expect(contentDiv.style.maxHeight).toBe(`${scrollHeightMock}px`);
|
|
119
|
+
|
|
120
|
+
const outside = container.querySelector('[data-testid="outside"]');
|
|
121
|
+
fireEvent.mouseDown(outside);
|
|
122
|
+
|
|
123
|
+
await waitFor(() => {
|
|
124
|
+
expect(['0', '0px']).toContain(contentDiv.style.maxHeight);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('does not apply maxHeight when onlyMobile and onlyDesktop are false', () => {
|
|
129
|
+
const { container } = setup({ initOpen: true });
|
|
130
|
+
|
|
131
|
+
const divs = container.querySelectorAll('div');
|
|
132
|
+
const contentDiv = Array.from(divs).find(div =>
|
|
133
|
+
div.innerHTML.includes('Test Content')
|
|
134
|
+
);
|
|
135
|
+
expect(contentDiv.style.maxHeight).toBe('');
|
|
46
136
|
});
|
|
47
|
-
});
|
|
48
|
-
afterEach(() => {
|
|
49
|
-
cleanup();
|
|
50
137
|
});
|
|
@@ -10,9 +10,11 @@ const Collapse = ({
|
|
|
10
10
|
onlyDesktop = false,
|
|
11
11
|
initOpen = false,
|
|
12
12
|
maxHeight = 0,
|
|
13
|
+
closeOnOutsideClick = false,
|
|
13
14
|
}) => {
|
|
14
15
|
const [maxHeightStyle, setMaxHeightStyle] = useState(maxHeight);
|
|
15
16
|
const contentRef = useRef(React.createRef());
|
|
17
|
+
const containerRef = useRef(null);
|
|
16
18
|
|
|
17
19
|
useEffect(() => {
|
|
18
20
|
if (initOpen) {
|
|
@@ -20,6 +22,22 @@ const Collapse = ({
|
|
|
20
22
|
}
|
|
21
23
|
}, [initOpen]);
|
|
22
24
|
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (!closeOnOutsideClick || maxHeightStyle === 0) return;
|
|
28
|
+
|
|
29
|
+
const handleClickOutside = (event) => {
|
|
30
|
+
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
31
|
+
setMaxHeightStyle(0);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
36
|
+
return () => {
|
|
37
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
38
|
+
};
|
|
39
|
+
}, [closeOnOutsideClick, maxHeightStyle]);
|
|
40
|
+
|
|
23
41
|
const clickHandler = () => {
|
|
24
42
|
if (maxHeightStyle === 0) {
|
|
25
43
|
setMaxHeightStyle(contentRef.current.scrollHeight);
|
|
@@ -29,7 +47,10 @@ const Collapse = ({
|
|
|
29
47
|
};
|
|
30
48
|
|
|
31
49
|
return (
|
|
32
|
-
<div
|
|
50
|
+
<div
|
|
51
|
+
ref={containerRef}
|
|
52
|
+
className={styles?.collapseContainer || ''}
|
|
53
|
+
>
|
|
33
54
|
<div className={maxHeightStyle !== 0 ? styles?.active || '' : ''}>
|
|
34
55
|
<button
|
|
35
56
|
type="button"
|
|
@@ -74,6 +95,7 @@ Collapse.propTypes = {
|
|
|
74
95
|
onlyDesktop: PropTypes.bool,
|
|
75
96
|
initOpen: PropTypes.bool,
|
|
76
97
|
maxHeight: PropTypes.number,
|
|
98
|
+
closeOnOutsideClick: PropTypes.bool,
|
|
77
99
|
};
|
|
78
100
|
|
|
79
101
|
export default Collapse;
|
|
@@ -97,11 +97,11 @@ const Comment = ({
|
|
|
97
97
|
}}
|
|
98
98
|
aria-label='Like Button'
|
|
99
99
|
type='button'
|
|
100
|
-
className={`${styles.buttonGroup} ${styles.left} ${currentUserInteractions.current?.find(v => v.startsWith(`${comment.comment_id}:`))?.split(': ')[1] === '
|
|
100
|
+
className={`${styles.buttonGroup} ${styles.left} ${currentUserInteractions.current?.find(v => v.startsWith(`${comment.comment_id}:`))?.split(': ')[1] === 'vote_up' && styles.disabled || ''}`}
|
|
101
101
|
disabled={currentUserInteractions.current?.find(v => v.startsWith(`${comment.comment_id}:`))}
|
|
102
102
|
>
|
|
103
103
|
<LazyImage className={styles.buttonGroupIcon} src='/images/like.svg' />
|
|
104
|
-
<span>{likes}</span>
|
|
104
|
+
<span>{currentUserInteractions.current?.find(v => v.startsWith(`${comment.comment_id}:`))?.split(': ')[1] === 'vote_down' ? setLikes(likes+1) : likes}</span>
|
|
105
105
|
</button>
|
|
106
106
|
<button
|
|
107
107
|
onClick={async () => {
|
|
@@ -110,11 +110,11 @@ const Comment = ({
|
|
|
110
110
|
}}
|
|
111
111
|
aria-label='Dislike Button'
|
|
112
112
|
type='button'
|
|
113
|
-
className={`${styles.buttonGroup} ${styles.right} ${currentUserInteractions.current?.find(v => v.startsWith(`${comment.comment_id}:`))?.split(': ')[1] === '
|
|
113
|
+
className={`${styles.buttonGroup} ${styles.right} ${currentUserInteractions.current?.find(v => v.startsWith(`${comment.comment_id}:`))?.split(': ')[1] === 'vote_down' && styles.disabled || ''}`}
|
|
114
114
|
disabled={currentUserInteractions.current?.find(v => v.startsWith(`${comment.comment_id}:`))}
|
|
115
115
|
>
|
|
116
116
|
<LazyImage className={styles.buttonGroupIcon} src='/images/dislike.svg' />
|
|
117
|
-
<span>{dislikes}</span>
|
|
117
|
+
<span>{currentUserInteractions.current?.find(v => v.startsWith(`${comment.comment_id}:`))?.split(': ')[1] === 'vote_down' ? setDislikes(dislikes+1) : dislikes}</span>
|
|
118
118
|
</button>
|
|
119
119
|
</>
|
|
120
120
|
)}
|