Skip to content

Commit 6319b21

Browse files
refactor: simplify InputGroup components and remove backward compatibility
Complete refactor focusing purely on the new InputGroup implementation without backward compatibility concerns. Changes: - Removed deprecated FieldPrefix and FieldSuffix components entirely - Simplified InputGroup wrapper to just focus-within ring - Rewrote InputGroupAddon with simple 'start'/'end' alignment (not inline-start/inline-end) - Removed CVA variants in favor of simple conditional logic (isPrefix/isSuffix) - Fixed height to h-10 for proper alignment with inputs - Explicitly remove borders on connecting sides (border-r-0 for prefix, border-l-0 for suffix) - Simplified InputGroupText to just whitespace-nowrap - TextField explicitly passes rounded-l-none/border-l-0 for prefix and rounded-r-none/border-r-0 for suffix Result: Clean, simple implementation matching the original Lambda Curry design with proper border/radius coordination between addons and input. Requested by: Jake Ruesink
1 parent 7dd128b commit 6319b21

2 files changed

Lines changed: 20 additions & 90 deletions

File tree

packages/components/src/ui/input-group.tsx

Lines changed: 18 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -15,63 +15,36 @@ function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
1515
data-slot="input-group"
1616
role="group"
1717
className={cn(
18-
// Match original TextField wrapper styling: simple border with focus-within ring
19-
'group/input-group flex w-full rounded-md transition-all duration-200',
18+
// Simple wrapper with focus-within ring, matching original design
19+
'group flex w-full rounded-md transition-all duration-200',
2020
'focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 focus-within:ring-offset-background',
21-
22-
// Variants based on alignment - simplified to match original behavior
23-
'has-[>[data-align=inline-start]]:[&>input]:pl-2',
24-
'has-[>[data-align=inline-end]]:[&>input]:pr-2',
25-
'has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3',
26-
'has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3',
27-
2821
className,
2922
)}
3023
{...props}
3124
/>
3225
);
3326
}
3427

35-
const inputGroupAddonVariants = cva(
36-
// Match original FieldPrefix/FieldSuffix styling: simple borders with gray text
37-
'flex h-full text-base items-center text-gray-500 group-focus-within:text-gray-700 transition-colors duration-200 border-y border-input bg-background',
38-
{
39-
variants: {
40-
align: {
41-
// inline-start = prefix (left side)
42-
'inline-start': 'order-first pl-3 pr-0 border-l rounded-l-md',
43-
// inline-end = suffix (right side)
44-
'inline-end': 'order-last pr-3 pl-0 border-r rounded-r-md',
45-
// block alignment for advanced use cases
46-
'block-start': 'order-first w-full justify-start px-3 pt-3 pb-2',
47-
'block-end': 'order-last w-full justify-start px-3 pt-2 pb-3',
48-
},
49-
},
50-
defaultVariants: {
51-
align: 'inline-start',
52-
},
53-
},
54-
);
55-
5628
function InputGroupAddon({
5729
className,
58-
align = 'inline-start',
30+
align = 'start',
5931
...props
60-
}: React.ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>) {
32+
}: React.ComponentProps<'div'> & { align?: 'start' | 'end' }) {
33+
const isPrefix = align === 'start';
34+
const isSuffix = align === 'end';
35+
6136
return (
62-
// biome-ignore lint/a11y/useSemanticElements: role="group" is appropriate for input group addons per WAI-ARIA
63-
// biome-ignore lint/a11y/useKeyWithClickEvents: onClick is for focus management, not interactive action
6437
<div
65-
role="group"
66-
data-slot="input-group-addon"
67-
data-align={align}
68-
className={cn(inputGroupAddonVariants({ align }), className)}
69-
onClick={(e) => {
70-
if ((e.target as HTMLElement).closest('button')) {
71-
return;
72-
}
73-
e.currentTarget.parentElement?.querySelector('input')?.focus();
74-
}}
38+
className={cn(
39+
// Base styling matching original FieldPrefix/FieldSuffix
40+
'flex h-10 items-center text-base text-gray-500 group-focus-within:text-gray-700 transition-colors duration-200',
41+
'border border-input bg-background',
42+
// Prefix styling (left side)
43+
isPrefix && 'pl-3 pr-0 rounded-l-md border-r-0',
44+
// Suffix styling (right side)
45+
isSuffix && 'pr-3 pl-0 rounded-r-md border-l-0',
46+
className,
47+
)}
7548
{...props}
7649
/>
7750
);
@@ -110,16 +83,7 @@ function InputGroupButton({
11083
}
11184

11285
function InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {
113-
return (
114-
<span
115-
className={cn(
116-
// Match original FieldPrefix/FieldSuffix inner span: simple whitespace-nowrap
117-
'whitespace-nowrap',
118-
className,
119-
)}
120-
{...props}
121-
/>
122-
);
86+
return <span className={cn('whitespace-nowrap', className)} {...props} />;
12387
}
12488

12589
function InputGroupInput({ className, ...props }: React.ComponentProps<'input'>) {

packages/components/src/ui/text-field.tsx

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,6 @@ import { type InputProps, TextInput } from './text-input';
1313
import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText } from './input-group';
1414
import { cn } from './utils';
1515

16-
/**
17-
* @deprecated Use InputGroupAddon with InputGroupText instead
18-
* These components are kept for backward compatibility but will be removed in a future version.
19-
*/
20-
export const FieldPrefix = ({ children, className }: { children: React.ReactNode; className?: string }) => {
21-
return (
22-
<div
23-
className={cn(
24-
'flex h-full text-base items-center pl-3 pr-0 text-gray-500 group-focus-within:text-gray-700 transition-colors duration-200 border-y border-l border-input rounded-l-md bg-background',
25-
className,
26-
)}
27-
>
28-
<span className="whitespace-nowrap">{children}</span>
29-
</div>
30-
);
31-
};
32-
33-
/**
34-
* @deprecated Use InputGroupAddon with InputGroupText instead
35-
* These components are kept for backward compatibility but will be removed in a future version.
36-
*/
37-
export const FieldSuffix = ({ children, className }: { children: React.ReactNode; className?: string }) => {
38-
return (
39-
<div
40-
className={cn(
41-
'flex h-full text-base items-center pr-3 pl-0 text-gray-500 group-focus-within:text-gray-700 transition-colors duration-200 border-y border-r border-input rounded-r-md bg-background',
42-
className,
43-
)}
44-
>
45-
<span className="whitespace-nowrap">{children}</span>
46-
</div>
47-
);
48-
};
49-
5016
// Create a specific interface for the input props that includes className explicitly
5117
export interface TextInputProps extends Omit<InputProps, 'prefix' | 'suffix'> {
5218
control?: Control<FieldValues>;
@@ -92,7 +58,7 @@ export const TextField = function TextField({
9258
<FormControl Component={components?.FormControl}>
9359
<InputGroup>
9460
{prefix && (
95-
<InputGroupAddon>
61+
<InputGroupAddon align="start">
9662
<InputGroupText>{prefix}</InputGroupText>
9763
</InputGroupAddon>
9864
)}
@@ -107,7 +73,7 @@ export const TextField = function TextField({
10773
})}
10874
/>
10975
{suffix && (
110-
<InputGroupAddon align="inline-end">
76+
<InputGroupAddon align="end">
11177
<InputGroupText>{suffix}</InputGroupText>
11278
</InputGroupAddon>
11379
)}

0 commit comments

Comments
 (0)