sh-ui-cli 0.52.0 → 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 (89) hide show
  1. package/data/changelog/versions.json +25 -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 +2 -2
  6. package/src/api.d.ts +3 -4
  7. package/src/constants.js +9 -5
  8. package/src/create/plugins/pluginSchema.js +5 -3
  9. package/src/mcp.mjs +4 -3
  10. package/data/registry/react/components/accordion/index.vanilla-extract.tsx +0 -97
  11. package/data/registry/react/components/accordion/styles.css.ts +0 -131
  12. package/data/registry/react/components/avatar/index.vanilla-extract.tsx +0 -73
  13. package/data/registry/react/components/avatar/styles.css.ts +0 -68
  14. package/data/registry/react/components/badge/index.vanilla-extract.tsx +0 -40
  15. package/data/registry/react/components/badge/styles.css.ts +0 -71
  16. package/data/registry/react/components/breadcrumb/index.vanilla-extract.tsx +0 -152
  17. package/data/registry/react/components/breadcrumb/styles.css.ts +0 -95
  18. package/data/registry/react/components/calendar/index.vanilla-extract.tsx +0 -806
  19. package/data/registry/react/components/calendar/styles.css.ts +0 -250
  20. package/data/registry/react/components/carousel/index.vanilla-extract.tsx +0 -430
  21. package/data/registry/react/components/carousel/styles.css.ts +0 -169
  22. package/data/registry/react/components/checkbox/index.vanilla-extract.tsx +0 -96
  23. package/data/registry/react/components/checkbox/styles.css.ts +0 -74
  24. package/data/registry/react/components/code-editor/index.vanilla-extract.tsx +0 -230
  25. package/data/registry/react/components/code-editor/styles.css.ts +0 -97
  26. package/data/registry/react/components/code-panel/index.vanilla-extract.tsx +0 -191
  27. package/data/registry/react/components/code-panel/styles.css.ts +0 -151
  28. package/data/registry/react/components/color-picker/index.vanilla-extract.tsx +0 -467
  29. package/data/registry/react/components/color-picker/styles.css.ts +0 -169
  30. package/data/registry/react/components/combobox/index.vanilla-extract.tsx +0 -165
  31. package/data/registry/react/components/combobox/styles.css.ts +0 -174
  32. package/data/registry/react/components/context-menu/index.vanilla-extract.tsx +0 -251
  33. package/data/registry/react/components/context-menu/styles.css.ts +0 -167
  34. package/data/registry/react/components/date-picker/index.vanilla-extract.tsx +0 -520
  35. package/data/registry/react/components/date-picker/styles.css.ts +0 -111
  36. package/data/registry/react/components/dialog/index.vanilla-extract.tsx +0 -95
  37. package/data/registry/react/components/dialog/styles.css.ts +0 -140
  38. package/data/registry/react/components/dropdown-menu/index.vanilla-extract.tsx +0 -255
  39. package/data/registry/react/components/dropdown-menu/styles.css.ts +0 -175
  40. package/data/registry/react/components/file-upload/index.vanilla-extract.tsx +0 -487
  41. package/data/registry/react/components/file-upload/styles.css.ts +0 -193
  42. package/data/registry/react/components/form/index.vanilla-extract.tsx +0 -61
  43. package/data/registry/react/components/form/styles.css.ts +0 -56
  44. package/data/registry/react/components/header/index.vanilla-extract.tsx +0 -805
  45. package/data/registry/react/components/header/styles.css.ts +0 -413
  46. package/data/registry/react/components/label/index.vanilla-extract.tsx +0 -52
  47. package/data/registry/react/components/label/styles.css.ts +0 -141
  48. package/data/registry/react/components/markdown-editor/index.vanilla-extract.tsx +0 -119
  49. package/data/registry/react/components/markdown-editor/styles.css.ts +0 -231
  50. package/data/registry/react/components/menubar/index.vanilla-extract.tsx +0 -32
  51. package/data/registry/react/components/menubar/styles.css.ts +0 -53
  52. package/data/registry/react/components/numeric-input/index.vanilla-extract.tsx +0 -148
  53. package/data/registry/react/components/numeric-input/styles.css.ts +0 -65
  54. package/data/registry/react/components/page-toc/index.vanilla-extract.tsx +0 -174
  55. package/data/registry/react/components/page-toc/styles.css.ts +0 -97
  56. package/data/registry/react/components/pagination/index.vanilla-extract.tsx +0 -269
  57. package/data/registry/react/components/pagination/styles.css.ts +0 -113
  58. package/data/registry/react/components/popover/index.vanilla-extract.tsx +0 -113
  59. package/data/registry/react/components/popover/styles.css.ts +0 -78
  60. package/data/registry/react/components/progress/index.vanilla-extract.tsx +0 -54
  61. package/data/registry/react/components/progress/styles.css.ts +0 -53
  62. package/data/registry/react/components/radio/index.vanilla-extract.tsx +0 -65
  63. package/data/registry/react/components/radio/styles.css.ts +0 -79
  64. package/data/registry/react/components/rich-text-editor/index.vanilla-extract.tsx +0 -348
  65. package/data/registry/react/components/rich-text-editor/styles.css.ts +0 -243
  66. package/data/registry/react/components/select/index.vanilla-extract.tsx +0 -234
  67. package/data/registry/react/components/select/styles.css.ts +0 -225
  68. package/data/registry/react/components/separator/index.vanilla-extract.tsx +0 -46
  69. package/data/registry/react/components/separator/styles.css.ts +0 -24
  70. package/data/registry/react/components/sidebar/index.vanilla-extract.tsx +0 -1067
  71. package/data/registry/react/components/sidebar/styles.css.ts +0 -578
  72. package/data/registry/react/components/skeleton/index.vanilla-extract.tsx +0 -22
  73. package/data/registry/react/components/skeleton/styles.css.ts +0 -30
  74. package/data/registry/react/components/slider/index.vanilla-extract.tsx +0 -298
  75. package/data/registry/react/components/slider/styles.css.ts +0 -75
  76. package/data/registry/react/components/spinner/index.vanilla-extract.tsx +0 -38
  77. package/data/registry/react/components/spinner/styles.css.ts +0 -60
  78. package/data/registry/react/components/switch/index.vanilla-extract.tsx +0 -39
  79. package/data/registry/react/components/switch/styles.css.ts +0 -87
  80. package/data/registry/react/components/tabs/index.vanilla-extract.tsx +0 -91
  81. package/data/registry/react/components/tabs/styles.css.ts +0 -145
  82. package/data/registry/react/components/textarea/index.vanilla-extract.tsx +0 -23
  83. package/data/registry/react/components/textarea/styles.css.ts +0 -55
  84. package/data/registry/react/components/toast/index.vanilla-extract.tsx +0 -258
  85. package/data/registry/react/components/toast/styles.css.ts +0 -307
  86. package/data/registry/react/components/toggle/index.vanilla-extract.tsx +0 -131
  87. package/data/registry/react/components/toggle/styles.css.ts +0 -109
  88. package/data/registry/react/components/tooltip/index.vanilla-extract.tsx +0 -83
  89. 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
- };