@team-monolith/cds 1.9.6 → 1.9.8

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.
@@ -38,19 +38,19 @@ export function InputComponent(props) {
38
38
  return (_jsx(Input, { size: "small", placeholder: placeholder || "여기에 입력하세요.", value: answerInput, color: "default", fullWidth: true, inputProps: { readOnly: true } }));
39
39
  }
40
40
  else {
41
- return (_jsx(Input, { size: "small", placeholder: placeholder || "여기에 입력하세요.", value: answerInput, onChange: (e) => setAnswerInput(e.target.value),
42
- // 한글 입력시에 onChange마다 update가 일어나는 것을 방지하기 위해 입력 완료후 onBlur시에 update하는 전략을 사용합니다.
43
- // 이를 위해 answerInput을 state로 관리합니다.
44
- inputProps: {
45
- onBlur: (_e) => {
46
- editor.update(() => {
47
- const node = $getNodeByKey(nodeKey);
48
- if (!$isProblemInputNode(node)) {
49
- return;
50
- }
51
- node.setAnswer(answerInput);
52
- });
53
- },
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);
47
+ editor.update(() => {
48
+ const node = $getNodeByKey(nodeKey);
49
+ if (!$isProblemInputNode(node)) {
50
+ return;
51
+ }
52
+ node.setAnswer(e.target.value);
53
+ });
54
54
  }, color: "default", fullWidth: true }));
55
55
  }
56
56
  }
@@ -13,9 +13,13 @@ export function FormSelection(props) {
13
13
  const { index, control, field, update, rules, onDelete } = props;
14
14
  const [imageOpen, setImageOpen] = useState(false);
15
15
  const [inputFocused, setInputFocused] = useState(false);
16
- return (_jsxs(_Fragment, { children: [_jsx(InsertImageDialog, { open: imageOpen, onClose: () => setImageOpen(false), updateImg: (props) => {
16
+ return (_jsxs(_Fragment, { children: [_jsx(InsertImageDialog, { title: field.show.image ? "이미지 바꾸기" : "이미지 삽입하기", open: imageOpen, onClose: () => setImageOpen(false), updateImg: (props) => {
17
17
  update(index, Object.assign(Object.assign({}, field), { show: Object.assign(Object.assign({}, field.show), { image: props }) }));
18
- } }), _jsxs(Container, { children: [_jsx(Index, { children: index + 1 }), _jsxs("div", Object.assign({ css: css `
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 `
19
23
  display: flex;
20
24
  flex: 1;
21
25
  flex-direction: column;
@@ -1,7 +1,10 @@
1
1
  import { ImageProps } from "../ProblemSelectNode";
2
2
  export interface InsertImageDialogProps {
3
+ title: string;
3
4
  open: boolean;
4
5
  onClose: () => void;
5
6
  updateImg: (props: ImageProps) => void;
7
+ /** 전달하면 "이미지 삭제하기" 버튼이 생깁니다. */
8
+ deleteImg?: () => void;
6
9
  }
7
- export declare function InsertImageDialog(props: InsertImageDialogProps): import("react/jsx-runtime").JSX.Element;
10
+ export declare function InsertImageDialog(props: InsertImageDialogProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -7,10 +7,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/react/jsx-runtime";
11
+ /** @jsxImportSource @emotion/react */
11
12
  import { useContext, useRef, useState } from "react";
12
13
  import styled from "@emotion/styled";
13
- import { useTheme } from "@emotion/react";
14
+ import { css, useTheme } from "@emotion/react";
14
15
  import { ImageFillIcon, LinkIcon, UploadLineIcon } from "../../../../../icons";
15
16
  import { AlertDialog, AlertDialogContent, AlertDialogTitle, } from "../../../../../components/AlertDialog";
16
17
  import Button from "../../../../../components/Button";
@@ -18,7 +19,7 @@ import { CodleDesignSystemContext } from "../../../../../CodleDesignSystemProvid
18
19
  import { InsertImageUriDialogBody } from "./InsertImageUriDialogBody";
19
20
  import { InsertImageUploadedDialogBody } from "./InsertImageUploadedDialogBody";
20
21
  export function InsertImageDialog(props) {
21
- const { open, onClose, updateImg } = props;
22
+ const { title, open, onClose, updateImg, deleteImg } = props;
22
23
  const theme = useTheme();
23
24
  const [mode, setMode] = useState(null);
24
25
  const inputRef = useRef(null);
@@ -35,20 +36,26 @@ export function InsertImageDialog(props) {
35
36
  setAltText("");
36
37
  onClose();
37
38
  };
38
- 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: () => {
39
- var _a;
40
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click();
41
- } }), _jsx(HiddenInput, { ref: inputRef, type: "file", accept: "image/*", onChange: (event) => __awaiter(this, void 0, void 0, function* () {
42
- var _a, _b;
43
- const file = (_a = event.target.files) === null || _a === void 0 ? void 0 : _a[0];
44
- if (!file)
45
- return;
46
- const uploadByFile = (_b = cdsContext.lexical) === null || _b === void 0 ? void 0 : _b.uploadByFile;
47
- if (uploadByFile) {
48
- setSrc(yield uploadByFile(file));
49
- setMode("file");
50
- }
51
- }) })] })] }) })), 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 }))] })));
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 }))] })));
52
59
  }
53
60
  const StyledAlertDialog = styled(AlertDialog) `
54
61
  gap: 16px;
@@ -67,12 +74,15 @@ const StyledAlertDialogTitle = styled(AlertDialogTitle) `
67
74
  `;
68
75
  const Buttons = styled.div `
69
76
  display: flex;
77
+ flex: 1;
70
78
  align-items: flex-start;
71
79
  gap: 8px;
72
-
73
- // Actions가 없는 경우 하단이 디자인과 맞지 않는다
74
- margin-bottom: -16px;
75
80
  `;
81
+ const Divider = styled.div(({ theme }) => css `
82
+ width: 100%;
83
+ height: 1px;
84
+ background: ${theme.color.background.neutralAltActive};
85
+ `);
76
86
  const ButtonAndDescription = styled.div `
77
87
  display: flex;
78
88
  flex-direction: column;
@@ -8,9 +8,12 @@ import shadows from "../../../../../foundation/shadows";
8
8
  import { AddFillIcon, AlarmWarningFillIcon, ListRadioIcon, } from "../../../../../icons";
9
9
  import Button from "../../../../../components/Button";
10
10
  import { FormSelection } from "./FormSelection";
11
+ import Tooltip from "../../../../../components/Tooltip";
12
+ import { useState } from "react";
11
13
  export default function SettingForm(props) {
12
14
  const { control, handleSubmit, fields, append, remove, update, nodeKey, onClose, } = props;
13
15
  const [editor] = useLexicalComposerContext();
16
+ const [tooltipOpen, setTooltipOpen] = useState(false);
14
17
  const onSettingSubmit = (data) => {
15
18
  editor.update(() => {
16
19
  const node = $getNodeByKey(nodeKey);
@@ -32,6 +35,7 @@ export default function SettingForm(props) {
32
35
  return `${duplicatedIndex + 1}번 선택지와 같은 내용입니다.`;
33
36
  }
34
37
  const hasMultipleAnswers = fields.filter((field) => field.isAnswer).length > 1;
38
+ const hasAnswer = fields.some((field) => field.isAnswer);
35
39
  return (_jsxs(Form, Object.assign({ onSubmit: handleSubmit(onSettingSubmit) }, { children: [_jsxs(Title, { children: [_jsx(ListRadioIcon, { css: css `
36
40
  width: 12px;
37
41
  height: 12px;
@@ -53,7 +57,7 @@ export default function SettingForm(props) {
53
57
  } }), hasMultipleAnswers && (_jsxs(Alert, { children: [_jsx(AlarmWarningFillIcon, { css: css `
54
58
  width: 14px;
55
59
  height: 14px;
56
- ` }), "\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(Button, { color: "primary", size: "xsmall", label: "\uC774\uB300\uB85C \uB123\uAE30", type: "submit" })] })] })));
60
+ ` }), "\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 }) }) }))] })] })));
57
61
  }
58
62
  const Form = styled.form(({ theme }) => css `
59
63
  display: flex;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-monolith/cds",
3
- "version": "1.9.6",
3
+ "version": "1.9.8",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "sideEffects": false,