@team-monolith/cds 1.6.1 → 1.7.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/components/Popover.d.ts +16 -0
- package/dist/components/Popover.js +59 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/patterns/LexicalEditor/LexicalEditor.js +8 -0
- package/dist/patterns/LexicalEditor/nodes/ColoredQuoteNode.d.ts +21 -0
- package/dist/patterns/LexicalEditor/nodes/ColoredQuoteNode.js +50 -0
- package/dist/patterns/LexicalEditor/plugins/ComponentAdderPlugin/ComponentAdder.js +1 -1
- package/dist/patterns/LexicalEditor/plugins/ComponentAdderPlugin/ComponentAdderPlugin.js +19 -16
- package/dist/patterns/LexicalEditor/plugins/ComponentAdderPlugin/getContextMenuOptions.js +117 -10
- package/dist/patterns/LexicalEditor/plugins/ComponentAdderPlugin/useContextMenuOptions.d.ts +6 -0
- package/dist/patterns/LexicalEditor/plugins/ComponentAdderPlugin/useContextMenuOptions.js +172 -0
- package/dist/patterns/LexicalEditor/plugins/ComponentPickerMenuPlugin/ComponentPickerMenuItem.js +2 -1
- package/dist/patterns/LexicalEditor/plugins/ComponentPickerMenuPlugin/ComponentPickerMenuPlugin.d.ts +5 -3
- package/dist/patterns/LexicalEditor/plugins/ComponentPickerMenuPlugin/ComponentPickerMenuPlugin.js +1 -0
- package/dist/patterns/LexicalEditor/plugins/FloatingLinkEditorPlugin/FloatingLinkEditor.js +1 -1
- package/dist/patterns/LexicalEditor/plugins/FloatingLinkEditorPlugin/index.js +1 -1
- package/dist/patterns/LexicalEditor/theme.d.ts +7 -0
- package/dist/patterns/LexicalEditor/theme.js +73 -1
- package/package.json +1 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface PopoverProps {
|
|
3
|
+
className?: string;
|
|
4
|
+
/** 제목 */
|
|
5
|
+
headline?: React.ReactNode;
|
|
6
|
+
/** 내용 */
|
|
7
|
+
content?: React.ReactNode;
|
|
8
|
+
/** 좌측 아이콘 */
|
|
9
|
+
icon?: React.ReactNode;
|
|
10
|
+
/** 우측 버튼 텍스트 */
|
|
11
|
+
buttonLabel?: string;
|
|
12
|
+
/** 우측 버튼 클릭시 동작 */
|
|
13
|
+
onButtonClick?: () => void;
|
|
14
|
+
}
|
|
15
|
+
declare const Popover: React.ForwardRefExoticComponent<PopoverProps & React.RefAttributes<HTMLDivElement>>;
|
|
16
|
+
export default Popover;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import styled from "@emotion/styled";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import shadows from "../foundation/shadows";
|
|
5
|
+
import { RESET_BUTTON } from "../utils/reset";
|
|
6
|
+
import { HOVER } from "../utils/hover";
|
|
7
|
+
import { css } from "@emotion/react";
|
|
8
|
+
const Popover = React.forwardRef((props, ref) => {
|
|
9
|
+
const { className, headline, content, icon, buttonLabel, onButtonClick } = props;
|
|
10
|
+
return (_jsxs(Container, Object.assign({ ref: ref, className: className }, { children: [icon && _jsx(Icon, { children: icon }), _jsxs(ContentArea, { children: [headline && _jsx(Headline, { children: headline }), content && _jsx(Content, { children: content })] }), buttonLabel && (_jsx(PopoverButton, Object.assign({ type: "button", onClick: onButtonClick }, { children: buttonLabel })))] })));
|
|
11
|
+
});
|
|
12
|
+
export default Popover;
|
|
13
|
+
const Container = styled.div(({ theme }) => css `
|
|
14
|
+
display: inline-flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
width: auto;
|
|
17
|
+
padding: 6px 16px;
|
|
18
|
+
gap: 12px;
|
|
19
|
+
border-radius: 100px;
|
|
20
|
+
background-color: ${theme.color.foreground.neutralBase};
|
|
21
|
+
color: ${theme.color.background.neutralBase};
|
|
22
|
+
box-shadow: ${shadows.shadow32};
|
|
23
|
+
`);
|
|
24
|
+
const Icon = styled.div `
|
|
25
|
+
display: block;
|
|
26
|
+
width: 20px;
|
|
27
|
+
height: 20px;
|
|
28
|
+
svg {
|
|
29
|
+
width: 100%;
|
|
30
|
+
height: 100%;
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
const ContentArea = styled.div `
|
|
34
|
+
flex: 1 0 auto;
|
|
35
|
+
font-size: 14px;
|
|
36
|
+
line-height: 20px;
|
|
37
|
+
`;
|
|
38
|
+
const Headline = styled.div `
|
|
39
|
+
margin-bottom: 2px;
|
|
40
|
+
font-weight: 700;
|
|
41
|
+
`;
|
|
42
|
+
const Content = styled.div `
|
|
43
|
+
font-weight: 400;
|
|
44
|
+
`;
|
|
45
|
+
const PopoverButton = styled.button(({ theme }) => css `
|
|
46
|
+
${RESET_BUTTON}
|
|
47
|
+
margin: 4px;
|
|
48
|
+
padding: 6px 8px;
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
background-color: ${theme.color.background.primary};
|
|
51
|
+
color: ${theme.color.background.neutralAlt};
|
|
52
|
+
font-size: 14px;
|
|
53
|
+
line-height: 16px;
|
|
54
|
+
border-radius: 8px;
|
|
55
|
+
${HOVER(css `
|
|
56
|
+
color: ${theme.color.foreground.neutralAlt};
|
|
57
|
+
background: ${theme.color.background.primaryActive};
|
|
58
|
+
`)}
|
|
59
|
+
`);
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export { default as Pagination } from "./components/Pagination";
|
|
|
12
12
|
export * from "./components/Pagination";
|
|
13
13
|
export { default as PinInput } from "./components/PinInput";
|
|
14
14
|
export * from "./components/PinInput";
|
|
15
|
+
export { default as Popover } from "./components/Popover";
|
|
16
|
+
export * from "./components/Popover";
|
|
15
17
|
export { default as RadioInput } from "./components/RadioInput";
|
|
16
18
|
export * from "./components/RadioInput";
|
|
17
19
|
export { default as SquareButton } from "./components/SquareButton";
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,8 @@ export { default as Pagination } from "./components/Pagination";
|
|
|
12
12
|
export * from "./components/Pagination";
|
|
13
13
|
export { default as PinInput } from "./components/PinInput";
|
|
14
14
|
export * from "./components/PinInput";
|
|
15
|
+
export { default as Popover } from "./components/Popover";
|
|
16
|
+
export * from "./components/Popover";
|
|
15
17
|
export { default as RadioInput } from "./components/RadioInput";
|
|
16
18
|
export * from "./components/RadioInput";
|
|
17
19
|
export { default as SquareButton } from "./components/SquareButton";
|
|
@@ -10,6 +10,7 @@ import { HorizontalRuleNode } from "@lexical/react/LexicalHorizontalRuleNode";
|
|
|
10
10
|
import { getTheme } from "./theme";
|
|
11
11
|
import { useTheme } from "@emotion/react";
|
|
12
12
|
import Plugins from "./Plugins";
|
|
13
|
+
import { ColoredQuoteNode } from "./nodes/ColoredQuoteNode";
|
|
13
14
|
function validateValue(value) {
|
|
14
15
|
var _a, _b;
|
|
15
16
|
if (value && typeof value !== "object") {
|
|
@@ -46,6 +47,13 @@ export function LexicalEditor(props) {
|
|
|
46
47
|
LinkNode,
|
|
47
48
|
ImageNode,
|
|
48
49
|
HorizontalRuleNode,
|
|
50
|
+
ColoredQuoteNode,
|
|
51
|
+
{
|
|
52
|
+
replace: QuoteNode,
|
|
53
|
+
with: (_node) => {
|
|
54
|
+
return new ColoredQuoteNode("grey");
|
|
55
|
+
},
|
|
56
|
+
},
|
|
49
57
|
],
|
|
50
58
|
theme: getTheme(theme),
|
|
51
59
|
editorState: validateValue(value) ? JSON.stringify(value) : undefined,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { QuoteNode } from "@lexical/rich-text";
|
|
2
|
+
import { EditorConfig, LexicalNode, NodeKey, SerializedElementNode } from "lexical";
|
|
3
|
+
type COLOR = "red" | "yellow" | "blue" | "green" | "grey";
|
|
4
|
+
export type SerializedColoredQuoteNode = SerializedElementNode & {
|
|
5
|
+
color: COLOR;
|
|
6
|
+
};
|
|
7
|
+
export declare class ColoredQuoteNode extends QuoteNode {
|
|
8
|
+
__color: COLOR;
|
|
9
|
+
static getType(): string;
|
|
10
|
+
static clone(node: ColoredQuoteNode): ColoredQuoteNode;
|
|
11
|
+
constructor(color: COLOR, key?: NodeKey);
|
|
12
|
+
setColor(color: COLOR): void;
|
|
13
|
+
getColor(): COLOR;
|
|
14
|
+
createDOM(config: EditorConfig): HTMLElement;
|
|
15
|
+
updateDOM(prevNode: ColoredQuoteNode, dom: HTMLElement): boolean;
|
|
16
|
+
static importJSON(serializedNode: SerializedColoredQuoteNode): QuoteNode;
|
|
17
|
+
exportJSON(): SerializedColoredQuoteNode;
|
|
18
|
+
}
|
|
19
|
+
export declare function $createColoredQuoteNode(color: COLOR): QuoteNode;
|
|
20
|
+
export declare function $isColoredQuoteNode(node: LexicalNode | null | undefined): node is ColoredQuoteNode;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { QuoteNode } from "@lexical/rich-text";
|
|
2
|
+
import { $applyNodeReplacement, } from "lexical";
|
|
3
|
+
import { addClassNamesToElement } from "@lexical/utils";
|
|
4
|
+
export class ColoredQuoteNode extends QuoteNode {
|
|
5
|
+
static getType() {
|
|
6
|
+
return "colored-quote";
|
|
7
|
+
}
|
|
8
|
+
static clone(node) {
|
|
9
|
+
return new ColoredQuoteNode(node.__color, node.__key);
|
|
10
|
+
}
|
|
11
|
+
constructor(color, key) {
|
|
12
|
+
super(key);
|
|
13
|
+
this.__color = color;
|
|
14
|
+
}
|
|
15
|
+
setColor(color) {
|
|
16
|
+
const self = this.getWritable();
|
|
17
|
+
self.__color = color;
|
|
18
|
+
}
|
|
19
|
+
getColor() {
|
|
20
|
+
const self = this.getLatest();
|
|
21
|
+
return self.__color;
|
|
22
|
+
}
|
|
23
|
+
createDOM(config) {
|
|
24
|
+
const element = document.createElement("blockquote");
|
|
25
|
+
addClassNamesToElement(element, config.theme.coloredQuote[this.__color]);
|
|
26
|
+
return element;
|
|
27
|
+
}
|
|
28
|
+
updateDOM(prevNode, dom) {
|
|
29
|
+
if (prevNode.__color !== this.__color) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
return super.updateDOM(prevNode, dom);
|
|
33
|
+
}
|
|
34
|
+
static importJSON(serializedNode) {
|
|
35
|
+
const node = $createColoredQuoteNode(serializedNode.color);
|
|
36
|
+
node.setFormat(serializedNode.format);
|
|
37
|
+
node.setIndent(serializedNode.indent);
|
|
38
|
+
node.setDirection(serializedNode.direction);
|
|
39
|
+
return node;
|
|
40
|
+
}
|
|
41
|
+
exportJSON() {
|
|
42
|
+
return Object.assign(Object.assign({}, super.exportJSON()), { type: "colored-quote", color: this.__color });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function $createColoredQuoteNode(color) {
|
|
46
|
+
return $applyNodeReplacement(new ColoredQuoteNode(color));
|
|
47
|
+
}
|
|
48
|
+
export function $isColoredQuoteNode(node) {
|
|
49
|
+
return node instanceof ColoredQuoteNode;
|
|
50
|
+
}
|
|
@@ -5,7 +5,7 @@ import plus from "./plus.svg";
|
|
|
5
5
|
import menu from "./menu.svg";
|
|
6
6
|
import styled from "@emotion/styled";
|
|
7
7
|
function ComponentAdder(props, ref) {
|
|
8
|
-
const { className, onPlusClick, onMenuClick, onMenuDragStart, onMenuDragEnd } = props;
|
|
8
|
+
const { className, onPlusClick, onMenuClick, onMenuDragStart, onMenuDragEnd, } = props;
|
|
9
9
|
const [editor] = useLexicalComposerContext();
|
|
10
10
|
return (_jsxs(Container, Object.assign({ ref: ref, className: className }, { children: [_jsx(PlusContainer, Object.assign({ onClick: onPlusClick }, { children: editor._editable && _jsx(PlusIcon, {}) })), _jsx(MenuContainer, Object.assign({ draggable: true, onClick: onMenuClick, onDragStart: onMenuDragStart, onDragEnd: onMenuDragEnd }, { children: editor._editable && _jsx(MenuIcon, {}) }))] })));
|
|
11
11
|
}
|
|
@@ -15,7 +15,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "@emotion/reac
|
|
|
15
15
|
/** @jsxImportSource @emotion/react */
|
|
16
16
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
17
17
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
18
|
-
import { $getNearestNodeFromDOMNode, $createParagraphNode, $isParagraphNode, $
|
|
18
|
+
import { $getNearestNodeFromDOMNode, $createParagraphNode, $isParagraphNode, $getSelection, $isRangeSelection, $createNodeSelection, $setSelection, $isNodeSelection, } from "lexical";
|
|
19
19
|
import ReactDOM, { createPortal } from "react-dom";
|
|
20
20
|
// LexicalNodeMenuPlugin는 특정 Node 옆에 메뉴를 노출시키는 플러그인
|
|
21
21
|
// 공식 문서에는 아무 내용도 없음...
|
|
@@ -26,7 +26,7 @@ import { ComponentPickerMenuList, getBaseOptions, } from "../ComponentPickerMenu
|
|
|
26
26
|
import { useFloatingMenu } from "./useFloatingMenu";
|
|
27
27
|
import ComponentAdder from "./ComponentAdder";
|
|
28
28
|
import styled from "@emotion/styled";
|
|
29
|
-
import {
|
|
29
|
+
import { useContextMenuOptions } from "./useContextMenuOptions";
|
|
30
30
|
import { InsertImageDialog } from "../ImagesPlugin/InsertImageDialog";
|
|
31
31
|
import { ZINDEX } from "../../../../utils/zIndex";
|
|
32
32
|
export const COMPONENT_ADDER_MENU_CLASSNAME = "component-adder-menu";
|
|
@@ -66,7 +66,7 @@ export function ComponentAdderPlugin(props) {
|
|
|
66
66
|
useEffect(() => {
|
|
67
67
|
const updateListener = () => {
|
|
68
68
|
editor.getEditorState().read(() => {
|
|
69
|
-
var _a;
|
|
69
|
+
var _a, _b;
|
|
70
70
|
if (nodeKey === null) {
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
@@ -77,15 +77,11 @@ export function ComponentAdderPlugin(props) {
|
|
|
77
77
|
// 비교할 때는 selection이 Nested 하게 있을 수 있어 Root 바로 아래의 Node를 찾아 비교합니다.
|
|
78
78
|
const nodes = selection.getNodes();
|
|
79
79
|
const isAllNodesNotMatched = nodes.every((node) => {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
// 선택된 노드 자체가 Root Node라면
|
|
83
|
-
// maybeTopNode가 undefined가 됩니다.
|
|
84
|
-
// 다른 노드를 선택한 것으로 간주하고 true(not matched)를 반환합니다.
|
|
85
|
-
if (!maybeTopNode) {
|
|
80
|
+
const topLevelElement = node.getTopLevelElement();
|
|
81
|
+
if (!topLevelElement) {
|
|
86
82
|
return true;
|
|
87
83
|
}
|
|
88
|
-
return
|
|
84
|
+
return topLevelElement.getKey() !== nodeKey;
|
|
89
85
|
});
|
|
90
86
|
if (isAllNodesNotMatched) {
|
|
91
87
|
setQuery("");
|
|
@@ -98,6 +94,13 @@ export function ComponentAdderPlugin(props) {
|
|
|
98
94
|
setQuery((_a = getTextUpToAnchor(selection)) !== null && _a !== void 0 ? _a : "");
|
|
99
95
|
}
|
|
100
96
|
}
|
|
97
|
+
else if ($isNodeSelection(selection)) {
|
|
98
|
+
const nodes = selection.getNodes();
|
|
99
|
+
if (((_b = nodes[0]) === null || _b === void 0 ? void 0 : _b.getKey()) !== nodeKey) {
|
|
100
|
+
setQuery("");
|
|
101
|
+
setNodeKey(null);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
101
104
|
else {
|
|
102
105
|
setQuery("");
|
|
103
106
|
setNodeKey(null);
|
|
@@ -123,6 +126,7 @@ export function ComponentAdderPlugin(props) {
|
|
|
123
126
|
return newResolves.filter((newResolve) => resolves.indexOf(newResolve) === -1);
|
|
124
127
|
});
|
|
125
128
|
});
|
|
129
|
+
const getContextMenuOptions = useContextMenuOptions();
|
|
126
130
|
const filteredOptions = options.filter((option) => {
|
|
127
131
|
const regex = new RegExp(query, "i");
|
|
128
132
|
return (regex.test(option.title) ||
|
|
@@ -187,12 +191,11 @@ export function ComponentAdderPlugin(props) {
|
|
|
187
191
|
if (!newNode) {
|
|
188
192
|
return;
|
|
189
193
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
194
|
+
// Set a node selection
|
|
195
|
+
const nodeSelection = $createNodeSelection();
|
|
196
|
+
// Add a node key to the selection.
|
|
197
|
+
nodeSelection.add(newNode.getKey());
|
|
198
|
+
$setSelection(nodeSelection);
|
|
196
199
|
const contextMenuOptions = getContextMenuOptions(editor, newNode, setOpen);
|
|
197
200
|
setOptions(contextMenuOptions);
|
|
198
201
|
if (nodeKey === null) {
|
|
@@ -2,12 +2,112 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
/**
|
|
3
3
|
* Context Menu (:: 버튼)
|
|
4
4
|
*/
|
|
5
|
-
import { $
|
|
5
|
+
import { $createParagraphNode, ParagraphNode, } from "lexical";
|
|
6
6
|
import { ComponentPickerOption, getBaseOptions, } from "../ComponentPickerMenuPlugin";
|
|
7
|
-
import { $createHeadingNode, HeadingNode } from "@lexical/rich-text";
|
|
7
|
+
import { $createHeadingNode, $createQuoteNode, HeadingNode, } from "@lexical/rich-text";
|
|
8
8
|
import { $setBlocksType } from "@lexical/selection";
|
|
9
9
|
import { ListItemNode, ListNode, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, } from "@lexical/list";
|
|
10
|
-
import { H1Icon, H2Icon, H3Icon, CloseFillIcon, ListUnorderedIcon, ListOrderedIcon, } from "../../../../icons";
|
|
10
|
+
import { H1Icon, H2Icon, H3Icon, CloseFillIcon, ListUnorderedIcon, ListOrderedIcon, CodeViewIcon, DoubleQuotesLIcon, ImageLineIcon, SeparatorIcon, TextIcon, } from "../../../../icons";
|
|
11
|
+
import { INSERT_HORIZONTAL_RULE_COMMAND } from "@lexical/react/LexicalHorizontalRuleNode";
|
|
12
|
+
import { $createCodeNode } from "@lexical/code";
|
|
13
|
+
function getParagraphContextOptions(editor, node, setOpen) {
|
|
14
|
+
return [
|
|
15
|
+
new ComponentPickerOption("본문", {
|
|
16
|
+
icon: _jsx(TextIcon, {}),
|
|
17
|
+
keywords: ["normal", "paragraph", "p", "text", "본문", "단락", "내용"],
|
|
18
|
+
onSelect: () => editor.update(() => {
|
|
19
|
+
const selection = node.selectStart();
|
|
20
|
+
$setBlocksType(selection, () => $createParagraphNode());
|
|
21
|
+
}),
|
|
22
|
+
}),
|
|
23
|
+
...[1, 2, 3].map((n) => {
|
|
24
|
+
const titleMap = {
|
|
25
|
+
1: "큰 제목",
|
|
26
|
+
2: "중간 제목",
|
|
27
|
+
3: "작은 제목",
|
|
28
|
+
};
|
|
29
|
+
const iconMap = {
|
|
30
|
+
1: _jsx(H1Icon, {}),
|
|
31
|
+
2: _jsx(H2Icon, {}),
|
|
32
|
+
3: _jsx(H3Icon, {}),
|
|
33
|
+
};
|
|
34
|
+
return new ComponentPickerOption(titleMap[n], {
|
|
35
|
+
icon: iconMap[n],
|
|
36
|
+
keywords: ["heading", "header", `h${n}`, titleMap[n]],
|
|
37
|
+
onSelect: () => editor.update(() => {
|
|
38
|
+
const selection = node.selectStart();
|
|
39
|
+
$setBlocksType(selection, () => $createHeadingNode(`h${n}`));
|
|
40
|
+
}),
|
|
41
|
+
});
|
|
42
|
+
}),
|
|
43
|
+
new ComponentPickerOption("일반 목록", {
|
|
44
|
+
icon: _jsx(ListUnorderedIcon, {}),
|
|
45
|
+
keywords: ["bulleted list", "unordered list", "ul"],
|
|
46
|
+
onSelect: () => {
|
|
47
|
+
node.selectStart();
|
|
48
|
+
editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);
|
|
49
|
+
},
|
|
50
|
+
}),
|
|
51
|
+
new ComponentPickerOption("숫자 목록", {
|
|
52
|
+
icon: _jsx(ListOrderedIcon, {}),
|
|
53
|
+
keywords: ["numbered list", "ordered list", "ol"],
|
|
54
|
+
onSelect: () => {
|
|
55
|
+
node.selectStart();
|
|
56
|
+
editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined);
|
|
57
|
+
},
|
|
58
|
+
}),
|
|
59
|
+
new ComponentPickerOption("인용 블록", {
|
|
60
|
+
icon: _jsx(DoubleQuotesLIcon, {}),
|
|
61
|
+
keywords: ["block quote"],
|
|
62
|
+
onSelect: () => editor.update(() => {
|
|
63
|
+
const selection = node.selectStart();
|
|
64
|
+
$setBlocksType(selection, () => $createQuoteNode());
|
|
65
|
+
}),
|
|
66
|
+
}),
|
|
67
|
+
new ComponentPickerOption("코드 블록", {
|
|
68
|
+
icon: _jsx(CodeViewIcon, {}),
|
|
69
|
+
keywords: ["javascript", "python", "js", "codeblock"],
|
|
70
|
+
onSelect: () => editor.update(() => {
|
|
71
|
+
const selection = node.selectStart();
|
|
72
|
+
if (selection.isCollapsed()) {
|
|
73
|
+
$setBlocksType(selection, () => $createCodeNode());
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// Will this ever happen?
|
|
77
|
+
const textContent = selection.getTextContent();
|
|
78
|
+
const codeNode = $createCodeNode();
|
|
79
|
+
selection.insertNodes([codeNode]);
|
|
80
|
+
selection.insertRawText(textContent);
|
|
81
|
+
}
|
|
82
|
+
}),
|
|
83
|
+
}),
|
|
84
|
+
new ComponentPickerOption("구분선", {
|
|
85
|
+
icon: _jsx(SeparatorIcon, {}),
|
|
86
|
+
keywords: ["horizontal rule", "divider", "hr"],
|
|
87
|
+
onSelect: () => {
|
|
88
|
+
node.selectStart();
|
|
89
|
+
editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined);
|
|
90
|
+
},
|
|
91
|
+
}),
|
|
92
|
+
new ComponentPickerOption("이미지", {
|
|
93
|
+
icon: _jsx(ImageLineIcon, {}),
|
|
94
|
+
keywords: ["image", "photo", "picture", "file"],
|
|
95
|
+
onSelect: () => {
|
|
96
|
+
node.selectStart();
|
|
97
|
+
setOpen(true);
|
|
98
|
+
},
|
|
99
|
+
}),
|
|
100
|
+
new ComponentPickerOption("블록 삭제", {
|
|
101
|
+
icon: _jsx(CloseFillIcon, {}),
|
|
102
|
+
keywords: [],
|
|
103
|
+
onSelect: () => {
|
|
104
|
+
editor.update(() => {
|
|
105
|
+
node.remove();
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
}),
|
|
109
|
+
];
|
|
110
|
+
}
|
|
11
111
|
function getHeadingContextMenuOptions(editor, node, setOpen) {
|
|
12
112
|
return [
|
|
13
113
|
...[1, 2, 3].map((n) => {
|
|
@@ -25,10 +125,8 @@ function getHeadingContextMenuOptions(editor, node, setOpen) {
|
|
|
25
125
|
icon: iconMap[n],
|
|
26
126
|
keywords: ["heading", "header", `h${n}`, titleMap[n]],
|
|
27
127
|
onSelect: () => editor.update(() => {
|
|
28
|
-
const selection =
|
|
29
|
-
|
|
30
|
-
$setBlocksType(selection, () => $createHeadingNode(`h${n}`));
|
|
31
|
-
}
|
|
128
|
+
const selection = node.selectStart();
|
|
129
|
+
$setBlocksType(selection, () => $createHeadingNode(`h${n}`));
|
|
32
130
|
}),
|
|
33
131
|
});
|
|
34
132
|
}),
|
|
@@ -48,12 +146,18 @@ function getListContextMenuOptions(editor, node, setOpen) {
|
|
|
48
146
|
new ComponentPickerOption("일반 목록", {
|
|
49
147
|
icon: _jsx(ListUnorderedIcon, {}),
|
|
50
148
|
keywords: ["bulleted list", "unordered list", "ul"],
|
|
51
|
-
onSelect: () =>
|
|
149
|
+
onSelect: () => {
|
|
150
|
+
node.selectStart();
|
|
151
|
+
editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);
|
|
152
|
+
},
|
|
52
153
|
}),
|
|
53
154
|
new ComponentPickerOption("숫자 목록", {
|
|
54
155
|
icon: _jsx(ListOrderedIcon, {}),
|
|
55
156
|
keywords: ["numbered list", "ordered list", "ol"],
|
|
56
|
-
onSelect: () =>
|
|
157
|
+
onSelect: () => {
|
|
158
|
+
node.selectStart();
|
|
159
|
+
editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined);
|
|
160
|
+
},
|
|
57
161
|
}),
|
|
58
162
|
new ComponentPickerOption("블록 삭제", {
|
|
59
163
|
icon: _jsx(CloseFillIcon, {}),
|
|
@@ -67,7 +171,10 @@ function getListContextMenuOptions(editor, node, setOpen) {
|
|
|
67
171
|
];
|
|
68
172
|
}
|
|
69
173
|
export function getContextMenuOptions(editor, node, setOpen) {
|
|
70
|
-
if (node instanceof
|
|
174
|
+
if (node instanceof ParagraphNode) {
|
|
175
|
+
return getParagraphContextOptions(editor, node, setOpen);
|
|
176
|
+
}
|
|
177
|
+
else if (node instanceof HeadingNode) {
|
|
71
178
|
return getHeadingContextMenuOptions(editor, node, setOpen);
|
|
72
179
|
}
|
|
73
180
|
else if (node instanceof ListNode || node instanceof ListItemNode) {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Menu (:: 버튼)
|
|
3
|
+
*/
|
|
4
|
+
import { LexicalEditor, LexicalNode } from "lexical";
|
|
5
|
+
import { ComponentPickerOption } from "../ComponentPickerMenuPlugin";
|
|
6
|
+
export declare function useContextMenuOptions(): (editor: LexicalEditor, node: LexicalNode, setOpen: (open: boolean) => void) => ComponentPickerOption[];
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Context Menu (:: 버튼)
|
|
4
|
+
*/
|
|
5
|
+
import { $getSelection, $isRangeSelection, } from "lexical";
|
|
6
|
+
import { ComponentPickerOption, getBaseOptions, } from "../ComponentPickerMenuPlugin";
|
|
7
|
+
import { $createHeadingNode, HeadingNode } from "@lexical/rich-text";
|
|
8
|
+
import { $setBlocksType } from "@lexical/selection";
|
|
9
|
+
import { ListItemNode, ListNode, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, } from "@lexical/list";
|
|
10
|
+
import { H1Icon, H2Icon, H3Icon, CloseFillIcon, ListUnorderedIcon, ListOrderedIcon, InputMethodLineIcon, } from "../../../../icons";
|
|
11
|
+
import { $isColoredQuoteNode, } from "../../nodes/ColoredQuoteNode";
|
|
12
|
+
import { useTheme } from "@emotion/react";
|
|
13
|
+
import { css } from "@emotion/css";
|
|
14
|
+
function getHeadingContextMenuOptions(editor, theme, node, setOpen) {
|
|
15
|
+
return [
|
|
16
|
+
...[1, 2, 3].map((n) => {
|
|
17
|
+
const titleMap = {
|
|
18
|
+
1: "큰 제목",
|
|
19
|
+
2: "중간 제목",
|
|
20
|
+
3: "작은 제목",
|
|
21
|
+
};
|
|
22
|
+
const iconMap = {
|
|
23
|
+
1: _jsx(H1Icon, {}),
|
|
24
|
+
2: _jsx(H2Icon, {}),
|
|
25
|
+
3: _jsx(H3Icon, {}),
|
|
26
|
+
};
|
|
27
|
+
return new ComponentPickerOption(titleMap[n], {
|
|
28
|
+
icon: iconMap[n],
|
|
29
|
+
keywords: ["heading", "header", `h${n}`, titleMap[n]],
|
|
30
|
+
onSelect: () => editor.update(() => {
|
|
31
|
+
const selection = $getSelection();
|
|
32
|
+
if ($isRangeSelection(selection)) {
|
|
33
|
+
$setBlocksType(selection, () => $createHeadingNode(`h${n}`));
|
|
34
|
+
}
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
}),
|
|
38
|
+
new ComponentPickerOption("블록 삭제", {
|
|
39
|
+
icon: _jsx(CloseFillIcon, {}),
|
|
40
|
+
keywords: [],
|
|
41
|
+
onSelect: () => {
|
|
42
|
+
editor.update(() => {
|
|
43
|
+
node.remove();
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
}),
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
function getListContextMenuOptions(editor, theme, node, setOpen) {
|
|
50
|
+
return [
|
|
51
|
+
new ComponentPickerOption("일반 목록", {
|
|
52
|
+
icon: _jsx(ListUnorderedIcon, {}),
|
|
53
|
+
keywords: ["bulleted list", "unordered list", "ul"],
|
|
54
|
+
onSelect: () => editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined),
|
|
55
|
+
}),
|
|
56
|
+
new ComponentPickerOption("숫자 목록", {
|
|
57
|
+
icon: _jsx(ListOrderedIcon, {}),
|
|
58
|
+
keywords: ["numbered list", "ordered list", "ol"],
|
|
59
|
+
onSelect: () => editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined),
|
|
60
|
+
}),
|
|
61
|
+
new ComponentPickerOption("블록 삭제", {
|
|
62
|
+
icon: _jsx(CloseFillIcon, {}),
|
|
63
|
+
keywords: [],
|
|
64
|
+
onSelect: () => {
|
|
65
|
+
editor.update(() => {
|
|
66
|
+
node.remove();
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
}),
|
|
70
|
+
];
|
|
71
|
+
}
|
|
72
|
+
function getColoredQuoteContextMenuOptions(editor, theme, node, setOpen) {
|
|
73
|
+
return [
|
|
74
|
+
new ComponentPickerOption("회색", {
|
|
75
|
+
icon: (_jsx(InputMethodLineIcon, { color: theme.color.container.marbleOnContainer })),
|
|
76
|
+
iconContainerClassName: css `
|
|
77
|
+
background: ${theme.color.container.marbleContainer};
|
|
78
|
+
`,
|
|
79
|
+
keywords: ["grey", "gray"],
|
|
80
|
+
onSelect: () => {
|
|
81
|
+
editor.update(() => {
|
|
82
|
+
node.setColor("grey");
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
}),
|
|
86
|
+
new ComponentPickerOption("빨간색", {
|
|
87
|
+
icon: (_jsx(InputMethodLineIcon, { color: theme.color.container.dangerOnContainer })),
|
|
88
|
+
iconContainerClassName: css `
|
|
89
|
+
background: ${theme.color.container.dangerContainer};
|
|
90
|
+
`,
|
|
91
|
+
keywords: ["red"],
|
|
92
|
+
onSelect: () => {
|
|
93
|
+
editor.update(() => {
|
|
94
|
+
node.setColor("red");
|
|
95
|
+
});
|
|
96
|
+
},
|
|
97
|
+
}),
|
|
98
|
+
new ComponentPickerOption("노란색", {
|
|
99
|
+
icon: (_jsx(InputMethodLineIcon, { color: theme.color.container.warningOnContainer })),
|
|
100
|
+
iconContainerClassName: css `
|
|
101
|
+
background: ${theme.color.container.warningContainer};
|
|
102
|
+
`,
|
|
103
|
+
keywords: ["yellow"],
|
|
104
|
+
onSelect: () => {
|
|
105
|
+
editor.update(() => {
|
|
106
|
+
node.setColor("yellow");
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
}),
|
|
110
|
+
new ComponentPickerOption("파란색", {
|
|
111
|
+
icon: (_jsx(InputMethodLineIcon, { color: theme.color.container.primaryOnContainer })),
|
|
112
|
+
iconContainerClassName: css `
|
|
113
|
+
background: ${theme.color.container.primaryContainer};
|
|
114
|
+
`,
|
|
115
|
+
keywords: ["blue"],
|
|
116
|
+
onSelect: () => {
|
|
117
|
+
editor.update(() => {
|
|
118
|
+
node.setColor("blue");
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
}),
|
|
122
|
+
new ComponentPickerOption("초록색", {
|
|
123
|
+
icon: (_jsx(InputMethodLineIcon, { color: theme.color.container.successOnContainer })),
|
|
124
|
+
iconContainerClassName: css `
|
|
125
|
+
background: ${theme.color.container.successContainer};
|
|
126
|
+
`,
|
|
127
|
+
keywords: ["green"],
|
|
128
|
+
onSelect: () => {
|
|
129
|
+
editor.update(() => {
|
|
130
|
+
node.setColor("green");
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
}),
|
|
134
|
+
new ComponentPickerOption("블록 삭제", {
|
|
135
|
+
icon: _jsx(CloseFillIcon, {}),
|
|
136
|
+
keywords: [],
|
|
137
|
+
onSelect: () => {
|
|
138
|
+
editor.update(() => {
|
|
139
|
+
node.remove();
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
}),
|
|
143
|
+
];
|
|
144
|
+
}
|
|
145
|
+
export function useContextMenuOptions() {
|
|
146
|
+
const theme = useTheme();
|
|
147
|
+
return (editor, node, setOpen) => {
|
|
148
|
+
if (node instanceof HeadingNode) {
|
|
149
|
+
return getHeadingContextMenuOptions(editor, theme, node, setOpen);
|
|
150
|
+
}
|
|
151
|
+
else if (node instanceof ListNode || node instanceof ListItemNode) {
|
|
152
|
+
return getListContextMenuOptions(editor, theme, node, setOpen);
|
|
153
|
+
}
|
|
154
|
+
else if ($isColoredQuoteNode(node)) {
|
|
155
|
+
return getColoredQuoteContextMenuOptions(editor, theme, node, setOpen);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
return [
|
|
159
|
+
...getBaseOptions(editor, setOpen),
|
|
160
|
+
new ComponentPickerOption("블록 삭제", {
|
|
161
|
+
icon: _jsx(CloseFillIcon, {}),
|
|
162
|
+
keywords: [],
|
|
163
|
+
onSelect: () => {
|
|
164
|
+
editor.update(() => {
|
|
165
|
+
node.remove();
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
}),
|
|
169
|
+
];
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
package/dist/patterns/LexicalEditor/plugins/ComponentPickerMenuPlugin/ComponentPickerMenuItem.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
|
|
|
2
2
|
import styled from "@emotion/styled";
|
|
3
3
|
export function ComponentPickerMenuItem(props) {
|
|
4
4
|
const { index, isSelected, onClick, onMouseEnter, option } = props;
|
|
5
|
-
return (_jsxs(ItemContainer, Object.assign({ tabIndex: -1, ref: option.setRefElement, role: "option", "aria-selected": isSelected, id: "typeahead-item-" + index, onMouseEnter: onMouseEnter, onClick: onClick, isSelected: isSelected }, { children: [_jsx(IconContainer, { children: option.icon }), _jsx(Title, { children: option.title })] }), option.key));
|
|
5
|
+
return (_jsxs(ItemContainer, Object.assign({ tabIndex: -1, ref: option.setRefElement, role: "option", "aria-selected": isSelected, id: "typeahead-item-" + index, onMouseEnter: onMouseEnter, onClick: onClick, isSelected: isSelected }, { children: [_jsx(IconContainer, Object.assign({ className: option.iconContainerClassName }, { children: option.icon })), _jsx(Title, { children: option.title })] }), option.key));
|
|
6
6
|
}
|
|
7
7
|
const ItemContainer = styled.li `
|
|
8
8
|
display: flex;
|
|
@@ -10,6 +10,7 @@ const ItemContainer = styled.li `
|
|
|
10
10
|
align-items: center;
|
|
11
11
|
gap: 10px;
|
|
12
12
|
width: 100%;
|
|
13
|
+
cursor: pointer;
|
|
13
14
|
|
|
14
15
|
${({ isSelected }) => isSelected && "background: #eee;"}
|
|
15
16
|
`;
|
package/dist/patterns/LexicalEditor/plugins/ComponentPickerMenuPlugin/ComponentPickerMenuPlugin.d.ts
CHANGED
|
@@ -6,17 +6,19 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
/** @jsxImportSource @emotion/react */
|
|
9
|
-
/// <reference types="react" />
|
|
10
9
|
import { MenuOption } from "@lexical/react/LexicalTypeaheadMenuPlugin";
|
|
11
10
|
import { LexicalEditor } from "lexical";
|
|
11
|
+
import { ReactElement } from "react";
|
|
12
12
|
export declare class ComponentPickerOption extends MenuOption {
|
|
13
13
|
title: string;
|
|
14
|
-
icon?:
|
|
14
|
+
icon?: ReactElement;
|
|
15
|
+
iconContainerClassName?: string;
|
|
15
16
|
keywords: Array<string>;
|
|
16
17
|
keyboardShortcut?: string;
|
|
17
18
|
onSelect: (queryString: string) => void;
|
|
18
19
|
constructor(title: string, options: {
|
|
19
|
-
icon?:
|
|
20
|
+
icon?: ReactElement;
|
|
21
|
+
iconContainerClassName?: string;
|
|
20
22
|
keywords?: Array<string>;
|
|
21
23
|
keyboardShortcut?: string;
|
|
22
24
|
onSelect: (queryString: string) => void;
|
package/dist/patterns/LexicalEditor/plugins/ComponentPickerMenuPlugin/ComponentPickerMenuPlugin.js
CHANGED
|
@@ -32,6 +32,7 @@ export class ComponentPickerOption extends MenuOption {
|
|
|
32
32
|
this.title = title;
|
|
33
33
|
this.keywords = options.keywords || [];
|
|
34
34
|
this.icon = options.icon;
|
|
35
|
+
this.iconContainerClassName = options.iconContainerClassName;
|
|
35
36
|
this.keyboardShortcut = options.keyboardShortcut;
|
|
36
37
|
this.onSelect = options.onSelect.bind(this);
|
|
37
38
|
}
|
|
@@ -7,7 +7,7 @@ import { $isLinkNode, TOGGLE_LINK_COMMAND } from "@lexical/link";
|
|
|
7
7
|
import { setFloatingElemPositionForLinkEditor } from "../../utils/setFloatingElemPositionForLinkEditor";
|
|
8
8
|
import { $findMatchingParent, mergeRegister } from "@lexical/utils";
|
|
9
9
|
import styled from "@emotion/styled";
|
|
10
|
-
import { CloseFillIcon, CheckLineIcon, EditLineIcon, DeleteBinLineIcon } from "../../../../icons";
|
|
10
|
+
import { CloseFillIcon, CheckLineIcon, EditLineIcon, DeleteBinLineIcon, } from "../../../../icons";
|
|
11
11
|
import Input from "../../../../components/Input";
|
|
12
12
|
export function FloatingLinkEditor(props) {
|
|
13
13
|
const { editor, isLink, setIsLink, anchorElem, isLinkEditMode, setIsLinkEditMode, } = props;
|
|
@@ -6,7 +6,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*
|
|
8
8
|
*/
|
|
9
|
-
import { $isAutoLinkNode, $isLinkNode
|
|
9
|
+
import { $isAutoLinkNode, $isLinkNode } from "@lexical/link";
|
|
10
10
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
11
11
|
import { $findMatchingParent, mergeRegister } from "@lexical/utils";
|
|
12
12
|
import { $getSelection, $isRangeSelection, CLICK_COMMAND, COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_LOW, SELECTION_CHANGE_COMMAND, } from "lexical";
|
|
@@ -2,6 +2,13 @@ import { Theme } from "@emotion/react";
|
|
|
2
2
|
export declare function getTheme(theme: Theme): {
|
|
3
3
|
paragraph: string;
|
|
4
4
|
quote: string;
|
|
5
|
+
coloredQuote: {
|
|
6
|
+
grey: string;
|
|
7
|
+
red: string;
|
|
8
|
+
yellow: string;
|
|
9
|
+
blue: string;
|
|
10
|
+
green: string;
|
|
11
|
+
};
|
|
5
12
|
heading: {
|
|
6
13
|
h1: string;
|
|
7
14
|
h2: string;
|
|
@@ -23,8 +23,80 @@ export function getTheme(theme) {
|
|
|
23
23
|
|
|
24
24
|
margin: 16px 0;
|
|
25
25
|
padding-left: 12px;
|
|
26
|
-
border-left:
|
|
26
|
+
border-left: 4px solid ${theme.color.container.marbleContainer};
|
|
27
27
|
`,
|
|
28
|
+
coloredQuote: {
|
|
29
|
+
grey: css `
|
|
30
|
+
color: ${theme.color.container.marbleOnContainer};
|
|
31
|
+
|
|
32
|
+
/* Default/Paragraph/14px-Rg */
|
|
33
|
+
font-family: ${theme.fontFamily.ui};
|
|
34
|
+
font-size: 14px;
|
|
35
|
+
font-style: normal;
|
|
36
|
+
font-weight: 400;
|
|
37
|
+
line-height: 20px; /* 142.857% */
|
|
38
|
+
|
|
39
|
+
margin: 16px 0;
|
|
40
|
+
padding-left: 12px;
|
|
41
|
+
border-left: 4px solid ${theme.color.container.marbleContainer};
|
|
42
|
+
`,
|
|
43
|
+
red: css `
|
|
44
|
+
color: ${theme.color.container.dangerOnContainer};
|
|
45
|
+
|
|
46
|
+
/* Default/Paragraph/14px-Rg */
|
|
47
|
+
font-family: ${theme.fontFamily.ui};
|
|
48
|
+
font-size: 14px;
|
|
49
|
+
font-style: normal;
|
|
50
|
+
font-weight: 400;
|
|
51
|
+
line-height: 20px; /* 142.857% */
|
|
52
|
+
|
|
53
|
+
margin: 16px 0;
|
|
54
|
+
padding-left: 12px;
|
|
55
|
+
border-left: 4px solid ${theme.color.container.dangerContainer};
|
|
56
|
+
`,
|
|
57
|
+
yellow: css `
|
|
58
|
+
color: ${theme.color.container.warningOnContainer};
|
|
59
|
+
|
|
60
|
+
/* Default/Paragraph/14px-Rg */
|
|
61
|
+
font-family: ${theme.fontFamily.ui};
|
|
62
|
+
font-size: 14px;
|
|
63
|
+
font-style: normal;
|
|
64
|
+
font-weight: 400;
|
|
65
|
+
line-height: 20px; /* 142.857% */
|
|
66
|
+
|
|
67
|
+
margin: 16px 0;
|
|
68
|
+
padding-left: 12px;
|
|
69
|
+
border-left: 4px solid ${theme.color.container.warningContainer};
|
|
70
|
+
`,
|
|
71
|
+
blue: css `
|
|
72
|
+
color: ${theme.color.container.primaryOnContainer};
|
|
73
|
+
|
|
74
|
+
/* Default/Paragraph/14px-Rg */
|
|
75
|
+
font-family: ${theme.fontFamily.ui};
|
|
76
|
+
font-size: 14px;
|
|
77
|
+
font-style: normal;
|
|
78
|
+
font-weight: 400;
|
|
79
|
+
line-height: 20px; /* 142.857% */
|
|
80
|
+
|
|
81
|
+
margin: 16px 0;
|
|
82
|
+
padding-left: 12px;
|
|
83
|
+
border-left: 4px solid ${theme.color.container.primaryContainer};
|
|
84
|
+
`,
|
|
85
|
+
green: css `
|
|
86
|
+
color: ${theme.color.container.successOnContainer};
|
|
87
|
+
|
|
88
|
+
/* Default/Paragraph/14px-Rg */
|
|
89
|
+
font-family: ${theme.fontFamily.ui};
|
|
90
|
+
font-size: 14px;
|
|
91
|
+
font-style: normal;
|
|
92
|
+
font-weight: 400;
|
|
93
|
+
line-height: 20px; /* 142.857% */
|
|
94
|
+
|
|
95
|
+
margin: 16px 0;
|
|
96
|
+
padding-left: 12px;
|
|
97
|
+
border-left: 4px solid ${theme.color.container.successContainer};
|
|
98
|
+
`,
|
|
99
|
+
},
|
|
28
100
|
heading: {
|
|
29
101
|
h1: css `
|
|
30
102
|
color: ${theme.color.foreground.neutralBase};
|