sh-ui-cli 0.52.1 → 0.52.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/data/changelog/versions.json +14 -0
  2. package/data/registry/react/components/_smoke/vanilla-extract.test.ts +33 -0
  3. package/data/registry/react/components/input/styles.css.ts +6 -6
  4. package/data/registry/react/registry.json +35 -852
  5. package/package.json +1 -1
  6. package/src/api.d.ts +3 -4
  7. package/src/constants.js +9 -5
  8. package/src/mcp.mjs +0 -1
  9. package/data/registry/react/components/accordion/index.vanilla-extract.tsx +0 -97
  10. package/data/registry/react/components/accordion/styles.css.ts +0 -131
  11. package/data/registry/react/components/avatar/index.vanilla-extract.tsx +0 -73
  12. package/data/registry/react/components/avatar/styles.css.ts +0 -68
  13. package/data/registry/react/components/badge/index.vanilla-extract.tsx +0 -40
  14. package/data/registry/react/components/badge/styles.css.ts +0 -71
  15. package/data/registry/react/components/breadcrumb/index.vanilla-extract.tsx +0 -152
  16. package/data/registry/react/components/breadcrumb/styles.css.ts +0 -95
  17. package/data/registry/react/components/calendar/index.vanilla-extract.tsx +0 -806
  18. package/data/registry/react/components/calendar/styles.css.ts +0 -250
  19. package/data/registry/react/components/carousel/index.vanilla-extract.tsx +0 -430
  20. package/data/registry/react/components/carousel/styles.css.ts +0 -169
  21. package/data/registry/react/components/checkbox/index.vanilla-extract.tsx +0 -96
  22. package/data/registry/react/components/checkbox/styles.css.ts +0 -74
  23. package/data/registry/react/components/code-editor/index.vanilla-extract.tsx +0 -230
  24. package/data/registry/react/components/code-editor/styles.css.ts +0 -97
  25. package/data/registry/react/components/code-panel/index.vanilla-extract.tsx +0 -191
  26. package/data/registry/react/components/code-panel/styles.css.ts +0 -151
  27. package/data/registry/react/components/color-picker/index.vanilla-extract.tsx +0 -467
  28. package/data/registry/react/components/color-picker/styles.css.ts +0 -169
  29. package/data/registry/react/components/combobox/index.vanilla-extract.tsx +0 -165
  30. package/data/registry/react/components/combobox/styles.css.ts +0 -174
  31. package/data/registry/react/components/context-menu/index.vanilla-extract.tsx +0 -251
  32. package/data/registry/react/components/context-menu/styles.css.ts +0 -167
  33. package/data/registry/react/components/date-picker/index.vanilla-extract.tsx +0 -520
  34. package/data/registry/react/components/date-picker/styles.css.ts +0 -111
  35. package/data/registry/react/components/dialog/index.vanilla-extract.tsx +0 -95
  36. package/data/registry/react/components/dialog/styles.css.ts +0 -140
  37. package/data/registry/react/components/dropdown-menu/index.vanilla-extract.tsx +0 -255
  38. package/data/registry/react/components/dropdown-menu/styles.css.ts +0 -175
  39. package/data/registry/react/components/file-upload/index.vanilla-extract.tsx +0 -487
  40. package/data/registry/react/components/file-upload/styles.css.ts +0 -193
  41. package/data/registry/react/components/form/index.vanilla-extract.tsx +0 -61
  42. package/data/registry/react/components/form/styles.css.ts +0 -56
  43. package/data/registry/react/components/header/index.vanilla-extract.tsx +0 -805
  44. package/data/registry/react/components/header/styles.css.ts +0 -413
  45. package/data/registry/react/components/label/index.vanilla-extract.tsx +0 -52
  46. package/data/registry/react/components/label/styles.css.ts +0 -141
  47. package/data/registry/react/components/markdown-editor/index.vanilla-extract.tsx +0 -119
  48. package/data/registry/react/components/markdown-editor/styles.css.ts +0 -231
  49. package/data/registry/react/components/menubar/index.vanilla-extract.tsx +0 -32
  50. package/data/registry/react/components/menubar/styles.css.ts +0 -53
  51. package/data/registry/react/components/numeric-input/index.vanilla-extract.tsx +0 -148
  52. package/data/registry/react/components/numeric-input/styles.css.ts +0 -65
  53. package/data/registry/react/components/page-toc/index.vanilla-extract.tsx +0 -174
  54. package/data/registry/react/components/page-toc/styles.css.ts +0 -97
  55. package/data/registry/react/components/pagination/index.vanilla-extract.tsx +0 -269
  56. package/data/registry/react/components/pagination/styles.css.ts +0 -113
  57. package/data/registry/react/components/popover/index.vanilla-extract.tsx +0 -113
  58. package/data/registry/react/components/popover/styles.css.ts +0 -78
  59. package/data/registry/react/components/progress/index.vanilla-extract.tsx +0 -54
  60. package/data/registry/react/components/progress/styles.css.ts +0 -53
  61. package/data/registry/react/components/radio/index.vanilla-extract.tsx +0 -65
  62. package/data/registry/react/components/radio/styles.css.ts +0 -79
  63. package/data/registry/react/components/rich-text-editor/index.vanilla-extract.tsx +0 -348
  64. package/data/registry/react/components/rich-text-editor/styles.css.ts +0 -243
  65. package/data/registry/react/components/select/index.vanilla-extract.tsx +0 -234
  66. package/data/registry/react/components/select/styles.css.ts +0 -225
  67. package/data/registry/react/components/separator/index.vanilla-extract.tsx +0 -46
  68. package/data/registry/react/components/separator/styles.css.ts +0 -24
  69. package/data/registry/react/components/sidebar/index.vanilla-extract.tsx +0 -1067
  70. package/data/registry/react/components/sidebar/styles.css.ts +0 -578
  71. package/data/registry/react/components/skeleton/index.vanilla-extract.tsx +0 -22
  72. package/data/registry/react/components/skeleton/styles.css.ts +0 -30
  73. package/data/registry/react/components/slider/index.vanilla-extract.tsx +0 -298
  74. package/data/registry/react/components/slider/styles.css.ts +0 -75
  75. package/data/registry/react/components/spinner/index.vanilla-extract.tsx +0 -38
  76. package/data/registry/react/components/spinner/styles.css.ts +0 -60
  77. package/data/registry/react/components/switch/index.vanilla-extract.tsx +0 -39
  78. package/data/registry/react/components/switch/styles.css.ts +0 -87
  79. package/data/registry/react/components/tabs/index.vanilla-extract.tsx +0 -91
  80. package/data/registry/react/components/tabs/styles.css.ts +0 -145
  81. package/data/registry/react/components/textarea/index.vanilla-extract.tsx +0 -23
  82. package/data/registry/react/components/textarea/styles.css.ts +0 -55
  83. package/data/registry/react/components/toast/index.vanilla-extract.tsx +0 -258
  84. package/data/registry/react/components/toast/styles.css.ts +0 -307
  85. package/data/registry/react/components/toggle/index.vanilla-extract.tsx +0 -131
  86. package/data/registry/react/components/toggle/styles.css.ts +0 -109
  87. package/data/registry/react/components/tooltip/index.vanilla-extract.tsx +0 -83
  88. package/data/registry/react/components/tooltip/styles.css.ts +0 -59
@@ -1,348 +0,0 @@
1
- "use client";
2
-
3
- import { useCallback, useEffect } from "react";
4
- import { useEditor, EditorContent, type Editor } from "@tiptap/react";
5
- import StarterKit from "@tiptap/starter-kit";
6
- import Placeholder from "@tiptap/extension-placeholder";
7
- import Link from "@tiptap/extension-link";
8
- import { cn } from "@SH_UI_UTILS@";
9
- import {
10
- BoldIcon,
11
- ItalicIcon,
12
- StrikethroughIcon,
13
- Heading1Icon,
14
- Heading2Icon,
15
- Heading3Icon,
16
- ListIcon,
17
- ListOrderedIcon,
18
- QuoteIcon,
19
- CodeIcon,
20
- Code2Icon,
21
- LinkIcon,
22
- MinusIcon,
23
- Undo2Icon,
24
- Redo2Icon,
25
- } from "lucide-react";
26
- import { byKey, rte, rte__toolbar, rte__btn, rte__sep, rte__viewport, rte__content, rteIsEmpty } from "./styles.css";
27
-
28
- export interface RichTextEditorProps {
29
- /**
30
- * Controlled — 현재 HTML. 명시 시 외부 상태가 진실원천이 되고 onChange 로 갱신한다.
31
- * 미지정이면 uncontrolled — Tiptap editor 가 자체 doc 으로 동작.
32
- */
33
- value?: string;
34
- /**
35
- * Uncontrolled 초기 HTML. value 미지정 시에만 사용.
36
- * @default ""
37
- */
38
- defaultValue?: string;
39
- /** 본문이 바뀔 때마다 호출 (controlled · uncontrolled 모두). HTML 문자열을 그대로 넘긴다. */
40
- onChange?: (html: string) => void;
41
- /** 비어 있을 때 표시할 placeholder. */
42
- placeholder?: string;
43
- /** 읽기 전용. 키 입력·툴바 차단. */
44
- readOnly?: boolean;
45
- /** 상단 툴바 숨기기. 본문 영역만 렌더. */
46
- hideToolbar?: boolean;
47
- /** 본문 영역의 최소 높이. */
48
- minHeight?: string;
49
- /** 본문 영역의 최대 높이. 초과 시 내부 스크롤. */
50
- maxHeight?: string;
51
- className?: string;
52
- "aria-label"?: string;
53
- }
54
-
55
-
56
- /**
57
- * Tiptap 기반 리치 텍스트 에디터.
58
- *
59
- * Controlled (value/onChange) · Uncontrolled (defaultValue) 모두 지원. 라우터·외부 상태와
60
- * 동기화할 게 없는 단일 입력 폼이라면 defaultValue 한 줄로 끝 — useState 불필요.
61
- *
62
- * 기본 toolbar 는 StarterKit 의 표준 마크업(헤딩·리스트·인용·코드·링크 등) 을 다룬다.
63
- */
64
- export function RichTextEditor({
65
- value: valueProp,
66
- defaultValue,
67
- onChange,
68
- placeholder,
69
- readOnly = false,
70
- hideToolbar = false,
71
- minHeight,
72
- maxHeight,
73
- className,
74
- "aria-label": ariaLabel = "Rich text editor",
75
- }: RichTextEditorProps) {
76
- const isControlled = valueProp !== undefined;
77
- const editor = useEditor({
78
- extensions: [
79
- StarterKit,
80
- Placeholder.configure({
81
- placeholder: placeholder ?? "",
82
- emptyEditorClass: rteIsEmpty,
83
- }),
84
- Link.configure({
85
- openOnClick: false,
86
- autolink: true,
87
- HTMLAttributes: { rel: "noopener noreferrer", target: "_blank" },
88
- }),
89
- ],
90
- content: valueProp ?? defaultValue ?? "",
91
- editable: !readOnly,
92
- immediatelyRender: false,
93
- onUpdate: ({ editor }) => {
94
- onChange?.(editor.getHTML());
95
- },
96
- editorProps: {
97
- attributes: {
98
- class: rte__content,
99
- "aria-label": ariaLabel,
100
- },
101
- },
102
- });
103
-
104
- // controlled 모드에서만 외부 value 를 에디터 doc 에 동기화
105
- useEffect(() => {
106
- if (!isControlled) return;
107
- if (!editor) return;
108
- if (editor.getHTML() === valueProp) return;
109
- editor.commands.setContent(valueProp ?? "", { emitUpdate: false });
110
- }, [isControlled, valueProp, editor]);
111
-
112
- useEffect(() => {
113
- editor?.setEditable(!readOnly);
114
- }, [readOnly, editor]);
115
-
116
- return (
117
- <div
118
- className={cn(rte, className)}
119
- data-readonly={readOnly || undefined}
120
- style={
121
- {
122
- "--sh-ui-rte-min-height": minHeight,
123
- "--sh-ui-rte-max-height": maxHeight,
124
- } as React.CSSProperties
125
- }
126
- >
127
- {!hideToolbar && <Toolbar editor={editor} disabled={readOnly} />}
128
- <EditorContent editor={editor} className={rte__viewport} />
129
- </div>
130
- );
131
- }
132
-
133
- interface ToolbarProps {
134
- editor: Editor | null;
135
- disabled: boolean;
136
- }
137
-
138
- function Toolbar({ editor, disabled }: ToolbarProps) {
139
- const promptLink = useCallback(() => {
140
- if (!editor) return;
141
- const previous = editor.getAttributes("link").href as string | undefined;
142
- const url = window.prompt("URL", previous ?? "https://");
143
- if (url === null) return;
144
- if (url === "") {
145
- editor.chain().focus().extendMarkRange("link").unsetLink().run();
146
- return;
147
- }
148
- const { empty } = editor.state.selection;
149
- const inLink = editor.isActive("link");
150
- if (empty && !inLink) {
151
- // 선택 없이 호출되면 URL 자체를 anchor 텍스트로 삽입 — 빈 링크 마크가 남는 걸 방지
152
- editor
153
- .chain()
154
- .focus()
155
- .insertContent({
156
- type: "text",
157
- text: url,
158
- marks: [{ type: "link", attrs: { href: url } }],
159
- })
160
- .run();
161
- return;
162
- }
163
- editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
164
- }, [editor]);
165
-
166
- return (
167
- <div className={rte__toolbar} role="toolbar" aria-label="Formatting" aria-disabled={disabled || undefined}>
168
- <ToolbarButton
169
- editor={editor}
170
- label="Bold"
171
- icon={<BoldIcon size={16} />}
172
- isActive={editor?.isActive("bold")}
173
- canRun={() => !!editor?.can().toggleBold()}
174
- run={() => editor?.chain().focus().toggleBold().run()}
175
- disabled={disabled}
176
- />
177
- <ToolbarButton
178
- editor={editor}
179
- label="Italic"
180
- icon={<ItalicIcon size={16} />}
181
- isActive={editor?.isActive("italic")}
182
- canRun={() => !!editor?.can().toggleItalic()}
183
- run={() => editor?.chain().focus().toggleItalic().run()}
184
- disabled={disabled}
185
- />
186
- <ToolbarButton
187
- editor={editor}
188
- label="Strikethrough"
189
- icon={<StrikethroughIcon size={16} />}
190
- isActive={editor?.isActive("strike")}
191
- canRun={() => !!editor?.can().toggleStrike()}
192
- run={() => editor?.chain().focus().toggleStrike().run()}
193
- disabled={disabled}
194
- />
195
- <ToolbarButton
196
- editor={editor}
197
- label="Inline code"
198
- icon={<CodeIcon size={16} />}
199
- isActive={editor?.isActive("code")}
200
- canRun={() => !!editor?.can().toggleCode()}
201
- run={() => editor?.chain().focus().toggleCode().run()}
202
- disabled={disabled}
203
- />
204
-
205
- <ToolbarSeparator />
206
-
207
- <ToolbarButton
208
- editor={editor}
209
- label="Heading 1"
210
- icon={<Heading1Icon size={16} />}
211
- isActive={editor?.isActive("heading", { level: 1 })}
212
- run={() => editor?.chain().focus().toggleHeading({ level: 1 }).run()}
213
- disabled={disabled}
214
- />
215
- <ToolbarButton
216
- editor={editor}
217
- label="Heading 2"
218
- icon={<Heading2Icon size={16} />}
219
- isActive={editor?.isActive("heading", { level: 2 })}
220
- run={() => editor?.chain().focus().toggleHeading({ level: 2 }).run()}
221
- disabled={disabled}
222
- />
223
- <ToolbarButton
224
- editor={editor}
225
- label="Heading 3"
226
- icon={<Heading3Icon size={16} />}
227
- isActive={editor?.isActive("heading", { level: 3 })}
228
- run={() => editor?.chain().focus().toggleHeading({ level: 3 }).run()}
229
- disabled={disabled}
230
- />
231
-
232
- <ToolbarSeparator />
233
-
234
- <ToolbarButton
235
- editor={editor}
236
- label="Bulleted list"
237
- icon={<ListIcon size={16} />}
238
- isActive={editor?.isActive("bulletList")}
239
- run={() => editor?.chain().focus().toggleBulletList().run()}
240
- disabled={disabled}
241
- />
242
- <ToolbarButton
243
- editor={editor}
244
- label="Ordered list"
245
- icon={<ListOrderedIcon size={16} />}
246
- isActive={editor?.isActive("orderedList")}
247
- run={() => editor?.chain().focus().toggleOrderedList().run()}
248
- disabled={disabled}
249
- />
250
- <ToolbarButton
251
- editor={editor}
252
- label="Blockquote"
253
- icon={<QuoteIcon size={16} />}
254
- isActive={editor?.isActive("blockquote")}
255
- run={() => editor?.chain().focus().toggleBlockquote().run()}
256
- disabled={disabled}
257
- />
258
- <ToolbarButton
259
- editor={editor}
260
- label="Code block"
261
- icon={<Code2Icon size={16} />}
262
- isActive={editor?.isActive("codeBlock")}
263
- run={() => editor?.chain().focus().toggleCodeBlock().run()}
264
- disabled={disabled}
265
- />
266
-
267
- <ToolbarSeparator />
268
-
269
- <ToolbarButton
270
- editor={editor}
271
- label="Link"
272
- icon={<LinkIcon size={16} />}
273
- isActive={editor?.isActive("link")}
274
- run={promptLink}
275
- disabled={disabled}
276
- />
277
- <ToolbarButton
278
- editor={editor}
279
- label="Horizontal rule"
280
- icon={<MinusIcon size={16} />}
281
- run={() => editor?.chain().focus().setHorizontalRule().run()}
282
- disabled={disabled}
283
- />
284
-
285
- <ToolbarSeparator />
286
-
287
- <ToolbarButton
288
- editor={editor}
289
- label="Undo"
290
- icon={<Undo2Icon size={16} />}
291
- canRun={() => !!editor?.can().undo()}
292
- run={() => editor?.chain().focus().undo().run()}
293
- disabled={disabled}
294
- />
295
- <ToolbarButton
296
- editor={editor}
297
- label="Redo"
298
- icon={<Redo2Icon size={16} />}
299
- canRun={() => !!editor?.can().redo()}
300
- run={() => editor?.chain().focus().redo().run()}
301
- disabled={disabled}
302
- />
303
- </div>
304
- );
305
- }
306
-
307
- interface ToolbarButtonProps {
308
- editor: Editor | null;
309
- label: string;
310
- icon: React.ReactNode;
311
- isActive?: boolean;
312
- /** false 를 반환하면 비활성. */
313
- canRun?: () => boolean;
314
- run: () => void;
315
- disabled: boolean;
316
- }
317
-
318
- function ToolbarButton({
319
- editor,
320
- label,
321
- icon,
322
- isActive,
323
- canRun,
324
- run,
325
- disabled,
326
- }: ToolbarButtonProps) {
327
- const isDisabled = disabled || !editor || (canRun ? !canRun() : false);
328
- return (
329
- <button
330
- type="button"
331
- className={cn(rte__btn, isActive && "is-active")}
332
- aria-label={label}
333
- aria-pressed={isActive || undefined}
334
- title={label}
335
- disabled={isDisabled}
336
- onMouseDown={(e) => {
337
- e.preventDefault();
338
- }}
339
- onClick={run}
340
- >
341
- {icon}
342
- </button>
343
- );
344
- }
345
-
346
- function ToolbarSeparator() {
347
- return <span aria-hidden className={rte__sep} />;
348
- }
@@ -1,243 +0,0 @@
1
- import { style } from "@vanilla-extract/css";
2
-
3
- export const rte = style({
4
- display: "flex",
5
- flexDirection: "column",
6
- border: "1px solid var(--border)",
7
- borderRadius: "var(--radius)",
8
- background: "var(--background)",
9
- overflow: "hidden",
10
- transition: "border-color var(--duration-fast)",
11
- selectors: {
12
- "&:focus-within": {
13
- borderColor: "var(--foreground)",
14
- outline: "var(--border-width-strong) solid var(--foreground)",
15
- outlineOffset: "2px",
16
- },
17
- "&[data-readonly]": {
18
- background: "var(--background-subtle)",
19
- },
20
- },
21
- });
22
-
23
- export const rte__toolbar = style({
24
- display: "flex",
25
- flexWrap: "wrap",
26
- alignItems: "center",
27
- gap: "0.125rem",
28
- padding: "var(--space-1) var(--space-2)",
29
- background: "var(--background-muted)",
30
- borderBottom: "1px solid var(--border)",
31
- });
32
-
33
- export const rte__btn = style({
34
- display: "inline-flex",
35
- alignItems: "center",
36
- justifyContent: "center",
37
- width: "1.875rem",
38
- height: "1.875rem",
39
- padding: 0,
40
- background: "transparent",
41
- color: "var(--foreground-muted)",
42
- border: "1px solid transparent",
43
- borderRadius: "calc(var(--radius) - 2px)",
44
- cursor: "pointer",
45
- transition: "color var(--duration-fast),\n background-color var(--duration-fast),\n border-color var(--duration-fast)",
46
- WebkitTapHighlightColor: "transparent",
47
- selectors: {
48
- "&:hover:not(:disabled)": {
49
- color: "var(--foreground)",
50
- background: "var(--background)",
51
- borderColor: "var(--border)",
52
- },
53
- "&:focus-visible": {
54
- outline: "var(--border-width-strong) solid var(--foreground)",
55
- outlineOffset: "1px",
56
- },
57
- "&.is-active": {
58
- color: "var(--foreground)",
59
- background: "var(--background)",
60
- borderColor: "var(--border-strong)",
61
- },
62
- "&:disabled": {
63
- opacity: 0.5,
64
- cursor: "not-allowed",
65
- },
66
- },
67
- });
68
-
69
- export const rte__sep = style({
70
- display: "inline-block",
71
- width: "1px",
72
- height: "1.25rem",
73
- margin: "0 var(--space-1)",
74
- background: "var(--border)",
75
- });
76
-
77
- export const rte__viewport = style({
78
- display: "flex",
79
- minHeight: "var(--sh-ui-rte-min-height, 9rem)",
80
- maxHeight: "var(--sh-ui-rte-max-height, 28rem)",
81
- overflowY: "auto",
82
- selectors: {
83
- "& > .ProseMirror": {
84
- flex: 1,
85
- },
86
- },
87
- });
88
-
89
- export const rte__content = style({
90
- outline: "none",
91
- padding: "var(--space-3) var(--space-4)",
92
- fontSize: "0.9375rem",
93
- lineHeight: 1.65,
94
- color: "var(--foreground)",
95
- selectors: {
96
- "& > :first-child": {
97
- marginTop: 0,
98
- },
99
- "& > :last-child": {
100
- marginBottom: 0,
101
- },
102
- "& p": {
103
- margin: "0 0 var(--space-3)",
104
- },
105
- "& h1": {
106
- margin: "var(--space-4) 0 var(--space-2)",
107
- fontWeight: 600,
108
- lineHeight: 1.3,
109
- },
110
- "& h2": {
111
- margin: "var(--space-4) 0 var(--space-2)",
112
- fontWeight: 600,
113
- lineHeight: 1.3,
114
- },
115
- "& h3": {
116
- margin: "var(--space-4) 0 var(--space-2)",
117
- fontWeight: 600,
118
- lineHeight: 1.3,
119
- },
120
- "& h4": {
121
- margin: "var(--space-4) 0 var(--space-2)",
122
- fontWeight: 600,
123
- lineHeight: 1.3,
124
- },
125
- "& h5": {
126
- margin: "var(--space-4) 0 var(--space-2)",
127
- fontWeight: 600,
128
- lineHeight: 1.3,
129
- },
130
- "& h6": {
131
- margin: "var(--space-4) 0 var(--space-2)",
132
- fontWeight: 600,
133
- lineHeight: 1.3,
134
- },
135
- "& h1": {
136
- fontSize: "1.5rem",
137
- },
138
- "& h2": {
139
- fontSize: "1.25rem",
140
- },
141
- "& h3": {
142
- fontSize: "1.125rem",
143
- },
144
- "& ul": {
145
- margin: "0 0 var(--space-3)",
146
- paddingLeft: "var(--space-5)",
147
- },
148
- "& ol": {
149
- margin: "0 0 var(--space-3)",
150
- paddingLeft: "var(--space-5)",
151
- },
152
- "& li": {
153
- marginBottom: "var(--space-1)",
154
- },
155
- "& li > p": {
156
- margin: 0,
157
- },
158
- "& blockquote": {
159
- margin: "0 0 var(--space-3)",
160
- padding: "var(--space-2) var(--space-3)",
161
- borderLeft: "3px solid var(--border-strong)",
162
- background: "var(--background-subtle)",
163
- color: "var(--foreground-muted)",
164
- borderRadius: "0 calc(var(--radius) - 2px) calc(var(--radius) - 2px) 0",
165
- },
166
- "& blockquote > :last-child": {
167
- marginBottom: 0,
168
- },
169
- "& code": {
170
- fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
171
- fontSize: "0.875em",
172
- padding: "0.125rem 0.375rem",
173
- borderRadius: "calc(var(--radius) - 4px)",
174
- background: "var(--background-muted)",
175
- color: "var(--foreground)",
176
- },
177
- "& pre": {
178
- margin: "0 0 var(--space-3)",
179
- padding: "var(--space-3)",
180
- border: "1px solid var(--border)",
181
- borderRadius: "var(--radius)",
182
- background: "var(--background-subtle)",
183
- overflowX: "auto",
184
- fontSize: "0.8125rem",
185
- lineHeight: 1.6,
186
- },
187
- "& pre code": {
188
- padding: 0,
189
- background: "transparent",
190
- fontSize: "inherit",
191
- },
192
- "& hr": {
193
- border: 0,
194
- borderTop: "1px solid var(--border)",
195
- margin: "var(--space-4) 0",
196
- },
197
- "& a": {
198
- color: "var(--primary)",
199
- textDecoration: "underline",
200
- textUnderlineOffset: "2px",
201
- },
202
- "& a:hover": {
203
- textDecorationThickness: "2px",
204
- },
205
- "& p.is-editor-empty:first-child::before": {
206
- content: "attr(data-placeholder)",
207
- color: "var(--foreground-muted)",
208
- float: "left",
209
- pointerEvents: "none",
210
- height: 0,
211
- },
212
- "& .is-editor-empty:first-child::before": {
213
- content: "attr(data-placeholder)",
214
- color: "var(--foreground-muted)",
215
- float: "left",
216
- pointerEvents: "none",
217
- height: 0,
218
- },
219
- "& del": {
220
- color: "var(--foreground-muted)",
221
- },
222
- "& s": {
223
- color: "var(--foreground-muted)",
224
- },
225
- "& ::selection": {
226
- background: "var(--background-muted)",
227
- },
228
- },
229
- });
230
-
231
- export const rteIsEmpty = style({
232
- });
233
-
234
- /** 동적 키로 클래스 참조용 — `byKey[\`badge--${variant}\`]` 같은 패턴 지원. */
235
- export const byKey: Record<string, string> = {
236
- "rte": rte,
237
- "rte__toolbar": rte__toolbar,
238
- "rte__btn": rte__btn,
239
- "rte__sep": rte__sep,
240
- "rte__viewport": rte__viewport,
241
- "rte__content": rte__content,
242
- "rte__is-empty": rteIsEmpty,
243
- };