From bc1b39024dc96782d91abd6cf5e8e0e3a3b8bc7f Mon Sep 17 00:00:00 2001 From: Rain120 <1085131904@qq.com> Date: Mon, 16 Feb 2026 23:20:01 +0800 Subject: [PATCH] feat: select option style, add demo and test --- docs/demo/select-content-option.md | 8 + docs/examples/select-content-option.tsx | 186 ++++++++++ src/SelectInput/Content/SingleContent.tsx | 24 +- tests/Select.test.tsx | 406 ++++++++++++++++++++++ 4 files changed, 610 insertions(+), 14 deletions(-) create mode 100644 docs/demo/select-content-option.md create mode 100644 docs/examples/select-content-option.tsx diff --git a/docs/demo/select-content-option.md b/docs/demo/select-content-option.md new file mode 100644 index 000000000..1ff617025 --- /dev/null +++ b/docs/demo/select-content-option.md @@ -0,0 +1,8 @@ +--- +title: select-content-option +nav: + title: Demo + path: /demo +--- + + diff --git a/docs/examples/select-content-option.tsx b/docs/examples/select-content-option.tsx new file mode 100644 index 000000000..2b809e55a --- /dev/null +++ b/docs/examples/select-content-option.tsx @@ -0,0 +1,186 @@ +import React from 'react'; +import Select, { Option } from '@rc-component/select'; +import '../../assets/index.less'; + +const Demo: React.FC = () => { + const [value, setValue] = React.useState('red'); + const [dynamicOptions, setDynamicOptions] = React.useState< + { value: string; label: string; style?: React.CSSProperties }[] + >([ + { + value: 'custom-1', + label: 'Custom Option 1', + style: { color: '#1890ff' }, + }, + { + value: 'custom-2', + label: 'Custom Option 2', + style: { color: '#52c41a' }, + }, + ]); + + const handleSearch = (searchValue: string) => { + if (searchValue && !dynamicOptions.find((opt) => opt.value === searchValue)) { + setDynamicOptions([ + ...dynamicOptions, + { + value: searchValue, + label: searchValue, + style: { color: '#faad14' }, + }, + ]); + } + }; + + return ( +
+

Option Style & ClassName for Selected Item

+

+ When an option has style or className props, they will be applied + to the selected item display. +

+ +
+

Basic Usage with Style

+ +
+ +
+

With Title (Tooltip)

+ + + + + +
+ +
+

Root Title Override

+ ( + + )} + options={dynamicOptions} + /> +
+
+ + ); +}; + +export default Demo; diff --git a/src/SelectInput/Content/SingleContent.tsx b/src/SelectInput/Content/SingleContent.tsx index 6a44357f8..ce5603cfe 100644 --- a/src/SelectInput/Content/SingleContent.tsx +++ b/src/SelectInput/Content/SingleContent.tsx @@ -71,20 +71,16 @@ const SingleContent = React.forwardRef( // Render value const renderValue = displayValue ? ( - hasOptionStyle ? ( -
- {displayValue.label} -
- ) : ( - displayValue.label - ) +
+ {displayValue.label} +
) : ( ); diff --git a/tests/Select.test.tsx b/tests/Select.test.tsx index 3cdf61287..de3d01d7a 100644 --- a/tests/Select.test.tsx +++ b/tests/Select.test.tsx @@ -3045,4 +3045,410 @@ describe('Select.Basic', () => { expect(preventDefaultSpy).not.toHaveBeenCalled(); }); }); + + describe('option style, className and title for selected item', () => { + it('should apply option style to selected item display', () => { + const { container } = render( + , + ); + + const selectedValue = container.querySelector('.rc-select-content-value'); + expect(selectedValue).toBeTruthy(); + expect(selectedValue).toHaveClass('custom-option-class'); + }); + + it('should apply option title to selected item display when has style', () => { + const { container } = render( + , + ); + + const contentElement = container.querySelector('.rc-select-content'); + expect(contentElement).toBeTruthy(); + expect(contentElement.getAttribute('title')).toBe('Custom tooltip for this option'); + }); + + it('should use label as title when option has no title', () => { + const { container } = render( + , + ); + + const selectedValue = container.querySelector('.rc-select-content-value'); + expect(selectedValue).toBeTruthy(); + expect(selectedValue).toHaveAttribute('title', 'Root title override'); + }); + + it('should add content-has-option-style class when option has style or className', () => { + const { container: containerWithStyle } = render( + , + ); + expect(containerWithClass.querySelector('.rc-select-content-has-option-style')).toBeTruthy(); + }); + + it('should not add content-has-option-style class when option has no style or className', () => { + const { container } = render( + , + ); + + const selectedValue = container.querySelector('.rc-select-content-value'); + expect(selectedValue).toBeTruthy(); + expect(selectedValue.tagName).toBe('DIV'); + expect(selectedValue.textContent).toBe('Styled Option'); + }); + + it('should render selected value in a div even when option has no style or className', () => { + const { container } = render( + + + + , + ); + + const selectedValue = container.querySelector('.rc-select-content-value'); + expect(selectedValue).toBeTruthy(); + expect(selectedValue).toHaveStyle({ color: 'orange' }); + expect(selectedValue).toHaveClass('custom-className'); + expect(selectedValue).toHaveAttribute('title', 'Custom title'); + }); + + it('should update style when value changes', () => { + const { container, rerender } = render( + , + ); + + selectedValue = container.querySelector('.rc-select-content-value'); + expect(selectedValue).toHaveStyle({ color: 'blue' }); + }); + + it('should work with combobox mode', () => { + const { container } = render( + , + ); + + const selectedValue = container.querySelector('.rc-select-content-value'); + expect(selectedValue).toBeTruthy(); + expect(selectedValue).toHaveStyle({ color: 'teal' }); + expect(selectedValue).toHaveClass('label-in-value-class'); + }); + + it('should hide value visibility when searching', () => { + const { container } = render( + , + ); + + const selectedValue = container.querySelector('.rc-select-content-value'); + expect(selectedValue).toBeTruthy(); + expect(selectedValue).toHaveStyle({ color: 'red', fontSize: '16px' }); + expect(selectedValue).toHaveClass('combined-class'); + expect(selectedValue).toHaveClass('another-class'); + }); + + it('should handle empty string title', () => { + const { container } = render( + , + ); + + const selectedValue = container.querySelector('.rc-select-content-value'); + expect(selectedValue).toBeTruthy(); + expect(selectedValue).toHaveStyle({ color: 'blue' }); + expect(selectedValue.textContent).toBe('One'); + }); + }); });