sh-ui-cli 0.82.0 → 0.82.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.
- package/data/changelog/versions.json +23 -0
- package/data/registry/react/components/header/index.tailwind.tsx +1 -1
- package/data/registry/react/components/sidebar/index.tailwind.tsx +1 -1
- package/package.json +1 -1
- package/templates/nextjs-app/_arch/flat/components/layouts/RootLayout.tsx +3 -2
- package/templates/nextjs-app/_arch/fsd/src/app/layouts/RootLayout.tsx +6 -1
- package/templates/nextjs-app/_arch/mes/src/components/layouts/RootLayout.tsx +3 -2
- package/templates/nextjs-standalone/_arch/flat/components/layouts/RootLayout.tsx +3 -2
- package/templates/nextjs-standalone/_arch/fsd/src/app/layouts/RootLayout.tsx +3 -2
- package/templates/nextjs-standalone/_arch/mes/src/components/layouts/RootLayout.tsx +3 -2
|
@@ -2,6 +2,29 @@
|
|
|
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.82.2",
|
|
7
|
+
"date": "2026-05-13",
|
|
8
|
+
"title": "RootLayout themeInitScript 가 'system' 케이스 누락하던 FOUC 결함 수정",
|
|
9
|
+
"type": "patch",
|
|
10
|
+
"highlights": [
|
|
11
|
+
"**RootLayout 의 FOUC 차단 inline script 가 `theme === 'system'` 케이스를 처리 안 해 새로고침 시 light → dark 깜빡임이 남던 결함 수정** — 기존 스크립트는 `t === 'dark'` 또는 `!t && system pref dark` 만 처리, `t === 'system'` 일 땐 next-themes 가 resolve 한 후에야 `.dark` 가 박혀 한 frame 흰 깜빡임. next-themes 의 `setTheme('system')` 호출 직후 localStorage 에 `'system'` 문자열이 들어가는데 이 케이스가 누락. matrix 정정: `'dark'` → `.dark`, `'light'` → none, `'system'`/unset → system pref 따라감. 6개 RootLayout 템플릿 (nextjs-app · nextjs-standalone × flat/mes/fsd) 일괄 수정.",
|
|
12
|
+
"**알려진 이슈 (이번 릴리즈 미반영)** — `@base-ui/react` 1.4.1 의 id 생성기가 Dialog/DropdownMenu/Popover Trigger 에서 server/client id 불일치로 hydration mismatch console error 발생. upstream 이슈 — 1.4.1 이 npm 최신이라 dep bump 로 해결 불가. 기능 영향은 없고 console error 만 뜸. 향후 Base UI 픽스 버전 나오면 peerDep 갱신."
|
|
13
|
+
],
|
|
14
|
+
"url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.82.2"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"version": "0.82.1",
|
|
18
|
+
"date": "2026-05-13",
|
|
19
|
+
"title": "Sidebar / Header tailwind 변종의 결합 data 셀렉터 → Tailwind v4 호환 체이닝 수정",
|
|
20
|
+
"type": "patch",
|
|
21
|
+
"highlights": [
|
|
22
|
+
"**Sidebar tailwind 변종의 결합 data 셀렉터가 Tailwind v4 에서 미emit 되던 결함 수정** — `data-[state=collapsed][data-collapsible=offcanvas]:w-0` 류 형식이 Tailwind v4 파서에서 해석 안 되어 `<SidebarTrigger>` 클릭으로 `data-state` 가 토글돼도 width 가 그대로 유지되어 시각적으로 안 닫히던 결함. v4 호환 syntax (variant 체이닝) `data-[state=collapsed]:data-[collapsible=offcanvas]:w-0` 로 일괄 변환. offcanvas (w-0/border-r-0/border-l-0/overflow-hidden) + icon collapsible (w-[var(--sidebar-width-icon)]) 5개 selector 모두 적용.",
|
|
23
|
+
"**Header tailwind 변종의 동일 안티패턴 수정** — `data-[sticky-hide][data-hidden]:-translate-y-full` → `data-[sticky-hide]:data-[hidden]:-translate-y-full`. sticky-hide 모드의 스크롤-숨김 transform 이 적용 안 되던 결함 해소.",
|
|
24
|
+
"plain CSS / module CSS 변종은 영향 없음 — 처음부터 CSS attribute selector(`.sh-ui-sidebar[data-state=\"collapsed\"][data-collapsible=\"offcanvas\"]`) 라 정상 동작."
|
|
25
|
+
],
|
|
26
|
+
"url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.82.1"
|
|
27
|
+
},
|
|
5
28
|
{
|
|
6
29
|
"version": "0.82.0",
|
|
7
30
|
"date": "2026-05-13",
|
|
@@ -150,7 +150,7 @@ export const Header = React.forwardRef<HTMLElement, HeaderProps>(function Header
|
|
|
150
150
|
<header
|
|
151
151
|
ref={setRefs}
|
|
152
152
|
className={cn(
|
|
153
|
-
"relative flex items-center gap-[var(--space-4)] h-[var(--control-md)] px-[var(--space-3)] border-b border-border transition-[transform,background-color] duration-[var(--duration-base)] [--sh-ui-header-hover-bg:var(--background-muted)] [--sh-ui-header-blur-opacity:85%] [--sh-ui-header-blur-radius:16px] motion-reduce:transition-none max-md:gap-[var(--space-2)] data-[sticky-hide]
|
|
153
|
+
"relative flex items-center gap-[var(--space-4)] h-[var(--control-md)] px-[var(--space-3)] border-b border-border transition-[transform,background-color] duration-[var(--duration-base)] [--sh-ui-header-hover-bg:var(--background-muted)] [--sh-ui-header-blur-opacity:85%] [--sh-ui-header-blur-radius:16px] motion-reduce:transition-none max-md:gap-[var(--space-2)] data-[sticky-hide]:data-[hidden]:-translate-y-full",
|
|
154
154
|
variantClasses[variant],
|
|
155
155
|
className,
|
|
156
156
|
)}
|
|
@@ -149,7 +149,7 @@ export interface SidebarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
const sidebarRoot =
|
|
152
|
-
"flex flex-col w-[var(--sidebar-width)] shrink-0 bg-[var(--sidebar-bg)] text-[var(--sidebar-fg)] border-r border-[var(--sidebar-border)] transition-[width] duration-[var(--duration-slow)] relative z-[5] data-[side=right]:border-r-0 data-[side=right]:border-l data-[side=right]:order-1 data-[state=collapsed]
|
|
152
|
+
"flex flex-col w-[var(--sidebar-width)] shrink-0 bg-[var(--sidebar-bg)] text-[var(--sidebar-fg)] border-r border-[var(--sidebar-border)] transition-[width] duration-[var(--duration-slow)] relative z-[5] data-[side=right]:border-r-0 data-[side=right]:border-l data-[side=right]:order-1 data-[state=collapsed]:data-[collapsible=offcanvas]:w-0 data-[state=collapsed]:data-[collapsible=offcanvas]:border-r-0 data-[state=collapsed]:data-[collapsible=offcanvas]:border-l-0 data-[state=collapsed]:data-[collapsible=offcanvas]:overflow-hidden data-[state=collapsed]:data-[collapsible=icon]:w-[var(--sidebar-width-icon)] data-[variant=floating]:border-none data-[variant=floating]:p-[var(--space-2)] data-[variant=floating]:bg-transparent data-[variant=inset]:bg-transparent data-[variant=inset]:border-none motion-reduce:transition-none";
|
|
153
153
|
|
|
154
154
|
export function Sidebar({ side = "left", variant = "sidebar", collapsible = "offcanvas", className, children, ...props }: SidebarProps) {
|
|
155
155
|
const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { GlobalProvider } from '@/components/providers';
|
|
2
2
|
|
|
3
|
-
/** FOUC 차단 — next-themes mount 전에 첫 paint 에 dark
|
|
4
|
-
|
|
3
|
+
/** FOUC 차단 — next-themes mount 전에 첫 paint 에 dark class 박기.
|
|
4
|
+
* matrix: 'dark' → .dark, 'light' → (none), 'system'/unset → system pref. */
|
|
5
|
+
const themeInitScript = `try{var t=localStorage.getItem('theme');var d=t==='dark'||((!t||t==='system')&&matchMedia('(prefers-color-scheme:dark)').matches);if(d){document.documentElement.classList.add('dark');}}catch(e){}`;
|
|
5
6
|
|
|
6
7
|
export function RootLayout({ children }: { children: React.ReactNode }) {
|
|
7
8
|
// `lang` 은 앱의 주 언어. 영어 등 다른 언어 우선이면 'en' 으로 바꾸거나
|
|
@@ -5,8 +5,13 @@ import { GlobalProvider } from '@/src/app/providers';
|
|
|
5
5
|
* FOUC 차단 inline script. next-themes 의 ThemeProvider 가 client mount 후
|
|
6
6
|
* 동일 작업을 하지만, mount 전 한 frame 동안 light/dark 깜빡임이 생긴다.
|
|
7
7
|
* 이걸 막으려고 SSR 응답 head 안쪽에 동기 실행 script 박음.
|
|
8
|
+
*
|
|
9
|
+
* next-themes 의 theme 값 매트릭스:
|
|
10
|
+
* - 'dark' → .dark
|
|
11
|
+
* - 'light' → (no class — Tailwind 디폴트가 light)
|
|
12
|
+
* - 'system' 또는 unset → system pref 따라감
|
|
8
13
|
*/
|
|
9
|
-
const themeInitScript = `try{var t=localStorage.getItem('theme');var
|
|
14
|
+
const themeInitScript = `try{var t=localStorage.getItem('theme');var d=t==='dark'||((!t||t==='system')&&matchMedia('(prefers-color-scheme:dark)').matches);if(d){document.documentElement.classList.add('dark');}}catch(e){}`;
|
|
10
15
|
|
|
11
16
|
export function RootLayout({ children }: { children: React.ReactNode }) {
|
|
12
17
|
// `lang` 은 앱의 주 언어. 영어 등 다른 언어 우선이면 'en' 으로 바꾸거나
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { GlobalProvider } from '@/components/providers';
|
|
2
2
|
|
|
3
|
-
/** FOUC 차단 — next-themes mount 전에 첫 paint 에 dark
|
|
4
|
-
|
|
3
|
+
/** FOUC 차단 — next-themes mount 전에 첫 paint 에 dark class 박기.
|
|
4
|
+
* matrix: 'dark' → .dark, 'light' → (none), 'system'/unset → system pref. */
|
|
5
|
+
const themeInitScript = `try{var t=localStorage.getItem('theme');var d=t==='dark'||((!t||t==='system')&&matchMedia('(prefers-color-scheme:dark)').matches);if(d){document.documentElement.classList.add('dark');}}catch(e){}`;
|
|
5
6
|
|
|
6
7
|
export function RootLayout({ children }: { children: React.ReactNode }) {
|
|
7
8
|
// `lang` 은 앱의 주 언어. 영어 등 다른 언어 우선이면 'en' 으로 바꾸거나
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { GlobalProvider } from '@/components/providers';
|
|
2
2
|
|
|
3
|
-
/** FOUC 차단 — next-themes mount 전에 첫 paint 에 dark
|
|
4
|
-
|
|
3
|
+
/** FOUC 차단 — next-themes mount 전에 첫 paint 에 dark class 박기.
|
|
4
|
+
* matrix: 'dark' → .dark, 'light' → (none), 'system'/unset → system pref. */
|
|
5
|
+
const themeInitScript = `try{var t=localStorage.getItem('theme');var d=t==='dark'||((!t||t==='system')&&matchMedia('(prefers-color-scheme:dark)').matches);if(d){document.documentElement.classList.add('dark');}}catch(e){}`;
|
|
5
6
|
|
|
6
7
|
export function RootLayout({ children }: { children: React.ReactNode }) {
|
|
7
8
|
// `lang` 은 앱의 주 언어. 영어 등 다른 언어 우선이면 'en' 으로 바꾸거나
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { GlobalProvider } from '@/src/app/providers';
|
|
2
2
|
|
|
3
|
-
/** FOUC 차단 — next-themes mount 전에 첫 paint 에 dark
|
|
4
|
-
|
|
3
|
+
/** FOUC 차단 — next-themes mount 전에 첫 paint 에 dark class 박기.
|
|
4
|
+
* matrix: 'dark' → .dark, 'light' → (none), 'system'/unset → system pref. */
|
|
5
|
+
const themeInitScript = `try{var t=localStorage.getItem('theme');var d=t==='dark'||((!t||t==='system')&&matchMedia('(prefers-color-scheme:dark)').matches);if(d){document.documentElement.classList.add('dark');}}catch(e){}`;
|
|
5
6
|
|
|
6
7
|
export function RootLayout({ children }: { children: React.ReactNode }) {
|
|
7
8
|
// `lang` 은 앱의 주 언어. 영어 등 다른 언어 우선이면 'en' 으로 바꾸거나
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { GlobalProvider } from '@/components/providers';
|
|
2
2
|
|
|
3
|
-
/** FOUC 차단 — next-themes mount 전에 첫 paint 에 dark
|
|
4
|
-
|
|
3
|
+
/** FOUC 차단 — next-themes mount 전에 첫 paint 에 dark class 박기.
|
|
4
|
+
* matrix: 'dark' → .dark, 'light' → (none), 'system'/unset → system pref. */
|
|
5
|
+
const themeInitScript = `try{var t=localStorage.getItem('theme');var d=t==='dark'||((!t||t==='system')&&matchMedia('(prefers-color-scheme:dark)').matches);if(d){document.documentElement.classList.add('dark');}}catch(e){}`;
|
|
5
6
|
|
|
6
7
|
export function RootLayout({ children }: { children: React.ReactNode }) {
|
|
7
8
|
// `lang` 은 앱의 주 언어. 영어 등 다른 언어 우선이면 'en' 으로 바꾸거나
|