Feat(design-system): toggle component 구현#17
Conversation
Walkthrough디자인 시스템에 Radix 기반 Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor App as 소비자(App)
participant DS as DesignSystem.Switch
participant Radix as Radix.SwitchPrimitive
App->>DS: <Switch {...props} />
DS->>Radix: Render Root with props (forward ref/props)
Radix->>DS: 상태 이벤트 (checked/focus/disabled)
DS-->>App: 콜백/props로 상태·변경 전파
note right of DS #e0f7fa: 클래스 결합으로 상태·다크·비활성 스타일 적용
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. 📜 Recent review detailsConfiguration used: .coderabbit.yaml 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/design-system/styles.css (1)
24-25: 라이트 모드에서--destructive와--destructive-foreground가 동일 — 가독성/접근성 심각 이슈:root에서 두 변수가 동일 색상으로 설정되어 있어 파괴적 버튼/배경과 전경 텍스트가 구분되지 않습니다. 즉시 수정이 필요합니다.
다음과 같이 전경색을 명확히 대비되는 값으로 조정해 주세요(예: 거의 흰색):
- --destructive: oklch(0.577 0.245 27.325); - --destructive-foreground: oklch(0.577 0.245 27.325); + --destructive: oklch(0.577 0.245 27.325); + --destructive-foreground: oklch(0.985 0 0);또는 이미 정의된
--primary-foreground등을 재사용해도 됩니다.
🧹 Nitpick comments (6)
packages/design-system/package.json (1)
1-45: CSS 트리셰이킹 방지와 React 중복 설치 방지 설정 제안
- 디자인 시스템의 CSS가 소비 앱 번들 과정에서 트리셰이킹으로 제거되지 않도록
sideEffects에./styles.css를 명시하는 것을 권장합니다.- 컴포넌트 라이브러리 특성상
react,react-dom은dependencies가 아니라peerDependencies로 선언하는 편이 중복 인스톨과 리액트 다중 인스턴스 문제를 예방합니다. 현재 패키지는 private이긴 하지만 워크스페이스 외부 소비 가능성을 고려하면 선제적으로 맞춰두는 것이 안전합니다.다음과 같이 변경을 제안드립니다.
{ "name": "@pinback/design-system", "version": "0.0.0", "type": "module", "private": true, "exports": { "./ui": "./src/components/index.ts", "./icons": "./src/icons/index.ts", "./styles": "./styles.css", "./utils": "./src/lib/index.ts" }, + "sideEffects": ["./styles.css"], "scripts": { "lint": "eslint .", "build": "vite build", "check-types": "tsc --noEmit", "generate:component": "turbo gen react-component" }, "devDependencies": { ... }, - "dependencies": { + "dependencies": { "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-switch": "^1.2.6", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^0.540.0", - "react": "^19.1.0", - "react-dom": "^19.1.0", + "lucide-react": "^0.540.0", "tailwind-merge": "^3.3.1", "tw-animate-css": "^1.3.7" }, + "peerDependencies": { + "react": "^19.0.0", + "react-dom": "^19.0.0" + } }packages/design-system/src/components/index.ts (2)
1-2: 이름 논의: Switch 유지 권장 (Toggle로 변경 비권장)
- Radix에는 Switch와 Toggle(버튼) 두 프리미티브가 모두 존재합니다. Toggle은 토글 가능한 버튼(aria-pressed), Switch는 이진 on/off(aria-checked) 의미가 달라 충돌 소지가 있습니다.
- 접근성과 API 기대치(폼 값 등)를 고려하면 현재 구현은 Switch가 더 정확한 도메인 명칭입니다.
1-2: Barrel export 스타일 일관화 제안
Button은 default export,Switch는 named export로 섞여 있습니다. 신규 컴포넌트가 계속 추가될 예정이라면 다음 릴리스에서 일괄 named export로 통일하는 것을 고려해 주세요(브레이킹 변경).예시:
- export { default as Button } from './button/Button'; - export { Switch } from './switch/switch'; + export { Button } from './button/Button'; + export { Switch } from './switch/switch';단, 이 변경은 소비 측 전역 코드 변경이 필요합니다.
apps/landing/src/App.tsx (1)
12-16: 보안 헤더 보강: rel="noopener noreferrer" 사용 권장
target="_blank"링크에rel="noreferrer"만 있어도 대부분의 브라우저에서noopener가 포함되지만, 호환성과 명시성을 위해 둘 다 명시하는 것을 권장합니다.- <a href="https://vite.dev" target="_blank" rel="noreferrer"> + <a href="https://vite.dev" target="_blank" rel="noopener noreferrer"> ... - <a href="https://react.dev" target="_blank" rel="noreferrer"> + <a href="https://react.dev" target="_blank" rel="noopener noreferrer">packages/design-system/src/components/switch/switch.tsx (2)
11-27: 여분 래퍼 div 제거 제안
<div className="text-main600">래퍼는 불필요한 DOM 깊이를 추가하고, 의도치 않게 텍스트 색이 자식에 상속될 수 있습니다. Root에 필요한 스타일만 두고 래퍼는 제거하는 편이 낫습니다(위 diff에 포함).
6-10: 접근성 가이드컴포넌트 자체는 ARIA role/state를 제공하지만, 레이블이 없는 단독 사용 시 소비 측에서
aria-label또는 연관<label htmlFor>제공이 필요합니다. 문서화에 한 줄 안내를 추가하면 재사용성이 좋아집니다.원하시면 Story/Docs에 접근성 사용 섹션을 추가해 드릴게요.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
apps/landing/src/App.tsx(2 hunks)packages/design-system/package.json(2 hunks)packages/design-system/src/components/index.ts(1 hunks)packages/design-system/src/components/switch/switch.tsx(1 hunks)packages/design-system/styles.css(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-08-19T17:18:57.657Z
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#5
File: apps/extension/src/index.css:1-1
Timestamp: 2025-08-19T17:18:57.657Z
Learning: constantly-dev는 디자인 시스템 설정 PR 머지 후 `import 'pinback/tailwind-config/shared-styles.css';`를 `app.css`나 `index.css`에서 사용하여 공유 스타일을 관리할 계획입니다.
Applied to files:
packages/design-system/styles.css
📚 Learning: 2025-07-04T10:12:01.690Z
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#10
File: apps/landing/src/index.css:1-1
Timestamp: 2025-07-04T10:12:01.690Z
Learning: In TailwindCSS v4, the import "tailwindcss"; syntax is the new recommended approach that replaces the three separate tailwind directives (tailwind base;, tailwind components;, tailwind utilities;). This single import pulls in all of Tailwind's preflight, components, and utilities in one step and is used with the tailwindcss/vite plugin.
Applied to files:
packages/design-system/styles.css
📚 Learning: 2025-07-04T10:12:01.690Z
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#10
File: apps/landing/src/index.css:1-1
Timestamp: 2025-07-04T10:12:01.690Z
Learning: In TailwindCSS v4, the import "tailwindcss"; syntax is the new recommended approach that replaces the three separate tailwind directives (tailwind base;, tailwind components;, tailwind utilities;). This is used with the tailwindcss/vite plugin.
Applied to files:
packages/design-system/styles.csspackages/design-system/package.json
🧬 Code graph analysis (1)
packages/design-system/src/components/switch/switch.tsx (2)
packages/design-system/src/components/index.ts (1)
Switch(2-2)packages/design-system/src/lib/utils.ts (1)
cn(108-110)
🔇 Additional comments (6)
packages/design-system/package.json (2)
36-36: Radix Switch 의존성 추가 적절새 컴포넌트 구현에 필요한
@radix-ui/react-switch추가가 정확합니다. 버전 범위도 최신 Radix 1.x 라인과 호환되어 보입니다.
34-44: Radix/React 피어 의존성 호환성 확인 완료
npm view @radix-ui/react-switch@^1.2.6 peerDependencies결과, React 및 React DOM이^19.0범위를 공식 지원함을 확인했습니다.pnpm ls react react-dom @radix-ui/react-switch결과, 워크스페이스에 설치된 React 19.1.0/React DOM 19.1.0과 충돌이 없음을 확인했습니다.pnpm ls @types/react @types/react-dom결과, 타입 패키지 역시 정합성에 문제가 없습니다.따라서 피어 의존성 관련 별도 수정이나 추가 검증이 필요 없으니, 현 상태로 유지해 주세요.
packages/design-system/styles.css (1)
5-6: Tailwind v4 @source 추가 적절디자인 시스템 패키지 내부 소스 탐색을 위해
@source "./src";를 스타일 파일에 선언한 것은 v4 요구사항과 일치하며, 소비 앱에서 클래스 누락 문제를 예방합니다.packages/design-system/src/components/index.ts (1)
2-2: Switch 배럴 export 추가 적절컴포넌트 공개 표면에 스위치를 포함시킨 변경이 일관되며, 공개 API에 문제 없어 보입니다.
apps/landing/src/App.tsx (1)
1-4: 형식/세미콜론 추가는 무해하며 가독성 개선임포트/익스포트 세미콜론 및 사소한 포맷 정리는 일관성 측면에서 긍정적입니다.
Also applies to: 7-7, 32-35
packages/design-system/src/components/switch/switch.tsx (1)
15-16: 치수/이동량 검증 요청
- Root:
w-[4rem], Thumb:size-[1.6rem], 이동량:0.1rem↔2.1rem. 패딩/테두리/트랜지션 상태에서 썸이 정확히 중앙에 정지하는지 UX 확인 부탁드립니다. 간헐적으로 1px misalignment가 보일 수 있습니다.필요 시 다음처럼 계산식 기반으로 오프셋을 맞추는 방법도 고려 가능합니다.
- data-[state=checked]:translate-x-[2.1rem] - data-[state=unchecked]:translate-x-[0.1rem] + data-[state=checked]:translate-x-[calc(4rem-1.6rem-0.1rem)] + data-[state=unchecked]:translate-x-[0.1rem]Also applies to: 23-24
| function Switch({ | ||
| className, | ||
| ...props | ||
| }: React.ComponentProps<typeof SwitchPrimitive.Root>) { | ||
| return ( |
There was a problem hiding this comment.
🛠️ Refactor suggestion
ref 미전달 — 포커스 관리/폼 연동에 영향, forwardRef로 전환 권장
디자인 시스템 입력형 컴포넌트는 보통 ref 전달을 지원해야 포커스 트랩, 포커스 이동, 폼 라이브러리(react-hook-form 등)와 매끄럽게 동작합니다. 현재 일반 함수 컴포넌트로 정의되어 ref가 전달되지 않습니다. forwardRef로 전환해 주세요.
-import * as React from 'react';
+import * as React from 'react';
...
-function Switch({
- className,
- ...props
-}: React.ComponentProps<typeof SwitchPrimitive.Root>) {
- return (
- <div className="text-main600">
- <SwitchPrimitive.Root
+const Switch = React.forwardRef<
+ React.ElementRef<typeof SwitchPrimitive.Root>,
+ React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root>
+>(({ className, ...props }, ref) => {
+ return (
+ <SwitchPrimitive.Root
+ ref={ref}
data-slot="switch"
className={cn(
- 'data-[state=checked]:bg-main400 data-[state=unchecked]:bg-gray200 focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 shadow-xs peer inline-flex h-[1.15rem] h-[2rem] w-[4rem] shrink-0 items-center rounded-full border border-transparent outline-none transition-all focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
+ 'data-[state=checked]:bg-main400 data-[state=unchecked]:bg-gray200 focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 shadow-xs inline-flex h-[2rem] w-[4rem] shrink-0 items-center rounded-full border border-transparent outline-none transition-all focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
className
)}
{...props}
>
<SwitchPrimitive.Thumb
data-slot="switch-thumb"
className={cn(
- 'bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-[1.6rem] rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[2.1rem] data-[state=unchecked]:translate-x-[0.1rem]'
+ 'bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-[1.6rem] rounded-full ring-0 transition-transform motion-reduce:transition-none data-[state=checked]:translate-x-[2.1rem] data-[state=unchecked]:translate-x-[0.1rem]'
)}
/>
</SwitchPrimitive.Root>
- </div>
);
-}
+});
-export { Switch };
+Switch.displayName = 'Switch';
+
+export { Switch };- 중복 클래스
h-[1.15rem] h-[2rem]도 함께 정리했습니다(마지막 값이 유효하지만 혼란을 야기). peer클래스는 현재 사용되지 않아 제거했습니다.- 모션 민감 사용자 배려를 위해
motion-reduce:transition-none추가를 제안합니다.
Also applies to: 12-18, 20-26, 31-31
🤖 Prompt for AI Agents
packages/design-system/src/components/switch/switch.tsx around lines 6-31: the
component is a plain function so it doesn't forward refs, which breaks focus
management and form integrations; convert the component to use React.forwardRef
and type the ref as the underlying SwitchPrimitive.Root element, forward the ref
to the Root primitive and pass through props, remove duplicate height classes
(h-[1.15rem] h-[2rem]) and the unused peer class, and add
motion-reduce:transition-none to transition classes to respect reduced-motion
preferences; apply the same forwardRef and class cleanups at the other indicated
sections (lines 12-18, 20-26, 31).
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
packages/design-system/src/components/switch/switch.tsx (2)
22-22: 모션 민감 사용자 배려: Thumb에도 reduce 적용Thumb에도
motion-reduce:transition-none를 추가해 주세요.- 'bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-[1.6rem] rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[2.1rem] data-[state=unchecked]:translate-x-[0.1rem]' + 'bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-[1.6rem] rounded-full ring-0 transition-transform motion-reduce:transition-none data-[state=checked]:translate-x-[2.1rem] data-[state=unchecked]:translate-x-[0.1rem]'
5-28: forwardRef로 전환하고 불필요한 wrapper 제거 제안입력형 컴포넌트는 ref 전달이 필수적입니다(포커스 관리, 모달/포커스트랩, react-hook-form 등 연동). 현재 일반 함수 컴포넌트여서 ref가 루트로 전달되지 않습니다. 또한 바깥쪽
<div className="text-main600">는 실질적인 역할이 없고 레이아웃만 깊어집니다. 아래처럼 forwardRef로 전환하면서 wrapper를 제거해 주세요. displayName도 함께 지정합니다.-function Switch({ - className, - ...props -}: React.ComponentProps<typeof SwitchPrimitive.Root>) { - return ( - <div className="text-main600"> - <SwitchPrimitive.Root - data-slot="switch" - className={cn( - 'data-[state=checked]:bg-main400 data-[state=unchecked]:bg-gray200 focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 shadow-xs peer inline-flex h-[1.15rem] h-[2rem] w-[4rem] shrink-0 items-center rounded-full border border-transparent outline-none transition-all focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50', - className - )} - {...props} - > - <SwitchPrimitive.Thumb - data-slot="switch-thumb" - className={cn( - 'bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-[1.6rem] rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[2.1rem] data-[state=unchecked]:translate-x-[0.1rem]' - )} - /> - </SwitchPrimitive.Root> - </div> - ); -} +const Switch = React.forwardRef< + React.ElementRef<typeof SwitchPrimitive.Root>, + React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root> +>(({ className, ...props }, ref) => { + return ( + <SwitchPrimitive.Root + ref={ref} + data-slot="switch" + className={cn( + 'data-[state=checked]:bg-main400 data-[state=unchecked]:bg-gray200 focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 shadow-xs peer inline-flex h-[1.15rem] h-[2rem] w-[4rem] shrink-0 items-center rounded-full border border-transparent outline-none transition-all focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50', + className + )} + {...props} + > + <SwitchPrimitive.Thumb + data-slot="switch-thumb" + className={cn( + 'bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-[1.6rem] rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[2.1rem] data-[state=unchecked]:translate-x-[0.1rem]' + )} + /> + </SwitchPrimitive.Root> + ); +}); + +Switch.displayName = 'Switch';
🧹 Nitpick comments (4)
packages/design-system/src/components/switch/switch.tsx (4)
14-14: 중복·불필요 클래스 정리 및 모션 리듀스 추가
h-[1.15rem] h-[2rem]중복,peer는 현재 미사용입니다. 또한 환경설정에서 모션 감소 선호를 존중하도록 root에도motion-reduce:transition-none를 권장합니다.- 'data-[state=checked]:bg-main400 data-[state=unchecked]:bg-gray200 focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 shadow-xs peer inline-flex h-[1.15rem] h-[2rem] w-[4rem] shrink-0 items-center rounded-full border border-transparent outline-none transition-all focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50', + 'data-[state=checked]:bg-main400 data-[state=unchecked]:bg-gray200 focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 shadow-xs inline-flex h-[2rem] w-[4rem] shrink-0 items-center rounded-full border border-transparent outline-none transition-all motion-reduce:transition-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
21-23: 하드코딩된 translate 오프셋(2.1rem/0.1rem) 유지보수성현재 Thumb 오프셋이 고정 수치라 크기(폭/Thumb size) 변경 시 즉시 깨질 수 있습니다. CSS 변수로 Thumb 크기·패딩을 지정하고
calc()로 이동값을 계산하는 방식을 추천합니다. 구현은 선택 사항입니다.예시(개념):
<SwitchPrimitive.Root /* root에 정의해 두면 테마에서 한 번에 조정 가능 */ style={ { ['--switch-thumb-size' as any]: '1.6rem', ['--switch-gap' as any]: '0.1rem', } as React.CSSProperties } ... > <SwitchPrimitive.Thumb className={cn( '...', 'data-[state=checked]:translate-x-[calc(100%-var(--switch-thumb-size)-var(--switch-gap))]', 'data-[state=unchecked]:translate-x-[var(--switch-gap)]', )} /> </SwitchPrimitive.Root>
12-18: 접근성(A11y) 가이드: 레이블 연동과 폼 사용 주의
- Radix Switch는 본질적으로 role="switch"인 버튼입니다. 시각적 레이블과의 연결을 위해 id/Label 연동 또는
aria-label제공이 필요합니다.- 폼 입력으로 바로 제출되는
<input>이 아니므로 폼 라이브러리 사용 시checked/onCheckedChange를 Controller로 바인딩하세요.확인용 스니펫:
// 레이블 연동 <Label htmlFor="marketing">마케팅 수신 동의</Label> <Switch id="marketing" /> // 대체: 화면리더 전용 라벨 <Switch aria-label="마케팅 수신 동의" />원하시면 Storybook 스토리(기본/비활성/에러/라벨 좌우/제어형·비제어형)와 a11y 테스트(Lighthouse/axe) 템플릿을 추가해 드릴게요.
Also applies to: 20-24
30-30: 이름 논의: Switch 유지 + Toggle 별칭(export alias) 제안디자인 시스템 관점에선 Radix와 동일한 명칭(Switch)을 유지하는 편이 인지부하·문서 정합성 면에서 유리합니다. 다만 앱 팀에서 “Toggle”로 부르길 원한다면 barrel에서 alias를 함께 노출할 수 있습니다.
index barrel 예시:
// packages/design-system/src/components/index.ts export { Switch } from './switch/switch'; export { Switch as Toggle } from './switch/switch';
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/design-system/src/components/switch/switch.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/design-system/src/components/switch/switch.tsx (2)
packages/design-system/src/components/index.ts (1)
Switch(2-2)packages/design-system/src/lib/utils.ts (1)
cn(108-110)
| <SwitchPrimitive.Root | ||
| data-slot="switch" | ||
| className={cn( | ||
| 'data-[state=checked]:bg-main400 data-[state=unchecked]:bg-gray200 focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 shadow-xs peer inline-flex h-[1.15rem] h-[2rem] w-[4rem] shrink-0 items-center rounded-full border border-transparent outline-none transition-all focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50', |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
디자인 토큰/유틸 클래스 존재 여부 확인 요청(shadow-xs, main400 등)
shadow-xs, bg-main400, bg-gray200, bg-input/80, ring-ring/50가 Tailwind v4 설정/토큰에 실제로 정의되어 있는지 한 번 확인 부탁드립니다. 미정의 시 purge로 인해 의도치 않게 누락될 수 있습니다.
다음 스크립트로 설정 파일에서 토큰 정의를 찾아볼 수 있습니다(리포지토리 루트에서 실행).
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Tailwind 설정 파일 탐색 =="
fd -HI 'tailwind.config*' -t f
echo "== 색상/그림자 토큰 정의 검색 =="
# colors에 main400/gray200/input/ring 등이 정의되어 있는지
rg -nP 'colors\s*:\s*{[^}]*\b(main400|gray200|input|ring)\b' -C2 --hidden
echo "== 임의 클래스 사용 여부 점검(shadow-xs) =="
rg -n '\bshadow-xs\b' --hidden
echo "== v4 @source 적용 여부 재확인 =="
rg -n '@source' packages/design-system -C1 --hiddenLength of output: 272
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Tailwind 설정 파일 (apps/extension/tailwind.config.ts) 처음 200행 =="
sed -n '1,200p' apps/extension/tailwind.config.ts
echo "== 메인 색상 토큰(main400) 검색 =="
rg -n -C3 'main400' apps/extension/tailwind.config.ts || true
echo "== gray200 검색 =="
rg -n -C3 'gray200' apps/extension/tailwind.config.ts || true
echo "== input 색상 토큰(input) 검색 =="
rg -n -C3 'input' apps/extension/tailwind.config.ts || true
echo "== ring 색상 토큰(ring) 검색 =="
rg -n -C3 'ring' apps/extension/tailwind.config.ts || true
echo "== 그림자 유틸(shadow-xs) 검색 =="
rg -n -C3 'shadow-xs' apps/extension/tailwind.config.ts || trueLength of output: 991
Tailwind 설정에 커스텀 토큰·유틸이 정의되어 있지 않습니다
bg-main400, bg-gray200, bg-input/80, ring-ring/50, shadow-xs 등이 실제로 사용되려면 Tailwind 설정(tailwind.config.{js,ts})의 theme.extend에 명시적으로 추가되어야 합니다. 현재 리포지토리에서 발견된 apps/extension/tailwind.config.ts에는 extend: {}만 정의되어 있어, 해당 클래스들은 Purge 단계에서 제거될 위험이 있습니다.
조치 사항:
- 다음 파일 경로를 확인하고, 커스텀 색상·그림자 토큰을 추가해 주세요.
apps/extension/tailwind.config.ts
theme.extend에 아래와 같은 예시 형태로 필요한 토큰 정의를 추가해야 합니다.theme: { extend: { colors: { main400: '…', gray200: '#…', input: 'hsla(…, 0.8)', ring: '…', }, boxShadow: { xs: '0 0 0 1px rgba(0,0,0,0.05)', }, }, },
- 혹은 디자인 시스템 전체에서 공유하는 별도의 Tailwind 설정 파일이 있다면, 해당 파일에도 동일하게 정의했는지 재확인해 주세요.
🤖 Prompt for AI Agents
In packages/design-system/src/components/switch/switch.tsx around line 14 you
use Tailwind classes like bg-main400, bg-gray200, bg-input/80, ring-ring/50 and
shadow-xs that are not defined in the repository Tailwind config and will be
purged; open apps/extension/tailwind.config.ts and add these custom tokens under
theme.extend (e.g., extend.colors: main400, gray200, input, ring and
extend.boxShadow: xs or map shadow-xs) or ensure the shared/global Tailwind
config used by the design system contains identical entries, then rebuild to
confirm the classes are preserved.
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== 모든 Tailwind 설정 파일 탐색 ==="
fd -HI 'tailwind.*\.(js|ts|cjs|mjs)$' -t f
echo "=== packages/design-system의 Tailwind 설정 확인 ==="
fd -HI 'tailwind.*\.(js|ts|cjs|mjs)$' packages/design-system -t f
echo "=== 공유 Tailwind 설정 파일 확인 ==="
fd -HI 'tailwind.*\.(js|ts|cjs|mjs)$' packages -t f
echo "=== main400, gray200 등 커스텀 색상 토큰 정의 검색 ==="
rg -nP '\b(main400|gray200|input|ring)\b' --type js --type ts -A3 -B3
echo "=== shadow-xs 그림자 토큰 정의 검색 ==="
rg -nP 'shadow.*xs|boxShadow.*xs' --type js --type ts -A3 -B3
echo "=== @source 지시문 확인 ==="
rg -n '@source' packages/design-system -C2
Length of output: 4714
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== apps/extension/tailwind.config.ts 내용 확인 ==="
cat apps/extension/tailwind.config.ts
echo "=== @pinback/tailwind-config 패키지 확인 ==="
ls -la packages/ | grep tailwind || echo "tailwind-config 패키지 없음"
fd -HI 'tailwind-config' packages -t d
echo "=== packages/design-system/src/lib/utils.ts에서 색상 토큰 정의 부분 전체 확인 ==="
cat packages/design-system/src/lib/utils.ts
echo "=== shared-styles.css 확인 ==="
fd -HI 'shared-styles.css' -t f
echo "=== node_modules나 외부 패키지에서 tailwind-config 확인 ==="
ls -la node_modules/@pinback/ 2>/dev/null || echo "@pinback 스코프 없음"
Length of output: 3302
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== packages/tailwind-config/shared-styles.css 내용 확인 ==="
cat packages/tailwind-config/shared-styles.css
echo "=== packages/tailwind-config 디렉토리 전체 구조 확인 ==="
ls -la packages/tailwind-config/
echo "=== tailwind-config 패키지에 Tailwind 설정 파일이 있는지 확인 ==="
fd -HI 'tailwind.*\.(js|ts|cjs|mjs)$' packages/tailwind-config -t f
echo "=== CSS 변수나 커스텀 프로퍼티 정의 확인 ==="
rg -nP '--.*main400|--.*gray200|--.*input|--.*ring' packages/tailwind-config/ || echo "CSS 변수 정의 없음"
echo "=== @layer 나 @apply 지시문 확인 ==="
rg -nP '@layer|@apply' packages/tailwind-config/ || echo "@layer/@apply 없음"
Length of output: 6457
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== input, ring 색상 변수 정의 확인 ==="
rg -n 'color-input|color-ring' packages/tailwind-config/
echo "=== background, foreground 등 기본 색상 확인 ==="
rg -n 'color-background|color-foreground|primary-foreground' packages/tailwind-config/
echo "=== shadow-xs 정의 확인 ==="
rg -n 'shadow.*xs' packages/tailwind-config/
echo "=== 모든 그림자 관련 정의 확인 ==="
rg -n 'shadow|Shadow' packages/tailwind-config/
echo "=== Tailwind v4에서 사용하는 기본 색상 토큰들 확인 ==="
echo "Tailwind v4 기본 색상들이 정의되어 있는지 확인..."
rg -n 'color-(background|foreground|primary|input|ring)' packages/tailwind-config/ || echo "기본 Tailwind v4 색상 토큰 정의 없음"
Length of output: 151
@constantly-dev 부분적으로만 잘 적용됩니다!
분석 결과:
✅ 잘 작동하는 클래스들:
bg-main400,bg-gray200→packages/tailwind-config/shared-styles.css에@theme으로 정의되어 있음@source "./src";지시문도 올바르게 설정됨
❌ 작동하지 않는 클래스들:
bg-input/80→--color-input정의 없음ring-ring/50→--color-ring정의 없음shadow-xs→ shadow-xs 유틸리티 정의 없음bg-background,bg-foreground,bg-primary-foreground→ Tailwind v4 기본 시맨틱 토큰들이 정의되지 않음
해결 방법:
packages/tailwind-config/shared-styles.css의 @theme 블록에 다음 토큰들을 추가해야 합니다:
@theme {
/* 기존 색상들... */
/* 추가 필요한 시맨틱 토큰들 */
--color-background: #ffffff;
--color-foreground: #111111;
--color-input: #f1f1f5;
--color-ring: #54d19d;
--color-primary-foreground: #ffffff;
}
/* 그림자 유틸리티 추가 */
@utility shadow-xs {
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05);
}현재 상태에서는 토글 컴포넌트가 렌더링되지만 일부 스타일링(포커스 링, 다크모드 배경, 그림자)이 누락될 것입니다.
∧ ∧
( ._. )
o_("_")_o
분석하는 토끼
🧠 Learnings used
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#5
File: apps/extension/src/index.css:1-1
Timestamp: 2025-08-19T17:18:57.657Z
Learning: constantly-dev는 디자인 시스템 설정 PR 머지 후 `import 'pinback/tailwind-config/shared-styles.css';`를 `app.css`나 `index.css`에서 사용하여 공유 스타일을 관리할 계획입니다.
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#89
File: apps/client/src/pages/onBoarding/components/OnboardingNavButton.tsx:26-34
Timestamp: 2025-07-16T13:11:52.976Z
Learning: In the Pinback-Team/pinback-client project, `bg-gray200` is a custom design token used consistently throughout the design system, not a typo. The project uses custom color tokens like `gray0`, `gray100`, `gray200`, `gray300`, etc. without hyphens, which is different from standard Tailwind CSS naming conventions. This should not be changed to `bg-gray-200` as it would break the design system.
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#2
File: pnpm-workspace.yaml:3-3
Timestamp: 2025-08-18T13:48:59.021Z
Learning: constantly-dev는 docs 디렉터리를 컨벤션 문서 추가용으로 사용할 예정이라고 명시했습니다.
우아! 처음에 design-system에서 css 파일을 만들고 import도 안 했는데 자동 완성이 잘 되길래 참 이 부분이 의이 디자인시스템에서 컴포넌트 만들고 apps에서 불러왔지만 렌더링이 안되는 문제가 있었습니다. 따로 찾아보니 Tailwind v4에서는 content 대신 CSS 안에서 @source로 외부 경로를 지정해서 tailwind v4가 DS 소스(다른 패키지)를 스캔하도록 해주어야한다고합니다. 아래 챀고 아티클 첨부할게요 관련문제 깃허브 공식문서
우아! 처음에 design-system에서 css 파일을 만들고 import도 안 했는데 자동 완성이 잘 되길래 참 이 부분이 의아했는데, 역시 안되는 부분이 맞았네요!!!! 이 진짜 너무 속 시원합니다!!~~~ 수고하셨어요 👍 👍 |
| <SwitchPrimitive.Root | ||
| data-slot="switch" | ||
| className={cn( | ||
| 'data-[state=checked]:bg-main400 data-[state=unchecked]:bg-gray200 focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 shadow-xs peer inline-flex h-[1.15rem] h-[2rem] w-[4rem] shrink-0 items-center rounded-full border border-transparent outline-none transition-all focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50', |
|
|
||
| @import '@pinback/tailwind-config/shared-styles.css'; | ||
|
|
||
| @source "./src"; |
into feat/#16/toggle-component
|
✅ Storybook chromatic 배포 확인: |
📌 Related Issues
✅ 체크 리스트
📄 Tasks
⭐ PR Point (To Reviewer)
shadecn 사용하여 만들었습니다.
컴포넌트 이름이 shadecn에서 switch로 되어있어 현재 컴포넌트 이름도 switch인데 toggle로 변경이 필요할까요?? 헷갈릴거같아 고민이됩니다
문제점
디자인시스템에서 컴포넌트 만들고 apps에서 불러왔지만 렌더링이 안되는 문제가 있었습니다.
따로 찾아보니 Tailwind v4에서는 content 대신 CSS 안에서 @source로 외부 경로를 지정해서 tailwind v4가 DS 소스(다른 패키지)를 스캔하도록 해주어야한다고합니다.
아래 챀고 아티클 첨부할게요
관련문제 깃허브
공식문서
디자인시스템의 스타일 파일에
@source "./src";명령어가 필요하다하여 추가하니 문제해결됐습니다~..📷 Screenshot
Summary by CodeRabbit
신규 기능
보안
작업(Chores)
스타일