sh-ui-cli 0.59.6 → 0.59.8
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.
- package/data/changelog/versions.json +27 -0
- package/data/registry/react/components/combobox/index.tailwind.tsx +1 -1
- package/data/registry/react/components/combobox/styles.css +1 -1
- package/data/registry/react/components/combobox/styles.module.css +1 -1
- package/data/registry/react/components/context-menu/index.tailwind.tsx +1 -1
- package/data/registry/react/components/date-picker/index.tailwind.tsx +1 -1
- package/data/registry/react/components/date-picker/styles.css +1 -1
- package/data/registry/react/components/date-picker/styles.module.css +1 -1
- package/data/registry/react/components/dropdown-menu/index.tailwind.tsx +1 -1
- package/data/registry/react/components/menubar/index.tailwind.tsx +1 -1
- package/data/registry/react/components/menubar/styles.css +1 -1
- package/data/registry/react/components/menubar/styles.module.css +1 -1
- package/data/registry/react/components/popover/index.tailwind.tsx +1 -1
- package/data/registry/react/components/popover/styles.css +1 -1
- package/data/registry/react/components/popover/styles.module.css +1 -1
- package/data/registry/react/components/select/index.tailwind.tsx +1 -1
- package/data/registry/react/components/sidebar/index.tailwind.tsx +1 -1
- package/data/registry/react/components/sidebar/styles.css +1 -1
- package/data/registry/react/components/sidebar/styles.module.css +1 -1
- package/data/registry/react/components/slider/index.tailwind.tsx +1 -1
- package/data/registry/react/components/slider/styles.css +1 -1
- package/data/registry/react/components/slider/styles.module.css +1 -1
- package/data/registry/react/components/switch/index.tailwind.tsx +1 -1
- package/data/registry/react/components/switch/styles.css +1 -1
- package/data/registry/react/components/switch/styles.module.css +1 -1
- package/data/registry/react/components/tabs/index.tailwind.tsx +1 -1
- package/data/registry/react/components/tabs/styles.css +1 -1
- package/data/registry/react/components/tabs/styles.module.css +1 -1
- package/data/registry/react/components/toast/index.tailwind.tsx +1 -1
- package/data/registry/react/components/toast/styles.css +1 -1
- package/data/registry/react/components/toast/styles.module.css +1 -1
- package/package.json +1 -1
- package/src/create/theme/inject.js +4 -1
- package/templates/nextjs-standalone/_arch/flat/app/globals.css +49 -0
- package/templates/nextjs-standalone/_arch/flat/lib/styles/tokens.css +1 -0
- package/templates/nextjs-standalone/_arch/fsd/src/shared/styles/tokens.css +1 -0
- package/templates/ui-app-template/src/styles/tokens.css +1 -0
|
@@ -2,6 +2,33 @@
|
|
|
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.59.8",
|
|
7
|
+
"date": "2026-05-06",
|
|
8
|
+
"title": "fix — flat standalone globals.css 토큰 import 경로",
|
|
9
|
+
"type": "patch",
|
|
10
|
+
"highlights": [
|
|
11
|
+
"**`sh-ui-cli create --arch flat --structure standalone` 빌드 폭발 수정** — 베이스 `app/globals.css` 가 fsd 경로(`../src/shared/styles/tokens.css`)를 하드코딩하고 있었고 `_arch/flat/` 에 오버라이드가 없어, flat standalone 으로 생성한 프로젝트는 `pnpm dev` 첫 페이지에서 tailwindcss 가 토큰 파일을 못 찾고 CssSyntaxError 로 죽었다.",
|
|
12
|
+
"**오버라이드 추가** — `_arch/flat/app/globals.css` 가 베이스를 덮어 `../lib/styles/tokens.css` 로 토큰을 import. 다른 토큰 주입(`injectCssTheme`)/마커 검증은 이미 flat 경로를 알고 있었어서 그쪽은 변경 불필요.",
|
|
13
|
+
"**회귀 가드** — 기존 flat 가드는 `.ts/.tsx` 만 검사해 `.css` 의 상대 import 누수를 못 잡았다. `globals.css 의 tokens import 가 실재하는 파일을 가리킴` 케이스를 smoke.test 에 추가해 재발 방지.",
|
|
14
|
+
"**영향 범위** — flat + standalone 조합만 해당. fsd standalone, 어떤 monorepo 조합도 영향 없음 (monorepo 는 토큰을 별도 패키지에서 import)."
|
|
15
|
+
],
|
|
16
|
+
"url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.59.8"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"version": "0.59.7",
|
|
20
|
+
"date": "2026-05-06",
|
|
21
|
+
"title": "라운드 7 — Shadow 토큰 일관화",
|
|
22
|
+
"type": "patch",
|
|
23
|
+
"highlights": [
|
|
24
|
+
"**하드코딩된 `box-shadow: ... rgba(0,0,0,X)` 를 토큰으로 교체** — 11+ 컴포넌트가 직접 알파 값을 박아 두던 그림자를 `var(--shadow-sm/md/lg/xl)` 로 통일. 토큰 정의(`tokens.css`)만 바꾸면 전체 조정 가능.",
|
|
25
|
+
"**`--shadow-menu` 신규 토큰** — 드롭다운/콘텍스트 메뉴/셀렉트의 multi-layer crispy 그림자(`0 4px 6px -1px ..., 0 2px 4px -2px ...`)는 단일 sm/md 와 다른 elevation 시그니처라 별도 토큰화. 4 tokens.css 위치 + inject.js 에 추가.",
|
|
26
|
+
"**대상 컴포넌트** — Combobox / Context-Menu / Date-Picker / Dropdown-Menu / Menubar / Popover / Select / Sidebar / Slider / Switch / Tabs / Toast.",
|
|
27
|
+
"**유지한 예외** — Color-picker thumb 의 `0 0 0 1px rgba(0,0,0,0.4)` 는 그림자가 아니라 어떤 색 위에서도 보여야 하는 1px 테두리. Header dropdown 의 `0 8px 24px -8px ...` 는 negative spread 가 의도적 (사이드 절단).",
|
|
28
|
+
"**다크 모드 영향** — 토큰화로 향후 다크 전용 shadow 값 분기 (예: 더 강한 알파 + 컬러 시프트) 가 1 라인 변경으로 가능."
|
|
29
|
+
],
|
|
30
|
+
"url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.59.7"
|
|
31
|
+
},
|
|
5
32
|
{
|
|
6
33
|
"version": "0.59.6",
|
|
7
34
|
"date": "2026-05-06",
|
|
@@ -48,7 +48,7 @@ export const ComboboxContent = React.forwardRef<
|
|
|
48
48
|
<BaseCombobox.Popup
|
|
49
49
|
ref={ref}
|
|
50
50
|
className={cn(
|
|
51
|
-
"max-h-[min(20rem,var(--available-height))] overflow-y-auto p-[var(--space-1)] bg-background text-foreground border border-border rounded-[var(--radius)] shadow-[
|
|
51
|
+
"max-h-[min(20rem,var(--available-height))] overflow-y-auto p-[var(--space-1)] bg-background text-foreground border border-border rounded-[var(--radius)] shadow-[var(--shadow-lg)] outline-none origin-[var(--transform-origin)] transition-[opacity,transform] duration-[140ms] ease-out motion-reduce:transition-none data-[starting-style]:opacity-0 data-[starting-style]:scale-[0.97] data-[ending-style]:opacity-0 data-[ending-style]:scale-[0.97]",
|
|
52
52
|
className,
|
|
53
53
|
)}
|
|
54
54
|
{...props}
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
color: var(--foreground);
|
|
45
45
|
border: 1px solid var(--border);
|
|
46
46
|
border-radius: var(--radius);
|
|
47
|
-
box-shadow:
|
|
47
|
+
box-shadow: var(--shadow-lg);
|
|
48
48
|
outline: none;
|
|
49
49
|
transform-origin: var(--transform-origin);
|
|
50
50
|
transition: opacity 140ms ease, transform 140ms ease;
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
color: var(--foreground);
|
|
45
45
|
border: 1px solid var(--border);
|
|
46
46
|
border-radius: var(--radius);
|
|
47
|
-
box-shadow:
|
|
47
|
+
box-shadow: var(--shadow-lg);
|
|
48
48
|
outline: none;
|
|
49
49
|
transform-origin: var(--transform-origin);
|
|
50
50
|
transition: opacity 140ms ease, transform 140ms ease;
|
|
@@ -9,7 +9,7 @@ const itemBase =
|
|
|
9
9
|
"relative flex items-center gap-[var(--space-2)] py-2 px-3 rounded-[calc(var(--radius)-2px)] cursor-pointer outline-none select-none transition-colors duration-[80ms] data-[highlighted]:bg-background-muted hover:bg-background-muted data-[disabled]:opacity-[var(--opacity-disabled)] data-[disabled]:pointer-events-none motion-reduce:transition-none";
|
|
10
10
|
const itemCheck = "pl-7";
|
|
11
11
|
const contentClasses =
|
|
12
|
-
"min-w-40 max-h-[min(24rem,var(--available-height,24rem))] overflow-y-auto p-[var(--space-1)] bg-background text-foreground border border-border rounded-[var(--radius)] shadow-[
|
|
12
|
+
"min-w-40 max-h-[min(24rem,var(--available-height,24rem))] overflow-y-auto p-[var(--space-1)] bg-background text-foreground border border-border rounded-[var(--radius)] shadow-[var(--shadow-menu)] text-[length:var(--text-sm)] origin-[var(--transform-origin)] animate-[sh-ui-cm-in_140ms_ease-out] data-[ending-style]:animate-[sh-ui-cm-out_100ms_ease-in_forwards] outline-none motion-reduce:animate-none motion-reduce:data-[ending-style]:animate-none";
|
|
13
13
|
|
|
14
14
|
export const ContextMenu = BaseContextMenu.Root;
|
|
15
15
|
|
|
@@ -25,7 +25,7 @@ const triggerClasses =
|
|
|
25
25
|
"inline-flex items-center justify-between w-full h-[var(--control-md)] px-[var(--space-3)] bg-background text-foreground border border-border rounded-[var(--radius)] font-[inherit] text-[length:var(--text-sm)] leading-none cursor-pointer transition-[border-color,box-shadow] duration-[var(--duration-fast)] hover:not-disabled:border-border-strong focus-visible:outline-none focus-visible:border-primary focus-visible:shadow-[0_0_0_1px_var(--primary)] disabled:opacity-[var(--opacity-disabled)] disabled:cursor-not-allowed disabled:bg-background-subtle aria-[invalid=true]:border-danger aria-[invalid=true]:focus-visible:shadow-[0_0_0_1px_var(--danger)] [@media(hover:none)_and_(pointer:coarse)]:h-11 [@media(hover:none)_and_(pointer:coarse)]:text-[length:var(--text-base)]";
|
|
26
26
|
|
|
27
27
|
const popupClasses =
|
|
28
|
-
"bg-background border border-border rounded-[var(--radius)] shadow-[
|
|
28
|
+
"bg-background border border-border rounded-[var(--radius)] shadow-[var(--shadow-lg)] outline-none p-[var(--space-3)] origin-[var(--transform-origin)] transition-[opacity,transform] duration-[140ms] ease-out motion-reduce:transition-none data-[starting-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:scale-95";
|
|
29
29
|
|
|
30
30
|
function CalendarIcon() {
|
|
31
31
|
return (
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
background: var(--background);
|
|
78
78
|
border: 1px solid var(--border);
|
|
79
79
|
border-radius: var(--radius);
|
|
80
|
-
box-shadow:
|
|
80
|
+
box-shadow: var(--shadow-lg);
|
|
81
81
|
outline: none;
|
|
82
82
|
padding: var(--space-3);
|
|
83
83
|
transform-origin: var(--transform-origin);
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
background: var(--background);
|
|
78
78
|
border: 1px solid var(--border);
|
|
79
79
|
border-radius: var(--radius);
|
|
80
|
-
box-shadow:
|
|
80
|
+
box-shadow: var(--shadow-lg);
|
|
81
81
|
outline: none;
|
|
82
82
|
padding: var(--space-3);
|
|
83
83
|
transform-origin: var(--transform-origin);
|
|
@@ -53,7 +53,7 @@ export const DropdownMenuContent = React.forwardRef<HTMLDivElement, DropdownMenu
|
|
|
53
53
|
<BaseMenu.Popup
|
|
54
54
|
ref={ref}
|
|
55
55
|
className={cn(
|
|
56
|
-
"min-w-40 max-h-[min(24rem,var(--available-height,24rem))] overflow-y-auto p-[var(--space-1)] bg-background text-foreground border border-border rounded-[var(--radius)] shadow-[
|
|
56
|
+
"min-w-40 max-h-[min(24rem,var(--available-height,24rem))] overflow-y-auto p-[var(--space-1)] bg-background text-foreground border border-border rounded-[var(--radius)] shadow-[var(--shadow-menu)] text-[length:var(--text-sm)] origin-[var(--transform-origin)] animate-[sh-ui-dm-in_140ms_ease-out] data-[ending-style]:animate-[sh-ui-dm-out_100ms_ease-in_forwards] outline-none motion-reduce:animate-none motion-reduce:data-[ending-style]:animate-none",
|
|
57
57
|
className,
|
|
58
58
|
)}
|
|
59
59
|
{...props}
|
|
@@ -21,7 +21,7 @@ export const Menubar = React.forwardRef<
|
|
|
21
21
|
<BaseMenubar
|
|
22
22
|
ref={ref}
|
|
23
23
|
className={cn(
|
|
24
|
-
"inline-flex items-center gap-[var(--space-1)] p-[var(--space-1)] bg-background border border-border rounded-[var(--radius)] shadow-[
|
|
24
|
+
"inline-flex items-center gap-[var(--space-1)] p-[var(--space-1)] bg-background border border-border rounded-[var(--radius)] shadow-[var(--shadow-sm)]",
|
|
25
25
|
className,
|
|
26
26
|
)}
|
|
27
27
|
{...props}
|
|
@@ -34,7 +34,7 @@ export const PopoverContent = React.forwardRef<HTMLDivElement, PopoverContentPro
|
|
|
34
34
|
<BasePopover.Popup
|
|
35
35
|
ref={ref}
|
|
36
36
|
className={cn(
|
|
37
|
-
"min-w-48 p-[var(--space-2)] bg-background text-foreground border border-border rounded-[var(--radius)] shadow-[
|
|
37
|
+
"min-w-48 p-[var(--space-2)] bg-background text-foreground border border-border rounded-[var(--radius)] shadow-[var(--shadow-lg)] outline-none text-[length:var(--text-sm)] leading-snug origin-[var(--transform-origin)] transition-[opacity,transform] duration-[140ms] ease-out motion-reduce:transition-none data-[starting-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:scale-95 motion-reduce:data-[starting-style]:scale-100 motion-reduce:data-[ending-style]:scale-100 focus-visible:outline-[length:var(--border-width-strong)] focus-visible:outline-ring focus-visible:outline-offset-2",
|
|
38
38
|
className,
|
|
39
39
|
)}
|
|
40
40
|
{...props}
|
|
@@ -60,7 +60,7 @@ export const SelectContent = React.forwardRef<
|
|
|
60
60
|
<BaseSelect.Popup
|
|
61
61
|
ref={ref}
|
|
62
62
|
className={cn(
|
|
63
|
-
"min-w-[var(--anchor-width,10rem)] max-h-[min(24rem,var(--available-height,24rem))] overflow-y-auto p-[var(--space-1)] bg-background text-foreground border border-border rounded-[var(--radius)] shadow-[
|
|
63
|
+
"min-w-[var(--anchor-width,10rem)] max-h-[min(24rem,var(--available-height,24rem))] overflow-y-auto p-[var(--space-1)] bg-background text-foreground border border-border rounded-[var(--radius)] shadow-[var(--shadow-menu)] text-[length:var(--text-sm)] origin-[var(--transform-origin)] animate-[sh-ui-select-in_140ms_ease-out] data-[ending-style]:animate-[sh-ui-select-out_100ms_ease-in_forwards] motion-reduce:animate-none motion-reduce:data-[ending-style]:animate-none",
|
|
64
64
|
className,
|
|
65
65
|
)}
|
|
66
66
|
{...props}
|
|
@@ -262,7 +262,7 @@ export function SidebarPanel({ id, className, children, ...props }: SidebarPanel
|
|
|
262
262
|
return (
|
|
263
263
|
<aside
|
|
264
264
|
ref={ref}
|
|
265
|
-
className={cn("[--sidebar-panel-width:20rem] flex flex-col w-[var(--sidebar-panel-width)] shrink-0 bg-background border-r border-[var(--sidebar-border)] relative z-[4] overflow-hidden animate-[sh-ui-sidebar-panel-in_180ms_ease-out] data-[state=closed]:hidden max-md:fixed max-md:top-0 max-md:bottom-0 max-md:left-0 max-md:w-[min(var(--sidebar-panel-width),90vw)] max-md:z-[var(--z-modal)] max-md:shadow-[
|
|
265
|
+
className={cn("[--sidebar-panel-width:20rem] flex flex-col w-[var(--sidebar-panel-width)] shrink-0 bg-background border-r border-[var(--sidebar-border)] relative z-[4] overflow-hidden animate-[sh-ui-sidebar-panel-in_180ms_ease-out] data-[state=closed]:hidden max-md:fixed max-md:top-0 max-md:bottom-0 max-md:left-0 max-md:w-[min(var(--sidebar-panel-width),90vw)] max-md:z-[var(--z-modal)] max-md:shadow-[var(--shadow-xl)] motion-reduce:animate-none",
|
|
266
266
|
className)}
|
|
267
267
|
data-state={open ? "open" : "closed"}
|
|
268
268
|
role={isMobile ? "dialog" : undefined}
|
|
@@ -244,7 +244,7 @@
|
|
|
244
244
|
width: min(var(--sidebar-panel-width), 90vw);
|
|
245
245
|
z-index: var(--z-modal);
|
|
246
246
|
border-inline-end: 1px solid var(--sidebar-border);
|
|
247
|
-
box-shadow:
|
|
247
|
+
box-shadow: var(--shadow-xl);
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
.sh-ui-sidebar-wrapper[data-embedded] .sh-ui-sidebar__panel {
|
|
@@ -244,7 +244,7 @@
|
|
|
244
244
|
width: min(var(--sidebar-panel-width), 90vw);
|
|
245
245
|
z-index: var(--z-modal);
|
|
246
246
|
border-inline-end: 1px solid var(--sidebar-border);
|
|
247
|
-
box-shadow:
|
|
247
|
+
box-shadow: var(--shadow-xl);
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
.sidebar-wrapper[data-embedded] .sidebar__panel {
|
|
@@ -242,7 +242,7 @@ export const SliderThumb = React.forwardRef<
|
|
|
242
242
|
aria-disabled={disabled || undefined}
|
|
243
243
|
onKeyDown={onKeyDown}
|
|
244
244
|
className={cn(
|
|
245
|
-
"absolute top-1/2 w-4 h-4 -ml-2 -translate-y-1/2 bg-background border-2 border-primary rounded-full shadow-[
|
|
245
|
+
"absolute top-1/2 w-4 h-4 -ml-2 -translate-y-1/2 bg-background border-2 border-primary rounded-full shadow-[var(--shadow-sm)] cursor-grab transition-transform duration-[80ms] active:cursor-grabbing active:scale-110 active:-translate-y-1/2 focus-visible:outline-[length:var(--border-width-strong)] focus-visible:outline-ring focus-visible:outline-offset-2 [@media(hover:none)_and_(pointer:coarse)]:w-5 [@media(hover:none)_and_(pointer:coarse)]:h-5 [@media(hover:none)_and_(pointer:coarse)]:-ml-2.5",
|
|
246
246
|
className,
|
|
247
247
|
)}
|
|
248
248
|
style={{ left: percent, ...style }}
|
|
@@ -18,7 +18,7 @@ const switchRoot = cva(
|
|
|
18
18
|
);
|
|
19
19
|
|
|
20
20
|
const switchThumb = cva(
|
|
21
|
-
"block rounded-full bg-white shadow-[
|
|
21
|
+
"block rounded-full bg-white shadow-[var(--shadow-sm)] transition-transform duration-150 ease-out motion-reduce:transition-none forced-colors:[background:ButtonText] forced-colors:data-[checked]:[background:HighlightText] forced-colors:data-[disabled]:[background:GrayText]",
|
|
22
22
|
{
|
|
23
23
|
variants: {
|
|
24
24
|
size: {
|
|
@@ -75,7 +75,7 @@ export const TabsTrigger = React.forwardRef<
|
|
|
75
75
|
TabsTrigger.displayName = "TabsTrigger";
|
|
76
76
|
|
|
77
77
|
const indicatorVariantClasses =
|
|
78
|
-
"[[data-variant=underline]_&]:shadow-[inset_0_-2px_0_var(--primary)] [[data-variant=pill]_&]:bg-background [[data-variant=pill]_&]:rounded-[calc(var(--radius)-2px)] [[data-variant=pill]_&]:shadow-[
|
|
78
|
+
"[[data-variant=underline]_&]:shadow-[inset_0_-2px_0_var(--primary)] [[data-variant=pill]_&]:bg-background [[data-variant=pill]_&]:rounded-[calc(var(--radius)-2px)] [[data-variant=pill]_&]:shadow-[var(--shadow-sm)] [[data-variant=plain]_&]:hidden [[data-orientation=vertical][data-variant=underline]_&]:shadow-[inset_-2px_0_0_var(--primary)] forced-colors:[[data-variant=underline]_&]:shadow-[inset_0_-2px_0_Highlight] forced-colors:[[data-variant=pill]_&]:[border:1px_solid_Highlight] forced-colors:[[data-variant=pill]_&]:[background:ButtonFace] forced-colors:[[data-orientation=vertical][data-variant=underline]_&]:shadow-[inset_-2px_0_0_Highlight]";
|
|
79
79
|
|
|
80
80
|
export const TabsIndicator = React.forwardRef<
|
|
81
81
|
HTMLSpanElement,
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
height: var(--active-tab-height);
|
|
131
131
|
background: var(--background);
|
|
132
132
|
border-radius: calc(var(--radius) - 2px);
|
|
133
|
-
box-shadow:
|
|
133
|
+
box-shadow: var(--shadow-sm);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
/* ─────────────── variant: plain (컨테이너 없음) ─────────────── */
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
height: var(--active-tab-height);
|
|
131
131
|
background: var(--background);
|
|
132
132
|
border-radius: calc(var(--radius) - 2px);
|
|
133
|
-
box-shadow:
|
|
133
|
+
box-shadow: var(--shadow-sm);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
/* ─────────────── variant: plain (컨테이너 없음) ─────────────── */
|
|
@@ -107,7 +107,7 @@ function ToastCard({ item, onDismiss }: { item: ToastItem; onDismiss: () => void
|
|
|
107
107
|
|
|
108
108
|
return (
|
|
109
109
|
<div
|
|
110
|
-
className="sh-ui-toast relative flex items-start gap-2.5 w-full pl-[var(--space-3)] pr-9 py-[var(--space-3)] bg-background text-foreground border border-border rounded-[var(--radius)] shadow-[
|
|
110
|
+
className="sh-ui-toast relative flex items-start gap-2.5 w-full pl-[var(--space-3)] pr-9 py-[var(--space-3)] bg-background text-foreground border border-border rounded-[var(--radius)] shadow-[var(--shadow-md)] pointer-events-auto motion-reduce:!animate-none"
|
|
111
111
|
role={item.variant === "danger" ? "alert" : "status"}
|
|
112
112
|
aria-live={item.variant === "danger" ? "assertive" : "polite"}
|
|
113
113
|
data-exiting={exiting || undefined}
|
package/package.json
CHANGED
|
@@ -303,7 +303,10 @@ const colorToARGBHex = ({ a, r, g, b }) => {
|
|
|
303
303
|
const SHADOW_KEYS = ['sm', 'md', 'lg', 'xl'];
|
|
304
304
|
|
|
305
305
|
export const buildCssShadowsBlock = (shadows) =>
|
|
306
|
-
|
|
306
|
+
[
|
|
307
|
+
...SHADOW_KEYS.map((k) => ` --shadow-${k}: ${shadows[k]};`),
|
|
308
|
+
` --shadow-menu: 0 4px 6px -1px rgba(0, 0, 0, 0.08), 0 2px 4px -2px rgba(0, 0, 0, 0.05);`,
|
|
309
|
+
].join('\n');
|
|
307
310
|
|
|
308
311
|
const parseSingleBoxShadow = (s) => {
|
|
309
312
|
const tokens = tokenizeSpaceAware(s);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
@import 'tailwindcss';
|
|
2
|
+
@import '../lib/styles/tokens.css';
|
|
3
|
+
|
|
4
|
+
@custom-variant dark (&:is(.dark *));
|
|
5
|
+
|
|
6
|
+
/* Tailwind v4 — 토큰 CSS 변수를 utility 클래스로 노출.
|
|
7
|
+
* `bg-primary` / `text-foreground` 같은 클래스가 토큰을 따라가도록 매핑.
|
|
8
|
+
* 옵셔널 색(success/warning/info)은 토큰에 없으면 변수가 undefined 라 browsers 가 단순 무시 — 안전.
|
|
9
|
+
*
|
|
10
|
+
* flat overlay — 베이스(`app/globals.css`)는 fsd 경로로 토큰을 import 하므로
|
|
11
|
+
* flat arch 에서는 이 파일이 베이스를 덮어 `lib/styles/tokens.css` 로 보낸다.
|
|
12
|
+
* 베이스 globals.css 내용 변경 시 이 파일도 동일하게 동기화할 것.
|
|
13
|
+
*/
|
|
14
|
+
@theme inline {
|
|
15
|
+
--color-background: var(--background);
|
|
16
|
+
--color-background-subtle: var(--background-subtle);
|
|
17
|
+
--color-background-muted: var(--background-muted);
|
|
18
|
+
--color-background-inverse: var(--background-inverse);
|
|
19
|
+
--color-foreground: var(--foreground);
|
|
20
|
+
--color-foreground-muted: var(--foreground-muted);
|
|
21
|
+
--color-foreground-subtle: var(--foreground-subtle);
|
|
22
|
+
--color-foreground-inverse: var(--foreground-inverse);
|
|
23
|
+
--color-border: var(--border);
|
|
24
|
+
--color-border-strong: var(--border-strong);
|
|
25
|
+
--color-primary: var(--primary);
|
|
26
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
27
|
+
--color-primary-hover: var(--primary-hover);
|
|
28
|
+
--color-ring: var(--ring);
|
|
29
|
+
--color-danger: var(--danger);
|
|
30
|
+
--color-danger-hover: var(--danger-hover);
|
|
31
|
+
--color-danger-foreground: var(--danger-foreground);
|
|
32
|
+
--color-success: var(--success);
|
|
33
|
+
--color-success-foreground: var(--success-foreground);
|
|
34
|
+
--color-warning: var(--warning);
|
|
35
|
+
--color-warning-foreground: var(--warning-foreground);
|
|
36
|
+
--color-info: var(--info);
|
|
37
|
+
--color-info-foreground: var(--info-foreground);
|
|
38
|
+
--radius-sm: calc(var(--radius) - 2px);
|
|
39
|
+
--radius-md: var(--radius);
|
|
40
|
+
--radius-lg: calc(var(--radius) + 2px);
|
|
41
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@layer base {
|
|
45
|
+
body {
|
|
46
|
+
background: var(--background);
|
|
47
|
+
color: var(--foreground);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
100
100
|
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.15);
|
|
101
101
|
--shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.18);
|
|
102
|
+
--shadow-menu: 0 4px 6px -1px rgba(0, 0, 0, 0.08), 0 2px 4px -2px rgba(0, 0, 0, 0.05);
|
|
102
103
|
/* sh-ui:theme-shadow-end */
|
|
103
104
|
/* sh-ui:theme-duration-start */
|
|
104
105
|
--duration-fast: 120ms;
|
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
100
100
|
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.15);
|
|
101
101
|
--shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.18);
|
|
102
|
+
--shadow-menu: 0 4px 6px -1px rgba(0, 0, 0, 0.08), 0 2px 4px -2px rgba(0, 0, 0, 0.05);
|
|
102
103
|
/* sh-ui:theme-shadow-end */
|
|
103
104
|
/* sh-ui:theme-duration-start */
|
|
104
105
|
--duration-fast: 120ms;
|
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
100
100
|
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.15);
|
|
101
101
|
--shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.18);
|
|
102
|
+
--shadow-menu: 0 4px 6px -1px rgba(0, 0, 0, 0.08), 0 2px 4px -2px rgba(0, 0, 0, 0.05);
|
|
102
103
|
/* sh-ui:theme-shadow-end */
|
|
103
104
|
/* sh-ui:theme-duration-start */
|
|
104
105
|
--duration-fast: 120ms;
|