sparkdesign 0.3.0 → 0.3.2

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.
Files changed (104) hide show
  1. package/README.md +7 -5
  2. package/cli/dist/index.js +0 -0
  3. package/cli/dist/utils/tokens.js +103 -17
  4. package/cli/registry/basic/button.test.tsx +333 -0
  5. package/cli/registry/chat/{question-part.tsx → ask-user-part.tsx} +4 -4
  6. package/cli/registry/chat/{browser-use-part.tsx → browser-action-part.tsx} +6 -6
  7. package/cli/registry/chat/{suggestion-part.tsx → hint-banner.tsx} +4 -4
  8. package/cli/registry/chat/markdown.test.tsx +387 -0
  9. package/cli/registry/chat/{reasoning-step.tsx → reasoning-step/compound.tsx} +163 -185
  10. package/cli/registry/chat/reasoning-step/context.tsx +114 -0
  11. package/cli/registry/chat/reasoning-step/index.tsx +45 -0
  12. package/cli/registry/chat/reasoning-step/types.ts +109 -0
  13. package/cli/registry/chat/response/compound.tsx +210 -0
  14. package/cli/registry/chat/{response.tsx → response/context.tsx} +65 -136
  15. package/cli/registry/chat/response/index.tsx +87 -0
  16. package/cli/registry/chat/response/types.ts +123 -0
  17. package/cli/registry/chat/thinking-indicator.test.tsx +244 -0
  18. package/cli/registry/chat/tool-invocation-card.test.tsx +346 -0
  19. package/cli/registry/chat/{request.tsx → user-message.tsx} +3 -3
  20. package/cli/registry/chat/user-question/compound.tsx +324 -0
  21. package/cli/registry/chat/user-question/context.tsx +456 -0
  22. package/cli/registry/chat/user-question/index.tsx +71 -316
  23. package/cli/registry/chat/user-question/useUserQuestionKeyboard.ts +5 -6
  24. package/cli/registry/tokens/index.css +31 -0
  25. package/cli/registry/tokens/scale/computed.css +103 -0
  26. package/cli/registry/tokens/scale/config.css +110 -0
  27. package/cli/registry/tokens/scale/index.css +30 -0
  28. package/cli/registry/tokens/scale/presets/compact.css +30 -0
  29. package/cli/registry/tokens/scale/presets/dense.css +64 -0
  30. package/cli/registry/tokens/scale/presets/sharp.css +40 -0
  31. package/cli/registry/tokens/scale/presets/soft.css +16 -0
  32. package/cli/registry/tokens/scale.css +12 -298
  33. package/cli/registry/tokens/scrollbar-utility.css +35 -0
  34. package/cli/registry/tokens/themes/dark-parchment.css +132 -0
  35. package/cli/registry/tokens/themes/dark-qoder.css +132 -0
  36. package/cli/registry/tokens/themes/light-parchment.css +123 -0
  37. package/cli/registry/tokens/themes/light-qoder.css +131 -0
  38. package/dist/qoder-design.css +1 -1
  39. package/dist/registry/chat/ask-user-part.d.ts +24 -0
  40. package/dist/registry/chat/browser-action-part.d.ts +28 -0
  41. package/dist/registry/chat/{suggestion-part.d.ts → hint-banner.d.ts} +4 -4
  42. package/dist/registry/chat/reasoning-step/compound.d.ts +17 -0
  43. package/dist/registry/chat/reasoning-step/context.d.ts +10 -0
  44. package/dist/registry/chat/reasoning-step/index.d.ts +14 -0
  45. package/dist/registry/chat/reasoning-step/types.d.ts +95 -0
  46. package/dist/registry/chat/response/compound.d.ts +25 -0
  47. package/dist/registry/chat/response/context.d.ts +9 -0
  48. package/dist/registry/chat/response/index.d.ts +15 -0
  49. package/dist/registry/chat/response/types.d.ts +99 -0
  50. package/dist/registry/chat/user-message.d.ts +6 -0
  51. package/dist/registry/chat/user-question/compound.d.ts +37 -0
  52. package/dist/registry/chat/user-question/context.d.ts +55 -0
  53. package/dist/registry/chat/user-question/index.d.ts +13 -5
  54. package/dist/registry/chat/user-question/useUserQuestionKeyboard.d.ts +2 -3
  55. package/dist/scale.css +9 -303
  56. package/dist/spark-design.cjs.js +62 -62
  57. package/dist/spark-design.es.js +3992 -3826
  58. package/dist/src/components/chat/AskUserPart/index.d.ts +6 -0
  59. package/dist/src/components/chat/BrowserActionPart/index.d.ts +7 -0
  60. package/dist/src/components/chat/HintBanner/index.d.ts +6 -0
  61. package/dist/src/components/chat/ReasoningStep/index.d.ts +11 -5
  62. package/dist/src/components/chat/Response/index.d.ts +16 -6
  63. package/dist/src/components/chat/UserMessage/index.d.ts +7 -0
  64. package/dist/src/components/chat/UserQuestion/index.d.ts +18 -4
  65. package/dist/src/components/index.d.ts +63 -63
  66. package/dist/theme.css +13 -800
  67. package/package.json +27 -3
  68. package/dist/registry/chat/browser-use-part.d.ts +0 -28
  69. package/dist/registry/chat/question-part.d.ts +0 -24
  70. package/dist/registry/chat/reasoning-step.d.ts +0 -35
  71. package/dist/registry/chat/request.d.ts +0 -6
  72. package/dist/registry/chat/response.d.ts +0 -28
  73. package/dist/src/components/chat/BrowserUsePart/index.d.ts +0 -7
  74. package/dist/src/components/chat/QuestionPart/index.d.ts +0 -6
  75. package/dist/src/components/chat/Request/index.d.ts +0 -7
  76. package/dist/src/components/chat/SuggestionPart/index.d.ts +0 -6
  77. /package/dist/src/components/{foundation → basic}/AlertDialog/index.d.ts +0 -0
  78. /package/dist/src/components/{foundation → basic}/Avatar/index.d.ts +0 -0
  79. /package/dist/src/components/{foundation → basic}/Button/index.d.ts +0 -0
  80. /package/dist/src/components/{foundation → basic}/Collapse/index.d.ts +0 -0
  81. /package/dist/src/components/{foundation → basic}/Collapsible/index.d.ts +0 -0
  82. /package/dist/src/components/{foundation → basic}/CollapsibleSection/index.d.ts +0 -0
  83. /package/dist/src/components/{foundation → basic}/DropdownMenu/index.d.ts +0 -0
  84. /package/dist/src/components/{foundation → basic}/EllipsisText/index.d.ts +0 -0
  85. /package/dist/src/components/{foundation → basic}/IconButton/index.d.ts +0 -0
  86. /package/dist/src/components/{foundation → basic}/Kbd/index.d.ts +0 -0
  87. /package/dist/src/components/{foundation → basic}/OptionList/index.d.ts +0 -0
  88. /package/dist/src/components/{foundation → basic}/Pagination/index.d.ts +0 -0
  89. /package/dist/src/components/{foundation → basic}/Progress/index.d.ts +0 -0
  90. /package/dist/src/components/{foundation → basic}/RadioGroup/index.d.ts +0 -0
  91. /package/dist/src/components/{foundation → basic}/Resizable/index.d.ts +0 -0
  92. /package/dist/src/components/{foundation → basic}/Scrollbar/index.d.ts +0 -0
  93. /package/dist/src/components/{foundation → basic}/Select/index.d.ts +0 -0
  94. /package/dist/src/components/{foundation → basic}/Skeleton/index.d.ts +0 -0
  95. /package/dist/src/components/{foundation → basic}/Slider/index.d.ts +0 -0
  96. /package/dist/src/components/{foundation → basic}/Spinner/index.d.ts +0 -0
  97. /package/dist/src/components/{foundation → basic}/Switch/index.d.ts +0 -0
  98. /package/dist/src/components/{foundation → basic}/Table/index.d.ts +0 -0
  99. /package/dist/src/components/{foundation → basic}/Tabs/index.d.ts +0 -0
  100. /package/dist/src/components/{foundation → basic}/Tag/index.d.ts +0 -0
  101. /package/dist/src/components/{foundation → basic}/Toast/index.d.ts +0 -0
  102. /package/dist/src/components/{foundation → basic}/Toggle/index.d.ts +0 -0
  103. /package/dist/src/components/{foundation → basic}/Tooltip/index.d.ts +0 -0
  104. /package/dist/src/components/{foundation → basic}/Typography/index.d.ts +0 -0
@@ -0,0 +1,387 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { render, screen } from '@testing-library/react'
3
+ import { MarkdownBody } from './markdown'
4
+
5
+ describe('MarkdownBody', () => {
6
+ // ============================================================
7
+ // 基础渲染测试
8
+ // ============================================================
9
+ describe('基础渲染', () => {
10
+ it('应正确渲染组件', () => {
11
+ const { container } = render(<MarkdownBody>Hello World</MarkdownBody>)
12
+ expect(container.firstChild).toBeInTheDocument()
13
+ })
14
+
15
+ it('应设置正确的 displayName', () => {
16
+ expect(MarkdownBody.displayName).toBe('MarkdownBody')
17
+ })
18
+
19
+ it('应渲染普通文本', () => {
20
+ render(<MarkdownBody>Simple text content</MarkdownBody>)
21
+ expect(screen.getByText('Simple text content')).toBeInTheDocument()
22
+ })
23
+ })
24
+
25
+ // ============================================================
26
+ // 段落渲染测试
27
+ // ============================================================
28
+ describe('段落 (p)', () => {
29
+ it('应渲染段落为 p 元素', () => {
30
+ const { container } = render(<MarkdownBody>A paragraph</MarkdownBody>)
31
+ expect(container.querySelector('p')).toBeInTheDocument()
32
+ })
33
+
34
+ it('段落应有正确的样式类', () => {
35
+ const { container } = render(<MarkdownBody>Styled paragraph</MarkdownBody>)
36
+ const p = container.querySelector('p')
37
+ expect(p).toHaveClass('text-sm')
38
+ expect(p).toHaveClass('text-text')
39
+ })
40
+ })
41
+
42
+ // ============================================================
43
+ // 标题渲染测试
44
+ // ============================================================
45
+ describe('标题 (h1-h6)', () => {
46
+ it('应渲染 h1 标题', () => {
47
+ const { container } = render(<MarkdownBody># Heading 1</MarkdownBody>)
48
+ const h1 = container.querySelector('h1')
49
+ expect(h1).toBeInTheDocument()
50
+ expect(h1).toHaveTextContent('Heading 1')
51
+ })
52
+
53
+ it('应渲染 h2 标题', () => {
54
+ const { container } = render(<MarkdownBody>## Heading 2</MarkdownBody>)
55
+ const h2 = container.querySelector('h2')
56
+ expect(h2).toBeInTheDocument()
57
+ expect(h2).toHaveTextContent('Heading 2')
58
+ })
59
+
60
+ it('应渲染 h3 标题', () => {
61
+ const { container } = render(<MarkdownBody>### Heading 3</MarkdownBody>)
62
+ const h3 = container.querySelector('h3')
63
+ expect(h3).toBeInTheDocument()
64
+ })
65
+
66
+ it('h1 应有正确的样式', () => {
67
+ const { container } = render(<MarkdownBody># Title</MarkdownBody>)
68
+ const h1 = container.querySelector('h1')
69
+ expect(h1).toHaveClass('text-4xl')
70
+ expect(h1).toHaveClass('font-medium')
71
+ })
72
+
73
+ it('h2 应有边框样式', () => {
74
+ const { container } = render(<MarkdownBody>## Section</MarkdownBody>)
75
+ const h2 = container.querySelector('h2')
76
+ expect(h2).toHaveClass('border-b')
77
+ })
78
+ })
79
+
80
+ // ============================================================
81
+ // 列表渲染测试
82
+ // ============================================================
83
+ describe('列表 (ul/ol)', () => {
84
+ it('应渲染无序列表', () => {
85
+ const { container } = render(
86
+ <MarkdownBody>{`- Item 1\n- Item 2\n- Item 3`}</MarkdownBody>
87
+ )
88
+ const ul = container.querySelector('ul')
89
+ expect(ul).toBeInTheDocument()
90
+ expect(ul).toHaveClass('list-disc')
91
+ })
92
+
93
+ it('应渲染有序列表', () => {
94
+ const { container } = render(
95
+ <MarkdownBody>{`1. First\n2. Second\n3. Third`}</MarkdownBody>
96
+ )
97
+ const ol = container.querySelector('ol')
98
+ expect(ol).toBeInTheDocument()
99
+ expect(ol).toHaveClass('list-decimal')
100
+ })
101
+
102
+ it('列表项应正确渲染', () => {
103
+ const { container } = render(
104
+ <MarkdownBody>{`- Apple\n- Banana`}</MarkdownBody>
105
+ )
106
+ const items = container.querySelectorAll('li')
107
+ expect(items).toHaveLength(2)
108
+ })
109
+ })
110
+
111
+ // ============================================================
112
+ // 代码渲染测试
113
+ // ============================================================
114
+ describe('代码 (code/pre)', () => {
115
+ it('应渲染行内代码', () => {
116
+ const { container } = render(
117
+ <MarkdownBody>Use `npm install` to install</MarkdownBody>
118
+ )
119
+ const code = container.querySelector('code')
120
+ expect(code).toBeInTheDocument()
121
+ expect(code).toHaveTextContent('npm install')
122
+ })
123
+
124
+ it('行内代码应有背景样式', () => {
125
+ const { container } = render(
126
+ <MarkdownBody>Run `test` command</MarkdownBody>
127
+ )
128
+ const code = container.querySelector('code')
129
+ expect(code).toHaveClass('bg-fill-tertiary')
130
+ expect(code).toHaveClass('rounded')
131
+ })
132
+
133
+ it('应渲染代码块', () => {
134
+ const { container } = render(
135
+ <MarkdownBody>{`\`\`\`javascript\nconst x = 1;\n\`\`\``}</MarkdownBody>
136
+ )
137
+ const pre = container.querySelector('pre')
138
+ expect(pre).toBeInTheDocument()
139
+ })
140
+
141
+ it('代码块应包含在滚动容器中', () => {
142
+ const { container } = render(
143
+ <MarkdownBody>{`\`\`\`js\ncode\n\`\`\``}</MarkdownBody>
144
+ )
145
+ // Scrollbar 组件包裹
146
+ const scrollContainer = container.querySelector('[class*="overflow"]')
147
+ expect(scrollContainer).toBeInTheDocument()
148
+ })
149
+ })
150
+
151
+ // ============================================================
152
+ // 引用渲染测试
153
+ // ============================================================
154
+ describe('引用 (blockquote)', () => {
155
+ it('应渲染引用块', () => {
156
+ const { container } = render(
157
+ <MarkdownBody>{'> This is a quote'}</MarkdownBody>
158
+ )
159
+ const blockquote = container.querySelector('blockquote')
160
+ expect(blockquote).toBeInTheDocument()
161
+ })
162
+
163
+ it('引用块应有边框样式', () => {
164
+ const { container } = render(
165
+ <MarkdownBody>{'> Quote text'}</MarkdownBody>
166
+ )
167
+ const blockquote = container.querySelector('blockquote')
168
+ expect(blockquote).toHaveClass('border-l-2')
169
+ expect(blockquote).toHaveClass('italic')
170
+ })
171
+ })
172
+
173
+ // ============================================================
174
+ // 链接渲染测试
175
+ // ============================================================
176
+ describe('链接 (a)', () => {
177
+ it('应渲染链接', () => {
178
+ render(<MarkdownBody>[Click me](https://example.com)</MarkdownBody>)
179
+ const link = screen.getByRole('link')
180
+ expect(link).toBeInTheDocument()
181
+ expect(link).toHaveTextContent('Click me')
182
+ })
183
+
184
+ it('链接应在新标签页打开', () => {
185
+ render(<MarkdownBody>[Link](https://example.com)</MarkdownBody>)
186
+ const link = screen.getByRole('link')
187
+ expect(link).toHaveAttribute('target', '_blank')
188
+ expect(link).toHaveAttribute('rel', 'noopener noreferrer')
189
+ })
190
+
191
+ it('链接应有正确的 href', () => {
192
+ render(<MarkdownBody>[Test](https://test.com)</MarkdownBody>)
193
+ const link = screen.getByRole('link')
194
+ expect(link).toHaveAttribute('href', 'https://test.com')
195
+ })
196
+ })
197
+
198
+ // ============================================================
199
+ // 强调渲染测试
200
+ // ============================================================
201
+ describe('强调 (strong/em)', () => {
202
+ it('应渲染粗体', () => {
203
+ const { container } = render(
204
+ <MarkdownBody>**Bold text**</MarkdownBody>
205
+ )
206
+ const strong = container.querySelector('strong')
207
+ expect(strong).toBeInTheDocument()
208
+ expect(strong).toHaveTextContent('Bold text')
209
+ })
210
+
211
+ it('应渲染斜体', () => {
212
+ const { container } = render(
213
+ <MarkdownBody>*Italic text*</MarkdownBody>
214
+ )
215
+ const em = container.querySelector('em')
216
+ expect(em).toBeInTheDocument()
217
+ expect(em).toHaveTextContent('Italic text')
218
+ })
219
+
220
+ it('粗体应有正确样式', () => {
221
+ const { container } = render(
222
+ <MarkdownBody>**Strong**</MarkdownBody>
223
+ )
224
+ const strong = container.querySelector('strong')
225
+ expect(strong).toHaveClass('font-semibold')
226
+ })
227
+
228
+ it('斜体应有正确样式', () => {
229
+ const { container } = render(
230
+ <MarkdownBody>*Emphasis*</MarkdownBody>
231
+ )
232
+ const em = container.querySelector('em')
233
+ expect(em).toHaveClass('italic')
234
+ })
235
+ })
236
+
237
+ // ============================================================
238
+ // 水平线渲染测试
239
+ // ============================================================
240
+ describe('水平线 (hr)', () => {
241
+ it('应渲染水平线', () => {
242
+ const { container } = render(
243
+ <MarkdownBody>{`Above\n\n---\n\nBelow`}</MarkdownBody>
244
+ )
245
+ const hr = container.querySelector('hr')
246
+ expect(hr).toBeInTheDocument()
247
+ })
248
+ })
249
+
250
+ // ============================================================
251
+ // 表格渲染测试 (GFM)
252
+ // ============================================================
253
+ describe('表格 (GFM)', () => {
254
+ it('应渲染表格', () => {
255
+ const tableMarkdown = `
256
+ | Name | Age |
257
+ |------|-----|
258
+ | Alice | 25 |
259
+ | Bob | 30 |
260
+ `
261
+ const { container } = render(<MarkdownBody>{tableMarkdown}</MarkdownBody>)
262
+ expect(container.querySelector('table')).toBeInTheDocument()
263
+ })
264
+
265
+ it('应渲染表头', () => {
266
+ const tableMarkdown = `
267
+ | Header1 | Header2 |
268
+ |---------|---------|
269
+ | Cell1 | Cell2 |
270
+ `
271
+ const { container } = render(<MarkdownBody>{tableMarkdown}</MarkdownBody>)
272
+ const thead = container.querySelector('thead')
273
+ expect(thead).toBeInTheDocument()
274
+ })
275
+
276
+ it('应渲染表体', () => {
277
+ const tableMarkdown = `
278
+ | A | B |
279
+ |---|---|
280
+ | 1 | 2 |
281
+ `
282
+ const { container } = render(<MarkdownBody>{tableMarkdown}</MarkdownBody>)
283
+ const tbody = container.querySelector('tbody')
284
+ expect(tbody).toBeInTheDocument()
285
+ })
286
+
287
+ it('表格应在滚动容器中', () => {
288
+ const tableMarkdown = `
289
+ | Col1 | Col2 |
290
+ |------|------|
291
+ | Data | Data |
292
+ `
293
+ const { container } = render(<MarkdownBody>{tableMarkdown}</MarkdownBody>)
294
+ // Scrollbar 组件包裹
295
+ const scrollContainer = container.querySelector('[class*="border"]')
296
+ expect(scrollContainer).toBeInTheDocument()
297
+ })
298
+ })
299
+
300
+ // ============================================================
301
+ // 任务列表测试 (GFM)
302
+ // ============================================================
303
+ describe('任务列表 (GFM)', () => {
304
+ it('应渲染任务列表', () => {
305
+ const taskList = `
306
+ - [ ] Unchecked
307
+ - [x] Checked
308
+ `
309
+ const { container } = render(<MarkdownBody>{taskList}</MarkdownBody>)
310
+ const checkboxes = container.querySelectorAll('input[type="checkbox"]')
311
+ expect(checkboxes.length).toBeGreaterThan(0)
312
+ })
313
+
314
+ it('任务列表应无圆点样式', () => {
315
+ const taskList = `
316
+ - [ ] Task 1
317
+ - [x] Task 2
318
+ `
319
+ const { container } = render(<MarkdownBody>{taskList}</MarkdownBody>)
320
+ const ul = container.querySelector('ul')
321
+ expect(ul).toHaveClass('list-none')
322
+ })
323
+ })
324
+
325
+ // ============================================================
326
+ // className 测试
327
+ // ============================================================
328
+ describe('className', () => {
329
+ it('应合并自定义 className', () => {
330
+ const { container } = render(
331
+ <MarkdownBody className="custom-markdown">Content</MarkdownBody>
332
+ )
333
+ expect(container.firstChild).toHaveClass('custom-markdown')
334
+ })
335
+
336
+ it('根元素应有 markdown-body 类', () => {
337
+ const { container } = render(
338
+ <MarkdownBody>Content</MarkdownBody>
339
+ )
340
+ expect(container.firstChild).toHaveClass('markdown-body')
341
+ })
342
+ })
343
+
344
+ // ============================================================
345
+ // 复杂内容测试
346
+ // ============================================================
347
+ describe('复杂内容', () => {
348
+ it('应正确渲染混合内容', () => {
349
+ const complexMarkdown = `
350
+ # Title
351
+
352
+ A paragraph with **bold** and *italic* text.
353
+
354
+ - List item 1
355
+ - List item 2
356
+
357
+ \`\`\`js
358
+ const x = 1;
359
+ \`\`\`
360
+
361
+ > A quote
362
+
363
+ [A link](https://example.com)
364
+ `
365
+ const { container } = render(<MarkdownBody>{complexMarkdown}</MarkdownBody>)
366
+
367
+ expect(container.querySelector('h1')).toBeInTheDocument()
368
+ expect(container.querySelector('p')).toBeInTheDocument()
369
+ expect(container.querySelector('strong')).toBeInTheDocument()
370
+ expect(container.querySelector('em')).toBeInTheDocument()
371
+ expect(container.querySelector('ul')).toBeInTheDocument()
372
+ expect(container.querySelector('pre')).toBeInTheDocument()
373
+ expect(container.querySelector('blockquote')).toBeInTheDocument()
374
+ expect(container.querySelector('a')).toBeInTheDocument()
375
+ })
376
+
377
+ it('应处理空字符串', () => {
378
+ const { container } = render(<MarkdownBody>{''}</MarkdownBody>)
379
+ expect(container.firstChild).toBeInTheDocument()
380
+ })
381
+
382
+ it('应处理纯空白字符串', () => {
383
+ const { container } = render(<MarkdownBody>{' '}</MarkdownBody>)
384
+ expect(container.firstChild).toBeInTheDocument()
385
+ })
386
+ })
387
+ })