@team-monolith/cds 1.8.4 → 1.8.6

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 (16) hide show
  1. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/InputComponent.d.ts +7 -2
  2. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/InputComponent.js +41 -143
  3. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/ProblemInputNode.d.ts +14 -13
  4. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/ProblemInputNode.js +24 -30
  5. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/{Form/FormAnswer.d.ts → SettingForm/FormSolution.d.ts} +1 -1
  6. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/{Form/FormAnswer.js → SettingForm/FormSolution.js} +7 -9
  7. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/SettingForm/SettingForm.d.ts +10 -0
  8. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/SettingForm/SettingForm.js +149 -0
  9. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/{Form → SettingForm}/index.d.ts +2 -1
  10. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/{Form → SettingForm}/index.js +2 -1
  11. package/dist/patterns/LexicalEditor/plugins/ComponentPickerMenuPlugin/ComponentPickerMenuPlugin.js +2 -2
  12. package/package.json +1 -1
  13. /package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/{Form → SettingForm}/FormCharacterCount.d.ts +0 -0
  14. /package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/{Form → SettingForm}/FormCharacterCount.js +0 -0
  15. /package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/{Form → SettingForm}/FormPlaceholder.d.ts +0 -0
  16. /package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/{Form → SettingForm}/FormPlaceholder.js +0 -0
@@ -1,4 +1,9 @@
1
- import { ProblemInputNode } from "./ProblemInputNode";
1
+ import { Solution } from "./ProblemInputNode";
2
+ import { NodeKey } from "lexical";
2
3
  export declare function InputComponent(props: {
3
- node: ProblemInputNode;
4
+ solutions: Solution[];
5
+ showCharacterCount: boolean;
6
+ placeholder: string;
7
+ answer: string;
8
+ nodeKey: NodeKey;
4
9
  }): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,172 +1,70 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/react/jsx-runtime";
2
13
  /** @jsxImportSource @emotion/react */
3
- import { css, useTheme } from "@emotion/react";
4
- import { Suspense, useState } from "react";
5
- import { useForm, useFieldArray } from "react-hook-form";
14
+ import { css } from "@emotion/react";
15
+ import { useState } from "react";
6
16
  import Input from "../../../../components/Input";
7
17
  import SquareButton from "../../../../components/SquareButton";
8
- import { AddFillIcon, AlarmWarningFillIcon, InputMethodLineIcon, QuestionFillIcon, Settings3FillIcon, } from "../../../../icons";
18
+ import { Settings3FillIcon } from "../../../../icons";
9
19
  import styled from "@emotion/styled";
10
- import shadows from "../../../../foundation/shadows";
11
- import Button from "../../../../components/Button";
12
- import Tooltip from "../../../../components/Tooltip";
13
- import { FormAnswer, FormCharacterCount, FormPlaceholder } from "./Form";
20
+ import SettingForm from "./SettingForm";
14
21
  import useLexicalEditable from "@lexical/react/useLexicalEditable";
22
+ import { $isProblemInputNode, } from "./ProblemInputNode";
15
23
  import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
24
+ import { $getNodeByKey } from "lexical";
16
25
  export function InputComponent(props) {
17
- const theme = useTheme();
18
- const { node } = props;
26
+ const { answer } = props, settingFormProps = __rest(props, ["answer"]);
27
+ const { placeholder, nodeKey } = settingFormProps;
19
28
  const [editor] = useLexicalComposerContext();
20
- const answers = node.getAnswers();
21
- const showCharacterCount = node.getShowCharacterCount();
22
- const placeholder = node.getPlaceholder();
23
- const response = node.getResponse();
24
29
  const [settingOpen, setSettingOpen] = useState(false);
25
- const [multiAnswerDisabled, setMultiAnswerDisabled] = useState(showCharacterCount);
26
30
  const isEditable = useLexicalEditable();
27
- const { control, handleSubmit, getValues } = useForm({
28
- defaultValues: {
29
- answers: answers !== null && answers !== void 0 ? answers : [],
30
- showCharacterCount,
31
- placeholder,
32
- },
33
- });
34
- const { fields, append, remove, update } = useFieldArray({
35
- control,
36
- name: "answers",
37
- keyName: "uid",
38
- });
39
- const onSettingSubmit = (data) => {
40
- editor.update(() => {
41
- node.setAnswers(data.answers);
42
- node.setShowCharacterCount(data.showCharacterCount);
43
- node.setPlaceholder(data.placeholder);
44
- });
45
- setSettingOpen(false);
46
- };
47
31
  // 학생 view
32
+ // TODO: "글자 수대로" 옵션시에 글자 수대로 입력칸을 표시해야 합니다.
48
33
  if (!isEditable) {
49
- return (_jsx(Input, { size: "small", placeholder: getValues("placeholder") || "여기에 입력하세요.", value: response, onChange: (e) => {
34
+ return (_jsx(Input, { size: "small", placeholder: placeholder || "여기에 입력하세요.", value: answer, onChange: (e) => {
50
35
  editor.update(() => {
51
- node.setResponse(e.target.value);
36
+ const node = $getNodeByKey(nodeKey);
37
+ if (!$isProblemInputNode(node)) {
38
+ return;
39
+ }
40
+ node.setAnswer(e.target.value);
52
41
  });
53
42
  }, color: "default", css: css `
54
43
  width: 300px;
55
44
  ` }));
56
45
  }
57
46
  // 교사 edit view
58
- return (_jsxs(Suspense, Object.assign({ fallback: null }, { children: [_jsxs("div", Object.assign({ css: css `
47
+ return (_jsxs(_Fragment, { children: [_jsxs("div", Object.assign({ css: css `
59
48
  display: flex;
60
49
  align-items: center;
61
50
  gap: 4px;
62
- ` }, { children: [_jsx(Input, { size: "small", placeholder: "주관식 입력 ", value: "", onChange: () => {
63
- // 수정모드에서는 입력칸 수정을 허용하지 않습니다.
64
- }, color: "default", css: css `
65
- width: 300px;
66
- ` }), _jsx(SquareButton, { size: "small", color: "icon", icon: _jsx(Settings3FillIcon, {}), onClick: () => {
51
+ ` }, { children: [_jsx(VirtualInput, Object.assign({ onClick: () => setSettingOpen(true) }, { children: "\uC8FC\uAD00\uC2DD \uC785\uB825 \uCE78" })), _jsx(SquareButton, { size: "small", color: "icon", icon: _jsx(Settings3FillIcon, {}), onClick: () => {
67
52
  setSettingOpen(true);
68
- } })] })), settingOpen && (_jsxs(SettingForm, Object.assign({ onSubmit: handleSubmit(onSettingSubmit) }, { children: [_jsxs(Title, { children: [_jsx(InputMethodLineIcon, { css: css `
69
- width: 12px;
70
- height: 12px;
71
- ` }), "\uC8FC\uAD00\uC2DD \uC785\uB825 \uCE78"] }), _jsxs(Content, { children: [_jsxs(Left, { children: [_jsxs(FormArea, { children: [_jsx(Label, { children: "\uC815\uB2F5" }), fields
72
- .map((field, index) => ({
73
- field,
74
- index,
75
- }))
76
- .filter(({ field }) => !field.destroyed)
77
- .map(({ field, index }) => (_jsx(FormAnswer, { index: index, control: control, disabled: index !== 0 && multiAnswerDisabled, onDelete: index !== 0
78
- ? () => {
79
- if (field.value) {
80
- update(index, Object.assign(Object.assign({}, field), { destroyed: true }));
81
- }
82
- else {
83
- remove(index);
84
- }
85
- }
86
- : undefined }, field.uid)))] }), _jsx(Button, { color: "grey", size: "small", startIcon: _jsx(AddFillIcon, {}), label: "\uBCF5\uC218 \uC815\uB2F5 \uCD94\uAC00", disabled: multiAnswerDisabled, onClick: () => {
87
- append({
88
- textType: "normal",
89
- value: "",
90
- });
91
- } }), _jsxs("div", Object.assign({ css: css `
92
- display: flex;
93
- gap: 4px;
94
- ` }, { children: [_jsx(AlarmWarningFillIcon, { color: theme.color.foreground.neutralBaseDisabled, css: css `
95
- width: 14px;
96
- height: 14px;
97
- ` }), _jsxs(Label, { children: ["\uB744\uC5B4\uC4F0\uAE30, \uC54C\uD30C\uBCB3\uC758 \uB300\uC18C\uBB38\uC790 \uAD6C\uBD84\uAE4C\uC9C0 \uC77C\uCE58\uD574\uC57C \uC815\uB2F5\uC73C\uB85C \uCC98\uB9AC\uB429\uB2C8\uB2E4.", _jsx("br", {}), "\uAC00\uB2A5\uD55C \uC815\uB2F5\uC744 \uBAA8\uB450 \uCD94\uAC00\uD574\uC57C \uC6D0\uD65C\uD558\uAC8C \uC790\uB3D9 \uCC44\uC810\uD560 \uC218 \uC788\uC5B4\uC694."] })] }))] }), _jsxs(Right, { children: [_jsxs(FormArea, { children: [_jsxs(Label, { children: ["\uC785\uB825 \uCE78", _jsx(Tooltip, Object.assign({ text: _jsxs("span", { children: ["\uC608\uB97C \uB4E4\uC5B4 \uC815\uB2F5\uC774 '\uAE00\uC790 \uC218'\uC774\uACE0", _jsx("br", {}), _jsx("b", { children: "\uAE00\uC790 \uC218\uB300\uB85C" }), " \uC635\uC158\uC744 \uC120\uD0DD\uD588\uB2E4\uBA74", _jsx("br", {}), "\uC785\uB825 \uCE78\uC774 '\u2610\u2610 \u2610' \uCC98\uB7FC \uD45C\uC2DC\uB429\uB2C8\uB2E4."] }), placement: "top" }, { children: _jsx(QuestionFillIcon, { css: css `
98
- width: 12px;
99
- height: 12px;
100
- ` }) }))] }), _jsx(FormCharacterCount, { control: control, setMultiAnswerDisabled: setMultiAnswerDisabled })] }), _jsxs(FormArea, { children: [_jsxs(Label, { children: ["\uC790\uB9AC \uD45C\uC2DC\uC790", _jsx(Tooltip, Object.assign({ text: _jsx("span", { children: "\uC785\uB825 \uCE78\uC5D0 \uAE30\uBCF8\uC73C\uB85C \uB178\uCD9C\uB418\uB294 \uD14D\uC2A4\uD2B8\uC785\uB2C8\uB2E4." }), placement: "top" }, { children: _jsx(QuestionFillIcon, { css: css `
101
- width: 12px;
102
- height: 12px;
103
- ` }) }))] }), _jsx(FormPlaceholder, { control: control })] })] })] }), _jsxs(Buttons, { children: [_jsx(Button, { color: "grey", size: "xsmall", label: "\uB2EB\uAE30", onClick: () => {
104
- setSettingOpen(false);
105
- } }), _jsx(Button, { color: "primary", size: "xsmall", label: "\uC774\uB300\uB85C \uB123\uAE30", type: "submit" })] })] })))] })));
53
+ } })] })), settingOpen && (_jsx(SettingForm, Object.assign({}, settingFormProps, { onClose: () => setSettingOpen(false) })))] }));
106
54
  }
107
- const SettingForm = styled.form(({ theme }) => css `
108
- display: flex;
109
- width: 620px;
110
- flex-direction: column;
111
- border-radius: 6px;
112
- border: 1px solid ${theme.color.background.neutralAltActive};
113
- background: ${theme.color.background.neutralBase};
114
- box-shadow: ${shadows.shadow08};
115
- `);
116
- const Title = styled.div(({ theme }) => css `
117
- display: flex;
118
- padding: 8px 12px;
119
- gap: 4px;
120
- align-items: center;
121
- color: ${theme.color.foreground.neutralBase};
122
- /* Default/Label/12px-Md */
123
- font-family: ${theme.fontFamily.ui};
124
- font-size: 12px;
125
- font-style: normal;
126
- font-weight: 500;
127
- line-height: 16px; /* 133.333% */
128
- `);
129
- const Content = styled.div(({ theme }) => css `
130
- display: flex;
131
- border-top: 1px solid ${theme.color.background.neutralAltActive};
132
- border-bottom: 1px solid ${theme.color.background.neutralAltActive};
133
- `);
134
- const Left = styled.div `
135
- display: flex;
136
- flex-direction: column;
137
- padding: 12px;
138
- gap: 12px;
139
- flex: 1;
140
- `;
141
- const FormArea = styled.div `
142
- display: flex;
143
- flex-direction: column;
144
- gap: 8px;
145
- `;
146
- const Right = styled.div `
147
- display: flex;
148
- box-sizing: border-box;
149
- width: 240px;
150
- flex-direction: column;
151
- padding: 12px;
152
- gap: 12px;
153
- `;
154
- const Label = styled.div(({ theme }) => css `
155
- display: flex;
156
- gap: 4px;
55
+ const VirtualInput = styled.div(({ theme }) => css `
56
+ box-sizing: border-box;
57
+ height: 36px;
58
+ width: 300px;
59
+ padding: 8px 16px;
157
60
  align-items: center;
61
+ border-radius: 8px;
62
+ background: ${theme.color.background.neutralAlt};
63
+ cursor: pointer;
158
64
  color: ${theme.color.foreground.neutralBaseDisabled};
159
- /* Default/Label/12px-Md */
160
65
  font-family: ${theme.fontFamily.ui};
161
- font-size: 12px;
66
+ font-size: 14px;
162
67
  font-style: normal;
163
- font-weight: 500;
164
- line-height: 16px; /* 133.333% */
68
+ font-weight: 400;
69
+ line-height: 20px; /* 142.857% */
165
70
  `);
166
- const Buttons = styled.div `
167
- display: flex;
168
- padding: 12px;
169
- justify-content: flex-end;
170
- align-items: center;
171
- gap: 8px;
172
- `;
@@ -1,6 +1,6 @@
1
1
  import { DecoratorNode, EditorConfig, LexicalNode, NodeKey, SerializedLexicalNode, Spread } from "lexical";
2
2
  import { ReactNode } from "react";
3
- export interface Answer {
3
+ export interface Solution {
4
4
  textType: "normal" | "code";
5
5
  value: string;
6
6
  destroyed?: boolean;
@@ -8,36 +8,37 @@ export interface Answer {
8
8
  export interface ProblemInputPayload {
9
9
  showCharacterCount: boolean;
10
10
  placeholder: string;
11
- answers: Answer[];
12
- response: string;
11
+ solutions: Solution[];
12
+ answer: string;
13
13
  key?: NodeKey;
14
14
  }
15
15
  export type SerializedProblemInputNode = Spread<ProblemInputPayload, SerializedLexicalNode>;
16
16
  /**
17
- * answersAnswer타입의 배열로서 정답을 담고 있습니다. (교사용)
18
- * response는 학생이 입력한 답을 담고 있습니다.(학생용)
17
+ * solutionsSolution타입의 배열로서 정답을 담고 있습니다. (교사용)
18
+ * answer는 학생이 입력한 답을 담고 있습니다.(학생용)
19
19
  */
20
20
  export declare class ProblemInputNode extends DecoratorNode<ReactNode> {
21
- __answers: Answer[];
21
+ __solutions: Solution[];
22
22
  __showCharacterCount: boolean;
23
23
  __placeholder: string;
24
- __response: string;
24
+ __answer: string;
25
+ isInline(): boolean;
25
26
  static getType(): string;
26
- getAnswers(): Answer[];
27
+ getSolutions(): Solution[];
27
28
  getShowCharacterCount(): boolean;
28
29
  getPlaceholder(): string;
29
- getResponse(): string;
30
- setAnswers(answers: Answer[]): void;
30
+ getAnswer(): string;
31
+ setSolutions(solutions: Solution[]): void;
31
32
  setShowCharacterCount(showCharacterCount: boolean): void;
32
33
  setPlaceholder(placeholder: string): void;
33
- setResponse(response: string): void;
34
+ setAnswer(answer: string): void;
34
35
  static clone(node: ProblemInputNode): ProblemInputNode;
35
- constructor(showCharacterCount: boolean, placeholder: string, answers: Answer[], response: string, key?: NodeKey);
36
+ constructor(showCharacterCount: boolean, placeholder: string, solutions: Solution[], answer: string, key?: NodeKey);
36
37
  createDOM(config: EditorConfig): HTMLElement;
37
38
  updateDOM(): boolean;
38
39
  static importJSON(serializedNode: SerializedProblemInputNode): ProblemInputNode;
39
40
  exportJSON(): SerializedProblemInputNode;
40
41
  decorate(): ReactNode;
41
42
  }
42
- export declare function $createProblemInputNode({ showCharacterCount, placeholder, answers, response, key, }: ProblemInputPayload): ProblemInputNode;
43
+ export declare function $createProblemInputNode({ showCharacterCount, placeholder, solutions, answer, key, }: ProblemInputPayload): ProblemInputNode;
43
44
  export declare function $isProblemInputNode(node: LexicalNode | null | undefined): node is ProblemInputNode;
@@ -3,15 +3,18 @@ import { $applyNodeReplacement, DecoratorNode, } from "lexical";
3
3
  import { addClassNamesToElement } from "@lexical/utils";
4
4
  import { InputComponent } from "./InputComponent";
5
5
  /**
6
- * answersAnswer타입의 배열로서 정답을 담고 있습니다. (교사용)
7
- * response는 학생이 입력한 답을 담고 있습니다.(학생용)
6
+ * solutionsSolution타입의 배열로서 정답을 담고 있습니다. (교사용)
7
+ * answer는 학생이 입력한 답을 담고 있습니다.(학생용)
8
8
  */
9
9
  export class ProblemInputNode extends DecoratorNode {
10
+ isInline() {
11
+ return false;
12
+ }
10
13
  static getType() {
11
14
  return "problem-input";
12
15
  }
13
- getAnswers() {
14
- return this.__answers;
16
+ getSolutions() {
17
+ return this.__solutions;
15
18
  }
16
19
  getShowCharacterCount() {
17
20
  return this.__showCharacterCount;
@@ -19,12 +22,12 @@ export class ProblemInputNode extends DecoratorNode {
19
22
  getPlaceholder() {
20
23
  return this.__placeholder;
21
24
  }
22
- getResponse() {
23
- return this.__response;
25
+ getAnswer() {
26
+ return this.__answer;
24
27
  }
25
- setAnswers(answers) {
28
+ setSolutions(solutions) {
26
29
  const self = this.getWritable();
27
- self.__answers = answers;
30
+ self.__solutions = solutions;
28
31
  }
29
32
  setShowCharacterCount(showCharacterCount) {
30
33
  const self = this.getWritable();
@@ -34,25 +37,19 @@ export class ProblemInputNode extends DecoratorNode {
34
37
  const self = this.getWritable();
35
38
  self.__placeholder = placeholder;
36
39
  }
37
- setResponse(response) {
40
+ setAnswer(answer) {
38
41
  const self = this.getWritable();
39
- self.__response = response;
42
+ self.__answer = answer;
40
43
  }
41
44
  static clone(node) {
42
- return $createProblemInputNode({
43
- showCharacterCount: node.__showCharacterCount,
44
- placeholder: node.__placeholder,
45
- answers: node.__answers,
46
- response: node.__response,
47
- key: node.__key,
48
- });
45
+ return new ProblemInputNode(node.__showCharacterCount, node.__placeholder, node.__solutions, node.__answer, node.__key);
49
46
  }
50
- constructor(showCharacterCount, placeholder, answers, response, key) {
47
+ constructor(showCharacterCount, placeholder, solutions, answer, key) {
51
48
  super(key);
52
- this.__answers = answers;
53
49
  this.__showCharacterCount = showCharacterCount;
54
50
  this.__placeholder = placeholder;
55
- this.__response = response;
51
+ this.__solutions = solutions;
52
+ this.__answer = answer;
56
53
  }
57
54
  createDOM(config) {
58
55
  // Define the DOM element here
@@ -66,10 +63,10 @@ export class ProblemInputNode extends DecoratorNode {
66
63
  static importJSON(serializedNode) {
67
64
  const node = $createProblemInputNode({
68
65
  key: serializedNode.key,
69
- answers: serializedNode.answers,
66
+ solutions: serializedNode.solutions,
70
67
  showCharacterCount: serializedNode.showCharacterCount,
71
68
  placeholder: serializedNode.placeholder,
72
- response: serializedNode.response,
69
+ answer: serializedNode.answer,
73
70
  });
74
71
  return node;
75
72
  }
@@ -79,19 +76,16 @@ export class ProblemInputNode extends DecoratorNode {
79
76
  type: "problem-input",
80
77
  showCharacterCount: this.__showCharacterCount,
81
78
  placeholder: this.__placeholder,
82
- answers: this.__answers,
83
- response: this.__response,
79
+ solutions: this.__solutions,
80
+ answer: this.__answer,
84
81
  };
85
82
  }
86
- // TODO: 이 노드의 selected가 제대로 동작하지 않습니다.
87
- // nodeKey를 전달하고 getNodeByKey로 노드를 찾는 것이 일반적이나
88
- // 현재 이 노드가 selected가 제대로 동작하지 않아서 노드를 직접 전달했습니다.
89
83
  decorate() {
90
- return _jsx(InputComponent, { node: this });
84
+ return (_jsx(InputComponent, { solutions: this.__solutions, showCharacterCount: this.__showCharacterCount, placeholder: this.__placeholder, answer: this.__answer, nodeKey: this.getKey() }));
91
85
  }
92
86
  }
93
- export function $createProblemInputNode({ showCharacterCount, placeholder, answers, response, key, }) {
94
- return $applyNodeReplacement(new ProblemInputNode(showCharacterCount, placeholder, answers, response, key));
87
+ export function $createProblemInputNode({ showCharacterCount, placeholder, solutions, answer, key, }) {
88
+ return $applyNodeReplacement(new ProblemInputNode(showCharacterCount, placeholder, solutions, answer, key));
95
89
  }
96
90
  export function $isProblemInputNode(node) {
97
91
  return node instanceof ProblemInputNode;
@@ -6,4 +6,4 @@ export interface FormAnswerProps {
6
6
  onDelete?: () => void;
7
7
  disabled?: boolean;
8
8
  }
9
- export declare function FormAnswer(props: FormAnswerProps): import("@emotion/react/jsx-runtime").JSX.Element;
9
+ export declare function FormSolution(props: FormAnswerProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -8,10 +8,10 @@ import Input from "../../../../../components/Input";
8
8
  import { AlertFillIcon, DeleteBinLineIcon, ErrorWarningFillIcon, } from "../../../../../icons";
9
9
  import SquareButton from "../../../../../components/SquareButton";
10
10
  import Tooltip from "../../../../../components/Tooltip";
11
- export function FormAnswer(props) {
11
+ export function FormSolution(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: field.value === "normal" ? "일반 텍스트" : "코드 텍스트", size: "xsmall", color: "textNeutral", closeOnItemClick: true, disabled: disabled, buttonCss: css `
14
+ const TextTypeDropdown = (_jsx(Controller, { name: `solutions.${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: field.value === "code" ? (_jsx(DropdownItem, { index: 0, label: "일반 텍스트", onClick: () => {
29
- field.onChange("normal");
30
- } })) : (_jsx(DropdownItem, { index: 0, label: "코드 텍스트", onClick: () => {
31
- field.onChange("code");
32
- } })) }))) }));
33
- return (_jsx(Controller, { name: `answers.${index}.value`, control: control, rules: {
28
+ } }, { children: _jsx(DropdownItem, { index: 0, label: value === "normal" ? "코드 텍스트" : "일반 텍스트", onClick: () => {
29
+ onChange(value === "normal" ? "code" : "normal");
30
+ } }) }))) }));
31
+ return (_jsx(Controller, { name: `solutions.${index}.value`, control: control, rules: {
34
32
  required: "정답을 입력해주세요.",
35
- }, render: ({ field: { onChange, value }, 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 `
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
  }
@@ -0,0 +1,10 @@
1
+ import { Solution } from "../ProblemInputNode";
2
+ import { NodeKey } from "lexical";
3
+ export interface SettingFormProps {
4
+ solutions: Solution[];
5
+ showCharacterCount: boolean;
6
+ placeholder: string;
7
+ nodeKey: NodeKey;
8
+ onClose: () => void;
9
+ }
10
+ export default function SettingForm(props: SettingFormProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1,149 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
+ /** @jsxImportSource @emotion/react */
3
+ import { css, useTheme } from "@emotion/react";
4
+ import styled from "@emotion/styled";
5
+ import shadows from "../../../../../foundation/shadows";
6
+ import { AddFillIcon, AlarmWarningFillIcon, InputMethodLineIcon, QuestionFillIcon, } from "../../../../../icons";
7
+ import { useFieldArray, useForm, } from "react-hook-form";
8
+ import { $isProblemInputNode, } from "../ProblemInputNode";
9
+ import { FormSolution } from "./FormSolution";
10
+ import Button from "../../../../../components/Button";
11
+ import Tooltip from "../../../../../components/Tooltip";
12
+ import { FormCharacterCount } from "./FormCharacterCount";
13
+ import { FormPlaceholder } from "./FormPlaceholder";
14
+ import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
15
+ import { $getNodeByKey } from "lexical";
16
+ import { useState } from "react";
17
+ export default function SettingForm(props) {
18
+ const { solutions, showCharacterCount, placeholder, nodeKey, onClose } = props;
19
+ const [editor] = useLexicalComposerContext();
20
+ //fixme: multiAnswerDisabled 삭제
21
+ const [multiAnswerDisabled, setMultiAnswerDisabled] = useState(showCharacterCount);
22
+ const { control, handleSubmit } = useForm({
23
+ defaultValues: {
24
+ solutions,
25
+ showCharacterCount,
26
+ placeholder,
27
+ },
28
+ });
29
+ const theme = useTheme();
30
+ const { fields, append, remove, update } = useFieldArray({
31
+ control,
32
+ name: "solutions",
33
+ keyName: "uid",
34
+ });
35
+ const onSettingSubmit = (data) => {
36
+ editor.update(() => {
37
+ const node = $getNodeByKey(nodeKey);
38
+ if (!$isProblemInputNode(node)) {
39
+ return;
40
+ }
41
+ node.setSolutions(data.solutions);
42
+ node.setShowCharacterCount(data.showCharacterCount);
43
+ node.setPlaceholder(data.placeholder);
44
+ });
45
+ onClose();
46
+ };
47
+ return (_jsxs(Form, Object.assign({ onSubmit: handleSubmit(onSettingSubmit) }, { children: [_jsxs(Title, { children: [_jsx(InputMethodLineIcon, { css: css `
48
+ width: 12px;
49
+ height: 12px;
50
+ ` }), "\uC8FC\uAD00\uC2DD \uC785\uB825 \uCE78"] }), _jsxs(Content, { children: [_jsxs(Left, { children: [_jsxs(FormArea, { children: [_jsx(Label, { children: "\uC815\uB2F5" }), fields
51
+ .map((field, index) => ({
52
+ field,
53
+ index,
54
+ }))
55
+ .filter(({ field }) => !field.destroyed)
56
+ .map(({ field, index }) => (_jsx(FormSolution, { index: index, control: control, disabled: index !== 0 && multiAnswerDisabled, onDelete: index !== 0
57
+ ? () => {
58
+ if (field.value) {
59
+ update(index, Object.assign(Object.assign({}, field), { destroyed: true }));
60
+ }
61
+ else {
62
+ remove(index);
63
+ }
64
+ }
65
+ : undefined }, field.uid)))] }), _jsx(Button, { color: "grey", size: "small", startIcon: _jsx(AddFillIcon, {}), label: "\uBCF5\uC218 \uC815\uB2F5 \uCD94\uAC00", disabled: multiAnswerDisabled, onClick: () => {
66
+ append({
67
+ textType: "normal",
68
+ value: "",
69
+ });
70
+ } }), _jsxs("div", Object.assign({ css: css `
71
+ display: flex;
72
+ gap: 4px;
73
+ ` }, { children: [_jsx(AlarmWarningFillIcon, { color: theme.color.foreground.neutralBaseDisabled, css: css `
74
+ width: 14px;
75
+ height: 14px;
76
+ ` }), _jsxs(Label, { children: ["\uB744\uC5B4\uC4F0\uAE30, \uC54C\uD30C\uBCB3\uC758 \uB300\uC18C\uBB38\uC790 \uAD6C\uBD84\uAE4C\uC9C0 \uC77C\uCE58\uD574\uC57C \uC815\uB2F5\uC73C\uB85C \uCC98\uB9AC\uB429\uB2C8\uB2E4.", _jsx("br", {}), "\uAC00\uB2A5\uD55C \uC815\uB2F5\uC744 \uBAA8\uB450 \uCD94\uAC00\uD574\uC57C \uC6D0\uD65C\uD558\uAC8C \uC790\uB3D9 \uCC44\uC810\uD560 \uC218 \uC788\uC5B4\uC694."] })] }))] }), _jsxs(Right, { children: [_jsxs(FormArea, { children: [_jsxs(Label, { children: ["\uC785\uB825 \uCE78", _jsx(Tooltip, Object.assign({ text: _jsxs("span", { children: ["\uC608\uB97C \uB4E4\uC5B4 \uC815\uB2F5\uC774 '\uAE00\uC790 \uC218'\uC774\uACE0", _jsx("br", {}), _jsx("b", { children: "\uAE00\uC790 \uC218\uB300\uB85C" }), " \uC635\uC158\uC744 \uC120\uD0DD\uD588\uB2E4\uBA74", _jsx("br", {}), "\uC785\uB825 \uCE78\uC774 '\u2610\u2610 \u2610' \uCC98\uB7FC \uD45C\uC2DC\uB429\uB2C8\uB2E4."] }), placement: "top" }, { children: _jsx(QuestionFillIcon, { css: css `
77
+ width: 12px;
78
+ height: 12px;
79
+ ` }) }))] }), _jsx(FormCharacterCount, { control: control, setMultiAnswerDisabled: setMultiAnswerDisabled })] }), _jsxs(FormArea, { children: [_jsxs(Label, { children: ["\uC790\uB9AC \uD45C\uC2DC\uC790", _jsx(Tooltip, Object.assign({ text: _jsx("span", { children: "\uC785\uB825 \uCE78\uC5D0 \uAE30\uBCF8\uC73C\uB85C \uB178\uCD9C\uB418\uB294 \uD14D\uC2A4\uD2B8\uC785\uB2C8\uB2E4." }), placement: "top" }, { children: _jsx(QuestionFillIcon, { css: css `
80
+ width: 12px;
81
+ height: 12px;
82
+ ` }) }))] }), _jsx(FormPlaceholder, { control: control })] })] })] }), _jsxs(Buttons, { children: [_jsx(Button, { color: "grey", size: "xsmall", label: "\uB2EB\uAE30", onClick: onClose }), _jsx(Button, { color: "primary", size: "xsmall", label: "\uC774\uB300\uB85C \uB123\uAE30", type: "submit" })] })] })));
83
+ }
84
+ const Form = styled.form(({ theme }) => css `
85
+ display: flex;
86
+ width: 620px;
87
+ flex-direction: column;
88
+ border-radius: 6px;
89
+ border: 1px solid ${theme.color.background.neutralAltActive};
90
+ background: ${theme.color.background.neutralBase};
91
+ box-shadow: ${shadows.shadow08};
92
+ `);
93
+ const Title = styled.div(({ theme }) => css `
94
+ display: flex;
95
+ padding: 8px 12px;
96
+ gap: 4px;
97
+ align-items: center;
98
+ color: ${theme.color.foreground.neutralBase};
99
+ /* Default/Label/12px-Md */
100
+ font-family: ${theme.fontFamily.ui};
101
+ font-size: 12px;
102
+ font-style: normal;
103
+ font-weight: 500;
104
+ line-height: 16px; /* 133.333% */
105
+ `);
106
+ const Content = styled.div(({ theme }) => css `
107
+ display: flex;
108
+ border-top: 1px solid ${theme.color.background.neutralAltActive};
109
+ border-bottom: 1px solid ${theme.color.background.neutralAltActive};
110
+ `);
111
+ const Left = styled.div `
112
+ display: flex;
113
+ flex-direction: column;
114
+ padding: 12px;
115
+ gap: 12px;
116
+ flex: 1;
117
+ `;
118
+ const FormArea = styled.div `
119
+ display: flex;
120
+ flex-direction: column;
121
+ gap: 8px;
122
+ `;
123
+ const Right = styled.div `
124
+ display: flex;
125
+ box-sizing: border-box;
126
+ width: 240px;
127
+ flex-direction: column;
128
+ padding: 12px;
129
+ gap: 12px;
130
+ `;
131
+ const Label = styled.div(({ theme }) => css `
132
+ display: flex;
133
+ gap: 4px;
134
+ align-items: center;
135
+ color: ${theme.color.foreground.neutralBaseDisabled};
136
+ /* Default/Label/12px-Md */
137
+ font-family: ${theme.fontFamily.ui};
138
+ font-size: 12px;
139
+ font-style: normal;
140
+ font-weight: 500;
141
+ line-height: 16px; /* 133.333% */
142
+ `);
143
+ const Buttons = styled.div `
144
+ display: flex;
145
+ padding: 12px;
146
+ justify-content: flex-end;
147
+ align-items: center;
148
+ gap: 8px;
149
+ `;
@@ -1,3 +1,4 @@
1
- export * from "./FormAnswer";
1
+ export * from "./FormSolution";
2
2
  export * from "./FormCharacterCount";
3
3
  export * from "./FormPlaceholder";
4
+ export { default } from "./SettingForm";
@@ -1,3 +1,4 @@
1
- export * from "./FormAnswer";
1
+ export * from "./FormSolution";
2
2
  export * from "./FormCharacterCount";
3
3
  export * from "./FormPlaceholder";
4
+ export { default } from "./SettingForm";
@@ -71,7 +71,7 @@ function getQuizContextOptions(editor, theme) {
71
71
  icon: _jsx(InputMethodLineIcon, { color: theme.color.foreground.primary }),
72
72
  keywords: ["short answer", "short answer input", "주관식", "주관식 입력"],
73
73
  onSelect: () => editor.dispatchCommand(INSERT_SHORT_ANSWER_COMMAND, {
74
- answers: [
74
+ solutions: [
75
75
  {
76
76
  textType: "normal",
77
77
  value: "",
@@ -79,7 +79,7 @@ function getQuizContextOptions(editor, theme) {
79
79
  ],
80
80
  showCharacterCount: false,
81
81
  placeholder: "",
82
- response: "",
82
+ answer: "",
83
83
  }),
84
84
  }),
85
85
  new ComponentPickerOption("객관식 입력 칸", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-monolith/cds",
3
- "version": "1.8.4",
3
+ "version": "1.8.6",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "sideEffects": false,