ds-markdown 0.1.1 → 0.1.2-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +129 -240
- package/README.ja.md +209 -161
- package/README.ko.md +323 -236
- package/README.md +67 -37
- package/dist/cjs/Markdown/index.d.ts +2 -7
- package/dist/cjs/Markdown/index.js.map +1 -1
- package/dist/cjs/MarkdownCMD/index.d.ts +2 -2
- package/dist/cjs/MarkdownCMD/index.js +24 -18
- package/dist/cjs/MarkdownCMD/index.js.map +1 -1
- package/dist/cjs/defined.d.ts +14 -4
- package/dist/cjs/hooks/useTypingTask.d.ts +2 -0
- package/dist/cjs/hooks/useTypingTask.js +53 -2
- package/dist/cjs/hooks/useTypingTask.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -2
- package/dist/esm/Markdown/index.d.ts +2 -7
- package/dist/esm/Markdown/index.js.map +1 -1
- package/dist/esm/MarkdownCMD/index.d.ts +2 -2
- package/dist/esm/MarkdownCMD/index.js +24 -18
- package/dist/esm/MarkdownCMD/index.js.map +1 -1
- package/dist/esm/defined.d.ts +14 -4
- package/dist/esm/hooks/useTypingTask.d.ts +2 -0
- package/dist/esm/hooks/useTypingTask.js +53 -2
- package/dist/esm/hooks/useTypingTask.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/package.json +2 -2
package/README.ko.md
CHANGED
|
@@ -20,39 +20,31 @@
|
|
|
20
20
|
|
|
21
21
|
## ✨ 핵심 기능
|
|
22
22
|
|
|
23
|
-
###
|
|
23
|
+
### 🤖 **AI 대화 시나리오**
|
|
24
24
|
|
|
25
25
|
- [DeepSeek 웹사이트](https://chat.deepseek.com/) 채팅 응답 효과를 1:1로 재현
|
|
26
26
|
- 사고 과정(`thinking`)과 답변 내용(`answer`) 두 가지 모드 지원
|
|
27
|
-
-
|
|
28
|
-
- 라이트/다크 테마 지원, 다양한 시나리오에 완벽하게 대응
|
|
27
|
+
- 스트리밍 데이터에 완벽하게 적응, 사용자 입력에 대한 지연 없는 응답
|
|
29
28
|
|
|
30
|
-
###
|
|
29
|
+
### 📊 **콘텐츠 표시 시나리오**
|
|
31
30
|
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
31
|
+
- 코드 하이라이팅, 테이블, 목록 등을 포함한 완전한 Markdown 구문 지원
|
|
32
|
+
- 수식 렌더링 (KaTeX), `$...$` 및 `\[...\]` 구문 지원
|
|
33
|
+
- 라이트/다크 테마 지원, 다양한 제품 스타일에 적응
|
|
34
|
+
- remark/rehype 플러그인 확장을 지원하는 플러그인 아키텍처
|
|
35
|
+
|
|
36
|
+
### 🔧 **개발자 경험**
|
|
37
|
+
|
|
38
|
+
- 타이핑 중단 `stop` 및 재개 `resume` 지원
|
|
39
|
+
- 타이핑 비활성화 및 활성화 지원
|
|
35
40
|
|
|
36
41
|
### 🎬 **부드러운 애니메이션**
|
|
37
42
|
|
|
43
|
+
- 듀얼 타이머 모드 최적화, `requestAnimationFrame` 및 `setTimeout` 모드 지원
|
|
38
44
|
- 고주파 타이핑 지원(`requestAnimationFrame` 모드에서 `0ms`에 가까운 타이핑 간격 지원)
|
|
39
|
-
- 프레임 동기화 렌더링으로 브라우저
|
|
45
|
+
- 프레임 동기화 렌더링으로 브라우저 새로고침 속도와 완벽 매칭
|
|
40
46
|
- 스마트 문자 배치 처리로 더 자연스러운 시각적 효과
|
|
41
47
|
|
|
42
|
-
### 🔧 **유연하고 사용하기 쉬움**
|
|
43
|
-
|
|
44
|
-
- **선언적 API**: 간단한 시나리오에 적합, React 스타일
|
|
45
|
-
- **명령형 API**: 스트리밍 데이터에 적합, 더 나은 성능
|
|
46
|
-
- **네이티브 TypeScript 지원**: 완전한 타입 힌트
|
|
47
|
-
|
|
48
|
-
### 🧮 **수식 지원**
|
|
49
|
-
|
|
50
|
-
- **KaTeX 통합**: 고성능 수식 렌더링
|
|
51
|
-
- **플러그인 아키텍처**: 플러그인 시스템을 통한 유연한 설정
|
|
52
|
-
- **이중 구문 지원**: `$...$` 및 `\[...\]` 구분자
|
|
53
|
-
- **스트리밍 호환**: 타이핑 애니메이션에서 수식의 완벽한 지원
|
|
54
|
-
- **테마 적응**: 라이트/다크 테마에 자동 적응
|
|
55
|
-
|
|
56
48
|
---
|
|
57
49
|
|
|
58
50
|
## 📦 빠른 설치
|
|
@@ -72,39 +64,18 @@ pnpm add ds-markdown
|
|
|
72
64
|
|
|
73
65
|
설치 없이 브라우저에서 직접 사용할 수 있습니다:
|
|
74
66
|
|
|
67
|
+
[DEMO](https://stackblitz.com/edit/stackblitz-starters-7vcclcw7?file=index.html)
|
|
68
|
+
|
|
75
69
|
```html
|
|
76
|
-
<!-- 스타일
|
|
70
|
+
<!-- 스타일 가져오기, 필수 -->
|
|
77
71
|
<link rel="stylesheet" href="https://esm.sh/ds-markdown/dist/style.css" />
|
|
78
72
|
|
|
79
|
-
<!--
|
|
80
|
-
<
|
|
81
|
-
{
|
|
82
|
-
"imports": {
|
|
83
|
-
"react": "https://esm.sh/react@19.1.0",
|
|
84
|
-
"react-dom/client": "https://esm.sh/react-dom@19.1.0/client",
|
|
85
|
-
"ds-markdown": "https://esm.sh/ds-markdown"
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
</script>
|
|
89
|
-
<script type="module" src="https://esm.sh/tsx"></script>
|
|
90
|
-
|
|
91
|
-
<script type="text/babel">
|
|
92
|
-
import { createRoot } from 'react-dom/client';
|
|
93
|
-
import DsMarkdown from 'ds-markdown';
|
|
94
|
-
|
|
95
|
-
const markdown = `
|
|
96
|
-
# Hello ds-markdown
|
|
97
|
-
|
|
98
|
-
이것은 **고성능** 타이핑 애니메이션 컴포넌트입니다!
|
|
73
|
+
<!-- katex 수학 공식 스타일 가져오기, 필요한 경우만 -->
|
|
74
|
+
<link rel="stylesheet" href="https://esm.sh/ds-markdown/dist/katex.css" />
|
|
99
75
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
- 🎯 완벽한 구문 지원
|
|
104
|
-
`;
|
|
105
|
-
|
|
106
|
-
const root = createRoot(document.getElementById('root'));
|
|
107
|
-
root.render(<DsMarkdown interval={20}>{markdown}</DsMarkdown>);
|
|
76
|
+
<!-- 컴포넌트 가져오기 -->
|
|
77
|
+
<script type="module">
|
|
78
|
+
import Markdown from 'https://esm.sh/ds-markdown';
|
|
108
79
|
</script>
|
|
109
80
|
```
|
|
110
81
|
|
|
@@ -112,6 +83,8 @@ pnpm add ds-markdown
|
|
|
112
83
|
|
|
113
84
|
### 기본 사용법
|
|
114
85
|
|
|
86
|
+
[DEMO](https://stackblitz.com/edit/vitejs-vite-z94syu8j?file=src%2FApp.tsx)
|
|
87
|
+
|
|
115
88
|
```tsx
|
|
116
89
|
import DsMarkdown from 'ds-markdown';
|
|
117
90
|
import 'ds-markdown/style.css';
|
|
@@ -125,6 +98,48 @@ function App() {
|
|
|
125
98
|
}
|
|
126
99
|
```
|
|
127
100
|
|
|
101
|
+
### 타이핑 애니메이션 비활성화
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import DsMarkdown from 'ds-markdown';
|
|
105
|
+
import 'ds-markdown/style.css';
|
|
106
|
+
|
|
107
|
+
function StaticDemo() {
|
|
108
|
+
const [disableTyping, setDisableTyping] = useState(false);
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<div>
|
|
112
|
+
<button onClick={() => setDisableTyping(!disableTyping)}>{disableTyping ? '활성화' : '비활성화'}타이핑 효과</button>
|
|
113
|
+
|
|
114
|
+
<DsMarkdown interval={20} answerType="answer" disableTyping={disableTyping}>
|
|
115
|
+
# 정적 표시 모드 `disableTyping`이 `true`일 때, 콘텐츠는 타이핑 애니메이션 효과 없이 즉시 모두 표시됩니다. 이는 특정 시나리오에서 매우 유용합니다: - 📄 정적 문서 표시 - 🔄 표시 모드 전환 - ⚡
|
|
116
|
+
콘텐츠 빠른 미리보기
|
|
117
|
+
</DsMarkdown>
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 수학 공식 지원
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import DsMarkdown from 'ds-markdown';
|
|
127
|
+
// 공식을 표시해야 하는 경우 공식 변환 플러그인을 가져옵니다
|
|
128
|
+
import { katexPlugin } from 'ds-markdown/plugins';
|
|
129
|
+
import 'ds-markdown/style.css';
|
|
130
|
+
// 공식을 표시해야 하는 경우 수학 공식 스타일을 가져옵니다
|
|
131
|
+
import 'ds-markdown/katex.css';
|
|
132
|
+
|
|
133
|
+
function MathDemo() {
|
|
134
|
+
return (
|
|
135
|
+
<DsMarkdown interval={20} answerType="answer" plugins={[katexPlugin]} math={{ splitSymbol: 'dollar' }}>
|
|
136
|
+
# 피타고라스 정리 직각삼각형에서 빗변의 제곱은 두 직각변의 제곱의 합과 같습니다: $a^2 + b^2 = c^2$ 여기서: - $a$와 $b$는 직각변 - $c$는 빗변 고전적인 "구삼고사현오"의 경우: $c = \sqrt
|
|
137
|
+
{3 ^ (2 + 4) ^ 2} = \sqrt{25} = 5$
|
|
138
|
+
</DsMarkdown>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
128
143
|
### AI 대화 시나리오
|
|
129
144
|
|
|
130
145
|
```tsx
|
|
@@ -173,40 +188,75 @@ React 19는 많은 흥미로운 새 기능을 제공합니다:
|
|
|
173
188
|
|
|
174
189
|
## 📚 완전 API 문서
|
|
175
190
|
|
|
176
|
-
###
|
|
191
|
+
### 기본 내보내기 DsMarkdown 및 MarkdownCMD props
|
|
177
192
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
| `timerType` | `'setTimeout'` \| `'requestAnimationFrame'` | 타이머 타입 | 현재 기본값은 `setTimeout`, 나중에 `requestAnimationFrame`로 변경 예정 |
|
|
182
|
-
| `answerType` | `'thinking'` \| `'answer'` | 콘텐츠 타입 | `'answer'` |
|
|
183
|
-
| `theme` | `'light'` \| `'dark'` | 테마 타입 | `'light'` |
|
|
184
|
-
| `onEnd` | `(data: EndData) => void` | 타이핑 완료 콜백 | - |
|
|
185
|
-
| `onStart` | `(data: StartData) => void` | 타이핑 시작 콜백 | - |
|
|
186
|
-
| `onTypedChar` | `(data: CharData) => void` | 문자별 타이핑 콜백 | - |
|
|
193
|
+
```js
|
|
194
|
+
import DsMarkdown, { MarkdownCMD } from 'ds-markdown';
|
|
195
|
+
```
|
|
187
196
|
|
|
188
|
-
|
|
197
|
+
| 속성 | 타입 | 설명 | 기본값 |
|
|
198
|
+
| --------------- | --------------------------------------------- | -------------------------- | ---------------------------------------------------------------------- |
|
|
199
|
+
| `interval` | `number` | 타이핑 간격 (밀리초) | `30` |
|
|
200
|
+
| `timerType` | `'setTimeout'` \| `'requestAnimationFrame'` | 타이머 타입 | 현재 기본값은 `setTimeout`, 나중에 `requestAnimationFrame`로 변경 예정 |
|
|
201
|
+
| `answerType` | `'thinking'` \| `'answer'` | 콘텐츠 타입 (스타일 영향) | `'answer'` |
|
|
202
|
+
| `theme` | `'light'` \| `'dark'` | 테마 타입 | `'light'` |
|
|
203
|
+
| `plugins` | `IMarkdownPlugin[]` | 플러그인 설정 | `[]` |
|
|
204
|
+
| `math` | [IMarkdownMath](#IMarkdownMath) | 수학 공식 설정 | `{ splitSymbol: 'dollar' }` |
|
|
205
|
+
| `onEnd` | `(data: EndData) => void` | 타이핑 완료 콜백 | - |
|
|
206
|
+
| `onStart` | `(data: StartData) => void` | 타이핑 시작 콜백 | - |
|
|
207
|
+
| `onTypedChar` | `(data: `[ITypedChar](#ITypedChar)`) => void` | 문자별 타이핑 콜백 | - |
|
|
208
|
+
| `disableTyping` | `boolean` | 타이핑 애니메이션 비활성화 | `false` |
|
|
189
209
|
|
|
190
|
-
|
|
191
|
-
import { MarkdownCMD, MarkdownCMDRef } from 'ds-markdown';
|
|
210
|
+
> 참고: 타이핑 중에 `disableTyping`이 `true`에서 `false`로 변경되면 다음 타이핑 트리거 시 남은 모든 문자가 한 번에 표시됩니다.
|
|
192
211
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
212
|
+
### ITypedChar
|
|
213
|
+
|
|
214
|
+
| 속성 | 타입 | 설명 | 기본값 |
|
|
215
|
+
| -------------- | -------- | --------------------------- | ------ |
|
|
216
|
+
| `percent` | `number` | 타이핑 진행률 백분율 | `0` |
|
|
217
|
+
| `currentChar` | `string` | 현재 타이핑 중인 문자 | - |
|
|
218
|
+
| `currentIndex` | `number` | 전체 문자열에서 현재 인덱스 | `0` |
|
|
219
|
+
|
|
220
|
+
#### IMarkdownMath
|
|
221
|
+
|
|
222
|
+
| 속성 | 타입 | 설명 | 기본값 |
|
|
223
|
+
| ------------- | ------------------------- | ---------------- | ---------- |
|
|
224
|
+
| `splitSymbol` | `'dollar'` \| `'bracket'` | 수학 공식 구분자 | `'dollar'` |
|
|
225
|
+
|
|
226
|
+
**구분자 설명:**
|
|
227
|
+
|
|
228
|
+
- `'dollar'`: `$...$` 및 `$$...$$` 구문 사용
|
|
229
|
+
- `'bracket'`: `\(...\)` 및 `\[...\]` 구문 사용
|
|
230
|
+
|
|
231
|
+
#### IMarkdownPlugin
|
|
232
|
+
|
|
233
|
+
| 속성 | 타입 | 설명 | 기본값 |
|
|
234
|
+
| -------------- | ------------------------- | ---------------- | ------ |
|
|
235
|
+
| `remarkPlugin` | `unknown` | remark 플러그인 | - |
|
|
236
|
+
| `rehypePlugin` | `unknown` | rehype 플러그인 | - |
|
|
237
|
+
| `type` | `'buildIn'` \| `'custom'` | 플러그인 타입 | - |
|
|
238
|
+
| `id` | `any` | 플러그인 고유 ID | - |
|
|
239
|
+
|
|
240
|
+
### 컴포넌트 노출 메서드
|
|
241
|
+
|
|
242
|
+
#### 기본 내보내기 DsMarkdown
|
|
243
|
+
|
|
244
|
+
| 메서드 | 매개변수 | 설명 |
|
|
245
|
+
| -------- | -------- | --------------- |
|
|
246
|
+
| `stop` | - | 타이핑 일시정지 |
|
|
247
|
+
| `resume` | - | 타이핑 재개 |
|
|
248
|
+
|
|
249
|
+
#### MarkdownCMD 노출 메서드
|
|
199
250
|
|
|
200
251
|
| 메서드 | 매개변수 | 설명 |
|
|
201
252
|
| ----------------- | ------------------------------------------- | -------------------------- |
|
|
202
253
|
| `push` | `(content: string, answerType: AnswerType)` | 콘텐츠 추가 및 타이핑 시작 |
|
|
203
|
-
| `clear` | - | 모든
|
|
204
|
-
| `triggerWholeEnd` | - | 완료 콜백
|
|
205
|
-
|
|
206
|
-
| `
|
|
207
|
-
| `resume` | - | 타이핑 애니메이션 재개 |
|
|
254
|
+
| `clear` | - | 모든 콘텐츠 및 상태 지우기 |
|
|
255
|
+
| `triggerWholeEnd` | - | 수동으로 완료 콜백 트리거 |
|
|
256
|
+
| `stop` | - | 타이핑 일시정지 |
|
|
257
|
+
| `resume` | - | 타이핑 재개 |
|
|
208
258
|
|
|
209
|
-
**사용
|
|
259
|
+
**사용 예:**
|
|
210
260
|
|
|
211
261
|
```tsx
|
|
212
262
|
markdownRef.current?.stop(); // 애니메이션 일시정지
|
|
@@ -215,50 +265,168 @@ markdownRef.current?.resume(); // 애니메이션 재개
|
|
|
215
265
|
|
|
216
266
|
---
|
|
217
267
|
|
|
218
|
-
##
|
|
268
|
+
## 🧮 수학 공식 사용 가이드
|
|
269
|
+
|
|
270
|
+
[DEMO1: 피타고라스 정리](https://stackblitz.com/edit/vitejs-vite-z94syu8j?file=src%2FApp.tsx)
|
|
271
|
+
|
|
272
|
+
[DEMO2: 문제 해답](https://stackblitz.com/edit/vitejs-vite-xk9lxagc?file=README.md)
|
|
219
273
|
|
|
220
|
-
###
|
|
274
|
+
### 기본 구문
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
import { katexPlugin } from 'ds-markdown/plugins';
|
|
278
|
+
|
|
279
|
+
// 1. 수학 공식 지원 활성화
|
|
280
|
+
<DsMarkdown plugins={[katexPlugin]}>
|
|
281
|
+
# 수학 공식 예제
|
|
282
|
+
|
|
283
|
+
// 인라인 공식
|
|
284
|
+
이것은 인라인 공식입니다: $E = mc^2$
|
|
285
|
+
|
|
286
|
+
// 블록 공식
|
|
287
|
+
$$\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}$$
|
|
288
|
+
</DsMarkdown>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### 구분자 선택
|
|
292
|
+
|
|
293
|
+
```tsx
|
|
294
|
+
// 달러 기호 구분자 사용 (기본값)
|
|
295
|
+
<DsMarkdown
|
|
296
|
+
plugins={[katexPlugin]}
|
|
297
|
+
math={{ splitSymbol: 'dollar' }}
|
|
298
|
+
>
|
|
299
|
+
인라인: $a + b = c$
|
|
300
|
+
블록: $$\sum_{i=1}^{n} x_i = x_1 + x_2 + \cdots + x_n$$
|
|
301
|
+
</DsMarkdown>
|
|
302
|
+
|
|
303
|
+
// 괄호 구분자 사용
|
|
304
|
+
<DsMarkdown
|
|
305
|
+
plugins={[katexPlugin]}
|
|
306
|
+
math={{ splitSymbol: 'bracket' }}
|
|
307
|
+
>
|
|
308
|
+
인라인: \(a + b = c\)
|
|
309
|
+
블록: \[\sum_{i=1}^{n} x_i = x_1 + x_2 + \cdots + x_n\]
|
|
310
|
+
</DsMarkdown>
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### 스트리밍 수학 공식
|
|
314
|
+
|
|
315
|
+
```tsx
|
|
316
|
+
// 스트리밍 출력에서 수학 공식을 완벽하게 지원
|
|
317
|
+
const mathContent = [
|
|
318
|
+
'피타고라스 정리:',
|
|
319
|
+
'$a^2 + b^2 = c^2$',
|
|
320
|
+
'\n\n',
|
|
321
|
+
'여기서:',
|
|
322
|
+
'- $a$와 $b$는 직각변\n',
|
|
323
|
+
'- $c$는 빗변\n\n',
|
|
324
|
+
'고전적인 "구삼고사현오"의 경우:\n',
|
|
325
|
+
'$c = \\sqrt{3^2 + 4^2} = \\sqrt{25} = 5$\n\n',
|
|
326
|
+
'이 정리는 기하학에서 광범위하게 응용됩니다!',
|
|
327
|
+
];
|
|
328
|
+
|
|
329
|
+
mathContent.forEach((chunk) => {
|
|
330
|
+
markdownRef.current?.push(chunk, 'answer');
|
|
331
|
+
});
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### 스타일 커스터마이징
|
|
335
|
+
|
|
336
|
+
```css
|
|
337
|
+
/* 수학 공식 스타일 커스터마이징 */
|
|
338
|
+
.katex {
|
|
339
|
+
font-size: 1.1em;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.katex-display {
|
|
343
|
+
margin: 1em 0;
|
|
344
|
+
text-align: center;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/* 다크 테마 적응 */
|
|
348
|
+
[data-theme='dark'] .katex {
|
|
349
|
+
color: #e1e1e1;
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## 🔌 플러그인 시스템
|
|
356
|
+
|
|
357
|
+
### 내장 플러그인
|
|
358
|
+
|
|
359
|
+
#### KaTeX 수학 공식 플러그인
|
|
360
|
+
|
|
361
|
+
```tsx
|
|
362
|
+
import { katexPlugin } from 'ds-markdown/plugins';
|
|
363
|
+
|
|
364
|
+
// 수학 공식 지원 활성화
|
|
365
|
+
<DsMarkdown plugins={[katexPlugin]}>수학 공식: $E = mc^2$</DsMarkdown>;
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### 커스텀 플러그인
|
|
369
|
+
|
|
370
|
+
```tsx
|
|
371
|
+
import { createBuildInPlugin } from 'ds-markdown/plugins';
|
|
372
|
+
|
|
373
|
+
// 커스텀 플러그인 생성
|
|
374
|
+
const customPlugin = createBuildInPlugin({
|
|
375
|
+
remarkPlugin: yourRemarkPlugin,
|
|
376
|
+
rehypePlugin: yourRehypePlugin,
|
|
377
|
+
id: Symbol('custom-plugin'),
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
// 커스텀 플러그인 사용
|
|
381
|
+
<DsMarkdown plugins={[katexPlugin, customPlugin]}>콘텐츠</DsMarkdown>;
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
## 🎛️ 타이머 모드 상세
|
|
387
|
+
|
|
388
|
+
### `requestAnimationFrame` 모드 🌟 (권장)
|
|
221
389
|
|
|
222
390
|
```typescript
|
|
223
391
|
// 🎯 특징
|
|
224
|
-
- 시간 기반: 실제 경과 시간을
|
|
392
|
+
- 시간 기반: 실제 경과 시간을 바탕으로 문자 수 계산
|
|
225
393
|
- 배치 처리: 단일 프레임 내에서 여러 문자 처리 가능
|
|
226
394
|
- 프레임 동기화: 브라우저 60fps 새로고침 속도와 동기화
|
|
227
|
-
- 고주파 최적화: interval < 16ms 고속
|
|
395
|
+
- 고주파 최적화: interval < 16ms의 고속 타이핑을 완벽하게 지원
|
|
228
396
|
|
|
229
397
|
// 🎯 적용 시나리오
|
|
230
398
|
- 현대 웹 애플리케이션의 기본 선택
|
|
231
399
|
- 부드러운 애니메이션 효과 추구
|
|
232
|
-
- 고주파 타이핑 (interval > 0
|
|
400
|
+
- 고주파 타이핑 (interval > 0으로 충분)
|
|
233
401
|
- AI 실시간 대화 시나리오
|
|
234
402
|
```
|
|
235
403
|
|
|
236
|
-
### `setTimeout` 모드 📟 (
|
|
404
|
+
### `setTimeout` 모드 📟 (호환)
|
|
237
405
|
|
|
238
406
|
```typescript
|
|
239
407
|
// 🎯 특징
|
|
240
|
-
- 단일 문자:
|
|
408
|
+
- 단일 문자: 매번 정확히 한 문자씩 처리
|
|
241
409
|
- 고정 간격: 설정된 시간에 따라 엄격하게 실행
|
|
242
|
-
- 리듬감: 클래식 타자기의
|
|
410
|
+
- 리듬감: 클래식 타자기의 리듬감
|
|
243
411
|
- 정밀 제어: 특정 타이밍 요구사항에 적합
|
|
244
412
|
|
|
245
413
|
// 🎯 적용 시나리오
|
|
246
|
-
- 정밀한 시간 제어가
|
|
247
|
-
- 레트로 타자기 효과
|
|
414
|
+
- 정밀한 시간 제어가 필요한 경우
|
|
415
|
+
- 레트로 타자기 효과 연출
|
|
248
416
|
- 호환성 요구사항이 높은 시나리오
|
|
249
417
|
```
|
|
250
418
|
|
|
251
419
|
### 📊 성능 비교
|
|
252
420
|
|
|
253
|
-
|
|
|
254
|
-
| ----------------- | ---------------------------------- |
|
|
255
|
-
| **문자 처리** | 프레임당 여러 문자
|
|
256
|
-
|
|
|
257
|
-
|
|
|
258
|
-
| **시각적 효과** | 🎬 부드러운 애니메이션
|
|
259
|
-
| **성능 오버헤드** | 🟢 낮음 (프레임 동기화) | 🟡
|
|
421
|
+
| 특징 | requestAnimationFrame | setTimeout |
|
|
422
|
+
| ----------------- | ---------------------------------- | ---------------- |
|
|
423
|
+
| **문자 처리** | 프레임당 여러 문자 | 한 번에 한 문자 |
|
|
424
|
+
| **고주파** | ✅ 우수 (5ms → 프레임당 3문자) | ❌ 지연 가능성 |
|
|
425
|
+
| **저주파** | ✅ 정상 (100ms → 6프레임 후 1문자) | ✅ 정밀 |
|
|
426
|
+
| **시각적 효과** | 🎬 부드러운 애니메이션 감각 | ⚡ 정밀한 리듬감 |
|
|
427
|
+
| **성능 오버헤드** | 🟢 낮음 (프레임 동기화) | 🟡 보통 (타이머) |
|
|
260
428
|
|
|
261
|
-
고주파는 `requestAnimationFrame
|
|
429
|
+
고주파는 `requestAnimationFrame` 권장, 저주파는 `setTimeout` 권장
|
|
262
430
|
|
|
263
431
|
---
|
|
264
432
|
|
|
@@ -266,6 +434,8 @@ markdownRef.current?.resume(); // 애니메이션 재개
|
|
|
266
434
|
|
|
267
435
|
### 📝 AI 스트리밍 대화
|
|
268
436
|
|
|
437
|
+
[DEMO: 🔧 StackBlitz 체험](https://stackblitz.com/edit/vitejs-vite-2ri8kex3?file=src%2FApp.tsx)
|
|
438
|
+
|
|
269
439
|
````tsx
|
|
270
440
|
import { useRef } from 'react';
|
|
271
441
|
import { MarkdownCMD, MarkdownCMDRef } from 'ds-markdown';
|
|
@@ -278,18 +448,18 @@ function StreamingChat() {
|
|
|
278
448
|
markdownRef.current?.clear();
|
|
279
449
|
|
|
280
450
|
// 사고 단계
|
|
281
|
-
markdownRef.current?.push('🤔 질문을
|
|
451
|
+
markdownRef.current?.push('🤔 질문을 분석 중입니다...', 'thinking');
|
|
282
452
|
await delay(1000);
|
|
283
|
-
markdownRef.current?.push('\n\n✅ 분석 완료,
|
|
453
|
+
markdownRef.current?.push('\n\n✅ 분석 완료, 답변 시작', 'thinking');
|
|
284
454
|
|
|
285
455
|
// 스트리밍 답변
|
|
286
456
|
const chunks = [
|
|
287
|
-
'# React 19
|
|
457
|
+
'# React 19 신기능 분석\n\n',
|
|
288
458
|
'## 🚀 React Compiler\n',
|
|
289
459
|
'React 19의 가장 큰 하이라이트는 **React Compiler** 도입입니다:\n\n',
|
|
290
460
|
'- 🎯 **자동 최적화**: 수동 memo와 useMemo 불필요\n',
|
|
291
|
-
'- ⚡ **성능 향상**: 컴파일 타임 최적화, 런타임
|
|
292
|
-
'- 🔧
|
|
461
|
+
'- ⚡ **성능 향상**: 컴파일 타임 최적화, 런타임 제로 오버헤드\n',
|
|
462
|
+
'- 🔧 **후방 호환성**: 기존 코드 수정 불필요\n\n',
|
|
293
463
|
'## 📝 Actions로 폼 간소화\n',
|
|
294
464
|
'새로운 Actions API로 폼 처리가 더 간단해집니다:\n\n',
|
|
295
465
|
'```tsx\n',
|
|
@@ -314,9 +484,9 @@ function StreamingChat() {
|
|
|
314
484
|
|
|
315
485
|
return (
|
|
316
486
|
<div className="chat-container">
|
|
317
|
-
<button onClick={simulateAIResponse}>🤖 React 19
|
|
487
|
+
<button onClick={simulateAIResponse}>🤖 React 19 신기능에 대해 질문</button>
|
|
318
488
|
|
|
319
|
-
<MarkdownCMD ref={markdownRef} interval={10} timerType="requestAnimationFrame" onEnd={(data) => console.log('
|
|
489
|
+
<MarkdownCMD ref={markdownRef} interval={10} timerType="requestAnimationFrame" onEnd={(data) => console.log('섹션 완료:', data)} />
|
|
320
490
|
</div>
|
|
321
491
|
);
|
|
322
492
|
}
|
|
@@ -324,80 +494,64 @@ function StreamingChat() {
|
|
|
324
494
|
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
325
495
|
````
|
|
326
496
|
|
|
327
|
-
###
|
|
328
|
-
|
|
329
|
-
**핵심 문제**: 스트리밍 출력 시 불완전한 Markdown 구문이 렌더링 오류를 일으킬 수 있음
|
|
497
|
+
### 🧮 수학 공식 스트리밍 렌더링
|
|
330
498
|
|
|
331
499
|
```tsx
|
|
332
|
-
|
|
333
|
-
push('#'); // "# "
|
|
334
|
-
push(' '); // "# "
|
|
335
|
-
push('제목'); // "# 제목"
|
|
336
|
-
push('\n'); // "# 제목\n"
|
|
337
|
-
push('1'); // "# 제목\n1" ← 이것은 단락으로 잘못 해석됨
|
|
338
|
-
push('.'); // "# 제목\n1." ← 올바른 리스트 형성
|
|
339
|
-
push(' 항목'); // "# 제목\n1. 항목"
|
|
340
|
-
```
|
|
500
|
+
import { katexPlugin } from 'ds-markdown/plugins';
|
|
341
501
|
|
|
342
|
-
|
|
502
|
+
function MathStreamingDemo() {
|
|
503
|
+
const markdownRef = useRef<MarkdownCMDRef>(null);
|
|
343
504
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
const handleStreamingMarkdown = () => {
|
|
347
|
-
const chunks = ['#', ' ', '사용', '기술', '\n', '1', '.', ' ', '기술1', '\n', '2', '.', ' 기술2'];
|
|
348
|
-
|
|
349
|
-
chunks.forEach((chunk) => {
|
|
350
|
-
markdownRef.current?.push(chunk, 'answer');
|
|
351
|
-
// 지연 불필요, 컴포넌트 내부에서 지능적 버퍼링
|
|
352
|
-
});
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
// 🧠 스마트 처리 플로우:
|
|
356
|
-
// 1. "# 사용기술\n1" 구문 불완전 실시간 감지
|
|
357
|
-
// 2. 스마트 버퍼링, 더 많은 문자 대기
|
|
358
|
-
// 3. "."을 받아 "1." 형성 후 즉시 처리
|
|
359
|
-
// 4. 지연 없음, 순수 동기 처리
|
|
360
|
-
```
|
|
505
|
+
const simulateMathResponse = async () => {
|
|
506
|
+
markdownRef.current?.clear();
|
|
361
507
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
'
|
|
367
|
-
'
|
|
368
|
-
'-
|
|
369
|
-
'
|
|
370
|
-
'
|
|
371
|
-
'
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
// 🔄 불완전한 구문 (스마트 버퍼링)
|
|
375
|
-
'##'; // 제목 기호만
|
|
376
|
-
'1'; // 숫자만
|
|
377
|
-
'```java'; // 가능한 코드 블록 시작
|
|
378
|
-
````
|
|
508
|
+
const mathChunks = [
|
|
509
|
+
'# 피타고라스 정리 상세 설명\n\n',
|
|
510
|
+
'직각삼각형에서 빗변의 제곱은 두 직각변의 제곱의 합과 같습니다:\n\n',
|
|
511
|
+
'$a^2 + b^2 = c^2$\n\n',
|
|
512
|
+
'여기서:\n',
|
|
513
|
+
'- $a$와 $b$는 직각변\n',
|
|
514
|
+
'- $c$는 빗변\n\n',
|
|
515
|
+
'고전적인 "구삼고사현오"의 경우:\n',
|
|
516
|
+
'$c = \\sqrt{3^2 + 4^2} = \\sqrt{25} = 5$\n\n',
|
|
517
|
+
'이 정리는 기하학에서 광범위하게 응용됩니다!',
|
|
518
|
+
];
|
|
379
519
|
|
|
380
|
-
|
|
520
|
+
for (const chunk of mathChunks) {
|
|
521
|
+
await delay(150);
|
|
522
|
+
markdownRef.current?.push(chunk, 'answer');
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
return (
|
|
527
|
+
<div>
|
|
528
|
+
<button onClick={simulateMathResponse}>📐 피타고라스 정리 설명</button>
|
|
529
|
+
|
|
530
|
+
<MarkdownCMD ref={markdownRef} interval={20} timerType="requestAnimationFrame" plugins={[katexPlugin]} math={{ splitSymbol: 'dollar' }} />
|
|
531
|
+
</div>
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
```
|
|
381
535
|
|
|
382
536
|
## 🔧 모범 사례
|
|
383
537
|
|
|
384
538
|
### 1. 성능 최적화
|
|
385
539
|
|
|
386
540
|
```tsx
|
|
387
|
-
// ✅
|
|
541
|
+
// ✅ 권장 구성
|
|
388
542
|
<DsMarkdown
|
|
389
543
|
timerType="requestAnimationFrame"
|
|
390
544
|
interval={15} // 15-30ms가 최적 경험
|
|
391
545
|
/>
|
|
392
546
|
|
|
393
547
|
// ❌ 너무 작은 간격 피하기
|
|
394
|
-
<DsMarkdown interval={1} /> // 성능
|
|
548
|
+
<DsMarkdown interval={1} /> // 성능 문제 야기 가능
|
|
395
549
|
```
|
|
396
550
|
|
|
397
551
|
### 2. 스트리밍 데이터 처리
|
|
398
552
|
|
|
399
553
|
```tsx
|
|
400
|
-
// ✅
|
|
554
|
+
// ✅ 권장: 명령형 API
|
|
401
555
|
const ref = useRef<MarkdownCMDRef>(null);
|
|
402
556
|
useEffect(() => {
|
|
403
557
|
ref.current?.push(newChunk, 'answer');
|
|
@@ -405,97 +559,30 @@ useEffect(() => {
|
|
|
405
559
|
|
|
406
560
|
// ❌ 피하기: 빈번한 children 업데이트
|
|
407
561
|
const [content, setContent] = useState('');
|
|
408
|
-
// 각 업데이트마다 전체
|
|
562
|
+
// 각 업데이트마다 전체 내용을 재분석
|
|
409
563
|
```
|
|
410
564
|
|
|
411
|
-
### 3.
|
|
565
|
+
### 3. 수학 공식 최적화
|
|
412
566
|
|
|
413
567
|
```tsx
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
// 완전한 TypeScript 타입 힌트
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
### 4. 스타일 커스터마이징
|
|
421
|
-
|
|
422
|
-
```css
|
|
423
|
-
/* 사고 영역 스타일 */
|
|
424
|
-
.ds-markdown-thinking {
|
|
425
|
-
background: rgba(255, 193, 7, 0.1);
|
|
426
|
-
border-left: 3px solid #ffc107;
|
|
427
|
-
padding: 12px;
|
|
428
|
-
border-radius: 6px;
|
|
429
|
-
margin: 8px 0;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/* 답변 영역 스타일 */
|
|
433
|
-
.ds-markdown-answer {
|
|
434
|
-
color: #333;
|
|
435
|
-
line-height: 1.6;
|
|
436
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
/* 코드 블록 스타일 */
|
|
440
|
-
.ds-markdown pre {
|
|
441
|
-
background: #f8f9fa;
|
|
442
|
-
border-radius: 8px;
|
|
443
|
-
padding: 16px;
|
|
444
|
-
overflow-x: auto;
|
|
445
|
-
}
|
|
568
|
+
// ✅ 권장: 필요시 수학 공식 스타일 로드
|
|
569
|
+
import 'ds-markdown/style.css';
|
|
570
|
+
import 'ds-markdown/katex.css'; // 필요할 때만 가져오기
|
|
446
571
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
width: 100%;
|
|
451
|
-
margin: 16px 0;
|
|
452
|
-
}
|
|
572
|
+
// ✅ 권장: 적절한 구분자 사용
|
|
573
|
+
// 간단한 공식에는 $...$가 더 간결
|
|
574
|
+
// 복잡한 공식에는 $$...$$가 더 명확
|
|
453
575
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
padding: 8px 12px;
|
|
458
|
-
text-align: left;
|
|
459
|
-
}
|
|
576
|
+
// ✅ 권장: 플러그인 구성
|
|
577
|
+
import { katexPlugin } from 'ds-markdown/plugins';
|
|
578
|
+
<DsMarkdown plugins={[katexPlugin]}>수학 공식 내용</DsMarkdown>;
|
|
460
579
|
```
|
|
461
580
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
## 🌐 호환성
|
|
465
|
-
|
|
466
|
-
| 환경 | 버전 요구사항 | 설명 |
|
|
467
|
-
| -------------- | ----------------------------------- | --------------------- |
|
|
468
|
-
| **React** | 16.8.0+ | Hooks 지원 필요 |
|
|
469
|
-
| **TypeScript** | 4.0+ | 선택사항, 하지만 추천 |
|
|
470
|
-
| **브라우저** | Chrome 60+, Firefox 55+, Safari 12+ | 모던 브라우저 |
|
|
471
|
-
| **Node.js** | 14.0+ | 빌드 환경 |
|
|
472
|
-
|
|
473
|
-
---
|
|
474
|
-
|
|
475
|
-
## 🤝 기여 가이드
|
|
476
|
-
|
|
477
|
-
Issue와 Pull Request 제출을 환영합니다!
|
|
581
|
+
### 4. 타입 안전성
|
|
478
582
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
3. 변경사항 커밋: `git commit -m 'Add amazing feature'`
|
|
482
|
-
4. 브랜치 푸시: `git push origin feature/amazing-feature`
|
|
483
|
-
5. Pull Request 제출
|
|
484
|
-
|
|
485
|
-
---
|
|
486
|
-
|
|
487
|
-
## 📄 라이선스
|
|
488
|
-
|
|
489
|
-
MIT © [onshinpei](https://github.com/onshinpei)
|
|
490
|
-
|
|
491
|
-
---
|
|
583
|
+
```tsx
|
|
584
|
+
import { MarkdownCMDRef } from 'ds-markdown';
|
|
492
585
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
<br><br>
|
|
497
|
-
|
|
498
|
-
[🐛 문제 보고](https://github.com/onshinpei/ds-markdown/issues) |
|
|
499
|
-
[💡 기능 제안](https://github.com/onshinpei/ds-markdown/issues) |
|
|
500
|
-
[📖 문서 보기](https://onshinpei.github.io/ds-markdown/)
|
|
501
|
-
</div>
|
|
586
|
+
const ref = useRef<MarkdownCMDRef>(null);
|
|
587
|
+
// 완전한 TypeScript 타입 힌트
|
|
588
|
+
```
|