@team-monolith/cds 1.57.0 → 1.58.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.
Files changed (46) hide show
  1. package/dist/patterns/LexicalEditor/components/FileSelectInput.d.ts +11 -0
  2. package/dist/patterns/LexicalEditor/components/FileSelectInput.js +40 -0
  3. package/dist/patterns/LexicalEditor/components/InsertImageDialog/ImagePreview.d.ts +7 -0
  4. package/dist/patterns/LexicalEditor/components/InsertImageDialog/ImagePreview.js +13 -0
  5. package/dist/patterns/LexicalEditor/{nodes/insertImageDialog → components/InsertImageDialog}/InsertImageDialog.d.ts +5 -2
  6. package/dist/patterns/LexicalEditor/components/InsertImageDialog/InsertImageDialog.js +64 -0
  7. package/dist/patterns/LexicalEditor/index.d.ts +0 -1
  8. package/dist/patterns/LexicalEditor/index.js +0 -1
  9. package/dist/patterns/LexicalEditor/nodes/Form/FormInput.js +16 -5
  10. package/dist/patterns/LexicalEditor/nodes/{ImageComponent.js → ImageNode/ImageComponent.js} +43 -4
  11. package/dist/patterns/LexicalEditor/nodes/{ImageNode.d.ts → ImageNode/ImageNode.d.ts} +2 -0
  12. package/dist/patterns/LexicalEditor/nodes/{ImageNode.js → ImageNode/ImageNode.js} +8 -0
  13. package/dist/patterns/LexicalEditor/nodes/ImageNode/ImageNotAvailable.d.ts +1 -0
  14. package/dist/patterns/LexicalEditor/nodes/ImageNode/ImageNotAvailable.js +4 -0
  15. package/dist/patterns/LexicalEditor/nodes/ImageNode/index.d.ts +1 -0
  16. package/dist/patterns/LexicalEditor/nodes/ImageNode/index.js +1 -0
  17. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/ProblemSelectNode.d.ts +1 -1
  18. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectBox/SelectBoxComponent.d.ts +1 -1
  19. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectBox/SelectBoxEdit.d.ts +1 -1
  20. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectBox/SelectBoxView.d.ts +1 -1
  21. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/FormSelection.js +7 -2
  22. package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/SelectComponent/SelectBox/SelectBoxComponent.d.ts +1 -1
  23. package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/SelectComponent/SelectBox/SelectBoxEdit.d.ts +1 -1
  24. package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/SelectComponent/SelectBox/SelectBoxView.d.ts +1 -1
  25. package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/SelectComponent/SettingForm/FormSelection.js +7 -2
  26. package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/SheetSelectNode.d.ts +1 -1
  27. package/dist/patterns/LexicalEditor/plugins/ComponentAdderPlugin/ComponentAdderPlugin.js +5 -2
  28. package/dist/patterns/LexicalEditor/plugins/ComponentPickerMenuPlugin/ComponentPickerMenuPlugin.js +5 -2
  29. package/dist/patterns/LexicalEditor/plugins/ImagesPlugin/index.d.ts +1 -1
  30. package/dist/patterns/LexicalEditor/plugins/ImagesPlugin/index.js +1 -1
  31. package/dist/patterns/LexicalEditor/plugins/MarkdownTransformers/index.js +1 -1
  32. package/package.json +1 -1
  33. package/dist/patterns/LexicalEditor/nodes/insertImageDialog/InsertImageDialog.js +0 -114
  34. package/dist/patterns/LexicalEditor/nodes/insertImageDialog/InsertImageUploadedDialogBody.d.ts +0 -8
  35. package/dist/patterns/LexicalEditor/nodes/insertImageDialog/InsertImageUploadedDialogBody.js +0 -50
  36. package/dist/patterns/LexicalEditor/nodes/insertImageDialog/InsertImageUriDialogBody.d.ts +0 -7
  37. package/dist/patterns/LexicalEditor/nodes/insertImageDialog/InsertImageUriDialogBody.js +0 -17
  38. package/dist/patterns/LexicalEditor/plugins/ImagesPlugin/InsertImageDialog.d.ts +0 -7
  39. package/dist/patterns/LexicalEditor/plugins/ImagesPlugin/InsertImageDialog.js +0 -109
  40. package/dist/patterns/LexicalEditor/plugins/ImagesPlugin/InsertImageUploadedDialogBody.d.ts +0 -16
  41. package/dist/patterns/LexicalEditor/plugins/ImagesPlugin/InsertImageUploadedDialogBody.js +0 -50
  42. package/dist/patterns/LexicalEditor/plugins/ImagesPlugin/InsertImageUriDialogBody.d.ts +0 -12
  43. package/dist/patterns/LexicalEditor/plugins/ImagesPlugin/InsertImageUriDialogBody.js +0 -17
  44. /package/dist/patterns/LexicalEditor/{nodes/insertImageDialog → components/InsertImageDialog}/index.d.ts +0 -0
  45. /package/dist/patterns/LexicalEditor/{nodes/insertImageDialog → components/InsertImageDialog}/index.js +0 -0
  46. /package/dist/patterns/LexicalEditor/nodes/{ImageComponent.d.ts → ImageNode/ImageComponent.d.ts} +0 -0
@@ -0,0 +1,11 @@
1
+ interface FileSelectInputProps {
2
+ accept?: string;
3
+ onChange: (value: string) => void;
4
+ }
5
+ /**
6
+ * 파일 탐색기를 열어 특정 파일을 업로드 한 후, 그 경로를 onChange로 전달합니다.
7
+ * @param props
8
+ * @returns
9
+ */
10
+ export declare function FileSelectInput(props: FileSelectInputProps): import("react/jsx-runtime").JSX.Element;
11
+ export {};
@@ -0,0 +1,40 @@
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, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
11
+ import { useContext, useRef } from "react";
12
+ import { Button, CodleDesignSystemContext } from "../../..";
13
+ import { UploadLineIcon } from "../../../icons";
14
+ import styled from "@emotion/styled";
15
+ /**
16
+ * 파일 탐색기를 열어 특정 파일을 업로드 한 후, 그 경로를 onChange로 전달합니다.
17
+ * @param props
18
+ * @returns
19
+ */
20
+ export function FileSelectInput(props) {
21
+ const { onChange, accept } = props;
22
+ const inputRef = useRef(null);
23
+ const cdsContext = useContext(CodleDesignSystemContext);
24
+ return (_jsxs(_Fragment, { children: [_jsx(Button, { fullWidth: true, color: "grey", size: "medium", label: "\uD30C\uC77C \uC120\uD0DD\uD558\uAE30", onClick: () => {
25
+ var _a;
26
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click();
27
+ }, startIcon: _jsx(UploadLineIcon, {}) }), _jsx(HiddenInput, { ref: inputRef, type: "file", accept: accept, onChange: (event) => __awaiter(this, void 0, void 0, function* () {
28
+ var _a, _b;
29
+ const file = (_a = event.target.files) === null || _a === void 0 ? void 0 : _a[0];
30
+ if (!file)
31
+ return;
32
+ const uploadByFile = (_b = cdsContext.lexical) === null || _b === void 0 ? void 0 : _b.uploadByFile;
33
+ if (uploadByFile) {
34
+ onChange(yield uploadByFile(file));
35
+ }
36
+ }) })] }));
37
+ }
38
+ const HiddenInput = styled.input `
39
+ display: none;
40
+ `;
@@ -0,0 +1,7 @@
1
+ import { ReactNode } from "react";
2
+ export interface ImagePreviewProps {
3
+ src: string;
4
+ alt: string;
5
+ fallback?: ReactNode;
6
+ }
7
+ export declare function ImagePreview(props: ImagePreviewProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import styled from "@emotion/styled";
3
+ import { useState } from "react";
4
+ export function ImagePreview(props) {
5
+ const { src, alt, fallback } = props;
6
+ const [erroredSrc, setErroredSrc] = useState(null);
7
+ return (_jsxs(Container, { children: ["\uC774\uBBF8\uC9C0 \uBBF8\uB9AC\uBCF4\uAE30", erroredSrc === src ? (fallback) : (_jsx("img", { src: src, alt: alt, onError: () => setErroredSrc(src) }))] }));
8
+ }
9
+ const Container = styled.div `
10
+ display: flex;
11
+ flex-direction: column;
12
+ gap: 8px;
13
+ `;
@@ -6,8 +6,11 @@ export interface InsertImageDialogProps {
6
6
  title: string;
7
7
  open: boolean;
8
8
  onClose: () => void;
9
- updateImg: (props: ImageProps | null) => void;
9
+ imageProps?: ImageProps;
10
+ onChange: (props: ImageProps) => void;
10
11
  /** 전달하면 "이미지 삭제하기" 버튼이 생깁니다. */
11
- deleteButton?: boolean;
12
+ onDelete?: () => void;
13
+ /** 닫을 때마다 폼을 최초 상태로 초기화합니다. */
14
+ shouldReset?: boolean;
12
15
  }
13
16
  export declare function InsertImageDialog(props: InsertImageDialogProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1,64 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
+ /** @jsxImportSource @emotion/react */
3
+ import styled from "@emotion/styled";
4
+ import { useTheme } from "@emotion/react";
5
+ import { ImageFillIcon, LinkIcon } from "../../../../icons";
6
+ import { AlertDialog, AlertDialogActions, AlertDialogContent, AlertDialogTitle, } from "../../../../components/AlertDialog";
7
+ import { useForm } from "react-hook-form";
8
+ import { FileSelectInput } from "../FileSelectInput";
9
+ import { Button } from "../../../..";
10
+ import { FormInput } from "../../nodes/Form";
11
+ import { useState } from "react";
12
+ import { ImagePreview } from "./ImagePreview";
13
+ import { ImageNotAvailable } from "../../nodes/ImageNode/ImageNotAvailable";
14
+ export function InsertImageDialog(props) {
15
+ const { title, open, onClose, imageProps, onChange, onDelete, shouldReset } = props;
16
+ const theme = useTheme();
17
+ const { control, setValue, watch, reset, handleSubmit } = useForm({
18
+ defaultValues: imageProps !== null && imageProps !== void 0 ? imageProps : { src: "", altText: "" },
19
+ });
20
+ const handleOnClose = () => {
21
+ if (shouldReset)
22
+ reset();
23
+ onClose();
24
+ };
25
+ const onSubmit = (data) => {
26
+ onChange(data);
27
+ handleOnClose();
28
+ };
29
+ // 미리보기할 src를 저장합니다. watch("src")는 너무 자주 바뀌기 때문에 사용하지 않습니다.
30
+ const [previewSrc, setPreviewSrc] = useState(watch("src"));
31
+ const isDisabled = watch("src") === "";
32
+ return (_jsxs(StyledAlertDialog, Object.assign({ component: "form", icon: _jsx(ImageFillIcon, { color: theme.color.background.primary }), open: open, onClose: handleOnClose, onSubmit: (e) => {
33
+ // nested form 구조라서 submit이벤트 전파를 막습니다.
34
+ e.stopPropagation();
35
+ handleSubmit(onSubmit)();
36
+ }, disableIconPadding: true }, { children: [_jsx(StyledAlertDialogTitle, Object.assign({ onClose: handleOnClose }, { children: title })), _jsx(AlertDialogContent, { children: _jsxs(Inputs, { children: [_jsx(FileSelectInput, { onChange: (value) => {
37
+ setValue("src", value);
38
+ setPreviewSrc(value);
39
+ }, accept: "image/*" }), _jsx(FormInput, { name: "src", control: control, placeholder: "https://www.pexels.com/photo/n-2848492", size: "medium", label: "URL", fullWidth: true, startIcon: _jsx(LinkIcon, {}), inputProps: {
40
+ onBlur: () => {
41
+ setPreviewSrc(watch("src"));
42
+ },
43
+ } }), previewSrc && (_jsx(ImagePreview, { src: previewSrc, alt: watch("altText"), fallback: _jsx(ImageNotAvailable, {}) })), _jsx(FormInput, { name: "altText", control: control, placeholder: "\uC0BD\uC785\uD558\uB294 \uC774\uBBF8\uC9C0\uC5D0 \uAD00\uD55C \uC124\uBA85", size: "medium", label: "\uB300\uCCB4 \uD14D\uC2A4\uD2B8", fullWidth: true })] }) }), _jsxs(AlertDialogActions, { children: [_jsx(Button, { type: "submit", fullWidth: true, label: "\uC0BD\uC785\uD558\uAE30", size: "medium", color: "primary", disabled: isDisabled }), onDelete && (_jsx(Button, { color: "danger", size: "medium", fullWidth: true, label: "\uC0AD\uC81C\uD558\uAE30", onClick: onDelete }))] })] })));
44
+ }
45
+ const StyledAlertDialog = styled(AlertDialog) `
46
+ gap: 16px;
47
+ `;
48
+ const StyledAlertDialogTitle = styled(AlertDialogTitle) `
49
+ color: ${({ theme }) => theme.color.foreground.neutralBase};
50
+ text-align: center;
51
+
52
+ /* Default/Heading/20px-Bd */
53
+ font-family: ${({ theme }) => theme.fontFamily.ui};
54
+ font-size: 20px;
55
+ font-style: normal;
56
+ font-weight: 700;
57
+ line-height: 28px; /* 140% */
58
+ letter-spacing: 0.25px;
59
+ `;
60
+ const Inputs = styled.div `
61
+ display: flex;
62
+ flex-direction: column;
63
+ gap: 16px;
64
+ `;
@@ -1,3 +1,2 @@
1
1
  export * from "./LexicalEditor";
2
- export * from "./nodes/ImageNode";
3
2
  export * from "./plugins/MarkdownTransformers";
@@ -1,3 +1,2 @@
1
1
  export * from "./LexicalEditor";
2
- export * from "./nodes/ImageNode";
3
2
  export * from "./plugins/MarkdownTransformers";
@@ -29,11 +29,18 @@ export function FormInput(props) {
29
29
  ? "activeDanger"
30
30
  : inputFocused
31
31
  ? "activePrimary"
32
- : baseColor, onChange: onChangeHandler, value: value !== null && value !== void 0 ? value : "", hintIcon: invalid ? _jsx(ErrorWarningFillIcon, {}) : undefined, hintText: error === null || error === void 0 ? void 0 : error.message, inputProps: Object.assign(Object.assign({ name }, inputProps), { onFocus: () => {
32
+ : baseColor, onChange: onChangeHandler, value: value !== null && value !== void 0 ? value : "", hintIcon: invalid ? _jsx(ErrorWarningFillIcon, {}) : undefined, hintText: error === null || error === void 0 ? void 0 : error.message, inputProps: Object.assign(Object.assign({ name }, inputProps), { onFocus: (e) => {
33
+ var _a;
34
+ (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onFocus) === null || _a === void 0 ? void 0 : _a.call(inputProps, e);
33
35
  setInputFocused(true);
34
- }, onBlur: () => {
36
+ }, onBlur: (e) => {
37
+ var _a;
38
+ (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(inputProps, e);
35
39
  setInputFocused(false);
36
- } }) }, other)));
40
+ } }) }, other, {
41
+ // other에 multiline이 포함되고, 그게 true임이 자명하지만
42
+ // 명시적으로 넣지 않으면, 타입 추론이 되지 않음.
43
+ multiline: true })));
37
44
  }
38
45
  else {
39
46
  const { inputProps } = inputComponentProps, other = __rest(inputComponentProps, ["inputProps"]);
@@ -41,9 +48,13 @@ export function FormInput(props) {
41
48
  ? "activeDanger"
42
49
  : inputFocused
43
50
  ? "activePrimary"
44
- : baseColor, onChange: onChangeHandler, value: value !== null && value !== void 0 ? value : "", hintIcon: invalid ? _jsx(ErrorWarningFillIcon, {}) : undefined, hintText: error === null || error === void 0 ? void 0 : error.message, inputProps: Object.assign(Object.assign({ name }, inputProps), { onFocus: () => {
51
+ : baseColor, onChange: onChangeHandler, value: value !== null && value !== void 0 ? value : "", hintIcon: invalid ? _jsx(ErrorWarningFillIcon, {}) : undefined, hintText: error === null || error === void 0 ? void 0 : error.message, inputProps: Object.assign(Object.assign({ name }, inputProps), { onFocus: (e) => {
52
+ var _a;
53
+ (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onFocus) === null || _a === void 0 ? void 0 : _a.call(inputProps, e);
45
54
  setInputFocused(true);
46
- }, onBlur: () => {
55
+ }, onBlur: (e) => {
56
+ var _a;
57
+ (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(inputProps, e);
47
58
  setInputFocused(false);
48
59
  } }) }, other)));
49
60
  }
@@ -1,10 +1,16 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
3
3
  import { useLexicalNodeSelection } from "@lexical/react/useLexicalNodeSelection";
4
4
  import { mergeRegister } from "@lexical/utils";
5
5
  import { $getNodeByKey, $getSelection, $isNodeSelection, $isRangeSelection, $setSelection, CLICK_COMMAND, COMMAND_PRIORITY_LOW, createCommand, DRAGSTART_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, KEY_ENTER_COMMAND, KEY_ESCAPE_COMMAND, SELECTION_CHANGE_COMMAND, } from "lexical";
6
6
  import { Suspense, useCallback, useEffect, useRef, useState } from "react";
7
7
  import { $isImageNode } from "./ImageNode";
8
+ import SquareButton from "../../../../components/SquareButton";
9
+ import { Settings3FillIcon } from "../../../../icons";
10
+ import styled from "@emotion/styled";
11
+ import { InsertImageDialog } from "../../components/InsertImageDialog";
12
+ import useLexicalEditable from "@lexical/react/useLexicalEditable";
13
+ import { ImageNotAvailable } from "./ImageNotAvailable";
8
14
  const imageCache = new Set();
9
15
  export const RIGHT_CLICK_IMAGE_COMMAND = createCommand("RIGHT_CLICK_IMAGE_COMMAND");
10
16
  function useSuspenseImage(src) {
@@ -141,7 +147,40 @@ export default function ImageComponent({ src, altText, nodeKey, width, height, m
141
147
  ]);
142
148
  const draggable = isSelected && $isNodeSelection(selection);
143
149
  const isFocused = isSelected;
144
- return (_jsx(Suspense, Object.assign({ fallback: null }, { children: _jsx("div", Object.assign({ draggable: draggable }, { children: _jsx(LazyImage, { className: isFocused
145
- ? `focused ${$isNodeSelection(selection) ? "draggable" : ""}`
146
- : null, src: src, altText: altText, imageRef: imageRef, width: width, height: height, maxWidth: maxWidth }) })) })));
150
+ const [open, setOpen] = useState(false);
151
+ const isEditable = useLexicalEditable();
152
+ if (!isEditable) {
153
+ return (_jsx(Suspense, Object.assign({ fallback: _jsx(ImageNotAvailable, {}) }, { children: _jsx("div", Object.assign({ draggable: draggable }, { children: _jsx(LazyImage, { className: isFocused
154
+ ? `focused ${$isNodeSelection(selection) ? "draggable" : ""}`
155
+ : null, src: src, altText: altText, imageRef: imageRef, width: width, height: height, maxWidth: maxWidth }) })) })));
156
+ }
157
+ return (_jsxs(_Fragment, { children: [_jsxs(EditContainer, { children: [_jsx(Suspense, Object.assign({ fallback: _jsx(ImageNotAvailable, {}) }, { children: _jsx("div", Object.assign({ draggable: draggable }, { children: _jsx(LazyImage, { className: isFocused
158
+ ? `focused ${$isNodeSelection(selection) ? "draggable" : ""}`
159
+ : null, src: src, altText: altText, imageRef: imageRef, width: width, height: height, maxWidth: maxWidth }) })) })), _jsx(SquareButton, { size: "small", color: "icon", icon: _jsx(Settings3FillIcon, {}), onClick: () => {
160
+ setOpen(true);
161
+ } })] }), _jsx(InsertImageDialog, { open: open, title: "\uC774\uBBF8\uC9C0 \uC218\uC815\uD558\uAE30", onClose: () => setOpen(false), imageProps: {
162
+ src,
163
+ altText,
164
+ }, onChange: (props) => {
165
+ editor.update(() => {
166
+ const node = $getNodeByKey(nodeKey);
167
+ if (!$isImageNode(node)) {
168
+ return;
169
+ }
170
+ node.setSrc(props.src);
171
+ node.setAltText(props.altText);
172
+ });
173
+ }, onDelete: () => {
174
+ editor.update(() => {
175
+ const node = $getNodeByKey(nodeKey);
176
+ if (!$isImageNode(node)) {
177
+ return;
178
+ }
179
+ node.remove();
180
+ });
181
+ } })] }));
147
182
  }
183
+ const EditContainer = styled.div `
184
+ display: flex;
185
+ gap: 4px;
186
+ `;
@@ -46,6 +46,8 @@ export declare class ImageNode extends DecoratorNode<JSX.Element> {
46
46
  exportJSON(): SerializedImageNode;
47
47
  setWidthAndHeight(width: "inherit" | number, height: "inherit" | number): void;
48
48
  setShowCaption(showCaption: boolean): void;
49
+ setSrc(src: string): void;
50
+ setAltText(altText: string): void;
49
51
  createDOM(config: EditorConfig): HTMLElement;
50
52
  updateDOM(): false;
51
53
  getSrc(): string;
@@ -86,6 +86,14 @@ export class ImageNode extends DecoratorNode {
86
86
  const writable = this.getWritable();
87
87
  writable.__showCaption = showCaption;
88
88
  }
89
+ setSrc(src) {
90
+ const writable = this.getWritable();
91
+ writable.__src = src;
92
+ }
93
+ setAltText(altText) {
94
+ const writable = this.getWritable();
95
+ writable.__altText = altText;
96
+ }
89
97
  // View
90
98
  createDOM(config) {
91
99
  const span = document.createElement("span");
@@ -0,0 +1 @@
1
+ export declare function ImageNotAvailable(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ export function ImageNotAvailable() {
3
+ return (_jsxs("svg", Object.assign({ width: "400", height: "300", viewBox: "0 0 1200 900", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, { children: [_jsx("rect", { width: "1200", height: "900", fill: "#F6F9FC" }), _jsx("path", { d: "M519 369H537V387H519V369ZM555 369H573V387H555V369ZM591 369H609V387H591V369ZM627 369H645V387H627V369ZM663 369H681V387H663V369ZM663 405H681V423H663V405ZM519 513H537V531H519V513ZM519 477H537V495H519V477ZM519 441H537V459H519V441ZM519 405H537V423H519V405Z", fill: "black", "fill-opacity": "0.301961" }), _jsx("path", { d: "M623.183 422.382L680.197 521.134C681.85 523.997 680.869 527.657 678.006 529.31C677.097 529.835 676.065 530.112 675.014 530.112H560.985C557.68 530.112 555 527.432 555 524.127C555 523.076 555.277 522.044 555.802 521.134L612.816 422.382C614.469 419.519 618.129 418.539 620.992 420.191C621.902 420.717 622.657 421.472 623.183 422.382ZM612.014 500.187V512.157H623.984V500.187H612.014ZM612.014 458.292V488.217H623.984V458.292H612.014Z", fill: "black", "fill-opacity": "0.301961" })] })));
4
+ }
@@ -0,0 +1 @@
1
+ export * from "./ImageNode";
@@ -0,0 +1 @@
1
+ export * from "./ImageNode";
@@ -1,6 +1,6 @@
1
1
  import { DecoratorNode, EditorConfig, LexicalNode, NodeKey, SerializedLexicalNode, Spread } from "lexical";
2
2
  import { ReactNode } from "react";
3
- import { ImageProps } from "../insertImageDialog";
3
+ import { ImageProps } from "../../components/InsertImageDialog";
4
4
  export interface SelectionWithoutSolution {
5
5
  show: {
6
6
  image: ImageProps | null;
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { ImageProps } from "../../insertImageDialog";
2
+ import { ImageProps } from "../../../components/InsertImageDialog";
3
3
  export type SelectBoxType = "primary" | "success" | "danger";
4
4
  /** 비지니스 로직과 무관한 SelectBox를 그리는 공통 컴포넌트입니다. */
5
5
  export declare function SelectBoxComponent(props: {
@@ -1,4 +1,4 @@
1
- import { ImageProps } from "../../insertImageDialog";
1
+ import { ImageProps } from "../../../components/InsertImageDialog";
2
2
  export interface SelectBoxEditProps {
3
3
  index: number;
4
4
  isAnswer: boolean;
@@ -1,4 +1,4 @@
1
- import { ImageProps } from "../../insertImageDialog";
1
+ import { ImageProps } from "../../../components/InsertImageDialog";
2
2
  export interface SelectBoxViewProps {
3
3
  index: number;
4
4
  isSelected: boolean;
@@ -8,8 +8,9 @@ import { DeleteBinLineIcon, ErrorWarningFillIcon, ImageAddFillIcon, ImageEditFil
8
8
  import SquareButton from "../../../../../components/SquareButton";
9
9
  import Switch from "../../../../../components/Switch";
10
10
  import { useState } from "react";
11
- import { InsertImageDialog } from "../../insertImageDialog";
11
+ import { InsertImageDialog } from "../../../components/InsertImageDialog";
12
12
  export function FormSelection(props) {
13
+ var _a;
13
14
  const { index, control, rules, onDelete } = props;
14
15
  const [imageOpen, setImageOpen] = useState(false);
15
16
  const [inputFocused, setInputFocused] = useState(false);
@@ -23,7 +24,11 @@ export function FormSelection(props) {
23
24
  flex: 1;
24
25
  flex-direction: column;
25
26
  gap: 4px;
26
- ` }, { children: [_jsx(InsertImageDialog, { title: value.show.image ? "이미지 바꾸기" : "이미지 삽입하기", open: imageOpen, onClose: () => setImageOpen(false), updateImg: (props) => onChange(Object.assign(Object.assign({}, value), { show: Object.assign(Object.assign({}, value.show), { image: props }) })), deleteButton: Boolean(value.show.image) }), value.show.image && (_jsx("img", { src: value.show.image.src, alt: value.show.image.altText, css: css `
27
+ ` }, { children: [_jsx(InsertImageDialog, { title: value.show.image ? "이미지 바꾸기" : "이미지 삽입하기", open: imageOpen, imageProps: (_a = value.show.image) !== null && _a !== void 0 ? _a : undefined, onClose: () => setImageOpen(false), onChange: (props) => onChange(Object.assign(Object.assign({}, value), { show: Object.assign(Object.assign({}, value.show), { image: props }) })), onDelete: value.show.image
28
+ ? () => {
29
+ onChange(Object.assign(Object.assign({}, value), { show: Object.assign(Object.assign({}, value.show), { image: null }) }));
30
+ }
31
+ : undefined }), value.show.image && (_jsx("img", { src: value.show.image.src, alt: value.show.image.altText, css: css `
27
32
  height: auto;
28
33
  // 이미지로 인해 좌우로 스크롤이 생기는 것을 방지
29
34
  max-width: min(400px, 100%);
@@ -1,5 +1,5 @@
1
1
  /// <reference types="react" />
2
- import { ImageProps } from "../../../insertImageDialog";
2
+ import { ImageProps } from "../../../../components/InsertImageDialog";
3
3
  export declare const SelectBoxClasses: {
4
4
  readonly container: "SheetSelectNode-SelectBox-container";
5
5
  readonly index: "SheetSelectNode-SelectBox-index";
@@ -1,4 +1,4 @@
1
- import { ImageProps } from "../../../insertImageDialog";
1
+ import { ImageProps } from "../../../../components/InsertImageDialog";
2
2
  /** SheetSelectNode의 하나의 선택지 edit모드 컴포넌트입니다. */
3
3
  export declare function SelectBoxEdit(props: {
4
4
  index: number;
@@ -1,4 +1,4 @@
1
- import { ImageProps } from "../../../insertImageDialog";
1
+ import { ImageProps } from "../../../../components/InsertImageDialog";
2
2
  /** SheetSelectNode의 하나의 선택지 view모드 컴포넌트입니다. */
3
3
  export declare function SelectBoxView(props: {
4
4
  index: number;
@@ -4,10 +4,11 @@ import { useController } 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 "../../../insertImageDialog";
8
7
  import { DeleteBinLineIcon, ErrorWarningFillIcon, ImageAddFillIcon, ImageEditFillIcon, Input, SquareButton, } from "../../../../../..";
8
+ import { InsertImageDialog, } from "../../../../components/InsertImageDialog";
9
9
  /** SheetSelectNode SettingForm의 단일 선택지 폼입니다. */
10
10
  export default function FormSelection(props) {
11
+ var _a;
11
12
  const { index, control, rules, onDelete } = props;
12
13
  const [imageOpen, setImageOpen] = useState(false);
13
14
  const [inputFocused, setInputFocused] = useState(false);
@@ -21,7 +22,11 @@ export default function FormSelection(props) {
21
22
  flex: 1;
22
23
  flex-direction: column;
23
24
  gap: 4px;
24
- ` }, { 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 `
25
+ ` }, { children: [_jsx(InsertImageDialog, { title: value.image ? "이미지 바꾸기" : "이미지 삽입하기", open: imageOpen, imageProps: (_a = value.image) !== null && _a !== void 0 ? _a : undefined, onClose: () => setImageOpen(false), onChange: (props) => onChange(Object.assign(Object.assign({}, value), { image: props })), onDelete: value.image
26
+ ? () => {
27
+ onChange(Object.assign(Object.assign({}, value), { image: null }));
28
+ }
29
+ : undefined }), value.image && (_jsx("img", { src: value.image.src, alt: value.image.altText, css: css `
25
30
  height: auto;
26
31
  // 이미지로 인해 좌우로 스크롤이 생기는 것을 방지
27
32
  max-width: min(400px, 100%);
@@ -1,6 +1,6 @@
1
1
  import { DecoratorNode, EditorConfig, LexicalNode, NodeKey, SerializedLexicalNode, Spread } from "lexical";
2
2
  import { ReactNode } from "react";
3
- import { ImageProps } from "../insertImageDialog";
3
+ import { ImageProps } from "../../components/InsertImageDialog";
4
4
  export interface Selection {
5
5
  show: {
6
6
  image: ImageProps | null;
@@ -27,9 +27,10 @@ import { useFloatingMenu } from "./useFloatingMenu";
27
27
  import ComponentAdder from "./ComponentAdder";
28
28
  import styled from "@emotion/styled";
29
29
  import { useContextMenuOptions } from "./useContextMenuOptions";
30
- import { InsertImageDialog } from "../ImagesPlugin/InsertImageDialog";
31
30
  import { ZINDEX } from "../../../../utils/zIndex";
32
31
  import { useTheme } from "@emotion/react";
32
+ import { InsertImageDialog, } from "../../components/InsertImageDialog";
33
+ import { INSERT_IMAGE_COMMAND } from "../ImagesPlugin";
33
34
  export const COMPONENT_ADDER_MENU_CLASSNAME = "component-adder-menu";
34
35
  function isOnMenu(element) {
35
36
  return !!element.closest(`.${COMPONENT_ADDER_MENU_CLASSNAME}`);
@@ -151,7 +152,9 @@ export function ComponentAdderPlugin(props) {
151
152
  option.keywords.some((keyword) => regex.test(keyword))));
152
153
  });
153
154
  const { onDragStart, onDragEnd, targetLineRef } = useDraggableBlockMenu(editor, anchorElem, blockElem, setBlockElem);
154
- return (_jsxs(_Fragment, { children: [_jsx(InsertImageDialog, { open: imageOpen, activeEditor: editor, onClose: () => setImageOpen(false) }), _jsx(LexicalNodeMenuPlugin, { nodeKey: nodeKey, anchorClassName: cssToClassName `
155
+ return (_jsxs(_Fragment, { children: [_jsx(InsertImageDialog, { open: imageOpen, title: "\uC774\uBBF8\uC9C0 \uC0BD\uC785\uD558\uAE30", onClose: () => setImageOpen(false), onChange: (props) => {
156
+ editor.dispatchCommand(INSERT_IMAGE_COMMAND, props);
157
+ }, shouldReset: true }), _jsx(LexicalNodeMenuPlugin, { nodeKey: nodeKey, anchorClassName: cssToClassName `
155
158
  z-index: ${ZINDEX.DIALOG + 1};
156
159
  `, options: filteredOptions, menuRenderFn: (anchorElementRef, { selectedIndex, selectOptionAndCleanUp, setHighlightedIndex }) => anchorElementRef.current && filteredOptions.length
157
160
  ? ReactDOM.createPortal(_jsx(ComponentPickerMenuList, { options: filteredOptions, selectedIndex: selectedIndex, selectOptionAndCleanUp: selectOptionAndCleanUp, setHighlightedIndex: setHighlightedIndex }), anchorElementRef.current)
@@ -20,7 +20,6 @@ import { useCallback, useMemo, useState } from "react";
20
20
  import * as ReactDOM from "react-dom";
21
21
  import { css as cssToClassName } from "@emotion/css";
22
22
  import { ComponentPickerMenuList } from "./ComponentPickerMenuList";
23
- import { InsertImageDialog } from "../ImagesPlugin/InsertImageDialog";
24
23
  import { TextIcon, H1Icon, H2Icon, H3Icon, ListUnorderedIcon, ListOrderedIcon, DoubleQuotesLIcon, CodeViewIcon, SeparatorIcon, ImageLineIcon, InputMethodLineIcon, ListRadioIcon, LayoutColumnLineIcon, FileList2LineIcon, EmojiStickerLineIcon, } from "../../../../icons";
25
24
  import { ZINDEX } from "../../../../utils/zIndex";
26
25
  import { css, useTheme } from "@emotion/react";
@@ -30,6 +29,8 @@ import { INSERT_LAYOUT_COMMAND } from "../LayoutPlugin";
30
29
  import { INSERT_SHEET_SELECT_COMMAND } from "../SheetSelectPlugin";
31
30
  import { INSERT_SHEET_INPUT_COMMAND } from "../SheetInputPlugin";
32
31
  import { INSERT_SELF_EVALUATION_COMMAND } from "../SelfEvaluationPlugin";
32
+ import { InsertImageDialog, } from "../../components/InsertImageDialog";
33
+ import { INSERT_IMAGE_COMMAND } from "../ImagesPlugin";
33
34
  // import useModal from "../../hooks/useModal";
34
35
  // import catTypingGif from "../../images/cat-typing.gif";
35
36
  // import { INSERT_IMAGE_COMMAND, InsertImageDialog } from "../ImagesPlugin";
@@ -318,7 +319,9 @@ export function ComponentPickerMenuPlugin(props) {
318
319
  closeMenu();
319
320
  });
320
321
  }, [editor]);
321
- return (_jsxs(_Fragment, { children: [_jsx(InsertImageDialog, { open: open, activeEditor: editor, onClose: () => setOpen(false) }), _jsx(LexicalTypeaheadMenuPlugin, { onQueryChange: setQueryString, onSelectOption: onSelectOption, triggerFn: checkForTriggerMatch, options: options, anchorClassName: cssToClassName `
322
+ return (_jsxs(_Fragment, { children: [_jsx(InsertImageDialog, { title: "\uC774\uBBF8\uC9C0 \uC0BD\uC785\uD558\uAE30", open: open, onChange: (props) => {
323
+ editor.dispatchCommand(INSERT_IMAGE_COMMAND, props);
324
+ }, onClose: () => setOpen(false), shouldReset: true }), _jsx(LexicalTypeaheadMenuPlugin, { onQueryChange: setQueryString, onSelectOption: onSelectOption, triggerFn: checkForTriggerMatch, options: options, anchorClassName: cssToClassName `
322
325
  z-index: ${ZINDEX.DIALOG + 1};
323
326
  `, menuRenderFn: (anchorElementRef, { selectedIndex, selectOptionAndCleanUp, setHighlightedIndex }) => anchorElementRef.current && options.length
324
327
  ? ReactDOM.createPortal(_jsx(ComponentPickerMenuList, { options: options, selectedIndex: selectedIndex, selectOptionAndCleanUp: selectOptionAndCleanUp, setHighlightedIndex: setHighlightedIndex }), anchorElementRef.current)
@@ -1,6 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  import { LexicalCommand } from "lexical";
3
- import { ImagePayload } from "../../nodes/ImageNode";
3
+ import { ImagePayload } from "../../nodes";
4
4
  export type InsertImagePayload = Readonly<ImagePayload>;
5
5
  export declare const INSERT_IMAGE_COMMAND: LexicalCommand<InsertImagePayload>;
6
6
  export default function ImagesPlugin({ captionsEnabled, }: {
@@ -9,7 +9,7 @@ import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext
9
9
  import { $wrapNodeInElement, mergeRegister } from "@lexical/utils";
10
10
  import { $createParagraphNode, $createRangeSelection, $getSelection, $insertNodes, $isNodeSelection, $isRootOrShadowRoot, $setSelection, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, createCommand, DRAGOVER_COMMAND, DRAGSTART_COMMAND, DROP_COMMAND, } from "lexical";
11
11
  import { useEffect } from "react";
12
- import { $createImageNode, $isImageNode, ImageNode, } from "../../nodes/ImageNode";
12
+ import { $createImageNode, $isImageNode, ImageNode, } from "../../nodes";
13
13
  const CAN_USE_DOM = typeof window !== "undefined" &&
14
14
  typeof window.document !== "undefined" &&
15
15
  typeof window.document.createElement !== "undefined";
@@ -9,7 +9,7 @@ import { $convertFromMarkdownString, $convertToMarkdownString, CHECK_LIST, ELEME
9
9
  import { $createHorizontalRuleNode, $isHorizontalRuleNode, HorizontalRuleNode, } from "@lexical/react/LexicalHorizontalRuleNode";
10
10
  import { $createTableCellNode, $createTableNode, $createTableRowNode, $isTableCellNode, $isTableNode, $isTableRowNode, TableCellHeaderStates, TableCellNode, TableNode, TableRowNode, } from "@lexical/table";
11
11
  import { $isParagraphNode, $isTextNode } from "lexical";
12
- import { $createImageNode, $isImageNode, ImageNode, } from "../../nodes/ImageNode";
12
+ import { $createImageNode, $isImageNode, ImageNode } from "../../nodes";
13
13
  export const HR = {
14
14
  dependencies: [HorizontalRuleNode],
15
15
  export: (node) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-monolith/cds",
3
- "version": "1.57.0",
3
+ "version": "1.58.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "sideEffects": false,
@@ -1,114 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/react/jsx-runtime";
11
- /** @jsxImportSource @emotion/react */
12
- import { useContext, useRef, useState } from "react";
13
- import styled from "@emotion/styled";
14
- import { css, useTheme } from "@emotion/react";
15
- import { ImageFillIcon, LinkIcon, UploadLineIcon } from "../../../../icons";
16
- import { AlertDialog, AlertDialogContent, AlertDialogTitle, } from "../../../../components/AlertDialog";
17
- import Button from "../../../../components/Button";
18
- import { CodleDesignSystemContext } from "../../../../CodleDesignSystemProvider";
19
- import { InsertImageUriDialogBody } from "./InsertImageUriDialogBody";
20
- import { InsertImageUploadedDialogBody } from "./InsertImageUploadedDialogBody";
21
- import { useForm } from "react-hook-form";
22
- export function InsertImageDialog(props) {
23
- const { title, open, onClose, updateImg, deleteButton } = props;
24
- const theme = useTheme();
25
- const [mode, setMode] = useState(null);
26
- const inputRef = useRef(null);
27
- const cdsContext = useContext(CodleDesignSystemContext);
28
- const { control, setValue, watch, reset, handleSubmit } = useForm({
29
- defaultValues: { src: "", altText: "" },
30
- });
31
- const handleOnClose = () => {
32
- setMode(null);
33
- reset();
34
- onClose();
35
- };
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 `
45
- display: flex;
46
- flex-direction: column;
47
- gap: 16px;
48
- // Actions가 없는 경우 하단이 디자인과 맞지 않는다
49
- margin-bottom: -16px;
50
- ` }, { 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
- var _a;
52
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click();
53
- } }), _jsx(HiddenInput, { ref: inputRef, type: "file", accept: "image/*", onChange: (event) => __awaiter(this, void 0, void 0, function* () {
54
- var _a, _b;
55
- const file = (_a = event.target.files) === null || _a === void 0 ? void 0 : _a[0];
56
- if (!file)
57
- return;
58
- const uploadByFile = (_b = cdsContext.lexical) === null || _b === void 0 ? void 0 : _b.uploadByFile;
59
- if (uploadByFile) {
60
- setValue("src", yield uploadByFile(file));
61
- setMode("file");
62
- }
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 }))] })));
67
- }
68
- const StyledAlertDialog = styled(AlertDialog) `
69
- gap: 16px;
70
- `;
71
- const StyledAlertDialogTitle = styled(AlertDialogTitle) `
72
- color: ${({ theme }) => theme.color.foreground.neutralBase};
73
- text-align: center;
74
-
75
- /* Default/Heading/20px-Bd */
76
- font-family: ${({ theme }) => theme.fontFamily.ui};
77
- font-size: 20px;
78
- font-style: normal;
79
- font-weight: 700;
80
- line-height: 28px; /* 140% */
81
- letter-spacing: 0.25px;
82
- `;
83
- const Buttons = styled.div `
84
- display: flex;
85
- flex: 1;
86
- align-items: flex-start;
87
- gap: 8px;
88
- `;
89
- const Divider = styled.div(({ theme }) => css `
90
- width: 100%;
91
- height: 1px;
92
- background: ${theme.color.background.neutralAltActive};
93
- `);
94
- const ButtonAndDescription = styled.div `
95
- display: flex;
96
- flex-direction: column;
97
- align-items: center;
98
- gap: 8px;
99
- flex: 1 0 0;
100
- `;
101
- const Description = styled.div `
102
- color: ${({ theme }) => theme.color.foreground.neutralBaseDisabled};
103
- text-align: center;
104
-
105
- /* Default/Label/12px-Md */
106
- font-family: ${({ theme }) => theme.fontFamily.ui};
107
- font-size: 12px;
108
- font-style: normal;
109
- font-weight: 500;
110
- line-height: 16px; /* 133.333% */
111
- `;
112
- const HiddenInput = styled.input `
113
- display: none;
114
- `;
@@ -1,8 +0,0 @@
1
- import { Control, UseFormSetValue, UseFormWatch } from "react-hook-form";
2
- import { ImageProps } from "./InsertImageDialog";
3
- export interface InsertImageUploadedDialogBodyProps {
4
- control: Control<ImageProps, any>;
5
- watch: UseFormWatch<ImageProps>;
6
- setValue: UseFormSetValue<ImageProps>;
7
- }
8
- export declare function InsertImageUploadedDialogBody(props: InsertImageUploadedDialogBodyProps): import("react/jsx-runtime").JSX.Element;
@@ -1,50 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
11
- import { useContext, useRef } from "react";
12
- import styled from "@emotion/styled";
13
- import { CodleDesignSystemContext } from "../../../../CodleDesignSystemProvider";
14
- import { AlertDialogActions, AlertDialogContent, } from "../../../../components/AlertDialog";
15
- import Button from "../../../../components/Button";
16
- import { RefreshLineIcon } from "../../../../icons";
17
- import Input from "../../../../components/Input";
18
- import { Controller, } from "react-hook-form";
19
- export function InsertImageUploadedDialogBody(props) {
20
- const { control, watch, setValue } = props;
21
- const inputRef = useRef(null);
22
- const cdsContext = useContext(CodleDesignSystemContext);
23
- const isDisabled = watch("src") === "";
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: () => {
25
- var _a;
26
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click();
27
- }, startIcon: _jsx(RefreshLineIcon, {}) }), _jsx(HiddenInput, { ref: inputRef, type: "file", accept: "image/*", onChange: (event) => __awaiter(this, void 0, void 0, function* () {
28
- var _a, _b;
29
- const file = (_a = event.target.files) === null || _a === void 0 ? void 0 : _a[0];
30
- if (!file)
31
- return;
32
- const uploadByFile = (_b = cdsContext.lexical) === null || _b === void 0 ? void 0 : _b.uploadByFile;
33
- if (uploadByFile) {
34
- setValue("src", yield uploadByFile(file));
35
- }
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 }) })] }));
37
- }
38
- const Inputs = styled.div `
39
- display: flex;
40
- flex-direction: column;
41
- gap: 16px;
42
- `;
43
- const HiddenInput = styled.input `
44
- display: none;
45
- `;
46
- const ImagePreview = styled.div `
47
- display: flex;
48
- flex-direction: column;
49
- gap: 8px;
50
- `;
@@ -1,7 +0,0 @@
1
- import { Control, UseFormWatch } from "react-hook-form";
2
- import { ImageProps } from "./InsertImageDialog";
3
- export interface InsertImageUriDialogBodyProps {
4
- control: Control<ImageProps, any>;
5
- watch: UseFormWatch<ImageProps>;
6
- }
7
- export declare function InsertImageUriDialogBody(props: InsertImageUriDialogBodyProps): import("react/jsx-runtime").JSX.Element;
@@ -1,17 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import styled from "@emotion/styled";
3
- import { AlertDialogActions, AlertDialogContent, } from "../../../../components/AlertDialog";
4
- import Input from "../../../../components/Input";
5
- import { LinkIcon } from "../../../../icons";
6
- import Button from "../../../../components/Button";
7
- import { Controller } from "react-hook-form";
8
- export function InsertImageUriDialogBody(props) {
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 }) })] }));
12
- }
13
- const Inputs = styled.div `
14
- display: flex;
15
- flex-direction: column;
16
- gap: 16px;
17
- `;
@@ -1,7 +0,0 @@
1
- import { LexicalEditor } from "lexical";
2
- export interface InsertImageDialogProps {
3
- open: boolean;
4
- activeEditor: LexicalEditor;
5
- onClose: () => void;
6
- }
7
- export declare function InsertImageDialog(props: InsertImageDialogProps): import("react/jsx-runtime").JSX.Element;
@@ -1,109 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
- import { useContext, useEffect, useRef, useState } from "react";
12
- import { INSERT_IMAGE_COMMAND } from ".";
13
- import { InsertImageUriDialogBody } from "./InsertImageUriDialogBody";
14
- import { InsertImageUploadedDialogBody } from "./InsertImageUploadedDialogBody";
15
- import styled from "@emotion/styled";
16
- import { AlertDialog, AlertDialogContent, AlertDialogTitle, } from "../../../../components/AlertDialog";
17
- import { ImageFillIcon, LinkIcon, UploadLineIcon } from "../../../../icons";
18
- import Button from "../../../../components/Button";
19
- import { useTheme } from "@emotion/react";
20
- import { CodleDesignSystemContext } from "../../../../CodleDesignSystemProvider";
21
- import { useForm } from "react-hook-form";
22
- export function InsertImageDialog(props) {
23
- const { open, activeEditor, onClose } = props;
24
- const theme = useTheme();
25
- const [mode, setMode] = useState(null);
26
- const hasModifier = useRef(false);
27
- const inputRef = useRef(null);
28
- const cdsContext = useContext(CodleDesignSystemContext);
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
- };
36
- useEffect(() => {
37
- hasModifier.current = false;
38
- const handler = (e) => {
39
- hasModifier.current = e.altKey;
40
- };
41
- document.addEventListener("keydown", handler);
42
- return () => {
43
- document.removeEventListener("keydown", handler);
44
- };
45
- }, [activeEditor]);
46
- const handleOnClose = () => {
47
- setMode(null);
48
- reset();
49
- onClose();
50
- };
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: () => {
52
- var _a;
53
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click();
54
- } }), _jsx(HiddenInput, { ref: inputRef, type: "file", accept: "image/*", onChange: (event) => __awaiter(this, void 0, void 0, function* () {
55
- var _a, _b;
56
- const file = (_a = event.target.files) === null || _a === void 0 ? void 0 : _a[0];
57
- if (!file)
58
- return;
59
- const uploadByFile = (_b = cdsContext.lexical) === null || _b === void 0 ? void 0 : _b.uploadByFile;
60
- if (uploadByFile) {
61
- setValue("src", yield uploadByFile(file));
62
- setMode("file");
63
- }
64
- }) })] })] }) })), mode === "url" && (_jsx(InsertImageUriDialogBody, { control: control, watch: watch })), mode === "file" && (_jsx(InsertImageUploadedDialogBody, { control: control, watch: watch, setValue: setValue }))] })));
65
- }
66
- const StyledAlertDialog = styled(AlertDialog) `
67
- gap: 16px;
68
- `;
69
- const StyledAlertDialogTitle = styled(AlertDialogTitle) `
70
- color: ${({ theme }) => theme.color.foreground.neutralBase};
71
- text-align: center;
72
-
73
- /* Default/Heading/20px-Bd */
74
- font-family: ${({ theme }) => theme.fontFamily.ui};
75
- font-size: 20px;
76
- font-style: normal;
77
- font-weight: 700;
78
- line-height: 28px; /* 140% */
79
- letter-spacing: 0.25px;
80
- `;
81
- const Buttons = styled.div `
82
- display: flex;
83
- align-items: flex-start;
84
- gap: 8px;
85
-
86
- // Actions가 없는 경우 하단이 디자인과 맞지 않는다
87
- margin-bottom: -16px;
88
- `;
89
- const ButtonAndDescription = styled.div `
90
- display: flex;
91
- flex-direction: column;
92
- align-items: center;
93
- gap: 8px;
94
- flex: 1 0 0;
95
- `;
96
- const Description = styled.div `
97
- color: ${({ theme }) => theme.color.foreground.neutralBaseDisabled};
98
- text-align: center;
99
-
100
- /* Default/Label/12px-Md */
101
- font-family: ${({ theme }) => theme.fontFamily.ui};
102
- font-size: 12px;
103
- font-style: normal;
104
- font-weight: 500;
105
- line-height: 16px; /* 133.333% */
106
- `;
107
- const HiddenInput = styled.input `
108
- display: none;
109
- `;
@@ -1,16 +0,0 @@
1
- import { Control, UseFormSetValue, UseFormWatch } from "react-hook-form";
2
- export interface InsertImageUploadedDialogBodyProps {
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
- }>;
15
- }
16
- export declare function InsertImageUploadedDialogBody(props: InsertImageUploadedDialogBodyProps): import("react/jsx-runtime").JSX.Element;
@@ -1,50 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
11
- import { useContext, useRef } from "react";
12
- import styled from "@emotion/styled";
13
- import { CodleDesignSystemContext } from "../../../../CodleDesignSystemProvider";
14
- import { AlertDialogContent, AlertDialogActions, } from "../../../../components/AlertDialog";
15
- import Button from "../../../../components/Button";
16
- import Input from "../../../../components/Input";
17
- import { RefreshLineIcon } from "../../../../icons";
18
- import { Controller, } from "react-hook-form";
19
- export function InsertImageUploadedDialogBody(props) {
20
- const { control, watch, setValue } = props;
21
- const inputRef = useRef(null);
22
- const cdsContext = useContext(CodleDesignSystemContext);
23
- const isDisabled = watch("src") === "";
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: () => {
25
- var _a;
26
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click();
27
- }, startIcon: _jsx(RefreshLineIcon, {}) }), _jsx(HiddenInput, { ref: inputRef, type: "file", accept: "image/*", onChange: (event) => __awaiter(this, void 0, void 0, function* () {
28
- var _a, _b;
29
- const file = (_a = event.target.files) === null || _a === void 0 ? void 0 : _a[0];
30
- if (!file)
31
- return;
32
- const uploadByFile = (_b = cdsContext.lexical) === null || _b === void 0 ? void 0 : _b.uploadByFile;
33
- if (uploadByFile) {
34
- setValue("src", yield uploadByFile(file));
35
- }
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 }) })] }));
37
- }
38
- const Inputs = styled.div `
39
- display: flex;
40
- flex-direction: column;
41
- gap: 16px;
42
- `;
43
- const HiddenInput = styled.input `
44
- display: none;
45
- `;
46
- const ImagePreview = styled.div `
47
- display: flex;
48
- flex-direction: column;
49
- gap: 8px;
50
- `;
@@ -1,12 +0,0 @@
1
- import { Control, UseFormWatch } from "react-hook-form";
2
- export interface InsertImageUriDialogBodyProps {
3
- control: Control<{
4
- src: string;
5
- altText: string;
6
- }, any>;
7
- watch: UseFormWatch<{
8
- src: string;
9
- altText: string;
10
- }>;
11
- }
12
- export declare function InsertImageUriDialogBody(props: InsertImageUriDialogBodyProps): import("react/jsx-runtime").JSX.Element;
@@ -1,17 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import styled from "@emotion/styled";
3
- import { AlertDialogActions, AlertDialogContent, } from "../../../../components/AlertDialog";
4
- import Input from "../../../../components/Input";
5
- import { LinkIcon } from "../../../../icons";
6
- import Button from "../../../../components/Button";
7
- import { Controller } from "react-hook-form";
8
- export function InsertImageUriDialogBody(props) {
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 }) })] }));
12
- }
13
- const Inputs = styled.div `
14
- display: flex;
15
- flex-direction: column;
16
- gap: 16px;
17
- `;