Merge branch 'feat/v1.2.3-textarea-and-prep' into 'main'
feat(admin-ui): shadcn TextArea (Stage 3.8a) See merge request 2-6/2-6-4/terravault/ordinis!38
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import * as React from 'react'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
/**
|
||||
* TextArea — multi-line text input с handoff tokens. Заменяет {@code @nstart/ui}
|
||||
* TextArea (Phase 3 migration step).
|
||||
*
|
||||
* Поддерживает 2 режима (как Input):
|
||||
* - "bare" — просто <textarea>, для inline использования.
|
||||
* - "field" — когда задан label/hint/error, рендерится FormField обёртка.
|
||||
*/
|
||||
export type TextAreaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement> & {
|
||||
/** Если задан — рендерится field-обёртка с label выше. */
|
||||
label?: React.ReactNode
|
||||
/** Optional helper text under textarea. */
|
||||
hint?: React.ReactNode
|
||||
/** Error message — overrides hint визуально, accent в pink. */
|
||||
error?: React.ReactNode
|
||||
/** Wrapper className когда rendering field-mode. */
|
||||
containerClassName?: string
|
||||
}
|
||||
|
||||
export const TextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(
|
||||
function TextArea(
|
||||
{ className, label, hint, error, required, containerClassName, id, rows = 4, ...props },
|
||||
ref,
|
||||
) {
|
||||
const autoId = React.useId()
|
||||
const inputId = id ?? autoId
|
||||
const textareaEl = (
|
||||
<textarea
|
||||
id={inputId}
|
||||
ref={ref}
|
||||
rows={rows}
|
||||
required={required}
|
||||
aria-required={required || undefined}
|
||||
aria-invalid={Boolean(error) || undefined}
|
||||
className={cn(
|
||||
'flex w-full rounded-md border border-line bg-surface px-3 py-2 text-sm text-ink',
|
||||
'placeholder:text-mute',
|
||||
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-bg',
|
||||
'disabled:cursor-not-allowed disabled:opacity-50',
|
||||
'resize-y min-h-[80px]',
|
||||
error && 'border-pink focus-visible:ring-pink',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
if (!label && !hint && !error) return textareaEl
|
||||
|
||||
return (
|
||||
<div className={cn('flex flex-col gap-1', containerClassName)}>
|
||||
{label && (
|
||||
<label
|
||||
htmlFor={inputId}
|
||||
className="text-2xs font-medium font-display uppercase tracking-[0.10em] text-mute leading-none"
|
||||
>
|
||||
{label}
|
||||
{required && <span className="text-pink ml-0.5">*</span>}
|
||||
</label>
|
||||
)}
|
||||
{textareaEl}
|
||||
{error ? (
|
||||
<span className="text-xs text-pink">{error}</span>
|
||||
) : hint ? (
|
||||
<span className="text-xs text-mute">{hint}</span>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
)
|
||||
@@ -35,6 +35,9 @@ export * from '@nstart/ui'
|
||||
export { Button, buttonVariants, type ButtonProps } from './components/button'
|
||||
export { Badge, type BadgeProps } from './components/badge'
|
||||
export { Alert, type AlertProps } from './components/alert'
|
||||
// TextArea override — shadcn с handoff tokens. Phase 3 migration step
|
||||
// (Stage 3.8a). API совместим с @nstart/ui TextArea (label/hint/error).
|
||||
export { TextArea, type TextAreaProps } from './components/textarea'
|
||||
|
||||
// === Handoff design system primitives — новые компоненты без nstart-аналога ===
|
||||
export { Cap, type CapProps } from './components/cap'
|
||||
|
||||
Reference in New Issue
Block a user