diff --git a/apps/docs/src/ui/select-alignment.stories.tsx b/apps/docs/src/ui/select-alignment.stories.tsx index 955af9d..163676c 100644 --- a/apps/docs/src/ui/select-alignment.stories.tsx +++ b/apps/docs/src/ui/select-alignment.stories.tsx @@ -55,6 +55,10 @@ const RightAlignedSelectExample = () => { }; export const RightAligned: Story = { + args: { + options: fruits, + placeholder: 'Select a fruit...', + }, render: () => , play: async ({ canvasElement, step }) => { const canvas = within(canvasElement); @@ -79,7 +83,7 @@ export const RightAligned: Story = { await waitFor(() => { expect(document.activeElement).toBe(listbox); }); - await userEvent.keyboard('{ArrowDown}', { focusTrap: false }); + await userEvent.keyboard('{ArrowDown}'); await waitFor(() => { const activeItem = document.querySelector('[cmdk-item][aria-selected="true"]'); expect(activeItem).not.toBeNull(); diff --git a/packages/components/package.json b/packages/components/package.json index be7da4d..f43ba8e 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -58,7 +58,7 @@ "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-separator": "^1.1.6", "@radix-ui/react-slider": "^1.3.4", - "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-switch": "^1.1.2", "@radix-ui/react-tabs": "^1.1.11", "@radix-ui/react-tooltip": "^1.1.6", diff --git a/packages/components/src/ui/index.ts b/packages/components/src/ui/index.ts index 8e2550a..bb9c48b 100644 --- a/packages/components/src/ui/index.ts +++ b/packages/components/src/ui/index.ts @@ -13,6 +13,7 @@ export * from './date-picker-field'; export * from './dropdown-menu'; export * from './form'; export * from './form-error-field'; +export * from './input-group'; export * from './label'; export * from './otp-input'; export * from './otp-input-field'; diff --git a/packages/components/src/ui/input-group.tsx b/packages/components/src/ui/input-group.tsx new file mode 100644 index 0000000..fd4e6b7 --- /dev/null +++ b/packages/components/src/ui/input-group.tsx @@ -0,0 +1,117 @@ +'use client'; + +import type * as React from 'react'; +import { cva, type VariantProps } from 'class-variance-authority'; + +import { cn } from './utils'; +import { Button } from './button'; +import { TextInput } from './text-input'; +import { Textarea } from './textarea'; + +function InputGroup({ className, ...props }: React.ComponentProps<'div'>) { + return ( + // biome-ignore lint/a11y/useSemanticElements: role="group" is appropriate for input groups per WAI-ARIA +
+ ); +} + +function InputGroupAddon({ + className, + align = 'start', + ...props +}: React.ComponentProps<'div'> & { align?: 'start' | 'end' }) { + const isPrefix = align === 'start'; + const isSuffix = align === 'end'; + + return ( +
+ ); +} + +const inputGroupButtonVariants = cva('flex items-center gap-2 text-sm shadow-none', { + variants: { + size: { + xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5", + sm: 'h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5', + 'icon-xs': 'size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0', + 'icon-sm': 'size-8 p-0 has-[>svg]:p-0', + }, + }, + defaultVariants: { + size: 'xs', + }, +}); + +function InputGroupButton({ + className, + type = 'button', + variant = 'ghost', + size = 'xs', + ...props +}: Omit, 'size'> & VariantProps) { + return ( +