fix(web): keep shared select native wrapper

This commit is contained in:
dongmucat 2026-03-20 11:17:06 +08:00 • committed by Xudong Sun
parent cd8e3ee200
commit c116ac2167
2 changed files with 32 additions and 8 deletions

View file

@ -10,8 +10,12 @@ describe('shared select contract', () => {
it('keeps the trigger aligned with the existing input styling language', () => {
expect(SELECT_TRIGGER_CLASS_NAME).toContain('h-11')
expect(SELECT_TRIGGER_CLASS_NAME).toContain('rounded-lg')
expect(SELECT_TRIGGER_CLASS_NAME).toContain('border-border')
expect(SELECT_TRIGGER_CLASS_NAME).toContain('focus:ring-primary/40')
expect(SELECT_TRIGGER_CLASS_NAME).toContain('border-border/60')
expect(SELECT_TRIGGER_CLASS_NAME).toContain('bg-secondary/50')
expect(SELECT_TRIGGER_CLASS_NAME).toContain('focus-visible:outline-none')
expect(SELECT_TRIGGER_CLASS_NAME).toContain('focus-visible:ring-2')
expect(SELECT_TRIGGER_CLASS_NAME).toContain('focus-visible:ring-primary/40')
expect(SELECT_TRIGGER_CLASS_NAME).toContain('focus-visible:border-primary/50')
})
it('uses themed panel and item classes for the floating listbox', () => {
@ -21,8 +25,10 @@ describe('shared select contract', () => {
expect(SELECT_ITEM_CLASS_NAME).toContain('data-[disabled]:opacity-50')
})
it('maps empty string form state to an undefined Radix value', () => {
it('maps empty and nullish form state to an undefined Radix value', () => {
expect(normalizeSelectValue('')).toBeUndefined()
expect(normalizeSelectValue(null)).toBeUndefined()
expect(normalizeSelectValue(undefined)).toBeUndefined()
expect(normalizeSelectValue('PUBLIC')).toBe('PUBLIC')
})
})

View file

@ -1,10 +1,10 @@
import * as SelectPrimitive from '@radix-ui/react-select'
import * as React from 'react'
import { cn } from '@/shared/lib/utils'
export const SELECT_TRIGGER_CLASS_NAME = cn(
'flex h-11 w-full items-center justify-between rounded-lg border border-border bg-white px-4 py-2 text-sm text-foreground',
'flex h-11 w-full rounded-lg border border-border/60 bg-secondary/50 px-4 py-2 text-sm text-foreground',
'ring-offset-background transition-all duration-200',
'placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/40 focus:border-primary/50',
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:border-primary/50',
'disabled:cursor-not-allowed disabled:opacity-50'
)
@ -18,7 +18,25 @@ export const SELECT_ITEM_CLASS_NAME = cn(
)
export function normalizeSelectValue(value?: string | null) {
return value && value.length > 0 ? value : undefined
return typeof value === 'string' && value.length > 0 ? value : undefined
}
export const Select = SelectPrimitive.Root
interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {}
const Select = React.forwardRef<HTMLSelectElement, SelectProps>(
({ className, children, ...props }, ref) => {
return (
<select
className={cn(SELECT_TRIGGER_CLASS_NAME, className)}
ref={ref}
{...props}
>
{children}
</select>
)
}
)
Select.displayName = 'Select'
export { Select }