Компоненты
Markdown
Ограниченная разметка без зависимостей и без сырого HTML.
Ограниченный Markdown для текста, который пишут пользователи: описания задач, комментарии, заметки. Без зависимостей и без сырого HTML.
Пример
Что сделано
Переписали разбор входящих заявок: теперь они попадают сразу в колонку проекта, а не в общий список.
- проверка домена отправителя
- склейка дублей по теме письма
X-Request-Idв каждом ответе
Осталось решить, что делать с письмами без темы.
Подробности — в описании задачи.
import { Markdown, MarkdownInline } from "@toimetdev/pathlogs-core";
<Markdown text={task.description} mentions={members.map((m) => m.name)} />
// только инлайн-разметка — для пунктов списков и однострочных подписей
<MarkdownInline text={item.title} />Что поддерживается
# Заголовок (уровни 1–3)
**жирный** *курсив* ~~зачёркнутый~~ `код`
- маркированный список
1. нумерованный список
> цитата
---
[ссылка](https://example.com)
```ts
блок кода
```Уровень заголовка ограничен тремя, а сам заголовок рендерится абзацем с крупным начертанием: пользовательский текст не должен вмешиваться в структуру заголовков страницы и ломать её вёрстку.
Безопасность
<script>alert(1)</script> — остаётся текстом.
[Опасная ссылка](javascript:alert(1)) — ссылкой не становится.
Обычная ссылка — становится.
<Markdown text={"<script>alert(1)</script> — остаётся текстом.\n\n[Опасная](javascript:alert(1)) — не ссылка."} />Картинок нет намеренно: они позволяют утащить IP читателя на чужой сервер и ломают вёрстку списков.
Упоминания
Список известных имён подсвечивает @упоминания в тексте:
<Markdown text={comment.body} mentions={project.members.map((m) => m.name)} />Имена сортируются от длинных к коротким: иначе «@Иван» съел бы начало «@Иван Петров», и упоминание распалось бы на подсветку и хвост текста. Спецсимволы в именах экранируются — имя с точкой не превратится в «любой символ».
Разбор отдельно
| Проп | Тип | По умолчанию | Описание |
|---|---|---|---|
text* | string | — | Исходный текст. |
mentions | string[] | — | Имена для подсветки @упоминаний. |
className | string | — | Дополнительные классы контейнера. |
text*stringИсходный текст.
mentionsstring[]Имена для подсветки @упоминаний.
classNamestringДополнительные классы контейнера.
Грамматика доступна и без React — например, для оглавления или поиска:
import { parseBlocks, parseInline, parseInlineWithMentions } from "@toimetdev/pathlogs-core";
parseBlocks("# Заголовок\n\nтекст");
// [{ kind: "h", level: 1, text: "Заголовок" }, { kind: "p", lines: ["текст"] }]
parseInline("**жирный**");
// [{ kind: "strong", children: [{ kind: "text", text: "жирный" }] }]