fix: storybook font rendering and shared fonts module #1
@@ -0,0 +1,54 @@
|
|||||||
|
import { groupByKey } from './groupByKey';
|
||||||
|
|
||||||
|
describe('groupByKey', () => {
|
||||||
|
describe('basic grouping', () => {
|
||||||
|
it('groups items by a string key', () => {
|
||||||
|
const items = [
|
||||||
|
{ category: 'Frontend', name: 'React' },
|
||||||
|
{ category: 'Backend', name: 'Node' },
|
||||||
|
{ category: 'Frontend', name: 'Vue' },
|
||||||
|
];
|
||||||
|
expect(groupByKey(items, 'category')).toEqual({
|
||||||
|
Frontend: [
|
||||||
|
{ category: 'Frontend', name: 'React' },
|
||||||
|
{ category: 'Frontend', name: 'Vue' },
|
||||||
|
],
|
||||||
|
Backend: [{ category: 'Backend', name: 'Node' }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('preserves insertion order within each group', () => {
|
||||||
|
const items = [
|
||||||
|
{ category: 'A', order: 1 },
|
||||||
|
{ category: 'A', order: 2 },
|
||||||
|
];
|
||||||
|
expect(groupByKey(items, 'category')['A']).toEqual([
|
||||||
|
{ category: 'A', order: 1 },
|
||||||
|
{ category: 'A', order: 2 },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('edge cases', () => {
|
||||||
|
it('returns empty object for empty array', () => {
|
||||||
|
expect(groupByKey<{ category: string }>([], 'category')).toEqual({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles all items in same group', () => {
|
||||||
|
const items = [
|
||||||
|
{ type: 'X', id: 1 },
|
||||||
|
{ type: 'X', id: 2 },
|
||||||
|
];
|
||||||
|
const result = groupByKey(items, 'type');
|
||||||
|
expect(Object.keys(result)).toHaveLength(1);
|
||||||
|
expect(result['X']).toHaveLength(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles single item', () => {
|
||||||
|
const items = [{ category: 'Only', name: 'One' }];
|
||||||
|
expect(groupByKey(items, 'category')).toEqual({
|
||||||
|
Only: [{ category: 'Only', name: 'One' }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Groups an array of objects by a shared key into a record of arrays.
|
||||||
|
* @param items - Array of objects to group
|
||||||
|
* @param key - Key whose value determines the group
|
||||||
|
* @returns Record mapping each unique key value to an array of matching items
|
||||||
|
*/
|
||||||
|
export function groupByKey<T>(items: T[], key: keyof T): Record<string, T[]> {
|
||||||
|
return items.reduce(
|
||||||
|
(acc, item) => {
|
||||||
|
const k = String(item[key]);
|
||||||
|
if (!acc[k]) {
|
||||||
|
acc[k] = [];
|
||||||
|
}
|
||||||
|
acc[k].push(item);
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{} as Record<string, T[]>,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -2,3 +2,4 @@ export type { ClassValue } from 'clsx';
|
|||||||
export { cn } from './cn';
|
export { cn } from './cn';
|
||||||
export * from './fonts';
|
export * from './fonts';
|
||||||
export * from './formatDate';
|
export * from './formatDate';
|
||||||
|
export { groupByKey } from './groupByKey';
|
||||||
|
|||||||
Reference in New Issue
Block a user