본문으로 건너뛰기

마크다운

메시지 · 댓글 · 문서 · AI 답을 한 부품이 같은 계약으로 그립니다. 편집기와 같은 원문이 같은 그림이 됩니다.

요소 덮어쓰기(components)는 열지 않습니다. 앱마다 덮어 쓰면 취소선 · 링크 · 표 · 할 일 규칙이 다시 갈라집니다. 원시 HTML 은 실행하지 않고 원문을 읽기 전용 칸으로 보입니다. 흐르는 답은 굳은 블록과 꼬리로 나눠 그리고, 블록마다 따로 파싱하므로 다른 블록에 있는 참조식 링크 정의([1]: url)는 풀리지 않습니다.

import
import { Markdown } from "@uyoolabs/ui/markdown";
설치
pnpm add react-markdown remark-gfm remark-breaks (./markdown 의 선택 peer)
고르는 법
채널 메시지 · 댓글 → variant="message" · "comment"(14 · 줄바꿈 하나 = br · 제목 한 단계 내림). 문서 읽기 화면 → "document"(콘텐츠 언어의 명조 · 읽기 폭 · h1 허용). 사이드 패널 · 스레드 → size="sm". AI 답 → streaming.
쓰지 않는 경우
편집할 글에는 편집기를 씁니다(이 부품은 읽기 전용). 사용자 입력이 아닌 화면 문구에 마크다운을 쓰지 않습니다. 렌더마다 새 mentions · 플러그인 배열을 넘기지 않습니다(useMemo).

Markdown

멘션 · 할 일 · 인용 · 표 · 원시 HTML. 인용은 세로 강조선 대신 여는 따옴표와 파인 면입니다.

재시도 정책 정리

님, 실패한 결제는 세 번까지 다시 시도합니다. 간격은 maxAttempts 로 바꿉니다. 자세한 값은 PG 문서 (새 창)를 봅니다.

처리 기간은 3~5일, 환불은 7~9일입니다. 다음 주 화요일 배포 → 목요일로 미뤘습니다.

  • 웹훅 서명 검증 —
  • 재시도 큐 만들기
  • 알림 문구 정하기

같은 카드로 하루 세 번 넘게 실패하면 사람에게 넘긴다.

시도간격알림
11분—
210분채널
HTML 원문 — 그리지 않습니다<iframe src="https://x.example"></iframe>

onOpen: —

키동작
Tab·Enter링크로 이동 · 멘션은 onOpen(HoverCard — Esc 로 닫고 멘션으로)
Tab·←·→넘치는 표 · 코드에 들어와 민다
할 일 체크포커스를 받지 않는다(읽기 전용)

흐르는 중

끝에 2px 커서(aria-hidden)와 aria-busy. 줄인 모션에서는 커서가 깜빡이지 않습니다. 완료 알림은 AI 패널이 한 번만 냅니다.

재시도는 지수 백오프로 늘립니다.

  1. 첫 시도는 1분 뒤
  2. 둘째는 10분 뒤
ts
await retry(charge, { maxAttempts: 3, base: 60_000 });

세 번 모두 실패하면 담당자에게 알림을 보냅니다.

마크다운 계약

원문을 어떻게 그리는가. 편집기 스파이크(docs/spikes/0001)와 같은 계약입니다.

원문그림규칙
~~취소~~ · 3~5일취소선 · 글자 그대로remark-gfm singleTilde: false. 물결 하나는 글자다
[@김서연](mention:u_12)멘션 칩편집기와 같은 계약. 나를 부른 멘션은 data-self(primary 면)
[#일반](channel:c_1)채널 칩멘션과 같은 방식(결정 #33). channels.resolve
# 제목h2headingOffset 1. 제품 화면에 h1 금지, document 만 0
줄바꿈 하나message: br · document: 공백remark-breaks 는 message · comment 만
[문서](https://…) · /settings · //x.com새 창 + 아이콘 · 앱 안 · 새 창‘/’ 하나는 LinkProvider 로 앱 안 이동, ‘//’ 는 바깥. javascript: 는 href 를 지운다
```(언어 없음)CodeBlock(라벨 없음)인라인 코드로 그리지 않는다
- [x] 일읽기 전용 체크글머리 점 없음 · 이름 ‘완료: …’ · 줄을 긋지 않는다
<iframe> 등 HTML원문 칸실행 · 렌더하지 않는다. 주석은 버리고 <br> 은 줄바꿈

props

소스의 타입과 JSDoc 에서 생성한 표입니다. 컴포넌트를 고치면 pnpm gen 으로 다시 만듭니다.

Markdown

prop타입기본값설명
source필수string—마크다운 원문
variant"message" | "comment" | "document""message"message · comment: 14/1.6 · 줄바꿈 하나 = br · 제목 한 단계 내림. document: 콘텐츠 언어의 명조 · 읽기 폭 · 제목 그대로
size"sm" | "md""md"sm 13 — 사이드 패널 · 스레드
headingOffset0 | 1 | 2—제목을 내리는 단계. variant 기본값(message · comment 1, document 0)을 덮는다
breaksboolean—줄바꿈 하나를 br 로. variant 기본값(message · comment 켬, document 끔)을 덮는다
streamingboolean—흐르는 중(AI 답). 굳은 블록은 한 번만 그리고 꼬리만 다시 그린다. 끝에 커서 · aria-busy
mentionsMarkdownMentions—멘션 칩
channelsMarkdownChannels—채널 참조 칩
linkBasestring—‘/’ 로 시작하는 앱 안 링크의 앞(워크스페이스 경로 등)
remarkPluginsOptions["remarkPlugins"]—앱 remark 플러그인. 우리 플러그인(멘션 · 원시 HTML · 제목) 뒤에 돈다
rehypePluginsOptions["rehypePlugins"]—앱 rehype 플러그인(키 → 링크 등). code · pre 안은 건드리지 않게 플러그인이 스스로 거른다
componentsnever—요소 덮어쓰기는 열지 않는다. 앱마다 덮어 쓰면 링크 · 표 · 할 일 규칙이 다시 갈라진다
lang"ko" | "en" | "ja"—콘텐츠 언어. lang 속성 · 명조 · 기본 문구를 고른다
labelsPartial<MarkdownLabels>—기본 문구 중 바꿀 것만. 렌더마다 새 객체면 굳은 블록도 다시 그린다(useMemo 로 넘긴다)
classNamestring—