覆盖选择器组件边界情况、TypeScript 类型推断与 API 交互的综合性测试。 用于验证 strictNullChecks 缺陷修复,以及 renderValue/placeholder 的行为。
value={objectOrNull} 不应导致 T 被推断为 never。 onValueChange 回调应当收到 User | null。
const [selected, setSelected] = useState<User | null>(null);
<Select<User>
label="Select User"
placeholder="Choose a user..."
value={selected}
onValueChange={(value) => setSelected(value)} // value: User | null
renderValue={(user) => <span>{user.name}</span>}
>
{users.map((user) => (
<Select.Option key={user.id} value={user}>
{user.name}
</Select.Option>
))}
</Select>renderValue 只会在非空值时被调用。 未选中任何值时显示 placeholder。
<Select<Country>
label="Select Country"
placeholder="Pick a country..." // Shows when value is null
value={country}
onValueChange={setCountry}
renderValue={(c) => ( // Only called when c is non-null
<span>{c.flag} {c.name}</span>
)}
>
{countries.map((c) => (
<Select.Option key={c.code} value={c}>
{c.flag} {c.name}
</Select.Option>
))}
</Select>使用 items 属性传入 { label, value } 对象数组。 会自动生成 Select.Option 元素。
const priorities: Priority[] = [
{ level: 1, name: "Critical", color: "text-lark-danger" },
{ level: 2, name: "High", color: "text-lark-warning" },
// ...
];
<Select<Priority>
label="Priority"
placeholder="Select priority..."
value={priority}
onValueChange={setPriority}
items={priorities.map((p) => ({
label: <span className={p.color}>[{p.level}] {p.name}</span>,
value: p,
}))}
renderValue={(p) => (
<span className={p.color}>[{p.level}] {p.name}</span>
)}
/>使用 items 属性传入对象映射。 支持通过 SelectItemDescriptor 表示禁用的选项。
<Select
label="Status"
placeholder="Select status..."
value={status}
onValueChange={setStatus}
items={{
active: "Active", // Simple string label
pending: "Pending",
inactive: "Inactive",
archived: { label: "Archived", disabled: true }, // SelectItemDescriptor
}}
/>使用对象取值的 multiple 模式。renderValue 收到的是 T[] 而不是 T。
const [selectedUsers, setSelectedUsers] = useState<User[]>([]);
<Select<User, true> // Note: second generic is true
label="Select Users"
placeholder="Choose users..."
multiple // Enable multi-select
value={selectedUsers} // T[] not T
onValueChange={setSelectedUsers} // (users: User[]) => void
renderValue={(users) => ( // users is User[]
<span>{users.map((u) => u.name).join(", ")}</span>
)}
>
{users.map((user) => (
<Select.Option key={user.id} value={user}>
{user.name}
</Select.Option>
))}
</Select>在受控(value)与非受控(defaultValue)两种模式之间切换。
// Controlled: you manage the state
const [value, setValue] = useState<string | null>(null);
<Select
value={value}
onValueChange={setValue}
items={{ apple: "Apple", banana: "Banana" }}
/>
// Uncontrolled: component manages state internally
<Select
defaultValue="banana"
items={{ apple: "Apple", banana: "Banana" }}
/>使用复合组件构建结构化的选项列表。
<Select label="Category" placeholder="Select...">
<Select.Group>
<Select.GroupLabel>Fruits</Select.GroupLabel>
<Select.Option value="apple">Apple</Select.Option>
<Select.Option value="banana">Banana</Select.Option>
</Select.Group>
<Select.Separator />
<Select.Group>
<Select.GroupLabel>Vegetables</Select.GroupLabel>
<Select.Option value="carrot">Carrot</Select.Option>
<Select.Option value="broccoli">Broccoli</Select.Option>
</Select.Group>
</Select>当传入 label 时会自动包裹 Field 组件。
请从列表中选择一个选项。
<Select
label="Required Field"
placeholder="This field is required..."
required // Shows required indicator
value={value}
onValueChange={setValue}
description="Helper text below" // Shows description
error={!value ? "Required" : undefined} // Shows error message
labelTooltip="Tooltip on hover" // Info icon with tooltip
items={{ a: "Option A", b: "Option B" }}
/>四种尺寸与 Input 组件的尺寸规范保持一致。
<Select size="xs" ... /> // Extra small: h-5 (20px) <Select size="sm" ... /> // Small: h-6.5 (26px) <Select size="base" ... /> // Default: h-9 (36px) <Select size="lg" ... /> // Large: h-10 (40px)
加载期间显示骨架屏并禁用交互。
const [loading, setLoading] = useState(true);
<Select
label="Data Loading"
placeholder="Select when loaded..."
loading={loading} // Shows SkeletonLine, disables trigger
items={{ ... }}
/>可以通过 SelectItemDescriptor 或 Option 上的 disabled 属性禁用单个选项。
// Via items prop with SelectItemDescriptor
<Select
items={{
available: "Available",
disabled: { label: "Disabled", disabled: true },
}}
/>
// Via Select.Option prop
<Select>
<Select.Option value="available">Available</Select.Option>
<Select.Option value="disabled" disabled>Disabled</Select.Option>
</Select>在可能的情况下,TypeScript 会根据用法推断类型。
// No explicit <T> - inferred from items/value
const [value, setValue] = useState<string | null>(null);
<Select
value={value}
onValueChange={(v) => setValue(v)} // v inferred as string | null
items={{ foo: "Foo", bar: "Bar" }}
/>
// With explicit generic for complex types
<Select<User>
value={user}
onValueChange={setUser}
renderValue={(u) => u.name} // u is User, not unknown
>
...
</Select>