mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-07 13:45:01 +03:00
f4030c889c
Expose selectable options and selected values, associate validation guidance with controls, and contain keyboard focus in inbound dialogs. Preserve create and edit serialization and add Chromium keyboard and accessibility checks.
71 lines
2.3 KiB
TypeScript
71 lines
2.3 KiB
TypeScript
import type { ComponentPropsWithRef } from 'react';
|
|
import { theme } from 'antd';
|
|
|
|
import './NativeSelect.css';
|
|
|
|
export interface NativeSelectProps<Value extends string | number> extends Omit<
|
|
ComponentPropsWithRef<'select'>,
|
|
'value' | 'defaultValue' | 'onChange' | 'multiple' | 'children' | 'size'
|
|
> {
|
|
value?: Value | null;
|
|
onChange?: (value: Value) => void;
|
|
options: readonly { value: Value; label: string | number; disabled?: boolean }[];
|
|
placeholder?: string;
|
|
size?: 'small' | 'middle' | 'large';
|
|
}
|
|
|
|
export function NativeSelect<Value extends string | number>({
|
|
value,
|
|
options,
|
|
onChange,
|
|
placeholder,
|
|
disabled,
|
|
className,
|
|
style,
|
|
size,
|
|
...props
|
|
}: NativeSelectProps<Value>) {
|
|
const { token } = theme.useToken();
|
|
const selected = options.findIndex((option) => Object.is(option.value, value));
|
|
const hasUnlistedValue = selected < 0 && value != null;
|
|
return (
|
|
<select
|
|
{...props}
|
|
className={['native-select', className].filter(Boolean).join(' ')}
|
|
disabled={disabled}
|
|
value={selected < 0 ? '' : String(selected)}
|
|
onChange={(event) => {
|
|
const option = options[Number(event.target.value)];
|
|
if (event.target.value !== '' && option && !option.disabled) onChange?.(option.value);
|
|
}}
|
|
style={{
|
|
width: '100%',
|
|
minWidth: 0,
|
|
height:
|
|
size === 'small'
|
|
? token.controlHeightSM
|
|
: size === 'large'
|
|
? token.controlHeightLG
|
|
: token.controlHeight,
|
|
border: `1px solid ${props['aria-invalid'] === true || props['aria-invalid'] === 'true' ? token.colorError : token.colorBorder}`,
|
|
borderRadius: token.borderRadius,
|
|
backgroundColor: disabled ? token.colorBgContainerDisabled : token.colorBgContainer,
|
|
color: disabled ? token.colorTextDisabled : token.colorText,
|
|
fontSize: token.fontSize,
|
|
...style,
|
|
}}
|
|
>
|
|
{selected < 0 && (
|
|
<option value="" disabled={!hasUnlistedValue} hidden={!hasUnlistedValue}>
|
|
{hasUnlistedValue ? String(value) : (placeholder ?? '')}
|
|
</option>
|
|
)}
|
|
{options.map((option, index) => (
|
|
<option key={String(index)} value={String(index)} disabled={option.disabled}>
|
|
{option.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
);
|
|
}
|