Skip to content

feat: 레이아웃, 스타일링 유틸리티 컴포넌트 추가 #66#69

Merged
Seojunhwan merged 18 commits intomainfrom
feature/PRODUCT-131
Jul 6, 2025
Merged

feat: 레이아웃, 스타일링 유틸리티 컴포넌트 추가 #66#69
Seojunhwan merged 18 commits intomainfrom
feature/PRODUCT-131

Conversation

@Seojunhwan
Copy link
Member

@Seojunhwan Seojunhwan commented Jul 4, 2025

✅ 이슈 번호

close #66


🪄 작업 내용 (변경 사항)

  • stack 컴포넌트 추가
  • text 컴포넌트 추가
  • bleed 컴포넌트 추가
  • spacer 컴포넌트 추가

📸 스크린샷


💡 설명


🗣️ 리뷰어에게 전달 사항

스토리북을 꼭 보시면 좋을 것 같아요!


📍 트러블 슈팅

vanilla extract에서 스타일링을 만드는 함수 ex)recipe 등등,, 에 변경되는 값들이 많아지면 classname이 여러개 생성되어 cssVariable 형태로 처리했습니다!
근데 vanilla extract을 처음 써봐서 조금 헷갈렸네요 , ,

Summary by CodeRabbit

  • New Features

    • 새로운 UI 컴포넌트(Spacer, Stack, Bleed, Text)를 추가하여 레이아웃 및 텍스트 스타일링을 유연하게 지원합니다.
    • 각 컴포넌트는 다양한 방향, 간격, 색상, 폰트 스타일 등의 속성을 제공합니다.
    • Storybook 스토리를 통해 각 컴포넌트의 사용 예시와 문서를 확인할 수 있습니다.
  • Documentation

    • 모든 신규 컴포넌트에 대해 Storybook 문서 및 예제 스토리가 추가되었습니다.
  • Chores

    • 스타일 및 레이아웃 처리를 위한 외부 라이브러리 의존성이 추가되었습니다.
    • 유틸리티 함수 및 타입 정의가 도입되어 컴포넌트의 확장성과 타입 안전성이 향상되었습니다.

@coderabbitai
Copy link

coderabbitai bot commented Jul 4, 2025

Walkthrough

이 변경사항은 스타일링 유틸리티 컴포넌트인 Stack(HStack, VStack 포함)과 Spacer를 새롭게 추가하고, 이들에 필요한 CSS 및 타입 유틸리티, Storybook 스토리, 그리고 공통적으로 사용할 수 있는 폴리모픽 타입과 rem 변환 유틸리티를 도입합니다. Bleed, Text 컴포넌트도 함께 도입되었습니다.

Changes

파일/경로 요약 변경 요약
package.json @vanilla-extract/dynamic 패키지 의존성 추가
src/components/ui/Bleed/* Bleed 컴포넌트, 타입, CSS, Storybook 스토리, index 재export 추가
src/components/ui/Spacer/* Spacer 컴포넌트, 타입, Storybook 스토리, index 재export 추가
src/components/ui/Stack/* Stack, HStack, VStack 컴포넌트, 타입, CSS 레시피, Storybook 스토리, index 재export 추가
src/components/ui/Text/* Text 컴포넌트, 타입, CSS, Storybook 스토리, index 재export 추가
src/lib/utils/coerceCssRemValue.ts rem 단위 변환 유틸리티 함수 및 타입 추가
src/types/polymorphic.types.ts 폴리모픽 컴포넌트 지원 타입 유틸리티 추가

Sequence Diagram(s)

sequenceDiagram
  participant Consumer
  participant Stack
  participant Spacer
  participant Bleed

  Consumer->>Stack: Stack/HStack/VStack 컴포넌트 사용 (props 전달)
  Stack->>Stack: 방향, 정렬, gap 등 props 처리
  Stack->>Stack: CSS 변수 및 스타일 적용
  Stack-->>Consumer: 레이아웃된 children 반환

  Consumer->>Spacer: Spacer 컴포넌트 사용 (size, direction 등)
  Spacer->>Spacer: rem 변환 및 스타일 적용
  Spacer-->>Consumer: 공간 요소 반환

  Consumer->>Bleed: Bleed 컴포넌트 사용 (bleed props)
  Bleed->>Bleed: CSS 변수 및 스타일 적용
  Bleed-->>Consumer: bleed 적용된 요소 반환
Loading

Assessment against linked issues

Objective Addressed Explanation
Flex or VStack, HStack (#66)
Spacer (#66)

Suggested labels

✨ feature

Poem

🐇
스택과 스페이서, 줄 맞춰 춤추네
공간을 벌리고, 유연하게 늘어나
스타일링 유틸, 토끼도 신이 나
rem으로 맞추고, 폴리모픽 자유
새 컴포넌트와 함께, UI가 반짝!
🎉

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/components/ui/Bleed/Bleed.css.ts

Oops! Something went wrong! :(

ESLint: 9.27.0

ESLint couldn't find the plugin "eslint-plugin-react-hooks".

(The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-react-hooks@latest --save-dev

The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/eslint-config-next@15.3.2_eslint@9.27.0_jiti@2.4.2__typescript@5.8.3/node_modules/eslint-config-next/index.js".

If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting.

src/components/ui/Spacer/Spacer.tsx

Oops! Something went wrong! :(

ESLint: 9.27.0

ESLint couldn't find the plugin "eslint-plugin-react-hooks".

(The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-react-hooks@latest --save-dev

The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/eslint-config-next@15.3.2_eslint@9.27.0_jiti@2.4.2__typescript@5.8.3/node_modules/eslint-config-next/index.js".

If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting.

src/components/ui/Text/Text.tsx

Oops! Something went wrong! :(

ESLint: 9.27.0

ESLint couldn't find the plugin "eslint-plugin-react-hooks".

(The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-react-hooks@latest --save-dev

The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/eslint-config-next@15.3.2_eslint@9.27.0_jiti@2.4.2__typescript@5.8.3/node_modules/eslint-config-next/index.js".

If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting.

  • 5 others
✨ Finishing Touches
  • 📝 Generate Docstrings

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link

github-actions bot commented Jul 4, 2025

🎨 Storybook Preview: https://685a32a1c0bbd269fdb67af4-ivrwnchutg.chromatic.com/
🔗 Chromatic Build: https://www.chromatic.com/build?appId=685a32a1c0bbd269fdb67af4&number=76
🕖 Updated at: 2025년 07월 07일 00시 54분 53초

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (7)
src/lib/utils/coerceCssRemValue.ts (1)

12-14: 함수 구현 승인 및 경미한 개선 제안

함수 로직이 명확하고 올바르게 구현되었습니다. 하지만 NaN 또는 Infinity 같은 특수 값에 대한 처리를 고려해볼 수 있습니다.

더 안전한 구현을 위해 다음과 같이 개선할 수 있습니다:

export function coerceCssRemValue(value: CSSPixelValue): string {
-  return typeof value === "string" ? value : `${value / 10}rem`;
+  if (typeof value === "string") return value;
+  if (!Number.isFinite(value)) return "0rem";
+  return `${value / 10}rem`;
}
src/components/ui/Stack/Stack.css.ts (1)

6-63: 기본 variant 지정 누락

recipedefaultVariants를 지정하지 않으면 소비 측에서 모든 variant를 명시해야 하고, Storybook에서도 기본 케이스가 불명확해집니다.
예시:

 export const stackStyles = recipe({
   base: {
     display: "flex",
     gap: stackGapVar,
   },
+  defaultVariants: {
+    direction: "row",
+    justify: "start",
+    align: "stretch",
+    wrap: "nowrap",
+  },
   variants: {
     ...
   },
 })
src/components/ui/Bleed/Bleed.tsx (2)

42-70: 스타일 객체 구성 로직을 개선하세요.

현재 코드는 각 prop에 대해 개별적인 조건부 스프레드를 사용하고 있어 가독성이 떨어집니다. 더 간결하고 유지보수하기 쉬운 방식으로 리팩토링할 수 있습니다.

다음과 같이 개선할 수 있습니다:

  const style = {
    ...styleFromProps,
    ...assignInlineVars({
-     ...(inline
-       ? {
-           [bleedInlineStartVar]: coerceCssRemValue(inline),
-           [bleedInlineEndVar]: coerceCssRemValue(inline),
-         }
-       : {}),
-     ...(block
-       ? {
-           [bleedBlockStartVar]: coerceCssRemValue(block),
-           [bleedBlockEndVar]: coerceCssRemValue(block),
-         }
-       : {}),
-     ...(inlineStart
-       ? {
-           [bleedInlineStartVar]: coerceCssRemValue(inlineStart),
-         }
-       : {}),
-     ...(inlineEnd
-       ? { [bleedInlineEndVar]: coerceCssRemValue(inlineEnd) }
-       : {}),
-     ...(blockStart
-       ? { [bleedBlockStartVar]: coerceCssRemValue(blockStart) }
-       : {}),
-     ...(blockEnd ? { [bleedBlockEndVar]: coerceCssRemValue(blockEnd) } : {}),
+     ...(inline && {
+       [bleedInlineStartVar]: coerceCssRemValue(inline),
+       [bleedInlineEndVar]: coerceCssRemValue(inline),
+     }),
+     ...(block && {
+       [bleedBlockStartVar]: coerceCssRemValue(block),
+       [bleedBlockEndVar]: coerceCssRemValue(block),
+     }),
+     ...(inlineStart && {
+       [bleedInlineStartVar]: coerceCssRemValue(inlineStart),
+     }),
+     ...(inlineEnd && {
+       [bleedInlineEndVar]: coerceCssRemValue(inlineEnd),
+     }),
+     ...(blockStart && {
+       [bleedBlockStartVar]: coerceCssRemValue(blockStart),
+     }),
+     ...(blockEnd && {
+       [bleedBlockEndVar]: coerceCssRemValue(blockEnd),
+     }),
    }),
  };

74-74: className 합치기 로직을 개선하세요.

현재 문자열 템플릿을 사용한 className 합치기는 불필요한 공백을 만들 수 있습니다. 더 안전한 방식으로 개선할 수 있습니다.

다음과 같이 개선할 수 있습니다:

-     className={`${bleedStyles} ${className ?? ""}`.trim()}
+     className={[bleedStyles, className].filter(Boolean).join(" ")}
src/components/ui/Text/Text.tsx (1)

97-102: 조건부 로직을 간소화하세요.

assignInlineVars 내부의 조건부 로직을 더 간결하게 만들 수 있습니다.

다음과 같이 개선할 수 있습니다:

    ...assignInlineVars({
      [fontSizeVar]: typography[typo]?.fontSize,
      [lineHeightVar]: typography[typo]?.lineHeight,
      [letterSpacingVar]: typography[typo]?.letterSpacing,
-     [colorVar]: color ? resolveColor(color) : undefined,
+     [colorVar]: resolveColor(color),
    }),

resolveColor 함수에서 이미 undefined 처리를 하고 있으므로 중복 체크가 불필요합니다.

src/components/ui/Spacer/Spacer.tsx (1)

28-28: 기본 element type을 "div"로 변경하는 것을 고려해보세요.

현재 기본 element type이 "span"으로 설정되어 있는데, span은 인라인 요소입니다. Spacer 컴포넌트는 레이아웃에서 여백을 만드는 용도로 사용되므로, 블록 레벨 요소인 "div"가 더 적절할 수 있습니다.

-export const Spacer = <T extends ElementType = "span">({
+export const Spacer = <T extends ElementType = "div">({
src/components/ui/Stack/Stack.tsx (1)

53-58: 클래스명 연결 로직을 개선해보세요.

현재 코드에서는 classNameundefined이거나 빈 문자열일 때 여분의 공백이 생길 수 있습니다. trim()은 앞뒤 공백만 제거하므로 클래스명 사이의 여분 공백은 제거되지 않습니다.

-      className={`${stackStyles({
-        direction,
-        justify,
-        align,
-        wrap,
-      })} ${className ?? ""}`.trim()}
+      className={[
+        stackStyles({
+          direction,
+          justify,
+          align,
+          wrap,
+        }),
+        className,
+      ]
+        .filter(Boolean)
+        .join(" ")}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 79a76cc and 7c80156.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (18)
  • package.json (1 hunks)
  • src/components/ui/Bleed/Bleed.css.ts (1 hunks)
  • src/components/ui/Bleed/Bleed.stories.tsx (1 hunks)
  • src/components/ui/Bleed/Bleed.tsx (1 hunks)
  • src/components/ui/Bleed/index.ts (1 hunks)
  • src/components/ui/Spacer/Spacer.stories.tsx (1 hunks)
  • src/components/ui/Spacer/Spacer.tsx (1 hunks)
  • src/components/ui/Spacer/index.ts (1 hunks)
  • src/components/ui/Stack/Stack.css.ts (1 hunks)
  • src/components/ui/Stack/Stack.stories.tsx (1 hunks)
  • src/components/ui/Stack/Stack.tsx (1 hunks)
  • src/components/ui/Stack/index.ts (1 hunks)
  • src/components/ui/Text/Text.css.ts (1 hunks)
  • src/components/ui/Text/Text.stories.tsx (1 hunks)
  • src/components/ui/Text/Text.tsx (1 hunks)
  • src/components/ui/Text/index.ts (1 hunks)
  • src/lib/utils/coerceCssRemValue.ts (1 hunks)
  • src/types/polymorphic.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
`{src/app/**/_components/*.{ts,tsx},src/components/**/*.{ts,tsx}}`: 컴포넌트 파일은 PascalCase로 네이밍해야 한다 (예: `Button.tsx`, `DomainLayout.tsx`).

{src/app/**/_components/*.{ts,tsx},src/components/**/*.{ts,tsx}}: 컴포넌트 파일은 PascalCase로 네이밍해야 한다 (예: Button.tsx, DomainLayout.tsx).

📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)

List of files the instruction was applied to:

  • src/components/ui/Text/index.ts
  • src/components/ui/Stack/index.ts
  • src/components/ui/Spacer/index.ts
  • src/components/ui/Bleed/index.ts
  • src/components/ui/Text/Text.css.ts
  • src/components/ui/Bleed/Bleed.css.ts
  • src/components/ui/Text/Text.tsx
  • src/components/ui/Bleed/Bleed.tsx
  • src/components/ui/Stack/Stack.css.ts
  • src/components/ui/Spacer/Spacer.stories.tsx
  • src/components/ui/Spacer/Spacer.tsx
  • src/components/ui/Text/Text.stories.tsx
  • src/components/ui/Bleed/Bleed.stories.tsx
  • src/components/ui/Stack/Stack.stories.tsx
  • src/components/ui/Stack/Stack.tsx
`**/*.css.ts`: vanilla-extract 스타일 파일은 camelCase로, `.css.ts` 확장자를 사용해야 하며, 해당 컴포넌트와 같은 폴더에 배치해야 한다.

**/*.css.ts: vanilla-extract 스타일 파일은 camelCase로, .css.ts 확장자를 사용해야 하며, 해당 컴포넌트와 같은 폴더에 배치해야 한다.

📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)

List of files the instruction was applied to:

  • src/components/ui/Text/Text.css.ts
  • src/components/ui/Bleed/Bleed.css.ts
  • src/components/ui/Stack/Stack.css.ts
`{src/lib/utils/*.{ts,tsx},src/lib/api/*.{ts,tsx},src/app/**/_utils/*.{ts,tsx},s...

{src/lib/utils/*.{ts,tsx},src/lib/api/*.{ts,tsx},src/app/**/_utils/*.{ts,tsx},src/app/**/_api/*.{ts,tsx}}: 유틸리티 및 API 파일은 camelCase로 네이밍해야 한다 (예: domainUtils.ts, domain.api.ts).

📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)

List of files the instruction was applied to:

  • src/lib/utils/coerceCssRemValue.ts
`src/lib/utils/*.{ts,tsx}`: 전역 공통 유틸리티는 `lib/utils/` 폴더에 기능별로 분리해 위치해야 한다.

src/lib/utils/*.{ts,tsx}: 전역 공통 유틸리티는 lib/utils/ 폴더에 기능별로 분리해 위치해야 한다.

📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)

List of files the instruction was applied to:

  • src/lib/utils/coerceCssRemValue.ts
`{src/types/*.{ts,tsx},src/app/**/_types/*.{ts,tsx},src/app/**/_schemas/*.{ts,ts...

{src/types/*.{ts,tsx},src/app/**/_types/*.{ts,tsx},src/app/**/_schemas/*.{ts,tsx},src/lib/validations/*.{ts,tsx}}: 타입 및 스키마 파일은 camelCase로 네이밍해야 한다 (예: domain.types.ts, form.schema.ts).

📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)

List of files the instruction was applied to:

  • src/types/polymorphic.ts
`src/types/*.{ts,tsx}`: 전역 타입 정의는 `types/` 폴더에 위치해야 한다.

src/types/*.{ts,tsx}: 전역 타입 정의는 types/ 폴더에 위치해야 한다.

📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)

List of files the instruction was applied to:

  • src/types/polymorphic.ts
🧠 Learnings (8)
src/components/ui/Stack/index.ts (4)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/types/*.{ts,tsx} : 전역 타입 정의는 `types/` 폴더에 위치해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/app/**/_api/*.{api,queries}.ts : API 호출 관련 코드는 `_api` 폴더에 `.api.ts` (ky 사용) 및 `.queries.ts` (TanStack Query) 파일로 분리해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/lib/utils/*.{ts,tsx} : 전역 공통 유틸리티는 `lib/utils/` 폴더에 기능별로 분리해 위치해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/constants/*.{ts,tsx} : 전역 상수 정의는 `constants/` 폴더에 위치해야 한다.
src/components/ui/Spacer/index.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/lib/utils/*.{ts,tsx} : 전역 공통 유틸리티는 `lib/utils/` 폴더에 기능별로 분리해 위치해야 한다.
src/components/ui/Text/Text.css.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to **/*.css.ts : vanilla-extract 스타일 파일은 camelCase로, `.css.ts` 확장자를 사용해야 하며, 해당 컴포넌트와 같은 폴더에 배치해야 한다.
src/components/ui/Bleed/Bleed.css.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to **/*.css.ts : vanilla-extract 스타일 파일은 camelCase로, `.css.ts` 확장자를 사용해야 하며, 해당 컴포넌트와 같은 폴더에 배치해야 한다.
src/components/ui/Text/Text.tsx (2)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to **/*.css.ts : vanilla-extract 스타일 파일은 camelCase로, `.css.ts` 확장자를 사용해야 하며, 해당 컴포넌트와 같은 폴더에 배치해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to {src/app/**/_components/*.{ts,tsx},src/components/**/*.{ts,tsx}} : 컴포넌트 파일은 PascalCase로 네이밍해야 한다 (예: `Button.tsx`, `DomainLayout.tsx`).
src/components/ui/Stack/Stack.css.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to **/*.css.ts : vanilla-extract 스타일 파일은 camelCase로, `.css.ts` 확장자를 사용해야 하며, 해당 컴포넌트와 같은 폴더에 배치해야 한다.
src/types/polymorphic.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/types/*.{ts,tsx} : 전역 타입 정의는 `types/` 폴더에 위치해야 한다.
src/components/ui/Stack/Stack.tsx (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to **/*.css.ts : vanilla-extract 스타일 파일은 camelCase로, `.css.ts` 확장자를 사용해야 하며, 해당 컴포넌트와 같은 폴더에 배치해야 한다.
🧬 Code Graph Analysis (2)
src/components/ui/Text/Text.tsx (2)
src/types/polymorphic.ts (1)
  • PolymorphicComponentPropsWithRef (35-38)
src/components/ui/Text/Text.css.ts (5)
  • fontSizeVar (3-3)
  • lineHeightVar (4-4)
  • letterSpacingVar (5-5)
  • colorVar (6-6)
  • textStyles (8-13)
src/components/ui/Spacer/Spacer.tsx (3)
src/components/ui/Spacer/index.ts (1)
  • Spacer (1-1)
src/types/polymorphic.ts (1)
  • PolymorphicComponentPropsWithRef (35-38)
src/lib/utils/coerceCssRemValue.ts (1)
  • coerceCssRemValue (12-14)
🪛 Biome (1.9.4)
src/types/polymorphic.ts

[error] 27-27: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 37-37: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: test
  • GitHub Check: storybook-preview
🔇 Additional comments (20)
package.json (1)

23-23: 패키지 버전 및 보안 감사 후속 조치 필요

  • @vanilla-extract/dynamic@2.1.5가 npm registry 기준 최신 버전임을 확인했습니다.
  • npm audit는 lockfile 부재(ENOLOCK)로 실행되지 않았습니다.

보안 취약점 검사를 위해 아래 절차를 진행해주세요:

  1. lockfile 생성
    npm i --package-lock-only
  2. 보안 감사 재실행
    npm audit | grep -A 10 -B 10 "@vanilla-extract/dynamic"
src/lib/utils/coerceCssRemValue.ts (1)

1-1: 타입 정의 승인

CSSPixelValue 타입이 명확하고 적절하게 정의되었습니다.

src/types/polymorphic.ts (2)

1-1: ESLint 비활성화 승인

Polymorphic 타입 정의에서 any 타입 사용이 불가피한 경우이므로 ESLint 비활성화가 적절합니다.


10-38: Polymorphic 타입 시스템 설계 승인

전체적인 polymorphic 타입 시스템이 잘 설계되었고, React 컴포넌트의 다형성을 효과적으로 지원합니다.

src/components/ui/Text/index.ts (1)

1-1: 표준 re-export 패턴 승인

컴포넌트와 타입을 함께 export하는 표준 패턴을 올바르게 따르고 있습니다.

src/components/ui/Stack/index.ts (1)

1-1: Stack 컴포넌트 패밀리 export 승인

Stack 관련 컴포넌트들(HStack, VStack, Stack)과 타입을 함께 export하는 구조가 잘 설계되었습니다.

src/components/ui/Spacer/index.ts (1)

1-1: 깔끔한 재-익스포트 👍

Spacer 컴포넌트와 타입을 한 줄로 내보내는 패턴이 다른 UI 컴포넌트들과 일관되어 있습니다.

src/components/ui/Bleed/index.ts (1)

1-1: 익스포트 패턴 일관성 확인 완료

Bleed 컴포넌트 역시 동일한 방식으로 내보내고 있어 사용성이 좋습니다.

src/components/ui/Spacer/Spacer.stories.tsx (1)

1-92: 잘 구성된 Storybook 스토리입니다.

Spacer 컴포넌트의 스토리가 체계적으로 구성되어 있고, 수직/수평 간격 예제가 명확하게 제시되어 있습니다. 한국어 문서화도 잘 되어 있어 개발자가 쉽게 이해할 수 있습니다.

src/components/ui/Text/Text.tsx (1)

17-27: 복잡한 타입 유틸리티가 잘 구현되었습니다.

DotNestedKeys 타입 유틸리티는 중첩된 객체의 키를 점 표기법으로 추출하는 복잡한 로직을 잘 구현했습니다. 타입 안전성을 보장하면서도 사용자 친화적인 API를 제공합니다.

src/components/ui/Bleed/Bleed.stories.tsx (1)

1-207: 효과적인 시각적 데모를 제공하는 스토리입니다.

Bleed 컴포넌트의 효과를 이해하기 쉽게 시각화했습니다. 배경색을 사용하여 부모 요소의 패딩과 블리드 효과를 명확하게 구분할 수 있도록 구성했습니다. 세 가지 시나리오(inline, block, all directions)를 통해 다양한 사용 사례를 잘 보여주고 있습니다.

src/components/ui/Text/Text.stories.tsx (1)

1-126: 포괄적인 컴포넌트 사용 사례를 보여주는 스토리입니다.

Text 컴포넌트의 다양한 기능을 체계적으로 보여주고 있습니다. 특히 AllTypographies 스토리는 디자인 시스템의 모든 타이포그래피를 한 눈에 볼 수 있어 유용하고, AsHeading 스토리는 시맨틱 HTML 사용의 중요성을 잘 보여줍니다. 색상 토큰과 커스텀 색상 사용 예제도 실용적입니다.

src/components/ui/Spacer/Spacer.tsx (2)

15-27: 우수한 JSDoc 문서화!

컴포넌트의 용도와 사용법이 명확하게 문서화되어 있고, 실제 사용 예시도 포함되어 있어 매우 좋습니다.


41-41: 접근성 고려가 잘 되어 있습니다.

aria-hidden="true" 속성을 통해 이 컴포넌트가 순수하게 시각적인 여백을 위한 것임을 명시한 것이 좋습니다.

src/components/ui/Stack/Stack.tsx (3)

18-28: 훌륭한 JSDoc 문서화!

컴포넌트의 목적과 사용법이 명확하게 설명되어 있고, 실제 사용 예시도 포함되어 있어 매우 좋습니다.


43-48: vanilla-extract dynamic 사용이 적절합니다.

CSS 변수를 활용한 동적 스타일링 구현이 올바르게 되어 있습니다. coerceCssRemValue 유틸리티 함수를 통한 값 변환도 적절합니다.


77-81: HStack과 VStack 구현이 간결하고 명확합니다.

각각 direction"row""column"으로 고정한 래퍼 컴포넌트로 구현되어 있어 사용성이 좋습니다.

Also applies to: 95-99

src/components/ui/Stack/Stack.stories.tsx (3)

6-53: 포괄적이고 잘 구성된 Storybook 메타데이터!

각 prop에 대한 상세한 설명과 적절한 컨트롤 타입이 설정되어 있어 개발자가 컴포넌트를 쉽게 이해하고 테스트할 수 있습니다.


58-80: 시각화를 위한 Box 헬퍼 컴포넌트가 유용합니다.

Stack 컴포넌트의 레이아웃 동작을 시각적으로 확인할 수 있도록 도와주는 적절한 헬퍼 컴포넌트입니다.


96-122: 각 스토리가 특정 기능을 효과적으로 보여줍니다.

Justify, Align, Wrap 스토리들이 각각 해당 props의 다양한 옵션들을 명확하게 시연하고 있어 매우 유용합니다.

Also applies to: 124-151, 153-174

Copy link
Contributor

@wkdtnqls0506 wkdtnqls0506 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

준환님 JSDoc으로 정리까지 완벽하게 해주셔서 감사합니다! 저도 앞으로 애용해야겠어요!
스토리북으로도 구조가 잘 정리되어 있어서 이해가 수월했습니다 🤩

저는 import * as styles from "~" 형태로 불러와서 styles.wrapper처럼 사용하는데, 준환님은 import { wrapper } from "~" 방식으로 사용하시는 것 같더라구요!
이 방식도 정해서 컨벤션 맞춰가면 좋을 거 같아요 ㅎㅅㅎ
수고하셨습니다 🙇🏻‍♀️✨

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
src/types/polymorphic.types.ts (2)

25-30: Props = {} 사용은 지양하고 명시적 타입으로 대체 권장

Biome 경고처럼 {}는 “null 이외의 아무 값”을 의미해 타입 안정성을 떨어뜨립니다.
가능하다면 Record<string, unknown> 혹은 보다 구체적인 제네릭 파라미터로 대체하세요.

-  Props = {},
+  Props extends Record<string, unknown> = Record<string, unknown>,

31-38: PolymorphicRef · PolymorphicComponentPropsWithRef 의 기본 제네릭도 동일 기준 적용 필요

위와 같은 이유로 기본값 {} 대신 명시적 객체 타입으로 통일해 주세요.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7c80156 and 3796eda.

📒 Files selected for processing (8)
  • src/components/ui/Bleed/Bleed.css.ts (1 hunks)
  • src/components/ui/Bleed/Bleed.tsx (1 hunks)
  • src/components/ui/Spacer/Spacer.tsx (1 hunks)
  • src/components/ui/Stack/Stack.css.ts (1 hunks)
  • src/components/ui/Stack/Stack.tsx (1 hunks)
  • src/components/ui/Text/Text.css.ts (1 hunks)
  • src/components/ui/Text/Text.tsx (1 hunks)
  • src/types/polymorphic.types.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/components/ui/Bleed/Bleed.css.ts
  • src/components/ui/Stack/Stack.css.ts
  • src/components/ui/Text/Text.tsx
  • src/components/ui/Text/Text.css.ts
  • src/components/ui/Bleed/Bleed.tsx
  • src/components/ui/Spacer/Spacer.tsx
  • src/components/ui/Stack/Stack.tsx
🧰 Additional context used
📓 Path-based instructions (2)
`{src/types/*.{ts,tsx},src/app/**/_types/*.{ts,tsx},src/app/**/_schemas/*.{ts,ts...

{src/types/*.{ts,tsx},src/app/**/_types/*.{ts,tsx},src/app/**/_schemas/*.{ts,tsx},src/lib/validations/*.{ts,tsx}}: 타입 및 스키마 파일은 camelCase로 네이밍해야 한다 (예: domain.types.ts, form.schema.ts).

📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)

List of files the instruction was applied to:

  • src/types/polymorphic.types.ts
`src/types/*.{ts,tsx}`: 전역 타입 정의는 `types/` 폴더에 위치해야 한다.

src/types/*.{ts,tsx}: 전역 타입 정의는 types/ 폴더에 위치해야 한다.

📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)

List of files the instruction was applied to:

  • src/types/polymorphic.types.ts
🧠 Learnings (1)
src/types/polymorphic.types.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/types/*.{ts,tsx} : 전역 타입 정의는 `types/` 폴더에 위치해야 한다.
🪛 Biome (1.9.4)
src/types/polymorphic.types.ts

[error] 27-27: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 37-37: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: test
  • GitHub Check: storybook-preview

@Seojunhwan
Copy link
Member Author

@wkdtnqls0506 수빈님 꼼꼼한 확인 감사드려요! 스타일링은 말씀주신대로 namespace import로 변경하여 반영했어요!
3796eda (#69)

@wkdtnqls0506 wkdtnqls0506 reopened this Jul 6, 2025
Copy link
Contributor

@wkdtnqls0506 wkdtnqls0506 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아이고 모두 확인했습니다~!~! 수고하셨슴다🕺🏻🕺🏻🕺🏻🕺🏻🕺🏻🕺🏻🕺🏻🕺🏻

@wkdtnqls0506 wkdtnqls0506 added the ✨ feature 새로운 기능 추가 label Jul 6, 2025
@Seojunhwan Seojunhwan merged commit 20effd6 into main Jul 6, 2025
9 checks passed
@Seojunhwan Seojunhwan deleted the feature/PRODUCT-131 branch July 6, 2025 16:33
@coderabbitai coderabbitai bot mentioned this pull request Jul 20, 2025
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ feature 새로운 기능 추가

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[PRODUCT-131] 스타일링 유틸리티 컴포넌트 추가

2 participants