Skip to content

Commit cf13d72

Browse files
authored
DataList component (#1047)
1 parent 3abb78a commit cf13d72

File tree

11 files changed

+260
-3
lines changed

11 files changed

+260
-3
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import DataListRoot from './fragments/DataListRoot';
2+
import DataListItem from './fragments/DataListItem';
3+
import DataListLabel from './fragments/DataListLabel';
4+
import DataListValue from './fragments/DataListValue';
5+
6+
const DataList = () => {
7+
console.warn('Direct usage of DataList is not supported. Please use DataList.Root, DataList.Item, etc. instead.');
8+
return null;
9+
};
10+
11+
export default DataList;
12+
13+
DataList.Root = DataListRoot;
14+
DataList.Item = DataListItem;
15+
DataList.Label = DataListLabel;
16+
DataList.Value = DataListValue;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { createContext } from 'react';
2+
3+
interface DataListContextType {
4+
rootClass?: string;
5+
}
6+
7+
const DataListContext = createContext<DataListContextType>({
8+
rootClass: 'DataList'
9+
});
10+
11+
export default DataListContext;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React, { useContext } from 'react';
2+
import DataListContext from '../contexts/DataListContex';
3+
import { clsx } from 'clsx';
4+
5+
const DataListItem = ({ children, className = '', ...props }: { children: React.ReactNode, className?: string }) => {
6+
const { rootClass } = useContext(DataListContext);
7+
return <div className={clsx(`${rootClass}-item`, className)} {...props}>{children}</div>;
8+
};
9+
10+
export default DataListItem;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React, { useContext } from 'react';
2+
import DataListContext from '../contexts/DataListContex';
3+
import { clsx } from 'clsx';
4+
5+
const DataListLabel = ({ children, className = '', ...props }: { children: React.ReactNode, className?: string }) => {
6+
const { rootClass } = useContext(DataListContext);
7+
return <dt className={clsx(`${rootClass}-label`, className)} {...props}>{children}</dt>;
8+
};
9+
10+
export default DataListLabel;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from 'react';
2+
import DataListContext from '../contexts/DataListContex';
3+
import { customClassSwitcher } from '~/core';
4+
import { clsx } from 'clsx';
5+
6+
const COMPONENT_NAME = 'DataList';
7+
8+
const DataListRoot = ({ children, className = '', customRootClass = '', ...props }: { children: React.ReactNode, className?: string, customRootClass?: string }) => {
9+
const rootClass = customClassSwitcher(customRootClass, COMPONENT_NAME);
10+
return <DataListContext.Provider
11+
value={{
12+
rootClass
13+
}}>
14+
<div className={clsx(rootClass, className)} {...props}>{children}</div>
15+
</DataListContext.Provider>;
16+
};
17+
18+
export default DataListRoot;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React, { useContext } from 'react';
2+
import DataListContext from '../contexts/DataListContex';
3+
import { clsx } from 'clsx';
4+
5+
const DataListValue = ({ children, className = '', ...props }: { children: React.ReactNode, className?: string }) => {
6+
const { rootClass } = useContext(DataListContext);
7+
return <dd className={clsx(`${rootClass}-value`, className)} {...props}>{children}</dd>;
8+
};
9+
10+
export default DataListValue;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Meta } from '@storybook/react';
2+
import React, { useState } from 'react';
3+
import SandboxEditor from '~/components/tools/SandboxEditor/SandboxEditor';
4+
import DataList from '../DataList';
5+
import Badge from '~/components/ui/Badge/Badge';
6+
7+
const meta: Meta<typeof DataList> = {
8+
component: DataList,
9+
title: 'WIP/DataList'
10+
};
11+
12+
export default meta;
13+
14+
export const Default = () => {
15+
return (
16+
<section>
17+
<SandboxEditor className="">
18+
<DataList.Root>
19+
<DataList.Item>
20+
<DataList.Label>Name</DataList.Label>
21+
<DataList.Value>John Doe</DataList.Value>
22+
</DataList.Item>
23+
<DataList.Item>
24+
<DataList.Label>Email</DataList.Label>
25+
<DataList.Value>john.doe@example.com</DataList.Value>
26+
</DataList.Item>
27+
<DataList.Item>
28+
<DataList.Label>Phone</DataList.Label>
29+
<DataList.Value>+123 456 7890</DataList.Value>
30+
</DataList.Item>
31+
<DataList.Item>
32+
<DataList.Label>Address</DataList.Label>
33+
<DataList.Value>123 Main St, Anytown, USA</DataList.Value>
34+
</DataList.Item>
35+
<DataList.Item>
36+
<DataList.Label>Status</DataList.Label>
37+
<DataList.Value>
38+
<Badge color="green" size="small">Active</Badge>
39+
</DataList.Value>
40+
</DataList.Item>
41+
<DataList.Item>
42+
<DataList.Label>Actions</DataList.Label>
43+
<DataList.Value>
44+
This is a paragraph of text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.This is a paragraph of text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.This is a paragraph of text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.This is a paragraph of text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.This is a paragraph of text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
45+
</DataList.Value>
46+
</DataList.Item>
47+
</DataList.Root>
48+
</SandboxEditor>
49+
</section>
50+
);
51+
};
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import React from 'react';
2+
import { render, screen } from '@testing-library/react';
3+
import DataList from '../DataList';
4+
5+
describe('DataList Component', () => {
6+
test('should render DataList components without crashing', () => {
7+
render(
8+
<DataList.Root>
9+
<DataList.Item>
10+
<DataList.Label>Name</DataList.Label>
11+
<DataList.Value>John Doe</DataList.Value>
12+
</DataList.Item>
13+
</DataList.Root>
14+
);
15+
expect(screen.getByText('Name')).toBeInTheDocument();
16+
expect(screen.getByText('John Doe')).toBeInTheDocument();
17+
});
18+
19+
test('should apply default class names correctly', () => {
20+
const { container } = render(
21+
<DataList.Root>
22+
<DataList.Item>
23+
<DataList.Label>Email</DataList.Label>
24+
<DataList.Value>test@example.com</DataList.Value>
25+
</DataList.Item>
26+
</DataList.Root>
27+
);
28+
29+
const rootElement = container.firstChild;
30+
expect(rootElement).toHaveClass('rad-ui-data-list');
31+
32+
const itemElement = container.querySelector('.rad-ui-data-list-item');
33+
expect(itemElement).toBeInTheDocument();
34+
35+
const labelElement = container.querySelector('.rad-ui-data-list-label');
36+
expect(labelElement).toBeInTheDocument();
37+
38+
const valueElement = container.querySelector('.rad-ui-data-list-value');
39+
expect(valueElement).toBeInTheDocument();
40+
});
41+
42+
test('should apply custom class names correctly', () => {
43+
const { container } = render(
44+
<DataList.Root className="custom-root" customRootClass="custom-datalist">
45+
<DataList.Item className="custom-item">
46+
<DataList.Label className="custom-label">Phone</DataList.Label>
47+
<DataList.Value className="custom-value">123-456-7890</DataList.Value>
48+
</DataList.Item>
49+
</DataList.Root>
50+
);
51+
52+
const rootElement = container.firstChild;
53+
expect(rootElement).toHaveClass('custom-datalist');
54+
expect(rootElement).toHaveClass('custom-root');
55+
56+
const itemElement = container.querySelector('.custom-datalist-item');
57+
expect(itemElement).toHaveClass('custom-item');
58+
59+
const labelElement = container.querySelector('.custom-datalist-label');
60+
expect(labelElement).toHaveClass('custom-label');
61+
62+
const valueElement = container.querySelector('.custom-datalist-value');
63+
expect(valueElement).toHaveClass('custom-value');
64+
});
65+
66+
test('should handle multiple DataList Items', () => {
67+
render(
68+
<DataList.Root>
69+
<DataList.Item>
70+
<DataList.Label>Name</DataList.Label>
71+
<DataList.Value>John Doe</DataList.Value>
72+
</DataList.Item>
73+
<DataList.Item>
74+
<DataList.Label>Email</DataList.Label>
75+
<DataList.Value>john.doe@example.com</DataList.Value>
76+
</DataList.Item>
77+
<DataList.Item>
78+
<DataList.Label>Phone</DataList.Label>
79+
<DataList.Value>123-456-7890</DataList.Value>
80+
</DataList.Item>
81+
</DataList.Root>
82+
);
83+
84+
expect(screen.getByText('Name')).toBeInTheDocument();
85+
expect(screen.getByText('John Doe')).toBeInTheDocument();
86+
expect(screen.getByText('Email')).toBeInTheDocument();
87+
expect(screen.getByText('john.doe@example.com')).toBeInTheDocument();
88+
expect(screen.getByText('Phone')).toBeInTheDocument();
89+
expect(screen.getByText('123-456-7890')).toBeInTheDocument();
90+
});
91+
92+
test('should warn when using DataList directly', () => {
93+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
94+
render(<DataList />);
95+
96+
expect(consoleSpy).toHaveBeenCalledWith(
97+
'Direct usage of DataList is not supported. Please use DataList.Root, DataList.Item, etc. instead.'
98+
);
99+
100+
consoleSpy.mockRestore();
101+
});
102+
});

styles/themes/components/badge.scss

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
color: var(--rad-ui-color-accent-950);
55
padding:4px 8px;
66
height: 32px;
7-
display: flex;
7+
display: inline-flex;
88
align-items: center;
99
justify-content: center;
1010
font-weight: 600;
@@ -26,8 +26,6 @@
2626
border-bottom: 1px solid var(--rad-ui-color-accent-600);
2727
color: var(--rad-ui-color-accent-950);
2828
background-color: var(--rad-ui-color-accent-400);
29-
30-
3129
}
3230

3331

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
.rad-ui-data-list {
2+
display: grid;
3+
grid-template-columns: auto 1fr;
4+
gap: 16px;
5+
6+
7+
.rad-ui-data-list-item {
8+
display:grid;
9+
grid-template-columns: subgrid;
10+
gap: inherit;
11+
grid-column: span 2;
12+
13+
.rad-ui-data-list-label {
14+
grid-column: 1;
15+
color: var(--rad-ui-color-gray-900);
16+
font-size: 14px;
17+
line-height: 20px;
18+
letter-spacing: 0.1px;
19+
}
20+
21+
.rad-ui-data-list-value {
22+
grid-column: 2;
23+
color: var(--rad-ui-color-gray-1000);
24+
font-size: 14px;
25+
line-height: 20px;
26+
letter-spacing: 0.1px;
27+
}
28+
}
29+
}
30+

0 commit comments

Comments
 (0)