gatsby-core-theme 44.4.41 → 44.4.42

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,17 @@
1
+ ## [44.4.42](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.4.41...v44.4.42) (2025-08-29)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * outside click ([8b88022](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/8b88022dafe14a4c7c7d3d8efe08207a76659724))
7
+ * test collapse ([a5dc747](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/a5dc7471eae5df4ab4b3eda3e91856a2e728476c))
8
+ * test coverage ([bbd1138](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/bbd1138c1c668e745923917ddc5b08c5d994f64d))
9
+ * test outside click ([c616f66](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/c616f66192927bc53366f5ede49827614dcdf847))
10
+ * voting ([2f2eb5c](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/2f2eb5c696d96c591af536a81f45bc7d4484e632))
11
+
12
+
13
+ * Merge branch 'collapse-outside-click' into 'master' ([ade0483](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/ade0483aef0a470638e1b3132e11c850db0662b2))
14
+
1
15
  ## [44.4.41](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.4.40...v44.4.41) (2025-08-28)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gatsby-core-theme",
3
- "version": "44.4.41",
3
+ "version": "44.4.42",
4
4
  "description": "Gatsby Theme NPM Package",
5
5
  "author": "",
6
6
  "license": "ISC",
@@ -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
- test('Render', () => {
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 buttonText="Open" contentText="Content Text" initOpen />
47
+ <Collapse
48
+ buttonText="Toggle"
49
+ contentText="Test Content"
50
+ initOpen
51
+ onlyMobile
52
+ />
12
53
  );
13
54
 
14
- const button = container.querySelector('button');
15
- const content = container.querySelector('div.content');
55
+ const contentDiv = container.querySelector('div[style]');
56
+ expect(contentDiv).toBeInTheDocument();
16
57
 
17
- expect(button.innerHTML).toBe('Open');
18
- expect(content.innerHTML).toBe('Content Text');
58
+ await waitFor(() => {
59
+ expect(contentDiv.style.maxHeight).toBe(`${scrollHeightMock}px`);
60
+ });
19
61
  });
20
62
 
21
- test('Open collapse', () => {
22
- const { container } = render(<Collapse buttonText="Open" contentText="Content Text" />);
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
- // jest does not render the component, hence testing the actual layout cannot be done due to the collapse using scrollHeight.
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('Open collapse with different initial height', () => {
31
- const { container } = render(
32
- <Collapse buttonText="Open" maxHeight={20} contentText="Content Text" />
33
- );
85
+ test('renders correctly with onlyMobile and onlyDesktop props', () => {
86
+ const { getByText } = setup({ onlyMobile: true });
87
+ expect(getByText('Toggle')).toBeInTheDocument();
34
88
 
35
- const button = container.querySelector('button');
36
- fireEvent.click(button);
37
- expect(button.classList.contains('active')).toBeFalsy();
89
+ cleanup();
90
+
91
+ const { getByText: getByText2 } = setup({ onlyDesktop: true });
92
+ expect(getByText2('Toggle')).toBeInTheDocument();
38
93
  });
39
94
 
40
- test('Only Mobile', () => {
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
- <Collapse buttonText="Open" contentText="Content Text" onlyMobile />
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
- expect(container.querySelector('button')).toBeTruthy();
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 className={styles?.collapseContainer || ''}>
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] === 'vote_down' && styles.disabled || ''}`}
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' ? 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] === 'vote_up' && styles.disabled || ''}`}
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' ? dislikes+1 : dislikes}</span>
118
118
  </button>
119
119
  </>
120
120
  )}