sh-ui-cli 0.83.0 → 0.84.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,19 @@
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.84.0",
7
+ "date": "2026-05-13",
8
+ "title": "Sidebar — Brand 컴파운드 primitive (브랜드 카드 · 워크스페이스 스위처 · 유저 프로필)",
9
+ "type": "minor",
10
+ "highlights": [
11
+ "**`SidebarBrand` 컴파운드 primitive 신설 — 브랜드 카드 / 워크스페이스 스위처 / 유저 프로필 의 90% 를 커버** — `<SidebarHeader>` / `<SidebarFooter>` 안에서 매번 박던 패턴 (icon + title + subtitle + trailing chevron) 을 단일 합성으로. Card/Dialog 와 동일한 separate-exports 컨벤션.",
12
+ "**Exports (6개)**: `SidebarBrand` (행 wrapper, 내부 `data-when-collapsed=\"center\"` 자동 적용) · `SidebarBrandIcon` (항상 visible, collapsed 시 sole 요소) · `SidebarBrandText` (`data-when-collapsed=\"hide\"`) · `SidebarBrandTitle` (단일 줄 본문, truncate 내장) · `SidebarBrandSubtitle` (보조 줄, foreground-muted) · `SidebarBrandAction` (`data-when-collapsed=\"hide\"`, ml-auto trailing icon).",
13
+ "**v0.83.0 의 `data-when-collapsed` 컨벤션 내장** — 사용자가 attribute 박지 않아도 collapsible=\"icon\" 모드 전환 시 자동 적응. 인터랙티브 케이스는 `<DropdownMenuTrigger render={<button data-when-collapsed=\"strip-chrome\" />}>` 로 wrap.",
14
+ "**3 변종 모두 지원** — plain `styles.css` / module `styles.module.css` 에 룰 직접, tailwind 변종은 utility 클래스로 동등 스타일. 듀얼카피 (apps/docs) 동기화."
15
+ ],
16
+ "url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.84.0"
17
+ },
5
18
  {
6
19
  "version": "0.83.0",
7
20
  "date": "2026-05-13",
@@ -511,6 +511,66 @@ export function SidebarFooter({ className, ...props }: React.HTMLAttributes<HTML
511
511
  );
512
512
  }
513
513
 
514
+ /* ───────────── Brand (compound primitive, v0.84.0+) ─────────────
515
+ * data-when-collapsed 컨벤션 내장. plain 변종 주석 참고. */
516
+
517
+ export function SidebarBrand({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
518
+ return (
519
+ <div
520
+ data-when-collapsed="center"
521
+ className={cn(styles.sidebar__brand, className)}
522
+ {...props}
523
+ />
524
+ );
525
+ }
526
+
527
+ export function SidebarBrandIcon({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
528
+ return (
529
+ <div
530
+ className={cn(styles.sidebar__brand_icon, className)}
531
+ {...props}
532
+ />
533
+ );
534
+ }
535
+
536
+ export function SidebarBrandText({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
537
+ return (
538
+ <div
539
+ data-when-collapsed="hide"
540
+ className={cn(styles.sidebar__brand_text, className)}
541
+ {...props}
542
+ />
543
+ );
544
+ }
545
+
546
+ export function SidebarBrandTitle({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
547
+ return (
548
+ <div
549
+ className={cn(styles.sidebar__brand_title, className)}
550
+ {...props}
551
+ />
552
+ );
553
+ }
554
+
555
+ export function SidebarBrandSubtitle({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
556
+ return (
557
+ <div
558
+ className={cn(styles.sidebar__brand_subtitle, className)}
559
+ {...props}
560
+ />
561
+ );
562
+ }
563
+
564
+ export function SidebarBrandAction({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
565
+ return (
566
+ <div
567
+ data-when-collapsed="hide"
568
+ className={cn(styles.sidebar__brand_action, className)}
569
+ {...props}
570
+ />
571
+ );
572
+ }
573
+
514
574
  /** Sidebar의 스크롤 영역. 메뉴/그룹 목록을 둔다. */
515
575
  export function SidebarContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
516
576
  return (
@@ -352,6 +352,66 @@ export function SidebarFooter({ className, ...props }: React.HTMLAttributes<HTML
352
352
  return <div className={cn("flex flex-col gap-[var(--space-2)] p-[var(--space-2)] overflow-hidden", className)} {...props} />;
353
353
  }
354
354
 
355
+ /* ───────────── Brand (compound primitive, v0.84.0+) ─────────────
356
+ * data-when-collapsed 컨벤션 내장. plain 변종 주석 참고. */
357
+
358
+ export function SidebarBrand({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
359
+ return (
360
+ <div
361
+ data-when-collapsed="center"
362
+ className={cn("flex flex-row items-center gap-[var(--space-2)] px-[var(--space-2)] py-[var(--space-2)] rounded-[var(--radius)] min-w-0", className)}
363
+ {...props}
364
+ />
365
+ );
366
+ }
367
+
368
+ export function SidebarBrandIcon({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
369
+ return (
370
+ <div
371
+ className={cn("flex items-center justify-center shrink-0 size-8 rounded-[calc(var(--radius)-2px)]", className)}
372
+ {...props}
373
+ />
374
+ );
375
+ }
376
+
377
+ export function SidebarBrandText({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
378
+ return (
379
+ <div
380
+ data-when-collapsed="hide"
381
+ className={cn("flex flex-col flex-1 min-w-0 gap-0", className)}
382
+ {...props}
383
+ />
384
+ );
385
+ }
386
+
387
+ export function SidebarBrandTitle({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
388
+ return (
389
+ <div
390
+ className={cn("text-[length:var(--text-sm)] font-[var(--weight-medium)] leading-tight truncate text-[color:var(--sidebar-fg)]", className)}
391
+ {...props}
392
+ />
393
+ );
394
+ }
395
+
396
+ export function SidebarBrandSubtitle({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
397
+ return (
398
+ <div
399
+ className={cn("text-[length:var(--text-xs)] leading-tight truncate text-[color:var(--foreground-muted)]", className)}
400
+ {...props}
401
+ />
402
+ );
403
+ }
404
+
405
+ export function SidebarBrandAction({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
406
+ return (
407
+ <div
408
+ data-when-collapsed="hide"
409
+ className={cn("ml-auto shrink-0 flex items-center justify-center", className)}
410
+ {...props}
411
+ />
412
+ );
413
+ }
414
+
355
415
  export function SidebarContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
356
416
  return <div className={cn("flex flex-col flex-1 min-h-0 overflow-y-auto gap-0", className)} {...props} />;
357
417
  }
@@ -521,6 +521,92 @@ export function SidebarFooter({ className, ...props }: React.HTMLAttributes<HTML
521
521
  );
522
522
  }
523
523
 
524
+ /* ───────────── Brand (compound primitive, v0.84.0+) ─────────────
525
+ * SidebarHeader / SidebarFooter 의 흔한 패턴 (브랜드 카드 · 워크스페이스 스위처 ·
526
+ * 유저 프로필) 의 90% 를 커버. data-when-collapsed 컨벤션을 내장해 사용자가
527
+ * attribute 박지 않아도 collapsed/icon 모드 자동 적응.
528
+ *
529
+ * 정적 예시:
530
+ * <SidebarBrand>
531
+ * <SidebarBrandIcon><Logo /></SidebarBrandIcon>
532
+ * <SidebarBrandText>
533
+ * <SidebarBrandTitle>Atlas</SidebarBrandTitle>
534
+ * <SidebarBrandSubtitle>workspace</SidebarBrandSubtitle>
535
+ * </SidebarBrandText>
536
+ * </SidebarBrand>
537
+ *
538
+ * 인터랙티브 (워크스페이스 스위처):
539
+ * <DropdownMenu>
540
+ * <DropdownMenuTrigger render={<button data-when-collapsed='strip-chrome' />}>
541
+ * <SidebarBrand>...</SidebarBrand>
542
+ * </DropdownMenuTrigger>
543
+ * ...
544
+ * </DropdownMenu>
545
+ */
546
+
547
+ /** 브랜드 행 wrapper. collapsed 일 땐 가운데 정렬 + 좌우 padding 0 (data-when-collapsed=center 내장). */
548
+ export function SidebarBrand({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
549
+ return (
550
+ <div
551
+ data-when-collapsed="center"
552
+ className={cn("sh-ui-sidebar__brand", className)}
553
+ {...props}
554
+ />
555
+ );
556
+ }
557
+
558
+ /** 항상 visible 한 아이콘 슬롯. collapsed 일 땐 SidebarBrand 의 유일한 요소. */
559
+ export function SidebarBrandIcon({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
560
+ return (
561
+ <div
562
+ className={cn("sh-ui-sidebar__brand-icon", className)}
563
+ {...props}
564
+ />
565
+ );
566
+ }
567
+
568
+ /** 텍스트 컨테이너. collapsed 일 땐 hidden (data-when-collapsed=hide 내장). */
569
+ export function SidebarBrandText({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
570
+ return (
571
+ <div
572
+ data-when-collapsed="hide"
573
+ className={cn("sh-ui-sidebar__brand-text", className)}
574
+ {...props}
575
+ />
576
+ );
577
+ }
578
+
579
+ /** 단일 줄 본문 (편의) — sh-ui-sidebar__brand-title 클래스만 박는다. */
580
+ export function SidebarBrandTitle({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
581
+ return (
582
+ <div
583
+ className={cn("sh-ui-sidebar__brand-title", className)}
584
+ {...props}
585
+ />
586
+ );
587
+ }
588
+
589
+ /** 보조 줄 — sh-ui-sidebar__brand-subtitle. text-foreground-muted + text-xs. */
590
+ export function SidebarBrandSubtitle({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
591
+ return (
592
+ <div
593
+ className={cn("sh-ui-sidebar__brand-subtitle", className)}
594
+ {...props}
595
+ />
596
+ );
597
+ }
598
+
599
+ /** Trailing icon (드롭다운 chevron 등). collapsed 일 땐 hidden. */
600
+ export function SidebarBrandAction({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
601
+ return (
602
+ <div
603
+ data-when-collapsed="hide"
604
+ className={cn("sh-ui-sidebar__brand-action", className)}
605
+ {...props}
606
+ />
607
+ );
608
+ }
609
+
524
610
  /** Sidebar의 스크롤 영역. 메뉴/그룹 목록을 둔다. */
525
611
  export function SidebarContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
526
612
  return (
@@ -318,6 +318,57 @@
318
318
  background-color: transparent;
319
319
  }
320
320
 
321
+ /* ───────────── Brand (compound primitive, v0.84.0+) ───────────── */
322
+ .sh-ui-sidebar__brand {
323
+ display: flex;
324
+ flex-direction: row;
325
+ align-items: center;
326
+ gap: var(--space-2);
327
+ padding: var(--space-2);
328
+ border-radius: var(--radius);
329
+ min-width: 0;
330
+ }
331
+ .sh-ui-sidebar__brand-icon {
332
+ display: flex;
333
+ align-items: center;
334
+ justify-content: center;
335
+ flex-shrink: 0;
336
+ width: 2rem;
337
+ height: 2rem;
338
+ border-radius: calc(var(--radius) - 2px);
339
+ }
340
+ .sh-ui-sidebar__brand-text {
341
+ display: flex;
342
+ flex-direction: column;
343
+ flex: 1 1 0%;
344
+ min-width: 0;
345
+ gap: 0;
346
+ }
347
+ .sh-ui-sidebar__brand-title {
348
+ font-size: var(--text-sm);
349
+ font-weight: var(--weight-medium);
350
+ line-height: 1.25;
351
+ color: var(--sidebar-fg);
352
+ white-space: nowrap;
353
+ overflow: hidden;
354
+ text-overflow: ellipsis;
355
+ }
356
+ .sh-ui-sidebar__brand-subtitle {
357
+ font-size: var(--text-xs);
358
+ line-height: 1.25;
359
+ color: var(--foreground-muted);
360
+ white-space: nowrap;
361
+ overflow: hidden;
362
+ text-overflow: ellipsis;
363
+ }
364
+ .sh-ui-sidebar__brand-action {
365
+ margin-left: auto;
366
+ flex-shrink: 0;
367
+ display: flex;
368
+ align-items: center;
369
+ justify-content: center;
370
+ }
371
+
321
372
  .sh-ui-sidebar__content {
322
373
  display: flex;
323
374
  flex-direction: column;
@@ -301,6 +301,57 @@
301
301
  background-color: transparent;
302
302
  }
303
303
 
304
+ /* ───────────── Brand (compound primitive, v0.84.0+) ───────────── */
305
+ .sidebar__brand {
306
+ display: flex;
307
+ flex-direction: row;
308
+ align-items: center;
309
+ gap: var(--space-2);
310
+ padding: var(--space-2);
311
+ border-radius: var(--radius);
312
+ min-width: 0;
313
+ }
314
+ .sidebar__brand_icon {
315
+ display: flex;
316
+ align-items: center;
317
+ justify-content: center;
318
+ flex-shrink: 0;
319
+ width: 2rem;
320
+ height: 2rem;
321
+ border-radius: calc(var(--radius) - 2px);
322
+ }
323
+ .sidebar__brand_text {
324
+ display: flex;
325
+ flex-direction: column;
326
+ flex: 1 1 0%;
327
+ min-width: 0;
328
+ gap: 0;
329
+ }
330
+ .sidebar__brand_title {
331
+ font-size: var(--text-sm);
332
+ font-weight: var(--weight-medium);
333
+ line-height: 1.25;
334
+ color: var(--sidebar-fg);
335
+ white-space: nowrap;
336
+ overflow: hidden;
337
+ text-overflow: ellipsis;
338
+ }
339
+ .sidebar__brand_subtitle {
340
+ font-size: var(--text-xs);
341
+ line-height: 1.25;
342
+ color: var(--foreground-muted);
343
+ white-space: nowrap;
344
+ overflow: hidden;
345
+ text-overflow: ellipsis;
346
+ }
347
+ .sidebar__brand_action {
348
+ margin-left: auto;
349
+ flex-shrink: 0;
350
+ display: flex;
351
+ align-items: center;
352
+ justify-content: center;
353
+ }
354
+
304
355
  .sidebar__content {
305
356
  display: flex;
306
357
  flex-direction: column;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$description": "컴포넌트별 토큰 의존성 (var(--*) 추출). build-registry-tokens.mjs 가 자동 생성.",
3
- "$generated": "2026-05-12T23:53:11.079Z",
3
+ "$generated": "2026-05-13T03:22:30.348Z",
4
4
  "components": {
5
5
  "button": {
6
6
  "plain": [
@@ -678,6 +678,7 @@
678
678
  "--duration-fast",
679
679
  "--duration-slow",
680
680
  "--foreground",
681
+ "--foreground-muted",
681
682
  "--opacity-disabled",
682
683
  "--radius",
683
684
  "--shadow-xl",
@@ -688,6 +689,7 @@
688
689
  "--text-lg",
689
690
  "--text-sm",
690
691
  "--text-xs",
692
+ "--weight-medium",
691
693
  "--z-modal",
692
694
  "--z-overlay"
693
695
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh-ui-cli",
3
- "version": "0.83.0",
3
+ "version": "0.84.0",
4
4
  "description": "sh-ui CLI — 프로젝트 스캐폴드(create) + 컴포넌트 추가(add/list/remove) + IDE-내 AI용 MCP 서버",
5
5
  "license": "MIT",
6
6
  "repository": {