@team-monolith/cds 1.52.0 → 1.52.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectBox/SelectBoxEdit.d.ts +2 -1
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectComponent.js +2 -1
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/FormSelection.js +15 -15
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/SettingForm.js +25 -3
- package/dist/patterns/LexicalEditor/nodes/SheetInputNode/InputComponent.js +11 -6
- package/dist/patterns/LexicalEditor/nodes/SheetInputNode/index.d.ts +0 -1
- package/dist/patterns/LexicalEditor/nodes/SheetInputNode/index.js +0 -1
- package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SelectBox → SelectComponent/SelectBox}/SelectBoxComponent.d.ts +1 -1
- package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SelectBox → SelectComponent/SelectBox}/SelectBoxEdit.d.ts +3 -2
- package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SelectBox → SelectComponent/SelectBox}/SelectBoxView.d.ts +1 -1
- package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SelectBox → SelectComponent/SelectBox}/SelectBoxView.js +1 -1
- package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SelectComponent.d.ts → SelectComponent/SelectComponent.d.ts} +1 -1
- package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SelectComponent.js → SelectComponent/SelectComponent.js} +7 -6
- package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SettingForm → SelectComponent/SettingForm}/FormAllowMultipleAnswers.js +1 -1
- package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SettingForm → SelectComponent/SettingForm}/FormSelection.js +17 -17
- package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SettingForm → SelectComponent/SettingForm}/SettingForm.d.ts +1 -1
- package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SettingForm → SelectComponent/SettingForm}/SettingForm.js +27 -5
- package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/SelectComponent/index.d.ts +1 -0
- package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/SelectComponent/index.js +1 -0
- package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/index.d.ts +0 -1
- package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/index.js +0 -1
- package/dist/patterns/LexicalEditor/plugins/ComponentAdderPlugin/useContextMenuOptions.js +30 -0
- package/package.json +1 -1
- /package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SelectBox → SelectComponent/SelectBox}/SelectBoxComponent.js +0 -0
- /package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SelectBox → SelectComponent/SelectBox}/SelectBoxEdit.js +0 -0
- /package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SelectBox → SelectComponent/SelectBox}/index.d.ts +0 -0
- /package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SelectBox → SelectComponent/SelectBox}/index.js +0 -0
- /package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SettingForm → SelectComponent/SettingForm}/FormAllowMultipleAnswers.d.ts +0 -0
- /package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SettingForm → SelectComponent/SettingForm}/FormSelection.d.ts +0 -0
- /package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SettingForm → SelectComponent/SettingForm}/index.d.ts +0 -0
- /package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/{SettingForm → SelectComponent/SettingForm}/index.js +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { ImageProps } from "../../insertImageDialog";
|
|
2
|
+
import React from "react";
|
|
2
3
|
export interface SelectBoxEditProps {
|
|
3
4
|
index: number;
|
|
4
5
|
isAnswer: boolean;
|
|
5
6
|
image?: ImageProps | null;
|
|
6
|
-
text:
|
|
7
|
+
text: React.ReactNode;
|
|
7
8
|
onClick: () => void;
|
|
8
9
|
}
|
|
9
10
|
export declare function SelectBoxEdit(props: SelectBoxEditProps): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
@@ -65,7 +65,8 @@ export function SelectComponent(props) {
|
|
|
65
65
|
display: flex;
|
|
66
66
|
flex-direction: column;
|
|
67
67
|
gap: 4px;
|
|
68
|
-
` }, { children: selections.map((selection, index) => (_jsx(SelectBoxEdit, { index: index + 1, isAnswer: "isAnswer" in selection && selection.isAnswer, image: selection.show.image, text: selection.show.text ||
|
|
68
|
+
` }, { children: selections.map((selection, index) => (_jsx(SelectBoxEdit, { index: index + 1, isAnswer: "isAnswer" in selection && selection.isAnswer, image: selection.show.image, text: selection.show.text ||
|
|
69
|
+
(selection.show.image ? null : `${index + 1}번 선택지`), onClick: () => setSettingOpen(true) }, index))) })), _jsx(SquareButton, { size: "small", color: "icon", icon: _jsx(Settings3FillIcon, {}), onClick: () => {
|
|
69
70
|
setSettingOpen(true);
|
|
70
71
|
} })] })), settingOpen && (_jsx(SettingForm, { selections: selections, nodeKey: nodeKey, onClose: () => setSettingOpen(false) }))] }));
|
|
71
72
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
|
|
2
2
|
/** @jsxImportSource @emotion/react */
|
|
3
3
|
import styled from "@emotion/styled";
|
|
4
4
|
import { Controller } from "react-hook-form";
|
|
@@ -13,22 +13,22 @@ export function FormSelection(props) {
|
|
|
13
13
|
const { index, control, watch, rules, onDelete } = props;
|
|
14
14
|
const [imageOpen, setImageOpen] = useState(false);
|
|
15
15
|
const [inputFocused, setInputFocused] = useState(false);
|
|
16
|
-
return (_jsxs(Container, { children: [_jsx(Index, { children: index + 1 }), _jsxs("div", Object.assign({ css: css `
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
16
|
+
return (_jsxs(Container, { children: [_jsx(Index, { children: index + 1 }), _jsx(Controller, { name: `selections.${index}.show`, control: control, rules: rules, render: ({ field: { value, onChange }, fieldState: { invalid, error }, }) => (_jsxs("div", Object.assign({ css: css `
|
|
17
|
+
display: flex;
|
|
18
|
+
flex: 1;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
gap: 4px;
|
|
21
|
+
` }, { children: [_jsx(InsertImageDialog, { title: value.image ? "이미지 바꾸기" : "이미지 삽입하기", open: imageOpen, onClose: () => setImageOpen(false), updateImg: (props) => onChange(Object.assign(Object.assign({}, value), { image: props })), deleteButton: Boolean(value.image) }), value.image && (_jsx("img", { src: value.image.src, alt: value.image.altText, css: css `
|
|
22
|
+
height: auto;
|
|
23
|
+
// 이미지로 인해 좌우로 스크롤이 생기는 것을 방지
|
|
24
|
+
max-width: min(400px, 100%);
|
|
25
|
+
width: fit-content;
|
|
26
|
+
border-radius: 6px;
|
|
27
|
+
`, draggable: "false" })), _jsx(Input, { size: "small", color: invalid
|
|
28
28
|
? "activeDanger"
|
|
29
29
|
: inputFocused
|
|
30
30
|
? "activePrimary"
|
|
31
|
-
: "default", value: value, onChange: onChange, inputProps: {
|
|
31
|
+
: "default", value: value.text, onChange: (e) => onChange(Object.assign(Object.assign({}, value), { text: e.target.value })), inputProps: {
|
|
32
32
|
onFocus: (_e) => {
|
|
33
33
|
setInputFocused(true);
|
|
34
34
|
},
|
|
@@ -37,7 +37,7 @@ export function FormSelection(props) {
|
|
|
37
37
|
},
|
|
38
38
|
}, placeholder: `${index + 1}번 선택지`, hintIcon: invalid ? _jsx(ErrorWarningFillIcon, {}) : undefined, hintText: error === null || error === void 0 ? void 0 : error.message, multiline: true, fullWidth: true, css: css `
|
|
39
39
|
flex: 1;
|
|
40
|
-
` })
|
|
40
|
+
` })] }))) }), _jsxs("div", Object.assign({ css: css `
|
|
41
41
|
display: flex;
|
|
42
42
|
height: 36px;
|
|
43
43
|
gap: 8px;
|
|
@@ -38,13 +38,30 @@ export default function SettingForm(props) {
|
|
|
38
38
|
});
|
|
39
39
|
onClose();
|
|
40
40
|
};
|
|
41
|
+
function validateRequiredSelection(index) {
|
|
42
|
+
const selections = watch("selections");
|
|
43
|
+
const selection = selections[index];
|
|
44
|
+
if (selection.show.image || selection.show.text)
|
|
45
|
+
return true;
|
|
46
|
+
return "필수 입력 항목입니다.";
|
|
47
|
+
}
|
|
41
48
|
function validateDuplicatedSelection(index) {
|
|
42
49
|
const selections = watch("selections");
|
|
43
50
|
if (index === 0)
|
|
44
51
|
return true;
|
|
52
|
+
const image = selections[index].show.image;
|
|
53
|
+
const text = selections[index].show.text;
|
|
45
54
|
const duplicatedIndex = selections
|
|
46
55
|
.slice(0, index)
|
|
47
|
-
.findIndex((selection) =>
|
|
56
|
+
.findIndex((selection) => {
|
|
57
|
+
var _a;
|
|
58
|
+
// text를 비교하고, text가 같은 경우 image도 비교합니다.
|
|
59
|
+
if (selection.show.text !== text)
|
|
60
|
+
return false;
|
|
61
|
+
if (((_a = selection.show.image) === null || _a === void 0 ? void 0 : _a.src) !== (image === null || image === void 0 ? void 0 : image.src))
|
|
62
|
+
return false;
|
|
63
|
+
return true;
|
|
64
|
+
});
|
|
48
65
|
if (duplicatedIndex < 0)
|
|
49
66
|
return true;
|
|
50
67
|
return `${duplicatedIndex + 1}번 선택지와 같은 내용입니다.`;
|
|
@@ -56,8 +73,13 @@ export default function SettingForm(props) {
|
|
|
56
73
|
width: 12px;
|
|
57
74
|
height: 12px;
|
|
58
75
|
` }), "\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, watch: watch, rules: {
|
|
59
|
-
|
|
60
|
-
|
|
76
|
+
validate: () => {
|
|
77
|
+
const required = validateRequiredSelection(index);
|
|
78
|
+
if (required !== true) {
|
|
79
|
+
return required;
|
|
80
|
+
}
|
|
81
|
+
return validateDuplicatedSelection(index);
|
|
82
|
+
},
|
|
61
83
|
}, onDelete: index !== 0
|
|
62
84
|
? () => {
|
|
63
85
|
remove(index);
|
|
@@ -10,6 +10,9 @@ import { css } from "@emotion/react";
|
|
|
10
10
|
import { Input, Settings3FillIcon, SquareButton } from "../../../..";
|
|
11
11
|
import { SettingForm } from "./SettingForm";
|
|
12
12
|
import { $isSheetInputNode } from "./SheetInputNode";
|
|
13
|
+
const TEXTAREA_HEIGHT = 84;
|
|
14
|
+
/** VirtualInput을 Input(size: small)처럼 만들기 위한 padding 값입니다. */
|
|
15
|
+
const INPUT_VERTICAL_PADDING = 8;
|
|
13
16
|
export function InputComponent(props) {
|
|
14
17
|
const { multiline, value, placeholder, nodeKey } = props;
|
|
15
18
|
const [editor] = useLexicalComposerContext();
|
|
@@ -36,10 +39,12 @@ export function InputComponent(props) {
|
|
|
36
39
|
if (!isEditable) {
|
|
37
40
|
return (_jsx(Input, { multiline: multiline, css: css `
|
|
38
41
|
textarea {
|
|
39
|
-
//
|
|
40
|
-
max-height:
|
|
41
|
-
min-height:
|
|
42
|
-
// mui
|
|
42
|
+
// textarea의 height를 고정시키기 위해 max-height와 min-height를 설정합니다.
|
|
43
|
+
max-height: ${TEXTAREA_HEIGHT}px;
|
|
44
|
+
min-height: ${TEXTAREA_HEIGHT}px;
|
|
45
|
+
// https://github.com/mui/material-ui/blob/next/packages/mui-base/src/TextareaAutosize/TextareaAutosize.tsx
|
|
46
|
+
// MUI TextareaAutoSize는 overflow를 hidden으로 설정하는 로직이 있습니다.
|
|
47
|
+
// 그래서 부득이하게 !important를 사용합니다.
|
|
43
48
|
overflow: auto !important;
|
|
44
49
|
}
|
|
45
50
|
`, inputProps: freezeProblemNode
|
|
@@ -58,14 +63,14 @@ export function InputComponent(props) {
|
|
|
58
63
|
gap: 4px;
|
|
59
64
|
` }, { children: [_jsx(VirtualInput, Object.assign({ onClick: () => setSettingOpen((open) => !open), css: multiline &&
|
|
60
65
|
css `
|
|
61
|
-
height:
|
|
66
|
+
height: ${TEXTAREA_HEIGHT + 2 * INPUT_VERTICAL_PADDING}px;
|
|
62
67
|
` }, { children: multiline ? "서술형 입력 칸" : "단답형 입력 칸" })), _jsx(SquareButton, { size: "small", color: "icon", icon: _jsx(Settings3FillIcon, {}), onClick: () => setSettingOpen((open) => !open) })] })), settingOpen && (_jsx(SettingForm, { multiline: multiline, placeholder: placeholder, nodeKey: nodeKey, onClose: () => setSettingOpen(false) }))] }));
|
|
63
68
|
}
|
|
64
69
|
const VirtualInput = styled.div(({ theme }) => css `
|
|
65
70
|
box-sizing: border-box;
|
|
66
71
|
height: 36px;
|
|
67
72
|
width: 400px;
|
|
68
|
-
padding:
|
|
73
|
+
padding: ${INPUT_VERTICAL_PADDING}px 16px;
|
|
69
74
|
align-items: center;
|
|
70
75
|
border-radius: 8px;
|
|
71
76
|
background: ${theme.color.background.neutralAlt};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import { ImageProps } from "
|
|
2
|
+
import { ImageProps } from "../../../insertImageDialog";
|
|
3
3
|
export declare const SelectBoxClasses: {
|
|
4
4
|
readonly container: "SheetSelectNode-SelectBox-container";
|
|
5
5
|
readonly index: "SheetSelectNode-SelectBox-index";
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ImageProps } from "../../../insertImageDialog";
|
|
2
3
|
/** SheetSelectNode의 하나의 선택지 edit모드 컴포넌트입니다. */
|
|
3
4
|
export declare function SelectBoxEdit(props: {
|
|
4
5
|
index: number;
|
|
5
6
|
image?: ImageProps | null;
|
|
6
|
-
text:
|
|
7
|
+
text: React.ReactNode;
|
|
7
8
|
onClick: () => void;
|
|
8
9
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "@emotion/react/jsx-runtime";
|
|
|
2
2
|
/** @jsxImportSource @emotion/react */
|
|
3
3
|
import { css } from "@emotion/react";
|
|
4
4
|
import { SelectBoxComponent } from "./SelectBoxComponent";
|
|
5
|
-
import { CheckFillIcon } from "
|
|
5
|
+
import { CheckFillIcon } from "../../../../../../icons";
|
|
6
6
|
function getIndexIcon(type, index) {
|
|
7
7
|
return {
|
|
8
8
|
primary: (_jsx(CheckFillIcon, { css: css `
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @jsxImportSource @emotion/react */
|
|
2
2
|
import { NodeKey } from "lexical";
|
|
3
|
-
import { Selection } from "
|
|
3
|
+
import { Selection } from "../SheetSelectNode";
|
|
4
4
|
export declare function SelectComponent(props: {
|
|
5
5
|
selections: Selection[];
|
|
6
6
|
selected: string[];
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/react/jsx-runtime";
|
|
2
2
|
/** @jsxImportSource @emotion/react */
|
|
3
3
|
import { $getNodeByKey } from "lexical";
|
|
4
|
-
import { $isSheetSelectNode } from "
|
|
4
|
+
import { $isSheetSelectNode } from "../SheetSelectNode";
|
|
5
5
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
6
6
|
import { useContext, useState } from "react";
|
|
7
7
|
import useLexicalEditable from "@lexical/react/useLexicalEditable";
|
|
8
|
-
import { LexicalCustomConfigContext } from "
|
|
8
|
+
import { LexicalCustomConfigContext } from "../../../LexicalCustomConfigContext";
|
|
9
9
|
import styled from "@emotion/styled";
|
|
10
10
|
import { css } from "@emotion/react";
|
|
11
|
-
import { AlarmWarningFillIcon, Settings3FillIcon } from "
|
|
12
|
-
import
|
|
13
|
-
import SquareButton from "../../../../components/SquareButton";
|
|
11
|
+
import { AlarmWarningFillIcon, Settings3FillIcon } from "../../../../../icons";
|
|
12
|
+
import SquareButton from "../../../../../components/SquareButton";
|
|
14
13
|
import { SettingForm } from "./SettingForm";
|
|
14
|
+
import { SelectBoxEdit, SelectBoxView } from "./SelectBox";
|
|
15
15
|
export function SelectComponent(props) {
|
|
16
16
|
const { selections, selected, allowMultipleAnswers, nodeKey } = props;
|
|
17
17
|
const [editor] = useLexicalComposerContext();
|
|
@@ -60,7 +60,8 @@ export function SelectComponent(props) {
|
|
|
60
60
|
display: flex;
|
|
61
61
|
flex-direction: column;
|
|
62
62
|
gap: 4px;
|
|
63
|
-
` }, { children: selections.map((selection, index) => (_jsx(SelectBoxEdit, { index: index + 1, image: selection.show.image, text: selection.show.text ||
|
|
63
|
+
` }, { children: selections.map((selection, index) => (_jsx(SelectBoxEdit, { index: index + 1, image: selection.show.image, text: selection.show.text ||
|
|
64
|
+
(selection.show.image ? null : `${index + 1}번 선택지`), onClick: () => setSettingOpen((open) => !open) }, index))) })), _jsx(SquareButton, { size: "small", color: "icon", icon: _jsx(Settings3FillIcon, {}), onClick: () => {
|
|
64
65
|
setSettingOpen((open) => !open);
|
|
65
66
|
} })] })), settingOpen && (_jsx(SettingForm, { data: {
|
|
66
67
|
selections,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Controller } from "react-hook-form";
|
|
3
|
-
import { SegmentedControlButton, SegmentedControlGroup, } from "
|
|
3
|
+
import { SegmentedControlButton, SegmentedControlGroup, } from "../../../../../SegmentedControl";
|
|
4
4
|
/** SheetSelectNode SettingForm의 다중 선택 허용 여부 폼입니다. */
|
|
5
5
|
export function FormAllowMultipleAnswers(props) {
|
|
6
6
|
const { control } = props;
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
|
|
2
2
|
/** @jsxImportSource @emotion/react */
|
|
3
3
|
import { Controller } from "react-hook-form";
|
|
4
4
|
import styled from "@emotion/styled";
|
|
5
5
|
import { css } from "@emotion/react";
|
|
6
6
|
import { useState } from "react";
|
|
7
|
-
import { InsertImageDialog } from "
|
|
8
|
-
import { DeleteBinLineIcon, ErrorWarningFillIcon, ImageAddFillIcon, ImageEditFillIcon, Input, SquareButton, } from "
|
|
7
|
+
import { InsertImageDialog } from "../../../insertImageDialog";
|
|
8
|
+
import { DeleteBinLineIcon, ErrorWarningFillIcon, ImageAddFillIcon, ImageEditFillIcon, Input, SquareButton, } from "../../../../../..";
|
|
9
9
|
/** SheetSelectNode SettingForm의 단일 선택지 폼입니다. */
|
|
10
10
|
export default function FormSelection(props) {
|
|
11
11
|
const { index, control, watch, rules, onDelete } = props;
|
|
12
12
|
const [imageOpen, setImageOpen] = useState(false);
|
|
13
13
|
const [inputFocused, setInputFocused] = useState(false);
|
|
14
|
-
return (_jsxs(Container, { children: [_jsx(Index, { children: index + 1 }), _jsxs("div", Object.assign({ css: css `
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
return (_jsxs(Container, { children: [_jsx(Index, { children: index + 1 }), _jsx(Controller, { name: `selections.${index}.show`, control: control, rules: rules, render: ({ field: { value, onChange }, fieldState: { invalid, error }, }) => (_jsxs("div", Object.assign({ css: css `
|
|
15
|
+
display: flex;
|
|
16
|
+
flex: 1;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
gap: 4px;
|
|
19
|
+
` }, { children: [_jsx(InsertImageDialog, { title: value.image ? "이미지 바꾸기" : "이미지 삽입하기", open: imageOpen, onClose: () => setImageOpen(false), updateImg: (props) => onChange(Object.assign(Object.assign({}, value), { image: props })), deleteButton: Boolean(value.image) }), value.image && (_jsx("img", { src: value.image.src, alt: value.image.altText, css: css `
|
|
20
|
+
height: auto;
|
|
21
|
+
// 이미지로 인해 좌우로 스크롤이 생기는 것을 방지
|
|
22
|
+
max-width: min(400px, 100%);
|
|
23
|
+
width: fit-content;
|
|
24
|
+
border-radius: 6px;
|
|
25
|
+
`, draggable: "false" })), _jsx(Input, { size: "small", color: invalid
|
|
26
26
|
? "activeDanger"
|
|
27
27
|
: inputFocused
|
|
28
28
|
? "activePrimary"
|
|
29
|
-
: "default", value: value, onChange: onChange, inputProps: {
|
|
29
|
+
: "default", value: value.text, onChange: (e) => onChange(Object.assign(Object.assign({}, value), { text: e.target.value })), inputProps: {
|
|
30
30
|
onFocus: (_e) => {
|
|
31
31
|
setInputFocused(true);
|
|
32
32
|
},
|
|
@@ -35,7 +35,7 @@ export default function FormSelection(props) {
|
|
|
35
35
|
},
|
|
36
36
|
}, placeholder: `${index + 1}번 선택지`, hintIcon: invalid ? _jsx(ErrorWarningFillIcon, {}) : undefined, hintText: error === null || error === void 0 ? void 0 : error.message, multiline: true, fullWidth: true, css: css `
|
|
37
37
|
flex: 1;
|
|
38
|
-
` })
|
|
38
|
+
` })] }))) }), _jsxs("div", Object.assign({ css: css `
|
|
39
39
|
display: flex;
|
|
40
40
|
// 이미지가 들어가서 container height가 커져도 높이가 유지되도록 설정
|
|
41
41
|
height: 36px;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @jsxImportSource @emotion/react */
|
|
2
2
|
import { NodeKey } from "lexical";
|
|
3
|
-
import { Selection } from "
|
|
3
|
+
import { Selection } from "../../SheetSelectNode";
|
|
4
4
|
export interface SettingFormData {
|
|
5
5
|
selections: Selection[];
|
|
6
6
|
allowMultipleAnswers: boolean;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
|
|
2
2
|
/** @jsxImportSource @emotion/react */
|
|
3
3
|
import { $getNodeByKey } from "lexical";
|
|
4
|
-
import { $isSheetSelectNode } from "
|
|
4
|
+
import { $isSheetSelectNode } from "../../SheetSelectNode";
|
|
5
5
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
6
6
|
import { useFieldArray, useForm } from "react-hook-form";
|
|
7
7
|
import styled from "@emotion/styled";
|
|
8
8
|
import { css } from "@emotion/react";
|
|
9
|
-
import { AddFillIcon, AlarmWarningFillIcon, Button, ListRadioIcon, shadows, } from "
|
|
9
|
+
import { AddFillIcon, AlarmWarningFillIcon, Button, ListRadioIcon, shadows, } from "../../../../../..";
|
|
10
10
|
import { uid } from "uid";
|
|
11
11
|
import FormSelection from "./FormSelection";
|
|
12
12
|
import { FormAllowMultipleAnswers } from "./FormAllowMultipleAnswers";
|
|
@@ -38,13 +38,30 @@ export function SettingForm(props) {
|
|
|
38
38
|
});
|
|
39
39
|
onClose();
|
|
40
40
|
};
|
|
41
|
+
function validateRequiredSelection(index) {
|
|
42
|
+
const selections = watch("selections");
|
|
43
|
+
const selection = selections[index];
|
|
44
|
+
if (selection.show.image || selection.show.text)
|
|
45
|
+
return true;
|
|
46
|
+
return "필수 입력 항목입니다.";
|
|
47
|
+
}
|
|
41
48
|
function validateDuplicatedSelection(index) {
|
|
42
49
|
const selections = watch("selections");
|
|
43
50
|
if (index === 0)
|
|
44
51
|
return true;
|
|
52
|
+
const image = selections[index].show.image;
|
|
53
|
+
const text = selections[index].show.text;
|
|
45
54
|
const duplicatedIndex = selections
|
|
46
55
|
.slice(0, index)
|
|
47
|
-
.findIndex((selection) =>
|
|
56
|
+
.findIndex((selection) => {
|
|
57
|
+
var _a;
|
|
58
|
+
// text를 비교하고, text가 같은 경우 image도 비교합니다.
|
|
59
|
+
if (selection.show.text !== text)
|
|
60
|
+
return false;
|
|
61
|
+
if (((_a = selection.show.image) === null || _a === void 0 ? void 0 : _a.src) !== (image === null || image === void 0 ? void 0 : image.src))
|
|
62
|
+
return false;
|
|
63
|
+
return true;
|
|
64
|
+
});
|
|
48
65
|
if (duplicatedIndex < 0)
|
|
49
66
|
return true;
|
|
50
67
|
return `${duplicatedIndex + 1}번 선택지와 같은 내용입니다.`;
|
|
@@ -53,8 +70,13 @@ export function SettingForm(props) {
|
|
|
53
70
|
width: 12px;
|
|
54
71
|
height: 12px;
|
|
55
72
|
` }), "\uC120\uD0DD\uD615 \uC785\uB825 \uCE78"] }), _jsxs(Content, { children: [_jsxs(Left, { children: [_jsxs(FormArea, { children: [_jsx(Label, { children: "\uC120\uD0DD\uC9C0" }), fields.map((field, index) => (_jsx(FormSelection, { index: index, control: control, watch: watch, rules: {
|
|
56
|
-
|
|
57
|
-
|
|
73
|
+
validate: () => {
|
|
74
|
+
const required = validateRequiredSelection(index);
|
|
75
|
+
if (required !== true) {
|
|
76
|
+
return required;
|
|
77
|
+
}
|
|
78
|
+
return validateDuplicatedSelection(index);
|
|
79
|
+
},
|
|
58
80
|
}, onDelete: index !== 0
|
|
59
81
|
? () => {
|
|
60
82
|
remove(index);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./SelectComponent";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./SelectComponent";
|
|
@@ -15,6 +15,8 @@ import { useTheme } from "@emotion/react";
|
|
|
15
15
|
import { css } from "@emotion/css";
|
|
16
16
|
import { $isProblemInputNode } from "../../nodes";
|
|
17
17
|
import { $isProblemSelectNode, } from "../../nodes/ProblemSelectNode";
|
|
18
|
+
import { $isSheetInputNode } from "../../nodes/SheetInputNode";
|
|
19
|
+
import { $isSheetSelectNode, } from "../../nodes/SheetSelectNode";
|
|
18
20
|
function getParagraphContextMenuOptions(editor, node, setOpen) {
|
|
19
21
|
return [
|
|
20
22
|
new ComponentPickerOption("본문", {
|
|
@@ -197,6 +199,28 @@ function getProblemSelectContextMenuOptions(node) {
|
|
|
197
199
|
}),
|
|
198
200
|
];
|
|
199
201
|
}
|
|
202
|
+
function getSheetInputContextMenuOptions(node) {
|
|
203
|
+
return [
|
|
204
|
+
new ComponentPickerOption("블록 삭제", {
|
|
205
|
+
icon: _jsx(CloseFillIcon, {}),
|
|
206
|
+
keywords: [],
|
|
207
|
+
onSelect: () => {
|
|
208
|
+
node.remove();
|
|
209
|
+
},
|
|
210
|
+
}),
|
|
211
|
+
];
|
|
212
|
+
}
|
|
213
|
+
function getSheetSelectContextMenuOptions(node) {
|
|
214
|
+
return [
|
|
215
|
+
new ComponentPickerOption("블록 삭제", {
|
|
216
|
+
icon: _jsx(CloseFillIcon, {}),
|
|
217
|
+
keywords: [],
|
|
218
|
+
onSelect: () => {
|
|
219
|
+
node.remove();
|
|
220
|
+
},
|
|
221
|
+
}),
|
|
222
|
+
];
|
|
223
|
+
}
|
|
200
224
|
function getColoredQuoteContextMenuOptions(editor, theme, node) {
|
|
201
225
|
return [
|
|
202
226
|
new ComponentPickerOption("회색", {
|
|
@@ -280,6 +304,12 @@ export function useContextMenuOptions(props) {
|
|
|
280
304
|
else if ($isProblemSelectNode(node)) {
|
|
281
305
|
return getProblemSelectContextMenuOptions(node);
|
|
282
306
|
}
|
|
307
|
+
else if ($isSheetInputNode(node)) {
|
|
308
|
+
return getSheetInputContextMenuOptions(node);
|
|
309
|
+
}
|
|
310
|
+
else if ($isSheetSelectNode(node)) {
|
|
311
|
+
return getSheetSelectContextMenuOptions(node);
|
|
312
|
+
}
|
|
283
313
|
else if (node instanceof ParagraphNode) {
|
|
284
314
|
return getParagraphContextMenuOptions(editor, node, setImageOpen);
|
|
285
315
|
}
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|