@team-monolith/cds 1.114.0 → 1.114.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/patterns/LexicalEditor/components/InsertImageDialog/InsertImageDialog.js +15 -9
- package/dist/patterns/LexicalEditor/components/InsertVideoDialog/InsertVideoDialog.js +12 -10
- package/dist/patterns/LexicalEditor/nodes/Form/FormInput.d.ts +0 -2
- package/dist/patterns/LexicalEditor/nodes/Form/FormInput.js +2 -4
- package/dist/patterns/LexicalEditor/plugins/ComponentPickerMenuPlugin/ComponentPickerMenuPlugin.js +1 -1
- package/package.json +2 -2
|
@@ -7,19 +7,19 @@ import { useForm } from "react-hook-form";
|
|
|
7
7
|
import { FileSelectInput } from "../FileSelectInput";
|
|
8
8
|
import { Button } from "../../../..";
|
|
9
9
|
import { FormInput } from "../../nodes/Form";
|
|
10
|
-
import { useState } from "react";
|
|
10
|
+
import { useEffect, useMemo, useState } from "react";
|
|
11
11
|
import { ImagePreview } from "./ImagePreview";
|
|
12
12
|
import { ImageNotAvailable } from "../../nodes/ImageNode/ImageNotAvailable";
|
|
13
13
|
import styled from "@emotion/styled";
|
|
14
|
+
import { debounce } from "lodash";
|
|
14
15
|
export function InsertImageDialog(props) {
|
|
15
16
|
const { title, open, onClose, imageProps, onChange, onDelete, shouldReset } = props;
|
|
16
17
|
const theme = useTheme();
|
|
17
|
-
const { control, setValue, watch, reset, handleSubmit } = useForm({
|
|
18
|
+
const { control, setValue, watch, reset, handleSubmit, subscribe } = useForm({
|
|
18
19
|
defaultValues: imageProps !== null && imageProps !== void 0 ? imageProps : { src: "", altText: "" },
|
|
19
20
|
});
|
|
20
21
|
const handleOnClose = () => {
|
|
21
22
|
if (shouldReset) {
|
|
22
|
-
setPreviewSrc("");
|
|
23
23
|
reset();
|
|
24
24
|
}
|
|
25
25
|
onClose();
|
|
@@ -32,18 +32,24 @@ export function InsertImageDialog(props) {
|
|
|
32
32
|
// 두 값은 시멘틱이 다르므로 독립적인 state로 관리합니다.
|
|
33
33
|
const [previewSrc, setPreviewSrc] = useState(watch("src"));
|
|
34
34
|
const isDisabled = watch("src") === "";
|
|
35
|
+
const debouncedSetPreviewSrc = useMemo(() => debounce((value) => setPreviewSrc(value), 500), []);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
const unsubscribe = subscribe({
|
|
38
|
+
name: "src",
|
|
39
|
+
formState: { values: true },
|
|
40
|
+
callback: ({ values }) => {
|
|
41
|
+
debouncedSetPreviewSrc(values.src);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
return () => unsubscribe();
|
|
45
|
+
}, [debouncedSetPreviewSrc, subscribe]);
|
|
35
46
|
return (_jsxs(StyledAlertDialog, { component: "form", icon: _jsx(ImageFillIcon, { color: theme.color.background.primary }), open: open, onClose: handleOnClose, onSubmit: (e) => {
|
|
36
47
|
// nested form 구조라서 submit이벤트 전파를 막습니다.
|
|
37
48
|
e.stopPropagation();
|
|
38
49
|
handleSubmit(onSubmit)();
|
|
39
50
|
}, disableIconPadding: true, children: [_jsx(StyledAlertDialogTitle, { onClose: handleOnClose, children: title }), _jsx(AlertDialogContent, { children: _jsxs(Inputs, { children: [_jsx(FileSelectInput, { onChange: (value) => {
|
|
40
51
|
setValue("src", value);
|
|
41
|
-
|
|
42
|
-
}, fileType: "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: {
|
|
43
|
-
onBlur: () => {
|
|
44
|
-
setPreviewSrc(watch("src"));
|
|
45
|
-
},
|
|
46
|
-
} }), 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 }))] })] }));
|
|
52
|
+
}, fileType: "image" }), _jsx(FormInput, { name: "src", control: control, placeholder: "https://www.pexels.com/photo/n-2848492", size: "medium", label: "URL", fullWidth: true, startIcon: _jsx(LinkIcon, {}) }), 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 }))] })] }));
|
|
47
53
|
}
|
|
48
54
|
const StyledAlertDialog = styled(AlertDialog) `
|
|
49
55
|
gap: 16px;
|
|
@@ -13,13 +13,12 @@ import { debounce } from "lodash";
|
|
|
13
13
|
export function InsertVideoDialog(props) {
|
|
14
14
|
const { title, open, onClose, videoProps, onChange, onDelete, shouldReset } = props;
|
|
15
15
|
const theme = useTheme();
|
|
16
|
-
const { control, watch, reset, handleSubmit } = useForm({
|
|
16
|
+
const { control, watch, reset, handleSubmit, subscribe } = useForm({
|
|
17
17
|
defaultValues: videoProps !== null && videoProps !== void 0 ? videoProps : { src: "" },
|
|
18
18
|
mode: "onChange",
|
|
19
19
|
});
|
|
20
20
|
const handleOnClose = () => {
|
|
21
21
|
if (shouldReset) {
|
|
22
|
-
setPreviewSrc("");
|
|
23
22
|
reset();
|
|
24
23
|
}
|
|
25
24
|
onClose();
|
|
@@ -33,20 +32,23 @@ export function InsertVideoDialog(props) {
|
|
|
33
32
|
const [previewSrc, setPreviewSrc] = useState(watch("src"));
|
|
34
33
|
const videoCanPlay = ReactPlayer.canPlay(previewSrc);
|
|
35
34
|
const debouncedSetPreviewSrc = useMemo(() => debounce((value) => setPreviewSrc(value), 500), []);
|
|
36
|
-
useEffect(() =>
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const unsubscribe = subscribe({
|
|
37
|
+
name: "src",
|
|
38
|
+
formState: { values: true },
|
|
39
|
+
callback: ({ values }) => {
|
|
40
|
+
debouncedSetPreviewSrc(values.src);
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
return () => unsubscribe();
|
|
44
|
+
}, [debouncedSetPreviewSrc, subscribe]);
|
|
39
45
|
return (_jsxs(StyledAlertDialog, { component: "form", icon: _jsx(VideoLineIcon, { color: theme.color.background.primary }), open: open, onClose: handleOnClose, onSubmit: (e) => {
|
|
40
46
|
// nested form 구조라서 submit이벤트 전파를 막습니다.
|
|
41
47
|
e.stopPropagation();
|
|
42
48
|
handleSubmit(onSubmit)();
|
|
43
49
|
}, disableIconPadding: true, children: [_jsx(StyledAlertDialogTitle, { onClose: handleOnClose, children: title }), _jsx(AlertDialogContent, { children: _jsxs(Inputs, { children: [_jsx(FormInput, { name: "src", control: control, rules: {
|
|
44
50
|
validate: (value) => ReactPlayer.canPlay(value) || "올바른 동영상 URL을 입력하세요.",
|
|
45
|
-
}, placeholder: "https://example.com/video.mp4", size: "medium", label: "URL", fullWidth: true, startIcon: _jsx(LinkIcon, {}),
|
|
46
|
-
onBlur: () => {
|
|
47
|
-
setPreviewSrc(watch("src"));
|
|
48
|
-
},
|
|
49
|
-
} }), videoCanPlay && (_jsx(ReactPlayer, { css: css `
|
|
51
|
+
}, placeholder: "https://example.com/video.mp4", size: "medium", label: "URL", fullWidth: true, startIcon: _jsx(LinkIcon, {}) }), videoCanPlay && (_jsx(ReactPlayer, { css: css `
|
|
50
52
|
background: black;
|
|
51
53
|
`, width: "100%", url: previewSrc, controls: true, config: {
|
|
52
54
|
file: {
|
|
@@ -8,7 +8,5 @@ export type FormInputProps<T extends FieldValues, TName extends FieldPath<T>> =
|
|
|
8
8
|
rules?: ControllerProps<T, TName>["rules"];
|
|
9
9
|
/** html event에서 얻은 value를 form에 주입하기 전에 변환합니다. */
|
|
10
10
|
transform?: (value: string) => unknown;
|
|
11
|
-
/** react-hook-form onChange후 호출되는 콜백 */
|
|
12
|
-
onAfterChange?: (value: string) => void;
|
|
13
11
|
};
|
|
14
12
|
export declare function FormInput<T extends FieldValues, TName extends FieldPath<T>>(props: FormInputProps<T, TName>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -14,13 +14,11 @@ import { ErrorWarningFillIcon, Input } from "../../../..";
|
|
|
14
14
|
import { Controller, } from "react-hook-form";
|
|
15
15
|
import { useState } from "react";
|
|
16
16
|
export function FormInput(props) {
|
|
17
|
-
const { name, control, rules, baseColor = "default", transform = (value) => value
|
|
17
|
+
const { name, control, rules, baseColor = "default", transform = (value) => value } = props, inputComponentProps = __rest(props, ["name", "control", "rules", "baseColor", "transform"]);
|
|
18
18
|
const [inputFocused, setInputFocused] = useState(false);
|
|
19
19
|
return (_jsx(Controller, { name: name, control: control, rules: rules, render: ({ field: { onChange, value }, fieldState: { invalid, error }, }) => {
|
|
20
20
|
const onChangeHandler = (e) => {
|
|
21
|
-
|
|
22
|
-
onChange(nextValue);
|
|
23
|
-
onAfterChange === null || onAfterChange === void 0 ? void 0 : onAfterChange(nextValue);
|
|
21
|
+
onChange(transform(e.target.value));
|
|
24
22
|
};
|
|
25
23
|
// multiline 여부에 따라 inputProps의 type이 변경되므로 (union type)
|
|
26
24
|
// type-safety를 보장하기 위해 if 문을 분기하여 inputProps에 `name` 을 추가합니다.
|
package/dist/patterns/LexicalEditor/plugins/ComponentPickerMenuPlugin/ComponentPickerMenuPlugin.js
CHANGED
|
@@ -336,7 +336,7 @@ export function ComponentPickerMenuPlugin(props) {
|
|
|
336
336
|
option.keywords.some((keyword) => regex.test(keyword)))),
|
|
337
337
|
];
|
|
338
338
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
339
|
-
}, [editor, queryString
|
|
339
|
+
}, [editor, queryString]);
|
|
340
340
|
const onSelectOption = useCallback((selectedOption, nodeToRemove, closeMenu, matchingString) => {
|
|
341
341
|
if (selectedOption instanceof ComponentDrawerOption) {
|
|
342
342
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@team-monolith/cds",
|
|
3
|
-
"version": "1.114.
|
|
3
|
+
"version": "1.114.2",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"moment": "^2.30.1",
|
|
21
21
|
"react": "^18.2.0",
|
|
22
22
|
"react-dom": "^18.2.0",
|
|
23
|
-
"react-hook-form": "^7.
|
|
23
|
+
"react-hook-form": "^7.55.0",
|
|
24
24
|
"react-player": "^2.16.0",
|
|
25
25
|
"remixicon": "^4.3.0",
|
|
26
26
|
"typescript": "~5.5.4",
|