@team-monolith/cds 1.9.0 → 1.9.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.
@@ -1,9 +1,13 @@
1
1
  import { DecoratorNode, EditorConfig, LexicalNode, NodeKey, SerializedLexicalNode, Spread } from "lexical";
2
2
  import { ReactNode } from "react";
3
+ export interface ImageProps {
4
+ src: string;
5
+ altText: string;
6
+ }
3
7
  export interface Selection {
4
8
  isAnswer: boolean;
5
9
  show: {
6
- image?: any;
10
+ image?: ImageProps;
7
11
  text: string;
8
12
  };
9
13
  value: string;
@@ -1,10 +1,9 @@
1
- /** @jsxImportSource @emotion/react */
2
- import { ImagePayload } from "../ImageNode";
1
+ import { ImageProps } from "./ProblemSelectNode";
3
2
  export interface SelectBoxProps {
4
3
  index: number;
5
4
  isSelected?: boolean;
6
5
  isAnswer?: boolean;
7
- image?: ImagePayload;
6
+ image?: ImageProps;
8
7
  text: string;
9
8
  onClick: () => void;
10
9
  fullWidth?: boolean;
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
+ /** @jsxImportSource @emotion/react */
2
3
  import styled from "@emotion/styled";
3
4
  import { css, useTheme } from "@emotion/react";
4
5
  import { CheckFillIcon, CheckboxCircleFillIcon } from "../../../../icons";
@@ -8,7 +9,13 @@ export default function SelectBox(props) {
8
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 `
9
10
  width: 12px;
10
11
  height: 12px;
11
- ` })) : (index) })), _jsx(Content, { children: text }), isAnswer && (_jsx(CheckboxCircleFillIcon, { color: theme.color.foreground.success, css: css `
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 `
12
19
  width: 16px;
13
20
  height: 16px;
14
21
  ` }))] })));
@@ -30,34 +30,32 @@ export function SelectComponent(props) {
30
30
  });
31
31
  // 학생 view
32
32
  if (!isEditable) {
33
- return (_jsx(_Fragment, { children: selections.map((selection, index) => {
34
- return (_jsx(SelectBox, { index: index + 1, isSelected: selected.includes(selection.value), text: selection.show.text, onClick: () => {
35
- const isSelected = selected.includes(selection.value);
36
- if (isSelected) {
37
- editor.update(() => {
38
- const node = $getNodeByKey(nodeKey);
39
- if (!$isProblemSelectNode(node)) {
40
- return;
41
- }
42
- const newSelected = [...selected];
43
- const index = newSelected.indexOf(selection.value);
44
- newSelected.splice(index, 1);
45
- node.setSelected(newSelected);
46
- });
47
- }
48
- else {
49
- editor.update(() => {
50
- const node = $getNodeByKey(nodeKey);
51
- if (!$isProblemSelectNode(node)) {
52
- return;
53
- }
54
- const newSelected = [...selected];
55
- newSelected.push(selection.value);
56
- node.setSelected(newSelected);
57
- });
58
- }
59
- }, fullWidth: true }, index));
60
- }) }));
33
+ return (_jsx(_Fragment, { children: fields.map((field, index) => (_jsx(SelectBox, { index: index + 1, isSelected: selected.includes(field.value), image: field.show.image, text: field.show.text, onClick: () => {
34
+ const isSelected = selected.includes(field.value);
35
+ if (isSelected) {
36
+ editor.update(() => {
37
+ const node = $getNodeByKey(nodeKey);
38
+ if (!$isProblemSelectNode(node)) {
39
+ return;
40
+ }
41
+ const newSelected = [...selected];
42
+ const index = newSelected.indexOf(field.value);
43
+ newSelected.splice(index, 1);
44
+ node.setSelected(newSelected);
45
+ });
46
+ }
47
+ else {
48
+ editor.update(() => {
49
+ const node = $getNodeByKey(nodeKey);
50
+ if (!$isProblemSelectNode(node)) {
51
+ return;
52
+ }
53
+ const newSelected = [...selected];
54
+ newSelected.push(field.value);
55
+ node.setSelected(newSelected);
56
+ });
57
+ }
58
+ }, fullWidth: true }, index))) }));
61
59
  }
62
60
  // 교사 edit view
63
61
  return (_jsxs(_Fragment, { children: [_jsxs("div", Object.assign({ css: css `
@@ -67,7 +65,7 @@ export function SelectComponent(props) {
67
65
  display: flex;
68
66
  flex-direction: column;
69
67
  gap: 4px;
70
- ` }, { children: fields.map((field, index) => (_jsx(SelectBox, { index: index + 1, isAnswer: field.isAnswer, text: field.show.text || `${index + 1}번 선택지`, onClick: () => setSettingOpen(true) }, index))) })), _jsx(SquareButton, { size: "small", color: "icon", icon: _jsx(Settings3FillIcon, {}), onClick: () => {
68
+ ` }, { children: fields.map((field, index) => (_jsx(SelectBox, { index: index + 1, isAnswer: field.isAnswer, image: field.show.image, text: field.show.text || `${index + 1}번 선택지`, onClick: () => setSettingOpen(true) }, index))) })), _jsx(SquareButton, { size: "small", color: "icon", icon: _jsx(Settings3FillIcon, {}), onClick: () => {
71
69
  setSettingOpen(true);
72
70
  } })] })), settingOpen && (_jsx(SettingForm, { control: control, handleSubmit: handleSubmit, fields: fields, append: append, remove: remove, update: update, nodeKey: nodeKey, onClose: () => setSettingOpen(false) }))] }));
73
71
  }
@@ -1,34 +1,63 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } 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";
5
5
  import { css } from "@emotion/react";
6
6
  import Input from "../../../../../components/Input";
7
- import { DeleteBinLineIcon, ErrorWarningFillIcon, ImageAddFillIcon, } from "../../../../../icons";
7
+ import { DeleteBinLineIcon, ErrorWarningFillIcon, ImageAddFillIcon, ImageEditFillIcon, } from "../../../../../icons";
8
8
  import SquareButton from "../../../../../components/SquareButton";
9
9
  import Switch from "../../../../../components/Switch";
10
+ import { useState } from "react";
11
+ import { InsertImageDialog } from "./InsertImageDialog";
10
12
  export function FormSelection(props) {
11
13
  const { index, control, field, update, rules, onDelete } = props;
12
- return (_jsxs(Container, { children: [_jsx(Index, { children: index + 1 }), _jsx(Controller, { name: `selections.${index}.show.text`, control: control, rules: rules, render: ({ field: { value, onChange }, fieldState: { invalid, error }, }) => (_jsx(Input, { size: "small", color: invalid ? "activeDanger" : "default", value: value, onChange: onChange, inputProps: {
13
- onBlur: (_e) => {
14
- // onBlur시에 선택지 미리보기에 반영합니다.
15
- update(index, Object.assign(Object.assign({}, field), { show: Object.assign(Object.assign({}, field.show), { text: value }) }));
16
- },
17
- }, placeholder: `${index + 1}번 선택지`, hintIcon: invalid ? _jsx(ErrorWarningFillIcon, {}) : undefined, hintText: error === null || error === void 0 ? void 0 : error.message, multiline: true, fullWidth: true, css: css `
18
- flex: 1;
19
- ` })) }), _jsx(SquareButton, { color: "icon", size: "xsmall", icon: _jsx(ImageAddFillIcon, {}), onClick: () => {
20
- // TODO: 이미지 추가
21
- } }), _jsx(Controller, { name: `selections.${index}.isAnswer`, control: control, render: ({ field: { value, onChange } }) => (_jsxs(Answer, Object.assign({ onClick: () => {
22
- onChange(!value);
23
- // 선택지 미리보기에 정답여부를 반영합니다.
24
- update(index, Object.assign(Object.assign({}, field), { isAnswer: !value }));
25
- } }, { children: ["\uC815\uB2F5", _jsx(Switch, { checked: value, size: "small" })] }))) }), onDelete && (_jsx(SquareButton, { color: "white", size: "xsmall", icon: _jsx(DeleteBinLineIcon, {}), onClick: onDelete }))] }));
14
+ const [imageOpen, setImageOpen] = useState(false);
15
+ const [inputFocused, setInputFocused] = useState(false);
16
+ return (_jsxs(_Fragment, { children: [_jsx(InsertImageDialog, { 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
+ } }), _jsxs(Container, { children: [_jsx(Index, { children: index + 1 }), _jsxs("div", Object.assign({ css: css `
19
+ display: flex;
20
+ flex: 1;
21
+ flex-direction: column;
22
+ gap: 4px;
23
+ ` }, { children: [field.show.image && field.show.image.src && (_jsx("img", { src: field.show.image.src, alt: field.show.image.altText, css: css `
24
+ height: auto;
25
+ // 이미지로 인해 좌우로 스크롤이 생기는 것을 방지
26
+ max-width: min(400px, 100%);
27
+ width: fit-content;
28
+ border-radius: 6px;
29
+ `, 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
30
+ ? "activeDanger"
31
+ : inputFocused
32
+ ? "activePrimary"
33
+ : "default", value: value, onChange: onChange, inputProps: {
34
+ onFocus: (_e) => {
35
+ setInputFocused(true);
36
+ },
37
+ onBlur: (_e) => {
38
+ setInputFocused(false);
39
+ // onBlur시에 선택지 미리보기에 반영합니다.
40
+ update(index, Object.assign(Object.assign({}, field), { show: Object.assign(Object.assign({}, field.show), { text: value }) }));
41
+ },
42
+ }, placeholder: `${index + 1}번 선택지`, hintIcon: invalid ? _jsx(ErrorWarningFillIcon, {}) : undefined, hintText: error === null || error === void 0 ? void 0 : error.message, multiline: true, fullWidth: true, css: css `
43
+ flex: 1;
44
+ ` })) })] })), _jsxs("div", Object.assign({ css: css `
45
+ display: flex;
46
+ height: 36px;
47
+ gap: 8px;
48
+ align-items: center;
49
+ ` }, { children: [_jsx(SquareButton, { color: "icon", size: "xsmall", icon: field.show.image ? _jsx(ImageEditFillIcon, {}) : _jsx(ImageAddFillIcon, {}), onClick: () => {
50
+ setImageOpen(true);
51
+ } }), _jsx(Controller, { name: `selections.${index}.isAnswer`, control: control, render: ({ field: { value, onChange } }) => (_jsxs(Answer, Object.assign({ onClick: () => {
52
+ onChange(!value);
53
+ // 선택지 미리보기에 정답여부를 반영합니다.
54
+ update(index, Object.assign(Object.assign({}, field), { isAnswer: !value }));
55
+ } }, { children: ["\uC815\uB2F5", _jsx(Switch, { checked: value, size: "small" })] }))) }), onDelete && (_jsx(SquareButton, { color: "white", size: "xsmall", icon: _jsx(DeleteBinLineIcon, {}), onClick: onDelete }))] }))] })] }));
26
56
  }
27
57
  const Container = styled.div(({ theme }) => css `
28
58
  display: flex;
29
59
  padding: 4px 12px;
30
60
  gap: 8px;
31
- align-items: center;
32
61
  border-radius: 8px;
33
62
  background: ${theme.color.background.neutralAlt};
34
63
  `);
@@ -38,6 +67,7 @@ const Index = styled.div(({ theme }) => css `
38
67
  width: 20px;
39
68
  height: 20px;
40
69
  padding: 4px;
70
+ margin-top: 8px;
41
71
  justify-content: center;
42
72
  align-items: center;
43
73
  border-radius: 4px;
@@ -51,6 +81,7 @@ const Index = styled.div(({ theme }) => css `
51
81
  `);
52
82
  const Answer = styled.div(({ theme }) => css `
53
83
  display: flex;
84
+ align-items: center;
54
85
  padding-right: 4px;
55
86
  gap: 8px;
56
87
  color: ${theme.color.foreground.neutralBase};
@@ -0,0 +1,7 @@
1
+ import { ImageProps } from "../ProblemSelectNode";
2
+ export interface InsertImageDialogProps {
3
+ open: boolean;
4
+ onClose: () => void;
5
+ updateImg: (props: ImageProps) => void;
6
+ }
7
+ export declare function InsertImageDialog(props: InsertImageDialogProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,96 @@
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 } from "react/jsx-runtime";
11
+ import { useContext, useRef, useState } from "react";
12
+ import styled from "@emotion/styled";
13
+ import { useTheme } from "@emotion/react";
14
+ import { ImageFillIcon, LinkIcon, UploadLineIcon } from "../../../../../icons";
15
+ import { AlertDialog, AlertDialogContent, AlertDialogTitle, } from "../../../../../components/AlertDialog";
16
+ import Button from "../../../../../components/Button";
17
+ import { CodleDesignSystemContext } from "../../../../../CodleDesignSystemProvider";
18
+ import { InsertImageUriDialogBody } from "./InsertImageUriDialogBody";
19
+ import { InsertImageUploadedDialogBody } from "./InsertImageUploadedDialogBody";
20
+ export function InsertImageDialog(props) {
21
+ const { open, onClose, updateImg } = props;
22
+ const theme = useTheme();
23
+ const [mode, setMode] = useState(null);
24
+ const inputRef = useRef(null);
25
+ const cdsContext = useContext(CodleDesignSystemContext);
26
+ const [src, setSrc] = useState("");
27
+ const [altText, setAltText] = useState("");
28
+ const onClick = (props) => {
29
+ updateImg(props);
30
+ handleOnClose();
31
+ };
32
+ const handleOnClose = () => {
33
+ setMode(null);
34
+ setSrc("");
35
+ setAltText("");
36
+ onClose();
37
+ };
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 }))] })));
52
+ }
53
+ const StyledAlertDialog = styled(AlertDialog) `
54
+ gap: 16px;
55
+ `;
56
+ const StyledAlertDialogTitle = styled(AlertDialogTitle) `
57
+ color: ${({ theme }) => theme.color.foreground.neutralBase};
58
+ text-align: center;
59
+
60
+ /* Default/Heading/20px-Bd */
61
+ font-family: ${({ theme }) => theme.fontFamily.ui};
62
+ font-size: 20px;
63
+ font-style: normal;
64
+ font-weight: 700;
65
+ line-height: 28px; /* 140% */
66
+ letter-spacing: 0.25px;
67
+ `;
68
+ const Buttons = styled.div `
69
+ display: flex;
70
+ align-items: flex-start;
71
+ gap: 8px;
72
+
73
+ // Actions가 없는 경우 하단이 디자인과 맞지 않는다
74
+ margin-bottom: -16px;
75
+ `;
76
+ const ButtonAndDescription = styled.div `
77
+ display: flex;
78
+ flex-direction: column;
79
+ align-items: center;
80
+ gap: 8px;
81
+ flex: 1 0 0;
82
+ `;
83
+ const Description = styled.div `
84
+ color: ${({ theme }) => theme.color.foreground.neutralBaseDisabled};
85
+ text-align: center;
86
+
87
+ /* Default/Label/12px-Md */
88
+ font-family: ${({ theme }) => theme.fontFamily.ui};
89
+ font-size: 12px;
90
+ font-style: normal;
91
+ font-weight: 500;
92
+ line-height: 16px; /* 133.333% */
93
+ `;
94
+ const HiddenInput = styled.input `
95
+ display: none;
96
+ `;
@@ -0,0 +1,9 @@
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;
@@ -0,0 +1,51 @@
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
+ `;
@@ -0,0 +1,9 @@
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;
@@ -0,0 +1,20 @@
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
+ `;
@@ -5,7 +5,7 @@ import { css } from "@emotion/react";
5
5
  import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
6
6
  import styled from "@emotion/styled";
7
7
  import shadows from "../../../../../foundation/shadows";
8
- import { AddFillIcon, ListRadioIcon } from "../../../../../icons";
8
+ import { AddFillIcon, AlarmWarningFillIcon, ListRadioIcon, } from "../../../../../icons";
9
9
  import Button from "../../../../../components/Button";
10
10
  import { FormSelection } from "./FormSelection";
11
11
  export default function SettingForm(props) {
@@ -31,6 +31,7 @@ export default function SettingForm(props) {
31
31
  return true;
32
32
  return `${duplicatedIndex + 1}번 선택지와 같은 내용입니다.`;
33
33
  }
34
+ const hasMultipleAnswers = fields.filter((field) => field.isAnswer).length > 1;
34
35
  return (_jsxs(Form, Object.assign({ onSubmit: handleSubmit(onSettingSubmit) }, { children: [_jsxs(Title, { children: [_jsx(ListRadioIcon, { css: css `
35
36
  width: 12px;
36
37
  height: 12px;
@@ -49,7 +50,10 @@ export default function SettingForm(props) {
49
50
  },
50
51
  value: (fields.length + 1).toString(),
51
52
  });
52
- } })] }), _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" })] })] })));
53
+ } }), hasMultipleAnswers && (_jsxs(Alert, { children: [_jsx(AlarmWarningFillIcon, { css: css `
54
+ width: 14px;
55
+ 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" })] })] })));
53
57
  }
54
58
  const Form = styled.form(({ theme }) => css `
55
59
  display: flex;
@@ -102,3 +106,14 @@ const Buttons = styled.div `
102
106
  align-items: center;
103
107
  gap: 8px;
104
108
  `;
109
+ const Alert = styled.div(({ theme }) => css `
110
+ display: flex;
111
+ gap: 4px;
112
+ color: ${theme.color.foreground.neutralBaseDisabled};
113
+ /* Default/Label/12px-Md */
114
+ font-family: ${theme.fontFamily.ui};
115
+ font-size: 12px;
116
+ font-style: normal;
117
+ font-weight: 500;
118
+ line-height: 16px; /* 133.333% */
119
+ `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-monolith/cds",
3
- "version": "1.9.0",
3
+ "version": "1.9.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "sideEffects": false,