-
-
Notifications
You must be signed in to change notification settings - Fork 491
fix: select option style, add demo and test #1211
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| --- | ||
| title: select-content-option | ||
| nav: | ||
| title: Demo | ||
| path: /demo | ||
| --- | ||
|
|
||
| <code src="../examples/select-content-option.tsx"></code> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<string>('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' }, | ||
| }, | ||
| ]); | ||
| } | ||
| }; | ||
|
Comment on lines
+22
to
+33
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
♻️ 建议使用函数式更新 const handleSearch = (searchValue: string) => {
- if (searchValue && !dynamicOptions.find((opt) => opt.value === searchValue)) {
- setDynamicOptions([
- ...dynamicOptions,
+ if (searchValue) {
+ setDynamicOptions((prev) => {
+ if (prev.find((opt) => opt.value === searchValue)) return prev;
+ return [
+ ...prev,
{
value: searchValue,
label: searchValue,
style: { color: '#faad14' },
},
- ]);
+ ];
+ });
}
};🤖 Prompt for AI Agents |
||
|
|
||
| return ( | ||
| <div style={{ margin: 20 }}> | ||
| <h2>Option Style & ClassName for Selected Item</h2> | ||
| <p> | ||
| When an option has <code>style</code> or <code>className</code> props, they will be applied | ||
| to the selected item display. | ||
| </p> | ||
|
|
||
| <div style={{ marginBottom: 24 }}> | ||
| <h3>Basic Usage with Style</h3> | ||
| <Select | ||
| value={value} | ||
| style={{ width: 200 }} | ||
| onChange={(val) => setValue(val as string)} | ||
| options={[ | ||
| { | ||
| value: 'red', | ||
| label: 'Red Color', | ||
| style: { color: 'red', fontWeight: 'bold' }, | ||
| }, | ||
| { | ||
| value: 'blue', | ||
| label: 'Blue Color', | ||
| style: { color: 'blue', fontWeight: 'bold' }, | ||
| }, | ||
| { | ||
| value: 'green', | ||
| label: 'Green Color', | ||
| style: { color: 'green', fontWeight: 'bold' }, | ||
| }, | ||
| { | ||
| value: 'normal', | ||
| label: 'Normal (no style)', | ||
| }, | ||
| ]} | ||
| /> | ||
| </div> | ||
|
|
||
| <div style={{ marginBottom: 24 }}> | ||
| <h3>With ClassName</h3> | ||
| <Select | ||
| defaultValue="styled" | ||
| style={{ width: 200 }} | ||
| options={[ | ||
| { | ||
| value: 'styled', | ||
| label: 'Styled Option', | ||
| className: 'custom-option-class', | ||
| style: { background: '#e6f7ff', border: '1px solid #1890ff' }, | ||
| }, | ||
| { | ||
| value: 'normal', | ||
| label: 'Normal Option', | ||
| }, | ||
| ]} | ||
| /> | ||
| </div> | ||
|
|
||
| <div style={{ marginBottom: 24 }}> | ||
| <h3>With Title (Tooltip)</h3> | ||
| <Select | ||
| defaultValue="with-title" | ||
| style={{ width: 200 }} | ||
| options={[ | ||
| { | ||
| value: 'with-title', | ||
| label: 'Hover me!', | ||
| title: 'This is a custom tooltip for this option', | ||
| style: { color: 'purple' }, | ||
| }, | ||
| { | ||
| value: 'without-title', | ||
| label: 'No Title', | ||
| style: { color: 'orange' }, | ||
| }, | ||
| ]} | ||
| /> | ||
| </div> | ||
|
|
||
| <div style={{ marginBottom: 24 }}> | ||
| <h3>Using Option Children Syntax</h3> | ||
| <Select defaultValue="option1" style={{ width: 200 }}> | ||
| <Option | ||
| value="option1" | ||
| style={{ color: 'orange' }} | ||
| className="custom-className" | ||
| title="Custom title for option 1" | ||
| > | ||
| Option 1 | ||
| </Option> | ||
| <Option value="option2" style={{ color: 'pink' }}> | ||
| Option 2 | ||
| </Option> | ||
| <Option value="option3">Option 3 (no style)</Option> | ||
| </Select> | ||
| </div> | ||
|
|
||
| <div style={{ marginBottom: 24 }}> | ||
| <h3>Root Title Override</h3> | ||
| <Select | ||
| value="override" | ||
| title="This title overrides option title" | ||
| style={{ width: 200 }} | ||
| options={[ | ||
| { | ||
| value: 'override', | ||
| label: 'Hover to see title', | ||
| title: 'Option title (will be overridden)', | ||
| style: { color: 'teal' }, | ||
| }, | ||
| ]} | ||
| /> | ||
| <h3>Custom Input Element with getInputElement (combobox mode)</h3> | ||
| <div style={{ marginBottom: 24 }}> | ||
| <p> | ||
| Use <code>getInputElement</code> to customize the input element. This only works with{' '} | ||
| <code>mode="combobox"</code>. Type to add new options dynamically. | ||
| </p> | ||
| <Select | ||
| mode="combobox" | ||
| style={{ width: 300 }} | ||
| suffixIcon={null} | ||
| showSearch | ||
| onSearch={handleSearch} | ||
| classNames={{ | ||
| prefix: 'custom-prefix', | ||
| suffix: 'custom-suffix', | ||
| }} | ||
| styles={{ | ||
| prefix: { marginRight: 8 }, | ||
| suffix: { marginLeft: 8 }, | ||
| }} | ||
| getInputElement={() => ( | ||
| <input | ||
| style={{ | ||
| border: '2px solid #1890ff', | ||
| borderRadius: 4, | ||
| padding: '4px 8px', | ||
| outline: 'none', | ||
| }} | ||
| placeholder="Type to add new option" | ||
| /> | ||
| )} | ||
| options={dynamicOptions} | ||
| /> | ||
| </div> | ||
| </div> | ||
|
Comment on lines
+132
to
+181
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Custom Input Element" 部分嵌套在 "Root Title Override" 的 div 内 Line 147 的 ♻️ 建议拆分为独立的 section />
+ </div>
+
+ <div style={{ marginBottom: 24 }}>
<h3>Custom Input Element with getInputElement (combobox mode)</h3>同时移除 Line 181 多余的 🤖 Prompt for AI Agents |
||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default Demo; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -71,20 +71,16 @@ const SingleContent = React.forwardRef<HTMLInputElement, SharedContentProps>( | |
|
|
||
| // Render value | ||
| const renderValue = displayValue ? ( | ||
| hasOptionStyle ? ( | ||
| <div | ||
| className={clsx(`${prefixCls}-content-value`, optionClassName)} | ||
| style={{ | ||
| ...(mergedSearchValue ? { visibility: 'hidden' } : {}), | ||
| ...optionStyle, | ||
| }} | ||
| title={optionTitle} | ||
| > | ||
| {displayValue.label} | ||
| </div> | ||
| ) : ( | ||
| displayValue.label | ||
| ) | ||
| <div | ||
| className={clsx(`${prefixCls}-content-value`, optionClassName)} | ||
| style={{ | ||
| ...(mergedSearchValue ? { visibility: 'hidden' } : {}), | ||
| ...optionStyle, | ||
| }} | ||
| title={optionTitle} | ||
| > | ||
| {displayValue.label} | ||
| </div> | ||
|
Comment on lines
+74
to
+83
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 当 Line 80 始终将 考虑仅在 Also applies to: 99-99 🤖 Prompt for AI Agents
当 建议将 🐛 建议修复样式合并顺序 style={{
+ ...optionStyle,
...(mergedSearchValue ? { visibility: 'hidden' } : {}),
- ...optionStyle,
}}🤖 Prompt for AI Agents |
||
| ) : ( | ||
| <Placeholder show={!mergedSearchValue} /> | ||
| ); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For state updates that depend on the previous state, it's a best practice to use the functional update form of
useState's setter function. This avoids potential issues with stale state, for example ifhandleSearchwere to be called in quick succession.