@team-monolith/cds 1.8.3 → 1.8.5
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/dist/patterns/LexicalEditor/nodes/ProblemInputNode/Form/FormAnswer.d.ts +1 -1
- package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/Form/FormAnswer.js +5 -7
- package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/Form/FormCharacterCount.d.ts +1 -1
- package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/Form/FormPlaceholder.d.ts +1 -1
- package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/InputComponent.d.ts +5 -13
- package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/InputComponent.js +22 -12
- package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/ProblemInputNode.d.ts +23 -4
- package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/ProblemInputNode.js +23 -11
- package/dist/patterns/LexicalEditor/plugins/ComponentPickerMenuPlugin/ComponentPickerMenuPlugin.js +1 -0
- package/package.json +1 -1
|
@@ -11,7 +11,7 @@ import Tooltip from "../../../../../components/Tooltip";
|
|
|
11
11
|
export function FormAnswer(props) {
|
|
12
12
|
const { index, control, onDelete, disabled } = props;
|
|
13
13
|
const theme = useTheme();
|
|
14
|
-
const TextTypeDropdown = (_jsx(Controller, { name: `answers.${index}.textType`, control: control, render: ({ field }) => (_jsx(Dropdown, Object.assign({ label:
|
|
14
|
+
const TextTypeDropdown = (_jsx(Controller, { name: `answers.${index}.textType`, control: control, render: ({ field: { value, onChange } }) => (_jsx(Dropdown, Object.assign({ label: value === "normal" ? "일반 텍스트" : "코드 텍스트", size: "xsmall", color: "textNeutral", closeOnItemClick: true, disabled: disabled, buttonCss: css `
|
|
15
15
|
${disabled && `color: ${theme.color.foreground.neutralAlt};`}
|
|
16
16
|
> span {
|
|
17
17
|
font-weight: 700;
|
|
@@ -25,14 +25,12 @@ export function FormAnswer(props) {
|
|
|
25
25
|
vertical: "top",
|
|
26
26
|
horizontal: "center",
|
|
27
27
|
},
|
|
28
|
-
} }, { children:
|
|
29
|
-
|
|
30
|
-
} }))
|
|
31
|
-
field.onChange("code");
|
|
32
|
-
} })) }))) }));
|
|
28
|
+
} }, { children: _jsx(DropdownItem, { index: 0, label: value === "normal" ? "코드 텍스트" : "일반 텍스트", onClick: () => {
|
|
29
|
+
onChange(value === "normal" ? "code" : "normal");
|
|
30
|
+
} }) }))) }));
|
|
33
31
|
return (_jsx(Controller, { name: `answers.${index}.value`, control: control, rules: {
|
|
34
32
|
required: "정답을 입력해주세요.",
|
|
35
|
-
}, render: ({ field: {
|
|
33
|
+
}, render: ({ field: { value, onChange }, fieldState: { invalid, error }, }) => (_jsx(Input, { size: "small", color: invalid ? "activeDanger" : "default", onChange: onChange, disabled: disabled, value: value, hintIcon: invalid ? _jsx(ErrorWarningFillIcon, {}) : undefined, hintText: error === null || error === void 0 ? void 0 : error.message, placeholder: "\uC548\uB155\uD558\uC138\uC694", fullWidth: true, css: css `
|
|
36
34
|
> div {
|
|
37
35
|
padding: 4px 12px;
|
|
38
36
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Control } from "react-hook-form";
|
|
2
|
-
import { ProblemInputPayload } from "../InputComponent";
|
|
3
2
|
import React from "react";
|
|
3
|
+
import { ProblemInputPayload } from "../ProblemInputNode";
|
|
4
4
|
export interface FormCharacterCountProps {
|
|
5
5
|
control: Control<ProblemInputPayload, any>;
|
|
6
6
|
setMultiAnswerDisabled: React.Dispatch<React.SetStateAction<boolean>>;
|
|
@@ -1,17 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
export
|
|
4
|
-
textType: "normal" | "code";
|
|
5
|
-
value: string;
|
|
6
|
-
destroyed?: boolean;
|
|
7
|
-
}
|
|
8
|
-
export interface ProblemInputPayload {
|
|
9
|
-
key?: NodeKey;
|
|
1
|
+
import { Answer } from "./ProblemInputNode";
|
|
2
|
+
import { NodeKey } from "lexical";
|
|
3
|
+
export declare function InputComponent(props: {
|
|
10
4
|
answers: Answer[];
|
|
11
5
|
showCharacterCount: boolean;
|
|
12
6
|
placeholder: string;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export declare function InputComponent(props: {
|
|
16
|
-
node: ProblemInputNode;
|
|
7
|
+
response: string;
|
|
8
|
+
nodeKey: NodeKey;
|
|
17
9
|
}): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
@@ -12,26 +12,23 @@ import Button from "../../../../components/Button";
|
|
|
12
12
|
import Tooltip from "../../../../components/Tooltip";
|
|
13
13
|
import { FormAnswer, FormCharacterCount, FormPlaceholder } from "./Form";
|
|
14
14
|
import useLexicalEditable from "@lexical/react/useLexicalEditable";
|
|
15
|
+
import { $isProblemInputNode, } from "./ProblemInputNode";
|
|
15
16
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
17
|
+
import { $getNodeByKey } from "lexical";
|
|
16
18
|
export function InputComponent(props) {
|
|
17
|
-
var _a;
|
|
18
19
|
const theme = useTheme();
|
|
19
|
-
const {
|
|
20
|
+
const { answers, showCharacterCount, placeholder, response, nodeKey } = props;
|
|
20
21
|
const [editor] = useLexicalComposerContext();
|
|
21
|
-
const answers = node.getAnswers();
|
|
22
|
-
const showCharacterCount = node.getShowCharacterCount();
|
|
23
|
-
const placeholder = node.getPlaceholder();
|
|
24
22
|
const [settingOpen, setSettingOpen] = useState(false);
|
|
25
23
|
const [multiAnswerDisabled, setMultiAnswerDisabled] = useState(showCharacterCount);
|
|
26
24
|
const isEditable = useLexicalEditable();
|
|
27
|
-
const { control, handleSubmit
|
|
25
|
+
const { control, handleSubmit } = useForm({
|
|
28
26
|
defaultValues: {
|
|
29
27
|
answers,
|
|
30
28
|
showCharacterCount,
|
|
31
29
|
placeholder,
|
|
32
30
|
},
|
|
33
31
|
});
|
|
34
|
-
// TODO: 읽기전용 모드(학생 view)에서 문제 제출 api를 추가해야 합니다.
|
|
35
32
|
const { fields, append, remove, update } = useFieldArray({
|
|
36
33
|
control,
|
|
37
34
|
name: "answers",
|
|
@@ -39,26 +36,39 @@ export function InputComponent(props) {
|
|
|
39
36
|
});
|
|
40
37
|
const onSettingSubmit = (data) => {
|
|
41
38
|
editor.update(() => {
|
|
39
|
+
const node = $getNodeByKey(nodeKey);
|
|
40
|
+
if (!$isProblemInputNode(node)) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
42
43
|
node.setAnswers(data.answers);
|
|
43
44
|
node.setShowCharacterCount(data.showCharacterCount);
|
|
44
45
|
node.setPlaceholder(data.placeholder);
|
|
45
46
|
});
|
|
46
47
|
setSettingOpen(false);
|
|
47
48
|
};
|
|
48
|
-
//
|
|
49
|
-
|
|
49
|
+
// 학생 view
|
|
50
|
+
// TODO: "글자 수대로" 옵션시에 글자 수대로 입력칸을 표시해야 합니다.
|
|
50
51
|
if (!isEditable) {
|
|
51
|
-
return (_jsx(Input, { size: "small", placeholder:
|
|
52
|
-
|
|
52
|
+
return (_jsx(Input, { size: "small", placeholder: placeholder || "여기에 입력하세요.", value: response, onChange: (e) => {
|
|
53
|
+
editor.update(() => {
|
|
54
|
+
const node = $getNodeByKey(nodeKey);
|
|
55
|
+
if (!$isProblemInputNode(node)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
node.setResponse(e.target.value);
|
|
59
|
+
});
|
|
53
60
|
}, color: "default", css: css `
|
|
54
61
|
width: 300px;
|
|
55
62
|
` }));
|
|
56
63
|
}
|
|
64
|
+
// 교사 edit view
|
|
57
65
|
return (_jsxs(Suspense, Object.assign({ fallback: null }, { children: [_jsxs("div", Object.assign({ css: css `
|
|
58
66
|
display: flex;
|
|
59
67
|
align-items: center;
|
|
60
68
|
gap: 4px;
|
|
61
|
-
` }, { children: [_jsx(Input, { size: "small", placeholder: "주관식 입력 칸",
|
|
69
|
+
` }, { children: [_jsx(Input, { size: "small", placeholder: "주관식 입력 칸", value: "", onChange: () => {
|
|
70
|
+
// 수정모드에서는 입력칸 수정을 허용하지 않습니다.
|
|
71
|
+
}, color: "default", css: css `
|
|
62
72
|
width: 300px;
|
|
63
73
|
` }), _jsx(SquareButton, { size: "small", color: "icon", icon: _jsx(Settings3FillIcon, {}), onClick: () => {
|
|
64
74
|
setSettingOpen(true);
|
|
@@ -1,24 +1,43 @@
|
|
|
1
|
-
import { DecoratorNode, EditorConfig, LexicalNode, NodeKey } from "lexical";
|
|
1
|
+
import { DecoratorNode, EditorConfig, LexicalNode, NodeKey, SerializedLexicalNode, Spread } from "lexical";
|
|
2
2
|
import { ReactNode } from "react";
|
|
3
|
-
|
|
3
|
+
export interface Answer {
|
|
4
|
+
textType: "normal" | "code";
|
|
5
|
+
value: string;
|
|
6
|
+
destroyed?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface ProblemInputPayload {
|
|
9
|
+
showCharacterCount: boolean;
|
|
10
|
+
placeholder: string;
|
|
11
|
+
answers: Answer[];
|
|
12
|
+
response: string;
|
|
13
|
+
key?: NodeKey;
|
|
14
|
+
}
|
|
15
|
+
export type SerializedProblemInputNode = Spread<ProblemInputPayload, SerializedLexicalNode>;
|
|
16
|
+
/**
|
|
17
|
+
* answers는 Answer타입의 배열로서 정답을 담고 있습니다. (교사용)
|
|
18
|
+
* response는 학생이 입력한 답을 담고 있습니다.(학생용)
|
|
19
|
+
*/
|
|
4
20
|
export declare class ProblemInputNode extends DecoratorNode<ReactNode> {
|
|
5
21
|
__answers: Answer[];
|
|
6
22
|
__showCharacterCount: boolean;
|
|
7
23
|
__placeholder: string;
|
|
24
|
+
__response: string;
|
|
8
25
|
static getType(): string;
|
|
9
26
|
getAnswers(): Answer[];
|
|
10
27
|
getShowCharacterCount(): boolean;
|
|
11
28
|
getPlaceholder(): string;
|
|
29
|
+
getResponse(): string;
|
|
12
30
|
setAnswers(answers: Answer[]): void;
|
|
13
31
|
setShowCharacterCount(showCharacterCount: boolean): void;
|
|
14
32
|
setPlaceholder(placeholder: string): void;
|
|
33
|
+
setResponse(response: string): void;
|
|
15
34
|
static clone(node: ProblemInputNode): ProblemInputNode;
|
|
16
|
-
constructor(answers: Answer[],
|
|
35
|
+
constructor(showCharacterCount: boolean, placeholder: string, answers: Answer[], response: string, key?: NodeKey);
|
|
17
36
|
createDOM(config: EditorConfig): HTMLElement;
|
|
18
37
|
updateDOM(): boolean;
|
|
19
38
|
static importJSON(serializedNode: SerializedProblemInputNode): ProblemInputNode;
|
|
20
39
|
exportJSON(): SerializedProblemInputNode;
|
|
21
40
|
decorate(): ReactNode;
|
|
22
41
|
}
|
|
23
|
-
export declare function $createProblemInputNode({
|
|
42
|
+
export declare function $createProblemInputNode({ showCharacterCount, placeholder, answers, response, key, }: ProblemInputPayload): ProblemInputNode;
|
|
24
43
|
export declare function $isProblemInputNode(node: LexicalNode | null | undefined): node is ProblemInputNode;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { $applyNodeReplacement, DecoratorNode, } from "lexical";
|
|
3
3
|
import { addClassNamesToElement } from "@lexical/utils";
|
|
4
|
-
import { InputComponent
|
|
4
|
+
import { InputComponent } from "./InputComponent";
|
|
5
|
+
/**
|
|
6
|
+
* answers는 Answer타입의 배열로서 정답을 담고 있습니다. (교사용)
|
|
7
|
+
* response는 학생이 입력한 답을 담고 있습니다.(학생용)
|
|
8
|
+
*/
|
|
5
9
|
export class ProblemInputNode extends DecoratorNode {
|
|
6
10
|
static getType() {
|
|
7
11
|
return "problem-input";
|
|
@@ -15,6 +19,9 @@ export class ProblemInputNode extends DecoratorNode {
|
|
|
15
19
|
getPlaceholder() {
|
|
16
20
|
return this.__placeholder;
|
|
17
21
|
}
|
|
22
|
+
getResponse() {
|
|
23
|
+
return this.__response;
|
|
24
|
+
}
|
|
18
25
|
setAnswers(answers) {
|
|
19
26
|
const self = this.getWritable();
|
|
20
27
|
self.__answers = answers;
|
|
@@ -27,19 +34,25 @@ export class ProblemInputNode extends DecoratorNode {
|
|
|
27
34
|
const self = this.getWritable();
|
|
28
35
|
self.__placeholder = placeholder;
|
|
29
36
|
}
|
|
37
|
+
setResponse(response) {
|
|
38
|
+
const self = this.getWritable();
|
|
39
|
+
self.__response = response;
|
|
40
|
+
}
|
|
30
41
|
static clone(node) {
|
|
31
42
|
return $createProblemInputNode({
|
|
32
|
-
key: node.__key,
|
|
33
|
-
answers: node.__answers,
|
|
34
43
|
showCharacterCount: node.__showCharacterCount,
|
|
35
44
|
placeholder: node.__placeholder,
|
|
45
|
+
answers: node.__answers,
|
|
46
|
+
response: node.__response,
|
|
47
|
+
key: node.__key,
|
|
36
48
|
});
|
|
37
49
|
}
|
|
38
|
-
constructor(
|
|
50
|
+
constructor(showCharacterCount, placeholder, answers, response, key) {
|
|
39
51
|
super(key);
|
|
40
52
|
this.__answers = answers;
|
|
41
53
|
this.__showCharacterCount = showCharacterCount;
|
|
42
54
|
this.__placeholder = placeholder;
|
|
55
|
+
this.__response = response;
|
|
43
56
|
}
|
|
44
57
|
createDOM(config) {
|
|
45
58
|
// Define the DOM element here
|
|
@@ -56,6 +69,7 @@ export class ProblemInputNode extends DecoratorNode {
|
|
|
56
69
|
answers: serializedNode.answers,
|
|
57
70
|
showCharacterCount: serializedNode.showCharacterCount,
|
|
58
71
|
placeholder: serializedNode.placeholder,
|
|
72
|
+
response: serializedNode.response,
|
|
59
73
|
});
|
|
60
74
|
return node;
|
|
61
75
|
}
|
|
@@ -63,20 +77,18 @@ export class ProblemInputNode extends DecoratorNode {
|
|
|
63
77
|
return {
|
|
64
78
|
version: 1,
|
|
65
79
|
type: "problem-input",
|
|
66
|
-
answers: this.__answers,
|
|
67
80
|
showCharacterCount: this.__showCharacterCount,
|
|
68
81
|
placeholder: this.__placeholder,
|
|
82
|
+
answers: this.__answers,
|
|
83
|
+
response: this.__response,
|
|
69
84
|
};
|
|
70
85
|
}
|
|
71
|
-
// TODO: 이 노드의 selected가 제대로 동작하지 않습니다.
|
|
72
|
-
// nodeKey를 전달하고 getNodeByKey로 노드를 찾는 것이 일반적이나
|
|
73
|
-
// 현재 이 노드가 selected가 제대로 동작하지 않아서 노드를 직접 전달했습니다.
|
|
74
86
|
decorate() {
|
|
75
|
-
return _jsx(InputComponent, {
|
|
87
|
+
return (_jsx(InputComponent, { answers: this.__answers, showCharacterCount: this.__showCharacterCount, placeholder: this.__placeholder, response: this.__response, nodeKey: this.getKey() }));
|
|
76
88
|
}
|
|
77
89
|
}
|
|
78
|
-
export function $createProblemInputNode({
|
|
79
|
-
return $applyNodeReplacement(new ProblemInputNode(
|
|
90
|
+
export function $createProblemInputNode({ showCharacterCount, placeholder, answers, response, key, }) {
|
|
91
|
+
return $applyNodeReplacement(new ProblemInputNode(showCharacterCount, placeholder, answers, response, key));
|
|
80
92
|
}
|
|
81
93
|
export function $isProblemInputNode(node) {
|
|
82
94
|
return node instanceof ProblemInputNode;
|