Files
mdm-ordinis/ordinis-admin-ui/src/ui/components/textarea.tsx
T
Zimin A.N. 71432e9ae7 fix(fonts): align all text sizes to handoff spec via Tailwind theme overrides
Глобальные правки через @theme в styles.css вместо 200+ точечных правок:

- text-sm: 14px -> 13px (handoff workhorse — body, buttons, tabs)
- text-2xs: undefined -> 11px (handoff IDs, mono meta — было невидимо)
- @utility text-cap: 10.5px Tektur uppercase 0.10em (handoff caps)

Codemod (30 sites): text-2xs + uppercase + tracking-[0.10em] -> text-cap.
Sidebar section labels consolidated с explicit text-[10.5px] на text-cap.

Покрывает 64 text-sm + 148 text-2xs автоматически. Table cells (12.5px)
и page/modal titles (17px/22px) остаются explicit text-[Npx] arbitrary
values по месту — нет slots в Tailwind scale.
2026-05-11 14:12:57 +03:00

74 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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-cap font-medium font-display 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>
)
},
)