Programmer-RD-AI
feat: add Paragraph component and types for typography
a8aec61
import * as React from 'react'
import { cn } from '@/lib/utils'
type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement> & {
className?: string
value?: string
onChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void
}
const MIN_HEIGHT = 40
const MAX_HEIGHT = 96
const TextArea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, value, onChange, ...props }, forwardedRef) => {
const [showScroll, setShowScroll] = React.useState(false)
const textareaRef = React.useRef<HTMLTextAreaElement | null>(null)
const adjustHeight = React.useCallback(() => {
const textarea = textareaRef.current
if (!textarea) return
textarea.style.height = `${MIN_HEIGHT}px`
const { scrollHeight } = textarea
const newHeight = Math.min(Math.max(scrollHeight, MIN_HEIGHT), MAX_HEIGHT)
textarea.style.height = `${newHeight}px`
setShowScroll(scrollHeight > MAX_HEIGHT)
}, [])
const handleChange = React.useCallback(
(e: React.ChangeEvent<HTMLTextAreaElement>) => {
const cursorPosition = e.target.selectionStart
onChange?.(e)
requestAnimationFrame(() => {
adjustHeight()
if (textareaRef.current) {
textareaRef.current.setSelectionRange(
cursorPosition,
cursorPosition
)
}
})
},
[onChange, adjustHeight]
)
const handleRef = React.useCallback(
(node: HTMLTextAreaElement | null) => {
const ref = forwardedRef as
| React.MutableRefObject<HTMLTextAreaElement | null>
| ((instance: HTMLTextAreaElement | null) => void)
| null
if (typeof ref === 'function') {
ref(node)
} else if (ref) {
ref.current = node
}
textareaRef.current = node
},
[forwardedRef]
)
React.useEffect(() => {
if (textareaRef.current) {
adjustHeight()
}
}, [value, adjustHeight])
return (
<textarea
className={cn(
'w-full resize-none bg-transparent shadow-sm',
'rounded-xl border border-border',
'px-3 py-2',
'text-sm leading-5',
'placeholder:text-muted-foreground',
'focus-visible:ring-0.5 focus-visible:ring-ring focus-visible:border-primary/50 focus-visible:outline-none',
'disabled:cursor-not-allowed disabled:opacity-50',
showScroll ? 'overflow-y-auto' : 'overflow-hidden',
className
)}
style={{
minHeight: `${MIN_HEIGHT}px`,
height: `${MIN_HEIGHT}px`,
maxHeight: `${MAX_HEIGHT}px`
}}
ref={handleRef}
value={value}
onChange={handleChange}
{...props}
/>
)
}
)
TextArea.displayName = 'TextArea'
export type { TextareaProps }
export { TextArea }