import { component, signal, type Define } from '@sigx/lynx'; import { Pressable } from '@sigx/lynx-gestures'; import { PRESSED_SCALE, PRESSED_OPACITY, type ColorVariant, type SizeScale, type WithAccessibility } from '@sigx/lynx-zero'; export type SelectSize = Extract; /** Upstream HeroUI select variants — flat (filled surface) is the default. */ export type SelectVariant = 'flat' | 'bordered'; export type SelectColor = Exclude; export interface SelectOption { label: string; value: string; } export type SelectProps = & Define.Prop<'options', SelectOption[], false> & Define.Prop<'value', string, false> & Define.Prop<'placeholder', string, false> & Define.Prop<'size', SelectSize, false> & Define.Prop<'variant', SelectVariant, false> & Define.Prop<'color', SelectColor, false> & Define.Prop<'disabled', boolean, false> & Define.Prop<'class', string, false> & WithAccessibility // Two-way binding (the sigx way): `model={() => state.country}`. Picking an // option writes its value into the model. The static `value` prop is honored // as display-only initial selection when no model is bound. There is no // `change` event: a prop named `value` trips runtime-core's emit lookup, so // use `model` for interactivity. & Define.Model; const sizeClasses: Record = { sm: 'hero-select-sm', md: '', lg: 'hero-select-lg', }; export const Select = component(({ props }) => { const state = signal({ open: false }); // Resolved selection: the bound model wins, else the static `value` prop. const selectedValue = () => (props.model ? props.model.value : props.value); const getClasses = () => { const c = ['hero-select']; if (props.variant === 'bordered') c.push('hero-select-bordered'); if (props.color) c.push(`hero-select-${props.color}`); if (props.size) { const s = sizeClasses[props.size]; if (s) c.push(s); } if (props.class) c.push(props.class); return c.join(' '); }; const getSelectedLabel = () => { const found = (props.options ?? []).find((o) => o.value === selectedValue()); return found ? found.label : (props.placeholder ?? 'Select…'); }; return () => ( { if (!props.disabled) state.open = !state.open; }} > {getSelectedLabel()} {state.open ? '▲' : '▼'} {state.open && !props.disabled ? ( {(props.options ?? []).map((option) => ( { if (props.model) props.model.value = option.value; state.open = false; }} > {option.label} ))} ) : null} ); });