@team-monolith/cds 1.10.6 → 1.11.0
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/CodleDesignSystemProvider.d.ts +0 -12
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/InputComponent.js +24 -15
- package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/SegmentedInput.d.ts +12 -0
- package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/SegmentedInput.js +95 -0
- package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/TextInput.d.ts +6 -0
- package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/TextInput.js +28 -0
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectBox.js +5 -0
- package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/SettingForm.js +1 -1
- package/package.json +4 -17
- package/dist/patterns/ReactEditorJS/Layout.d.ts +0 -8
- package/dist/patterns/ReactEditorJS/Layout.js +0 -91
- package/dist/patterns/ReactEditorJS/ReactEditorJS.d.ts +0 -15
- package/dist/patterns/ReactEditorJS/ReactEditorJS.js +0 -87
- package/dist/patterns/ReactEditorJS/customTools/block/Callout.d.ts +0 -38
- package/dist/patterns/ReactEditorJS/customTools/block/Callout.js +0 -162
- package/dist/patterns/ReactEditorJS/customTools/block/Delimiter.d.ts +0 -10
- package/dist/patterns/ReactEditorJS/customTools/block/Delimiter.js +0 -26
- package/dist/patterns/ReactEditorJS/customTools/block/Header.d.ts +0 -60
- package/dist/patterns/ReactEditorJS/customTools/block/Header.js +0 -122
- package/dist/patterns/ReactEditorJS/customTools/block/Image.d.ts +0 -22
- package/dist/patterns/ReactEditorJS/customTools/block/Image.js +0 -61
- package/dist/patterns/ReactEditorJS/customTools/block/NestedList.d.ts +0 -28
- package/dist/patterns/ReactEditorJS/customTools/block/NestedList.js +0 -74
- package/dist/patterns/ReactEditorJS/customTools/block/Quote.d.ts +0 -42
- package/dist/patterns/ReactEditorJS/customTools/block/Quote.js +0 -171
- package/dist/patterns/ReactEditorJS/customTools/block/Raw.d.ts +0 -30
- package/dist/patterns/ReactEditorJS/customTools/block/Raw.js +0 -107
- package/dist/patterns/ReactEditorJS/customTools/block/Table.d.ts +0 -9
- package/dist/patterns/ReactEditorJS/customTools/block/Table.js +0 -28
- package/dist/patterns/ReactEditorJS/customTools/index.d.ts +0 -16
- package/dist/patterns/ReactEditorJS/customTools/index.js +0 -16
- package/dist/patterns/ReactEditorJS/customTools/inline/Bold.d.ts +0 -52
- package/dist/patterns/ReactEditorJS/customTools/inline/Bold.js +0 -83
- package/dist/patterns/ReactEditorJS/customTools/inline/InlineCode.d.ts +0 -4
- package/dist/patterns/ReactEditorJS/customTools/inline/InlineCode.js +0 -7
- package/dist/patterns/ReactEditorJS/customTools/inline/Italic.d.ts +0 -48
- package/dist/patterns/ReactEditorJS/customTools/inline/Italic.js +0 -79
- package/dist/patterns/ReactEditorJS/customTools/inline/StrikeThrough.d.ts +0 -4
- package/dist/patterns/ReactEditorJS/customTools/inline/StrikeThrough.js +0 -7
- package/dist/patterns/ReactEditorJS/customTools/inline/Underline.d.ts +0 -4
- package/dist/patterns/ReactEditorJS/customTools/inline/Underline.js +0 -7
- package/dist/patterns/ReactEditorJS/customTools/tunes/Delete.d.ts +0 -30
- package/dist/patterns/ReactEditorJS/customTools/tunes/Delete.js +0 -36
- package/dist/patterns/ReactEditorJS/customTools/tunes/MoveDown.d.ts +0 -34
- package/dist/patterns/ReactEditorJS/customTools/tunes/MoveDown.js +0 -58
- package/dist/patterns/ReactEditorJS/customTools/tunes/MoveUp.d.ts +0 -34
- package/dist/patterns/ReactEditorJS/customTools/tunes/MoveUp.js +0 -68
- package/dist/patterns/ReactEditorJS/i18n.d.ts +0 -128
- package/dist/patterns/ReactEditorJS/i18n.js +0 -128
- package/dist/patterns/ReactEditorJS/index.d.ts +0 -3
- package/dist/patterns/ReactEditorJS/index.js +0 -3
- package/dist/patterns/ReactEditorJS/tools.d.ts +0 -80
- package/dist/patterns/ReactEditorJS/tools.js +0 -106
|
@@ -71,18 +71,6 @@ export declare const light: {
|
|
|
71
71
|
};
|
|
72
72
|
};
|
|
73
73
|
interface CodleDesignSystemContext {
|
|
74
|
-
editorjs?: {
|
|
75
|
-
image: {
|
|
76
|
-
uploader: {
|
|
77
|
-
uploadByFile: (file: File) => Promise<{
|
|
78
|
-
success: number;
|
|
79
|
-
file: {
|
|
80
|
-
url: string;
|
|
81
|
-
};
|
|
82
|
-
}>;
|
|
83
|
-
};
|
|
84
|
-
};
|
|
85
|
-
};
|
|
86
74
|
lexical?: {
|
|
87
75
|
uploadByFile: (file: File) => Promise<string>;
|
|
88
76
|
};
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -13,7 +13,6 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/reac
|
|
|
13
13
|
/** @jsxImportSource @emotion/react */
|
|
14
14
|
import { css } from "@emotion/react";
|
|
15
15
|
import { useContext, useState } from "react";
|
|
16
|
-
import Input from "../../../../components/Input";
|
|
17
16
|
import SquareButton from "../../../../components/SquareButton";
|
|
18
17
|
import { Settings3FillIcon } from "../../../../icons";
|
|
19
18
|
import styled from "@emotion/styled";
|
|
@@ -23,36 +22,46 @@ import { $isProblemInputNode } from "./ProblemInputNode";
|
|
|
23
22
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
24
23
|
import { $getNodeByKey } from "lexical";
|
|
25
24
|
import { LexicalCustomConfigContext } from "../../LexicalCustomConfigContext";
|
|
25
|
+
import TextInput from "./TextInput";
|
|
26
|
+
import SegmentedInput from "./SegmentedInput";
|
|
26
27
|
export function InputComponent(props) {
|
|
27
28
|
const { answer } = props, settingFormProps = __rest(props, ["answer"]);
|
|
28
|
-
const { placeholder, nodeKey } = settingFormProps;
|
|
29
|
+
const { solutions, showCharacterCount, placeholder, nodeKey } = settingFormProps;
|
|
29
30
|
const [editor] = useLexicalComposerContext();
|
|
30
31
|
const [settingOpen, setSettingOpen] = useState(false);
|
|
31
32
|
const isEditable = useLexicalEditable();
|
|
32
33
|
const [answerInput, setAnswerInput] = useState(answer);
|
|
33
34
|
const lexicalCustomConfig = useContext(LexicalCustomConfigContext);
|
|
35
|
+
// "** ***" 같은 형태입니다.
|
|
36
|
+
const answerFormat = solutions[0].value;
|
|
34
37
|
// 학생 view
|
|
35
|
-
// TODO: "글자 수대로" 옵션시에 글자 수대로 입력칸을 표시해야 합니다.
|
|
36
38
|
if (!isEditable) {
|
|
37
|
-
if (
|
|
38
|
-
return (_jsx(
|
|
39
|
-
|
|
40
|
-
else {
|
|
41
|
-
return (_jsx(Input, { size: "small", placeholder: placeholder || "여기에 입력하세요.", value: answerInput, onChange: (e) => {
|
|
42
|
-
// SoT를 EditorState로 설정하는 경우 한글 입력시 문제가 생김.
|
|
43
|
-
// ex) "나비" 입력시 -> "ㄴ나납ㅂ비"
|
|
44
|
-
// SoT를 내부 State로 관리하고 EditorState를 따로 설정.
|
|
45
|
-
// 문제를 더 파악하고 추후 개선 필요.
|
|
46
|
-
setAnswerInput(e.target.value);
|
|
39
|
+
if (showCharacterCount) {
|
|
40
|
+
return (_jsx(SegmentedInput, { readOnly: lexicalCustomConfig.freezeProblemNode, answerFormat: answerFormat, placeholder: placeholder || "여기에 입력하세요.", value: answerInput, onChange: (e) => {
|
|
41
|
+
setAnswerInput(e.value);
|
|
47
42
|
editor.update(() => {
|
|
48
43
|
const node = $getNodeByKey(nodeKey);
|
|
49
44
|
if (!$isProblemInputNode(node)) {
|
|
50
45
|
return;
|
|
51
46
|
}
|
|
52
|
-
node.setAnswer(e.
|
|
47
|
+
node.setAnswer(e.value);
|
|
53
48
|
});
|
|
54
|
-
}
|
|
49
|
+
} }));
|
|
55
50
|
}
|
|
51
|
+
return (_jsx(TextInput, { readOnly: lexicalCustomConfig.freezeProblemNode, size: "small", color: "default", placeholder: placeholder || "여기에 입력하세요.", value: answerInput, onChange: (e) => {
|
|
52
|
+
// SoT를 EditorState로 설정하는 경우 한글 입력시 문제가 생김.
|
|
53
|
+
// ex) "나비" 입력시 -> "ㄴ나납ㅂ비"
|
|
54
|
+
// SoT를 내부 State로 관리하고 EditorState를 따로 설정.
|
|
55
|
+
// 문제를 더 파악하고 추후 개선 필요.
|
|
56
|
+
setAnswerInput(e.target.value);
|
|
57
|
+
editor.update(() => {
|
|
58
|
+
const node = $getNodeByKey(nodeKey);
|
|
59
|
+
if (!$isProblemInputNode(node)) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
node.setAnswer(e.target.value);
|
|
63
|
+
});
|
|
64
|
+
}, fullWidth: true }));
|
|
56
65
|
}
|
|
57
66
|
// 교사 edit view
|
|
58
67
|
return (_jsxs(_Fragment, { children: [_jsxs("div", Object.assign({ css: css `
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export interface SegmentedInputProps {
|
|
3
|
+
readOnly: boolean;
|
|
4
|
+
answerFormat: string;
|
|
5
|
+
placeholder: string;
|
|
6
|
+
value: string;
|
|
7
|
+
onChange: (e: {
|
|
8
|
+
value: string;
|
|
9
|
+
event: React.ChangeEvent<HTMLInputElement>;
|
|
10
|
+
}) => void;
|
|
11
|
+
}
|
|
12
|
+
export default function SegmentedInput(props: SegmentedInputProps): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
|
|
2
|
+
/** @jsxImportSource @emotion/react */
|
|
3
|
+
import { css } from "@emotion/react";
|
|
4
|
+
import styled from "@emotion/styled";
|
|
5
|
+
import { InputBase } from "../../../../components/InputBase";
|
|
6
|
+
import { useRef, useState } from "react";
|
|
7
|
+
/** i번째 값을 value로 바꾸는 setState Wrapper 함수 */
|
|
8
|
+
function updateFocus(value, i, setFocus) {
|
|
9
|
+
setFocus((prevFocus) => {
|
|
10
|
+
const newFocus = prevFocus.slice();
|
|
11
|
+
newFocus[i] = value;
|
|
12
|
+
return newFocus;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export default function SegmentedInput(props) {
|
|
16
|
+
const { readOnly, answerFormat, placeholder, value, onChange } = props;
|
|
17
|
+
// "** ***" => ["*", "*", " ", "*", "*", "*"]
|
|
18
|
+
const splitedFormat = answerFormat.split("");
|
|
19
|
+
// "안녕 하세요" => ["안","녕"," ","하","세","요"]
|
|
20
|
+
const splitedValues = value.split("");
|
|
21
|
+
const [focus, setFocus] = useState([]);
|
|
22
|
+
const refs = useRef([]);
|
|
23
|
+
return (_jsxs(Container, { children: [_jsxs(InputWrapper, { children: [_jsx("div", Object.assign({ css: css `
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
gap: 4px;
|
|
27
|
+
` }, { children: splitedFormat.map((format, i) => format === " " ? (_jsx(Space, {}, i)) : (_jsx(SquareInput, { size: "small", color: focus[i] ? "activePrimary" : "default", inputRef: (element) => {
|
|
28
|
+
refs.current[i] = element;
|
|
29
|
+
}, inputProps: {
|
|
30
|
+
readOnly,
|
|
31
|
+
onBlur: () => updateFocus(false, i, setFocus),
|
|
32
|
+
onFocus: () => updateFocus(true, i, setFocus),
|
|
33
|
+
onKeyDown: (e) => {
|
|
34
|
+
var _a, _b;
|
|
35
|
+
// Backspace 키로 이전 input으로의 포커스 이동
|
|
36
|
+
if (e.key === "Backspace" && !splitedValues[i] && i > 0) {
|
|
37
|
+
if (splitedFormat[i - 1] === " ") {
|
|
38
|
+
(_a = refs.current[i - 2]) === null || _a === void 0 ? void 0 : _a.focus();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
(_b = refs.current[i - 1]) === null || _b === void 0 ? void 0 : _b.focus();
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
}, value: splitedValues[i] || "", onChange: (event) => {
|
|
45
|
+
const eventValue = event.target.value;
|
|
46
|
+
// 복붙으로 입력을 입력한 경우
|
|
47
|
+
if (eventValue.length > 2) {
|
|
48
|
+
onChange({ value: value + eventValue, event });
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
} }, i))) })), _jsx(InputMarker, {})] }), _jsx(Text, { children: placeholder })] }));
|
|
52
|
+
}
|
|
53
|
+
const Container = styled.div `
|
|
54
|
+
display: flex;
|
|
55
|
+
width: fit-content;
|
|
56
|
+
flex-direction: column;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
gap: 8px;
|
|
59
|
+
`;
|
|
60
|
+
const InputWrapper = styled.div `
|
|
61
|
+
display: flex;
|
|
62
|
+
width: fit-content;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
gap: 8px;
|
|
65
|
+
margin: auto;
|
|
66
|
+
`;
|
|
67
|
+
const SquareInput = styled(InputBase) `
|
|
68
|
+
width: 36px;
|
|
69
|
+
height: 36px;
|
|
70
|
+
padding-left: 0;
|
|
71
|
+
padding-right: 0;
|
|
72
|
+
input {
|
|
73
|
+
text-align: center;
|
|
74
|
+
}
|
|
75
|
+
`;
|
|
76
|
+
const Space = styled.div `
|
|
77
|
+
width: 4px;
|
|
78
|
+
`;
|
|
79
|
+
const InputMarker = styled.div(({ theme }) => css `
|
|
80
|
+
height: 8px;
|
|
81
|
+
border: 1px solid ${theme.color.background.neutralAltActive};
|
|
82
|
+
border-top: none;
|
|
83
|
+
border-bottom-left-radius: 4px;
|
|
84
|
+
border-bottom-right-radius: 4px;
|
|
85
|
+
`);
|
|
86
|
+
const Text = styled.span(({ theme }) => css `
|
|
87
|
+
color: ${theme.color.foreground.neutralBaseDisabled};
|
|
88
|
+
text-align: center;
|
|
89
|
+
/* Default/Label/12px-Md */
|
|
90
|
+
font-family: ${theme.fontFamily.ui};
|
|
91
|
+
font-size: 12px;
|
|
92
|
+
font-style: normal;
|
|
93
|
+
font-weight: 500;
|
|
94
|
+
line-height: 16px; /* 133.333% */
|
|
95
|
+
`);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
+
import { useState } from "react";
|
|
14
|
+
import Input from "../../../../components/Input";
|
|
15
|
+
/** 읽기모드/편집모드가 가능한 input 컴포넌트 */
|
|
16
|
+
export default function TextInput(props) {
|
|
17
|
+
const { readOnly } = props, InputOriginalProps = __rest(props, ["readOnly"]);
|
|
18
|
+
const [focus, setFocus] = useState(false);
|
|
19
|
+
if (readOnly) {
|
|
20
|
+
return (_jsx(Input, Object.assign({}, InputOriginalProps, { inputProps: {
|
|
21
|
+
readOnly: true,
|
|
22
|
+
} })));
|
|
23
|
+
}
|
|
24
|
+
return (_jsx(Input, Object.assign({}, InputOriginalProps, { color: focus ? "activePrimary" : "default", inputProps: {
|
|
25
|
+
onFocus: () => setFocus(true),
|
|
26
|
+
onBlur: () => setFocus(false),
|
|
27
|
+
} })));
|
|
28
|
+
}
|
|
@@ -44,6 +44,11 @@ const Index = styled.div(({ theme, isSelected }) => css `
|
|
|
44
44
|
width: 20px;
|
|
45
45
|
height: 20px;
|
|
46
46
|
padding: 4px;
|
|
47
|
+
// https://www.w3schools.com/howto/howto_css_disable_text_selection.asp
|
|
48
|
+
-webkit-user-select: none; /* Safari */
|
|
49
|
+
-ms-user-select: none; /* IE 10 and IE 11 */
|
|
50
|
+
user-select: none; /* Standard syntax */
|
|
51
|
+
|
|
47
52
|
justify-content: center;
|
|
48
53
|
align-items: center;
|
|
49
54
|
border-radius: 4px;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
|
|
2
2
|
/** @jsxImportSource @emotion/react */
|
|
3
|
-
import { useFieldArray, useForm
|
|
3
|
+
import { useFieldArray, useForm } from "react-hook-form";
|
|
4
4
|
import { $isProblemSelectNode } from "../ProblemSelectNode";
|
|
5
5
|
import { $getNodeByKey } from "lexical";
|
|
6
6
|
import { css } from "@emotion/react";
|
package/package.json
CHANGED
|
@@ -1,21 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@team-monolith/cds",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"sideEffects": false,
|
|
7
|
-
"dependencies": {
|
|
8
|
-
"@editorjs/delimiter": "^1.4.0",
|
|
9
|
-
"@editorjs/editorjs": "2.28.2",
|
|
10
|
-
"@editorjs/header": "^2.8.1",
|
|
11
|
-
"@editorjs/image": "^2.9.0",
|
|
12
|
-
"@editorjs/inline-code": "^1.5.0",
|
|
13
|
-
"@editorjs/nested-list": "^1.4.1",
|
|
14
|
-
"@editorjs/paragraph": "2.11.3",
|
|
15
|
-
"@editorjs/quote": "^2.6.0",
|
|
16
|
-
"@editorjs/raw": "^2.5.0",
|
|
17
|
-
"@editorjs/table": "^2.3.0",
|
|
18
|
-
"@editorjs/underline": "^1.1.0",
|
|
7
|
+
"dependencies": {
|
|
19
8
|
"@emotion/css": "^11.11.2",
|
|
20
9
|
"@emotion/react": "^11.8.2",
|
|
21
10
|
"@emotion/styled": "^11.8.1",
|
|
@@ -23,13 +12,11 @@
|
|
|
23
12
|
"@mui/material": "^5.13.6",
|
|
24
13
|
"@types/node": "^16.11.26",
|
|
25
14
|
"@types/react": "^18.2.28",
|
|
26
|
-
"@types/react-dom": "^18.2.13",
|
|
27
|
-
"editorjs-strikethrough": "^1.0.0",
|
|
15
|
+
"@types/react-dom": "^18.2.13",
|
|
28
16
|
"hex-to-css-filter": "^5.4.0",
|
|
29
17
|
"lexical": "^0.12.4",
|
|
30
18
|
"react": "^18.2.0",
|
|
31
|
-
"react-dom": "^18.2.0",
|
|
32
|
-
"react-editor-js": "^2.1.0",
|
|
19
|
+
"react-dom": "^18.2.0",
|
|
33
20
|
"react-hook-form": "^7.48.2",
|
|
34
21
|
"remixicon": "^3.4.0",
|
|
35
22
|
"typescript": "^4.5.5",
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
declare const Layout: import("@emotion/styled").StyledComponent<{
|
|
3
|
-
theme?: import("@emotion/react").Theme | undefined;
|
|
4
|
-
as?: import("react").ElementType<any> | undefined;
|
|
5
|
-
} & {
|
|
6
|
-
readOnly?: boolean | undefined;
|
|
7
|
-
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
|
|
8
|
-
export default Layout;
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { css } from "@emotion/react";
|
|
2
|
-
import styled from "@emotion/styled";
|
|
3
|
-
import { hexToCSSFilter } from "hex-to-css-filter";
|
|
4
|
-
import { CalloutStyle, DelimiterStyle, HeaderStyle, NestedListStyle, QuoteStyle, RawStyle, } from "./customTools";
|
|
5
|
-
const Layout = styled.div(({ theme, readOnly }) => css `
|
|
6
|
-
.codex-editor__redactor {
|
|
7
|
-
padding-bottom: 0 !important;
|
|
8
|
-
}
|
|
9
|
-
.ce-block {
|
|
10
|
-
margin-left: ${readOnly ? "0" : "58px"};
|
|
11
|
-
}
|
|
12
|
-
.ce-block__content {
|
|
13
|
-
margin: 0;
|
|
14
|
-
max-width: unset;
|
|
15
|
-
}
|
|
16
|
-
.ce-paragraph {
|
|
17
|
-
font-family: ${theme.fontFamily.ui};
|
|
18
|
-
font-weight: 400;
|
|
19
|
-
font-size: 16px;
|
|
20
|
-
line-height: 24px;
|
|
21
|
-
padding: 0 0 8px;
|
|
22
|
-
}
|
|
23
|
-
// toolbar__actions의 position이 absolute이고, 상위인 toolbar__content의 기본 position이 relative입니다.
|
|
24
|
-
// actions의 위치를 올바르게 변경하기 위해 content의 position을 static으로 변경합니다.
|
|
25
|
-
.ce-toolbar__content {
|
|
26
|
-
position: static;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
${HeaderStyle(theme)}
|
|
30
|
-
${NestedListStyle}
|
|
31
|
-
${QuoteStyle(theme)}
|
|
32
|
-
${CalloutStyle(theme)}
|
|
33
|
-
${RawStyle(theme)}
|
|
34
|
-
${DelimiterStyle(theme)}
|
|
35
|
-
|
|
36
|
-
// editorjs에서는 content의 width가 모자라는 경우 narrow모드로 변경합니다.
|
|
37
|
-
// https://github.com/codex-team/editor.js/blob/next/src/components/modules/ui.ts#L268
|
|
38
|
-
// 그런데, narrow모드가 의도하지 않은 상황에 발생하는 버그가 있습니다.
|
|
39
|
-
// 관련이슈: https://github.com/codex-team/editor.js/issues/2457
|
|
40
|
-
// narrow 모드가 아직 제거되지 않아서 narrow모드가 발생했을 때를 고려해야 합니다.
|
|
41
|
-
// 그래서 narrow모드가 변경하는 css를 override합니다.
|
|
42
|
-
.codex-editor--narrow .codex-editor__redactor {
|
|
43
|
-
margin-right: 0;
|
|
44
|
-
}
|
|
45
|
-
.codex-editor--narrow .ce-popover {
|
|
46
|
-
left: 0;
|
|
47
|
-
right: unset;
|
|
48
|
-
}
|
|
49
|
-
// toolbar를 항상 왼쪽에서 나타나게 하기 위해 narrow모드의 right 스타일을 제거하고, left 스타일을 추가합니다.
|
|
50
|
-
.ce-toolbar__actions {
|
|
51
|
-
left: -5px;
|
|
52
|
-
right: unset;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// block tool 스타일
|
|
56
|
-
.ce-popover-item__icon img {
|
|
57
|
-
width: 18px;
|
|
58
|
-
height: 18px;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// inline tool 스타일
|
|
62
|
-
.ce-conversion-tool img {
|
|
63
|
-
width: 18px;
|
|
64
|
-
height: 18px;
|
|
65
|
-
}
|
|
66
|
-
.ce-inline-toolbar__buttons {
|
|
67
|
-
gap: 4px;
|
|
68
|
-
.ce-inline-tool--active img {
|
|
69
|
-
// color를 editorjs에서는 active icon을 svg color: #388ae5로 변경합니다.
|
|
70
|
-
// cds color인 primary로 변경합니다.
|
|
71
|
-
filter: ${hexToCSSFilter(theme.color.foreground.primary).filter};
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
.ce-inline-toolbar__dropdown {
|
|
75
|
-
padding: 8px 4px;
|
|
76
|
-
gap: 4px;
|
|
77
|
-
}
|
|
78
|
-
.ce-inline-toolbar__dropdown-content img {
|
|
79
|
-
margin-left: 4px;
|
|
80
|
-
width: 18px;
|
|
81
|
-
height: 18px;
|
|
82
|
-
}
|
|
83
|
-
.ce-inline-tool {
|
|
84
|
-
padding: 8px 4px;
|
|
85
|
-
img {
|
|
86
|
-
width: 18px;
|
|
87
|
-
height: 18px;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
`);
|
|
91
|
-
export default Layout;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { EditorCore } from "@react-editor-js/core";
|
|
2
|
-
export interface ReactEditorJSProps {
|
|
3
|
-
className?: string;
|
|
4
|
-
/** 읽기모드 여부(preview 여부) */
|
|
5
|
-
readOnly?: boolean;
|
|
6
|
-
/** 에디터의 블록데이터 */
|
|
7
|
-
blocks: any;
|
|
8
|
-
/** 데이터가 변경되었을 때 실행될 콜백 */
|
|
9
|
-
onChange?: (blocks: any) => void;
|
|
10
|
-
/** 에러 발생시 처리콜백 */
|
|
11
|
-
onError?: (error: any) => void;
|
|
12
|
-
/** 초기화시 콜백 */
|
|
13
|
-
onInitialize?: (instance: EditorCore) => void;
|
|
14
|
-
}
|
|
15
|
-
export declare function ReactEditorJS(props: ReactEditorJSProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,87 +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 } from "react/jsx-runtime";
|
|
11
|
-
import { useCallback, useContext, useEffect, useRef, useState } from "react";
|
|
12
|
-
import { createReactEditorJS } from "react-editor-js";
|
|
13
|
-
import Layout from "./Layout";
|
|
14
|
-
import TOOLS from "./tools";
|
|
15
|
-
import I18n from "./i18n";
|
|
16
|
-
import { CodleDesignSystemContext } from "../../CodleDesignSystemProvider";
|
|
17
|
-
export function ReactEditorJS(props) {
|
|
18
|
-
var _a;
|
|
19
|
-
const { className, readOnly = false, blocks, onChange, onError, onInitialize, } = props;
|
|
20
|
-
const ReactEditorJS = createReactEditorJS();
|
|
21
|
-
const editorCore = useRef(null);
|
|
22
|
-
const [isInitialized, setIsInitialized] = useState(false);
|
|
23
|
-
const codleDesignSystemContext = useContext(CodleDesignSystemContext);
|
|
24
|
-
const handleInitialize = useCallback((instance) => __awaiter(this, void 0, void 0, function* () {
|
|
25
|
-
try {
|
|
26
|
-
setIsInitialized(false);
|
|
27
|
-
yield instance.dangerouslyLowLevelInstance.isReady;
|
|
28
|
-
editorCore.current = instance;
|
|
29
|
-
setIsInitialized(true);
|
|
30
|
-
onInitialize === null || onInitialize === void 0 ? void 0 : onInitialize(instance);
|
|
31
|
-
}
|
|
32
|
-
catch (e) {
|
|
33
|
-
onError === null || onError === void 0 ? void 0 : onError(e);
|
|
34
|
-
}
|
|
35
|
-
}), []);
|
|
36
|
-
const handleSave = useCallback((onChange) => __awaiter(this, void 0, void 0, function* () {
|
|
37
|
-
if (!editorCore.current || readOnly) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
// 저장 전에 isReady 상태를 기다리기
|
|
41
|
-
// https://github.com/codex-team/editor.js/issues/1136
|
|
42
|
-
try {
|
|
43
|
-
yield editorCore.current.dangerouslyLowLevelInstance.isReady;
|
|
44
|
-
const savedData = yield editorCore.current.save();
|
|
45
|
-
if (savedData) {
|
|
46
|
-
onChange(savedData.blocks);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
catch (e) {
|
|
50
|
-
onError === null || onError === void 0 ? void 0 : onError(e);
|
|
51
|
-
}
|
|
52
|
-
}), []);
|
|
53
|
-
// blocks가 변경될 때 preview가 다시 렌더링되게 하려면 controlled component를 위한 "value"인자를 전달하는 것이 올바른 방법이지만
|
|
54
|
-
// controlled를 위해 "defaultValue" 대신 "value"를 사용하면 불필요하게 많이 리렌더링 되고, 그에 따른 오류가 발생합니다.
|
|
55
|
-
// 따라서, highly recommended인 "defaultValue" 사용을 유지하고 blocks가 변경될 때마다
|
|
56
|
-
// useEffect를 사용하여 editorCore의 render 메서드를 호출하여 리렌더링을 수행하도록 구현합니다.
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
if (!isInitialized || !editorCore.current || !readOnly) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
editorCore.current.render({
|
|
62
|
-
blocks,
|
|
63
|
-
});
|
|
64
|
-
}, [blocks, readOnly, isInitialized]);
|
|
65
|
-
const tools = Object.assign(Object.assign({}, TOOLS), { image: Object.assign(Object.assign({}, TOOLS.image), { config: {
|
|
66
|
-
uploader: (_a = codleDesignSystemContext.editorjs) === null || _a === void 0 ? void 0 : _a.image.uploader,
|
|
67
|
-
} }) });
|
|
68
|
-
// readOnly가 변경되면 ReactEditorJS를 다시 마운트하기 위해 key를 변경합니다.
|
|
69
|
-
// readOnly 모드에서는 onChange를 전달할 수 없어서 케이스를 분리합니다.
|
|
70
|
-
if (readOnly) {
|
|
71
|
-
return (_jsx(Layout, Object.assign({ className: className, readOnly: true }, { children: _jsx(ReactEditorJS, { onInitialize: handleInitialize, tools: tools, defaultValue: {
|
|
72
|
-
blocks,
|
|
73
|
-
}, i18n: I18n, readOnly: true }, "readOnly") })));
|
|
74
|
-
}
|
|
75
|
-
return (_jsx(Layout, Object.assign({ className: className }, { children: _jsx(ReactEditorJS, { onInitialize: handleInitialize, tools: tools, inlineToolbar: [
|
|
76
|
-
"bold",
|
|
77
|
-
"italic",
|
|
78
|
-
"underline",
|
|
79
|
-
"strikeThrough",
|
|
80
|
-
"inlineCode",
|
|
81
|
-
"link",
|
|
82
|
-
], tunes: ["moveUp", "delete", "moveDown"],
|
|
83
|
-
// onChange를 사용하므로 value를 사용하면 안됩니다.(defaultValue 사용이 highly recommended)
|
|
84
|
-
defaultValue: {
|
|
85
|
-
blocks,
|
|
86
|
-
}, onChange: () => handleSave(onChange), i18n: I18n }, "editable") })));
|
|
87
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { BlockTool } from "@editorjs/editorjs";
|
|
2
|
-
import { Theme } from "@emotion/react";
|
|
3
|
-
type COLOR_TYPE = "grey" | "red" | "yellow" | "blue" | "green";
|
|
4
|
-
export declare const CalloutStyle: (theme: Theme) => import("@emotion/utils").SerializedStyles;
|
|
5
|
-
export declare class Callout implements BlockTool {
|
|
6
|
-
api: any;
|
|
7
|
-
config: any;
|
|
8
|
-
readOnly: any;
|
|
9
|
-
private _wrapper;
|
|
10
|
-
constructor({ api, config, readOnly, data }: any);
|
|
11
|
-
/** 주어진 data에 따라 HTML Element를 반환함. */
|
|
12
|
-
private createWrapper;
|
|
13
|
-
/** 주어진 data에 따라 this._wrapper를 업데이트함. */
|
|
14
|
-
private updateWrapper;
|
|
15
|
-
get colors(): string[];
|
|
16
|
-
get defaultColor(): string;
|
|
17
|
-
get color(): COLOR_TYPE;
|
|
18
|
-
save(): {
|
|
19
|
-
color: COLOR_TYPE;
|
|
20
|
-
text: string;
|
|
21
|
-
};
|
|
22
|
-
render(): HTMLDivElement;
|
|
23
|
-
renderSettings(): {
|
|
24
|
-
name: string;
|
|
25
|
-
icon: string;
|
|
26
|
-
label: any;
|
|
27
|
-
isActive: boolean;
|
|
28
|
-
closeOnActivate: boolean;
|
|
29
|
-
onActivate: () => void;
|
|
30
|
-
}[];
|
|
31
|
-
static get isReadOnlySupported(): boolean;
|
|
32
|
-
static get enableLineBreaks(): boolean;
|
|
33
|
-
static get toolbox(): {
|
|
34
|
-
icon: string;
|
|
35
|
-
title: string;
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
export {};
|