import type { FieldValues, Path } from 'react-hook-form' import { useFormContext } from 'react-hook-form' import { texts, format } from '@/texts' interface SeoCharCounterHintProps { name: Path max: number min?: number } /** * Live `n/max` counter for an SEO/char-limited text field, rendered as the * field's `description` — shared across the admin CRUD form modals * (tags, event categories, blog articles) so the display logic and its * `max`/`min` thresholds live in one place instead of being hand-defined * per modal. `max`/`min` should always be passed from the exported * constants next to the corresponding zod schema, not bare literals. */ export function SeoCharCounterHint({ name, max, min }: SeoCharCounterHintProps) { const { watch } = useFormContext() // `watch(name)`'s return type doesn't fully resolve for a naked generic // `T extends FieldValues` (react-hook-form's conditional path-value type // needs a concrete field-map to compute against) — widen explicitly to // `unknown` and narrow via `typeof` rather than let it flow as `any`. const value: unknown = watch(name) const length = typeof value === 'string' ? value.length : 0 const tooShort = min !== undefined && length > 0 && length < min return ( max || tooShort ? 'text-fourth' : undefined}> {`${length.toLocaleString('fa-IR')}/${max.toLocaleString('fa-IR')}`} {min !== undefined ? format(texts.common.seoCharMinHint, { min: min.toLocaleString('fa-IR') }) : ''} ) }