sh-ui-cli 0.112.0 → 0.113.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.
@@ -2,6 +2,18 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$description": "sh-ui 릴리즈 노트 단일 소스. docs(React)와 showcase(Flutter)가 함께 읽는다. 새 릴리즈마다 맨 앞에 추가.",
4
4
  "versions": [
5
+ {
6
+ "version": "0.113.0",
7
+ "date": "2026-05-26",
8
+ "title": "components — Separator label 슬롯 + align",
9
+ "type": "minor",
10
+ "highlights": [
11
+ "**`Separator` 라벨 슬롯 신규** — `<Separator />` 는 기존처럼 가로/세로 1px 선이지만, `<Separator>섹션 라벨</Separator>` 처럼 children 을 넘기면 가운데 라벨이 있는 `──── label ────` 형식으로 렌더. 라벨이 있을 땐 horizontal 로 강제되고 `align` prop(`start`/`center`/`end`) 으로 라벨 위치를 정한다. 기존 사용처는 그대로 — children 없는 호출은 동작 변화 없음.",
12
+ "**디자인 토큰 활용** — 선 색은 `--border`, 라벨은 `--foreground-subtle` + uppercase + tracking-wide 가 기본. 시안 빈도 높은 \"섹션 라벨 양옆 1px 선\" 패턴 (login OAuth 구분, 워크스페이스 스위처 invite 섹션 등) 을 1줄로 줄여준다. `className` 으로 라벨 컨테이너의 typography·spacing 도 override 가능.",
13
+ "**Tailwind / CSS Modules / plain CSS 세 변종 모두 갱신** — 라벨이 있을 때만 `flex items-center gap` 컨테이너로 전환되고 plain 변종은 컨테이너 자체에 background 를 두지 않아 visual side effect 없음."
14
+ ],
15
+ "url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.113.0"
16
+ },
5
17
  {
6
18
  "version": "0.112.0",
7
19
  "date": "2026-05-22",
@@ -4,42 +4,74 @@ import styles from "./styles.module.css";
4
4
 
5
5
  import { cn } from "@SH_UI_UTILS@";
6
6
  export type SeparatorOrientation = "horizontal" | "vertical";
7
+ export type SeparatorAlign = "start" | "center" | "end";
7
8
 
8
9
  export interface SeparatorProps
9
10
  extends Omit<React.HTMLAttributes<HTMLDivElement>, "role"> {
10
11
  orientation?: SeparatorOrientation;
12
+ /**
13
+ * 라벨 정렬 — children 이 있을 때만 의미를 가진다. 기본 center.
14
+ */
15
+ align?: SeparatorAlign;
11
16
  /**
12
17
  * 의미 없는 시각적 구분선인지 여부. 기본 true(aria-hidden).
13
- * 스크린리더에도 섹션 구분을 알려야 하면 false.
14
18
  */
15
19
  decorative?: boolean;
16
20
  }
17
21
 
18
22
  /**
19
- * 시각적 구분선. 가로(height=1px) / 세로(width=1px).
20
- *
21
- * 의미 있는 구분에는 `decorative={false}`로 role=separator가 붙고, 그렇지 않으면
22
- * aria-hidden 처리되어 보조 기술에 노출되지 않는다.
23
+ * 시각적 구분선 (CSS Modules 변종). 두 변종을 한 컴포넌트로:
24
+ * - children 없음: 가로/세로 1px
25
+ * - children 있음: 가운데 라벨이 있는 "──── label ────" 형식
23
26
  */
24
27
  export const Separator = React.forwardRef<HTMLDivElement, SeparatorProps>(
25
28
  function Separator(
26
- { className, orientation = "horizontal", decorative = true, ...props },
29
+ {
30
+ className,
31
+ orientation = "horizontal",
32
+ align = "center",
33
+ decorative = true,
34
+ children,
35
+ ...props
36
+ },
27
37
  ref,
28
38
  ) {
39
+ const hasLabel = children != null && children !== false;
40
+ if (!hasLabel) {
41
+ return (
42
+ <div
43
+ ref={ref}
44
+ role={decorative ? undefined : "separator"}
45
+ aria-orientation={decorative ? undefined : orientation}
46
+ aria-hidden={decorative || undefined}
47
+ data-orientation={orientation}
48
+ className={cn(
49
+ styles.separator,
50
+ styles[`separator--${orientation}`],
51
+ className,
52
+ )}
53
+ {...props}
54
+ />
55
+ );
56
+ }
29
57
  return (
30
58
  <div
31
59
  ref={ref}
32
60
  role={decorative ? undefined : "separator"}
33
- aria-orientation={decorative ? undefined : orientation}
34
- aria-hidden={decorative || undefined}
35
- data-orientation={orientation}
36
- className={cn(
37
- styles.separator,
38
- styles[`separator--${orientation}`],
39
- className,
40
- )}
61
+ aria-orientation={decorative ? undefined : "horizontal"}
62
+ data-orientation="horizontal"
63
+ data-align={align}
64
+ className={cn(styles.separator__labeled, className)}
41
65
  {...props}
42
- />
66
+ >
67
+ {align !== "start" ? (
68
+ <span aria-hidden className={styles.separator__line} />
69
+ ) : null}
70
+ <span className={styles.separator__label}>{children}</span>
71
+ {align !== "end" ? (
72
+ <span aria-hidden className={styles.separator__line} />
73
+ ) : null}
74
+ </div>
43
75
  );
44
76
  },
45
77
  );
@@ -3,37 +3,79 @@ import * as React from "react";
3
3
 
4
4
  import { cn } from "@SH_UI_UTILS@";
5
5
  export type SeparatorOrientation = "horizontal" | "vertical";
6
+ export type SeparatorAlign = "start" | "center" | "end";
6
7
 
7
8
  export interface SeparatorProps
8
9
  extends Omit<React.HTMLAttributes<HTMLDivElement>, "role"> {
9
10
  orientation?: SeparatorOrientation;
11
+ /**
12
+ * 라벨 정렬 — children 이 있을 때만 의미를 가진다. 기본 center.
13
+ */
14
+ align?: SeparatorAlign;
10
15
  /**
11
16
  * 의미 없는 시각적 구분선인지 여부. 기본 true(aria-hidden).
12
- * 스크린리더에도 섹션 구분을 알려야 하면 false.
13
17
  */
14
18
  decorative?: boolean;
15
19
  }
16
20
 
17
21
  /**
18
- * 시각적 구분선 (Tailwind utility 변종). 가로(height=1px) / 세로(width=1px).
22
+ * 시각적 구분선 (Tailwind utility 변종). 변종을 한 컴포넌트로:
23
+ * - children 없음: 가로(height=1px) / 세로(width=1px)
24
+ * - children 있음: 가운데에 라벨이 있는 "──── label ────" 형식
19
25
  */
20
26
  export const Separator = React.forwardRef<HTMLDivElement, SeparatorProps>(
21
27
  function Separator(
22
- { className, orientation = "horizontal", decorative = true, ...props },
28
+ {
29
+ className,
30
+ orientation = "horizontal",
31
+ align = "center",
32
+ decorative = true,
33
+ children,
34
+ ...props
35
+ },
23
36
  ref,
24
37
  ) {
25
- const sizing =
26
- orientation === "horizontal" ? "w-full h-px" : "w-px h-full self-stretch";
38
+ const hasLabel = children != null && children !== false;
39
+ if (!hasLabel) {
40
+ const sizing =
41
+ orientation === "horizontal"
42
+ ? "w-full h-px"
43
+ : "w-px h-full self-stretch";
44
+ return (
45
+ <div
46
+ ref={ref}
47
+ role={decorative ? undefined : "separator"}
48
+ aria-orientation={decorative ? undefined : orientation}
49
+ aria-hidden={decorative || undefined}
50
+ data-orientation={orientation}
51
+ className={cn("bg-border shrink-0", sizing, className)}
52
+ {...props}
53
+ />
54
+ );
55
+ }
27
56
  return (
28
57
  <div
29
58
  ref={ref}
30
59
  role={decorative ? undefined : "separator"}
31
- aria-orientation={decorative ? undefined : orientation}
32
- aria-hidden={decorative || undefined}
33
- data-orientation={orientation}
34
- className={cn("bg-border shrink-0", sizing, className)}
60
+ aria-orientation={decorative ? undefined : "horizontal"}
61
+ data-orientation="horizontal"
62
+ data-align={align}
63
+ className={cn(
64
+ "flex w-full shrink-0 items-center gap-[var(--space-3,0.75rem)]",
65
+ className,
66
+ )}
35
67
  {...props}
36
- />
68
+ >
69
+ {align !== "start" ? (
70
+ <span aria-hidden className="h-px flex-1 bg-border" />
71
+ ) : null}
72
+ <span className="text-[length:var(--text-xs,0.75rem)] font-semibold uppercase tracking-[0.04em] text-foreground-subtle">
73
+ {children}
74
+ </span>
75
+ {align !== "end" ? (
76
+ <span aria-hidden className="h-px flex-1 bg-border" />
77
+ ) : null}
78
+ </div>
37
79
  );
38
80
  },
39
81
  );
@@ -4,10 +4,16 @@ import "./styles.css";
4
4
 
5
5
  import { cn } from "@SH_UI_UTILS@";
6
6
  export type SeparatorOrientation = "horizontal" | "vertical";
7
+ export type SeparatorAlign = "start" | "center" | "end";
7
8
 
8
9
  export interface SeparatorProps
9
10
  extends Omit<React.HTMLAttributes<HTMLDivElement>, "role"> {
10
11
  orientation?: SeparatorOrientation;
12
+ /**
13
+ * 라벨 정렬 — children 이 있을 때만 의미를 가진다. 기본 center.
14
+ * `start` 면 라벨이 왼쪽에 붙고 오른쪽으로만 선이 뻗는다 (반대도 마찬가지).
15
+ */
16
+ align?: SeparatorAlign;
11
17
  /**
12
18
  * 의미 없는 시각적 구분선인지 여부. 기본 true(aria-hidden).
13
19
  * 스크린리더에도 섹션 구분을 알려야 하면 false.
@@ -16,30 +22,62 @@ export interface SeparatorProps
16
22
  }
17
23
 
18
24
  /**
19
- * 시각적 구분선. 가로(height=1px) / 세로(width=1px).
25
+ * 시각적 구분선. 변종을 한 컴포넌트로:
26
+ * - children 없음: 가로/세로 1px 선 (orientation 으로 선택)
27
+ * - children 있음: 가운데에 라벨이 있는 "──── label ────" 형식
28
+ * (horizontal 강제, align 으로 라벨 위치 지정)
20
29
  *
21
- * 의미 있는 구분에는 `decorative={false}`로 role=separator가 붙고, 그렇지 않으면
22
- * aria-hidden 처리되어 보조 기술에 노출되지 않는다.
30
+ * 의미 있는 구분에는 `decorative={false}` role=separator 가 붙고,
31
+ * 그렇지 않으면 aria-hidden 처리되어 보조 기술에 노출되지 않는다.
23
32
  */
24
33
  export const Separator = React.forwardRef<HTMLDivElement, SeparatorProps>(
25
34
  function Separator(
26
- { className, orientation = "horizontal", decorative = true, ...props },
35
+ {
36
+ className,
37
+ orientation = "horizontal",
38
+ align = "center",
39
+ decorative = true,
40
+ children,
41
+ ...props
42
+ },
27
43
  ref,
28
44
  ) {
45
+ const hasLabel = children != null && children !== false;
46
+ if (!hasLabel) {
47
+ return (
48
+ <div
49
+ ref={ref}
50
+ role={decorative ? undefined : "separator"}
51
+ aria-orientation={decorative ? undefined : orientation}
52
+ aria-hidden={decorative || undefined}
53
+ data-orientation={orientation}
54
+ className={cn(
55
+ "sh-ui-separator",
56
+ `sh-ui-separator--${orientation}`,
57
+ className,
58
+ )}
59
+ {...props}
60
+ />
61
+ );
62
+ }
29
63
  return (
30
64
  <div
31
65
  ref={ref}
32
66
  role={decorative ? undefined : "separator"}
33
- aria-orientation={decorative ? undefined : orientation}
34
- aria-hidden={decorative || undefined}
35
- data-orientation={orientation}
36
- className={cn(
37
- "sh-ui-separator",
38
- `sh-ui-separator--${orientation}`,
39
- className,
40
- )}
67
+ aria-orientation={decorative ? undefined : "horizontal"}
68
+ data-orientation="horizontal"
69
+ data-align={align}
70
+ className={cn("sh-ui-separator--labeled", className)}
41
71
  {...props}
42
- />
72
+ >
73
+ {align !== "start" ? (
74
+ <span aria-hidden className="sh-ui-separator__line" />
75
+ ) : null}
76
+ <span className="sh-ui-separator__label">{children}</span>
77
+ {align !== "end" ? (
78
+ <span aria-hidden className="sh-ui-separator__line" />
79
+ ) : null}
80
+ </div>
43
81
  );
44
82
  },
45
83
  );
@@ -13,3 +13,24 @@
13
13
  height: 100%;
14
14
  align-self: stretch;
15
15
  }
16
+
17
+ /* labeled — children 있을 때 적용. 컨테이너 자체에는 배경 없음 (내부 .line 만 1px). */
18
+ .sh-ui-separator--labeled {
19
+ display: flex;
20
+ align-items: center;
21
+ gap: var(--space-3, 0.75rem);
22
+ width: 100%;
23
+ flex-shrink: 0;
24
+ }
25
+ .sh-ui-separator__line {
26
+ flex: 1;
27
+ height: 1px;
28
+ background: var(--border);
29
+ }
30
+ .sh-ui-separator__label {
31
+ font-size: var(--text-xs, 0.75rem);
32
+ font-weight: 600;
33
+ text-transform: uppercase;
34
+ letter-spacing: 0.04em;
35
+ color: var(--foreground-subtle);
36
+ }
@@ -13,3 +13,23 @@
13
13
  height: 100%;
14
14
  align-self: stretch;
15
15
  }
16
+
17
+ .separator__labeled {
18
+ display: flex;
19
+ align-items: center;
20
+ gap: var(--space-3, 0.75rem);
21
+ width: 100%;
22
+ flex-shrink: 0;
23
+ }
24
+ .separator__line {
25
+ flex: 1;
26
+ height: 1px;
27
+ background: var(--border);
28
+ }
29
+ .separator__label {
30
+ font-size: var(--text-xs, 0.75rem);
31
+ font-weight: 600;
32
+ text-transform: uppercase;
33
+ letter-spacing: 0.04em;
34
+ color: var(--foreground-subtle);
35
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$description": "컴포넌트별 토큰 의존성 (var(--*) 추출). build-registry-tokens.mjs 가 자동 생성.",
3
- "$generated": "2026-05-21T07:02:56.611Z",
3
+ "$generated": "2026-05-26T05:20:38.023Z",
4
4
  "components": {
5
5
  "button": {
6
6
  "plain": [
@@ -1486,11 +1486,13 @@
1486
1486
  },
1487
1487
  "separator": {
1488
1488
  "plain": [
1489
- "--border"
1489
+ "--border",
1490
+ "--foreground-subtle"
1490
1491
  ],
1491
1492
  "tailwind": [],
1492
1493
  "css-modules": [
1493
- "--border"
1494
+ "--border",
1495
+ "--foreground-subtle"
1494
1496
  ],
1495
1497
  "vanilla-extract": []
1496
1498
  },
@@ -35,7 +35,7 @@
35
35
  "badge": "상태 뱃지 — variant, size.",
36
36
  "progress": "선형 진행률 — value 0~100, indeterminate.",
37
37
  "spinner": "로딩 스피너 — size.",
38
- "separator": "구분선 — orientation(horizontal/vertical).",
38
+ "separator": "구분선 — 두 변종 한 컴포넌트: children 없으면 가로/세로 1px 선(orientation), children 있으면 가운데 라벨 \"── label ──\"(align=start/center/end, horizontal 강제). decorative={false} 시 role=separator.",
39
39
  "skeleton": "스켈레톤 로딩 플레이스홀더.",
40
40
  "code-panel": "Shiki 기반 코드 하이라이트 패널 — 복사 버튼 포함.",
41
41
  "code-tabs": "여러 코드 뷰(예: React/Flutter, 강조/전체)를 탭으로 전환 — Tabs + CodePanel 합성, 각 탭 내용은 CodePanelProps 그대로.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh-ui-cli",
3
- "version": "0.112.0",
3
+ "version": "0.113.0",
4
4
  "description": "sh-ui CLI — 프로젝트 스캐폴드(create) + 컴포넌트 추가(add/list/remove) + IDE-내 AI용 MCP 서버",
5
5
  "license": "MIT",
6
6
  "repository": {