@team-monolith/cds 1.9.9 → 1.10.0

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 (40) hide show
  1. package/dist/icons/Custom.d.ts +8 -0
  2. package/dist/icons/Custom.js +11 -0
  3. package/dist/icons/custom/pdf-color.svg +12 -0
  4. package/dist/icons/custom/pdf.svg +3 -0
  5. package/dist/patterns/LexicalEditor/LexicalEditor.d.ts +0 -4
  6. package/dist/patterns/LexicalEditor/LexicalEditor.js +2 -5
  7. package/dist/patterns/LexicalEditor/Plugins.d.ts +0 -1
  8. package/dist/patterns/LexicalEditor/Plugins.js +3 -4
  9. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/InputComponent.js +9 -16
  10. package/dist/patterns/LexicalEditor/plugins/ComponentAdderPlugin/useContextMenuOptions.js +0 -15
  11. package/dist/patterns/LexicalEditor/plugins/ComponentPickerMenuPlugin/ComponentPickerMenuPlugin.js +1 -13
  12. package/dist/patterns/LexicalEditor/theme.d.ts +0 -1
  13. package/dist/patterns/LexicalEditor/theme.js +0 -7
  14. package/package.json +1 -1
  15. package/dist/patterns/LexicalEditor/LexicalCustomConfigContext.d.ts +0 -6
  16. package/dist/patterns/LexicalEditor/LexicalCustomConfigContext.js +0 -5
  17. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/ProblemSelectNode.d.ts +0 -45
  18. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/ProblemSelectNode.js +0 -74
  19. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectBox.d.ts +0 -11
  20. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectBox.js +0 -73
  21. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectComponent.d.ts +0 -9
  22. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectComponent.js +0 -90
  23. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/FormSelection.d.ts +0 -17
  24. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/FormSelection.js +0 -97
  25. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageDialog.d.ts +0 -10
  26. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageDialog.js +0 -106
  27. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageUploadedDialogBody.d.ts +0 -9
  28. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageUploadedDialogBody.js +0 -51
  29. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageUriDialogBody.d.ts +0 -9
  30. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageUriDialogBody.js +0 -20
  31. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/SettingForm.d.ts +0 -8
  32. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/SettingForm.js +0 -136
  33. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/index.d.ts +0 -1
  34. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/index.js +0 -1
  35. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/index.d.ts +0 -2
  36. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/index.js +0 -2
  37. package/dist/patterns/LexicalEditor/plugins/ActionsPlugin/index.d.ts +0 -9
  38. package/dist/patterns/LexicalEditor/plugins/ActionsPlugin/index.js +0 -24
  39. package/dist/patterns/LexicalEditor/plugins/ProblemSelectPlugin/index.d.ts +0 -5
  40. package/dist/patterns/LexicalEditor/plugins/ProblemSelectPlugin/index.js +0 -20
@@ -87,3 +87,11 @@ export declare const customQuizColorSvg: string;
87
87
  export declare const CustomQuizColorIcon: React.ForwardRefExoticComponent<{
88
88
  className?: string | undefined;
89
89
  } & React.RefAttributes<any>>;
90
+ export declare const customPdfColorSvg: string;
91
+ export declare const CustomPdfColorIcon: React.ForwardRefExoticComponent<{
92
+ className?: string | undefined;
93
+ } & React.RefAttributes<any>>;
94
+ export declare const customPdfSvg: string;
95
+ export declare const CustomPdfIcon: React.ForwardRefExoticComponent<{
96
+ className?: string | undefined;
97
+ } & React.RefAttributes<any>>;
@@ -91,3 +91,14 @@ export const CustomQuizColorIcon = forwardRef((props, ref) => {
91
91
  const uniqueId = useMemo(uid, []);
92
92
  return (_jsxs("svg", Object.assign({}, props, { ref: ref, width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, { children: [_jsxs("g", Object.assign({ clipPath: `url(#clip0_${uniqueId})` }, { children: [_jsx("path", { d: "M19.5238 19.81C19.5238 20.3913 19.2927 20.9478 18.8819 21.3584C18.4712 21.7691 17.9137 22.0002 17.3333 22.0002H4.19048C3.60913 22.0002 3.05258 21.7691 2.64186 21.3584C2.23115 20.9478 2 20.3903 2 19.81V6.09309C2 5.5118 2.23115 4.95531 2.64186 4.54463C3.05258 4.13396 3.61012 3.90283 4.19048 3.90283H17.3333C17.9147 3.90283 18.4712 4.13396 18.8819 4.54463C19.2927 4.95531 19.5238 5.51279 19.5238 6.09309V19.81C19.5238 20.3913 19.2927 20.9478 18.8819 21.3584C18.4712 21.7691 17.9137 22.0002 17.3333 22.0002", fill: "#FBEAF3" }), _jsx("path", { d: "M21.9999 17.9072C21.9999 18.4884 21.7687 19.0449 21.358 19.4556C20.9473 19.8663 20.3898 20.0974 19.8094 20.0974H6.66655C6.0852 20.0974 5.52865 19.8663 5.11794 19.4556C4.70723 19.0449 4.47607 18.4875 4.47607 17.9072V4.19026C4.47607 3.60897 4.70723 3.05247 5.11794 2.6418C5.52865 2.23113 6.08619 2 6.66655 2H19.8094C20.3908 2 20.9473 2.23113 21.358 2.6418C21.7687 3.05247 21.9999 3.60996 21.9999 4.19026V17.9072C21.9999 18.4884 21.7687 19.0449 21.358 19.4556C20.9473 19.8663 20.3898 20.0974 19.8094 20.0974", fill: "#F889AA" }), _jsx("path", { d: "M17.2836 14.917C18.4152 13.8846 19.0484 12.3944 19.0484 10.7363C19.0484 7.62109 16.8132 5.09766 13.2381 5.09766C9.66292 5.09766 7.42773 7.62274 7.42773 10.7363C7.42773 13.8499 9.66292 16.375 13.2381 16.375C14.044 16.375 14.7805 16.246 15.4394 16.0113L16.0651 16.9064C16.118 16.9833 16.2147 17.0172 16.304 16.9916L18.0341 16.494C18.1011 16.4742 18.1556 16.4237 18.1796 16.3568C18.2028 16.2907 18.1928 16.2171 18.1523 16.1584L17.2836 14.917ZM13.2381 13.6656C11.3815 13.6656 10.2192 12.3539 10.2192 10.7363C10.2192 9.11878 11.3798 7.80706 13.2381 7.80706C15.0963 7.80706 16.2569 9.11878 16.2569 10.7363C16.2569 11.4331 16.0403 12.0728 15.6468 12.5762L14.8864 11.4885C14.8326 11.4124 14.7367 11.3777 14.6475 11.4033L12.9165 11.9009C12.8496 11.9208 12.795 11.9712 12.771 12.0381C12.7479 12.1042 12.7578 12.1778 12.7983 12.2365L13.7696 13.6251C13.6001 13.6499 13.4241 13.6656 13.2381 13.6656Z", fill: "#FBEAF3" })] })), _jsx("defs", { children: _jsx("clipPath", Object.assign({ id: `clip0_${uniqueId}` }, { children: _jsx("rect", { width: "20", height: "20", fill: "white", transform: "translate(2 2)" }) })) })] })));
93
93
  });
94
+ import customPdfColorSvgImport from "./custom/pdf-color.svg";
95
+ export const customPdfColorSvg = customPdfColorSvgImport;
96
+ export const CustomPdfColorIcon = forwardRef((props, ref) => {
97
+ const uniqueId = useMemo(uid, []);
98
+ return (_jsxs("svg", Object.assign({}, props, { ref: ref, width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, { children: [_jsxs("g", Object.assign({ clipPath: `url(#clip0_${uniqueId})` }, { children: [_jsx("path", { d: "M21 6.5V20.8C21 21.3839 20.7626 21.9428 20.3407 22.3553C19.9188 22.7678 19.3461 23 18.75 23H5.25C4.65285 23 4.08118 22.7678 3.65931 22.3553C3.23743 21.9428 3 21.3829 3 20.8V3.2C3 2.61612 3.23743 2.05716 3.65931 1.64466C4.08118 1.23216 4.65285 1 5.25 1H15.375L21 6.5Z", fill: "#FF5850" }), _jsx("path", { d: "M16.5 6.5H21L15.375 1V5.4C15.375 5.69194 15.4932 5.97192 15.7041 6.17817C15.9151 6.38442 16.2014 6.5 16.5 6.5Z", fill: "#F1E0E0" }), _jsx("path", { d: "M12.7437 6.80746H10.6651C10.5459 6.80746 10.4507 6.90052 10.4481 7.01705C10.4089 8.90249 9.84591 11.0932 8.91557 13.1195C7.98522 15.1502 6.7418 16.8982 5.43701 17.9757C5.35073 18.047 5.3365 18.1723 5.40321 18.2618L6.63863 19.9133C6.70711 20.0046 6.83608 20.0273 6.93303 19.9646C10.4934 17.6731 14.4149 16.1077 18.2217 16.5695C18.332 16.5825 18.4352 16.5138 18.4609 16.4086L18.9439 14.4066C18.9697 14.3005 18.9083 14.1944 18.8043 14.1579C15.6165 13.0343 13.0719 9.94435 12.9598 7.00923C12.9554 6.89617 12.8584 6.80833 12.7437 6.80833V6.80746ZM11.1427 15.0989C10.9586 15.165 10.7869 14.9788 10.8732 14.8067C10.9871 14.5805 11.0965 14.3527 11.2023 14.1222C11.478 13.5195 11.728 12.8986 11.9476 12.269C12.0046 12.1055 12.2269 12.075 12.3292 12.2168C12.7926 12.8577 13.3209 13.4526 13.9053 13.9909C14.0334 14.1083 13.9729 14.317 13.8012 14.3518C12.8984 14.5336 12.0108 14.7884 11.1427 15.0989Z", fill: "#F1E0E0" })] })), _jsx("defs", { children: _jsx("clipPath", Object.assign({ id: `clip0_${uniqueId}` }, { children: _jsx("rect", { width: "18", height: "22", fill: "white", transform: "translate(3 1)" }) })) })] })));
99
+ });
100
+ import customPdfSvgImport from "./custom/pdf.svg";
101
+ export const customPdfSvg = customPdfSvgImport;
102
+ export const CustomPdfIcon = forwardRef((props, ref) => {
103
+ return (_jsx("svg", Object.assign({}, props, { ref: ref, width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, { children: _jsx("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M21 20.8V6.5L15.375 1H5.25C4.65285 1 4.08118 1.23216 3.65931 1.64466C3.23743 2.05716 3 2.61612 3 3.2V20.8C3 21.3829 3.23743 21.9428 3.65931 22.3553C4.08118 22.7678 4.65285 23 5.25 23H18.75C19.3461 23 19.9188 22.7678 20.3407 22.3553C20.7626 21.9428 21 21.3839 21 20.8ZM10.6651 6.80746H12.7437V6.80832C12.8585 6.80832 12.9554 6.89616 12.9599 7.00922C13.0719 9.94434 15.6166 13.0343 18.8043 14.1579C18.9084 14.1944 18.9698 14.3005 18.944 14.4066L18.461 16.4086C18.4352 16.5138 18.332 16.5825 18.2217 16.5695C14.415 16.1077 10.4935 17.6731 6.93308 19.9646C6.83613 20.0272 6.70717 20.0046 6.63868 19.9133L5.40326 18.2618C5.33655 18.1723 5.35078 18.047 5.43706 17.9757C6.74186 16.8982 7.98528 15.1502 8.91562 13.1195C9.84597 11.0932 10.409 8.90248 10.4481 7.01704C10.4508 6.90051 10.546 6.80746 10.6651 6.80746ZM10.8733 14.8066C10.787 14.9788 10.9586 15.1649 11.1428 15.0989C12.0108 14.7884 12.8985 14.5336 13.8013 14.3518C13.9729 14.317 14.0334 14.1083 13.9053 13.9909C13.321 13.4526 12.7927 12.8577 12.3293 12.2168C12.227 12.075 12.0046 12.1055 11.9477 12.269C11.728 12.8986 11.4781 13.5195 11.2024 14.1222C11.0965 14.3527 10.9871 14.5805 10.8733 14.8066Z", fill: "#363636" }) })));
104
+ });
@@ -0,0 +1,12 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g clip-path="url(#clip0_881_50)">
3
+ <path d="M21 6.5V20.8C21 21.3839 20.7626 21.9428 20.3407 22.3553C19.9188 22.7678 19.3461 23 18.75 23H5.25C4.65285 23 4.08118 22.7678 3.65931 22.3553C3.23743 21.9428 3 21.3829 3 20.8V3.2C3 2.61612 3.23743 2.05716 3.65931 1.64466C4.08118 1.23216 4.65285 1 5.25 1H15.375L21 6.5Z" fill="#FF5850" style="fill:#FF5850;fill:color(display-p3 1.0000 0.3449 0.3125);fill-opacity:1;"/>
4
+ <path d="M16.5 6.5H21L15.375 1V5.4C15.375 5.69194 15.4932 5.97192 15.7041 6.17817C15.9151 6.38442 16.2014 6.5 16.5 6.5Z" fill="#F1E0E0" style="fill:#F1E0E0;fill:color(display-p3 0.9451 0.8784 0.8784);fill-opacity:1;"/>
5
+ <path d="M12.7437 6.80746H10.6651C10.5459 6.80746 10.4507 6.90052 10.4481 7.01705C10.4089 8.90249 9.84591 11.0932 8.91557 13.1195C7.98522 15.1502 6.7418 16.8982 5.43701 17.9757C5.35073 18.047 5.3365 18.1723 5.40321 18.2618L6.63863 19.9133C6.70711 20.0046 6.83608 20.0273 6.93303 19.9646C10.4934 17.6731 14.4149 16.1077 18.2217 16.5695C18.332 16.5825 18.4352 16.5138 18.4609 16.4086L18.9439 14.4066C18.9697 14.3005 18.9083 14.1944 18.8043 14.1579C15.6165 13.0343 13.0719 9.94435 12.9598 7.00923C12.9554 6.89617 12.8584 6.80833 12.7437 6.80833V6.80746ZM11.1427 15.0989C10.9586 15.165 10.7869 14.9788 10.8732 14.8067C10.9871 14.5805 11.0965 14.3527 11.2023 14.1222C11.478 13.5195 11.728 12.8986 11.9476 12.269C12.0046 12.1055 12.2269 12.075 12.3292 12.2168C12.7926 12.8577 13.3209 13.4526 13.9053 13.9909C14.0334 14.1083 13.9729 14.317 13.8012 14.3518C12.8984 14.5336 12.0108 14.7884 11.1427 15.0989Z" fill="#F1E0E0" style="fill:#F1E0E0;fill:color(display-p3 0.9451 0.8784 0.8784);fill-opacity:1;"/>
6
+ </g>
7
+ <defs>
8
+ <clipPath id="clip0_881_50">
9
+ <rect width="18" height="22" fill="white" style="fill:white;fill-opacity:1;" transform="translate(3 1)"/>
10
+ </clipPath>
11
+ </defs>
12
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M21 20.8V6.5L15.375 1H5.25C4.65285 1 4.08118 1.23216 3.65931 1.64466C3.23743 2.05716 3 2.61612 3 3.2V20.8C3 21.3829 3.23743 21.9428 3.65931 22.3553C4.08118 22.7678 4.65285 23 5.25 23H18.75C19.3461 23 19.9188 22.7678 20.3407 22.3553C20.7626 21.9428 21 21.3839 21 20.8ZM10.6651 6.80746H12.7437V6.80832C12.8585 6.80832 12.9554 6.89616 12.9599 7.00922C13.0719 9.94434 15.6166 13.0343 18.8043 14.1579C18.9084 14.1944 18.9698 14.3005 18.944 14.4066L18.461 16.4086C18.4352 16.5138 18.332 16.5825 18.2217 16.5695C14.415 16.1077 10.4935 17.6731 6.93308 19.9646C6.83613 20.0272 6.70717 20.0046 6.63868 19.9133L5.40326 18.2618C5.33655 18.1723 5.35078 18.047 5.43706 17.9757C6.74186 16.8982 7.98528 15.1502 8.91562 13.1195C9.84597 11.0932 10.409 8.90248 10.4481 7.01704C10.4508 6.90051 10.546 6.80746 10.6651 6.80746ZM10.8733 14.8066C10.787 14.9788 10.9586 15.1649 11.1428 15.0989C12.0108 14.7884 12.8985 14.5336 13.8013 14.3518C13.9729 14.317 14.0334 14.1083 13.9053 13.9909C13.321 13.4526 12.7927 12.8577 12.3293 12.2168C12.227 12.075 12.0046 12.1055 11.9477 12.269C11.728 12.8986 11.4781 13.5195 11.2024 14.1222C11.0965 14.3527 10.9871 14.5805 10.8733 14.8066Z" fill="#363636" style="fill:#363636;fill:color(display-p3 0.2118 0.2118 0.2118);fill-opacity:1;"/>
3
+ </svg>
@@ -2,16 +2,12 @@
2
2
  import { SerializedEditorState, SerializedLexicalNode } from "lexical";
3
3
  export interface LexicalEditorProps {
4
4
  className?: string;
5
- contentEditableClassName?: string;
6
5
  value?: any;
7
6
  onChange?: (blocks: SerializedEditorState<SerializedLexicalNode>) => void;
8
7
  /** editable. 수정 모드 / 읽기 모드 여부
9
8
  * initialConfig에 전달되므로 마운트 된 이후 수정해도 반영되지 않음
10
9
  */
11
10
  editable?: boolean;
12
- /** freeze. 문제 블록을 수정하지 못하도록 함
13
- */
14
- freezeProblemNode?: boolean;
15
11
  /** 외부에서 플러그인을 주입하는 경우 활용함 */
16
12
  children?: JSX.Element | string | (JSX.Element | string)[];
17
13
  }
@@ -11,8 +11,6 @@ import { getTheme } from "./theme";
11
11
  import { useTheme } from "@emotion/react";
12
12
  import Plugins from "./Plugins";
13
13
  import { ColoredQuoteNode, ProblemInputNode } from "./nodes";
14
- import { LexicalCustomConfigContext } from "./LexicalCustomConfigContext";
15
- import { ProblemSelectNode } from "./nodes/ProblemSelectNode";
16
14
  function validateValue(value) {
17
15
  var _a, _b;
18
16
  if (value && typeof value !== "object") {
@@ -30,14 +28,13 @@ function validateValue(value) {
30
28
  return true;
31
29
  }
32
30
  export function LexicalEditor(props) {
33
- const { className, contentEditableClassName, value, onChange, editable = true, freezeProblemNode, children, } = props;
31
+ const { className, value, onChange, editable = true, children } = props;
34
32
  const theme = useTheme();
35
33
  const initialConfig = {
36
34
  namespace: "CodleLexicalEditor",
37
35
  onError: (error) => console.error(error),
38
36
  nodes: [
39
37
  ProblemInputNode,
40
- ProblemSelectNode,
41
38
  HeadingNode,
42
39
  ListNode,
43
40
  ListItemNode,
@@ -63,5 +60,5 @@ export function LexicalEditor(props) {
63
60
  editorState: validateValue(value) ? JSON.stringify(value) : undefined,
64
61
  editable: editable,
65
62
  };
66
- return (_jsx(LexicalCustomConfigContext.Provider, Object.assign({ value: { freezeProblemNode: freezeProblemNode !== null && freezeProblemNode !== void 0 ? freezeProblemNode : false } }, { children: _jsxs(LexicalComposer, Object.assign({ initialConfig: initialConfig }, { children: [_jsx(Plugins, { className: className, contentEditableClassName: contentEditableClassName, onChange: onChange }), _jsx(_Fragment, { children: children })] })) })));
63
+ return (_jsxs(LexicalComposer, Object.assign({ initialConfig: initialConfig }, { children: [_jsx(Plugins, { className: className, onChange: onChange }), _jsx(_Fragment, { children: children })] })));
67
64
  }
@@ -6,7 +6,6 @@ import { ReactElement } from "react";
6
6
  import { SerializedEditorState, SerializedLexicalNode } from "lexical";
7
7
  export interface PluginsProps {
8
8
  className?: string;
9
- contentEditableClassName?: string;
10
9
  onChange?: (blocks: SerializedEditorState<SerializedLexicalNode>) => void;
11
10
  }
12
11
  export default function Plugins(props: PluginsProps): ReactElement;
@@ -28,9 +28,8 @@ import useLexicalEditable from "@lexical/react/useLexicalEditable";
28
28
  import ListMaxIndentLevelPlugin from "./plugins/ListMaxIndentLevelPlugin";
29
29
  import styled from "@emotion/styled";
30
30
  import ProblemInputPlugin from "./plugins/ProblemInputPlugin";
31
- import ProblemSelectPlugin from "./plugins/ProblemSelectPlugin";
32
31
  export default function Plugins(props) {
33
- const { className, contentEditableClassName, onChange } = props;
32
+ const { className, onChange } = props;
34
33
  const isEditable = useLexicalEditable();
35
34
  const [floatingAnchorElem, setFloatingAnchorElem] = useState(null);
36
35
  const [isLinkEditMode, setIsLinkEditMode] = useState(false);
@@ -39,11 +38,11 @@ export default function Plugins(props) {
39
38
  setFloatingAnchorElem(_floatingAnchorElem);
40
39
  }
41
40
  };
42
- return (_jsxs(_Fragment, { children: [_jsx(RichTextPlugin, { contentEditable: _jsx(ScrollArea, Object.assign({ className: className }, { children: _jsx(FloatingAnchor, Object.assign({ ref: onRef }, { children: _jsx(StyledContentEditable, { className: contentEditableClassName, isEditable: isEditable }) })) })), placeholder: null, ErrorBoundary: LexicalErrorBoundary }), _jsx(OnChangePlugin, { onChange: (editorState) => {
41
+ return (_jsxs(_Fragment, { children: [_jsx(RichTextPlugin, { contentEditable: _jsx(ScrollArea, Object.assign({ className: className }, { children: _jsx(FloatingAnchor, Object.assign({ ref: onRef }, { children: _jsx(StyledContentEditable, { isEditable: isEditable }) })) })), placeholder: null, ErrorBoundary: LexicalErrorBoundary }), _jsx(OnChangePlugin, { onChange: (editorState) => {
43
42
  onChange === null || onChange === void 0 ? void 0 : onChange(editorState.toJSON());
44
43
  },
45
44
  // ignore 하지 않으면 Form에서 수정하지 않았는데 Dirty로 처리됨.
46
- ignoreSelectionChange: true }), _jsx(AutoFocusPlugin, {}), isEditable && (_jsxs(_Fragment, { children: [_jsx(TabIndentationPlugin, {}), _jsx(ComponentPickerMenuPlugin, {}), _jsx(MarkdownShortcutPlugin, { transformers: CODLE_TRANSFORMERS }), _jsx(HistoryPlugin, {})] })), floatingAnchorElem && isEditable && (_jsxs(_Fragment, { children: [_jsx(ComponentAdderPlugin, { anchorElem: floatingAnchorElem }), _jsx(FloatingTextFormatToolbarPlugin, { anchorElem: floatingAnchorElem }), _jsx(FloatingLinkEditorPlugin, { anchorElem: floatingAnchorElem, isLinkEditMode: isLinkEditMode, setIsLinkEditMode: setIsLinkEditMode })] })), !isEditable && _jsx(LexicalClickableLinkPlugin, {}), _jsx(ListPlugin, {}), _jsx(HorizontalRulePlugin, {}), _jsx(ImagesPlugin, {}), _jsx(TablePlugin, {}), _jsx(LinkPlugin, {}), _jsx(ListMaxIndentLevelPlugin, { maxDepth: 5 }), _jsx(ProblemInputPlugin, {}), _jsx(ProblemSelectPlugin, {})] }));
45
+ ignoreSelectionChange: true }), _jsx(AutoFocusPlugin, {}), isEditable && (_jsxs(_Fragment, { children: [_jsx(TabIndentationPlugin, {}), _jsx(ComponentPickerMenuPlugin, {}), _jsx(MarkdownShortcutPlugin, { transformers: CODLE_TRANSFORMERS }), _jsx(HistoryPlugin, {})] })), floatingAnchorElem && isEditable && (_jsxs(_Fragment, { children: [_jsx(ComponentAdderPlugin, { anchorElem: floatingAnchorElem }), _jsx(FloatingTextFormatToolbarPlugin, { anchorElem: floatingAnchorElem }), _jsx(FloatingLinkEditorPlugin, { anchorElem: floatingAnchorElem, isLinkEditMode: isLinkEditMode, setIsLinkEditMode: setIsLinkEditMode })] })), !isEditable && _jsx(LexicalClickableLinkPlugin, {}), _jsx(ListPlugin, {}), _jsx(HorizontalRulePlugin, {}), _jsx(ImagesPlugin, {}), _jsx(TablePlugin, {}), _jsx(LinkPlugin, {}), _jsx(ListMaxIndentLevelPlugin, { maxDepth: 5 }), _jsx(ProblemInputPlugin, {})] }));
47
46
  }
48
47
  const ScrollArea = styled.div `
49
48
  min-height: 150px;
@@ -12,7 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/react/jsx-runtime";
13
13
  /** @jsxImportSource @emotion/react */
14
14
  import { css } from "@emotion/react";
15
- import { useContext, useState } from "react";
15
+ import { useState } from "react";
16
16
  import Input from "../../../../components/Input";
17
17
  import SquareButton from "../../../../components/SquareButton";
18
18
  import { Settings3FillIcon } from "../../../../icons";
@@ -22,7 +22,6 @@ import useLexicalEditable from "@lexical/react/useLexicalEditable";
22
22
  import { $isProblemInputNode } from "./ProblemInputNode";
23
23
  import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
24
24
  import { $getNodeByKey } from "lexical";
25
- import { LexicalCustomConfigContext } from "../../LexicalCustomConfigContext";
26
25
  export function InputComponent(props) {
27
26
  const { answer } = props, settingFormProps = __rest(props, ["answer"]);
28
27
  const { placeholder, nodeKey } = settingFormProps;
@@ -30,29 +29,23 @@ export function InputComponent(props) {
30
29
  const [settingOpen, setSettingOpen] = useState(false);
31
30
  const isEditable = useLexicalEditable();
32
31
  const [answerInput, setAnswerInput] = useState(answer);
33
- const lexicalCustomConfig = useContext(LexicalCustomConfigContext);
34
32
  // 학생 view
35
33
  // TODO: "글자 수대로" 옵션시에 글자 수대로 입력칸을 표시해야 합니다.
36
34
  if (!isEditable) {
37
- if (lexicalCustomConfig.freezeProblemNode) {
38
- return (_jsx(Input, { size: "small", placeholder: placeholder || "여기에 입력하세요.", value: answerInput, color: "default", fullWidth: true, inputProps: { readOnly: true } }));
39
- }
40
- else {
41
- return (_jsx(Input, { size: "small", placeholder: placeholder || "여기에 입력하세요.", value: answerInput, onChange: (e) => {
42
- // SoT를 EditorState로 설정하는 경우 한글 입력시 문제가 생김.
43
- // ex) "나비" 입력시 -> "ㄴ나납ㅂ비"
44
- // SoT를 내부 State로 관리하고 EditorState를 따로 설정.
45
- // 문제를 더 파악하고 추후 개선 필요.
46
- setAnswerInput(e.target.value);
35
+ return (_jsx(Input, { size: "small", placeholder: placeholder || "여기에 입력하세요.", value: answerInput, onChange: (e) => setAnswerInput(e.target.value),
36
+ // 한글 입력시에 onChange마다 update가 일어나는 것을 방지하기 위해 입력 완료후 onBlur시에 update하는 전략을 사용합니다.
37
+ // 이를 위해 answerInput을 state로 관리합니다.
38
+ inputProps: {
39
+ onBlur: (_e) => {
47
40
  editor.update(() => {
48
41
  const node = $getNodeByKey(nodeKey);
49
42
  if (!$isProblemInputNode(node)) {
50
43
  return;
51
44
  }
52
- node.setAnswer(e.target.value);
45
+ node.setAnswer(answerInput);
53
46
  });
54
- }, color: "default", fullWidth: true }));
55
- }
47
+ },
48
+ }, color: "default", fullWidth: true }));
56
49
  }
57
50
  // 교사 edit view
58
51
  return (_jsxs(_Fragment, { children: [_jsxs("div", Object.assign({ css: css `
@@ -14,7 +14,6 @@ import { $isColoredQuoteNode, } from "../../nodes/ColoredQuoteNode";
14
14
  import { useTheme } from "@emotion/react";
15
15
  import { css } from "@emotion/css";
16
16
  import { $isProblemInputNode } from "../../nodes";
17
- import { $isProblemSelectNode, } from "../../nodes/ProblemSelectNode";
18
17
  function getParagraphContextMenuOptions(editor, node, setOpen) {
19
18
  return [
20
19
  new ComponentPickerOption("본문", {
@@ -186,17 +185,6 @@ function getProblemInputContextMenuOptions(node) {
186
185
  }),
187
186
  ];
188
187
  }
189
- function getProblemSelectContextMenuOptions(node) {
190
- return [
191
- new ComponentPickerOption("블록 삭제", {
192
- icon: _jsx(CloseFillIcon, {}),
193
- keywords: [],
194
- onSelect: () => {
195
- node.remove();
196
- },
197
- }),
198
- ];
199
- }
200
188
  function getColoredQuoteContextMenuOptions(editor, theme, node) {
201
189
  return [
202
190
  new ComponentPickerOption("회색", {
@@ -276,9 +264,6 @@ export function useContextMenuOptions() {
276
264
  if ($isProblemInputNode(node)) {
277
265
  return getProblemInputContextMenuOptions(node);
278
266
  }
279
- else if ($isProblemSelectNode(node)) {
280
- return getProblemSelectContextMenuOptions(node);
281
- }
282
267
  else if (node instanceof ParagraphNode) {
283
268
  return getParagraphContextMenuOptions(editor, node, setImageOpen);
284
269
  }
@@ -25,7 +25,6 @@ import { TextIcon, H1Icon, H2Icon, H3Icon, ListUnorderedIcon, ListOrderedIcon, D
25
25
  import { ZINDEX } from "../../../../utils/zIndex";
26
26
  import { css, useTheme } from "@emotion/react";
27
27
  import { INSERT_PROBLEM_INPUT_COMMAND } from "../ProblemInputPlugin";
28
- import { INSERT_PROBLEM_SELECT_COMMAND } from "../ProblemSelectPlugin";
29
28
  // import useModal from "../../hooks/useModal";
30
29
  // import catTypingGif from "../../images/cat-typing.gif";
31
30
  // import { INSERT_IMAGE_COMMAND, InsertImageDialog } from "../ImagesPlugin";
@@ -87,18 +86,7 @@ function getQuizContextOptions(editor, theme) {
87
86
  icon: _jsx(ListRadioIcon, { color: theme.color.foreground.primary }),
88
87
  keywords: ["problem select", "객관식 입력"],
89
88
  onSelect: () => {
90
- editor.dispatchCommand(INSERT_PROBLEM_SELECT_COMMAND, {
91
- selections: [
92
- {
93
- isAnswer: false,
94
- show: {
95
- text: "",
96
- },
97
- value: "1",
98
- },
99
- ],
100
- selected: [],
101
- });
89
+ // TODO: 객관식 입력 칸 추가
102
90
  },
103
91
  }),
104
92
  new ComponentDrawerOption("메뉴구분선", (_jsx("div", { css: css `
@@ -29,5 +29,4 @@ export declare function getTheme(theme: Theme): {
29
29
  strikethrough: string;
30
30
  };
31
31
  problemInput: string;
32
- problemSelect: string;
33
32
  };
@@ -252,13 +252,6 @@ export function getTheme(theme) {
252
252
  flex: 1;
253
253
  gap: 4px;
254
254
  margin-bottom: 8px;
255
- `,
256
- problemSelect: css `
257
- display: flex;
258
- flex-direction: column;
259
- flex: 1;
260
- gap: 4px;
261
- margin-bottom: 8px;
262
255
  `,
263
256
  };
264
257
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-monolith/cds",
3
- "version": "1.9.9",
3
+ "version": "1.10.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "sideEffects": false,
@@ -1,6 +0,0 @@
1
- /// <reference types="react" />
2
- export type LexicalCustomConfig = {
3
- freezeProblemNode: boolean;
4
- };
5
- declare const LexicalCustomConfigContext: import("react").Context<LexicalCustomConfig>;
6
- export { LexicalCustomConfigContext };
@@ -1,5 +0,0 @@
1
- import { createContext } from "react";
2
- const LexicalCustomConfigContext = createContext({
3
- freezeProblemNode: false,
4
- });
5
- export { LexicalCustomConfigContext };
@@ -1,45 +0,0 @@
1
- import { DecoratorNode, EditorConfig, LexicalNode, NodeKey, SerializedLexicalNode, Spread } from "lexical";
2
- import { ReactNode } from "react";
3
- export interface ImageProps {
4
- src: string;
5
- altText: string;
6
- }
7
- export interface Selection {
8
- isAnswer: boolean;
9
- show: {
10
- image?: ImageProps;
11
- text: string;
12
- };
13
- value: string;
14
- }
15
- export interface ProblemSelectPayload {
16
- selections: Selection[];
17
- selected: string[];
18
- hasMultipleAnswers?: boolean;
19
- key?: NodeKey;
20
- }
21
- export type SerializedProblemSelectNode = Spread<ProblemSelectPayload, SerializedLexicalNode>;
22
- /**
23
- * selections는 Selection타입의 배열로서 객관식 정보를 담고 있습니다. (교사용)
24
- * selected는 학생이 선택한 답의 value를 담고 있습니다.(학생용)
25
- */
26
- export declare class ProblemSelectNode extends DecoratorNode<ReactNode> {
27
- __selections: Selection[];
28
- __selected: string[];
29
- __hasMultipleAnswers: boolean | undefined;
30
- isInline(): boolean;
31
- static getType(): string;
32
- getSelections(): Selection[];
33
- getSelected(): string[];
34
- setSolutions(selections: Selection[]): void;
35
- setSelected(selected: string[]): void;
36
- static clone(node: ProblemSelectNode): ProblemSelectNode;
37
- constructor(selections: Selection[], selected: string[], hasMultipleAnswers?: boolean, key?: NodeKey);
38
- createDOM(config: EditorConfig): HTMLElement;
39
- updateDOM(): boolean;
40
- static importJSON(serializedNode: SerializedProblemSelectNode): ProblemSelectNode;
41
- exportJSON(): SerializedProblemSelectNode;
42
- decorate(): ReactNode;
43
- }
44
- export declare function $createProblemSelectNode({ selections, selected, hasMultipleAnswers, key, }: ProblemSelectPayload): ProblemSelectNode;
45
- export declare function $isProblemSelectNode(node: LexicalNode | null | undefined): node is ProblemSelectNode;
@@ -1,74 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { $applyNodeReplacement, DecoratorNode, } from "lexical";
3
- import { addClassNamesToElement } from "@lexical/utils";
4
- import { SelectComponent } from "./SelectComponent";
5
- /**
6
- * selections는 Selection타입의 배열로서 객관식 정보를 담고 있습니다. (교사용)
7
- * selected는 학생이 선택한 답의 value를 담고 있습니다.(학생용)
8
- */
9
- export class ProblemSelectNode extends DecoratorNode {
10
- isInline() {
11
- return false;
12
- }
13
- static getType() {
14
- return "problem-select";
15
- }
16
- getSelections() {
17
- return this.__selections;
18
- }
19
- getSelected() {
20
- return this.__selected;
21
- }
22
- setSolutions(selections) {
23
- const self = this.getWritable();
24
- self.__selections = selections;
25
- }
26
- setSelected(selected) {
27
- const self = this.getWritable();
28
- self.__selected = selected;
29
- }
30
- static clone(node) {
31
- return new ProblemSelectNode(node.__selections, node.__selected, node.__hasMultipleAnswers, node.__key);
32
- }
33
- constructor(selections, selected, hasMultipleAnswers, key) {
34
- super(key);
35
- this.__selections = selections;
36
- this.__selected = selected;
37
- this.__hasMultipleAnswers = hasMultipleAnswers;
38
- }
39
- createDOM(config) {
40
- // Define the DOM element here
41
- const root = document.createElement("div");
42
- addClassNamesToElement(root, config.theme.problemSelect);
43
- return root;
44
- }
45
- updateDOM() {
46
- return false;
47
- }
48
- static importJSON(serializedNode) {
49
- const node = $createProblemSelectNode({
50
- key: serializedNode.key,
51
- selections: serializedNode.selections,
52
- selected: serializedNode.selected,
53
- hasMultipleAnswers: serializedNode.hasMultipleAnswers,
54
- });
55
- return node;
56
- }
57
- exportJSON() {
58
- return {
59
- version: 1,
60
- type: "problem-select",
61
- selections: this.__selections,
62
- selected: this.__selected,
63
- };
64
- }
65
- decorate() {
66
- return (_jsx(SelectComponent, { selections: this.__selections, selected: this.__selected, hasMultipleAnswers: this.__hasMultipleAnswers, nodeKey: this.getKey() }));
67
- }
68
- }
69
- export function $createProblemSelectNode({ selections, selected, hasMultipleAnswers, key, }) {
70
- return $applyNodeReplacement(new ProblemSelectNode(selections, selected, hasMultipleAnswers, key));
71
- }
72
- export function $isProblemSelectNode(node) {
73
- return node instanceof ProblemSelectNode;
74
- }
@@ -1,11 +0,0 @@
1
- import { ImageProps } from "./ProblemSelectNode";
2
- export interface SelectBoxProps {
3
- index: number;
4
- isSelected?: boolean;
5
- isAnswer?: boolean;
6
- image?: ImageProps;
7
- text: string;
8
- onClick?: () => void;
9
- fullWidth?: boolean;
10
- }
11
- export default function SelectBox(props: SelectBoxProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,73 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
- /** @jsxImportSource @emotion/react */
3
- import styled from "@emotion/styled";
4
- import { css, useTheme } from "@emotion/react";
5
- import { CheckFillIcon, CheckboxCircleFillIcon } from "../../../../icons";
6
- export default function SelectBox(props) {
7
- const { index, isSelected, isAnswer, image, text, onClick, fullWidth } = props;
8
- const theme = useTheme();
9
- return (_jsxs(Container, Object.assign({ isSelected: isSelected, fullWidth: fullWidth, onClick: onClick }, { children: [_jsx(Index, Object.assign({ isSelected: isSelected }, { children: isSelected ? (_jsx(CheckFillIcon, { css: css `
10
- width: 12px;
11
- height: 12px;
12
- ` })) : (index) })), _jsxs(Content, { children: [image && (_jsx("img", { src: image.src, alt: image.altText, css: css `
13
- height: auto;
14
- // 이미지로 인해 좌우로 스크롤이 생기는 것을 방지
15
- max-width: min(328px, 100%);
16
- width: fit-content;
17
- border-radius: 6px;
18
- ` })), text] }), isAnswer && (_jsx(CheckboxCircleFillIcon, { color: theme.color.foreground.success, css: css `
19
- width: 16px;
20
- height: 16px;
21
- ` }))] })));
22
- }
23
- const Container = styled.div(({ theme, isSelected, fullWidth }) => css `
24
- cursor: pointer;
25
- display: flex;
26
- box-sizing: border-box;
27
- width: ${fullWidth ? "100%" : "400px"};
28
- padding: 8px;
29
- gap: 8px;
30
- border-radius: 8px;
31
- background: ${isSelected
32
- ? theme.color.container.primaryContainer
33
- : theme.color.background.neutralAlt};
34
- border: ${isSelected
35
- ? `1px solid ${theme.color.foreground.primary}`
36
- : "1px solid transparent"};
37
- color: ${isSelected
38
- ? theme.color.container.primaryOnContainer
39
- : theme.color.foreground.neutralBase};
40
- `);
41
- const Index = styled.div(({ theme, isSelected }) => css `
42
- display: flex;
43
- box-sizing: border-box;
44
- width: 20px;
45
- height: 20px;
46
- padding: 4px;
47
- justify-content: center;
48
- align-items: center;
49
- border-radius: 4px;
50
- border: ${isSelected
51
- ? "none"
52
- : `1px solid ${theme.color.background.neutralAltActive}`};
53
- background: ${isSelected
54
- ? theme.color.background.primary
55
- : theme.color.background.neutralBase};
56
- color: ${isSelected
57
- ? theme.color.foreground.neutralAlt
58
- : theme.color.foreground.neutralBaseDisabled};
59
- font-family: ${theme.fontFamily.ui};
60
- font-size: 14px;
61
- font-weight: 800;
62
- line-height: 16px;
63
- `);
64
- const Content = styled.div(({ theme }) => css `
65
- display: flex;
66
- flex-direction: column;
67
- gap: 12px;
68
- flex: 1;
69
- font-family: ${theme.fontFamily.ui};
70
- font-size: 14px;
71
- font-weight: 400;
72
- line-height: 20px;
73
- `);
@@ -1,9 +0,0 @@
1
- /** @jsxImportSource @emotion/react */
2
- import { NodeKey } from "lexical";
3
- import { Selection } from "./ProblemSelectNode";
4
- export declare function SelectComponent(props: {
5
- selections: Selection[];
6
- selected: string[];
7
- hasMultipleAnswers?: boolean;
8
- nodeKey: NodeKey;
9
- }): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,90 +0,0 @@
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";
13
- /** @jsxImportSource @emotion/react */
14
- import { $getNodeByKey } from "lexical";
15
- import { $isProblemSelectNode } from "./ProblemSelectNode";
16
- import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
17
- import { useContext, useState } from "react";
18
- import useLexicalEditable from "@lexical/react/useLexicalEditable";
19
- import SelectBox from "./SelectBox";
20
- import { css } from "@emotion/react";
21
- import SquareButton from "../../../../components/SquareButton";
22
- import { AlarmWarningFillIcon, Settings3FillIcon } from "../../../../icons";
23
- import SettingForm from "./SettingForm";
24
- import styled from "@emotion/styled";
25
- import { LexicalCustomConfigContext } from "../../LexicalCustomConfigContext";
26
- export function SelectComponent(props) {
27
- const { selected, hasMultipleAnswers } = props, settingFormProps = __rest(props, ["selected", "hasMultipleAnswers"]);
28
- const { selections, nodeKey } = settingFormProps;
29
- const [editor] = useLexicalComposerContext();
30
- const [settingOpen, setSettingOpen] = useState(false);
31
- const isEditable = useLexicalEditable();
32
- const lexicalCustomConfig = useContext(LexicalCustomConfigContext);
33
- // 학생 view
34
- if (!isEditable) {
35
- return (_jsxs(_Fragment, { children: [hasMultipleAnswers && (_jsxs(Alert, { children: [_jsx(AlarmWarningFillIcon, { css: css `
36
- width: 14px;
37
- height: 14px;
38
- ` }), "\uC9C8\uBB38\uC5D0 \uD574\uB2F9\uD558\uB294 \uB2F5\uC744 \uBAA8\uB450 \uACE0\uB974\uB294 \uBB38\uC81C\uC785\uB2C8\uB2E4."] })), selections.map((selection, index) => (_jsx(SelectBox, { index: index + 1, isSelected: selected.includes(selection.value), image: selection.show.image, text: selection.show.text, onClick: () => {
39
- if (lexicalCustomConfig.freezeProblemNode)
40
- return;
41
- const isSelected = selected.includes(selection.value);
42
- if (isSelected) {
43
- editor.update(() => {
44
- const node = $getNodeByKey(nodeKey);
45
- if (!$isProblemSelectNode(node)) {
46
- return;
47
- }
48
- const newSelected = [...selected];
49
- const index = newSelected.indexOf(selection.value);
50
- newSelected.splice(index, 1);
51
- node.setSelected(newSelected);
52
- });
53
- }
54
- else {
55
- editor.update(() => {
56
- const node = $getNodeByKey(nodeKey);
57
- if (!$isProblemSelectNode(node)) {
58
- return;
59
- }
60
- const newSelected = [...selected];
61
- newSelected.push(selection.value);
62
- node.setSelected(newSelected);
63
- });
64
- }
65
- }, fullWidth: true }, index)))] }));
66
- }
67
- // 교사 edit view
68
- return (_jsxs(_Fragment, { children: [_jsxs("div", Object.assign({ css: css `
69
- display: flex;
70
- gap: 4px;
71
- ` }, { children: [_jsx("div", Object.assign({ css: css `
72
- display: flex;
73
- flex-direction: column;
74
- gap: 4px;
75
- ` }, { children: selections.map((selection, index) => (_jsx(SelectBox, { index: index + 1, isAnswer: selection.isAnswer, image: selection.show.image, text: selection.show.text || `${index + 1}번 선택지`, onClick: () => setSettingOpen(true) }, index))) })), _jsx(SquareButton, { size: "small", color: "icon", icon: _jsx(Settings3FillIcon, {}), onClick: () => {
76
- setSettingOpen(true);
77
- } })] })), settingOpen && (_jsx(SettingForm, Object.assign({}, settingFormProps, { onClose: () => setSettingOpen(false) })))] }));
78
- }
79
- const Alert = styled.div(({ theme }) => css `
80
- display: flex;
81
- gap: 4px;
82
- margin-bottom: 12px;
83
- color: ${theme.color.foreground.neutralBaseDisabled};
84
- /* Default/Label/12px-Md */
85
- font-family: ${theme.fontFamily.ui};
86
- font-size: 12px;
87
- font-style: normal;
88
- font-weight: 500;
89
- line-height: 16px; /* 133.333% */
90
- `);
@@ -1,17 +0,0 @@
1
- import { Selection } from "../ProblemSelectNode";
2
- import { Control, FieldArrayWithId, UseFieldArrayUpdate } from "react-hook-form";
3
- export interface FormSelectionProps {
4
- index: number;
5
- control: Control<{
6
- selections: Selection[];
7
- }, any>;
8
- field: FieldArrayWithId<{
9
- selections: Selection[];
10
- }, "selections", "uid">;
11
- update: UseFieldArrayUpdate<{
12
- selections: Selection[];
13
- }, "selections">;
14
- rules?: any;
15
- onDelete?: () => void;
16
- }
17
- export declare function FormSelection(props: FormSelectionProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,97 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/react/jsx-runtime";
2
- /** @jsxImportSource @emotion/react */
3
- import styled from "@emotion/styled";
4
- import { Controller, } from "react-hook-form";
5
- import { css } from "@emotion/react";
6
- import Input from "../../../../../components/Input";
7
- import { DeleteBinLineIcon, ErrorWarningFillIcon, ImageAddFillIcon, ImageEditFillIcon, } from "../../../../../icons";
8
- import SquareButton from "../../../../../components/SquareButton";
9
- import Switch from "../../../../../components/Switch";
10
- import { useState } from "react";
11
- import { InsertImageDialog } from "./InsertImageDialog";
12
- export function FormSelection(props) {
13
- const { index, control, field, update, rules, onDelete } = props;
14
- const [imageOpen, setImageOpen] = useState(false);
15
- const [inputFocused, setInputFocused] = useState(false);
16
- return (_jsxs(_Fragment, { children: [_jsx(InsertImageDialog, { title: field.show.image ? "이미지 바꾸기" : "이미지 삽입하기", open: imageOpen, onClose: () => setImageOpen(false), updateImg: (props) => {
17
- update(index, Object.assign(Object.assign({}, field), { show: Object.assign(Object.assign({}, field.show), { image: props }) }));
18
- }, deleteImg: field.show.image
19
- ? () => {
20
- update(index, Object.assign(Object.assign({}, field), { show: Object.assign(Object.assign({}, field.show), { image: undefined }) }));
21
- }
22
- : undefined }), _jsxs(Container, { children: [_jsx(Index, { children: index + 1 }), _jsxs("div", Object.assign({ css: css `
23
- display: flex;
24
- flex: 1;
25
- flex-direction: column;
26
- gap: 4px;
27
- ` }, { children: [field.show.image && field.show.image.src && (_jsx("img", { src: field.show.image.src, alt: field.show.image.altText, css: css `
28
- height: auto;
29
- // 이미지로 인해 좌우로 스크롤이 생기는 것을 방지
30
- max-width: min(400px, 100%);
31
- width: fit-content;
32
- border-radius: 6px;
33
- `, draggable: "false" })), _jsx(Controller, { name: `selections.${index}.show.text`, control: control, rules: rules, render: ({ field: { value, onChange }, fieldState: { invalid, error }, }) => (_jsx(Input, { size: "small", color: invalid
34
- ? "activeDanger"
35
- : inputFocused
36
- ? "activePrimary"
37
- : "default", value: value, onChange: onChange, inputProps: {
38
- onFocus: (_e) => {
39
- setInputFocused(true);
40
- },
41
- onBlur: (_e) => {
42
- setInputFocused(false);
43
- update(index, Object.assign(Object.assign({}, field), { show: Object.assign(Object.assign({}, field.show), { text: value }) }));
44
- },
45
- }, placeholder: `${index + 1}번 선택지`, hintIcon: invalid ? _jsx(ErrorWarningFillIcon, {}) : undefined, hintText: error === null || error === void 0 ? void 0 : error.message, multiline: true, fullWidth: true, css: css `
46
- flex: 1;
47
- ` })) })] })), _jsxs("div", Object.assign({ css: css `
48
- display: flex;
49
- height: 36px;
50
- gap: 8px;
51
- align-items: center;
52
- ` }, { children: [_jsx(SquareButton, { color: "icon", size: "xsmall", icon: field.show.image ? _jsx(ImageEditFillIcon, {}) : _jsx(ImageAddFillIcon, {}), onClick: () => {
53
- setImageOpen(true);
54
- } }), _jsx(Controller, { name: `selections.${index}.isAnswer`, control: control, render: ({ field: { value, onChange } }) => (_jsxs(Answer, Object.assign({ onClick: () => {
55
- onChange(!value);
56
- update(index, Object.assign(Object.assign({}, field), { isAnswer: !value }));
57
- } }, { children: ["\uC815\uB2F5", _jsx(Switch, { checked: value, size: "small" })] }))) }), onDelete && (_jsx(SquareButton, { color: "white", size: "xsmall", icon: _jsx(DeleteBinLineIcon, {}), onClick: onDelete }))] }))] })] }));
58
- }
59
- const Container = styled.div(({ theme }) => css `
60
- display: flex;
61
- padding: 4px 12px;
62
- gap: 8px;
63
- border-radius: 8px;
64
- background: ${theme.color.background.neutralAlt};
65
- `);
66
- const Index = styled.div(({ theme }) => css `
67
- display: flex;
68
- box-sizing: border-box;
69
- width: 20px;
70
- height: 20px;
71
- padding: 4px;
72
- margin-top: 8px;
73
- justify-content: center;
74
- align-items: center;
75
- border-radius: 4px;
76
- border: 1px solid ${theme.color.background.neutralAltActive};
77
- background: ${theme.color.background.neutralBase};
78
- color: ${theme.color.foreground.neutralBaseDisabled};
79
- font-family: ${theme.fontFamily.ui};
80
- font-size: 14px;
81
- font-weight: 800;
82
- line-height: 16px;
83
- `);
84
- const Answer = styled.div(({ theme }) => css `
85
- display: flex;
86
- align-items: center;
87
- padding-right: 4px;
88
- gap: 8px;
89
- color: ${theme.color.foreground.neutralBase};
90
- cursor: pointer;
91
- /* Default/Label/14px-Md */
92
- font-family: ${theme.fontFamily.ui};
93
- font-size: 14px;
94
- font-style: normal;
95
- font-weight: 500;
96
- line-height: 16px; /* 114.286% */
97
- `);
@@ -1,10 +0,0 @@
1
- import { ImageProps } from "../ProblemSelectNode";
2
- export interface InsertImageDialogProps {
3
- title: string;
4
- open: boolean;
5
- onClose: () => void;
6
- updateImg: (props: ImageProps) => void;
7
- /** 전달하면 "이미지 삭제하기" 버튼이 생깁니다. */
8
- deleteImg?: () => void;
9
- }
10
- export declare function InsertImageDialog(props: InsertImageDialogProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,106 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/react/jsx-runtime";
11
- /** @jsxImportSource @emotion/react */
12
- import { useContext, useRef, useState } from "react";
13
- import styled from "@emotion/styled";
14
- import { css, useTheme } from "@emotion/react";
15
- import { ImageFillIcon, LinkIcon, UploadLineIcon } from "../../../../../icons";
16
- import { AlertDialog, AlertDialogContent, AlertDialogTitle, } from "../../../../../components/AlertDialog";
17
- import Button from "../../../../../components/Button";
18
- import { CodleDesignSystemContext } from "../../../../../CodleDesignSystemProvider";
19
- import { InsertImageUriDialogBody } from "./InsertImageUriDialogBody";
20
- import { InsertImageUploadedDialogBody } from "./InsertImageUploadedDialogBody";
21
- export function InsertImageDialog(props) {
22
- const { title, open, onClose, updateImg, deleteImg } = props;
23
- const theme = useTheme();
24
- const [mode, setMode] = useState(null);
25
- const inputRef = useRef(null);
26
- const cdsContext = useContext(CodleDesignSystemContext);
27
- const [src, setSrc] = useState("");
28
- const [altText, setAltText] = useState("");
29
- const onClick = (props) => {
30
- updateImg(props);
31
- handleOnClose();
32
- };
33
- const handleOnClose = () => {
34
- setMode(null);
35
- setSrc("");
36
- setAltText("");
37
- onClose();
38
- };
39
- return (_jsxs(StyledAlertDialog, Object.assign({ icon: _jsx(ImageFillIcon, { color: theme.color.background.primary }), open: open, onClose: handleOnClose, disableIconPadding: true }, { children: [_jsx(StyledAlertDialogTitle, Object.assign({ onClose: handleOnClose }, { children: title })), !mode && (_jsx(AlertDialogContent, { children: _jsxs("div", Object.assign({ css: css `
40
- display: flex;
41
- flex-direction: column;
42
- gap: 16px;
43
- // Actions가 없는 경우 하단이 디자인과 맞지 않는다
44
- margin-bottom: -16px;
45
- ` }, { children: [_jsxs(Buttons, { children: [_jsxs(ButtonAndDescription, { children: [_jsx(Description, { children: "\uC774\uBBF8\uC9C0 URL\uC744 \uC54C\uACE0 \uC788\uB2E4\uBA74" }), _jsx(Button, { color: "grey", size: "medium", fullWidth: true, label: "URL\uB85C \uC0BD\uC785\uD558\uAE30", startIcon: _jsx(LinkIcon, {}), onClick: () => setMode("url") })] }), _jsxs(ButtonAndDescription, { children: [_jsx(Description, { children: "\uAC16\uACE0 \uC788\uB294 \uC774\uBBF8\uC9C0\uB97C \uC0BD\uC785\uD558\uACE0 \uC2F6\uB2E4\uBA74" }), _jsx(Button, { color: "grey", size: "medium", fullWidth: true, label: "\uD30C\uC77C \uC120\uD0DD\uD558\uAE30", startIcon: _jsx(UploadLineIcon, {}), onClick: () => {
46
- var _a;
47
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click();
48
- } }), _jsx(HiddenInput, { ref: inputRef, type: "file", accept: "image/*", onChange: (event) => __awaiter(this, void 0, void 0, function* () {
49
- var _a, _b;
50
- const file = (_a = event.target.files) === null || _a === void 0 ? void 0 : _a[0];
51
- if (!file)
52
- return;
53
- const uploadByFile = (_b = cdsContext.lexical) === null || _b === void 0 ? void 0 : _b.uploadByFile;
54
- if (uploadByFile) {
55
- setSrc(yield uploadByFile(file));
56
- setMode("file");
57
- }
58
- }) })] })] }), deleteImg && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(Button, { color: "textDanger", size: "medium", fullWidth: true, label: "\uC774\uBBF8\uC9C0 \uC0AD\uC81C\uD558\uAE30", onClick: deleteImg })] }))] })) })), mode === "url" && (_jsx(InsertImageUriDialogBody, { src: src, setSrc: setSrc, altText: altText, setAltText: setAltText, onClick: onClick })), mode === "file" && (_jsx(InsertImageUploadedDialogBody, { src: src, setSrc: setSrc, altText: altText, setAltText: setAltText, onClick: onClick }))] })));
59
- }
60
- const StyledAlertDialog = styled(AlertDialog) `
61
- gap: 16px;
62
- `;
63
- const StyledAlertDialogTitle = styled(AlertDialogTitle) `
64
- color: ${({ theme }) => theme.color.foreground.neutralBase};
65
- text-align: center;
66
-
67
- /* Default/Heading/20px-Bd */
68
- font-family: ${({ theme }) => theme.fontFamily.ui};
69
- font-size: 20px;
70
- font-style: normal;
71
- font-weight: 700;
72
- line-height: 28px; /* 140% */
73
- letter-spacing: 0.25px;
74
- `;
75
- const Buttons = styled.div `
76
- display: flex;
77
- flex: 1;
78
- align-items: flex-start;
79
- gap: 8px;
80
- `;
81
- const Divider = styled.div(({ theme }) => css `
82
- width: 100%;
83
- height: 1px;
84
- background: ${theme.color.background.neutralAltActive};
85
- `);
86
- const ButtonAndDescription = styled.div `
87
- display: flex;
88
- flex-direction: column;
89
- align-items: center;
90
- gap: 8px;
91
- flex: 1 0 0;
92
- `;
93
- const Description = styled.div `
94
- color: ${({ theme }) => theme.color.foreground.neutralBaseDisabled};
95
- text-align: center;
96
-
97
- /* Default/Label/12px-Md */
98
- font-family: ${({ theme }) => theme.fontFamily.ui};
99
- font-size: 12px;
100
- font-style: normal;
101
- font-weight: 500;
102
- line-height: 16px; /* 133.333% */
103
- `;
104
- const HiddenInput = styled.input `
105
- display: none;
106
- `;
@@ -1,9 +0,0 @@
1
- import { ImageProps } from "../ProblemSelectNode";
2
- export interface InsertImageUploadedDialogBodyProps {
3
- src: string;
4
- setSrc: (src: string) => void;
5
- altText: string;
6
- setAltText: (altText: string) => void;
7
- onClick: (props: ImageProps) => void;
8
- }
9
- export declare function InsertImageUploadedDialogBody(props: InsertImageUploadedDialogBodyProps): import("react/jsx-runtime").JSX.Element;
@@ -1,51 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
11
- import { useContext, useRef } from "react";
12
- import styled from "@emotion/styled";
13
- import { CodleDesignSystemContext } from "../../../../../CodleDesignSystemProvider";
14
- import { AlertDialogActions, AlertDialogContent, } from "../../../../../components/AlertDialog";
15
- import Button from "../../../../../components/Button";
16
- import { RefreshLineIcon } from "../../../../../icons";
17
- import Input from "../../../../../components/Input";
18
- export function InsertImageUploadedDialogBody(props) {
19
- const { src, setSrc, altText, setAltText, onClick } = props;
20
- const inputRef = useRef(null);
21
- const cdsContext = useContext(CodleDesignSystemContext);
22
- const isDisabled = src === "";
23
- return (_jsxs(_Fragment, { children: [_jsx(AlertDialogContent, { children: _jsxs(Inputs, { children: [_jsx(Button, { fullWidth: true, color: "grey", size: "medium", label: "\uD30C\uC77C \uBC14\uAFB8\uAE30", onClick: () => {
24
- var _a;
25
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click();
26
- }, startIcon: _jsx(RefreshLineIcon, {}) }), _jsx(HiddenInput, { ref: inputRef, type: "file", accept: "image/*", onChange: (event) => __awaiter(this, void 0, void 0, function* () {
27
- var _a, _b;
28
- const file = (_a = event.target.files) === null || _a === void 0 ? void 0 : _a[0];
29
- if (!file)
30
- return;
31
- const uploadByFile = (_b = cdsContext.lexical) === null || _b === void 0 ? void 0 : _b.uploadByFile;
32
- if (uploadByFile) {
33
- setSrc(yield uploadByFile(file));
34
- }
35
- }) }), _jsxs(ImagePreview, { children: ["\uC774\uBBF8\uC9C0 \uBBF8\uB9AC\uBCF4\uAE30", _jsx("img", { src: src, alt: altText })] }), _jsx(Input, { fullWidth: true, label: "\uB300\uCCB4 \uD14D\uC2A4\uD2B8", placeholder: "\uC0BD\uC785\uD558\uB294 \uC774\uBBF8\uC9C0\uC5D0 \uAD00\uD55C \uC124\uBA85", color: "default", size: "medium", onChange: (e) => {
36
- setAltText(e.target.value);
37
- }, value: altText })] }) }), _jsx(AlertDialogActions, { children: _jsx(Button, { fullWidth: true, label: "\uC0BD\uC785\uD558\uAE30", size: "medium", color: "primary", disabled: isDisabled, onClick: () => onClick({ altText, src }) }) })] }));
38
- }
39
- const Inputs = styled.div `
40
- display: flex;
41
- flex-direction: column;
42
- gap: 16px;
43
- `;
44
- const HiddenInput = styled.input `
45
- display: none;
46
- `;
47
- const ImagePreview = styled.div `
48
- display: flex;
49
- flex-direction: column;
50
- gap: 8px;
51
- `;
@@ -1,9 +0,0 @@
1
- import { ImageProps } from "../ProblemSelectNode";
2
- export interface InsertImageUriDialogBodyProps {
3
- src: string;
4
- setSrc: (src: string) => void;
5
- altText: string;
6
- setAltText: (altText: string) => void;
7
- onClick: (props: ImageProps) => void;
8
- }
9
- export declare function InsertImageUriDialogBody(props: InsertImageUriDialogBodyProps): import("react/jsx-runtime").JSX.Element;
@@ -1,20 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import styled from "@emotion/styled";
3
- import { AlertDialogActions, AlertDialogContent, } from "../../../../../components/AlertDialog";
4
- import Input from "../../../../../components/Input";
5
- import { LinkIcon } from "../../../../../icons";
6
- import Button from "../../../../../components/Button";
7
- export function InsertImageUriDialogBody(props) {
8
- const { src, setSrc, altText, setAltText, onClick } = props;
9
- const isDisabled = src === "";
10
- return (_jsxs(_Fragment, { children: [" ", _jsx(AlertDialogContent, { children: _jsxs(Inputs, { children: [_jsx(Input, { fullWidth: true, label: "URL", placeholder: "https://www.pexels.com/photo/n-2848492/", color: "default", size: "medium", onChange: (e) => {
11
- setSrc(e.target.value);
12
- }, value: src, startIcon: _jsx(LinkIcon, {}) }), _jsx(Input, { fullWidth: true, label: "\uB300\uCCB4 \uD14D\uC2A4\uD2B8", placeholder: "\uC0BD\uC785\uD558\uB294 \uC774\uBBF8\uC9C0\uC5D0 \uAD00\uD55C \uC124\uBA85", color: "default", size: "medium", onChange: (e) => {
13
- setAltText(e.target.value);
14
- }, value: altText })] }) }), _jsx(AlertDialogActions, { children: _jsx(Button, { fullWidth: true, label: "\uC0BD\uC785\uD558\uAE30", size: "medium", color: "primary", disabled: isDisabled, onClick: () => onClick({ altText, src }) }) })] }));
15
- }
16
- const Inputs = styled.div `
17
- display: flex;
18
- flex-direction: column;
19
- gap: 16px;
20
- `;
@@ -1,8 +0,0 @@
1
- import { Selection } from "../ProblemSelectNode";
2
- import { NodeKey } from "lexical";
3
- export interface SettingFormProps {
4
- selections: Selection[];
5
- nodeKey: NodeKey;
6
- onClose: () => void;
7
- }
8
- export default function SettingForm(props: SettingFormProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,136 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
- /** @jsxImportSource @emotion/react */
3
- import { useFieldArray, useForm, } from "react-hook-form";
4
- import { $isProblemSelectNode } from "../ProblemSelectNode";
5
- import { $getNodeByKey } from "lexical";
6
- import { css } from "@emotion/react";
7
- import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
8
- import styled from "@emotion/styled";
9
- import shadows from "../../../../../foundation/shadows";
10
- import { AddFillIcon, AlarmWarningFillIcon, ListRadioIcon, } from "../../../../../icons";
11
- import Button from "../../../../../components/Button";
12
- import { FormSelection } from "./FormSelection";
13
- import Tooltip from "../../../../../components/Tooltip";
14
- import { useState } from "react";
15
- export default function SettingForm(props) {
16
- const { selections, nodeKey, onClose } = props;
17
- const [editor] = useLexicalComposerContext();
18
- const [tooltipOpen, setTooltipOpen] = useState(false);
19
- const { control, handleSubmit } = useForm({
20
- mode: "all",
21
- defaultValues: {
22
- selections,
23
- },
24
- });
25
- const { fields, append, remove, update } = useFieldArray({
26
- control,
27
- name: "selections",
28
- keyName: "uid",
29
- });
30
- const onSettingSubmit = (data) => {
31
- editor.update(() => {
32
- const node = $getNodeByKey(nodeKey);
33
- if (!$isProblemSelectNode(node)) {
34
- return;
35
- }
36
- node.setSolutions(data.selections);
37
- });
38
- onClose();
39
- };
40
- function validateDuplicatedSelection(fields, index) {
41
- if (index === 0)
42
- return true;
43
- const duplicatedIndex = fields
44
- .slice(0, index)
45
- .findIndex((prevField) => prevField.show.text === fields[index].show.text);
46
- if (duplicatedIndex < 0)
47
- return true;
48
- return `${duplicatedIndex + 1}번 선택지와 같은 내용입니다.`;
49
- }
50
- const hasMultipleAnswers = fields.filter((field) => field.isAnswer).length > 1;
51
- const hasAnswer = fields.some((field) => field.isAnswer);
52
- return (_jsxs(Form, Object.assign({ onSubmit: handleSubmit(onSettingSubmit) }, { children: [_jsxs(Title, { children: [_jsx(ListRadioIcon, { css: css `
53
- width: 12px;
54
- height: 12px;
55
- ` }), "\uAC1D\uAD00\uC2DD \uC785\uB825 \uCE78"] }), _jsxs(Content, { children: [_jsxs(FormArea, { children: [_jsx(Label, { children: "\uB2F5\uC548" }), fields.map((field, index) => (_jsx(FormSelection, { index: index, control: control, field: field, update: update, rules: {
56
- required: "필수 입력 항목입니다.",
57
- validate: () => validateDuplicatedSelection(fields, index),
58
- }, onDelete: index !== 0
59
- ? () => {
60
- remove(index);
61
- }
62
- : undefined }, field.uid)))] }), _jsx(Button, { color: "grey", size: "small", startIcon: _jsx(AddFillIcon, {}), label: "\uC120\uD0DD\uC9C0 \uCD94\uAC00", onClick: () => {
63
- append({
64
- isAnswer: false,
65
- show: {
66
- text: "",
67
- },
68
- value: (fields.length + 1).toString(),
69
- });
70
- } }), hasMultipleAnswers && (_jsxs(Alert, { children: [_jsx(AlarmWarningFillIcon, { css: css `
71
- width: 14px;
72
- height: 14px;
73
- ` }), "\uC815\uB2F5\uC774 \uC5EC\uB7EC \uAC1C\uC778 \uBB38\uC81C\uC5D0\uB294 \uC815\uB2F5\uC744 \uBAA8\uB450 \uC120\uD0DD\uD574\uC57C \uD55C\uB2E4\uB294 \uC548\uB0B4\uAC00 \uC81C\uACF5\uB429\uB2C8\uB2E4."] }))] }), _jsxs(Buttons, { children: [_jsx(Button, { color: "grey", size: "xsmall", label: "\uB2EB\uAE30", onClick: onClose }), _jsx(Tooltip, Object.assign({ open: !hasAnswer && tooltipOpen, text: "\uC120\uD0DD\uC9C0 \uC911 \uC815\uB2F5\uC744 \uD45C\uC2DC\uD574\uC8FC\uC138\uC694.", onOpen: () => setTooltipOpen(true), onClose: () => setTooltipOpen(false), placement: "top-end" }, { children: _jsx("span", { children: _jsx(Button, { color: "primary", size: "xsmall", label: "\uC774\uB300\uB85C \uB123\uAE30", type: "submit", disabled: !hasAnswer }) }) }))] })] })));
74
- }
75
- const Form = styled.form(({ theme }) => css `
76
- display: flex;
77
- width: 620px;
78
- flex-direction: column;
79
- border-radius: 6px;
80
- border: 1px solid ${theme.color.background.neutralAltActive};
81
- background: ${theme.color.background.neutralBase};
82
- box-shadow: ${shadows.shadow08};
83
- `);
84
- const Title = styled.div(({ theme }) => css `
85
- display: flex;
86
- padding: 8px 12px;
87
- gap: 4px;
88
- align-items: center;
89
- color: ${theme.color.foreground.neutralBase};
90
- /* Default/Label/12px-Md */
91
- font-family: ${theme.fontFamily.ui};
92
- font-size: 12px;
93
- font-style: normal;
94
- font-weight: 500;
95
- line-height: 16px; /* 133.333% */
96
- `);
97
- const Content = styled.div(({ theme }) => css `
98
- display: flex;
99
- flex-direction: column;
100
- gap: 12px;
101
- padding: 12px;
102
- border-top: 1px solid ${theme.color.background.neutralAltActive};
103
- border-bottom: 1px solid ${theme.color.background.neutralAltActive};
104
- `);
105
- const FormArea = styled.div `
106
- display: flex;
107
- flex-direction: column;
108
- gap: 8px;
109
- `;
110
- const Label = styled.div(({ theme }) => css `
111
- color: ${theme.color.foreground.neutralBaseDisabled};
112
- /* Default/Label/12px-Md */
113
- font-family: ${theme.fontFamily.ui};
114
- font-size: 12px;
115
- font-style: normal;
116
- font-weight: 500;
117
- line-height: 16px; /* 133.333% */
118
- `);
119
- const Buttons = styled.div `
120
- display: flex;
121
- padding: 12px;
122
- justify-content: flex-end;
123
- align-items: center;
124
- gap: 8px;
125
- `;
126
- const Alert = styled.div(({ theme }) => css `
127
- display: flex;
128
- gap: 4px;
129
- color: ${theme.color.foreground.neutralBaseDisabled};
130
- /* Default/Label/12px-Md */
131
- font-family: ${theme.fontFamily.ui};
132
- font-size: 12px;
133
- font-style: normal;
134
- font-weight: 500;
135
- line-height: 16px; /* 133.333% */
136
- `);
@@ -1 +0,0 @@
1
- export { default } from "./SettingForm";
@@ -1 +0,0 @@
1
- export { default } from "./SettingForm";
@@ -1,2 +0,0 @@
1
- export * from "./ProblemSelectNode";
2
- export * from "./SelectComponent";
@@ -1,2 +0,0 @@
1
- export * from "./ProblemSelectNode";
2
- export * from "./SelectComponent";
@@ -1,9 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- */
8
- import { ReactElement } from "react";
9
- export default function ActionsPlugin(): ReactElement;
@@ -1,24 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- /**
3
- * Copyright (c) Meta Platforms, Inc. and affiliates.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- *
8
- */
9
- import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
10
- import { mergeRegister } from "@lexical/utils";
11
- import { useEffect, useState } from "react";
12
- import { Button, LockFillIcon, LockUnlockFillIcon } from "../../../..";
13
- export default function ActionsPlugin() {
14
- const [editor] = useLexicalComposerContext();
15
- const [isEditable, setIsEditable] = useState(() => editor.isEditable());
16
- useEffect(() => {
17
- return mergeRegister(editor.registerEditableListener((editable) => {
18
- setIsEditable(editable);
19
- }));
20
- }, [editor]);
21
- return (_jsx(Button, { color: "primary", size: "small", startIcon: isEditable ? _jsx(LockFillIcon, {}) : _jsx(LockUnlockFillIcon, {}), onClick: () => {
22
- editor.setEditable(!editor.isEditable());
23
- }, title: "Read-Only Mode", label: `${!isEditable ? "수정 모드" : "읽기 모드"}로 변경`, "aria-label": `${!isEditable ? "Unlock" : "Lock"} read-only mode` }));
24
- }
@@ -1,5 +0,0 @@
1
- /// <reference types="react" />
2
- import { LexicalCommand } from "lexical";
3
- import { ProblemSelectPayload } from "../../nodes/ProblemSelectNode";
4
- export declare const INSERT_PROBLEM_SELECT_COMMAND: LexicalCommand<ProblemSelectPayload>;
5
- export default function ProblemInputPlugin(): JSX.Element | null;
@@ -1,20 +0,0 @@
1
- import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
2
- import { $insertNodeToNearestRoot } from "@lexical/utils";
3
- import { COMMAND_PRIORITY_EDITOR, createCommand, } from "lexical";
4
- import { useEffect } from "react";
5
- import { $createProblemSelectNode, ProblemSelectNode, } from "../../nodes/ProblemSelectNode";
6
- export const INSERT_PROBLEM_SELECT_COMMAND = createCommand("INSERT_PROBLEM_SELECT_COMMAND");
7
- export default function ProblemInputPlugin() {
8
- const [editor] = useLexicalComposerContext();
9
- useEffect(() => {
10
- if (!editor.hasNodes([ProblemSelectNode])) {
11
- throw new Error("ProblemSelectNode: ProblemSelectNode not registered on editor");
12
- }
13
- editor.registerCommand(INSERT_PROBLEM_SELECT_COMMAND, (payload) => {
14
- const problemInputNode = $createProblemSelectNode(payload);
15
- $insertNodeToNearestRoot(problemInputNode);
16
- return true;
17
- }, COMMAND_PRIORITY_EDITOR);
18
- }, [editor]);
19
- return null;
20
- }