@fe-free/core 2.3.3 → 2.3.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @fe-free/core
2
2
 
3
+ ## 2.3.4
4
+
5
+ ### Patch Changes
6
+
7
+ - feat: markdown chart
8
+ - @fe-free/tool@2.3.4
9
+
3
10
  ## 2.3.3
4
11
 
5
12
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fe-free/core",
3
- "version": "2.3.3",
3
+ "version": "2.3.4",
4
4
  "description": "",
5
5
  "main": "./src/index.ts",
6
6
  "author": "",
@@ -41,7 +41,7 @@
41
41
  "remark-gfm": "^4.0.1",
42
42
  "vanilla-jsoneditor": "^0.23.1",
43
43
  "zustand": "^4.5.4",
44
- "@fe-free/tool": "2.3.3"
44
+ "@fe-free/tool": "2.3.4"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "@ant-design/pro-components": "2.8.9",
@@ -1,6 +1,7 @@
1
1
  import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
2
2
  import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';
3
3
  import { ChartBlock } from './chart';
4
+ import { HMChartBlock } from './hm_chart';
4
5
 
5
6
  function CodeBlock(props: any) {
6
7
  const { children, className, ...rest } = props;
@@ -11,6 +12,11 @@ function CodeBlock(props: any) {
11
12
  return <ChartBlock>{children}</ChartBlock>;
12
13
  }
13
14
 
15
+ // 如果是 hmchart 类型的代码块,使用 HMChartBlock 组件
16
+ if (match && match[1] === 'hmchart') {
17
+ return <HMChartBlock>{children}</HMChartBlock>;
18
+ }
19
+
14
20
  return (
15
21
  <div className="markdown-body-code-block">
16
22
  {match ? (
@@ -0,0 +1,176 @@
1
+ import { Column, Line, Pie, Scatter } from '@ant-design/plots';
2
+ import React, { useMemo } from 'react';
3
+
4
+ enum EnumType {
5
+ /** 折线图 */
6
+ LINE = 'line',
7
+ /** 柱状图 */
8
+ BAR = 'bar',
9
+ /** 饼图 */
10
+ PIE = 'pie',
11
+ /** 散点图 */
12
+ SCATTER = 'scatter',
13
+ }
14
+
15
+ interface HMChartConfigLine<D> {
16
+ /** 折线图 */
17
+ type: EnumType.LINE;
18
+ /** 标题 */
19
+ title?: string;
20
+ /** 就是纯粹的数据 */
21
+ data: D[];
22
+ /** 横坐标字段 */
23
+ xField: keyof D;
24
+ /** 纵坐标字段 */
25
+ yField: keyof D;
26
+ /** 系列字段,多折线图用 */
27
+ seriesField?: keyof D;
28
+ }
29
+
30
+ interface HMChartConfigBar<D> {
31
+ /** 柱状图 */
32
+ type: EnumType.BAR;
33
+ /** 标题 */
34
+ title?: string;
35
+ /** 就是纯粹的数据 */
36
+ data: D[];
37
+ /** 横坐标字段 */
38
+ xField: keyof D;
39
+ /** 纵坐标字段 */
40
+ yField: keyof D;
41
+ /** 系列字段,多折线图用 */
42
+ seriesField?: keyof D;
43
+ }
44
+
45
+ interface HMChartConfigPie<D> {
46
+ /** 饼图 */
47
+ type: EnumType.PIE;
48
+ /** 标题 */
49
+ title?: string;
50
+ /** 就是纯粹的数据 */
51
+ data: D[];
52
+ /** 角度字段 */
53
+ angleField: keyof D;
54
+ /** 颜色字段 */
55
+ colorField: keyof D;
56
+ }
57
+
58
+ interface HMChartConfigScatter<D> {
59
+ /** 散点图 */
60
+ type: EnumType.SCATTER;
61
+ /** 标题 */
62
+ title?: string;
63
+ /** 就是纯粹的数据 */
64
+ data: D[];
65
+ /** 横坐标字段 */
66
+ xField: keyof D;
67
+ /** 纵坐标字段 */
68
+ yField: keyof D;
69
+ /** 颜色字段 */
70
+ colorField?: keyof D;
71
+ }
72
+
73
+ type HMChartConfig<D> =
74
+ | HMChartConfigLine<D>
75
+ | HMChartConfigBar<D>
76
+ | HMChartConfigPie<D>
77
+ | HMChartConfigScatter<D>;
78
+
79
+ // 错误处理组件
80
+ function ChartError(props: { children?: React.ReactNode }) {
81
+ const { children } = props;
82
+ return (
83
+ <div className="markdown-body-hmchart-block">
84
+ <div style={{ textAlign: 'center', padding: '20px' }}>{children || '图表发生错误'}</div>
85
+ </div>
86
+ );
87
+ }
88
+
89
+ class ErrorBoundary extends React.Component {
90
+ state = { hasError: false };
91
+
92
+ static getDerivedStateFromError(error) {
93
+ console.error('ErrorBoundary:', error);
94
+ return { hasError: true };
95
+ }
96
+
97
+ componentDidCatch(error, info) {
98
+ console.error('Error caught:', error, info);
99
+ }
100
+
101
+ render() {
102
+ if (this.state.hasError) {
103
+ return <ChartError />;
104
+ }
105
+ return this.props.children;
106
+ }
107
+ }
108
+
109
+ function ChartOfLine(props: { config: HMChartConfigLine<any> }) {
110
+ return <Line colorField={props.config.seriesField} {...props.config} />;
111
+ }
112
+
113
+ function ChartOfBar(props: { config: HMChartConfigBar<any> }) {
114
+ return <Column colorField={props.config.seriesField} {...props.config} />;
115
+ }
116
+
117
+ function ChartOfPie(props: { config: HMChartConfigPie<any> }) {
118
+ return <Pie {...props.config} />;
119
+ }
120
+
121
+ function ChartOfScatter(props: { config: HMChartConfigScatter<any> }) {
122
+ return <Scatter {...props.config} />;
123
+ }
124
+
125
+ // 主 ChartBlock 组件
126
+ function HMChartBlockBase(props: any) {
127
+ const { children } = props;
128
+
129
+ const chartConfig = useMemo(() => {
130
+ try {
131
+ return JSON.parse(children);
132
+ } catch (error) {
133
+ console.error('Failed to parse chart data:', error);
134
+ return null;
135
+ }
136
+ }, [children]);
137
+
138
+ if (!chartConfig) {
139
+ return <ChartError />;
140
+ }
141
+
142
+ const { type, ...config } = chartConfig;
143
+
144
+ switch (type) {
145
+ case EnumType.LINE:
146
+ return <ChartOfLine config={config} />;
147
+
148
+ case EnumType.BAR:
149
+ return <ChartOfBar config={config} />;
150
+
151
+ case EnumType.PIE:
152
+ return <ChartOfPie config={config} />;
153
+
154
+ case EnumType.SCATTER:
155
+ return <ChartOfScatter config={config} />;
156
+
157
+ default:
158
+ return <ChartError>不支持的图表类型:{type}</ChartError>;
159
+ }
160
+ }
161
+
162
+ function HMChartBlock(props: any) {
163
+ const { children } = props;
164
+
165
+ // eslint-disable-next-line no-irregular-whitespace
166
+ const content = children?.replace(/ /g, '');
167
+
168
+ return (
169
+ <ErrorBoundary>
170
+ <HMChartBlockBase>{content}</HMChartBlockBase>
171
+ </ErrorBoundary>
172
+ );
173
+ }
174
+
175
+ export { HMChartBlock };
176
+ export type { HMChartConfig };
@@ -141,8 +141,7 @@ export const DeepSeekPending: Story = {
141
141
 
142
142
  export const Chart: Story = {
143
143
  args: {
144
- children: `这是一个使用 @ant-design/plots 的 chart 示例
145
-
144
+ children: `
146
145
  ## 折线图示例
147
146
 
148
147
  \`\`\`chart
@@ -320,3 +319,179 @@ export const Chart: Story = {
320
319
  `,
321
320
  },
322
321
  };
322
+
323
+ export const HMChart: Story = {
324
+ args: {
325
+ children: `
326
+ 类型定义见:https://github.com/frontend-free/free/blob/main/packages/core/src/markdown/hm_chart.tsx
327
+
328
+ ## 折线图示例
329
+
330
+ \`\`\`hmchart
331
+ {
332
+ "title": "趋势变化",
333
+ "type": "line",
334
+ "data": [
335
+ { "year": "1991", "value": 3 },
336
+ { "year": "1992", "value": 4 },
337
+ { "year": "1993", "value": 3.5 }
338
+ ],
339
+ "xField": "year",
340
+ "yField": "value"
341
+ }
342
+ \`\`\`
343
+
344
+ \`\`\`hmchart
345
+ {
346
+ "title": "多条趋势变化",
347
+ "type": "line",
348
+ "data": [
349
+ { "year": "1991", "type": "A", "value": 3 },
350
+ { "year": "1991", "type": "B", "value": 4 },
351
+ { "year": "1992", "type": "A", "value": 4 },
352
+ { "year": "1992", "type": "B", "value": 4.5 },
353
+ { "year": "1993", "type": "A", "value": 3.5 },
354
+ { "year": "1993", "type": "B", "value": 6 }
355
+ ],
356
+ "xField": "year",
357
+ "yField": "value",
358
+ "seriesField": "type"
359
+ }
360
+ \`\`\`
361
+
362
+ \`\`\`hmchart
363
+ {
364
+ "title": "柱状图",
365
+ "type": "bar",
366
+ "data": [
367
+ { "year": "1991", "value": 3 },
368
+ { "year": "1992", "value": 4 },
369
+ { "year": "1993", "value": 3.5 }
370
+ ],
371
+ "xField": "year",
372
+ "yField": "value"
373
+ }
374
+ \`\`\`
375
+
376
+ \`\`\`hmchart
377
+ {
378
+ "title": "多条柱状图",
379
+ "type": "bar",
380
+ "data": [
381
+ { "year": "1991", "type": "A", "value": 3 },
382
+ { "year": "1991", "type": "B", "value": 4 },
383
+ { "year": "1992", "type": "A", "value": 4 },
384
+ { "year": "1992", "type": "B", "value": 4.5 },
385
+ { "year": "1993", "type": "A", "value": 3.5 },
386
+ { "year": "1993", "type": "B", "value": 6 }
387
+ ],
388
+ "xField": "year",
389
+ "yField": "value",
390
+ "seriesField": "type"
391
+ }
392
+ \`\`\`
393
+
394
+ \`\`\`hmchart
395
+ {
396
+ "title": "饼图",
397
+ "type": "pie",
398
+ "data": [
399
+ { "year": "1991", "value": 3 },
400
+ { "year": "1992", "value": 4 },
401
+ { "year": "1993", "value": 3.5 }
402
+ ],
403
+ "angleField": "value",
404
+ "colorField": "year"
405
+ }
406
+ \`\`\`
407
+
408
+ \`\`\`hmchart
409
+ {
410
+ "title": "散点图示例",
411
+ "type": "scatter",
412
+ "data": [
413
+ {
414
+ "gender": "female",
415
+ "height": 161.2,
416
+ "weight": 51.6
417
+ },
418
+ {
419
+ "gender": "male",
420
+ "height": 167.5,
421
+ "weight": 59
422
+ },
423
+ {
424
+ "gender": "female",
425
+ "height": 159.5,
426
+ "weight": 49.2
427
+ },
428
+ {
429
+ "gender": "male",
430
+ "height": 157,
431
+ "weight": 63
432
+ },
433
+ {
434
+ "gender": "male",
435
+ "height": 155.8,
436
+ "weight": 53.6
437
+ },
438
+ {
439
+ "gender": "female",
440
+ "height": 170,
441
+ "weight": 59
442
+ },
443
+ {
444
+ "gender": "female",
445
+ "height": 159.1,
446
+ "weight": 47.6
447
+ },
448
+ {
449
+ "gender": "female",
450
+ "height": 166,
451
+ "weight": 69.8
452
+ },
453
+ {
454
+ "gender": "female",
455
+ "height": 176.2,
456
+ "weight": 66.8
457
+ },
458
+ {
459
+ "gender": "female",
460
+ "height": 160.2,
461
+ "weight": 75.2
462
+ },
463
+ {
464
+ "gender": "female",
465
+ "height": 172.5,
466
+ "weight": 55.2
467
+ },
468
+ {
469
+ "gender": "female",
470
+ "height": 170.9,
471
+ "weight": 54.2
472
+ },
473
+ {
474
+ "gender": "female",
475
+ "height": 172.9,
476
+ "weight": 62.5
477
+ },
478
+ {
479
+ "gender": "male",
480
+ "height": 153.4,
481
+ "weight": 42
482
+ },
483
+ {
484
+ "gender": "male",
485
+ "height": 160,
486
+ "weight": 50
487
+ }
488
+ ],
489
+ "xField": "height",
490
+ "yField": "weight",
491
+ "colorField": "gender"
492
+ }
493
+ \`\`\`
494
+
495
+ `,
496
+ },
497
+ };