sh-ui-cli 0.46.0 → 0.48.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.
Files changed (85) hide show
  1. package/data/changelog/versions.json +25 -0
  2. package/data/registry/react/components/accordion/index.module.tsx +97 -0
  3. package/data/registry/react/components/accordion/styles.module.css +111 -0
  4. package/data/registry/react/components/avatar/index.module.tsx +73 -0
  5. package/data/registry/react/components/avatar/styles.module.css +36 -0
  6. package/data/registry/react/components/badge/index.module.tsx +40 -0
  7. package/data/registry/react/components/badge/styles.module.css +57 -0
  8. package/data/registry/react/components/breadcrumb/index.module.tsx +152 -0
  9. package/data/registry/react/components/breadcrumb/styles.module.css +82 -0
  10. package/data/registry/react/components/calendar/index.module.tsx +806 -0
  11. package/data/registry/react/components/calendar/styles.module.css +213 -0
  12. package/data/registry/react/components/carousel/index.module.tsx +430 -0
  13. package/data/registry/react/components/carousel/styles.module.css +155 -0
  14. package/data/registry/react/components/checkbox/index.module.tsx +96 -0
  15. package/data/registry/react/components/checkbox/styles.module.css +75 -0
  16. package/data/registry/react/components/code-editor/index.module.tsx +230 -0
  17. package/data/registry/react/components/code-editor/styles.module.css +76 -0
  18. package/data/registry/react/components/code-panel/index.module.tsx +191 -0
  19. package/data/registry/react/components/code-panel/styles.module.css +124 -0
  20. package/data/registry/react/components/color-picker/index.module.tsx +467 -0
  21. package/data/registry/react/components/color-picker/styles.module.css +166 -0
  22. package/data/registry/react/components/combobox/index.module.tsx +165 -0
  23. package/data/registry/react/components/combobox/styles.module.css +151 -0
  24. package/data/registry/react/components/context-menu/index.module.tsx +251 -0
  25. package/data/registry/react/components/context-menu/styles.module.css +140 -0
  26. package/data/registry/react/components/date-picker/index.module.tsx +520 -0
  27. package/data/registry/react/components/date-picker/styles.module.css +103 -0
  28. package/data/registry/react/components/dialog/index.module.tsx +95 -0
  29. package/data/registry/react/components/dialog/styles.module.css +127 -0
  30. package/data/registry/react/components/dropdown-menu/index.module.tsx +255 -0
  31. package/data/registry/react/components/dropdown-menu/styles.module.css +150 -0
  32. package/data/registry/react/components/file-upload/index.module.tsx +487 -0
  33. package/data/registry/react/components/file-upload/styles.module.css +170 -0
  34. package/data/registry/react/components/form/index.module.tsx +61 -0
  35. package/data/registry/react/components/form/styles.module.css +47 -0
  36. package/data/registry/react/components/header/index.module.tsx +805 -0
  37. package/data/registry/react/components/header/styles.module.css +350 -0
  38. package/data/registry/react/components/label/index.module.tsx +52 -0
  39. package/data/registry/react/components/label/styles.module.css +90 -0
  40. package/data/registry/react/components/markdown-editor/index.module.tsx +119 -0
  41. package/data/registry/react/components/markdown-editor/styles.module.css +160 -0
  42. package/data/registry/react/components/menubar/index.module.tsx +32 -0
  43. package/data/registry/react/components/menubar/styles.module.css +45 -0
  44. package/data/registry/react/components/numeric-input/index.module.tsx +148 -0
  45. package/data/registry/react/components/numeric-input/styles.module.css +56 -0
  46. package/data/registry/react/components/page-toc/index.module.tsx +174 -0
  47. package/data/registry/react/components/page-toc/styles.module.css +82 -0
  48. package/data/registry/react/components/pagination/index.module.tsx +269 -0
  49. package/data/registry/react/components/pagination/styles.module.css +105 -0
  50. package/data/registry/react/components/popover/index.module.tsx +113 -0
  51. package/data/registry/react/components/popover/styles.module.css +65 -0
  52. package/data/registry/react/components/progress/index.module.tsx +54 -0
  53. package/data/registry/react/components/progress/styles.module.css +41 -0
  54. package/data/registry/react/components/radio/index.module.tsx +65 -0
  55. package/data/registry/react/components/radio/styles.module.css +80 -0
  56. package/data/registry/react/components/rich-text-editor/index.module.tsx +348 -0
  57. package/data/registry/react/components/rich-text-editor/styles.module.css +196 -0
  58. package/data/registry/react/components/select/index.module.tsx +234 -0
  59. package/data/registry/react/components/select/styles.module.css +193 -0
  60. package/data/registry/react/components/separator/index.module.tsx +46 -0
  61. package/data/registry/react/components/separator/styles.module.css +15 -0
  62. package/data/registry/react/components/sidebar/index.module.tsx +1067 -0
  63. package/data/registry/react/components/sidebar/styles.module.css +502 -0
  64. package/data/registry/react/components/skeleton/index.module.tsx +22 -0
  65. package/data/registry/react/components/skeleton/styles.module.css +24 -0
  66. package/data/registry/react/components/slider/index.module.tsx +298 -0
  67. package/data/registry/react/components/slider/styles.module.css +64 -0
  68. package/data/registry/react/components/spinner/index.module.tsx +38 -0
  69. package/data/registry/react/components/spinner/styles.module.css +37 -0
  70. package/data/registry/react/components/switch/index.module.tsx +39 -0
  71. package/data/registry/react/components/switch/styles.module.css +83 -0
  72. package/data/registry/react/components/tabs/index.module.tsx +91 -0
  73. package/data/registry/react/components/tabs/styles.module.css +148 -0
  74. package/data/registry/react/components/textarea/index.module.tsx +23 -0
  75. package/data/registry/react/components/textarea/styles.module.css +54 -0
  76. package/data/registry/react/components/toast/index.module.tsx +258 -0
  77. package/data/registry/react/components/toast/styles.module.css +290 -0
  78. package/data/registry/react/components/toggle/index.module.tsx +131 -0
  79. package/data/registry/react/components/toggle/styles.module.css +85 -0
  80. package/data/registry/react/components/tooltip/index.module.tsx +83 -0
  81. package/data/registry/react/components/tooltip/styles.module.css +44 -0
  82. package/data/registry/react/registry.json +560 -0
  83. package/package.json +1 -1
  84. package/src/api.d.ts +4 -3
  85. package/src/constants.js +4 -3
@@ -0,0 +1,191 @@
1
+ import { codeToHtml } from "shiki";
2
+ import { CodePanelCopyButton } from "./copy";
3
+ import styles from "./styles.module.css";
4
+
5
+
6
+ import { cn } from "@SH_UI_UTILS@";
7
+ export interface CodePanelProps
8
+ extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
9
+ /** 하이라이팅할 코드 문자열. children을 제공하지 않을 때 필수. */
10
+ code?: string;
11
+ /**
12
+ * shiki가 지원하는 언어 ID (예: `"tsx"`, `"typescript"`, `"bash"`, `"json"`).
13
+ * 미지원 언어면 plain text로 폴백.
14
+ *
15
+ * @default "text"
16
+ */
17
+ language?: string;
18
+ /**
19
+ * 상단 헤더에 표시할 파일명. 지정하면 헤더가 그려지고 그 안에 복사 버튼이 들어가며,
20
+ * 미지정 시 우상단에 floating 복사 버튼만 표시된다.
21
+ */
22
+ filename?: string;
23
+ /**
24
+ * 좌측 줄 번호 표시 여부.
25
+ * @default true
26
+ */
27
+ showLineNumbers?: boolean;
28
+ /**
29
+ * 복사 버튼 숨기기. 코드 발췌가 클립보드 복사용이 아닐 때 사용.
30
+ * @default false
31
+ */
32
+ hideCopy?: boolean;
33
+ /**
34
+ * compound 모드. 직접 `CodePanelHeader`/`CodePanelFilename`/`CodePanelCopy`/`CodePanelBody`를
35
+ * 조합해 헤더 액션 추가나 복사 버튼 위치 변경 등을 한다. 지정 시 `code`/`language` 등은 무시.
36
+ */
37
+ children?: React.ReactNode;
38
+ }
39
+
40
+ /**
41
+ * 코드 블록 + 복사 버튼 패널. shiki로 SSR에서 하이라이팅.
42
+ *
43
+ * 기본 사용(자식 생략) — `code` prop만 넘기면 기본 레이아웃을 렌더한다.
44
+ * 커스텀 구성 — `CodePanelHeader`, `CodePanelFilename`, `CodePanelCopy`,
45
+ * `CodePanelBody`를 직접 조합하여 헤더 액션 추가·복사 버튼 위치 변경 등이 가능하다.
46
+ */
47
+ export async function CodePanel({
48
+ code,
49
+ language = "text",
50
+ filename,
51
+ showLineNumbers = true,
52
+ hideCopy,
53
+ className,
54
+ children,
55
+ ...rest
56
+ }: CodePanelProps) {
57
+ const classes = cn(styles.code, className);
58
+
59
+ if (children !== undefined) {
60
+ return (
61
+ <div className={classes} {...rest}>
62
+ {children}
63
+ </div>
64
+ );
65
+ }
66
+
67
+ if (code === undefined) {
68
+ throw new Error("CodePanel: `code` prop 또는 children 중 하나가 필요합니다.");
69
+ }
70
+
71
+ const trimmed = code.replace(/\n$/, "");
72
+
73
+ return (
74
+ <div className={classes} {...rest}>
75
+ {filename ? (
76
+ <CodePanelHeader>
77
+ <CodePanelFilename>{filename}</CodePanelFilename>
78
+ {!hideCopy && <CodePanelCopy code={trimmed} />}
79
+ </CodePanelHeader>
80
+ ) : (
81
+ !hideCopy && (
82
+ <div className={styles["code__copy-floating"]}>
83
+ <CodePanelCopy code={trimmed} />
84
+ </div>
85
+ )
86
+ )}
87
+ <CodePanelBody
88
+ code={trimmed}
89
+ language={language}
90
+ showLineNumbers={showLineNumbers}
91
+ />
92
+ </div>
93
+ );
94
+ }
95
+
96
+ /* ───────── CodePanelHeader ───────── */
97
+
98
+ /** 파일명·복사 버튼 등을 담는 코드 블록 상단 바. CodePanel 자식으로 사용. */
99
+ export function CodePanelHeader({
100
+ className,
101
+ children,
102
+ ...props
103
+ }: React.HTMLAttributes<HTMLDivElement>) {
104
+ return (
105
+ <div className={cn(styles.code__header, className)} {...props}>
106
+ {children}
107
+ </div>
108
+ );
109
+ }
110
+
111
+ /* ───────── CodePanelFilename ───────── */
112
+
113
+ /** CodePanelHeader 안에 표시되는 파일명 라벨. */
114
+ export function CodePanelFilename({
115
+ className,
116
+ children,
117
+ ...props
118
+ }: React.HTMLAttributes<HTMLSpanElement>) {
119
+ return (
120
+ <span className={cn(styles.code__filename, className)} {...props}>
121
+ {children}
122
+ </span>
123
+ );
124
+ }
125
+
126
+ /* ───────── CodePanelCopy ─────────
127
+ * 클립보드 복사 버튼. 내부적으로 client 컴포넌트를 사용한다.
128
+ */
129
+
130
+ export interface CodePanelCopyProps {
131
+ /** 클립보드에 복사할 코드 문자열. 부모(주로 CodePanel)가 명시적으로 전달한다. */
132
+ code: string;
133
+ }
134
+
135
+ /** 클립보드 복사 버튼. 부모가 복사할 코드 문자열을 명시적으로 전달한다. */
136
+ export function CodePanelCopy({ code }: CodePanelCopyProps) {
137
+ return <CodePanelCopyButton code={code} />;
138
+ }
139
+
140
+ /* ───────── CodePanelBody ─────────
141
+ * shiki로 코드를 하이라이팅하여 렌더하는 async 컴포넌트.
142
+ */
143
+
144
+ export interface CodePanelBodyProps
145
+ extends Omit<
146
+ React.HTMLAttributes<HTMLDivElement>,
147
+ "children" | "dangerouslySetInnerHTML"
148
+ > {
149
+ /** 하이라이팅할 코드 문자열. */
150
+ code: string;
151
+ /**
152
+ * shiki 언어 ID.
153
+ * @default "text"
154
+ */
155
+ language?: string;
156
+ /**
157
+ * 좌측 줄 번호 표시 여부.
158
+ * @default true
159
+ */
160
+ showLineNumbers?: boolean;
161
+ }
162
+
163
+ /**
164
+ * shiki로 코드를 SSR 하이라이팅하여 렌더하는 async 컴포넌트.
165
+ * 라이트/다크 테마는 `github-light`/`github-dark`를 사용하며, 부모 테마 클래스에 따라 자동 전환된다.
166
+ */
167
+ export async function CodePanelBody({
168
+ code,
169
+ language = "text",
170
+ showLineNumbers = true,
171
+ className,
172
+ ...rest
173
+ }: CodePanelBodyProps) {
174
+ const trimmed = code.replace(/\n$/, "");
175
+ const html = await codeToHtml(trimmed, {
176
+ lang: language,
177
+ themes: { light: "github-light", dark: "github-dark" },
178
+ defaultColor: false,
179
+ });
180
+
181
+ return (
182
+ <div
183
+ className={cn(styles.code__body, className)}
184
+ data-line-numbers={showLineNumbers || undefined}
185
+ dangerouslySetInnerHTML={{ __html: html }}
186
+ {...rest}
187
+ />
188
+ );
189
+ }
190
+
191
+ export { CodePanelCopyButton };
@@ -0,0 +1,124 @@
1
+ .code {
2
+ position: relative;
3
+ border: 1px solid var(--border);
4
+ border-radius: var(--radius);
5
+ background: var(--background-subtle);
6
+ overflow: hidden;
7
+ font-size: 0.8125rem;
8
+ line-height: 1.6;
9
+ margin: var(--space-4) 0;
10
+ }
11
+ @media (max-width: 640px) {
12
+ .code { font-size: var(--text-xs); }
13
+ }
14
+
15
+ /* 헤더 (filename 있을 때) */
16
+ .code__header {
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: space-between;
20
+ gap: var(--space-2);
21
+ padding: var(--space-2) var(--space-3) var(--space-2) var(--space-4);
22
+ border-bottom: 1px solid var(--border);
23
+ background: var(--background-muted);
24
+ font-size: var(--text-xs);
25
+ color: var(--foreground-muted);
26
+ }
27
+ .code__filename {
28
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
29
+ color: var(--foreground);
30
+ }
31
+
32
+ /* 헤더 없을 때 우상단에 떠있는 복사 버튼 */
33
+ .code__copy-floating {
34
+ position: absolute;
35
+ top: var(--space-2);
36
+ right: var(--space-2);
37
+ z-index: 1;
38
+ opacity: 0;
39
+ transition: opacity var(--duration-fast);
40
+ }
41
+ .code:hover .code__copy-floating,
42
+ .code:focus-within .code__copy-floating {
43
+ opacity: 1;
44
+ }
45
+
46
+ /* 복사 버튼 */
47
+ .code__copy {
48
+ display: inline-flex;
49
+ align-items: center;
50
+ gap: 0.375rem;
51
+ padding: var(--space-1) var(--space-2);
52
+ background: var(--background);
53
+ color: var(--foreground-muted);
54
+ border: 1px solid var(--border);
55
+ border-radius: calc(var(--radius) - 2px);
56
+ font-size: var(--text-xs);
57
+ line-height: 1;
58
+ cursor: pointer;
59
+ transition: color var(--duration-fast), border-color var(--duration-fast), background-color var(--duration-fast);
60
+ -webkit-tap-highlight-color: transparent;
61
+ }
62
+ .code__copy:hover {
63
+ color: var(--foreground);
64
+ border-color: var(--border-strong);
65
+ }
66
+ .code__copy:focus-visible {
67
+ outline: var(--border-width-strong) solid var(--foreground);
68
+ outline-offset: 2px;
69
+ }
70
+ .code__copy-label {
71
+ font-size: var(--text-xs);
72
+ }
73
+
74
+ /* 코드 본문 — shiki 출력(<pre class="shiki">...) */
75
+ .code__body {
76
+ overflow-x: auto;
77
+ }
78
+ .code__body pre {
79
+ margin: 0;
80
+ padding: var(--space-3) var(--space-4);
81
+ background: transparent !important;
82
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
83
+ font-size: inherit;
84
+ line-height: inherit;
85
+ border: none;
86
+ border-radius: 0;
87
+ }
88
+ .code__body code {
89
+ background: transparent;
90
+ padding: 0;
91
+ font-size: inherit;
92
+ display: block;
93
+ }
94
+
95
+ /* shiki dual theme — 기본은 light, .dark 스코프에선 dark.
96
+ span에는 color만 주고 background-color는 절대 강제하지 않는다.
97
+ (강제하면 --shiki-*-bg 변수가 상속돼 라인마다 띠가 생긴다.) */
98
+ .code__body .shiki,
99
+ .code__body .shiki span {
100
+ color: var(--shiki-light) !important;
101
+ background-color: transparent !important;
102
+ }
103
+ .dark .code__body .shiki,
104
+ .dark .code__body .shiki span {
105
+ color: var(--shiki-dark) !important;
106
+ background-color: transparent !important;
107
+ }
108
+
109
+ /* 라인 번호 */
110
+ .code__body[data-line-numbers] pre code {
111
+ counter-reset: step;
112
+ counter-increment: step 0;
113
+ }
114
+ .code__body[data-line-numbers] pre code .line::before {
115
+ content: counter(step);
116
+ counter-increment: step;
117
+ display: inline-block;
118
+ width: 1.75rem;
119
+ margin-right: var(--space-4);
120
+ text-align: right;
121
+ color: var(--foreground-muted);
122
+ opacity: 0.7;
123
+ user-select: none;
124
+ }