@team-monolith/cds 1.9.9 → 1.9.10
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/ProblemSelectNode.d.ts +2 -2
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/ProblemSelectNode.js +1 -1
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectBox.d.ts +1 -1
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectBox.js +1 -1
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectComponent.js +2 -7
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/FormSelection.d.ts +3 -6
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/FormSelection.js +37 -45
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageDialog.d.ts +2 -2
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageDialog.js +20 -12
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageUploadedDialogBody.d.ts +4 -5
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageUploadedDialogBody.js +5 -6
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageUriDialogBody.d.ts +3 -5
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageUriDialogBody.js +4 -7
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/SettingForm.js +22 -11
- package/dist/patterns/LexicalEditor/plugins/ImagesPlugin/InsertImageDialog.js +12 -11
- package/dist/patterns/LexicalEditor/plugins/ImagesPlugin/InsertImageUploadedDialogBody.d.ts +13 -6
- package/dist/patterns/LexicalEditor/plugins/ImagesPlugin/InsertImageUploadedDialogBody.js +5 -6
- package/dist/patterns/LexicalEditor/plugins/ImagesPlugin/InsertImageUriDialogBody.d.ts +9 -6
- package/dist/patterns/LexicalEditor/plugins/ImagesPlugin/InsertImageUriDialogBody.js +4 -7
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@ export interface ImageProps {
|
|
|
7
7
|
export interface Selection {
|
|
8
8
|
isAnswer: boolean;
|
|
9
9
|
show: {
|
|
10
|
-
image?: ImageProps;
|
|
10
|
+
image?: ImageProps | null;
|
|
11
11
|
text: string;
|
|
12
12
|
};
|
|
13
13
|
value: string;
|
|
@@ -31,7 +31,7 @@ export declare class ProblemSelectNode extends DecoratorNode<ReactNode> {
|
|
|
31
31
|
static getType(): string;
|
|
32
32
|
getSelections(): Selection[];
|
|
33
33
|
getSelected(): string[];
|
|
34
|
-
|
|
34
|
+
setSelections(selections: Selection[]): void;
|
|
35
35
|
setSelected(selected: string[]): void;
|
|
36
36
|
static clone(node: ProblemSelectNode): ProblemSelectNode;
|
|
37
37
|
constructor(selections: Selection[], selected: string[], hasMultipleAnswers?: boolean, key?: NodeKey);
|
|
@@ -12,7 +12,7 @@ export default function SelectBox(props) {
|
|
|
12
12
|
` })) : (index) })), _jsxs(Content, { children: [image && (_jsx("img", { src: image.src, alt: image.altText, css: css `
|
|
13
13
|
height: auto;
|
|
14
14
|
// 이미지로 인해 좌우로 스크롤이 생기는 것을 방지
|
|
15
|
-
max-width:
|
|
15
|
+
max-width: 100%;
|
|
16
16
|
width: fit-content;
|
|
17
17
|
border-radius: 6px;
|
|
18
18
|
` })), text] }), isAnswer && (_jsx(CheckboxCircleFillIcon, { color: theme.color.foreground.success, css: css `
|
|
@@ -45,10 +45,7 @@ export function SelectComponent(props) {
|
|
|
45
45
|
if (!$isProblemSelectNode(node)) {
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
const index = newSelected.indexOf(selection.value);
|
|
50
|
-
newSelected.splice(index, 1);
|
|
51
|
-
node.setSelected(newSelected);
|
|
48
|
+
node.setSelected(selected.filter((v) => v !== selection.value));
|
|
52
49
|
});
|
|
53
50
|
}
|
|
54
51
|
else {
|
|
@@ -57,9 +54,7 @@ export function SelectComponent(props) {
|
|
|
57
54
|
if (!$isProblemSelectNode(node)) {
|
|
58
55
|
return;
|
|
59
56
|
}
|
|
60
|
-
|
|
61
|
-
newSelected.push(selection.value);
|
|
62
|
-
node.setSelected(newSelected);
|
|
57
|
+
node.setSelected([...selected, selection.value]);
|
|
63
58
|
});
|
|
64
59
|
}
|
|
65
60
|
}, fullWidth: true }, index)))] }));
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { Selection } from "../ProblemSelectNode";
|
|
2
|
-
import { Control,
|
|
2
|
+
import { Control, UseFormWatch } from "react-hook-form";
|
|
3
3
|
export interface FormSelectionProps {
|
|
4
4
|
index: number;
|
|
5
5
|
control: Control<{
|
|
6
6
|
selections: Selection[];
|
|
7
7
|
}, any>;
|
|
8
|
-
|
|
8
|
+
watch: UseFormWatch<{
|
|
9
9
|
selections: Selection[];
|
|
10
|
-
}
|
|
11
|
-
update: UseFieldArrayUpdate<{
|
|
12
|
-
selections: Selection[];
|
|
13
|
-
}, "selections">;
|
|
10
|
+
}>;
|
|
14
11
|
rules?: any;
|
|
15
12
|
onDelete?: () => void;
|
|
16
13
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
|
|
2
2
|
/** @jsxImportSource @emotion/react */
|
|
3
3
|
import styled from "@emotion/styled";
|
|
4
|
-
import { Controller
|
|
4
|
+
import { Controller } from "react-hook-form";
|
|
5
5
|
import { css } from "@emotion/react";
|
|
6
6
|
import Input from "../../../../../components/Input";
|
|
7
7
|
import { DeleteBinLineIcon, ErrorWarningFillIcon, ImageAddFillIcon, ImageEditFillIcon, } from "../../../../../icons";
|
|
@@ -10,51 +10,43 @@ import Switch from "../../../../../components/Switch";
|
|
|
10
10
|
import { useState } from "react";
|
|
11
11
|
import { InsertImageDialog } from "./InsertImageDialog";
|
|
12
12
|
export function FormSelection(props) {
|
|
13
|
-
const { index, control,
|
|
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(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
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 }))] }))] })] }));
|
|
16
|
+
return (_jsxs(Container, { children: [_jsx(Index, { children: index + 1 }), _jsxs("div", Object.assign({ css: css `
|
|
17
|
+
display: flex;
|
|
18
|
+
flex: 1;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
gap: 4px;
|
|
21
|
+
` }, { children: [_jsx(Controller, { name: `selections.${index}.show.image`, control: control, render: ({ field: { value, onChange } }) => (_jsxs(_Fragment, { children: [_jsx(InsertImageDialog, { title: value ? "이미지 바꾸기" : "이미지 삽입하기", open: imageOpen, onClose: () => setImageOpen(false), updateImg: (props) => onChange(props), deleteButton: Boolean(value) }), value && value.src && (_jsx("img", { src: value.src, alt: value.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(Controller, { name: `selections.${index}.show.text`, control: control, rules: rules, render: ({ field: { value, onChange }, fieldState: { invalid, error }, }) => (_jsx(Input, { size: "small", color: invalid
|
|
28
|
+
? "activeDanger"
|
|
29
|
+
: inputFocused
|
|
30
|
+
? "activePrimary"
|
|
31
|
+
: "default", value: value, onChange: onChange, inputProps: {
|
|
32
|
+
onFocus: (_e) => {
|
|
33
|
+
setInputFocused(true);
|
|
34
|
+
},
|
|
35
|
+
onBlur: (_e) => {
|
|
36
|
+
setInputFocused(false);
|
|
37
|
+
},
|
|
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
|
+
flex: 1;
|
|
40
|
+
` })) })] })), _jsxs("div", Object.assign({ css: css `
|
|
41
|
+
display: flex;
|
|
42
|
+
height: 36px;
|
|
43
|
+
gap: 8px;
|
|
44
|
+
align-items: center;
|
|
45
|
+
` }, { children: [_jsx(SquareButton, { color: "icon", size: "xsmall", icon: watch(`selections.${index}.show.image`) ? (_jsx(ImageEditFillIcon, {})) : (_jsx(ImageAddFillIcon, {})), onClick: () => {
|
|
46
|
+
setImageOpen(true);
|
|
47
|
+
} }), _jsx(Controller, { name: `selections.${index}.isAnswer`, control: control, render: ({ field: { value, onChange } }) => (_jsxs(Answer, Object.assign({ onClick: () => {
|
|
48
|
+
onChange(!value);
|
|
49
|
+
} }, { children: ["\uC815\uB2F5", _jsx(Switch, { checked: value, size: "small" })] }))) }), onDelete && (_jsx(SquareButton, { color: "white", size: "xsmall", icon: _jsx(DeleteBinLineIcon, {}), onClick: onDelete }))] }))] }));
|
|
58
50
|
}
|
|
59
51
|
const Container = styled.div(({ theme }) => css `
|
|
60
52
|
display: flex;
|
package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageDialog.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export interface InsertImageDialogProps {
|
|
|
3
3
|
title: string;
|
|
4
4
|
open: boolean;
|
|
5
5
|
onClose: () => void;
|
|
6
|
-
updateImg: (props: ImageProps) => void;
|
|
6
|
+
updateImg: (props: ImageProps | null) => void;
|
|
7
7
|
/** 전달하면 "이미지 삭제하기" 버튼이 생깁니다. */
|
|
8
|
-
|
|
8
|
+
deleteButton?: boolean;
|
|
9
9
|
}
|
|
10
10
|
export declare function InsertImageDialog(props: InsertImageDialogProps): import("@emotion/react/jsx-runtime").JSX.Element;
|
package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageDialog.js
CHANGED
|
@@ -18,25 +18,30 @@ import Button from "../../../../../components/Button";
|
|
|
18
18
|
import { CodleDesignSystemContext } from "../../../../../CodleDesignSystemProvider";
|
|
19
19
|
import { InsertImageUriDialogBody } from "./InsertImageUriDialogBody";
|
|
20
20
|
import { InsertImageUploadedDialogBody } from "./InsertImageUploadedDialogBody";
|
|
21
|
+
import { useForm } from "react-hook-form";
|
|
21
22
|
export function InsertImageDialog(props) {
|
|
22
|
-
const { title, open, onClose, updateImg,
|
|
23
|
+
const { title, open, onClose, updateImg, deleteButton } = props;
|
|
23
24
|
const theme = useTheme();
|
|
24
25
|
const [mode, setMode] = useState(null);
|
|
25
26
|
const inputRef = useRef(null);
|
|
26
27
|
const cdsContext = useContext(CodleDesignSystemContext);
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
updateImg(props);
|
|
31
|
-
handleOnClose();
|
|
32
|
-
};
|
|
28
|
+
const { control, setValue, watch, reset, handleSubmit } = useForm({
|
|
29
|
+
defaultValues: { src: "", altText: "" },
|
|
30
|
+
});
|
|
33
31
|
const handleOnClose = () => {
|
|
34
32
|
setMode(null);
|
|
35
|
-
|
|
36
|
-
setAltText("");
|
|
33
|
+
reset();
|
|
37
34
|
onClose();
|
|
38
35
|
};
|
|
39
|
-
|
|
36
|
+
const onSubmit = (data) => {
|
|
37
|
+
updateImg(data);
|
|
38
|
+
handleOnClose();
|
|
39
|
+
};
|
|
40
|
+
return (_jsxs(StyledAlertDialog, Object.assign({ component: "form", icon: _jsx(ImageFillIcon, { color: theme.color.background.primary }), open: open, onClose: handleOnClose, onSubmit: (e) => {
|
|
41
|
+
// nested form 구조라서 submit이벤트 전파를 막습니다.
|
|
42
|
+
e.stopPropagation();
|
|
43
|
+
handleSubmit(onSubmit)();
|
|
44
|
+
}, disableIconPadding: true }, { children: [_jsx(StyledAlertDialogTitle, Object.assign({ onClose: handleOnClose }, { children: title })), !mode && (_jsx(AlertDialogContent, { children: _jsxs("div", Object.assign({ css: css `
|
|
40
45
|
display: flex;
|
|
41
46
|
flex-direction: column;
|
|
42
47
|
gap: 16px;
|
|
@@ -52,10 +57,13 @@ export function InsertImageDialog(props) {
|
|
|
52
57
|
return;
|
|
53
58
|
const uploadByFile = (_b = cdsContext.lexical) === null || _b === void 0 ? void 0 : _b.uploadByFile;
|
|
54
59
|
if (uploadByFile) {
|
|
55
|
-
|
|
60
|
+
setValue("src", yield uploadByFile(file));
|
|
56
61
|
setMode("file");
|
|
57
62
|
}
|
|
58
|
-
}) })] })] }),
|
|
63
|
+
}) })] })] }), deleteButton && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(Button, { color: "textDanger", size: "medium", fullWidth: true, label: "\uC774\uBBF8\uC9C0 \uC0AD\uC81C\uD558\uAE30", onClick: () => {
|
|
64
|
+
updateImg(null);
|
|
65
|
+
handleOnClose();
|
|
66
|
+
} })] }))] })) })), mode === "url" && (_jsx(InsertImageUriDialogBody, { control: control, watch: watch })), mode === "file" && (_jsx(InsertImageUploadedDialogBody, { control: control, watch: watch, setValue: setValue }))] })));
|
|
59
67
|
}
|
|
60
68
|
const StyledAlertDialog = styled(AlertDialog) `
|
|
61
69
|
gap: 16px;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { ImageProps } from "../ProblemSelectNode";
|
|
2
|
+
import { Control, UseFormSetValue, UseFormWatch } from "react-hook-form";
|
|
2
3
|
export interface InsertImageUploadedDialogBodyProps {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
setAltText: (altText: string) => void;
|
|
7
|
-
onClick: (props: ImageProps) => void;
|
|
4
|
+
control: Control<ImageProps, any>;
|
|
5
|
+
watch: UseFormWatch<ImageProps>;
|
|
6
|
+
setValue: UseFormSetValue<ImageProps>;
|
|
8
7
|
}
|
|
9
8
|
export declare function InsertImageUploadedDialogBody(props: InsertImageUploadedDialogBodyProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -15,11 +15,12 @@ import { AlertDialogActions, AlertDialogContent, } from "../../../../../componen
|
|
|
15
15
|
import Button from "../../../../../components/Button";
|
|
16
16
|
import { RefreshLineIcon } from "../../../../../icons";
|
|
17
17
|
import Input from "../../../../../components/Input";
|
|
18
|
+
import { Controller, } from "react-hook-form";
|
|
18
19
|
export function InsertImageUploadedDialogBody(props) {
|
|
19
|
-
const {
|
|
20
|
+
const { control, watch, setValue } = props;
|
|
20
21
|
const inputRef = useRef(null);
|
|
21
22
|
const cdsContext = useContext(CodleDesignSystemContext);
|
|
22
|
-
const isDisabled = src === "";
|
|
23
|
+
const isDisabled = watch("src") === "";
|
|
23
24
|
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
25
|
var _a;
|
|
25
26
|
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click();
|
|
@@ -30,11 +31,9 @@ export function InsertImageUploadedDialogBody(props) {
|
|
|
30
31
|
return;
|
|
31
32
|
const uploadByFile = (_b = cdsContext.lexical) === null || _b === void 0 ? void 0 : _b.uploadByFile;
|
|
32
33
|
if (uploadByFile) {
|
|
33
|
-
|
|
34
|
+
setValue("src", yield uploadByFile(file));
|
|
34
35
|
}
|
|
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: (
|
|
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 }) }) })] }));
|
|
36
|
+
}) }), _jsxs(ImagePreview, { children: ["\uC774\uBBF8\uC9C0 \uBBF8\uB9AC\uBCF4\uAE30", _jsx("img", { src: watch("src"), alt: watch("altText") })] }), _jsx(Controller, { name: "altText", control: control, render: ({ field: { value, onChange } }) => (_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: onChange, value: value })) })] }) }), _jsx(AlertDialogActions, { children: _jsx(Button, { type: "submit", fullWidth: true, label: "\uC0BD\uC785\uD558\uAE30", size: "medium", color: "primary", disabled: isDisabled }) })] }));
|
|
38
37
|
}
|
|
39
38
|
const Inputs = styled.div `
|
|
40
39
|
display: flex;
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { ImageProps } from "../ProblemSelectNode";
|
|
2
|
+
import { Control, UseFormWatch } from "react-hook-form";
|
|
2
3
|
export interface InsertImageUriDialogBodyProps {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
altText: string;
|
|
6
|
-
setAltText: (altText: string) => void;
|
|
7
|
-
onClick: (props: ImageProps) => void;
|
|
4
|
+
control: Control<ImageProps, any>;
|
|
5
|
+
watch: UseFormWatch<ImageProps>;
|
|
8
6
|
}
|
|
9
7
|
export declare function InsertImageUriDialogBody(props: InsertImageUriDialogBodyProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/InsertImageUriDialogBody.js
CHANGED
|
@@ -4,14 +4,11 @@ import { AlertDialogActions, AlertDialogContent, } from "../../../../../componen
|
|
|
4
4
|
import Input from "../../../../../components/Input";
|
|
5
5
|
import { LinkIcon } from "../../../../../icons";
|
|
6
6
|
import Button from "../../../../../components/Button";
|
|
7
|
+
import { Controller } from "react-hook-form";
|
|
7
8
|
export function InsertImageUriDialogBody(props) {
|
|
8
|
-
const {
|
|
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: (
|
|
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 }) }) })] }));
|
|
9
|
+
const { control, watch } = props;
|
|
10
|
+
const isDisabled = watch("src") === "";
|
|
11
|
+
return (_jsxs(_Fragment, { children: [" ", _jsx(AlertDialogContent, { children: _jsxs(Inputs, { children: [_jsx(Controller, { name: "src", control: control, render: ({ field: { value, onChange } }) => (_jsx(Input, { fullWidth: true, label: "URL", placeholder: "https://www.pexels.com/photo/n-2848492/", color: "default", size: "medium", onChange: onChange, value: value, startIcon: _jsx(LinkIcon, {}) })) }), _jsx(Controller, { name: "altText", control: control, render: ({ field: { value, onChange } }) => (_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: onChange, value: value })) })] }) }), _jsx(AlertDialogActions, { children: _jsx(Button, { type: "submit", fullWidth: true, label: "\uC0BD\uC785\uD558\uAE30", size: "medium", color: "primary", disabled: isDisabled }) })] }));
|
|
15
12
|
}
|
|
16
13
|
const Inputs = styled.div `
|
|
17
14
|
display: flex;
|
|
@@ -16,13 +16,22 @@ export default function SettingForm(props) {
|
|
|
16
16
|
const { selections, nodeKey, onClose } = props;
|
|
17
17
|
const [editor] = useLexicalComposerContext();
|
|
18
18
|
const [tooltipOpen, setTooltipOpen] = useState(false);
|
|
19
|
-
const { control, handleSubmit } = useForm({
|
|
19
|
+
const { control, handleSubmit, watch } = useForm({
|
|
20
20
|
mode: "all",
|
|
21
21
|
defaultValues: {
|
|
22
|
-
selections
|
|
22
|
+
selections: selections.map((selection) => {
|
|
23
|
+
var _a;
|
|
24
|
+
return ({
|
|
25
|
+
isAnswer: selection.isAnswer,
|
|
26
|
+
show: {
|
|
27
|
+
image: (_a = selection.show.image) !== null && _a !== void 0 ? _a : null,
|
|
28
|
+
text: selection.show.text,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}),
|
|
23
32
|
},
|
|
24
33
|
});
|
|
25
|
-
const { fields, append, remove
|
|
34
|
+
const { fields, append, remove } = useFieldArray({
|
|
26
35
|
control,
|
|
27
36
|
name: "selections",
|
|
28
37
|
keyName: "uid",
|
|
@@ -33,28 +42,30 @@ export default function SettingForm(props) {
|
|
|
33
42
|
if (!$isProblemSelectNode(node)) {
|
|
34
43
|
return;
|
|
35
44
|
}
|
|
36
|
-
node.
|
|
45
|
+
node.setSelections(data.selections);
|
|
37
46
|
});
|
|
38
47
|
onClose();
|
|
39
48
|
};
|
|
40
|
-
function validateDuplicatedSelection(
|
|
49
|
+
function validateDuplicatedSelection(index) {
|
|
50
|
+
const selections = watch("selections");
|
|
41
51
|
if (index === 0)
|
|
42
52
|
return true;
|
|
43
|
-
const duplicatedIndex =
|
|
53
|
+
const duplicatedIndex = selections
|
|
44
54
|
.slice(0, index)
|
|
45
|
-
.findIndex((
|
|
55
|
+
.findIndex((selection) => selection.show.text === selections[index].show.text);
|
|
46
56
|
if (duplicatedIndex < 0)
|
|
47
57
|
return true;
|
|
48
58
|
return `${duplicatedIndex + 1}번 선택지와 같은 내용입니다.`;
|
|
49
59
|
}
|
|
50
|
-
const
|
|
51
|
-
const
|
|
60
|
+
const answersCount = watch("selections").filter((selection) => selection.isAnswer).length;
|
|
61
|
+
const hasMultipleAnswers = answersCount > 1;
|
|
62
|
+
const hasAnswer = answersCount > 0;
|
|
52
63
|
return (_jsxs(Form, Object.assign({ onSubmit: handleSubmit(onSettingSubmit) }, { children: [_jsxs(Title, { children: [_jsx(ListRadioIcon, { css: css `
|
|
53
64
|
width: 12px;
|
|
54
65
|
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,
|
|
66
|
+
` }), "\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: {
|
|
56
67
|
required: "필수 입력 항목입니다.",
|
|
57
|
-
validate: () => validateDuplicatedSelection(
|
|
68
|
+
validate: () => validateDuplicatedSelection(index),
|
|
58
69
|
}, onDelete: index !== 0
|
|
59
70
|
? () => {
|
|
60
71
|
remove(index);
|
|
@@ -18,6 +18,7 @@ import { ImageFillIcon, LinkIcon, UploadLineIcon } from "../../../../icons";
|
|
|
18
18
|
import Button from "../../../../components/Button";
|
|
19
19
|
import { useTheme } from "@emotion/react";
|
|
20
20
|
import { CodleDesignSystemContext } from "../../../../CodleDesignSystemProvider";
|
|
21
|
+
import { useForm } from "react-hook-form";
|
|
21
22
|
export function InsertImageDialog(props) {
|
|
22
23
|
const { open, activeEditor, onClose } = props;
|
|
23
24
|
const theme = useTheme();
|
|
@@ -25,8 +26,13 @@ export function InsertImageDialog(props) {
|
|
|
25
26
|
const hasModifier = useRef(false);
|
|
26
27
|
const inputRef = useRef(null);
|
|
27
28
|
const cdsContext = useContext(CodleDesignSystemContext);
|
|
28
|
-
const
|
|
29
|
-
|
|
29
|
+
const { control, setValue, watch, reset, handleSubmit } = useForm({
|
|
30
|
+
defaultValues: { src: "", altText: "" },
|
|
31
|
+
});
|
|
32
|
+
const onSubmit = (data) => {
|
|
33
|
+
activeEditor.dispatchCommand(INSERT_IMAGE_COMMAND, data);
|
|
34
|
+
handleOnClose();
|
|
35
|
+
};
|
|
30
36
|
useEffect(() => {
|
|
31
37
|
hasModifier.current = false;
|
|
32
38
|
const handler = (e) => {
|
|
@@ -37,17 +43,12 @@ export function InsertImageDialog(props) {
|
|
|
37
43
|
document.removeEventListener("keydown", handler);
|
|
38
44
|
};
|
|
39
45
|
}, [activeEditor]);
|
|
40
|
-
const onClick = (payload) => {
|
|
41
|
-
activeEditor.dispatchCommand(INSERT_IMAGE_COMMAND, payload);
|
|
42
|
-
handleOnClose();
|
|
43
|
-
};
|
|
44
46
|
const handleOnClose = () => {
|
|
45
47
|
setMode(null);
|
|
46
|
-
|
|
47
|
-
setAltText("");
|
|
48
|
+
reset();
|
|
48
49
|
onClose();
|
|
49
50
|
};
|
|
50
|
-
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: "\uC774\uBBF8\uC9C0 \uC0BD\uC785\uD558\uAE30" })), !mode && (_jsx(AlertDialogContent, { 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: () => {
|
|
51
|
+
return (_jsxs(StyledAlertDialog, Object.assign({ component: "form", icon: _jsx(ImageFillIcon, { color: theme.color.background.primary }), open: open, onClose: handleOnClose, onSubmit: handleSubmit(onSubmit), disableIconPadding: true }, { children: [_jsx(StyledAlertDialogTitle, Object.assign({ onClose: handleOnClose }, { children: "\uC774\uBBF8\uC9C0 \uC0BD\uC785\uD558\uAE30" })), !mode && (_jsx(AlertDialogContent, { 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: () => {
|
|
51
52
|
var _a;
|
|
52
53
|
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click();
|
|
53
54
|
} }), _jsx(HiddenInput, { ref: inputRef, type: "file", accept: "image/*", onChange: (event) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -57,10 +58,10 @@ export function InsertImageDialog(props) {
|
|
|
57
58
|
return;
|
|
58
59
|
const uploadByFile = (_b = cdsContext.lexical) === null || _b === void 0 ? void 0 : _b.uploadByFile;
|
|
59
60
|
if (uploadByFile) {
|
|
60
|
-
|
|
61
|
+
setValue("src", yield uploadByFile(file));
|
|
61
62
|
setMode("file");
|
|
62
63
|
}
|
|
63
|
-
}) })] })] }) })), mode === "url" && (_jsx(InsertImageUriDialogBody, {
|
|
64
|
+
}) })] })] }) })), mode === "url" && (_jsx(InsertImageUriDialogBody, { control: control, watch: watch })), mode === "file" && (_jsx(InsertImageUploadedDialogBody, { control: control, watch: watch, setValue: setValue }))] })));
|
|
64
65
|
}
|
|
65
66
|
const StyledAlertDialog = styled(AlertDialog) `
|
|
66
67
|
gap: 16px;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Control, UseFormSetValue, UseFormWatch } from "react-hook-form";
|
|
2
2
|
export interface InsertImageUploadedDialogBodyProps {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
control: Control<{
|
|
4
|
+
src: string;
|
|
5
|
+
altText: string;
|
|
6
|
+
}, any>;
|
|
7
|
+
watch: UseFormWatch<{
|
|
8
|
+
src: string;
|
|
9
|
+
altText: string;
|
|
10
|
+
}>;
|
|
11
|
+
setValue: UseFormSetValue<{
|
|
12
|
+
src: string;
|
|
13
|
+
altText: string;
|
|
14
|
+
}>;
|
|
8
15
|
}
|
|
9
16
|
export declare function InsertImageUploadedDialogBody(props: InsertImageUploadedDialogBodyProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -15,11 +15,12 @@ import { AlertDialogContent, AlertDialogActions, } from "../../../../components/
|
|
|
15
15
|
import Button from "../../../../components/Button";
|
|
16
16
|
import Input from "../../../../components/Input";
|
|
17
17
|
import { RefreshLineIcon } from "../../../../icons";
|
|
18
|
+
import { Controller, } from "react-hook-form";
|
|
18
19
|
export function InsertImageUploadedDialogBody(props) {
|
|
19
|
-
const {
|
|
20
|
+
const { control, watch, setValue } = props;
|
|
20
21
|
const inputRef = useRef(null);
|
|
21
22
|
const cdsContext = useContext(CodleDesignSystemContext);
|
|
22
|
-
const isDisabled = src === "";
|
|
23
|
+
const isDisabled = watch("src") === "";
|
|
23
24
|
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
25
|
var _a;
|
|
25
26
|
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click();
|
|
@@ -30,11 +31,9 @@ export function InsertImageUploadedDialogBody(props) {
|
|
|
30
31
|
return;
|
|
31
32
|
const uploadByFile = (_b = cdsContext.lexical) === null || _b === void 0 ? void 0 : _b.uploadByFile;
|
|
32
33
|
if (uploadByFile) {
|
|
33
|
-
|
|
34
|
+
setValue("src", yield uploadByFile(file));
|
|
34
35
|
}
|
|
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: (
|
|
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 }) }) })] }));
|
|
36
|
+
}) }), _jsxs(ImagePreview, { children: ["\uC774\uBBF8\uC9C0 \uBBF8\uB9AC\uBCF4\uAE30", _jsx("img", { src: watch("src"), alt: watch("altText") })] }), _jsx(Controller, { name: "altText", control: control, render: ({ field: { value, onChange } }) => (_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: onChange, value: value })) })] }) }), _jsx(AlertDialogActions, { children: _jsx(Button, { type: "submit", fullWidth: true, label: "\uC0BD\uC785\uD558\uAE30", size: "medium", color: "primary", disabled: isDisabled }) })] }));
|
|
38
37
|
}
|
|
39
38
|
const Inputs = styled.div `
|
|
40
39
|
display: flex;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Control, UseFormWatch } from "react-hook-form";
|
|
2
2
|
export interface InsertImageUriDialogBodyProps {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
control: Control<{
|
|
4
|
+
src: string;
|
|
5
|
+
altText: string;
|
|
6
|
+
}, any>;
|
|
7
|
+
watch: UseFormWatch<{
|
|
8
|
+
src: string;
|
|
9
|
+
altText: string;
|
|
10
|
+
}>;
|
|
8
11
|
}
|
|
9
12
|
export declare function InsertImageUriDialogBody(props: InsertImageUriDialogBodyProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -4,14 +4,11 @@ import { AlertDialogActions, AlertDialogContent, } from "../../../../components/
|
|
|
4
4
|
import Input from "../../../../components/Input";
|
|
5
5
|
import { LinkIcon } from "../../../../icons";
|
|
6
6
|
import Button from "../../../../components/Button";
|
|
7
|
+
import { Controller } from "react-hook-form";
|
|
7
8
|
export function InsertImageUriDialogBody(props) {
|
|
8
|
-
const {
|
|
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: (
|
|
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 }) }) })] }));
|
|
9
|
+
const { control, watch } = props;
|
|
10
|
+
const isDisabled = watch("src") === "";
|
|
11
|
+
return (_jsxs(_Fragment, { children: [" ", _jsx(AlertDialogContent, { children: _jsxs(Inputs, { children: [_jsx(Controller, { name: "src", control: control, render: ({ field: { value, onChange } }) => (_jsx(Input, { fullWidth: true, label: "URL", placeholder: "https://www.pexels.com/photo/n-2848492/", color: "default", size: "medium", onChange: onChange, value: value, startIcon: _jsx(LinkIcon, {}) })) }), _jsx(Controller, { name: "altText", control: control, render: ({ field: { value, onChange } }) => (_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: onChange, value: value })) })] }) }), _jsx(AlertDialogActions, { children: _jsx(Button, { type: "submit", fullWidth: true, label: "\uC0BD\uC785\uD558\uAE30", size: "medium", color: "primary", disabled: isDisabled }) })] }));
|
|
15
12
|
}
|
|
16
13
|
const Inputs = styled.div `
|
|
17
14
|
display: flex;
|