@team-monolith/cds 1.120.3 → 1.121.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.
@@ -146,11 +146,7 @@ export function ComponentAdderPlugin(props) {
146
146
  resolves.forEach((resolve) => resolve());
147
147
  setResolves((newResolves) => newResolves.filter((newResolve) => resolves.indexOf(newResolve) === -1));
148
148
  });
149
- const getContextMenuOptions = useContextMenuOptions({
150
- isSheetEnabled,
151
- isQuizEnabled,
152
- showFileUpload,
153
- });
149
+ const getContextMenuOptions = useContextMenuOptions();
154
150
  const filteredOptions = options.filter((option) => {
155
151
  if (!query) {
156
152
  return true;
@@ -244,7 +240,7 @@ export function ComponentAdderPlugin(props) {
244
240
  // Add a node key to the selection.
245
241
  nodeSelection.add(newNode.getKey());
246
242
  $setSelection(nodeSelection);
247
- const contextMenuOptions = getContextMenuOptions(editor, newNode, setImageOpen, setVideoOpen, setFileOpen);
243
+ const contextMenuOptions = getContextMenuOptions(editor, newNode);
248
244
  setOptions(contextMenuOptions);
249
245
  if (nodeKey === null) {
250
246
  setNodeKey(newNode.getKey());
@@ -3,8 +3,4 @@
3
3
  */
4
4
  import { LexicalEditor, LexicalNode } from "lexical";
5
5
  import { ComponentDrawerOption, ComponentPickerOption } from "../ComponentPickerMenuPlugin";
6
- export declare function useContextMenuOptions(props: {
7
- isSheetEnabled: boolean;
8
- isQuizEnabled: boolean;
9
- showFileUpload: boolean;
10
- }): (editor: LexicalEditor, node: LexicalNode, setImageOpen: (open: boolean) => void, setVideoOpen: (open: boolean) => void, setFileOpen: (open: boolean) => void) => (ComponentPickerOption | ComponentDrawerOption)[];
6
+ export declare function useContextMenuOptions(): (editor: LexicalEditor, node: LexicalNode) => (ComponentPickerOption | ComponentDrawerOption)[];
@@ -1,81 +1,57 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
1
  /**
3
2
  * Context Menu (:: 버튼)
4
3
  */
5
4
  import { $createParagraphNode, ParagraphNode, } from "lexical";
6
- import { ComponentPickerOption, getBaseOptions, } from "../ComponentPickerMenuPlugin";
7
5
  import { $createHeadingNode, $createQuoteNode, HeadingNode, } from "@lexical/rich-text";
8
6
  import { $setBlocksType } from "@lexical/selection";
9
7
  import { ListItemNode, ListNode, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, } from "@lexical/list";
10
8
  import { $createCodeNode } from "@lexical/code";
11
- import { H1Icon, H2Icon, H3Icon, CloseFillIcon, ListUnorderedIcon, ListOrderedIcon, InputMethodLineIcon, CodeViewIcon, DoubleQuotesLIcon, TextIcon, } from "../../../../icons";
12
9
  import { $isColoredQuoteNode, } from "../../nodes/ColoredQuoteNode";
13
10
  import { useTheme } from "@emotion/react";
14
- import { css } from "@emotion/css";
15
- import { $isFileNode, $isImageNode, $isVideoNode, $isProblemInputNode, } from "../../nodes";
16
- import { $isProblemSelectNode, } from "../../nodes/ProblemSelectNode";
17
- import { $isSheetInputNode } from "../../nodes/SheetInputNode";
18
- import { $isSheetSelectNode, } from "../../nodes/SheetSelectNode";
19
- import { $isSelfEvaluationNode, } from "../../nodes/SelfEvaluationNode";
20
11
  import { useTranslation } from "react-i18next";
12
+ import { getComponentPickerOptions, getQuoteColorOptions, getRemoveBlockMenu, } from "../ComponentPickerMenuPlugin/componentPickerOptionUtils";
21
13
  function getParagraphContextMenuOptions(editor, node, t) {
22
14
  return [
23
- new ComponentPickerOption(t("본문", { context: "렉시컬 드롭다운 메뉴" }), {
24
- icon: _jsx(TextIcon, {}),
25
- // eslint-disable-next-line i18next/no-literal-string
26
- keywords: ["normal", "paragraph", "p", "text", "본문", "단락", "내용"],
15
+ getComponentPickerOptions({
16
+ key: "p",
27
17
  onSelect: () => editor.update(() => {
28
18
  const selection = node.selectStart();
29
19
  $setBlocksType(selection, () => $createParagraphNode());
30
20
  }),
31
- }),
21
+ }, t),
32
22
  ...[1, 2, 3].map((n) => {
33
- const titleMap = {
34
- 1: t("큰 제목", { context: "렉시컬 드롭다운 메뉴" }),
35
- 2: t("중간 제목", { context: "렉시컬 드롭다운 메뉴" }),
36
- 3: t("작은 제목", { context: "렉시컬 드롭다운 메뉴" }),
37
- };
38
- const iconMap = {
39
- 1: _jsx(H1Icon, {}),
40
- 2: _jsx(H2Icon, {}),
41
- 3: _jsx(H3Icon, {}),
42
- };
43
- return new ComponentPickerOption(titleMap[n], {
44
- icon: iconMap[n],
45
- keywords: ["heading", "header", `h${n}`, titleMap[n]],
23
+ const headerKey = `h${n}`;
24
+ return getComponentPickerOptions({
25
+ key: headerKey,
46
26
  onSelect: () => editor.update(() => {
47
27
  const selection = node.selectStart();
48
- $setBlocksType(selection, () => $createHeadingNode(`h${n}`));
28
+ $setBlocksType(selection, () => $createHeadingNode(headerKey));
49
29
  }),
50
- });
30
+ }, t);
51
31
  }),
52
- new ComponentPickerOption(t("일반 목록", { context: "렉시컬 드롭다운 메뉴" }), {
53
- icon: _jsx(ListUnorderedIcon, {}),
54
- keywords: ["bulleted list", "unordered list", "ul"],
32
+ getComponentPickerOptions({
33
+ key: "ul",
55
34
  onSelect: () => {
56
35
  node.selectStart();
57
36
  editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);
58
37
  },
59
- }),
60
- new ComponentPickerOption(t("숫자 목록", { context: "렉시컬 드롭다운 메뉴" }), {
61
- icon: _jsx(ListOrderedIcon, {}),
62
- keywords: ["numbered list", "ordered list", "ol"],
38
+ }, t),
39
+ getComponentPickerOptions({
40
+ key: "ol",
63
41
  onSelect: () => {
64
42
  node.selectStart();
65
43
  editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined);
66
44
  },
67
- }),
68
- new ComponentPickerOption(t("인용 블록", { context: "렉시컬 드롭다운 메뉴" }), {
69
- icon: _jsx(DoubleQuotesLIcon, {}),
70
- keywords: ["block quote"],
45
+ }, t),
46
+ getComponentPickerOptions({
47
+ key: "quote",
71
48
  onSelect: () => editor.update(() => {
72
49
  const selection = node.selectStart();
73
50
  $setBlocksType(selection, () => $createQuoteNode());
74
51
  }),
75
- }),
76
- new ComponentPickerOption(t("코드 블록", { context: "렉시컬 드롭다운 메뉴" }), {
77
- icon: _jsx(CodeViewIcon, {}),
78
- keywords: ["javascript", "python", "js", "codeblock"],
52
+ }, t),
53
+ getComponentPickerOptions({
54
+ key: "code",
79
55
  onSelect: () => editor.update(() => {
80
56
  const selection = node.selectStart();
81
57
  if (selection.isCollapsed()) {
@@ -89,307 +65,72 @@ function getParagraphContextMenuOptions(editor, node, t) {
89
65
  selection.insertRawText(textContent);
90
66
  }
91
67
  }),
92
- }),
93
- new ComponentPickerOption(t("블록 삭제"), {
94
- icon: _jsx(CloseFillIcon, {}),
95
- keywords: [],
96
- onSelect: () => {
97
- editor.update(() => {
98
- node.remove();
99
- });
100
- },
101
- }),
68
+ }, t),
69
+ getRemoveBlockMenu(editor, node, t),
102
70
  ];
103
71
  }
104
72
  function getHeadingContextMenuOptions(editor, node, t) {
105
73
  return [
106
74
  ...[1, 2, 3].map((n) => {
107
- const titleMap = {
108
- 1: t("큰 제목", { context: "렉시컬 드롭다운 메뉴" }),
109
- 2: t("중간 제목", { context: "렉시컬 드롭다운 메뉴" }),
110
- 3: t("작은 제목", { context: "렉시컬 드롭다운 메뉴" }),
111
- };
112
- const iconMap = {
113
- 1: _jsx(H1Icon, {}),
114
- 2: _jsx(H2Icon, {}),
115
- 3: _jsx(H3Icon, {}),
116
- };
117
- return new ComponentPickerOption(titleMap[n], {
118
- icon: iconMap[n],
119
- keywords: ["heading", "header", `h${n}`, titleMap[n]],
75
+ const headerKey = `h${n}`;
76
+ return getComponentPickerOptions({
77
+ key: headerKey,
120
78
  onSelect: () => editor.update(() => {
121
79
  const selection = node.selectStart();
122
- $setBlocksType(selection, () => $createHeadingNode(`h${n}`));
80
+ $setBlocksType(selection, () => $createHeadingNode(headerKey));
123
81
  }),
124
- });
125
- }),
126
- new ComponentPickerOption(t("블록 삭제"), {
127
- icon: _jsx(CloseFillIcon, {}),
128
- keywords: [],
129
- onSelect: () => {
130
- editor.update(() => {
131
- node.remove();
132
- });
133
- },
82
+ }, t);
134
83
  }),
84
+ getRemoveBlockMenu(editor, node, t),
135
85
  ];
136
86
  }
137
- function getListContextMenuOptions(editor, theme, node, t) {
87
+ function getListContextMenuOptions(editor, node, t) {
138
88
  return [
139
- new ComponentPickerOption(t("일반 목록", { context: "렉시컬 드롭다운 메뉴" }), {
140
- icon: _jsx(ListUnorderedIcon, {}),
141
- keywords: ["bulleted list", "unordered list", "ul"],
89
+ getComponentPickerOptions({
90
+ key: "ul",
142
91
  onSelect: () => {
143
92
  node.selectStart();
144
93
  editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);
145
94
  },
146
- }),
147
- new ComponentPickerOption(t("숫자 목록", { context: "렉시컬 드롭다운 메뉴" }), {
148
- icon: _jsx(ListOrderedIcon, {}),
149
- keywords: ["numbered list", "ordered list", "ol"],
95
+ }, t),
96
+ getComponentPickerOptions({
97
+ key: "ol",
150
98
  onSelect: () => {
151
99
  node.selectStart();
152
100
  editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined);
153
101
  },
154
- }),
155
- new ComponentPickerOption(t("블록 삭제"), {
156
- icon: _jsx(CloseFillIcon, {}),
157
- keywords: [],
158
- onSelect: () => {
159
- editor.update(() => {
160
- node.remove();
161
- });
162
- },
163
- }),
164
- ];
165
- }
166
- function getProblemInputContextMenuOptions(node, t) {
167
- return [
168
- new ComponentPickerOption(t("블록 삭제"), {
169
- icon: _jsx(CloseFillIcon, {}),
170
- keywords: [],
171
- onSelect: () => {
172
- node.remove();
173
- },
174
- }),
175
- ];
176
- }
177
- function getProblemSelectContextMenuOptions(node, t) {
178
- return [
179
- new ComponentPickerOption(t("블록 삭제"), {
180
- icon: _jsx(CloseFillIcon, {}),
181
- keywords: [],
182
- onSelect: () => {
183
- node.remove();
184
- },
185
- }),
186
- ];
187
- }
188
- function getSheetInputContextMenuOptions(node, t) {
189
- return [
190
- new ComponentPickerOption(t("블록 삭제"), {
191
- icon: _jsx(CloseFillIcon, {}),
192
- keywords: [],
193
- onSelect: () => {
194
- node.remove();
195
- },
196
- }),
197
- ];
198
- }
199
- function getSheetSelectContextMenuOptions(node, t) {
200
- return [
201
- new ComponentPickerOption(t("블록 삭제"), {
202
- icon: _jsx(CloseFillIcon, {}),
203
- keywords: [],
204
- onSelect: () => {
205
- node.remove();
206
- },
207
- }),
208
- ];
209
- }
210
- function getSelfEvaluationContextMenuOptions(node, t) {
211
- return [
212
- new ComponentPickerOption(t("블록 삭제"), {
213
- icon: _jsx(CloseFillIcon, {}),
214
- keywords: [],
215
- onSelect: () => {
216
- node.remove();
217
- },
218
- }),
219
- ];
220
- }
221
- function getImageContextMenuOptions(node, t) {
222
- return [
223
- new ComponentPickerOption(t("블록 삭제"), {
224
- icon: _jsx(CloseFillIcon, {}),
225
- keywords: [],
226
- onSelect: () => {
227
- node.remove();
228
- },
229
- }),
230
- ];
231
- }
232
- function getVideoContextMenuOptions(node, t) {
233
- return [
234
- new ComponentPickerOption(t("블록 삭제"), {
235
- icon: _jsx(CloseFillIcon, {}),
236
- keywords: [],
237
- onSelect: () => {
238
- node.remove();
239
- },
240
- }),
102
+ }, t),
103
+ getRemoveBlockMenu(editor, node, t),
241
104
  ];
242
105
  }
243
106
  function getColoredQuoteContextMenuOptions(editor, theme, node, t) {
244
107
  return [
245
- new ComponentPickerOption(t("회색"), {
246
- icon: (_jsx(InputMethodLineIcon, { color: theme.color.container.marbleOnContainer })),
247
- iconContainerClassName: css `
248
- background: ${theme.color.container.marbleContainer};
249
- `,
250
- keywords: ["grey", "gray"],
251
- onSelect: () => {
252
- editor.update(() => {
253
- node.setColor("grey");
254
- });
255
- },
256
- }),
257
- new ComponentPickerOption(t("빨간색"), {
258
- icon: (_jsx(InputMethodLineIcon, { color: theme.color.container.redOnContainer })),
259
- iconContainerClassName: css `
260
- background: ${theme.color.container.redContainer};
261
- `,
262
- keywords: ["red"],
263
- onSelect: () => {
264
- editor.update(() => {
265
- node.setColor("red");
266
- });
267
- },
268
- }),
269
- new ComponentPickerOption(t("노란색"), {
270
- icon: (_jsx(InputMethodLineIcon, { color: theme.color.container.yellowOnContainer })),
271
- iconContainerClassName: css `
272
- background: ${theme.color.container.yellowContainer};
273
- `,
274
- keywords: ["yellow"],
275
- onSelect: () => {
276
- editor.update(() => {
277
- node.setColor("yellow");
278
- });
279
- },
280
- }),
281
- new ComponentPickerOption(t("파란색"), {
282
- icon: (_jsx(InputMethodLineIcon, { color: theme.color.container.blueOnContainer })),
283
- iconContainerClassName: css `
284
- background: ${theme.color.container.blueContainer};
285
- `,
286
- keywords: ["blue"],
287
- onSelect: () => {
288
- editor.update(() => {
289
- node.setColor("blue");
290
- });
291
- },
292
- }),
293
- new ComponentPickerOption(t("초록색"), {
294
- icon: (_jsx(InputMethodLineIcon, { color: theme.color.container.greenOnContainer })),
295
- iconContainerClassName: css `
296
- background: ${theme.color.container.greenContainer};
297
- `,
298
- keywords: ["green"],
299
- onSelect: () => {
300
- editor.update(() => {
301
- node.setColor("green");
302
- });
303
- },
304
- }),
305
- new ComponentPickerOption(t("블록 삭제"), {
306
- icon: _jsx(CloseFillIcon, {}),
307
- keywords: [],
308
- onSelect: () => {
309
- editor.update(() => {
310
- node.remove();
311
- });
312
- },
313
- }),
314
- ];
315
- }
316
- function getUploadFileContextMenuOptions(editor, node, t) {
317
- return [
318
- new ComponentPickerOption(t("블록 삭제"), {
319
- icon: _jsx(CloseFillIcon, {}),
320
- keywords: [],
321
- onSelect: () => {
322
- editor.update(() => {
323
- node.remove();
324
- });
325
- },
326
- }),
108
+ getQuoteColorOptions(editor, node, "grey", t, theme),
109
+ getQuoteColorOptions(editor, node, "red", t, theme),
110
+ getQuoteColorOptions(editor, node, "yellow", t, theme),
111
+ getQuoteColorOptions(editor, node, "blue", t, theme),
112
+ getQuoteColorOptions(editor, node, "green", t, theme),
113
+ getRemoveBlockMenu(editor, node, t),
327
114
  ];
328
115
  }
329
- export function useContextMenuOptions(props) {
330
- const { isSheetEnabled, isQuizEnabled, showFileUpload } = props;
116
+ export function useContextMenuOptions() {
331
117
  const theme = useTheme();
332
118
  const { t } = useTranslation();
333
- return (editor, node, setImageOpen, setVideoOpen, setFileOpen) => {
334
- if ($isProblemInputNode(node)) {
335
- return getProblemInputContextMenuOptions(node, t);
336
- }
337
- else if ($isProblemSelectNode(node)) {
338
- return getProblemSelectContextMenuOptions(node, t);
339
- }
340
- else if ($isSheetInputNode(node)) {
341
- return getSheetInputContextMenuOptions(node, t);
342
- }
343
- else if ($isSheetSelectNode(node)) {
344
- return getSheetSelectContextMenuOptions(node, t);
345
- }
346
- else if ($isSelfEvaluationNode(node)) {
347
- return getSelfEvaluationContextMenuOptions(node, t);
348
- }
349
- else if ($isImageNode(node)) {
350
- return getImageContextMenuOptions(node, t);
351
- }
352
- else if ($isVideoNode(node)) {
353
- return getVideoContextMenuOptions(node, t);
354
- }
355
- else if (node instanceof ParagraphNode) {
119
+ return (editor, node) => {
120
+ if (node instanceof ParagraphNode) {
356
121
  return getParagraphContextMenuOptions(editor, node, t);
357
122
  }
358
123
  else if (node instanceof HeadingNode) {
359
124
  return getHeadingContextMenuOptions(editor, node, t);
360
125
  }
361
126
  else if (node instanceof ListNode || node instanceof ListItemNode) {
362
- return getListContextMenuOptions(editor, theme, node, t);
127
+ return getListContextMenuOptions(editor, node, t);
363
128
  }
364
129
  else if ($isColoredQuoteNode(node)) {
365
130
  return getColoredQuoteContextMenuOptions(editor, theme, node, t);
366
131
  }
367
- else if ($isFileNode(node)) {
368
- return getUploadFileContextMenuOptions(editor, node, t);
369
- }
370
132
  else {
371
- return [
372
- ...getBaseOptions({
373
- editor,
374
- theme,
375
- t,
376
- setImageOpen,
377
- setVideoOpen,
378
- isSheetEnabled,
379
- isQuizEnabled,
380
- setFileOpen,
381
- showFileUpload,
382
- }),
383
- new ComponentPickerOption(t("블록 삭제"), {
384
- icon: _jsx(CloseFillIcon, {}),
385
- keywords: [],
386
- onSelect: () => {
387
- editor.update(() => {
388
- node.remove();
389
- });
390
- },
391
- }),
392
- ];
133
+ return [getRemoveBlockMenu(editor, node, t)];
393
134
  }
394
135
  };
395
136
  }
@@ -14,13 +14,11 @@ import { INSERT_HORIZONTAL_RULE_COMMAND } from "@lexical/react/LexicalHorizontal
14
14
  import { LexicalTypeaheadMenuPlugin, MenuOption, useBasicTypeaheadTriggerMatch, } from "@lexical/react/LexicalTypeaheadMenuPlugin";
15
15
  import { $createHeadingNode, $createQuoteNode } from "@lexical/rich-text";
16
16
  import { $setBlocksType } from "@lexical/selection";
17
- import { INSERT_TABLE_COMMAND } from "@lexical/table";
18
17
  import { $createParagraphNode, $getSelection, $isRangeSelection, } from "lexical";
19
18
  import { useCallback, useMemo, useState } from "react";
20
19
  import * as ReactDOM from "react-dom";
21
20
  import { css as cssToClassName } from "@emotion/css";
22
21
  import { ComponentPickerMenuList } from "./ComponentPickerMenuList";
23
- import { TextIcon, H1Icon, H2Icon, H3Icon, ListUnorderedIcon, ListOrderedIcon, DoubleQuotesLIcon, CodeViewIcon, SeparatorIcon, ImageLineIcon, VideoLineIcon, InputMethodLineIcon, ListRadioIcon, LayoutColumnLineIcon, FileList2LineIcon, EmojiStickerLineIcon, File3LineIcon, } from "../../../../icons";
24
22
  import { ZINDEX } from "../../../../utils/zIndex";
25
23
  import { css, useTheme } from "@emotion/react";
26
24
  import { INSERT_PROBLEM_INPUT_COMMAND } from "../ProblemInputPlugin";
@@ -37,6 +35,7 @@ import { UploadFileDialog } from "../../components/UploadFileDialog";
37
35
  import { UPLOAD_FILE_COMMAND } from "../FilePlugin";
38
36
  import { useTranslation } from "react-i18next";
39
37
  import { getTexts } from "../../../../texts";
38
+ import { getComponentPickerOptions, getTableComponentPickerOption, getThemedComponentPickerOptions, } from "./componentPickerOptionUtils";
40
39
  // import useModal from "../../hooks/useModal";
41
40
  // import catTypingGif from "../../images/cat-typing.gif";
42
41
  // import { INSERT_IMAGE_COMMAND, InsertImageDialog } from "../ImagesPlugin";
@@ -71,20 +70,18 @@ function getDynamicOptions(editor, queryString) {
71
70
  const colOptions = tableMatch[2]
72
71
  ? [tableMatch[2]]
73
72
  : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(String);
74
- options.push(...colOptions.map((columns) => new ComponentPickerOption(`${rows}x${columns} Table`, {
75
- icon: _jsx("i", { className: "icon table" }),
76
- keywords: ["table"],
77
- onSelect: () => editor.dispatchCommand(INSERT_TABLE_COMMAND, { columns, rows }),
73
+ options.push(...colOptions.map((columns) => getTableComponentPickerOption({
74
+ editor,
75
+ rows,
76
+ columns,
78
77
  })));
79
78
  }
80
79
  return options;
81
80
  }
82
81
  function getSheetContextOptions(editor, theme, t) {
83
82
  return [
84
- new ComponentPickerOption(t("선택형 입력 칸", { context: "렉시컬 드롭다운 메뉴" }), {
85
- icon: _jsx(ListRadioIcon, { color: theme.color.foreground.primary }),
86
- // eslint-disable-next-line i18next/no-literal-string
87
- keywords: ["sheet select", "선택형 입력"],
83
+ getThemedComponentPickerOptions({
84
+ key: "sheet_select",
88
85
  onSelect: () => editor.dispatchCommand(INSERT_SHEET_SELECT_COMMAND, {
89
86
  selections: [
90
87
  {
@@ -98,14 +95,16 @@ function getSheetContextOptions(editor, theme, t) {
98
95
  selected: [],
99
96
  allowMultipleAnswers: false,
100
97
  }),
101
- }),
102
- new ComponentPickerOption(t("3단계 평가 입력 칸"), {
103
- icon: _jsx(EmojiStickerLineIcon, { color: theme.color.foreground.primary }),
104
- // eslint-disable-next-line i18next/no-literal-string
105
- keywords: ["self evaluation", "3단계 평가 입력"],
98
+ }, t, theme),
99
+ getThemedComponentPickerOptions({
100
+ key: "self_evaluation",
106
101
  onSelect: () => editor.dispatchCommand(INSERT_SELF_EVALUATION_COMMAND, {
107
102
  iconType: "emoji",
108
- labels: [t("아주 잘했어요!"), t("보통이에요."), t("잘 모르겠어요.")],
103
+ labels: [
104
+ t("아주 잘했어요!"),
105
+ t("보통이에요."),
106
+ t("잘 모르겠어요."),
107
+ ],
109
108
  evaluations: [
110
109
  {
111
110
  question: {
@@ -115,27 +114,23 @@ function getSheetContextOptions(editor, theme, t) {
115
114
  },
116
115
  ],
117
116
  }),
118
- }),
119
- new ComponentPickerOption(t("단답형 입력 칸", { context: "렉시컬 드롭다운 메뉴" }), {
120
- icon: _jsx(InputMethodLineIcon, { color: theme.color.foreground.primary }),
121
- // eslint-disable-next-line i18next/no-literal-string
122
- keywords: ["sheet short input", "단답형 입력"],
117
+ }, t, theme),
118
+ getThemedComponentPickerOptions({
119
+ key: "sheet_input",
123
120
  onSelect: () => editor.dispatchCommand(INSERT_SHEET_INPUT_COMMAND, {
124
121
  multiline: false,
125
122
  value: "",
126
123
  placeholder: "",
127
124
  }),
128
- }),
129
- new ComponentPickerOption(t("서술형 입력 칸", { context: "렉시컬 드롭다운 메뉴" }), {
130
- icon: _jsx(FileList2LineIcon, { color: theme.color.foreground.primary }),
131
- // eslint-disable-next-line i18next/no-literal-string
132
- keywords: ["sheet long input", "서술형 입력"],
125
+ }, t, theme),
126
+ getThemedComponentPickerOptions({
127
+ key: "sheet_long_input",
133
128
  onSelect: () => editor.dispatchCommand(INSERT_SHEET_INPUT_COMMAND, {
134
129
  multiline: true,
135
130
  value: "",
136
131
  placeholder: "",
137
132
  }),
138
- }),
133
+ }, t, theme),
139
134
  new ComponentDrawerOption(t("활동지 메뉴구분선"), (_jsx("div", { css: css `
140
135
  width: 100%;
141
136
  height: 1px;
@@ -146,10 +141,8 @@ function getSheetContextOptions(editor, theme, t) {
146
141
  }
147
142
  function getQuizContextOptions(editor, theme, t) {
148
143
  return [
149
- new ComponentPickerOption(t("주관식 입력 칸", { context: "렉시컬 드롭다운 메뉴" }), {
150
- icon: _jsx(InputMethodLineIcon, { color: theme.color.foreground.primary }),
151
- // eslint-disable-next-line i18next/no-literal-string
152
- keywords: ["problem input", "주관식 입력"],
144
+ getThemedComponentPickerOptions({
145
+ key: "problem_input",
153
146
  onSelect: () => editor.dispatchCommand(INSERT_PROBLEM_INPUT_COMMAND, {
154
147
  solutions: [
155
148
  {
@@ -163,11 +156,9 @@ function getQuizContextOptions(editor, theme, t) {
163
156
  caseSensitive: false,
164
157
  ignoreWhitespace: true,
165
158
  }),
166
- }),
167
- new ComponentPickerOption(t("객관식 입력 칸", { context: "렉시컬 드롭다운 메뉴" }), {
168
- icon: _jsx(ListRadioIcon, { color: theme.color.foreground.primary }),
169
- // eslint-disable-next-line i18next/no-literal-string
170
- keywords: ["problem select", "객관식 입력"],
159
+ }, t, theme),
160
+ getThemedComponentPickerOptions({
161
+ key: "problem_select",
171
162
  onSelect: () => {
172
163
  editor.dispatchCommand(INSERT_PROBLEM_SELECT_COMMAND, {
173
164
  selections: [
@@ -183,7 +174,7 @@ function getQuizContextOptions(editor, theme, t) {
183
174
  selected: [],
184
175
  });
185
176
  },
186
- }),
177
+ }, t, theme),
187
178
  new ComponentDrawerOption(t("퀴즈 메뉴구분선"), (_jsx("div", { css: css `
188
179
  width: 100%;
189
180
  height: 1px;
@@ -195,62 +186,46 @@ function getQuizContextOptions(editor, theme, t) {
195
186
  export function getBaseOptions(props) {
196
187
  const { editor, theme, t, setImageOpen, setVideoOpen, setFileOpen, isSheetEnabled, isQuizEnabled, showFileUpload, } = props;
197
188
  const baseOptions = [
198
- new ComponentPickerOption(t("본문", { context: "렉시컬 드롭다운 메뉴" }), {
199
- icon: _jsx(TextIcon, {}),
200
- // eslint-disable-next-line i18next/no-literal-string
201
- keywords: ["normal", "paragraph", "p", "text", "본문", "단락", "내용"],
189
+ getComponentPickerOptions({
190
+ key: "p",
202
191
  onSelect: () => editor.update(() => {
203
192
  const selection = $getSelection();
204
193
  if ($isRangeSelection(selection)) {
205
194
  $setBlocksType(selection, () => $createParagraphNode());
206
195
  }
207
196
  }),
208
- }),
197
+ }, t),
209
198
  ...[1, 2, 3].map((n) => {
210
- const titleMap = {
211
- 1: t("큰 제목", { context: "렉시컬 드롭다운 메뉴" }),
212
- 2: t("중간 제목", { context: "렉시컬 드롭다운 메뉴" }),
213
- 3: t("작은 제목", { context: "렉시컬 드롭다운 메뉴" }),
214
- };
215
- const iconMap = {
216
- 1: _jsx(H1Icon, {}),
217
- 2: _jsx(H2Icon, {}),
218
- 3: _jsx(H3Icon, {}),
219
- };
220
- return new ComponentPickerOption(titleMap[n], {
221
- icon: iconMap[n],
222
- keywords: ["heading", "header", `h${n}`, titleMap[n]],
199
+ const headerKey = `h${n}`;
200
+ return getComponentPickerOptions({
201
+ key: headerKey,
223
202
  onSelect: () => editor.update(() => {
224
203
  const selection = $getSelection();
225
204
  if ($isRangeSelection(selection)) {
226
- $setBlocksType(selection, () => $createHeadingNode(`h${n}`));
205
+ $setBlocksType(selection, () => $createHeadingNode(headerKey));
227
206
  }
228
207
  }),
229
- });
208
+ }, t);
230
209
  }),
231
- new ComponentPickerOption(t("일반 목록", { context: "렉시컬 드롭다운 메뉴" }), {
232
- icon: _jsx(ListUnorderedIcon, {}),
233
- keywords: ["bulleted list", "unordered list", "ul"],
210
+ getComponentPickerOptions({
211
+ key: "ul",
234
212
  onSelect: () => editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined),
235
- }),
236
- new ComponentPickerOption(t("숫자 목록", { context: "렉시컬 드롭다운 메뉴" }), {
237
- icon: _jsx(ListOrderedIcon, {}),
238
- keywords: ["numbered list", "ordered list", "ol"],
213
+ }, t),
214
+ getComponentPickerOptions({
215
+ key: "ol",
239
216
  onSelect: () => editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined),
240
- }),
241
- new ComponentPickerOption(t("인용 블록", { context: "렉시컬 드롭다운 메뉴" }), {
242
- icon: _jsx(DoubleQuotesLIcon, {}),
243
- keywords: ["block quote"],
217
+ }, t),
218
+ getComponentPickerOptions({
219
+ key: "quote",
244
220
  onSelect: () => editor.update(() => {
245
221
  const selection = $getSelection();
246
222
  if ($isRangeSelection(selection)) {
247
223
  $setBlocksType(selection, () => $createQuoteNode());
248
224
  }
249
225
  }),
250
- }),
251
- new ComponentPickerOption(t("코드 블록", { context: "렉시컬 드롭다운 메뉴" }), {
252
- icon: _jsx(CodeViewIcon, {}),
253
- keywords: ["javascript", "python", "js", "codeblock"],
226
+ }, t),
227
+ getComponentPickerOptions({
228
+ key: "code",
254
229
  onSelect: () => editor.update(() => {
255
230
  const selection = $getSelection();
256
231
  if ($isRangeSelection(selection)) {
@@ -266,22 +241,19 @@ export function getBaseOptions(props) {
266
241
  }
267
242
  }
268
243
  }),
269
- }),
270
- new ComponentPickerOption(t("구분선"), {
271
- icon: _jsx(SeparatorIcon, {}),
272
- keywords: ["horizontal rule", "divider", "hr"],
244
+ }, t),
245
+ getComponentPickerOptions({
246
+ key: "divider",
273
247
  onSelect: () => editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined),
274
- }),
275
- new ComponentPickerOption(t("이미지"), {
276
- icon: _jsx(ImageLineIcon, {}),
277
- keywords: ["image", "photo", "picture", "file"],
248
+ }, t),
249
+ getComponentPickerOptions({
250
+ key: "image",
278
251
  onSelect: () => setImageOpen(true),
279
- }),
280
- new ComponentPickerOption(t("동영상"), {
281
- icon: _jsx(VideoLineIcon, {}),
282
- keywords: ["video", "movie"],
252
+ }, t),
253
+ getComponentPickerOptions({
254
+ key: "video",
283
255
  onSelect: () => setVideoOpen(true),
284
- }),
256
+ }, t),
285
257
  ];
286
258
  // devMode, labMode 여부를 로컬스토리지에서 가져옵니다.
287
259
  const isDevMode = localStorage.getItem("devMode") === "true";
@@ -296,19 +268,17 @@ export function getBaseOptions(props) {
296
268
  }
297
269
  // devMode || labMode이면 칼럼 컨텍스트 메뉴를 추가합니다. (일부공개)
298
270
  if (isDevMode || isLabMode) {
299
- baseOptions.push(new ComponentPickerOption(t("칼럼"), {
300
- icon: _jsx(LayoutColumnLineIcon, {}),
301
- keywords: ["columns", "layout", "grid"],
271
+ baseOptions.push(getComponentPickerOptions({
272
+ key: "column",
302
273
  onSelect: () => editor.dispatchCommand(INSERT_LAYOUT_COMMAND, "1fr 1fr"),
303
- }));
274
+ }, t));
304
275
  }
305
276
  // showFileUpload 이면 파일블록을 추가합니다.
306
277
  if (showFileUpload || isDevMode) {
307
- baseOptions.push(new ComponentPickerOption(t("파일 게시"), {
308
- icon: _jsx(File3LineIcon, {}),
309
- keywords: ["file", "upload"],
278
+ baseOptions.push(getComponentPickerOptions({
279
+ key: "file",
310
280
  onSelect: () => setFileOpen(true),
311
- }));
281
+ }, t));
312
282
  }
313
283
  return baseOptions;
314
284
  }
@@ -0,0 +1,24 @@
1
+ import { LexicalEditor, LexicalNode } from "lexical";
2
+ import { ComponentPickerOption } from "./ComponentPickerMenuPlugin";
3
+ import { TFunction } from "i18next";
4
+ import { Theme } from "@emotion/react";
5
+ import { ColoredQuoteNode } from "../../nodes";
6
+ type ComponentPickerOptionKey = "p" | "h1" | "h2" | "h3" | "ul" | "ol" | "quote" | "code" | "toggle" | "divider" | "file" | "image" | "video" | "column";
7
+ type ThemedComponentPickerOptionKey = "sheet_select" | "sheet_input" | "sheet_long_input" | "self_evaluation" | "problem_select" | "problem_input";
8
+ type QuoteColorKey = "grey" | "red" | "yellow" | "blue" | "green";
9
+ export declare function getComponentPickerOptions(props: {
10
+ key: ComponentPickerOptionKey;
11
+ onSelect: (queryString: string) => void;
12
+ }, t: TFunction): ComponentPickerOption;
13
+ export declare function getThemedComponentPickerOptions(props: {
14
+ key: ThemedComponentPickerOptionKey;
15
+ onSelect: (queryString: string) => void;
16
+ }, t: TFunction, theme: Theme): ComponentPickerOption;
17
+ export declare function getTableComponentPickerOption(params: {
18
+ editor: LexicalEditor;
19
+ rows: string;
20
+ columns: string;
21
+ }): ComponentPickerOption;
22
+ export declare function getQuoteColorOptions(editor: LexicalEditor, node: ColoredQuoteNode, colorKey: QuoteColorKey, t: TFunction, theme: Theme): ComponentPickerOption;
23
+ export declare function getRemoveBlockMenu(editor: LexicalEditor, node: LexicalNode, t: TFunction): ComponentPickerOption;
24
+ export {};
@@ -0,0 +1,221 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { CloseFillIcon, CodeViewIcon, DoubleQuotesLIcon, EmojiStickerLineIcon, File3LineIcon, FileList2LineIcon, H1Icon, H2Icon, H3Icon, ImageLineIcon, InputMethodLineIcon, LayoutColumnLineIcon, ListOrderedIcon, ListRadioIcon, ListUnorderedIcon, PlayList2FillIcon, SeparatorIcon, TextIcon, VideoLineIcon, } from "../../../../icons";
3
+ import { ComponentPickerOption } from "./ComponentPickerMenuPlugin";
4
+ import { css } from "@emotion/css";
5
+ import { INSERT_TABLE_COMMAND } from "@lexical/table";
6
+ import { expectNever } from "../../../../utils/types";
7
+ const getHeaderInfo = (key, t) => ({
8
+ h1: {
9
+ title: t("큰 제목"),
10
+ icon: _jsx(H1Icon, {}),
11
+ },
12
+ h2: {
13
+ title: t("중간 제목"),
14
+ icon: _jsx(H2Icon, {}),
15
+ },
16
+ h3: {
17
+ title: t("작은 제목"),
18
+ icon: _jsx(H3Icon, {}),
19
+ },
20
+ })[key];
21
+ export function getComponentPickerOptions(props, t) {
22
+ const { key, onSelect } = props;
23
+ switch (key) {
24
+ case "p":
25
+ return new ComponentPickerOption(t("본문"), {
26
+ icon: _jsx(TextIcon, {}),
27
+ // eslint-disable-next-line i18next/no-literal-string
28
+ keywords: ["normal", "paragraph", "p", "text", "본문", "단락", "내용"],
29
+ onSelect,
30
+ });
31
+ case "h1":
32
+ case "h2":
33
+ case "h3": {
34
+ const { title, icon } = getHeaderInfo(key, t);
35
+ return new ComponentPickerOption(title, {
36
+ icon,
37
+ keywords: ["heading", "header", key, title],
38
+ onSelect,
39
+ });
40
+ }
41
+ case "ul":
42
+ return new ComponentPickerOption(t("일반 목록"), {
43
+ icon: _jsx(ListUnorderedIcon, {}),
44
+ keywords: ["bulleted list", "unordered list", "ul"],
45
+ onSelect,
46
+ });
47
+ case "ol":
48
+ return new ComponentPickerOption(t("숫자 목록"), {
49
+ icon: _jsx(ListOrderedIcon, {}),
50
+ keywords: ["numbered list", "ordered list", "ol"],
51
+ onSelect,
52
+ });
53
+ case "quote":
54
+ return new ComponentPickerOption(t("인용 블록"), {
55
+ icon: _jsx(DoubleQuotesLIcon, {}),
56
+ keywords: ["block quote"],
57
+ onSelect,
58
+ });
59
+ case "code":
60
+ return new ComponentPickerOption(t("코드 블록"), {
61
+ icon: _jsx(CodeViewIcon, {}),
62
+ keywords: ["javascript", "python", "js", "codeblock"],
63
+ onSelect,
64
+ });
65
+ case "toggle":
66
+ return new ComponentPickerOption(t("토글 목록", { context: "렉시컬 드롭다운 메뉴" }), {
67
+ icon: _jsx(PlayList2FillIcon, {}),
68
+ keywords: ["toggle", "collapsible"],
69
+ onSelect,
70
+ });
71
+ case "divider":
72
+ return new ComponentPickerOption(t("구분선"), {
73
+ icon: _jsx(SeparatorIcon, {}),
74
+ keywords: ["horizontal rule", "divider", "hr"],
75
+ onSelect,
76
+ });
77
+ case "file":
78
+ return new ComponentPickerOption(t("파일 게시"), {
79
+ icon: _jsx(File3LineIcon, {}),
80
+ keywords: ["file", "upload"],
81
+ onSelect,
82
+ });
83
+ case "image":
84
+ return new ComponentPickerOption(t("이미지"), {
85
+ icon: _jsx(ImageLineIcon, {}),
86
+ keywords: ["image", "photo", "picture", "file"],
87
+ onSelect,
88
+ });
89
+ case "video":
90
+ return new ComponentPickerOption(t("동영상"), {
91
+ icon: _jsx(VideoLineIcon, {}),
92
+ keywords: ["video", "movie"],
93
+ onSelect,
94
+ });
95
+ case "column":
96
+ return new ComponentPickerOption(t("칼럼"), {
97
+ icon: _jsx(LayoutColumnLineIcon, {}),
98
+ keywords: ["columns", "layout", "grid"],
99
+ onSelect,
100
+ });
101
+ default:
102
+ expectNever(key);
103
+ }
104
+ }
105
+ export function getThemedComponentPickerOptions(props, t, theme) {
106
+ const { key, onSelect } = props;
107
+ switch (key) {
108
+ case "sheet_select":
109
+ return new ComponentPickerOption(t("선택형 입력 칸", { context: "렉시컬 드롭다운 메뉴" }), {
110
+ icon: _jsx(ListRadioIcon, { color: theme.color.foreground.primary }),
111
+ // eslint-disable-next-line i18next/no-literal-string
112
+ keywords: ["sheet select", "선택형 입력"],
113
+ onSelect,
114
+ });
115
+ case "sheet_input":
116
+ return new ComponentPickerOption(t("단답형 입력 칸", { context: "렉시컬 드롭다운 메뉴" }), {
117
+ icon: _jsx(InputMethodLineIcon, { color: theme.color.foreground.primary }),
118
+ // eslint-disable-next-line i18next/no-literal-string
119
+ keywords: ["sheet short input", "단답형 입력"],
120
+ onSelect,
121
+ });
122
+ case "sheet_long_input":
123
+ return new ComponentPickerOption(t("서술형 입력 칸", { context: "렉시컬 드롭다운 메뉴" }), {
124
+ icon: _jsx(FileList2LineIcon, { color: theme.color.foreground.primary }),
125
+ // eslint-disable-next-line i18next/no-literal-string
126
+ keywords: ["sheet long input", "서술형 입력"],
127
+ onSelect,
128
+ });
129
+ case "self_evaluation":
130
+ return new ComponentPickerOption(t("3단계 평가 입력 칸"), {
131
+ icon: _jsx(EmojiStickerLineIcon, { color: theme.color.foreground.primary }),
132
+ // eslint-disable-next-line i18next/no-literal-string
133
+ keywords: ["self evaluation", "3단계 평가 입력"],
134
+ onSelect,
135
+ });
136
+ case "problem_select":
137
+ return new ComponentPickerOption(t("객관식 입력 칸", { context: "렉시컬 드롭다운 메뉴" }), {
138
+ icon: _jsx(ListRadioIcon, { color: theme.color.foreground.primary }),
139
+ // eslint-disable-next-line i18next/no-literal-string
140
+ keywords: ["problem select", "객관식 입력"],
141
+ onSelect,
142
+ });
143
+ case "problem_input":
144
+ return new ComponentPickerOption(t("주관식 입력 칸", { context: "렉시컬 드롭다운 메뉴" }), {
145
+ icon: _jsx(InputMethodLineIcon, { color: theme.color.foreground.primary }),
146
+ // eslint-disable-next-line i18next/no-literal-string
147
+ keywords: ["problem input", "주관식 입력"],
148
+ onSelect,
149
+ });
150
+ default:
151
+ expectNever(key);
152
+ }
153
+ }
154
+ export function getTableComponentPickerOption(params) {
155
+ const { editor, rows, columns } = params;
156
+ return new ComponentPickerOption(`${rows}x${columns} Table`, {
157
+ icon: _jsx("i", { className: "icon table" }),
158
+ keywords: ["table"],
159
+ onSelect: () => {
160
+ editor.dispatchCommand(INSERT_TABLE_COMMAND, { columns, rows });
161
+ },
162
+ });
163
+ }
164
+ const getColoredQuoteInfo = (key, t, theme) => ({
165
+ grey: {
166
+ title: t("회색"),
167
+ iconColor: theme.color.container.marbleOnContainer,
168
+ containerColor: theme.color.container.marbleContainer,
169
+ keywords: ["grey", "gray"],
170
+ },
171
+ red: {
172
+ title: t("빨간색"),
173
+ iconColor: theme.color.container.redOnContainer,
174
+ containerColor: theme.color.container.redContainer,
175
+ keywords: ["red"],
176
+ },
177
+ yellow: {
178
+ title: t("노란색"),
179
+ iconColor: theme.color.container.yellowOnContainer,
180
+ containerColor: theme.color.container.yellowContainer,
181
+ keywords: ["yellow"],
182
+ },
183
+ blue: {
184
+ title: t("파란색"),
185
+ iconColor: theme.color.container.blueOnContainer,
186
+ containerColor: theme.color.container.blueContainer,
187
+ keywords: ["blue"],
188
+ },
189
+ green: {
190
+ title: t("초록색"),
191
+ iconColor: theme.color.container.greenOnContainer,
192
+ containerColor: theme.color.container.greenContainer,
193
+ keywords: ["green"],
194
+ },
195
+ })[key];
196
+ export function getQuoteColorOptions(editor, node, colorKey, t, theme) {
197
+ const { title, iconColor, containerColor, keywords } = getColoredQuoteInfo(colorKey, t, theme);
198
+ return new ComponentPickerOption(title, {
199
+ icon: _jsx(InputMethodLineIcon, { color: iconColor }),
200
+ iconContainerClassName: css `
201
+ background: ${containerColor};
202
+ `,
203
+ keywords,
204
+ onSelect: () => {
205
+ editor.update(() => {
206
+ node.setColor(colorKey);
207
+ });
208
+ },
209
+ });
210
+ }
211
+ export function getRemoveBlockMenu(editor, node, t) {
212
+ return new ComponentPickerOption(t("블록 삭제"), {
213
+ icon: _jsx(CloseFillIcon, {}),
214
+ keywords: [],
215
+ onSelect: () => {
216
+ editor.update(() => {
217
+ node.remove();
218
+ });
219
+ },
220
+ });
221
+ }
@@ -0,0 +1 @@
1
+ export declare function expectNever(never: never): never;
@@ -0,0 +1,3 @@
1
+ export function expectNever(never) {
2
+ throw new Error("unreachable: " + never);
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-monolith/cds",
3
- "version": "1.120.3",
3
+ "version": "1.121.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "sideEffects": false,