@c2-markdown-ui/react 0.4.3 → 0.4.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.
Files changed (73) hide show
  1. package/README.md +6 -24
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +3733 -4365
  5. package/dist/lib/MarkdownUI.d.ts +10 -0
  6. package/dist/lib/MarkdownUI.d.ts.map +1 -0
  7. package/dist/lib/index.d.ts +4 -0
  8. package/dist/lib/index.d.ts.map +1 -0
  9. package/dist/widgets/Button.d.ts +15 -0
  10. package/dist/widgets/Button.d.ts.map +1 -0
  11. package/dist/widgets/ButtonGroup.d.ts +11 -0
  12. package/dist/widgets/ButtonGroup.d.ts.map +1 -0
  13. package/dist/widgets/Cascader.d.ts +34 -0
  14. package/dist/widgets/Cascader.d.ts.map +1 -0
  15. package/dist/widgets/Chart.d.ts +20 -0
  16. package/dist/widgets/Chart.d.ts.map +1 -0
  17. package/dist/widgets/DatePicker.d.ts +28 -0
  18. package/dist/widgets/DatePicker.d.ts.map +1 -0
  19. package/dist/widgets/Form.d.ts +47 -0
  20. package/dist/widgets/Form.d.ts.map +1 -0
  21. package/dist/widgets/Incomplete.d.ts +3 -0
  22. package/dist/widgets/Incomplete.d.ts.map +1 -0
  23. package/dist/widgets/MultipleChoiceQuestion.d.ts +15 -0
  24. package/dist/widgets/MultipleChoiceQuestion.d.ts.map +1 -0
  25. package/dist/widgets/NumberInput.d.ts +26 -0
  26. package/dist/widgets/NumberInput.d.ts.map +1 -0
  27. package/dist/widgets/Quiz.d.ts +37 -0
  28. package/dist/widgets/Quiz.d.ts.map +1 -0
  29. package/dist/widgets/Radio.d.ts +24 -0
  30. package/dist/widgets/Radio.d.ts.map +1 -0
  31. package/dist/widgets/Select.d.ts +15 -0
  32. package/dist/widgets/Select.d.ts.map +1 -0
  33. package/dist/widgets/SelectMulti.d.ts +20 -0
  34. package/dist/widgets/SelectMulti.d.ts.map +1 -0
  35. package/dist/widgets/ShortAnswerQuestion.d.ts +16 -0
  36. package/dist/widgets/ShortAnswerQuestion.d.ts.map +1 -0
  37. package/dist/widgets/Slider.d.ts +13 -0
  38. package/dist/widgets/Slider.d.ts.map +1 -0
  39. package/dist/widgets/Switch.d.ts +17 -0
  40. package/dist/widgets/Switch.d.ts.map +1 -0
  41. package/dist/widgets/TextInput.d.ts +11 -0
  42. package/dist/widgets/TextInput.d.ts.map +1 -0
  43. package/dist/widgets/Widget.d.ts +7 -0
  44. package/dist/widgets/Widget.d.ts.map +1 -0
  45. package/dist/widgets/chartRemoteData.d.ts +18 -0
  46. package/dist/widgets/chartRemoteData.d.ts.map +1 -0
  47. package/dist/widgets/choiceUtils.d.ts +24 -0
  48. package/dist/widgets/choiceUtils.d.ts.map +1 -0
  49. package/dist/widgets/index.d.ts +18 -0
  50. package/dist/widgets/index.d.ts.map +1 -0
  51. package/package.json +2 -2
  52. package/src/lib/MarkdownUI.tsx +9 -47
  53. package/src/lib/widgets.css +1372 -2188
  54. package/src/widgets/Button.tsx +39 -39
  55. package/src/widgets/ButtonGroup.tsx +47 -47
  56. package/src/widgets/Cascader.tsx +2 -3
  57. package/src/widgets/Chart.tsx +237 -237
  58. package/src/widgets/DatePicker.tsx +434 -451
  59. package/src/widgets/Form.tsx +372 -512
  60. package/src/widgets/Incomplete.tsx +3 -3
  61. package/src/widgets/MultipleChoiceQuestion.tsx +82 -82
  62. package/src/widgets/Quiz.tsx +320 -320
  63. package/src/widgets/Radio.tsx +26 -57
  64. package/src/widgets/Select.tsx +142 -178
  65. package/src/widgets/SelectMulti.tsx +72 -105
  66. package/src/widgets/ShortAnswerQuestion.tsx +101 -101
  67. package/src/widgets/Slider.tsx +56 -70
  68. package/src/widgets/Switch.tsx +2 -14
  69. package/src/widgets/TextInput.tsx +38 -76
  70. package/src/widgets/Widget.tsx +82 -130
  71. package/src/widgets/choiceUtils.ts +45 -90
  72. package/src/widgets/index.ts +16 -17
  73. package/src/widgets/TreeSelect.tsx +0 -649
@@ -1,101 +1,101 @@
1
- import React, { useState } from 'react';
2
-
3
- export interface ShortAnswerQuestionProps {
4
- question: string;
5
- placeholder?: string;
6
- correctAnswer?: string;
7
- correctAnswers?: string[];
8
- showFeedback?: boolean;
9
- /** 是否禁用:禁用后输入框与提交按钮不可交互 */
10
- disabled?: boolean;
11
- onchange: (value: { answer: string; isCorrect?: boolean }) => void;
12
- }
13
-
14
- export const ShortAnswerQuestion: React.FC<ShortAnswerQuestionProps> = ({
15
- question,
16
- placeholder = "Type your answer here...",
17
- correctAnswer,
18
- correctAnswers,
19
- showFeedback = false,
20
- disabled = false,
21
- onchange
22
- }) => {
23
- const [answer, setAnswer] = useState('');
24
- const [hasAnswered, setHasAnswered] = useState(false);
25
- const [isCorrect, setIsCorrect] = useState<boolean | undefined>(undefined);
26
-
27
- const handleSubmit = () => {
28
- if (disabled) return;
29
- if (!answer.trim()) return;
30
-
31
- setHasAnswered(true);
32
-
33
- const normalized = (correctAnswers && correctAnswers.length > 0)
34
- ? correctAnswers
35
- : (typeof correctAnswer === 'string' ? [correctAnswer] : undefined);
36
-
37
- const correct = normalized
38
- ? normalized.some(a => a.toLowerCase() === answer.trim().toLowerCase())
39
- : undefined;
40
-
41
- setIsCorrect(correct);
42
- onchange({ answer: answer.trim(), isCorrect: correct });
43
- };
44
-
45
- const handleKeyDown = (e: React.KeyboardEvent) => {
46
- if (e.key === 'Enter' && !hasAnswered && !disabled) {
47
- handleSubmit();
48
- }
49
- };
50
-
51
- const getFeedbackMessage = () => {
52
- if (!hasAnswered || !showFeedback) return null;
53
-
54
- const hasAnswers = (correctAnswers && correctAnswers.length > 0) || typeof correctAnswer !== 'undefined';
55
- if (!hasAnswers) {
56
- return `Your answer: ${answer.trim()}`;
57
- }
58
-
59
- if (correctAnswers && correctAnswers.length > 0) {
60
- return isCorrect
61
- ? '✓ Correct!'
62
- : `✗ Incorrect. Accepted answers: ${correctAnswers.join(', ')}`;
63
- }
64
- return isCorrect ? '✓ Correct!' : `✗ Incorrect. The correct answer is: ${correctAnswer}`;
65
- };
66
-
67
- return (
68
- <div className="widget-saq">
69
- <div className="saq-question">{question}</div>
70
- <div className="saq-input-container">
71
- <input
72
- type="text"
73
- value={answer}
74
- onChange={(e) => setAnswer(e.target.value)}
75
- onKeyDown={handleKeyDown}
76
- placeholder={placeholder}
77
- disabled={disabled || (hasAnswered && showFeedback)}
78
- className={`saq-input ${
79
- hasAnswered && showFeedback
80
- ? isCorrect ? 'saq-input-correct' : 'saq-input-incorrect'
81
- : ''
82
- }`}
83
- />
84
- {!hasAnswered && (
85
- <button
86
- onClick={handleSubmit}
87
- disabled={disabled || !answer.trim()}
88
- className="saq-submit"
89
- >
90
- Submit
91
- </button>
92
- )}
93
- </div>
94
- {hasAnswered && showFeedback && getFeedbackMessage() && (
95
- <div className={`saq-feedback ${isCorrect ? 'correct' : 'incorrect'}`}>
96
- {getFeedbackMessage()}
97
- </div>
98
- )}
99
- </div>
100
- );
101
- };
1
+ import React, { useState } from 'react';
2
+
3
+ export interface ShortAnswerQuestionProps {
4
+ question: string;
5
+ placeholder?: string;
6
+ correctAnswer?: string;
7
+ correctAnswers?: string[];
8
+ showFeedback?: boolean;
9
+ /** 是否禁用:禁用后输入框与提交按钮不可交互 */
10
+ disabled?: boolean;
11
+ onchange: (value: { answer: string; isCorrect?: boolean }) => void;
12
+ }
13
+
14
+ export const ShortAnswerQuestion: React.FC<ShortAnswerQuestionProps> = ({
15
+ question,
16
+ placeholder = "Type your answer here...",
17
+ correctAnswer,
18
+ correctAnswers,
19
+ showFeedback = false,
20
+ disabled = false,
21
+ onchange
22
+ }) => {
23
+ const [answer, setAnswer] = useState('');
24
+ const [hasAnswered, setHasAnswered] = useState(false);
25
+ const [isCorrect, setIsCorrect] = useState<boolean | undefined>(undefined);
26
+
27
+ const handleSubmit = () => {
28
+ if (disabled) return;
29
+ if (!answer.trim()) return;
30
+
31
+ setHasAnswered(true);
32
+
33
+ const normalized = (correctAnswers && correctAnswers.length > 0)
34
+ ? correctAnswers
35
+ : (typeof correctAnswer === 'string' ? [correctAnswer] : undefined);
36
+
37
+ const correct = normalized
38
+ ? normalized.some(a => a.toLowerCase() === answer.trim().toLowerCase())
39
+ : undefined;
40
+
41
+ setIsCorrect(correct);
42
+ onchange({ answer: answer.trim(), isCorrect: correct });
43
+ };
44
+
45
+ const handleKeyDown = (e: React.KeyboardEvent) => {
46
+ if (e.key === 'Enter' && !hasAnswered && !disabled) {
47
+ handleSubmit();
48
+ }
49
+ };
50
+
51
+ const getFeedbackMessage = () => {
52
+ if (!hasAnswered || !showFeedback) return null;
53
+
54
+ const hasAnswers = (correctAnswers && correctAnswers.length > 0) || typeof correctAnswer !== 'undefined';
55
+ if (!hasAnswers) {
56
+ return `Your answer: ${answer.trim()}`;
57
+ }
58
+
59
+ if (correctAnswers && correctAnswers.length > 0) {
60
+ return isCorrect
61
+ ? '✓ Correct!'
62
+ : `✗ Incorrect. Accepted answers: ${correctAnswers.join(', ')}`;
63
+ }
64
+ return isCorrect ? '✓ Correct!' : `✗ Incorrect. The correct answer is: ${correctAnswer}`;
65
+ };
66
+
67
+ return (
68
+ <div className="widget-saq">
69
+ <div className="saq-question">{question}</div>
70
+ <div className="saq-input-container">
71
+ <input
72
+ type="text"
73
+ value={answer}
74
+ onChange={(e) => setAnswer(e.target.value)}
75
+ onKeyDown={handleKeyDown}
76
+ placeholder={placeholder}
77
+ disabled={disabled || (hasAnswered && showFeedback)}
78
+ className={`saq-input ${
79
+ hasAnswered && showFeedback
80
+ ? isCorrect ? 'saq-input-correct' : 'saq-input-incorrect'
81
+ : ''
82
+ }`}
83
+ />
84
+ {!hasAnswered && (
85
+ <button
86
+ onClick={handleSubmit}
87
+ disabled={disabled || !answer.trim()}
88
+ className="saq-submit"
89
+ >
90
+ Submit
91
+ </button>
92
+ )}
93
+ </div>
94
+ {hasAnswered && showFeedback && getFeedbackMessage() && (
95
+ <div className={`saq-feedback ${isCorrect ? 'correct' : 'incorrect'}`}>
96
+ {getFeedbackMessage()}
97
+ </div>
98
+ )}
99
+ </div>
100
+ );
101
+ };
@@ -1,71 +1,57 @@
1
- import React, { useState } from 'react';
2
-
3
- export interface SliderProps {
4
- min: number;
5
- max: number;
6
- step?: number;
7
- label?: string;
8
- default?: number;
9
- /** 是否禁用 */
10
- disabled?: boolean;
11
- /** 表单项说明:label 后 ⓘ,悬浮显示 tooltip */
12
- hint?: string;
13
- /** 是否必填(slider 始终有值,仅语义标记) */
14
- required?: boolean;
15
- onchange: (value: number) => void;
16
- }
17
-
18
- export const Slider: React.FC<SliderProps> = ({
19
- min,
20
- max,
21
- step = 1,
22
- label = '',
23
- default: initial = min,
24
- disabled = false,
25
- hint = '',
26
- required = false,
27
- onchange
28
- }) => {
29
- const [value, setValue] = useState(initial);
30
-
31
- const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
32
- const newValue = Number(e.target.value);
33
- setValue(newValue);
34
- };
35
-
36
- const handleComplete = () => {
37
- onchange(value);
38
- };
39
-
40
- return (
41
- <div className="widget-slider">
42
- {label || hint || required ? (
43
- <div className="widget-label-row">
44
- {required && <span className="widget-required-mark" aria-hidden="true">*</span>}
45
- {label && <label>{label}</label>}
46
- {hint && <span className="widget-hint" data-hint={hint}>ⓘ</span>}
47
- </div>
48
- ) : null}
49
- <div className="widget-field-content">
50
- <div className="slider-container">
51
- <div className="slider-values">
52
- <span className="min-value">{min}</span>
53
- <span className="current-value">{value}</span>
54
- <span className="max-value">{max}</span>
55
- </div>
56
- <input
57
- type="range"
58
- value={value}
59
- min={min}
60
- max={max}
61
- step={step}
62
- onChange={handleChange}
63
- onMouseUp={handleComplete}
64
- onTouchEnd={handleComplete}
65
- disabled={disabled}
66
- />
67
- </div>
68
- </div>
69
- </div>
70
- );
1
+ import React, { useState } from 'react';
2
+
3
+ export interface SliderProps {
4
+ min: number;
5
+ max: number;
6
+ step?: number;
7
+ label?: string;
8
+ default?: number;
9
+ /** 是否禁用 */
10
+ disabled?: boolean;
11
+ onchange: (value: number) => void;
12
+ }
13
+
14
+ export const Slider: React.FC<SliderProps> = ({
15
+ min,
16
+ max,
17
+ step = 1,
18
+ label = '',
19
+ default: initial = min,
20
+ disabled = false,
21
+ onchange
22
+ }) => {
23
+ const [value, setValue] = useState(initial);
24
+
25
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
26
+ const newValue = Number(e.target.value);
27
+ setValue(newValue);
28
+ };
29
+
30
+ const handleComplete = () => {
31
+ onchange(value);
32
+ };
33
+
34
+ return (
35
+ <div className="widget-slider">
36
+ {label && <label>{label}</label>}
37
+ <div className="slider-container">
38
+ <div className="slider-values">
39
+ <span className="min-value">{min}</span>
40
+ <span className="current-value">{value}</span>
41
+ <span className="max-value">{max}</span>
42
+ </div>
43
+ <input
44
+ type="range"
45
+ value={value}
46
+ min={min}
47
+ max={max}
48
+ step={step}
49
+ onChange={handleChange}
50
+ onMouseUp={handleComplete}
51
+ onTouchEnd={handleComplete}
52
+ disabled={disabled}
53
+ />
54
+ </div>
55
+ </div>
56
+ );
71
57
  };
@@ -10,23 +10,17 @@ export interface SwitchProps {
10
10
  unCheckedText?: string;
11
11
  /** 是否禁用 */
12
12
  disabled?: boolean;
13
- /** 表单项说明:label 后 ⓘ,悬浮显示 tooltip */
14
- hint?: string;
15
- /** 是否必填(switch 始终有值,仅语义标记) */
16
- required?: boolean;
17
13
  onchange: (value: boolean) => void;
18
14
  }
19
15
 
20
16
  /** 开关组件(参考 antd Switch):布尔切换控件,可配置选中/未选中文案。
21
- 与表单其他字段同构(label-row 在前、内容在后),表单 layout:horizontal 时 label 在左、开关在右 */
17
+ label 在上(与表单其他字段同构),表单布局切换时位置自动跟随 */
22
18
  export const Switch: React.FC<SwitchProps> = ({
23
19
  label = '',
24
20
  default: initial = false,
25
21
  checkedText = '',
26
22
  unCheckedText = '',
27
23
  disabled = false,
28
- hint = '',
29
- required = false,
30
24
  onchange
31
25
  }) => {
32
26
  const [checked, setChecked] = useState(initial);
@@ -40,13 +34,7 @@ export const Switch: React.FC<SwitchProps> = ({
40
34
 
41
35
  return (
42
36
  <div className="widget-switch">
43
- {label || hint || required ? (
44
- <div className="widget-label-row switch-label-row">
45
- {required && <span className="widget-required-mark" aria-hidden="true">*</span>}
46
- {label && <label>{label}</label>}
47
- {hint && <span className="widget-hint" data-hint={hint}>ⓘ</span>}
48
- </div>
49
- ) : null}
37
+ {label && <label>{label}</label>}
50
38
  <div className="widget-field-content">
51
39
  <button
52
40
  type="button"
@@ -1,76 +1,38 @@
1
- import React, { useState } from 'react';
2
-
3
- export interface TextInputProps {
4
- placeholder?: string;
5
- label?: string;
6
- default?: string;
7
- hint?: string;
8
- /** 是否必填:label 前红色 * */
9
- required?: boolean;
10
- /** 正则校验规则(JS 正则源字符串) */
11
- pattern?: string;
12
- /** 校验失败提示文案 */
13
- message?: string;
14
- /** 外部(form 提交时)传入的错误信息,优先于组件内部即时校验 */
15
- error?: string;
16
- /** 是否禁用 */
17
- disabled?: boolean;
18
- onchange: (value: string) => void;
19
- }
20
-
21
- export const TextInput: React.FC<TextInputProps> = ({
22
- placeholder = '',
23
- label = '',
24
- default: initial = '',
25
- hint = '',
26
- required = false,
27
- pattern,
28
- message = '',
29
- error = '',
30
- disabled = false,
31
- onchange
32
- }) => {
33
- const [value, setValue] = useState(initial);
34
- const [localError, setLocalError] = useState('');
35
-
36
- /** 校验当前值:返回错误文案或空串 */
37
- const validate = (v: string): string => {
38
- if (required && !v.trim()) return message || (label ? `请填写${label}` : '该项为必填项');
39
- if (pattern && v && !new RegExp(pattern).test(v)) return message || (label ? `${label}格式不正确` : '格式不正确');
40
- return '';
41
- };
42
-
43
- const commit = () => {
44
- setLocalError(validate(value));
45
- onchange(value);
46
- };
47
-
48
- const shownError = error || localError;
49
-
50
- return (
51
- <div className={`widget-text-input${shownError ? ' widget-field-error' : ''}`}>
52
- {label || hint || required ? (
53
- <div className="widget-label-row">
54
- {required && <span className="widget-required-mark" aria-hidden="true">*</span>}
55
- {label && <label>{label}</label>}
56
- {hint && <span className="widget-hint" data-hint={hint}>ⓘ</span>}
57
- </div>
58
- ) : null}
59
- <div className="widget-field-content">
60
- <input
61
- type="text"
62
- className={shownError ? 'widget-input-error' : undefined}
63
- value={value}
64
- onChange={(e) => {
65
- setValue(e.target.value);
66
- if (localError) setLocalError(validate(e.target.value));
67
- }}
68
- onBlur={commit}
69
- placeholder={placeholder}
70
- disabled={disabled}
71
- />
72
- {shownError ? <div className="widget-error-text" role="alert">{shownError}</div> : null}
73
- </div>
74
- </div>
75
- );
76
- };
1
+ import React, { useState } from 'react';
2
+
3
+ export interface TextInputProps {
4
+ placeholder?: string;
5
+ label?: string;
6
+ default?: string;
7
+ /** 是否禁用 */
8
+ disabled?: boolean;
9
+ onchange: (value: string) => void;
10
+ }
11
+
12
+ export const TextInput: React.FC<TextInputProps> = ({
13
+ placeholder = '',
14
+ label = '',
15
+ default: initial = '',
16
+ disabled = false,
17
+ onchange
18
+ }) => {
19
+ const [value, setValue] = useState(initial);
20
+
21
+ const handleBlur = () => {
22
+ onchange(value);
23
+ };
24
+
25
+ return (
26
+ <div className="widget-text-input">
27
+ {label && <label>{label}</label>}
28
+ <input
29
+ type="text"
30
+ value={value}
31
+ onChange={(e) => setValue(e.target.value)}
32
+ onBlur={handleBlur}
33
+ placeholder={placeholder}
34
+ disabled={disabled}
35
+ />
36
+ </div>
37
+ );
38
+ };