Files
mdm-ordinis/ordinis-admin-ui/src/ui/components/input.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

75 lines
2.7 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'
/**
* Text input — single-line. Использует наши tokens, focus-ring через accent.
*
* Поддерживает 2 режима:
* - "bare" (default) — просто <input>, для inline использования в кастомных
* layout'ах (см. SearchInput, FormGrid с FieldLabel separately).
* - "field" — когда передан label / hint / error, рендерится FormField
* обёртка с label сверху + hint/error снизу. Match'ит @nstart/ui TextInput API.
*/
export type InputProps = React.InputHTMLAttributes<HTMLInputElement> & {
/** Если задан — рендерится field-обёртка с label выше. */
label?: React.ReactNode
/** Optional helper text under input. */
hint?: React.ReactNode
/** Error message — overrides hint визуально, accent в pink. */
error?: React.ReactNode
/** Wrapper className когда rendering field-mode. */
containerClassName?: string
}
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
function Input(
{ className, type = 'text', label, hint, error, required, containerClassName, id, ...props },
ref,
) {
const autoId = React.useId()
const inputId = id ?? autoId
const inputEl = (
<input
id={inputId}
ref={ref}
type={type}
required={required}
aria-required={required || undefined}
aria-invalid={Boolean(error) || undefined}
className={cn(
'flex h-9 w-full rounded-md border border-line bg-surface px-3 py-1 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',
'file:border-0 file:bg-transparent file:text-sm file:font-medium',
error && 'border-pink focus-visible:ring-pink',
className,
)}
{...props}
/>
)
if (!label && !hint && !error) return inputEl
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>
)}
{inputEl}
{error ? (
<span className="text-xs text-pink">{error}</span>
) : hint ? (
<span className="text-xs text-mute">{hint}</span>
) : null}
</div>
)
},
)