Выбор тегов
Сделай компонент выбора тегов для статьи: пользователь набирает теги в одном поле, каждый введённый тег превращается в удаляемую метку. Выбранные теги показывай под полем и отдавай наружу через колбэк onChange.
tag-picker__docs-rules__claude-code__claude-opus-5__1 · 23.09.2026, 21:55:08 мск
Есть проблемы
Доки + правила · claude-opus-5 · Claude CodeКонтекст до задачи~23 785
Токенов на прогон50 500
Цена$0.296
Ошибок компилятора1
Первый вызов модели получил 49 037 токенов входа, включая системный промпт Claude Code. Контекст до задачи — оценка по длине текста, для русского текста она занижает число токенов в полтора-два раза.
Компилятор
- Строка 39 · TS2322
Type '{ id: string; ariaLabel: string; placeholder: string; value: string[]; onValueChange: (next: string[]) => void; }' is not assignable to type 'IntrinsicAttributes & JxTagInputProps'.
Выдуманные пропсы
JxTagInput.id
Линтер и покрытие
- inline-styleСтроки 34, 51Инлайновые стили вместо классов и токенов библиотеки
Компоненты библиотеки
JxChip, JxTagInput
Ожидались JxTagInput · покрытие 100%
Доки (llms-full.txt, ~22548) · Правила (jinx-ui, ~1083)
Вход 2 · выход 1 463 · из кэша 8 233 · в кэш 40 802 · 18 с
Рендер
Код компонента
tsx64 строки
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
import { useCallback } from 'react';
import { JxChip, JxTagInput, useControllableState } from '@jinx-ui/react';
const EMPTY_TAGS: string[] = [];
export interface ArticleTagPickerProps {
value?: string[];
defaultValue?: string[];
onChange?: (tags: string[]) => void;
label?: string;
placeholder?: string;
}
export default function ArticleTagPicker({
value,
defaultValue = EMPTY_TAGS,
onChange,
label = 'Теги статьи',
placeholder = 'Введите тег и нажмите Enter',
}: ArticleTagPickerProps) {
const [tags, setTags] = useControllableState<string[]>(value, defaultValue, onChange);
const handleChange = useCallback(
(next: string[]) => {
const normalized = next.map((tag) => tag.trim()).filter(Boolean);
setTags(normalized.filter((tag, index) => normalized.indexOf(tag) === index));
},
[setTags],
);
const removeTag = (tag: string) => handleChange(tags.filter((item) => item !== tag));
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
<label className="jx-label" htmlFor="article-tags">
{label}
</label>
<JxTagInput
id="article-tags"
ariaLabel={label}
placeholder={placeholder}
value={tags}
onValueChange={handleChange}
/>
{tags.length === 0 ? (
<p className="jx-input-help">Пока ничего не выбрано. Добавьте первый тег, чтобы статью было легче найти.</p>
) : (
<div
role="list"
aria-label="Выбранные теги"
style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}
>
{tags.map((tag) => (
<span role="listitem" key={tag}>
<JxChip removable onRemove={() => removeTag(tag)}>
{tag}
</JxChip>
</span>
))}
</div>
)}
</div>
);
}