mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-26 20:12:38 +08:00
feat(input): refactor input component to support compound pattern
Add new Input component with support for Password and Button variants through compound pattern. Move input implementation to new directory structure and enhance with label and caption support. Remove old input implementation.
This commit is contained in:
parent
13cacaba7f
commit
cad71c3af7
@ -84,7 +84,7 @@ export { Sortable } from './composites/Sortable'
|
||||
export * from './primitives/button'
|
||||
export * from './primitives/command'
|
||||
export * from './primitives/dialog'
|
||||
export * from './primitives/input'
|
||||
export * from './primitives/Input'
|
||||
export * from './primitives/popover'
|
||||
export * from './primitives/radioGroup'
|
||||
export * from './primitives/shadcn-io/dropzone'
|
||||
|
||||
1
packages/ui/src/components/primitives/Input/button.tsx
Normal file
1
packages/ui/src/components/primitives/Input/button.tsx
Normal file
@ -0,0 +1 @@
|
||||
export function WithButton() {}
|
||||
14
packages/ui/src/components/primitives/Input/index.tsx
Normal file
14
packages/ui/src/components/primitives/Input/index.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import { WithButton } from './button'
|
||||
import { Input as InternalInput } from './input'
|
||||
import { Password } from './password'
|
||||
|
||||
type CompoundedComponent = typeof InternalInput & {
|
||||
Password: typeof Password
|
||||
Button: typeof WithButton
|
||||
}
|
||||
|
||||
const Input: CompoundedComponent = InternalInput as CompoundedComponent
|
||||
Input.Password = Password
|
||||
Input.Button = WithButton
|
||||
|
||||
export { Input }
|
||||
50
packages/ui/src/components/primitives/Input/input.tsx
Normal file
50
packages/ui/src/components/primitives/Input/input.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import { cn } from '@cherrystudio/ui/utils'
|
||||
import React from 'react'
|
||||
|
||||
interface BaseInputProps extends React.ComponentPropsWithRef<'input'> {
|
||||
startContent?: React.ReactNode
|
||||
endContent?: React.ReactNode
|
||||
}
|
||||
|
||||
interface WithLabel extends BaseInputProps {
|
||||
label: string
|
||||
caption?: string
|
||||
}
|
||||
|
||||
interface WithoutLabel extends BaseInputProps {
|
||||
label?: never
|
||||
caption?: never
|
||||
}
|
||||
|
||||
type InputProps = WithLabel | WithoutLabel
|
||||
|
||||
export function Input({ className, type, required, label, caption, ...props }: InputProps) {
|
||||
const id = React.useId()
|
||||
const input = (
|
||||
<input
|
||||
type={type}
|
||||
data-slot="input"
|
||||
id={id}
|
||||
className={cn(
|
||||
'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-2xs border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
||||
'focus-visible:border-primary focus-visible:ring-primary/50 focus-visible:ring-[3px]',
|
||||
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
|
||||
className
|
||||
)}
|
||||
required={required}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
if (label !== undefined) {
|
||||
return (
|
||||
<div className="flex flex-col w-full">
|
||||
<label htmlFor={id}>{label}</label>
|
||||
{input}
|
||||
{caption && <div className="text-muted-foreground">{caption}</div>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return input
|
||||
}
|
||||
1
packages/ui/src/components/primitives/Input/password.tsx
Normal file
1
packages/ui/src/components/primitives/Input/password.tsx
Normal file
@ -0,0 +1 @@
|
||||
export function Password() {}
|
||||
@ -1,20 +0,0 @@
|
||||
import { cn } from '@cherrystudio/ui/utils'
|
||||
import * as React from 'react'
|
||||
|
||||
function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
data-slot="input"
|
||||
className={cn(
|
||||
'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
||||
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
|
||||
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Input }
|
||||
Loading…
Reference in New Issue
Block a user