diff --git a/src/components/select.tsx b/src/components/select.tsx new file mode 100644 index 0000000..49a6bbf --- /dev/null +++ b/src/components/select.tsx @@ -0,0 +1,29 @@ +import { Select as AntSelect, type SelectProps as AntSelectProps } from 'antd'; + +import { cn } from '../lib'; + +/** + * The shared select entry point. It deliberately keeps Ant Design's option + * model intact while making sizing, invalid state and the stable ui-select + * hook part of the product contract. + */ +export interface SelectProps extends AntSelectProps { + invalid?: boolean; +} + +export function Select({ + className, + invalid, + status, + 'aria-invalid': ariaInvalid, + ...props +}: SelectProps) { + return ( + + className={cn('ui-select', className)} + status={invalid ? 'error' : status} + aria-invalid={(ariaInvalid ?? invalid) || undefined} + {...props} + /> + ); +} diff --git a/src/index.ts b/src/index.ts index d930f4e..b3c2bbb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -53,6 +53,7 @@ export { DropdownMenuTrigger, } from './components/dropdown-menu'; export { Input, type InputProps } from './components/input'; +export { Select, type SelectProps } from './components/select'; export { Skeleton } from './components/skeleton'; export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './components/tooltip'; export { AppShell, type AppShellProps } from './patterns/app-shell'; diff --git a/src/styles/components.css b/src/styles/components.css index 28226df..ba0fc7b 100644 --- a/src/styles/components.css +++ b/src/styles/components.css @@ -81,6 +81,10 @@ width: 100%; } +.ui-select.ant-select { + width: 100%; +} + .ui-card__header { display: flex; flex-direction: column; diff --git a/tests/primitives.test.tsx b/tests/primitives.test.tsx index 92d8a75..6fa015d 100644 --- a/tests/primitives.test.tsx +++ b/tests/primitives.test.tsx @@ -19,6 +19,7 @@ import { DropdownMenuItem, DropdownMenuTrigger, Input, + Select, Skeleton, Tooltip, TooltipContent, @@ -46,6 +47,20 @@ describe('core primitives', () => { ); }); + it('renders the shared select with a stable hook and invalid state', () => { + render( +