From afb156b5fd858a2ccd9a829f1497d09c40b69ae1 Mon Sep 17 00:00:00 2001
From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com>
Date: Thu, 13 Nov 2025 00:21:55 +0000
Subject: [PATCH 1/5] feat: integrate shadcn/ui InputGroup component for
prefix/suffix functionality
- Add official shadcn/ui InputGroup component with proper accessibility
- Refactor TextField to use InputGroup when prefix/suffix props are provided
- Maintain backward compatibility with existing TextField API
- Deprecate legacy FieldPrefix/FieldSuffix components (kept for compatibility)
- Add biome-ignore comments for intentional WAI-ARIA role usage
- All existing tests pass with the new implementation
Benefits:
- Cleaner, more maintainable code structure
- Better accessibility with proper semantic markup
- Official shadcn/ui patterns and styling
- Support for inline-start, inline-end, block-start, block-end alignment
- No breaking changes - existing code continues to work
Requested by: Jake Ruesink
---
packages/components/package.json | 2 +-
packages/components/src/ui/index.ts | 1 +
packages/components/src/ui/input-group.tsx | 152 +++++++++++++++++++++
packages/components/src/ui/text-field.tsx | 52 ++++---
yarn.lock | 19 ++-
5 files changed, 204 insertions(+), 22 deletions(-)
create mode 100644 packages/components/src/ui/input-group.tsx
diff --git a/packages/components/package.json b/packages/components/package.json
index be7da4d3..f43ba8eb 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 8e2550a8..bb9c48ba 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 00000000..b859b62f
--- /dev/null
+++ b/packages/components/src/ui/input-group.tsx
@@ -0,0 +1,152 @@
+'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
+
textarea]:h-auto',
+
+ // Variants based on alignment.
+ 'has-[>[data-align=inline-start]]:[&>input]:pl-2',
+ 'has-[>[data-align=inline-end]]:[&>input]:pr-2',
+ 'has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3',
+ 'has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3',
+
+ // Focus state.
+ 'has-[[data-slot=input-group-control]:focus-visible]:ring-ring has-[[data-slot=input-group-control]:focus-visible]:ring-1',
+
+ // Error state.
+ 'has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40',
+
+ className,
+ )}
+ {...props}
+ />
+ );
+}
+
+const inputGroupAddonVariants = cva(
+ "text-muted-foreground flex h-auto cursor-text select-none items-center justify-center gap-2 py-1.5 text-sm font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
+ {
+ variants: {
+ align: {
+ 'inline-start': 'order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]',
+ 'inline-end': 'order-last pr-3 has-[>button]:mr-[-0.4rem] has-[>kbd]:mr-[-0.35rem]',
+ 'block-start':
+ '[.border-b]:pb-3 order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5',
+ 'block-end': '[.border-t]:pt-3 order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5',
+ },
+ },
+ defaultVariants: {
+ align: 'inline-start',
+ },
+ },
+);
+
+function InputGroupAddon({
+ className,
+ align = 'inline-start',
+ ...props
+}: React.ComponentProps<'div'> & VariantProps
) {
+ return (
+ // biome-ignore lint/a11y/useSemanticElements: role="group" is appropriate for input group addons per WAI-ARIA
+ // biome-ignore lint/a11y/useKeyWithClickEvents: onClick is for focus management, not interactive action
+ {
+ if ((e.target as HTMLElement).closest('button')) {
+ return;
+ }
+ e.currentTarget.parentElement?.querySelector('input')?.focus();
+ }}
+ {...props}
+ />
+ );
+}
+
+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 (
+
+ );
+}
+
+function InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {
+ return (
+
+ );
+}
+
+function InputGroupInput({ className, ...props }: React.ComponentProps<'input'>) {
+ return (
+
+ );
+}
+
+function InputGroupTextarea({ className, ...props }: React.ComponentProps<'textarea'>) {
+ return (
+
+ );
+}
+
+export { InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InputGroupInput, InputGroupTextarea };
diff --git a/packages/components/src/ui/text-field.tsx b/packages/components/src/ui/text-field.tsx
index efcc3ba0..265d1945 100644
--- a/packages/components/src/ui/text-field.tsx
+++ b/packages/components/src/ui/text-field.tsx
@@ -10,8 +10,13 @@ import {
FormMessage,
} from './form';
import { type InputProps, TextInput } from './text-input';
+import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText } from './input-group';
import { cn } from './utils';
+/**
+ * @deprecated Use InputGroupAddon with InputGroupText instead
+ * These components are kept for backward compatibility but will be removed in a future version.
+ */
export const FieldPrefix = ({ children, className }: { children: React.ReactNode; className?: string }) => {
return (
{
return (
{
+ // Use the new InputGroup pattern when prefix or suffix is provided
+ const hasAddon = prefix || suffix;
+
return (
{label && {label}}
-
- {prefix && {prefix}}
+ {hasAddon ? (
+ // New shadcn/ui InputGroup pattern
+
+
+ {prefix && (
+
+ {prefix}
+
+ )}
+
+ {suffix && (
+
+ {suffix}
+
+ )}
+
+
+ ) : (
+ // Original pattern without addons
-
+
- {suffix && {suffix}}
-
+ )}
{description && {description}}
{fieldState.error && (
{fieldState.error.message}
diff --git a/yarn.lock b/yarn.lock
index 8a0053a1..42634fcb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1729,7 +1729,7 @@ __metadata:
"@radix-ui/react-select": "npm:^2.2.6"
"@radix-ui/react-separator": "npm:^1.1.6"
"@radix-ui/react-slider": "npm:^1.3.4"
- "@radix-ui/react-slot": "npm:^1.2.3"
+ "@radix-ui/react-slot": "npm:^1.2.4"
"@radix-ui/react-switch": "npm:^1.1.2"
"@radix-ui/react-tabs": "npm:^1.1.11"
"@radix-ui/react-tooltip": "npm:^1.1.6"
@@ -2639,7 +2639,7 @@ __metadata:
languageName: node
linkType: hard
-"@radix-ui/react-slot@npm:1.2.3, @radix-ui/react-slot@npm:^1.2.3":
+"@radix-ui/react-slot@npm:1.2.3":
version: 1.2.3
resolution: "@radix-ui/react-slot@npm:1.2.3"
dependencies:
@@ -2654,6 +2654,21 @@ __metadata:
languageName: node
linkType: hard
+"@radix-ui/react-slot@npm:^1.2.4":
+ version: 1.2.4
+ resolution: "@radix-ui/react-slot@npm:1.2.4"
+ dependencies:
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/8b719bb934f1ae5ac0e37214783085c17c2f1080217caf514c1c6cc3d9ca56c7e19d25470b26da79aa6e605ab36589edaade149b76f5fc0666f1063e2fc0a0dc
+ languageName: node
+ linkType: hard
+
"@radix-ui/react-switch@npm:^1.1.2":
version: 1.2.6
resolution: "@radix-ui/react-switch@npm:1.2.6"
From 1d3809de8b99eca04fd4b166d42fceb4f836d43d Mon Sep 17 00:00:00 2001
From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com>
Date: Thu, 13 Nov 2025 01:05:03 +0000
Subject: [PATCH 2/5] refactor: match InputGroup styling to original Lambda
Curry aesthetic
Update InputGroup component styles to match the simpler, cleaner look of the
original FieldPrefix/FieldSuffix implementation instead of shadcn's default styling.
Changes:
- Simplified InputGroup wrapper: removed shadow-xs, dark mode backgrounds, complex borders
- Updated to use simple focus-within ring (matching original wrapper behavior)
- Changed InputGroupAddon to use text-base (not text-sm) and gray-500/gray-700 colors
- Added proper border styling: border-y + border-l/r for prefix/suffix
- Simplified InputGroupText to just whitespace-nowrap (matching original)
- Updated InputGroupInput to conditionally remove borders/radius based on addons
Result: Inputs with prefix/suffix now match the original Lambda Curry design
while using the official shadcn/ui component architecture underneath.
Requested by: Jake Ruesink
---
packages/components/src/ui/input-group.tsx | 42 ++++++++++++----------
1 file changed, 23 insertions(+), 19 deletions(-)
diff --git a/packages/components/src/ui/input-group.tsx b/packages/components/src/ui/input-group.tsx
index b859b62f..d1cad6d5 100644
--- a/packages/components/src/ui/input-group.tsx
+++ b/packages/components/src/ui/input-group.tsx
@@ -15,20 +15,15 @@ function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
data-slot="input-group"
role="group"
className={cn(
- 'group/input-group border-input dark:bg-input/30 shadow-xs relative flex w-full min-w-0 items-center rounded-md border outline-none transition-[color,box-shadow]',
- 'h-9 has-[>textarea]:h-auto',
+ // Match original TextField wrapper styling: simple border with focus-within ring
+ 'group/input-group flex w-full rounded-md transition-all duration-200',
+ 'focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 focus-within:ring-offset-background',
- // Variants based on alignment.
+ // Variants based on alignment - simplified to match original behavior
'has-[>[data-align=inline-start]]:[&>input]:pl-2',
'has-[>[data-align=inline-end]]:[&>input]:pr-2',
- 'has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3',
- 'has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3',
-
- // Focus state.
- 'has-[[data-slot=input-group-control]:focus-visible]:ring-ring has-[[data-slot=input-group-control]:focus-visible]:ring-1',
-
- // Error state.
- 'has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40',
+ 'has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3',
+ 'has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3',
className,
)}
@@ -38,15 +33,18 @@ function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
}
const inputGroupAddonVariants = cva(
- "text-muted-foreground flex h-auto cursor-text select-none items-center justify-center gap-2 py-1.5 text-sm font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
+ // Match original FieldPrefix/FieldSuffix styling: simple borders with gray text
+ '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',
{
variants: {
align: {
- 'inline-start': 'order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]',
- 'inline-end': 'order-last pr-3 has-[>button]:mr-[-0.4rem] has-[>kbd]:mr-[-0.35rem]',
- 'block-start':
- '[.border-b]:pb-3 order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5',
- 'block-end': '[.border-t]:pt-3 order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5',
+ // inline-start = prefix (left side)
+ 'inline-start': 'order-first pl-3 pr-0 border-l rounded-l-md',
+ // inline-end = suffix (right side)
+ 'inline-end': 'order-last pr-3 pl-0 border-r rounded-r-md',
+ // block alignment for advanced use cases
+ 'block-start': 'order-first w-full justify-start px-3 pt-3 pb-2',
+ 'block-end': 'order-last w-full justify-start px-3 pt-2 pb-3',
},
},
defaultVariants: {
@@ -115,7 +113,8 @@ function InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {
return (
)
[data-align=inline-start]]:rounded-l-none group-has-[>[data-align=inline-start]]:border-l-0',
+ 'group-has-[>[data-align=inline-end]]:rounded-r-none group-has-[>[data-align=inline-end]]:border-r-0',
className,
)}
{...props}
From 7dd128bba04687e4020aee4cfa77aa1265b07172 Mon Sep 17 00:00:00 2001
From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com>
Date: Thu, 13 Nov 2025 01:10:23 +0000
Subject: [PATCH 3/5] fix: properly coordinate borders and border-radius
between input and addons
Fix the border and border-radius coordination so prefix/suffix addons connect
seamlessly with the input field without visible gaps.
Changes:
- Move border/radius removal logic from InputGroupInput to TextField
- TextField now explicitly passes 'rounded-l-none border-l-0' when prefix exists
- TextField now explicitly passes 'rounded-r-none border-r-0' when suffix exists
- Simplified InputGroupInput to just handle base styling
- This matches the original implementation's approach exactly
Result: Borders and corners now connect cleanly between addons and input,
matching the original FieldPrefix/FieldSuffix behavior.
Requested by: Jake Ruesink
---
packages/components/src/ui/input-group.tsx | 5 +----
packages/components/src/ui/text-field.tsx | 11 ++++++++++-
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/packages/components/src/ui/input-group.tsx b/packages/components/src/ui/input-group.tsx
index d1cad6d5..3dc81e96 100644
--- a/packages/components/src/ui/input-group.tsx
+++ b/packages/components/src/ui/input-group.tsx
@@ -128,11 +128,8 @@ function InputGroupInput({ className, ...props }: React.ComponentProps<'input'>)
data-slot="input-group-control"
className={cn(
// Match original input styling but remove focus ring/offset (handled by wrapper)
- // Remove left border and radius if prefix exists, remove right if suffix exists
+ // Border removal for prefix/suffix should be handled by the parent component
'flex-1 focus-visible:ring-0 focus-visible:ring-offset-0 border-input',
- // Conditionally remove borders based on presence of addons
- 'group-has-[>[data-align=inline-start]]:rounded-l-none group-has-[>[data-align=inline-start]]:border-l-0',
- 'group-has-[>[data-align=inline-end]]:rounded-r-none group-has-[>[data-align=inline-end]]:border-r-0',
className,
)}
{...props}
diff --git a/packages/components/src/ui/text-field.tsx b/packages/components/src/ui/text-field.tsx
index 265d1945..bf48a4ac 100644
--- a/packages/components/src/ui/text-field.tsx
+++ b/packages/components/src/ui/text-field.tsx
@@ -96,7 +96,16 @@ export const TextField = function TextField({
{prefix}
)}
-
+
{suffix && (
{suffix}
From 6319b2107f21d3e7c28c9267e65bc66f19d44024 Mon Sep 17 00:00:00 2001
From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com>
Date: Thu, 13 Nov 2025 01:17:35 +0000
Subject: [PATCH 4/5] 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
---
packages/components/src/ui/input-group.tsx | 72 ++++++----------------
packages/components/src/ui/text-field.tsx | 38 +-----------
2 files changed, 20 insertions(+), 90 deletions(-)
diff --git a/packages/components/src/ui/input-group.tsx b/packages/components/src/ui/input-group.tsx
index 3dc81e96..fd4e6b7e 100644
--- a/packages/components/src/ui/input-group.tsx
+++ b/packages/components/src/ui/input-group.tsx
@@ -15,16 +15,9 @@ function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
data-slot="input-group"
role="group"
className={cn(
- // Match original TextField wrapper styling: simple border with focus-within ring
- 'group/input-group flex w-full rounded-md transition-all duration-200',
+ // Simple wrapper with focus-within ring, matching original design
+ 'group flex w-full rounded-md transition-all duration-200',
'focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 focus-within:ring-offset-background',
-
- // Variants based on alignment - simplified to match original behavior
- 'has-[>[data-align=inline-start]]:[&>input]:pl-2',
- 'has-[>[data-align=inline-end]]:[&>input]:pr-2',
- 'has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3',
- 'has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3',
-
className,
)}
{...props}
@@ -32,46 +25,26 @@ function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
);
}
-const inputGroupAddonVariants = cva(
- // Match original FieldPrefix/FieldSuffix styling: simple borders with gray text
- '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',
- {
- variants: {
- align: {
- // inline-start = prefix (left side)
- 'inline-start': 'order-first pl-3 pr-0 border-l rounded-l-md',
- // inline-end = suffix (right side)
- 'inline-end': 'order-last pr-3 pl-0 border-r rounded-r-md',
- // block alignment for advanced use cases
- 'block-start': 'order-first w-full justify-start px-3 pt-3 pb-2',
- 'block-end': 'order-last w-full justify-start px-3 pt-2 pb-3',
- },
- },
- defaultVariants: {
- align: 'inline-start',
- },
- },
-);
-
function InputGroupAddon({
className,
- align = 'inline-start',
+ align = 'start',
...props
-}: React.ComponentProps<'div'> & VariantProps) {
+}: React.ComponentProps<'div'> & { align?: 'start' | 'end' }) {
+ const isPrefix = align === 'start';
+ const isSuffix = align === 'end';
+
return (
- // biome-ignore lint/a11y/useSemanticElements: role="group" is appropriate for input group addons per WAI-ARIA
- // biome-ignore lint/a11y/useKeyWithClickEvents: onClick is for focus management, not interactive action
{
- if ((e.target as HTMLElement).closest('button')) {
- return;
- }
- e.currentTarget.parentElement?.querySelector('input')?.focus();
- }}
+ className={cn(
+ // Base styling matching original FieldPrefix/FieldSuffix
+ 'flex h-10 items-center text-base text-gray-500 group-focus-within:text-gray-700 transition-colors duration-200',
+ 'border border-input bg-background',
+ // Prefix styling (left side)
+ isPrefix && 'pl-3 pr-0 rounded-l-md border-r-0',
+ // Suffix styling (right side)
+ isSuffix && 'pr-3 pl-0 rounded-r-md border-l-0',
+ className,
+ )}
{...props}
/>
);
@@ -110,16 +83,7 @@ function InputGroupButton({
}
function InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {
- return (
-
- );
+ return
;
}
function InputGroupInput({ className, ...props }: React.ComponentProps<'input'>) {
diff --git a/packages/components/src/ui/text-field.tsx b/packages/components/src/ui/text-field.tsx
index bf48a4ac..4611fe25 100644
--- a/packages/components/src/ui/text-field.tsx
+++ b/packages/components/src/ui/text-field.tsx
@@ -13,40 +13,6 @@ import { type InputProps, TextInput } from './text-input';
import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText } from './input-group';
import { cn } from './utils';
-/**
- * @deprecated Use InputGroupAddon with InputGroupText instead
- * These components are kept for backward compatibility but will be removed in a future version.
- */
-export const FieldPrefix = ({ children, className }: { children: React.ReactNode; className?: string }) => {
- return (
-
- {children}
-
- );
-};
-
-/**
- * @deprecated Use InputGroupAddon with InputGroupText instead
- * These components are kept for backward compatibility but will be removed in a future version.
- */
-export const FieldSuffix = ({ children, className }: { children: React.ReactNode; className?: string }) => {
- return (
-
- {children}
-
- );
-};
-
// Create a specific interface for the input props that includes className explicitly
export interface TextInputProps extends Omit
{
control?: Control;
@@ -92,7 +58,7 @@ export const TextField = function TextField({
{prefix && (
-
+
{prefix}
)}
@@ -107,7 +73,7 @@ export const TextField = function TextField({
})}
/>
{suffix && (
-
+
{suffix}
)}
From 9caf059ff474290b7c8734d2eb9e4f532b864c85 Mon Sep 17 00:00:00 2001
From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com>
Date: Thu, 13 Nov 2025 01:19:21 +0000
Subject: [PATCH 5/5] fix: resolve TypeScript errors in TextField and Storybook
- Fix className prop access in TextField InputGroupInput component
- Fix Storybook story type definitions in select-alignment.stories.tsx
- Remove invalid focusTrap option from userEvent.keyboard call
Fixes failing typecheck in PR quality checks workflow.
---
apps/docs/src/ui/select-alignment.stories.tsx | 6 +++++-
packages/components/src/ui/text-field.tsx | 2 +-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/apps/docs/src/ui/select-alignment.stories.tsx b/apps/docs/src/ui/select-alignment.stories.tsx
index 955af9d5..163676c3 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/src/ui/text-field.tsx b/packages/components/src/ui/text-field.tsx
index 4611fe25..5ea07357 100644
--- a/packages/components/src/ui/text-field.tsx
+++ b/packages/components/src/ui/text-field.tsx
@@ -67,7 +67,7 @@ export const TextField = function TextField({
{...props}
ref={ref}
aria-invalid={fieldState.error ? 'true' : 'false'}
- className={cn(props.className, {
+ className={cn(className, {
'rounded-l-none border-l-0': prefix,
'rounded-r-none border-r-0': suffix,
})}