@eeacms/volto-eea-design-system 1.40.1 → 1.40.2
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 +7 -0
- package/package.json +1 -1
- package/src/ui/Header/utils.js +15 -2
- package/src/ui/Header/utils.test.js +110 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
### [1.40.2](https://github.com/eea/volto-eea-design-system/compare/1.40.1...1.40.2) - 8 December 2025
|
|
8
|
+
|
|
9
|
+
#### :hammer_and_wrench: Others
|
|
10
|
+
|
|
11
|
+
- fix tests [Teodor - [`4b3db9b`](https://github.com/eea/volto-eea-design-system/commit/4b3db9b63230fcb43626eebddfed78007b24b464)]
|
|
12
|
+
- Add comprehensive tests for megamenu fix utilities [copilot-swe-agent[bot] - [`d4e1af8`](https://github.com/eea/volto-eea-design-system/commit/d4e1af8f3a8da40c64ccc122355ba90e19320288)]
|
|
13
|
+
- Initial plan [copilot-swe-agent[bot] - [`5e90591`](https://github.com/eea/volto-eea-design-system/commit/5e90591503dcff8af4d39298ac2c0e98b94ff2c0)]
|
|
7
14
|
### [1.40.1](https://github.com/eea/volto-eea-design-system/compare/1.40.0...1.40.1) - 4 December 2025
|
|
8
15
|
|
|
9
16
|
#### :bug: Bug Fixes
|
package/package.json
CHANGED
package/src/ui/Header/utils.js
CHANGED
|
@@ -73,8 +73,21 @@ export const numberToColumnString = (num) => {
|
|
|
73
73
|
|
|
74
74
|
export const numbersToMenuItemColumns = (numbers) => {
|
|
75
75
|
// Handle both single number and array of numbers for column dimensions
|
|
76
|
-
|
|
76
|
+
// Also handle pre-formatted strings (e.g., 'at-a-glance three wide column')
|
|
77
|
+
if (!Array.isArray(numbers)) {
|
|
78
|
+
// If it's already a string containing 'wide column', return it as-is
|
|
79
|
+
if (typeof numbers === 'string' && numbers.includes('wide column')) {
|
|
80
|
+
return numbers;
|
|
81
|
+
}
|
|
82
|
+
return numberToColumnString(numbers);
|
|
83
|
+
}
|
|
77
84
|
return numbers
|
|
78
|
-
.map((num) =>
|
|
85
|
+
.map((num) => {
|
|
86
|
+
// If array element is already a formatted string, return it as-is
|
|
87
|
+
if (typeof num === 'string' && num.includes('wide column')) {
|
|
88
|
+
return num;
|
|
89
|
+
}
|
|
90
|
+
return numberToColumnString(parseInt(num));
|
|
91
|
+
})
|
|
79
92
|
.filter((col) => col !== '');
|
|
80
93
|
};
|
|
@@ -98,6 +98,75 @@ describe('Header utils', () => {
|
|
|
98
98
|
expect(result3.bestMatchUrl).toBe(null);
|
|
99
99
|
expect(result3.bestScore).toBe(-1);
|
|
100
100
|
});
|
|
101
|
+
|
|
102
|
+
test('handles trailing slashes in URLs correctly', () => {
|
|
103
|
+
const menuItems = [
|
|
104
|
+
{ url: '/topics/', items: [] },
|
|
105
|
+
{ url: '/topics/climate/', items: [] },
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
// Active item with trailing slash should match menu item without
|
|
109
|
+
const result1 = findBestMatchingMenuItem(menuItems, '/topics/');
|
|
110
|
+
expect(result1.bestMatchUrl).toBe('/topics');
|
|
111
|
+
|
|
112
|
+
// Active item without trailing slash should match menu item with
|
|
113
|
+
const result2 = findBestMatchingMenuItem(menuItems, '/topics/climate');
|
|
114
|
+
expect(result2.bestMatchUrl).toBe('/topics/climate');
|
|
115
|
+
|
|
116
|
+
// Exact match with both having trailing slashes
|
|
117
|
+
const result3 = findBestMatchingMenuItem(menuItems, '/topics/climate/');
|
|
118
|
+
expect(result3.bestMatchUrl).toBe('/topics/climate');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('handles multiple trailing slashes', () => {
|
|
122
|
+
const menuItems = [{ url: '/topics///', items: [] }];
|
|
123
|
+
|
|
124
|
+
const result = findBestMatchingMenuItem(menuItems, '/topics');
|
|
125
|
+
expect(result.bestMatchUrl).toBe('/topics');
|
|
126
|
+
expect(result.bestScore).toBe('/topics'.length + 1);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('prevents sibling collision with similar URLs', () => {
|
|
130
|
+
// This is the key test for the megamenu fix
|
|
131
|
+
const menuItems = [
|
|
132
|
+
{ url: '/topics', items: [] },
|
|
133
|
+
{ url: '/topics-archive', items: [] },
|
|
134
|
+
{ url: '/topics/climate', items: [] },
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
// Should match /topics/climate (most specific parent), not /topics-archive
|
|
138
|
+
const result1 = findBestMatchingMenuItem(
|
|
139
|
+
menuItems,
|
|
140
|
+
'/topics/climate/overview',
|
|
141
|
+
);
|
|
142
|
+
expect(result1.bestMatchUrl).toBe('/topics/climate');
|
|
143
|
+
|
|
144
|
+
// Should match /topics-archive exactly, not /topics
|
|
145
|
+
const result2 = findBestMatchingMenuItem(menuItems, '/topics-archive');
|
|
146
|
+
expect(result2.bestMatchUrl).toBe('/topics-archive');
|
|
147
|
+
|
|
148
|
+
// Should match /topics-archive when on /topics-archive/page (parent-child relationship)
|
|
149
|
+
const result3 = findBestMatchingMenuItem(
|
|
150
|
+
menuItems,
|
|
151
|
+
'/topics-archive/page',
|
|
152
|
+
);
|
|
153
|
+
expect(result3.bestMatchUrl).toBe('/topics-archive');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('root path ("/") handling', () => {
|
|
157
|
+
const menuItems = [
|
|
158
|
+
{ url: '/', items: [] },
|
|
159
|
+
{ url: '/topics', items: [] },
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
const result1 = findBestMatchingMenuItem(menuItems, '/');
|
|
163
|
+
expect(result1.bestMatchUrl).toBe('/');
|
|
164
|
+
|
|
165
|
+
// Root should not match other paths
|
|
166
|
+
const result2 = findBestMatchingMenuItem(menuItems, '/topics');
|
|
167
|
+
expect(result2.bestMatchUrl).toBe('/topics');
|
|
168
|
+
expect(result2.bestScore).toBe('/topics'.length + 1);
|
|
169
|
+
});
|
|
101
170
|
});
|
|
102
171
|
|
|
103
172
|
describe('isMenuItemActive', () => {
|
|
@@ -214,5 +283,46 @@ describe('Header utils', () => {
|
|
|
214
283
|
const result = numbersToMenuItemColumns([0, 10, -1, 100]);
|
|
215
284
|
expect(result).toEqual([]);
|
|
216
285
|
});
|
|
286
|
+
|
|
287
|
+
test('handles single number input (non-array)', () => {
|
|
288
|
+
expect(numbersToMenuItemColumns(3)).toBe('three wide column');
|
|
289
|
+
expect(numbersToMenuItemColumns(5)).toBe('five wide column');
|
|
290
|
+
expect(numbersToMenuItemColumns(0)).toBe('');
|
|
291
|
+
expect(numbersToMenuItemColumns(10)).toBe('');
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
test('handles pre-formatted string input', () => {
|
|
295
|
+
const result = numbersToMenuItemColumns('at-a-glance three wide column');
|
|
296
|
+
expect(result).toBe('at-a-glance three wide column');
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
test('handles array with pre-formatted strings', () => {
|
|
300
|
+
const result = numbersToMenuItemColumns([
|
|
301
|
+
'custom one wide column',
|
|
302
|
+
2,
|
|
303
|
+
'another three wide column',
|
|
304
|
+
]);
|
|
305
|
+
expect(result).toEqual([
|
|
306
|
+
'custom one wide column',
|
|
307
|
+
'two wide column',
|
|
308
|
+
'another three wide column',
|
|
309
|
+
]);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
test('handles mixed array with numbers, strings, and pre-formatted strings', () => {
|
|
313
|
+
const result = numbersToMenuItemColumns([
|
|
314
|
+
1,
|
|
315
|
+
'special four wide column',
|
|
316
|
+
'3',
|
|
317
|
+
0,
|
|
318
|
+
'another five wide column',
|
|
319
|
+
]);
|
|
320
|
+
expect(result).toEqual([
|
|
321
|
+
'one wide column',
|
|
322
|
+
'special four wide column',
|
|
323
|
+
'three wide column',
|
|
324
|
+
'another five wide column',
|
|
325
|
+
]);
|
|
326
|
+
});
|
|
217
327
|
});
|
|
218
328
|
});
|