@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.
- package/README.md +6 -24
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3733 -4365
- package/dist/lib/MarkdownUI.d.ts +10 -0
- package/dist/lib/MarkdownUI.d.ts.map +1 -0
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/widgets/Button.d.ts +15 -0
- package/dist/widgets/Button.d.ts.map +1 -0
- package/dist/widgets/ButtonGroup.d.ts +11 -0
- package/dist/widgets/ButtonGroup.d.ts.map +1 -0
- package/dist/widgets/Cascader.d.ts +34 -0
- package/dist/widgets/Cascader.d.ts.map +1 -0
- package/dist/widgets/Chart.d.ts +20 -0
- package/dist/widgets/Chart.d.ts.map +1 -0
- package/dist/widgets/DatePicker.d.ts +28 -0
- package/dist/widgets/DatePicker.d.ts.map +1 -0
- package/dist/widgets/Form.d.ts +47 -0
- package/dist/widgets/Form.d.ts.map +1 -0
- package/dist/widgets/Incomplete.d.ts +3 -0
- package/dist/widgets/Incomplete.d.ts.map +1 -0
- package/dist/widgets/MultipleChoiceQuestion.d.ts +15 -0
- package/dist/widgets/MultipleChoiceQuestion.d.ts.map +1 -0
- package/dist/widgets/NumberInput.d.ts +26 -0
- package/dist/widgets/NumberInput.d.ts.map +1 -0
- package/dist/widgets/Quiz.d.ts +37 -0
- package/dist/widgets/Quiz.d.ts.map +1 -0
- package/dist/widgets/Radio.d.ts +24 -0
- package/dist/widgets/Radio.d.ts.map +1 -0
- package/dist/widgets/Select.d.ts +15 -0
- package/dist/widgets/Select.d.ts.map +1 -0
- package/dist/widgets/SelectMulti.d.ts +20 -0
- package/dist/widgets/SelectMulti.d.ts.map +1 -0
- package/dist/widgets/ShortAnswerQuestion.d.ts +16 -0
- package/dist/widgets/ShortAnswerQuestion.d.ts.map +1 -0
- package/dist/widgets/Slider.d.ts +13 -0
- package/dist/widgets/Slider.d.ts.map +1 -0
- package/dist/widgets/Switch.d.ts +17 -0
- package/dist/widgets/Switch.d.ts.map +1 -0
- package/dist/widgets/TextInput.d.ts +11 -0
- package/dist/widgets/TextInput.d.ts.map +1 -0
- package/dist/widgets/Widget.d.ts +7 -0
- package/dist/widgets/Widget.d.ts.map +1 -0
- package/dist/widgets/chartRemoteData.d.ts +18 -0
- package/dist/widgets/chartRemoteData.d.ts.map +1 -0
- package/dist/widgets/choiceUtils.d.ts +24 -0
- package/dist/widgets/choiceUtils.d.ts.map +1 -0
- package/dist/widgets/index.d.ts +18 -0
- package/dist/widgets/index.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/lib/MarkdownUI.tsx +9 -47
- package/src/lib/widgets.css +1372 -2188
- package/src/widgets/Button.tsx +39 -39
- package/src/widgets/ButtonGroup.tsx +47 -47
- package/src/widgets/Cascader.tsx +2 -3
- package/src/widgets/Chart.tsx +237 -237
- package/src/widgets/DatePicker.tsx +434 -451
- package/src/widgets/Form.tsx +372 -512
- package/src/widgets/Incomplete.tsx +3 -3
- package/src/widgets/MultipleChoiceQuestion.tsx +82 -82
- package/src/widgets/Quiz.tsx +320 -320
- package/src/widgets/Radio.tsx +26 -57
- package/src/widgets/Select.tsx +142 -178
- package/src/widgets/SelectMulti.tsx +72 -105
- package/src/widgets/ShortAnswerQuestion.tsx +101 -101
- package/src/widgets/Slider.tsx +56 -70
- package/src/widgets/Switch.tsx +2 -14
- package/src/widgets/TextInput.tsx +38 -76
- package/src/widgets/Widget.tsx +82 -130
- package/src/widgets/choiceUtils.ts +45 -90
- package/src/widgets/index.ts +16 -17
- 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
|
+
};
|
package/src/widgets/Slider.tsx
CHANGED
|
@@ -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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
min,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
{
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
};
|
package/src/widgets/Switch.tsx
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
+
};
|