// Styled Select = the unstyled @tamagui/ui Select behavior primitive + the
// default v2-look skin, layered here in `tamagui`. Single skin definition; the
// shadcn registry item is generated from this file. Default chevron/check icons
// are dependency-free glyphs (see IconGlyph) so `tamagui` stays lean and native-
// bundleable — no react-native-svg pulled into the core package. Consumers can
// pass their own icon components as children of the icon parts.
//
// Sizing is preset-based: `size` is one of xs sm md lg xl (default md), owned
// inline here like every other skin.
import {
type ComponentSize,
createStyledContext,
type GetProps,
styled,
withStaticProperties,
} from '@tamagui/core'
import {
Select as SelectBehavior,
SelectNativeComponentContext,
type SelectProps as SelectBehaviorProps,
type SelectScopedProps,
} from '@tamagui/select'
import { SizableText } from '@tamagui/text'
const IconGlyph = styled(SizableText, {
displayName: 'SelectIconGlyph',
color: 'color',
userSelect: 'none',
})
const ChevronDown = ({ size = 16 }: { size?: number }) => (
▾
)
const ChevronUp = ({ size = 16 }: { size?: number }) => (
▴
)
const Check = ({ size = 14 }: { size?: number }) => (
✓
)
export type SelectSize = ComponentSize | boolean
const SelectContext = createStyledContext<{ size?: SelectSize }>({ size: 'md' })
const selectFrameSize = {
xs: { paddingInline: '2', paddingBlock: '1', borderRadius: 'sm', gap: '1' },
sm: { paddingInline: '3', paddingBlock: '1.5', borderRadius: 'md', gap: '1.5' },
md: { paddingInline: '4', paddingBlock: '2', borderRadius: 'md', gap: '2' },
lg: { paddingInline: '6', paddingBlock: '2', borderRadius: 'md', gap: '2' },
xl: { paddingInline: '8', paddingBlock: '2.5', borderRadius: 'lg', gap: '2.5' },
} as const
const selectTextSize = {
xs: { fontSize: 'xs', lineHeight: 'xs' },
sm: { fontSize: 'sm', lineHeight: 'sm' },
md: { fontSize: 'sm', lineHeight: 'sm' },
lg: { fontSize: 'base', lineHeight: 'base' },
xl: { fontSize: 'lg', lineHeight: 'lg' },
} as const
const selectItemSize = {
xs: { gap: '1', paddingHorizontal: '2', paddingVertical: '1' },
sm: { gap: '1.5', paddingHorizontal: '3', paddingVertical: '1.5' },
md: { gap: '2', paddingHorizontal: '4', paddingVertical: '2' },
lg: { gap: '2', paddingHorizontal: '6', paddingVertical: '2' },
xl: { gap: '2.5', paddingHorizontal: '8', paddingVertical: '2.5' },
} as const
// appearance: none drops the platform arrow, so the skin draws its own chevron:
// two 5px gradient strokes in currentColor (it follows the theme), centered in
// where the trigger's 16px icon sits, one 16px box in from the inline padding
const nativeChevronStroke = (angle: number) =>
`linear-gradient(${angle}deg, transparent calc(50% - 0.75px), currentColor calc(50% - 0.75px) calc(50% + 0.75px), transparent calc(50% + 0.75px))`
const nativeChevronPosition = (paddingInline: number) => {
const center = paddingInline + 8
return `calc(100% - ${center - 0.25}px) 50%, calc(100% - ${center - 4.75}px) 50%`
}
const selectNativeSize = {
// a native