Skip to content

Commit 202d2b6

Browse files
authored
feat: add support for custom className and style props (#25)
1 parent 2a492e1 commit 202d2b6

File tree

14 files changed

+137
-14
lines changed

14 files changed

+137
-14
lines changed

lib/components/DualScrollSync/DualScrollSync.test.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,17 @@ describe('DualScrollSync', () => {
4949
expect(getByTestId('test')).toBeInTheDocument();
5050
expect(getByText('Child Heading')).toBeInTheDocument();
5151
});
52+
53+
it('should apply custom className and style', () => {
54+
const { getByTestId } = render(
55+
<DualScrollSyncBase id="test" className="custom-class" style={{ borderWidth: '1px' }}>
56+
Styled Nav
57+
</DualScrollSyncBase>
58+
);
59+
60+
const label = getByTestId('test');
61+
62+
expect(label).toHaveClass('custom-class');
63+
expect(label).toHaveStyle('border-width: 1px');
64+
});
5265
});

lib/components/DualScrollSync/DualScrollSync.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import clsx from 'clsx';
12
import type { FC } from 'react';
23
import { useMemo } from 'react';
34

@@ -15,9 +16,11 @@ import { DualScrollSyncNavItem } from './DualScrollSyncNavItem';
1516

1617
export const DualScrollSyncBase: FC<DualScrollSyncProps> = ({
1718
children,
19+
className,
1820
id,
1921
items,
20-
onItemClick
22+
onItemClick,
23+
style = {}
2124
}) => {
2225
const baseId = id ?? 'dual-scroll-sync';
2326
const navId = `${baseId}-nav`;
@@ -57,7 +60,12 @@ export const DualScrollSyncBase: FC<DualScrollSyncProps> = ({
5760

5861
return (
5962
<DualScrollSyncContext.Provider value={value}>
60-
<section id={baseId} data-testid={baseId} className={styles.scrollSync}>
63+
<section
64+
className={clsx(styles.scrollSync, className)}
65+
data-testid={baseId}
66+
id={baseId}
67+
style={style}
68+
>
6169
{items ? (
6270
<>
6371
<DualScrollSyncNav>

lib/components/DualScrollSync/DualScrollSync.types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export type DualScrollSyncOptions = {
1818

1919
export type DualScrollSyncItem = PropsWithChildren<DualScrollSyncOptions>;
2020

21-
export type DualScrollSyncProps = PropsWithChildren<{
21+
export type DualScrollSyncProps = PropsWithChildren<DualScrollSyncStyleProps> & {
2222
/**
2323
* Unique identifier for the DualScrollSync component. (Optional)
2424
* @default 'dual-scroll-sync'
@@ -41,7 +41,7 @@ export type DualScrollSyncProps = PropsWithChildren<{
4141
* @default () => {}
4242
*/
4343
onItemClick?: (activeKey: string) => void;
44-
}>;
44+
};
4545

4646
export type DualScrollSyncType = FC<DualScrollSyncProps> & {
4747
Nav: FC<DualScrollSyncNavProps>;

lib/components/DualScrollSync/DualScrollSyncContent/DualScrollSyncContent.test.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,17 @@ describe('DualScrollSyncContent', () => {
1717

1818
expect(getByTestId('test-content-id')).toBeInTheDocument();
1919
});
20+
21+
it('should apply custom className and style', () => {
22+
const { getByTestId } = render(
23+
<DualScrollSyncContent className="custom-class" style={{ borderWidth: '1px' }}>
24+
<div>Styled Content</div>
25+
</DualScrollSyncContent>
26+
);
27+
28+
const content = getByTestId('test-content-id');
29+
30+
expect(content).toHaveClass('custom-class');
31+
expect(content).toHaveStyle('border-width: 1px');
32+
});
2033
});

lib/components/DualScrollSync/DualScrollSyncContent/DualScrollSyncContent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ export const DualScrollSyncContent: FC<DualScrollSyncContentProps> = ({
1616
return (
1717
<section
1818
className={clsx(styles.scrollSyncContent, className)}
19-
style={style}
2019
data-testid={contentId}
2120
id={contentId}
2221
ref={contentRef}
22+
style={style}
2323
>
2424
{children}
2525
</section>

lib/components/DualScrollSync/DualScrollSyncContentSection/DualScrollSyncContentSection.test.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,21 @@ describe('DualScrollSyncContentSection', () => {
2020
expect(contentSection).toBeInTheDocument();
2121
expect(getByText('Test Content')).toBeInTheDocument();
2222
});
23+
24+
it('should apply custom className and style', () => {
25+
const { getByTestId } = render(
26+
<DualScrollSyncContentSection
27+
sectionKey="styled-section"
28+
className="custom-class"
29+
style={{ borderWidth: '1px' }}
30+
>
31+
<div>Styled Content</div>
32+
</DualScrollSyncContentSection>
33+
);
34+
35+
const contentSection = getByTestId('test-content-id-section-styled-section');
36+
37+
expect(contentSection).toHaveClass('custom-class');
38+
expect(contentSection).toHaveStyle({ borderWidth: '1px' });
39+
});
2340
});

lib/components/DualScrollSync/DualScrollSyncContentSection/DualScrollSyncContentSection.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import clsx from 'clsx';
12
import type { FC } from 'react';
23

34
import { useDualScrollSyncContext } from '@/hooks';
@@ -6,23 +7,26 @@ import styles from './DualScrollSyncContentSection.module.scss';
67
import type { DualScrollSyncContentSectionProps } from './DualScrollSyncContentSection.types';
78

89
export const DualScrollSyncContentSection: FC<DualScrollSyncContentSectionProps> = ({
10+
children,
11+
className,
912
sectionKey,
10-
children
13+
style = {}
1114
}) => {
1215
const { contentId, sectionRefs } = useDualScrollSyncContext();
1316

1417
const contentSectionId = `${contentId}-section-${sectionKey}`;
1518

1619
return (
1720
<article
18-
className={styles.scrollSyncContentSection}
21+
className={clsx(styles.scrollSyncContentSection, className)}
1922
data-section={sectionKey}
2023
data-testid={contentSectionId}
2124
id={contentSectionId}
2225
ref={(contentRef) => {
2326
if (!contentRef) return;
2427
sectionRefs.current[sectionKey] = contentRef;
2528
}}
29+
style={style}
2630
>
2731
{children}
2832
</article>

lib/components/DualScrollSync/DualScrollSyncLabel/DualScrollSyncLabel.test.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,31 @@ describe('DualScrollSyncLabel', () => {
2424
expect(getByText('Bold Label')).toBeInTheDocument();
2525
expect(getByText('Bold Label').tagName).toBe('STRONG');
2626
});
27+
28+
it('should apply custom className and style', () => {
29+
const { getByText } = render(
30+
<DualScrollSyncLabel className="custom-class" style={{ borderWidth: '1px' }}>
31+
Styled Label
32+
</DualScrollSyncLabel>
33+
);
34+
35+
const label = getByText('Styled Label');
36+
37+
expect(label).toHaveClass('custom-class');
38+
expect(label).toHaveStyle('border-width: 1px');
39+
});
40+
41+
it('should not apply custom className or style if children is not a string', () => {
42+
const { getByText } = render(
43+
<DualScrollSyncLabel className="custom-class" style={{ borderWidth: '1px' }}>
44+
<span>Styled Child</span>
45+
</DualScrollSyncLabel>
46+
);
47+
48+
const label = getByText('Styled Child');
49+
50+
expect(label).toBeInTheDocument();
51+
expect(label).not.toHaveClass('custom-class');
52+
expect(label).not.toHaveStyle('border-width: 1px');
53+
});
2754
});

lib/components/DualScrollSync/DualScrollSyncLabel/DualScrollSyncLabel.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
1+
import clsx from 'clsx';
12
import type { FC } from 'react';
23

34
import { useDualScrollSyncContext } from '@/hooks';
45

56
import styles from './DualScrollSyncLabel.module.scss';
67
import type { DualScrollSyncLabelProps } from './DualScrollSyncLabel.types';
78

8-
export const DualScrollSyncLabel: FC<DualScrollSyncLabelProps> = ({ children }) => {
9+
export const DualScrollSyncLabel: FC<DualScrollSyncLabelProps> = ({
10+
children,
11+
className,
12+
style = {}
13+
}) => {
914
useDualScrollSyncContext();
1015

1116
if (typeof children !== 'string') return children;
1217

1318
return (
14-
<span className={styles.scrollSyncContentSectionLabel} title={children}>
19+
<span
20+
className={clsx(styles.scrollSyncContentSectionLabel, className)}
21+
title={children}
22+
style={style}
23+
>
1524
{children}
1625
</span>
1726
);
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
import type { PropsWithChildren } from 'react';
22

3-
export type DualScrollSyncLabelProps = PropsWithChildren;
3+
import type { DualScrollSyncStyleProps } from '../DualScrollSync.types';
4+
5+
export type DualScrollSyncLabelProps = PropsWithChildren<DualScrollSyncStyleProps>;

0 commit comments

Comments
 (0)