Skip to content

refactor: JDS Hero/Title/Label 컴포넌트 제거#441

Open
ccconac wants to merge 17 commits into
devfrom
refactor/hero
Open

refactor: JDS Hero/Title/Label 컴포넌트 제거#441
ccconac wants to merge 17 commits into
devfrom
refactor/hero

Conversation

@ccconac
Copy link
Copy Markdown
Member

@ccconac ccconac commented May 16, 2026

💡 작업 내용

  • 텍스트 스타일 토큰 생성 방식 개선 (단일 JSON 구조로 통합)
  • jds 패키지의 Hero, Title, Label 컴포넌트 제거 및 apps/web 로컬 컴포넌트 생성
    • jds 내부 제거 컴포넌트 사용처를 VE 기반 typography 유틸로 교체
    • cn 유틸리티 함수 추가 (clsx + tailwind-merge)

💡 자세한 설명

파일 변경점이 많은데, 세 컴포넌트 제거에 대한 대응이 대부분이라 가볍게 보고 넘어가 주시면 됩니다!

1. 텍스트 스타일 토큰 생성 방식 개선

Hero 컴포넌트가 완전히 제거되면서, 피그마 variable 관련 토큰이 개편되었습니다. (hero가 title 5/6으로 변경) 이에 따라 textStyle.json도 변경이 필요하여 피그마 플러그인을 사용해 새롭게 추출하였습니다. 이에 따라 json 구조 및 빌더의 변환 방법이 일부 변경되었습니다.

  • 입력 파일 교체: textStyle.jsontextStyles.json
    • 각 항목은 token, fontFamily, fontWeight, fontSize, lineHeight, letterSpacing만 포함하는 플랫 구조
    • Figma export에서 필요한 항목만 추출
{
  "textStyles": [
    {
      "token": "semantic-textstyle-title-6",
      "type": "text",
      "fontFamily": "Pretendard Variable",
      "fontWeight": "600",
      "fontSize": "48px",
      "lineHeight": "62px",
      "letterSpacing": "-1.25px"
    },
  ...
  ]
}
  • tokensBuilder.ts 로직 추가: normalizeExtractedTextStyles 함수 신규 구현

    • token 문자열(semantic-textstyle-body-md-normal)을 파싱해 category / size / weight를 추출
    • 추출된 정보를 기반으로 primitive 토큰 경로(primitive/font/size/{category}/{size} 등)를 조합
    • primitive 토큰이 존재하면 하드코딩 값 대신 CSS 변수(var(--typo-primitive-fontSize-*))로 연결
    • public key는 Figma 원본(textstyle)을 코드 관례(textStyle)로 정규화해 하위 호환 유지
  • 자동 생성 결과: textStyles.css.ts, globalStyles.ts, theme.ts, tokens.ts에 누락됐던 title-5, title-6 토큰이 추가 생성됨

관련하여 Tokens.mdx에 반영해 두었으니 참고 부탁드립니다.

2-1. jds 패키지의 Hero, Title, Label 컴포넌트 제거

JDS에서 Hero, Title, Label 컴포넌트가 제거되면서 JDS 패키지에서도 제거를 진행했습니다. 이때, 세 컴포넌트에 공통으로 존재하던 매핑 객체 및 스타일 헬퍼 함수를 jds/src/utils/typography.ts로 통합했습니다.

기존에 세 컴포넌트를 사용하던 파일에 어떻게 적용할까 생각하다 textStyle이 여러 텍스트 관련 토큰을 한 번에 품고 있는 것이라, 중복 코드를 줄이기 위해서 유틸리티 함수가 필요하다고 판단했습니다.

추가로 JDS가 vanilla-extract로 migration 중인 점을 반영해 jds/src/utils/typography.ts도 Emotion 기반 구현에서 VE 기반 구현으로 변경했습니다.

  • src/utils/typography.css.ts 추가
    • label, title recipe를 정의하고 기존 semantic-textStyle-* 전역 클래스를 조합
    • 기본 색상, 정렬, cursor variant를 VE 스타일로 관리
  • src/utils/typography.ts 변경
    • Emotion styled, Theme, CSSObject 의존성 제거
    • getLabelClassName, getTitleClassName, typography 유틸 추가
    • React 컴포넌트 래퍼 없이 recipe className을 생성하는 순수 유틸로 유지
    • src/utils/index.ts에서 typography 유틸을 export해 JDS utils entry에서 사용할 수 있도록 처리
  • JDS 내부 사용처 대응
    • styled(Label), styled(Title), JSX의 <Label> 사용처를 실제 DOM 태그와 getLabelClassName / getTitleClassName 조합으로 교체
    • LabelSize, LabelOwnProps 타입 import를 제거된 component 경로가 아닌 @/utils/typography로 교체
    • Accordion, Badge, Dialog, EmptyState, FileItem, Input, Menu, Select, Snackbar, Step, Tab, Table, Toast, Uploader 등 내부 컴포넌트의 typography 의존성을 함께 전환
    • 제거된 Hero, Title, Label 컴포넌트는 JDS public export로 복구하지 않음

2-2. apps/web 로컬 컴포넌트 생성

기존 세 컴포넌트를 1팀에서 사용 중이라 고민이 많았는데요. 도메인에 종속된 공용 컴포넌트로 선언하는 것이 맞다고 판단되어 /web/src/components/common/typography/ 하위에 동일한 로컬 컴포넌트를 새로 구현했습니다.

이 과정에서 스타일을 부모에서 덧씌울 때 !(important)를 사용하는 케이스가 많이 생겨 tailwind-merge를 설치하고 cn 유틸리티를 구현했습니다. 직접 관련한 유틸을 처음부터 구현하는 것보다 라이브러리를 설치해 사용하는 게 비용 측면에서 좋다고 생각했는데, 1팀 작업 관련이라 추후 제거나 지속 사용을 논의할 필요성이 있어 보입니다.

  • cn 유틸리티(clsx + tailwind-merge)로 조건부 클래스와 외부에서 전달된 className를 병합
    • apps/web/src/utils/cn.tsclsx + tailwind-merge 조합으로 구현
    • 조건부 클래스 및 Tailwind 클래스 충돌 병합을 안전하게 처리
  • Labelas prop을 지원해 <label>, <span>, <p> 등 다형성 렌더링 가능

📗 참고 자료 (선택)

📢 리뷰 요구 사항 (선택)

  • 로컬 타이포그래피 컴포넌트의 size prop 네이밍이 기존 jds 컴포넌트와 일부 다릅니다. 사용처 전체를 일괄 수정했으나 누락이 없는지 확인 부탁드립니다.
  • JDS 내부 컴포넌트에서 Label / Title 컴포넌트 의존성을 className 유틸 조합으로 바꾸면서 시각적 차이가 생기지 않았는지 함께 확인 부탁드립니다.
  • @jects/jds/utils에서 typography 유틸을 노출하는 방향이 적절한지 확인 부탁드립니다.

✅ 셀프 체크리스트

  • 머지할 브랜치 확인했나요?
  • 이슈는 close 했나요?
  • Reviewers, Labels, Projects를 등록했나요?
  • 기능이 잘 동작하나요?
  • 불필요한 코드는 제거했나요?

closes #435

Summary by CodeRabbit

릴리스 노트

  • New Features

    • 타이포그래피 스타일 유틸리티 시스템 추가
    • tailwind-merge 통합으로 스타일 충돌 해결 개선
  • Refactor

    • 공통 타이포그래피 컴포넌트(Hero, Label, Title) 구조 최적화
    • 컴포넌트 스타일링 시스템 통합 및 일관성 강화
    • 디자인 토큰 및 텍스트 스타일 시스템 개선

Review Change Stack

@ccconac ccconac self-assigned this May 16, 2026
@ccconac ccconac added 👩🏻‍💻frontend 프론트엔드 작업 ♻refactor 리팩토링 labels May 16, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented May 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ject-official-web-site-client-web Ready Ready Preview, Comment May 26, 2026 8:09am

@ccconac ccconac changed the title refactor: JDS Hero/Title/Label 컴포넌트 제거 refactor: JDS Hero/Title/Label 컴포넌트 제거 (수정 중...) May 16, 2026
@ccconac ccconac changed the title refactor: JDS Hero/Title/Label 컴포넌트 제거 (수정 중...) refactor: JDS Hero/Title/Label 컴포넌트 제거 May 18, 2026
@ccconac ccconac removed the 👩🏻‍💻frontend 프론트엔드 작업 label May 19, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

JDS의 Label/Hero/Title 컴포넌트를 제거하고 새로운 typography 유틸 시스템을 구축한 후, apps/web에 로컬 대체 컴포넌트를 추가하여 모든 JDS typography 의존성을 제거하는 리팩토링입니다.

Changes

Typography 시스템 리팩토링 및 마이그레이션

Layer / File(s) Summary
Typography 유틸 시스템 및 토큰 기반 구축
packages/jds/src/utils/typography.ts, packages/jds/src/utils/typography.css.ts, packages/jds/src/tokens/tokensBuilder.ts, packages/jds/src/tokens/input/textStyles.json, packages/jds/src/tokens/Tokens.mdx
@/utils/typographygetLabelClassName, getTitleClassName, shouldForwardTypographyProp 헬퍼를 추가하고, vanilla-extract 기반 label/title recipe를 구현합니다. 토큰 빌더를 수정하여 input/textStyles.json을 읽고 정규화된 canonical 텍스트 스타일을 생성하며, 토큰 문서를 업데이트하여 새로운 생성 방식을 설명합니다.
JDS 컴포넌트에서 Label/Hero/Title 제거 및 마이그레이션
packages/jds/src/components/Label/*, packages/jds/src/components/Hero/*, packages/jds/src/components/Title/*, packages/jds/src/components/**/*.styles.ts, packages/jds/src/components/**/*.tsx
JDS의 Label/Hero/Title 컴포넌트를 완전히 제거하고, 50개 이상의 내부 styled 컴포넌트를 styled(Label)에서 styled("span", { shouldForwardProp: shouldForwardTypographyProp })로 재구현합니다. 모든 컴포넌트에서 getLabelClassName() 유틸을 사용하여 typography 스타일을 className으로 적용하고 && 선택자를 통해 색상/커서를 설정합니다.
apps/web에 로컬 typography 컴포넌트 및 cn 유틸 추가
apps/web/src/components/common/typography/Hero.tsx, apps/web/src/components/common/typography/Label.tsx, apps/web/src/components/common/typography/Title.tsx, apps/web/src/components/common/typography/index.ts, apps/web/src/utils/cn.ts, apps/web/package.json
새로운 Hero, Label, Title 컴포넌트를 apps/web에 추가하여 JDS 컴포넌트를 대체합니다. 각 컴포넌트는 size/textAlign 옵션에 따라 CSS 클래스를 매핑하고 cn 유틸로 병합합니다. tailwind-merge 의존성을 추가하여 Tailwind 클래스 충돌을 해결하는 cn 유틸을 구현합니다.
apps/web 페이지/섹션에서 JDS 컴포넌트를 로컬 컴포넌트로 마이그레이션
apps/web/src/pages/*, apps/web/src/components/main/sections/*, apps/web/src/components/vision/sections/*, apps/web/src/features/**/*
20개 이상의 페이지와 섹션 컴포넌트에서 JDS Hero/Label/Title 임포트를 @/components/common/typography로 변경합니다. 모든 color prop을 제거하고 className 기반 스타일(예: className='text-white')로 전환하여, 색상 지정 방식을 통일합니다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

라벨과 타이틀 사라져,
유틸로 거듭나고,
로컬에서 피어나니,
Typography의 봄이로다! 🌸✨

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/hero

Copy link
Copy Markdown

@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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/jds/src/components/Menu/Menu/Menu.tsx (1)

42-47: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

MenuCategory의 ref 타입을 실제 요소와 일치시켜주세요.

Line 42에서 forwardRef<HTMLDivElement, MenuCategoryProps>로 선언되어 있지만, StyledMenuCategorystyled("span")로 구현되어 있습니다. ref 타입 제네릭이 렌더되는 실제 DOM 요소와 맞지 않습니다.

제안 수정
-const MenuCategory = forwardRef<HTMLDivElement, MenuCategoryProps>(({ children, ...rest }, ref) => {
+const MenuCategory = forwardRef<HTMLSpanElement, MenuCategoryProps>(({ children, ...rest }, ref) => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/jds/src/components/Menu/Menu/Menu.tsx` around lines 42 - 47, The
forwardRef generic for MenuCategory doesn't match the rendered element:
MenuCategory uses forwardRef<HTMLDivElement, MenuCategoryProps> but renders
StyledMenuCategory which is a styled("span"). Update the ref generic to the
actual DOM element type (use HTMLSpanElement) by changing the forwardRef
declaration for MenuCategory to forwardRef<HTMLSpanElement, MenuCategoryProps>,
ensuring ref typing aligns with StyledMenuCategory; alternatively, if you
intended a div, change StyledMenuCategory to render a div instead—pick the
approach that preserves the intended DOM element.
apps/web/src/pages/ApplyGuidePage.tsx (1)

3-18: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Label을 로컬 typography에서 가져오도록 수정 필요합니다.

ApplyGuidePage.tsx의 line 8에서 Label@jects/jds에서 가져오고 있으나, JDS는 Label을 내보내지 않습니다. Label@/components/common/typography에서 이미 구현되어 있으며, HeroTitle도 동일한 위치에서 가져오고 있습니다. 현재 상태는 import 오류를 야기합니다.

수정 제안
 import {
   Accordion,
   BlockButton,
   Divider,
   IconButton,
-  Label,
   LocalNavigation,
   Tab,
   toastController,
 } from "`@jects/jds`";
 import { theme } from "`@jects/jds/tokens`";
 import { useNavigate, useParams, useSearchParams, Navigate } from "react-router-dom";

 import type { JobFamily } from "`@/apis/apply`";
-import { Hero, Title } from "`@/components/common/typography`";
+import { Hero, Label, Title } from "`@/components/common/typography`";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/pages/ApplyGuidePage.tsx` around lines 3 - 18, The import list
in ApplyGuidePage.tsx incorrectly imports Label from "`@jects/jds`" causing an
import error; update the imports so that Label is imported from the local
typography module alongside Hero and Title (i.e., move Label from the
"`@jects/jds`" import to the "`@/components/common/typography`" import) and remove
Label from the destructured imports from "`@jects/jds`" to match available
exports.
🧹 Nitpick comments (3)
packages/jds/src/components/Toast/toast.styles.ts (1)

79-88: 💤 Low value

&& 선택자를 사용한 specificity 증가를 고려하세요.

&& 선택자로 색상 적용 우선순위를 높이고 있습니다. 이 패턴은 getLabelClassName으로 생성된 className 스타일을 override하기 위한 의도로 보이지만, CSS specificity에 의존하는 방식은 향후 유지보수 시 스타일 충돌 가능성을 높일 수 있습니다.

다만 코드베이스 전반에 걸쳐 일관되게 사용되는 패턴이므로, 현재로서는 문제없습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/jds/src/components/Toast/toast.styles.ts` around lines 79 - 88, The
ToastLabel styled component currently uses the "&&" selector to force higher CSS
specificity and override styles produced by getLabelClassName; instead remove
the "&&" hack and resolve precedence by composing/merging the generated class or
by applying the toast style color via the same class generation path (e.g.,
update getLabelClassName to include color from toastStylesMap or pass a
className prop to ToastLabel), ensuring ToastLabel uses
toastStylesMap(theme)[toastStyle].color without relying on "&&" so styles are
deterministic and maintainable.
apps/web/src/components/common/typography/Label.tsx (1)

10-18: ⚖️ Poor tradeoff

htmlFor prop의 타입 안전성 문제

htmlFor가 props에 항상 포함되지만, as prop으로 label이 아닌 다른 요소를 렌더링할 경우에도 해당 prop이 전달되어 유효하지 않은 HTML attribute가 생성될 수 있습니다.

🔧 조건부 타입으로 개선

고급 타입 기법을 사용하여 as="label"일 때만 htmlFor를 허용하도록 개선할 수 있습니다:

+type LabelPropsBase = {
+  as?: ElementType;
+  size?: LabelSize;
+  textAlign?: LabelAlign;
+  weight?: LabelWeight;
+  cursor?: LabelCursor;
+  children: ReactNode;
+};
+
+type LabelPropsWithHtmlFor = LabelPropsBase & {
+  as?: "label";
+  htmlFor?: string;
+};
+
+type LabelPropsWithoutHtmlFor = LabelPropsBase & {
+  as: Exclude<ElementType, "label">;
+  htmlFor?: never;
+};
+
+type LabelProps = (LabelPropsWithHtmlFor | LabelPropsWithoutHtmlFor) & 
+  Omit<HTMLAttributes<HTMLElement>, "style">;

또는 간단하게 htmlFor를 제거하고 사용처에서 직접 spread할 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/common/typography/Label.tsx` around lines 10 - 18,
LabelProps currently always includes htmlFor which can produce invalid
attributes when as is not "label"; change the prop typing so htmlFor is allowed
only when as extends "label" (e.g., convert LabelProps into a discriminated
union with a variant for { as?: "label"; htmlFor?: string } and a variant for
other ElementType values that omits htmlFor), or alternatively remove htmlFor
from LabelProps and require callers to spread htmlFor themselves when rendering
a label; update the Label component signature and any usages to match the new
LabelProps shape (refer to LabelProps, the as prop and htmlFor) so non-label
elements no longer receive htmlFor.
apps/web/src/components/common/typography/Hero.tsx (1)

14-19: ⚖️ Poor tradeoff

Hero와 Title의 sizeClassName 매핑이 동일한 것은 의도된 설계입니다.

Hero.tsx와 Title.tsx가 동일한 sizeClassName 매핑(lg→title-4, md→title-3 등)을 사용하는 것은 맞습니다. 다만 이 두 컴포넌트의 의미적 차이는 매핑을 통해서가 아니라 기본값과 폰트 굵기를 통해 표현됩니다:

  • Hero: 기본 크기="lg"(title-4) + 굵기="boldest"
  • Title: 기본 크기="md"(title-3) + 굵기="bolder"

따라서 토큰 매핑을 별도로 분리할 필요는 없으며, 현재 구조는 일관되고 합리적인 설계 패턴입니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/common/typography/Hero.tsx` around lines 14 - 19, The
size-to-token mapping in Hero.tsx (sizeClassName) intentionally mirrors
Title.tsx; to avoid reviewer confusion, add a concise inline comment near the
sizeClassName declaration in Hero.tsx explaining that the identical mapping is
deliberate and that semantic differences are expressed via default props and
font weight (Hero: default size "lg" and weight "boldest"; Title: default "md"
and weight "bolder"), and reference the related Title component so future
readers understand the design choice.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/jds/src/components/Input/TextField/TextFieldButton.tsx`:
- Line 43: The label in TextFieldButton uses getLabelClassName({ weight: "bold"
}) without specifying size, causing inconsistent label sizing across
InputArea/SelectField/TagField/FormField which use size: "sm"; update the call
in TextFieldButton (where getLabelClassName is invoked) to include size: "sm"
alongside weight to match the other input components and ensure consistent label
typography.

In `@packages/jds/src/components/Select/SelectCheckbox.tsx`:
- Around line 60-62: The caption typography in SelectCheckbox is missing the
subtle weight, so update the getLabelClassName call in SelectCheckbox (where
size is passed) to also include weight: "subtle" so the caption uses the same
subtle weight as SelectList; modify the props passed to getLabelClassName
accordingly to include weight: "subtle" alongside the existing size logic.

---

Outside diff comments:
In `@apps/web/src/pages/ApplyGuidePage.tsx`:
- Around line 3-18: The import list in ApplyGuidePage.tsx incorrectly imports
Label from "`@jects/jds`" causing an import error; update the imports so that
Label is imported from the local typography module alongside Hero and Title
(i.e., move Label from the "`@jects/jds`" import to the
"`@/components/common/typography`" import) and remove Label from the destructured
imports from "`@jects/jds`" to match available exports.

In `@packages/jds/src/components/Menu/Menu/Menu.tsx`:
- Around line 42-47: The forwardRef generic for MenuCategory doesn't match the
rendered element: MenuCategory uses forwardRef<HTMLDivElement,
MenuCategoryProps> but renders StyledMenuCategory which is a styled("span").
Update the ref generic to the actual DOM element type (use HTMLSpanElement) by
changing the forwardRef declaration for MenuCategory to
forwardRef<HTMLSpanElement, MenuCategoryProps>, ensuring ref typing aligns with
StyledMenuCategory; alternatively, if you intended a div, change
StyledMenuCategory to render a div instead—pick the approach that preserves the
intended DOM element.

---

Nitpick comments:
In `@apps/web/src/components/common/typography/Hero.tsx`:
- Around line 14-19: The size-to-token mapping in Hero.tsx (sizeClassName)
intentionally mirrors Title.tsx; to avoid reviewer confusion, add a concise
inline comment near the sizeClassName declaration in Hero.tsx explaining that
the identical mapping is deliberate and that semantic differences are expressed
via default props and font weight (Hero: default size "lg" and weight "boldest";
Title: default "md" and weight "bolder"), and reference the related Title
component so future readers understand the design choice.

In `@apps/web/src/components/common/typography/Label.tsx`:
- Around line 10-18: LabelProps currently always includes htmlFor which can
produce invalid attributes when as is not "label"; change the prop typing so
htmlFor is allowed only when as extends "label" (e.g., convert LabelProps into a
discriminated union with a variant for { as?: "label"; htmlFor?: string } and a
variant for other ElementType values that omits htmlFor), or alternatively
remove htmlFor from LabelProps and require callers to spread htmlFor themselves
when rendering a label; update the Label component signature and any usages to
match the new LabelProps shape (refer to LabelProps, the as prop and htmlFor) so
non-label elements no longer receive htmlFor.

In `@packages/jds/src/components/Toast/toast.styles.ts`:
- Around line 79-88: The ToastLabel styled component currently uses the "&&"
selector to force higher CSS specificity and override styles produced by
getLabelClassName; instead remove the "&&" hack and resolve precedence by
composing/merging the generated class or by applying the toast style color via
the same class generation path (e.g., update getLabelClassName to include color
from toastStylesMap or pass a className prop to ToastLabel), ensuring ToastLabel
uses toastStylesMap(theme)[toastStyle].color without relying on "&&" so styles
are deterministic and maintainable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4dd2b4fa-0697-4165-b8f1-67b8349aac17

📥 Commits

Reviewing files that changed from the base of the PR and between 9f572bf and 7013656.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (117)
  • apps/web/package.json
  • apps/web/src/components/common/typography/Hero.tsx
  • apps/web/src/components/common/typography/Label.tsx
  • apps/web/src/components/common/typography/Title.tsx
  • apps/web/src/components/common/typography/index.ts
  • apps/web/src/components/curriculum/sections/CurriculumTabSection.tsx
  • apps/web/src/components/gnb/Sidebar.tsx
  • apps/web/src/components/main/sections/HeroSection.tsx
  • apps/web/src/components/main/sections/IntroSection.tsx
  • apps/web/src/components/main/sections/JoinSection.tsx
  • apps/web/src/components/vision/sections/GoalSection.tsx
  • apps/web/src/components/vision/sections/GrowthStorySection.tsx
  • apps/web/src/components/vision/sections/MemberSection.tsx
  • apps/web/src/components/vision/sections/ProjectStartSection.tsx
  • apps/web/src/components/vision/sections/VisionHeroSection.tsx
  • apps/web/src/features/apply/steps/CompleteStep.tsx
  • apps/web/src/features/apply/steps/applicationInfo/ApplicantInfoStep.tsx
  • apps/web/src/features/apply/steps/registration/components/QuestionFieldWrapper.tsx
  • apps/web/src/features/shared/components/ApplyStepLayout.tsx
  • apps/web/src/pages/ApplyGuidePage.tsx
  • apps/web/src/pages/ApplyListPage.tsx
  • apps/web/src/pages/Curriculum.tsx
  • apps/web/src/pages/Faq.tsx
  • apps/web/src/pages/LiveSession.tsx
  • apps/web/src/pages/Maintenance.tsx
  • apps/web/src/pages/MiniStudy.tsx
  • apps/web/src/pages/NonSpecificError.tsx
  • apps/web/src/pages/NotFoundError.tsx
  • apps/web/src/pages/TeamProject.tsx
  • apps/web/src/pages/TeamProjectDetail.tsx
  • apps/web/src/utils/cn.ts
  • packages/jds/package.json
  • packages/jds/src/components/Accordion/Accordion.tsx
  • packages/jds/src/components/Accordion/accordion.styles.ts
  • packages/jds/src/components/Badge/contentBadge/ContentBadge.style.ts
  • packages/jds/src/components/Badge/contentBadge/ContentBadge.tsx
  • packages/jds/src/components/Badge/numericBadge/NumericBadge.style.ts
  • packages/jds/src/components/Badge/numericBadge/NumericBadge.tsx
  • packages/jds/src/components/Checkbox/Checkbox.tsx
  • packages/jds/src/components/Checkbox/checkbox.styles.ts
  • packages/jds/src/components/Dialog/Dialog.styles.ts
  • packages/jds/src/components/Dialog/Dialog.tsx
  • packages/jds/src/components/EmptyState/EmptyState.tsx
  • packages/jds/src/components/EmptyState/emptyState.styles.ts
  • packages/jds/src/components/FileItem/FileItem.tsx
  • packages/jds/src/components/FileItem/fileItem.styles.ts
  • packages/jds/src/components/FileItem/fileItem.types.ts
  • packages/jds/src/components/Hero/Hero.stories.tsx
  • packages/jds/src/components/Hero/Hero.style.ts
  • packages/jds/src/components/Hero/Hero.tsx
  • packages/jds/src/components/Hero/index.ts
  • packages/jds/src/components/Image/Image.style.ts
  • packages/jds/src/components/Image/Image.tsx
  • packages/jds/src/components/Input/InputArea/InputArea.tsx
  • packages/jds/src/components/Input/InputArea/inputArea.styles.ts
  • packages/jds/src/components/Input/SelectField/SelectFieldButton.tsx
  • packages/jds/src/components/Input/TagField/TagFieldButton.tsx
  • packages/jds/src/components/Input/TextField/TextFieldButton.tsx
  • packages/jds/src/components/Input/shared/FormField.tsx
  • packages/jds/src/components/Input/shared/field.styles.ts
  • packages/jds/src/components/Label/Label.stories.tsx
  • packages/jds/src/components/Label/Label.style.ts
  • packages/jds/src/components/Label/Label.tsx
  • packages/jds/src/components/Label/index.ts
  • packages/jds/src/components/Label/label.types.ts
  • packages/jds/src/components/Menu/MegaMenu/MegaMenu.tsx
  • packages/jds/src/components/Menu/MegaMenu/megaMenu.styles.ts
  • packages/jds/src/components/Menu/Menu/Menu.stories.tsx
  • packages/jds/src/components/Menu/Menu/Menu.styles.ts
  • packages/jds/src/components/Menu/Menu/Menu.tsx
  • packages/jds/src/components/Menu/Menu/menu.types.ts
  • packages/jds/src/components/Menu/Menu/menu.variants.ts
  • packages/jds/src/components/Menu/MenuItem/MenuItem.tsx
  • packages/jds/src/components/Menu/MenuItem/menuItem.styles.ts
  • packages/jds/src/components/Radio/Radio.style.ts
  • packages/jds/src/components/SegmentedControl/SegmentedControl.tsx
  • packages/jds/src/components/SegmentedControl/segmentedControl.styles.ts
  • packages/jds/src/components/Select/Select.tsx
  • packages/jds/src/components/Select/SelectCheckbox.tsx
  • packages/jds/src/components/Select/SelectList.tsx
  • packages/jds/src/components/Select/SelectRadio.tsx
  • packages/jds/src/components/Select/select.styles.ts
  • packages/jds/src/components/Snackbar/Snackbar.tsx
  • packages/jds/src/components/Snackbar/snackbar.styles.ts
  • packages/jds/src/components/Step/Step.tsx
  • packages/jds/src/components/Step/step.styles.ts
  • packages/jds/src/components/Tab/tab.styles.ts
  • packages/jds/src/components/Tab/tab.tsx
  • packages/jds/src/components/Table/compound/Table.styles.ts
  • packages/jds/src/components/Table/compound/TableHeaderItem.tsx
  • packages/jds/src/components/Table/compound/TableRowItem.tsx
  • packages/jds/src/components/Title/Title.stories.tsx
  • packages/jds/src/components/Title/Title.style.ts
  • packages/jds/src/components/Title/Title.tsx
  • packages/jds/src/components/Title/index.ts
  • packages/jds/src/components/Toast/Toast.tsx
  • packages/jds/src/components/Toast/toast.styles.ts
  • packages/jds/src/components/Tooltip/Tooltip.stories.tsx
  • packages/jds/src/components/Uploader/Uploader.tsx
  • packages/jds/src/components/Uploader/UploaderFile.stories.tsx
  • packages/jds/src/components/Uploader/uploader.styles.ts
  • packages/jds/src/components/index.ts
  • packages/jds/src/tokens/Tokens.mdx
  • packages/jds/src/tokens/breakpoints.ts
  • packages/jds/src/tokens/globalStyles.ts
  • packages/jds/src/tokens/globalTokens.css.ts
  • packages/jds/src/tokens/input/textStyle.json
  • packages/jds/src/tokens/input/textStyles.json
  • packages/jds/src/tokens/input/token.json
  • packages/jds/src/tokens/textStyles.css.ts
  • packages/jds/src/tokens/theme.ts
  • packages/jds/src/tokens/tokens.ts
  • packages/jds/src/tokens/tokensBuilder.ts
  • packages/jds/src/tokens/vars.css.ts
  • packages/jds/src/utils/index.ts
  • packages/jds/src/utils/typography.css.ts
  • packages/jds/src/utils/typography.ts
💤 Files with no reviewable changes (15)
  • packages/jds/src/components/Hero/Hero.stories.tsx
  • packages/jds/src/components/Hero/Hero.tsx
  • packages/jds/src/components/Label/index.ts
  • packages/jds/src/components/Hero/index.ts
  • packages/jds/src/components/Label/Label.stories.tsx
  • packages/jds/src/components/Label/label.types.ts
  • packages/jds/src/components/Title/Title.stories.tsx
  • packages/jds/src/components/Title/Title.tsx
  • packages/jds/src/tokens/input/textStyle.json
  • packages/jds/src/components/Title/Title.style.ts
  • packages/jds/src/components/Hero/Hero.style.ts
  • packages/jds/src/components/Label/Label.style.ts
  • packages/jds/src/components/Label/Label.tsx
  • packages/jds/src/components/Title/index.ts
  • packages/jds/src/components/index.ts

htmlFor={inputId}
size='md'
weight='bold'
className={getLabelClassName({ weight: "bold" })}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

라벨 타이포 크기 지정 누락으로 입력 컴포넌트 간 스타일 불일치가 발생할 수 있습니다.

Line 43은 weight만 지정되어 기본 size가 적용됩니다. 같은 입력 계열(InputArea, SelectField, TagField, FormField) 라벨은 size: "sm"를 사용 중이라 시각 차이가 생길 수 있습니다.

수정 제안
-              className={getLabelClassName({ weight: "bold" })}
+              className={getLabelClassName({ size: "sm", weight: "bold" })}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/jds/src/components/Input/TextField/TextFieldButton.tsx` at line 43,
The label in TextFieldButton uses getLabelClassName({ weight: "bold" }) without
specifying size, causing inconsistent label sizing across
InputArea/SelectField/TagField/FormField which use size: "sm"; update the call
in TextFieldButton (where getLabelClassName is invoked) to include size: "sm"
alongside weight to match the other input components and ensure consistent label
typography.

Comment on lines +60 to +62
className={getLabelClassName({
size: size === "md" ? "sm" : "xs",
})}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

캡션 타이포그래피 weight가 누락되었습니다.

캡션은 보조 텍스트인데 여기서는 weight: "subtle"이 빠져 기본 weight로 적용됩니다. SelectList의 캡션 처리와 맞추려면 subtle을 명시하는 게 안전합니다.

🔧 제안 수정안
             <StyledSelectItemCaption
               className={getLabelClassName({
                 size: size === "md" ? "sm" : "xs",
+                weight: "subtle",
               })}
               $isDisabled={isDisabled}
             >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
className={getLabelClassName({
size: size === "md" ? "sm" : "xs",
})}
className={getLabelClassName({
size: size === "md" ? "sm" : "xs",
weight: "subtle",
})}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/jds/src/components/Select/SelectCheckbox.tsx` around lines 60 - 62,
The caption typography in SelectCheckbox is missing the subtle weight, so update
the getLabelClassName call in SelectCheckbox (where size is passed) to also
include weight: "subtle" so the caption uses the same subtle weight as
SelectList; modify the props passed to getLabelClassName accordingly to include
weight: "subtle" alongside the existing size logic.

Copy link
Copy Markdown
Member

@itwillbeoptimal itwillbeoptimal left a comment

Choose a reason for hiding this comment

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

고생하셨습니다~ 실제 사용 시 문제되는 부분은 없어 보이는데, 몇 가지 자잘한 코멘트 남겼습니다. 확인 부탁드립니다 🙂

Comment on lines +21 to +25
const alignClassName: Record<HeroAlign, string> = {
center: "justify-center",
left: "justify-start",
right: "justify-end",
};
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Title, Hero, Label 모두 textAlign이 현재 flex 정렬만 설정하고 실제 CSS text-align을 설정하지 않는데 의도된 동작인지 궁금합니다

Copy link
Copy Markdown
Member Author

@ccconac ccconac May 26, 2026

Choose a reason for hiding this comment

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

레이아웃만 생각해서 생긴 단순 누락입니다. 😅 반영해 두었습니다. c1a92a6

Comment thread packages/jds/src/utils/typography.ts Outdated
Comment on lines +34 to +45
export const titleStylesMap = {
"2xl": "semantic-textStyle-title-6",
xl: "semantic-textStyle-title-5",
lg: "semantic-textStyle-title-4",
md: "semantic-textStyle-title-3",
sm: "semantic-textStyle-title-2",
xs: "semantic-textStyle-title-1",
} as const satisfies Record<TitleSize, string>;

export const getLabelTokenKey = (size: LabelSize, weight: LabelWeight): string => {
return `semantic-textStyle-label-${size}-${weight}`;
};
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

(참고) 현재 두 부분 모두 실제 사용처는 없지만, getTitleClassName에서 titleStylesMap 대신 recipe를 직접 호출하고 있어 토큰 수정 시 두 곳을 각각 관리해야 할 가능성이 있어 보입니다~

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

두 값이 담고 있는 매핑은 이미 typography.css.ts의 recipe에 그대로 있어서 삭제해도 무방할 것 같네용

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

제거했습니다! 1763b14

Comment on lines +47 to +58
export const getLabelClassName = ({
size = "md",
textAlign = "left",
weight = "normal",
cursor = "default",
}: LabelOwnProps = {}) =>
typographyStyles.label({
size,
textAlign,
weight,
cursor,
});
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LabelOwnPropscolor 필드가 정의되어 있는데 이 함수에 전달되지 않아서 무시될 수 있을 것 같습니다

Copy link
Copy Markdown
Member Author

@ccconac ccconac May 26, 2026

Choose a reason for hiding this comment

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

해당 prop은 확장성을 고려하느라 넣어 뒀던 것 같은데요. 지금 다시 보니 color는 상위 래퍼에서 오버라이드하는 형식으로 사용하는 곳이 대부분이더라구요. 함수에 전달했을 때에 사용 빈도가 적거나 거의 없을 거라 예상되어 통일성을 유지하기 위해 아예 제거했습니다. 9590017

Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
packages/jds/src/utils/index.ts (1)

4-5: ⚡ Quick win

utils/index.ts의 추가 export 범위가 PR 목적과도 연관되는지 점검

  • focusRing.css, overlay.cssButton/Radio/LabelButton 등에서 실제로 사용되는 pseudo-element(focus/hover) 유틸로, PSEUDO_ELEMENT_POLICY.md와 함께 설계되어 있어 “typography 리팩토링과 무관”하다고 보기 어렵습니다.
  • forwardRefImage, CardOverlay 등에서 PolymorphicForwardRef로 사용되고 있어 유틸 export로서 자연스럽습니다.
  • typography(getLabelClassName, getTitleClassName, shouldForwardTypographyProp, typography object)는 다수 컴포넌트/문서에서 이미 사용 중이라(예: Tab, Dialog, Select, Tokens.mdx) 공개 API 노출 방향은 타당해 보입니다.
  • 다만 index.tsexport *로 유틸 전부를 노출하므로(특히 focusRing.css, overlay.css), PR 목표(“typography 통합”) 대비 “의도한 public surface”인지 범위만 최종 확인이 필요합니다. (index.ts 4-5, 8-9)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/jds/src/utils/index.ts` around lines 4 - 5, The utils index
currently exports everything including focusRing.css and overlay.css plus
forwardRef and typography helpers (getLabelClassName, getTitleClassName,
shouldForwardTypographyProp, typography); confirm whether exposing focusRing.css
and overlay.css is intentional for this PR (typography consolidation) or if they
should remain internal per PSEUDO_ELEMENT_POLICY, and if not intentional, narrow
the exports in utils/index.ts to only the intended public symbols (e.g., keep
forwardRef and the typography helpers but remove or move focusRing.css and
overlay.css) or add explicit documentation/notes explaining the expanded public
surface.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/jds/src/utils/index.ts`:
- Around line 4-5: The utils index currently exports everything including
focusRing.css and overlay.css plus forwardRef and typography helpers
(getLabelClassName, getTitleClassName, shouldForwardTypographyProp, typography);
confirm whether exposing focusRing.css and overlay.css is intentional for this
PR (typography consolidation) or if they should remain internal per
PSEUDO_ELEMENT_POLICY, and if not intentional, narrow the exports in
utils/index.ts to only the intended public symbols (e.g., keep forwardRef and
the typography helpers but remove or move focusRing.css and overlay.css) or add
explicit documentation/notes explaining the expanded public surface.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 69949169-e462-4933-a8e7-d96054c7c8b0

📥 Commits

Reviewing files that changed from the base of the PR and between 9590017 and 712e592.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • packages/jds/package.json
  • packages/jds/src/components/Select/SelectRadio.tsx
  • packages/jds/src/utils/index.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/jds/package.json

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

♻refactor 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: (JDS) Hero/Title/Label 컴포넌트 제거

2 participants