Skip to content

Commit 7f2e8f5

Browse files
authored
feat: segmented support classnames and styles (#296)
* feat: segmented support classnames and styles * fix
1 parent 8afca79 commit 7f2e8f5

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

src/index.tsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as React from 'react';
66

77
import MotionThumb from './MotionThumb';
88

9+
export type SemanticName = 'item' | 'label';
910
export type SegmentedValue = string | number;
1011

1112
export type SegmentedRawOption = SegmentedValue;
@@ -41,6 +42,8 @@ export interface SegmentedProps<ValueType = SegmentedValue>
4142
motionName?: string;
4243
vertical?: boolean;
4344
name?: string;
45+
classNames?: Partial<Record<SemanticName, string>>;
46+
styles?: Partial<Record<SemanticName, React.CSSProperties>>;
4447
}
4548

4649
function getValidTitle(option: SegmentedLabeledOption) {
@@ -74,6 +77,9 @@ function normalizeOptions(options: SegmentedOptions): SegmentedLabeledOption[] {
7477
const InternalSegmentedOption: React.FC<{
7578
prefixCls: string;
7679
className?: string;
80+
style?: React.CSSProperties;
81+
classNames?: Partial<Record<SemanticName, string>>;
82+
styles?: Partial<Record<SemanticName, React.CSSProperties>>;
7783
disabled?: boolean;
7884
checked: boolean;
7985
label: React.ReactNode;
@@ -92,6 +98,9 @@ const InternalSegmentedOption: React.FC<{
9298
}> = ({
9399
prefixCls,
94100
className,
101+
style,
102+
styles,
103+
classNames: segmentedClassNames,
95104
disabled,
96105
checked,
97106
label,
@@ -117,6 +126,7 @@ const InternalSegmentedOption: React.FC<{
117126
className={classNames(className, {
118127
[`${prefixCls}-item-disabled`]: disabled,
119128
})}
129+
style={style}
120130
onMouseDown={onMouseDown}
121131
>
122132
<input
@@ -132,9 +142,13 @@ const InternalSegmentedOption: React.FC<{
132142
onKeyUp={onKeyUp}
133143
/>
134144
<div
135-
className={`${prefixCls}-item-label`}
145+
className={classNames(
146+
`${prefixCls}-item-label`,
147+
segmentedClassNames?.label,
148+
)}
136149
title={title}
137150
aria-selected={checked}
151+
style={styles?.label}
138152
>
139153
{label}
140154
</div>
@@ -155,6 +169,9 @@ const Segmented = React.forwardRef<HTMLDivElement, SegmentedProps>(
155169
name,
156170
onChange,
157171
className = '',
172+
style,
173+
styles,
174+
classNames: segmentedClassNames,
158175
motionName = 'thumb-motion',
159176
...restProps
160177
} = props;
@@ -240,12 +257,12 @@ const Segmented = React.forwardRef<HTMLDivElement, SegmentedProps>(
240257
break;
241258
}
242259
};
243-
244260
return (
245261
<div
246262
role="radiogroup"
247263
aria-label="segmented control"
248264
tabIndex={disabled ? undefined : 0}
265+
style={style}
249266
{...divProps}
250267
className={classNames(
251268
prefixCls,
@@ -285,6 +302,7 @@ const Segmented = React.forwardRef<HTMLDivElement, SegmentedProps>(
285302
className={classNames(
286303
segmentedOption.className,
287304
`${prefixCls}-item`,
305+
segmentedClassNames?.item,
288306
{
289307
[`${prefixCls}-item-selected`]:
290308
segmentedOption.value === rawValue && !thumbShow,
@@ -294,6 +312,9 @@ const Segmented = React.forwardRef<HTMLDivElement, SegmentedProps>(
294312
segmentedOption.value === rawValue,
295313
},
296314
)}
315+
style={styles?.item}
316+
classNames={segmentedClassNames}
317+
styles={styles}
297318
checked={segmentedOption.value === rawValue}
298319
onChange={handleChange}
299320
onFocus={handleFocus}

tests/index.test.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,4 +765,38 @@ describe('Segmented keyboard navigation', () => {
765765
'rc-segmented-item-input-focused',
766766
);
767767
});
768+
it('should apply custom styles to Segmented', () => {
769+
const customClassNames = {
770+
item: 'custom-item',
771+
label: 'custom-label',
772+
};
773+
774+
const customStyles = {
775+
item: { color: 'yellow' },
776+
label: { backgroundColor: 'black' },
777+
};
778+
779+
const { container } = render(
780+
<Segmented
781+
options={['iOS', 'Android', 'Web']}
782+
classNames={customClassNames}
783+
styles={customStyles}
784+
/>,
785+
);
786+
787+
const itemElement = container.querySelector(
788+
'.rc-segmented-item',
789+
) as HTMLElement;
790+
const labelElement = container.querySelector(
791+
'.rc-segmented-item-label',
792+
) as HTMLElement;
793+
794+
// check classNames
795+
expect(itemElement.classList).toContain('custom-item');
796+
expect(labelElement.classList).toContain('custom-label');
797+
798+
// check styles
799+
expect(itemElement.style.color).toBe('yellow');
800+
expect(labelElement.style.backgroundColor).toBe('black');
801+
});
768802
});

0 commit comments

Comments
 (0)