Skip to content

refactor: JDS Checkbox 컴포넌트 vanilla-extract 마이그레이션#462

Merged
itwillbeoptimal merged 32 commits into
devfrom
refactor/451-jds-checkbox-migration
Jun 24, 2026
Merged

refactor: JDS Checkbox 컴포넌트 vanilla-extract 마이그레이션#462
itwillbeoptimal merged 32 commits into
devfrom
refactor/451-jds-checkbox-migration

Conversation

@itwillbeoptimal

@itwillbeoptimal itwillbeoptimal commented Jun 14, 2026

Copy link
Copy Markdown
Member

💡 작업 내용

  • @react-aria/checkbox 의존성 추가
  • 마이그레이션 타입 정의
  • CheckboxContext 작성
  • checkbox.css.ts VE 스타일 작성
  • migration/Checkbox.tsx VE 기반 구현체 작성
  • migration/Checkbox.stories.tsx 스토리 작성
  • 기존 Checkbox 구현 제거
  • breaking change changeset 추가

💡 자세한 설명

1. 개요

Checkbox의 스타일링 레이어를 Emotion에서 vanilla-extract로 마이그레이션합니다. @react-aria/checkbox를 도입하여 접근성 및 그룹 상태 관리를 위임하고, 전체 구조는 Radio 마이그레이션과 동일한 패턴을 따릅니다.

기존 Checkbox는 Emotion 기반으로 구현되어 있으며 그룹 사용을 지원하지 않습니다. 신규 구현은 우선 migration/ 디렉토리에 작성한 뒤, 본 PR 승인 후 기존 구현을 제거하고 migration/의 코드로 완전히 대체할 예정입니다.

Checkbox/
├── Checkbox.tsx               ← 기존 유지, 승인 후 제거 예정
├── checkbox.styles.ts         ← 기존 Emotion, 승인 후 제거 예정
├── checkbox.types.ts          ← 기존 타입, 승인 후 제거 예정
├── Checkbox.stories.tsx       ← 기존, 승인 후 제거 예정
├── index.ts                   ← 승인 후 migration 기준으로 교체
└── migration/
    ├── checkbox.types.ts      ← 완료
    ├── checkbox.variants.ts   ← 완료 (사이즈 맵 SSOT)
    ├── checkbox.css.ts        ← 완료
    ├── CheckboxContext.tsx    ← 완료
    ├── Checkbox.tsx           ← 완료
    └── Checkbox.stories.tsx   ← 완료

2. 컴포넌트 구조

신규 CheckboxRadio와 동일한 컴파운드 컴포넌트 구조를 따릅니다.

Checkbox (신규) 역할
Checkbox.Root 그룹 컨테이너 및 상태 관리
Checkbox.Item 레이아웃 및 인터랙션 컨테이너
Checkbox.Basic 실제 input과 시각적 인디케이터
Checkbox.Label 라벨 텍스트
Checkbox.Helper 보조 설명 텍스트

기존 Checkbox.Contentlabel, subLabel을 props로 받아 렌더링하는 프리셋 컴포넌트였습니다. 신규 구조에서는 Checkbox.Item, Checkbox.Basic, Checkbox.Label, Checkbox.Helper를 조합하는 방식으로 동일한 UI를 구성할 수 있습니다.


3. Checkbox.Root 도입 및 네이밍

기존 Checkbox 구현에는 그룹 컨테이너 개념이 없었습니다. 신규 구현에서는 @react-aria/checkboxuseCheckboxGroupuseCheckboxGroupState를 활용하여 Checkbox.Root를 추가합니다.

react-aria에서는 해당 개념을 CheckboxGroup으로 명명하고 있지만, 디자인 시스템 내부에서 Radio.Root와 동일한 패턴을 유지하기 위해 Checkbox.Root 네이밍을 사용합니다.

// Radio.Root: 단일 string 값 관리
type RadioRootControlledProps = {
  value: string;
  onChange: (value: string) => void;
};

// Checkbox.Root: 선택된 값 배열 관리
type CheckboxRootControlledProps = {
  value: string[];
  onChange: (value: string[]) => void;
};

Radio는 항상 그룹 단위로 동작하지만, 체크박스는 단독으로 사용할 수 있으므로 Checkbox.Root는 선택적으로 사용할 수 있습니다. Checkbox.Basic은 그룹 컨텍스트 존재 여부에 따라 내부 동작을 분기합니다.

// 그룹 내부 사용
// useCheckboxGroupItem을 통해 그룹 state 기반으로 checked 결정
if (context?.state) {
  return <CheckboxBasicGrouped ... />;
}

// 단독 사용
// useCheckbox + useToggleState를 통해 독립적으로 상태 관리
return <CheckboxBasicStandalone ... />;

4. Checkbox.Basic 제어/비제어 패턴

Radio.Basic은 그룹이 항상 선택 상태를 관리하므로 별도의 제어/비제어 분기가 존재하지 않습니다. 반면 Checkbox.Basic은 단독 사용 시 자체적으로 상태를 관리해야 합니다.

// 제어 컴포넌트, checked 사용 시 onCheckedChange 필수
type CheckboxBasicControlledProps = {
  checked: CheckState; // boolean | "indeterminate"
  defaultChecked?: never;
  onCheckedChange: (checked: CheckState) => void;
};

// 비제어 컴포넌트, defaultChecked만 사용
type CheckboxBasicUncontrolledProps = {
  checked?: never;
  defaultChecked?: boolean;
  onCheckedChange?: (checked: CheckState) => void;
};

indeterminate 상태는 비제어 모드에서 지원하지 않습니다. indeterminate는 HTML attribute가 아닌 DOM 프로퍼티(input.indeterminate)를 통해서만 설정할 수 있어 비제어 컴포넌트의 초기값으로 표현하기 어렵기 때문입니다.

Checkbox.Root 내부에서 사용되는 경우에는 그룹 상태가 선택 여부를 관리하므로 checkeddefaultChecked는 사용되지 않습니다. 이때 value: string은 그룹 내 각 체크박스를 식별하기 위한 키 역할을 합니다.


5. isInvalid 처리

isInvalidRadio에는 없는 개념입니다. Checkbox.RootCheckbox.Basic 모두에서 사용할 수 있으며, 그룹 전체 또는 개별 체크박스 단위로 유효성 검사 상태를 표현합니다.

@react-aria/checkboxCheckboxGroupStateisInvalid 상태를 기본적으로 지원하므로, 그룹 수준의 invalid 상태를 useCheckboxGroupState와 자연스럽게 연동할 수 있습니다.

스타일 레이어에서는 data-invalid 속성을 기반으로 처리하며, Radio에서 data-disabled를 전파하는 방식과 동일한 패턴입니다.

디자인 시스템 스펙상 invalid는 선택되지 않은 상태에 대한 유효성 검사 결과를 의미합니다. 따라서 checked 또는 indeterminate 상태에서는 invalid가 적용되지 않습니다.

이를 CSS 레이어에서 :not(:has(:checked)) 같은 셀렉터로 처리하는 대신 컴포넌트 레벨에서 invalid 상태를 필터링하여 data-invalid를 부여하도록 구현했습니다.

const isEffectiveInvalid = isInvalid && isChecked === false;

이렇게 계산된 isEffectiveInvalid를 기준으로 접근성 속성과 스타일 속성을 모두 제어합니다.

  • Checkbox.Basic

    • checked 상태를 직접 소유합니다. (그룹 state 또는 내부 toggle state)
    • data-invalid, aria-invalid, useCheckbox에 전달하는 isInvalid 모두 isEffectiveInvalid를 사용합니다.
    • 이를 통해 시각적 상태와 접근성 트리가 항상 동일한 상태를 유지합니다.
  • Checkbox.Item

    • checked 상태를 직접 알 수 없는 레이아웃 컨테이너입니다.
    • 자식 Checkbox.Basic으로부터 현재 checked 상태를 전달받아 invalid 여부를 판단합니다.
    • 상태 전달은 컨텍스트의 onChildCheckedChange 콜백을 통해 이루어지며, useLayoutEffect에서 페인트 이전에 반영합니다.

스타일 레이어의 :has() 기반 unchecked 가드를 사용하지 않고 data-invalid 속성 자체가 항상 unchecked + invalid 상태를 의미하도록 보장할 수 있습니다.


6. 컨텍스트 구조

컨텍스트 구조는 Radio와 동일하게 단일 컨텍스트를 사용합니다.

Checkbox.Root는 공통 설정과 그룹 상태를 제공하고, Checkbox.Item은 부모 컨텍스트를 읽어 자신의 props와 병합한 뒤 하위 컴포넌트에 전달합니다.

interface CheckboxContextValue {
  size: CheckboxSize;
  variant: CheckboxVariant;
  disabled: boolean;
  isInvalid: boolean;
  state?: CheckboxGroupState;
  onChildCheckedChange?: (checked: CheckState) => void;
}

onChildCheckedChange는 invalid 필터링을 위해 자식의 checked 상태를 상위로 전달하는 콜백입니다.

checked 상태는 Checkbox.Basic이 소유하지만, data-invalid 부여 여부는 Checkbox.Item에서 결정해야 합니다. 이를 위해 Item이 콜백을 제공하고, Basic이 상태 변경 시 현재 checked 값을 상위로 전달합니다.

Checkbox.Basic을 단독으로 사용하는 경우에는 해당 콜백이 존재하지 않으므로 별도의 동작 없이 무시됩니다.


7. 최신 DS 스펙 반영

마이그레이션 과정에서 확인된 최신 JDS 스펙을 반영했습니다.

항목 변경 전 변경 후
variant "empty" "hollow"
align 속성 "left" | "right" 제거
보조 텍스트 컴포넌트 Checkbox.SubLabel Checkbox.Helper
invalid 적용 범위 모든 상태 unchecked 상태에만 적용

8. 그리드 슬롯 배치 개선

처음 구현은 Radio에서 사용했던 위치 기반 배치 방식을 그대로 가져왔습니다.

globalStyle(`${checkboxItemGrid} > :nth-child(1)`, { ... }); // Control
globalStyle(`${checkboxItemGrid} > :nth-child(2)`, { ... }); // Label
globalStyle(`${checkboxItemGrid} > :nth-child(3)`, { ... }); // Helper

이 방식에서는 다음 문제들이 있었습니다.

  • 배치가 DOM 자식 순서에 의존합니다. Item > Basic + Helper처럼 특정 슬롯이 생략되면 의도하지 않은 위치에 배치될 수 있습니다.
  • :nth-child()는 자식 요소의 역할을 구분하지 않습니다. 예상하지 못한 요소가 추가될 경우 레이아웃이 깨질 수 있습니다.
  • 내부 서브 컴포넌트에 직접 클래스를 부여할 수 있음에도 위치 기반 globalStyle에 의존합니다.

이번 구현에서 역할 기반 클래스를 사용하여 위치 의존성을 제거했습니다.

const checkboxItemGrid = style({
  display: "inline-grid",
  gridTemplateColumns: "auto 1fr",
  alignItems: "center"
});

export const checkboxControlSlot = style({
  gridColumn: "1",
  gridRow: "1"
});

export const checkboxLabelSlot = style({
  gridColumn: "2",
  gridRow: "1"
});

export const checkboxHelperSlot = style({
  gridColumn: "2",
  gridRow: "2"
});

각 슬롯 클래스는 서브 컴포넌트에 직접 부여되며, DOM 순서나 자식 개수와 관계없이 역할에 맞는 위치에 배치됩니다.

처음에는 gridTemplateAreas를 사용했으나 Helper가 없어도 두 번째 행이 생성되어 row-gap 만큼의 하단 여백이 발생했습니다. 이를 방지하기 위해 gridRow 기반으로 수정했습니다.

📸 스크린샷

Before After
image image

📗 참고 자료 (선택)

📢 리뷰 요구 사항 (선택)

✅ 셀프 체크리스트

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

closes #451

Summary by CodeRabbit

릴리스 노트

  • New Features
    • Checkbox 마이그레이션 컴포넌트(Compound: Root / Item / Basic / Label / Helper) 추가: 단일/그룹 선택, Disabled/Invalid 표시, indeterminate 표현 지원.
  • Documentation
    • 마이그레이션 Storybook 스토리 추가(크기·상태·변형·그룹 시나리오 매트릭스) 및 마이그레이션 안내(예: empty→hollow, align 제거) 반영.
  • Bug Fixes
    • 체크박스 무효/색상 처리에 필요한 CSS 변수 연결 방식 개선.
  • Chores
    • Checkbox 관련 라이브러리 의존성 추가.

@itwillbeoptimal itwillbeoptimal self-assigned this Jun 14, 2026
@itwillbeoptimal itwillbeoptimal added the ♻refactor 리팩토링 label Jun 14, 2026
@vercel

vercel Bot commented Jun 14, 2026

Copy link
Copy Markdown

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 Jun 21, 2026 2:15pm

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

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

packages/jds/src/components/Checkbox/migration/ 디렉터리에 vanilla-extract 스타일과 react-aria/react-stately 기반의 신규 Checkbox 컴포넌트를 구현합니다. 타입 계약, 컨텍스트, 스타일 레시피, Root/Item/Basic/Label/Helper 컴포넌트, Storybook 스토리가 모두 신규 추가되며, @react-aria/checkbox 패키지 의존성이 등록되고 타이포그래피 유틸의 색상 변수가 재구성됩니다.

Changes

Checkbox 마이그레이션 (vanilla-extract + react-aria)

Layer / File(s) Summary
타입 계약, 사이즈 변형 매핑, 컨텍스트, 패키지 의존성
packages/jds/package.json, packages/jds/src/components/Checkbox/migration/checkbox.types.ts, packages/jds/src/components/Checkbox/migration/checkbox.variants.ts, packages/jds/src/components/Checkbox/migration/CheckboxContext.tsx
@react-aria/checkbox 의존성을 추가하고, CheckboxSize/CheckboxVariant/CheckedState 타입과 Root·Item·Basic·Label·Helper props 유니온을 선언합니다. 사이즈별 visual(pxToRem)·icon(IconSize)·label/helper(LabelSize) 매핑 상수와, CheckboxContextValue 인터페이스 및 CheckboxProvider·useCheckboxContext 훅을 정의합니다.
vanilla-extract 스타일 레시피 및 타이포그래피 변수화
packages/jds/src/components/Checkbox/migration/checkbox.css.ts, packages/jds/src/utils/typography.css.ts
checkboxGroupWrapper·checkboxInput·checkboxRootLabel 레이아웃을 정의하고, checkboxVisual 레시피로 size/체크/indeterminate/invalid/포커스 상태별 배경·테두리·오버레이를 제어합니다. checkboxItem 레시피는 size/styleOutlined compound variants와 data-disabled/data-invalid 테두리 색을 결합하며, checkboxTextLabel/checkboxHelper는 상위 상태에 따라 색상을 전환합니다. typography.css.ts에서 labelColorVar 변수를 추가하고 label 레시피를 변수 기반으로 리팩토링합니다.
Checkbox 컴포넌트 구현 (Root/Item/Basic/Label/Helper)
packages/jds/src/components/Checkbox/migration/Checkbox.tsx
CheckboxRootuseCheckboxGroupState로 그룹 상태를 생성해 CheckboxProvider로 전파합니다. CheckboxItemchildChecked로 invalid 조건을 계산하고, CheckboxBasic은 그룹 유무에 따라 useCheckboxGroupItem 또는 useToggleState+ref.indeterminate 직접 세팅으로 분기합니다. CheckboxLabel/CheckboxHelper는 컨텍스트 size로 래퍼 클래스를 결정하고, export const Checkbox = { Root, Item, Basic, Label, Helper }로 노출합니다.
Storybook 스토리 (Basic/Item/Group/Matrix)
packages/jds/src/components/Checkbox/migration/Checkbox.stories.tsx
CheckboxBasicSizes·CheckboxBasicStates, CheckboxItemStyle·Disabled·Invalid, CheckboxGroupUncontrolled·Controlled·SelectAll·Disabled·Invalid, CheckboxComprehensiveMatrix 스토리를 추가합니다.
변경 사항 문서화
.changeset/checkbox-migration.md
Checkbox API가 단일/프리셋 구조에서 Compound Component 패턴으로 변경됨을 명시하고, variant/align 변경, value 필수 조건, indeterminate/invalid 동작 규칙을 AS-IS/TO-BE 코드 예시로 설명합니다.

Sequence Diagram(s)

sequenceDiagram
  participant Consumer
  participant CheckboxRoot
  participant CheckboxProvider
  participant CheckboxItem
  participant CheckboxBasic

  Consumer->>CheckboxRoot: value / onChange / size / variant 전달
  CheckboxRoot->>CheckboxRoot: useCheckboxGroupState() 호출
  CheckboxRoot->>CheckboxProvider: size, variant, disabled, isInvalid, state 제공
  CheckboxProvider->>CheckboxItem: 컨텍스트 전파
  CheckboxItem->>CheckboxItem: childChecked로 isInvalid && !childChecked 계산
  CheckboxItem->>CheckboxProvider: onChildCheckedChange 콜백 등록
  CheckboxItem->>CheckboxBasic: 그룹 state 존재 여부 판단

  alt 그룹 내 아이템 (value 필수)
    CheckboxBasic->>CheckboxBasic: useCheckboxGroupItem() 호출
    CheckboxBasic->>CheckboxItem: onChildCheckedChange(isChecked) 동기화
  else 단독 아이템
    CheckboxBasic->>CheckboxBasic: useToggleState() 호출
    CheckboxBasic->>CheckboxBasic: ref.current.indeterminate 직접 세팅
    CheckboxBasic->>CheckboxItem: onChildCheckedChange(isChecked) 동기화
  end

  CheckboxBasic-->>Consumer: input + checkboxVisual 렌더링
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60분

Possibly related PRs

  • JECT-Study/JECT-Official-WebSite-Client#441: 타이포그래피 스타일 시스템 재구성 중 label 레시피의 색상 변수화(labelColorVar) 수행으로 checkbox 헬퍼 텍스트 색상 제어와 직접 연관됩니다.

Suggested reviewers

  • WonJuneKim
  • ccconac

Poem

🐇 토끼가 체크박스를 새로 만들었네,
vanilla-extract로 스타일을 입히고,
react-aria가 접근성을 지키며,
indeterminate도 빠짐없이 챙겼지!
Root, Item, Basic, Label, Helper 한 줄로 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 PR의 핵심 변경 사항인 Checkbox 컴포넌트의 vanilla-extract 마이그레이션을 명확하게 요약하고 있습니다.
Linked Issues check ✅ Passed PR은 linked issue #451의 모든 주요 요구사항을 충족합니다: vanilla-extract 마이그레이션 완료, 스타일/인터랙션 동작 확인, 불필요한 Emotion 의존성 제거.
Out of Scope Changes check ✅ Passed 모든 변경 사항이 Checkbox 마이그레이션의 범위 내에 있습니다. typography.css.ts의 labelColorVar 추가는 Checkbox 스타일링을 지원하기 위한 필수 변경입니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed PR 설명이 제공된 템플릿의 모든 필수 섹션을 포함하고 있으며, 작업 내용, 자세한 설명, 스크린샷, 셀프 체크리스트를 완벽하게 작성했습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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/451-jds-checkbox-migration

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
packages/jds/src/components/Checkbox/migration/checkbox.css.ts (1)

30-31: .visual 문자열에 대한 취약한 스타일 계약을 제거하세요.

checkbox.css.ts의 30-31줄과 163-165줄처럼 전역 선택자가 하드코딩된 "visual" 클래스에 의존하면, Checkbox.tsx에서 호출부를 리팩터링할 때 포커스 링 동작이 조용히 깨질 수 있습니다. 슬롯 전용 클래스를 checkbox.css.ts에서 export하고, Checkbox.tsx에서 그 클래스를 함께 주입하도록 변경하면 이러한 위험을 제거할 수 있습니다.

변경 예시
-// 호출자는 className에 "visual" 리터럴을 반드시 함께 부여해야 한다. checkboxItem globalStyle이 이 클래스명에 의존한다.
+export const checkboxVisualSlot = style({});

-globalStyle(`${checkboxItemGrid} input[type="checkbox"]:focus-visible + .visual`, {
+globalStyle(`${checkboxItemGrid} input[type="checkbox"]:focus-visible + .${checkboxVisualSlot}`, {
   boxShadow: "none !important",
});
-<span className={clsx(checkboxVisual({ size }), "visual")} aria-hidden='true'>
+<span className={clsx(checkboxVisual({ size }), checkboxVisualSlot)} aria-hidden='true'>
🤖 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/Checkbox/migration/checkbox.css.ts` around lines
30 - 31, Remove the brittle hardcoded dependency on the "visual" class string in
checkbox.css.ts. Instead of relying on callers to manually inject the "visual"
className, export a named class constant from checkbox.css.ts that represents
the visual slot (this will replace the reliance on the global selector and the
comments at lines 30-31 and 163-165 about the hardcoded "visual" string). Then
update Checkbox.tsx to import this exported class and inject it alongside other
classes when rendering the checkbox element, eliminating the fragile string
contract that could silently break during refactoring.
🤖 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/Checkbox/migration/checkbox.css.ts`:
- Line 9: The checkboxGroupWrapper style uses display: contents which removes
the element from the layout tree and breaks accessibility semantics for the
checkbox group, causing some browser and screen reader combinations to
incorrectly interpret the accessibility attributes from react-aria's
useCheckboxGroup(). Replace the display: contents value in the
checkboxGroupWrapper style definition with either display: block or display:
inline-flex to preserve the semantic meaning of the group wrapper while
maintaining proper accessibility support.

In `@packages/jds/src/components/Checkbox/migration/Checkbox.stories.tsx`:
- Around line 23-26: The Checkbox.Basic components in the stories lack
accessible names, causing accessibility warnings for unlabeled controls. Add
aria-label or aria-labelledby attributes to each Checkbox.Basic instance to
provide accessible names. This issue affects multiple locations in the file
packages/jds/src/components/Checkbox/migration/Checkbox.stories.tsx: at lines
23-26 (the anchor location showing the basic size variants), at lines 35-45, and
at lines 285-295. For each location, add appropriate aria-label attributes to
the Checkbox.Basic components to describe their purpose or distinguishing
characteristics.

In `@packages/jds/src/components/Checkbox/migration/Checkbox.tsx`:
- Around line 145-166: The forwardRef is created using
useObjectRef(forwardedRef) but is not being connected to the actual input
element, causing the ref contract to break in group mode where ref.current
remains empty. Add the ref attribute to the input element (the one with
mergeProps(inputProps, restProps)) by passing the ref variable that was created,
so the forwarded reference actually points to the underlying input DOM element.
- Around line 260-271: In group mode (when context?.state exists), the
CheckboxBasicGrouped component receives value={value ?? ""} which defaults
missing values to empty strings, causing multiple items without explicit values
to be treated identically and breaking group selection logic. Remove the
fallback to empty string and instead require value to be present in group mode -
either validate that value exists before rendering CheckboxBasicGrouped or throw
an error when value is missing, ensuring each checkbox item in the group has a
unique identifier.

---

Nitpick comments:
In `@packages/jds/src/components/Checkbox/migration/checkbox.css.ts`:
- Around line 30-31: Remove the brittle hardcoded dependency on the "visual"
class string in checkbox.css.ts. Instead of relying on callers to manually
inject the "visual" className, export a named class constant from
checkbox.css.ts that represents the visual slot (this will replace the reliance
on the global selector and the comments at lines 30-31 and 163-165 about the
hardcoded "visual" string). Then update Checkbox.tsx to import this exported
class and inject it alongside other classes when rendering the checkbox element,
eliminating the fragile string contract that could silently break during
refactoring.
🪄 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: 1aab636a-10b7-426c-9a4d-ee90a629b8d9

📥 Commits

Reviewing files that changed from the base of the PR and between 760f95f and b883727.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • packages/jds/package.json
  • packages/jds/src/components/Checkbox/migration/Checkbox.stories.tsx
  • packages/jds/src/components/Checkbox/migration/Checkbox.tsx
  • packages/jds/src/components/Checkbox/migration/CheckboxContext.tsx
  • packages/jds/src/components/Checkbox/migration/checkbox.css.ts
  • packages/jds/src/components/Checkbox/migration/checkbox.types.ts
  • packages/jds/src/components/Checkbox/migration/checkbox.variants.ts
  • packages/jds/src/utils/index.ts
  • packages/jds/src/utils/labelTypographyVars.css.ts

import { CHECKBOX_SIZE_OPTIONS, type CheckboxSize } from "./checkbox.types";
import { checkboxSizeMap } from "./checkbox.variants";

export const checkboxGroupWrapper = style({ display: "contents" });

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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# checkboxGroupWrapper가 실제 groupProps가 붙는 노드에 적용되는지 확인
rg -n -C3 'checkboxGroupWrapper|useCheckboxGroup|groupProps' packages/jds/src/components/Checkbox/migration/Checkbox.tsx
rg -n -C2 'display:\s*"contents"' packages/jds/src/components/Checkbox/migration/checkbox.css.ts

Repository: JECT-Study/JECT-Official-WebSite-Client

Length of output: 1716


display: contents가 그룹 접근성 시맨틱을 깨뜨릴 수 있습니다.

Line 60에서 checkboxGroupWrappergroupProps를 받는 div 요소에 적용됩니다. display: contents는 요소를 레이아웃 트리에서 제거하면서, react-aria의 useCheckboxGroup()에서 제공하는 접근성 속성을 일부 브라우저/스크린리더 조합에서 올바르게 해석하지 못할 수 있습니다. 그룹 래퍼는 시맨틱 보존이 가능한 display: block 또는 display: inline-flex 계열로 변경하는 것이 안전합니다.

🤖 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/Checkbox/migration/checkbox.css.ts` at line 9,
The checkboxGroupWrapper style uses display: contents which removes the element
from the layout tree and breaks accessibility semantics for the checkbox group,
causing some browser and screen reader combinations to incorrectly interpret the
accessibility attributes from react-aria's useCheckboxGroup(). Replace the
display: contents value in the checkboxGroupWrapper style definition with either
display: block or display: inline-flex to preserve the semantic meaning of the
group wrapper while maintaining proper accessibility support.

Comment on lines +23 to +26
<Checkbox.Basic size='lg' />
<Checkbox.Basic size='md' />
<Checkbox.Basic size='sm' />
<Checkbox.Basic size='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

Checkbox.Basic 단독 예시에 접근 가능한 이름을 추가해 주세요.

현재 여러 스토리에서 라벨 없이 Checkbox.Basic만 렌더링되어 접근성 검사에서 unlabeled control 경고가 날 수 있습니다. 각 항목에 aria-label(또는 aria-labelledby)을 넣어 주세요.

예시 수정
- <Checkbox.Basic size='lg' />
+ <Checkbox.Basic size='lg' aria-label='Large checkbox' />

- <Checkbox.Basic checked={false} onCheckedChange={() => {}} />
+ <Checkbox.Basic
+   checked={false}
+   aria-label='Unchecked checkbox'
+   onCheckedChange={() => {}}
+ />

Also applies to: 35-45, 285-295

🤖 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/Checkbox/migration/Checkbox.stories.tsx` around
lines 23 - 26, The Checkbox.Basic components in the stories lack accessible
names, causing accessibility warnings for unlabeled controls. Add aria-label or
aria-labelledby attributes to each Checkbox.Basic instance to provide accessible
names. This issue affects multiple locations in the file
packages/jds/src/components/Checkbox/migration/Checkbox.stories.tsx: at lines
23-26 (the anchor location showing the basic size variants), at lines 35-45, and
at lines 285-295. For each location, add appropriate aria-label attributes to
the Checkbox.Basic components to describe their purpose or distinguishing
characteristics.

Comment thread packages/jds/src/components/Checkbox/migration/Checkbox.tsx Outdated
Comment thread packages/jds/src/components/Checkbox/migration/Checkbox.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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/components/Checkbox/migration/checkbox.variants.ts (1)

6-14: 💤 Low value

타입 추론 강화를 위해 as const 단언 추가를 고려하세요 (선택 사항).

현재 구현은 정상 작동하지만, as const 단언을 추가하면 각 속성 값이 리터럴 타입으로 좁혀져 더 엄격한 타입 안전성을 제공합니다.

♻️ 제안하는 개선 사항
 export const checkboxSizeMap: Record<
   CheckboxSize,
   { visual: string; icon: IconSize; label: LabelSize; helper: LabelSize }
-> = {
+> = {
   lg: { visual: pxToRem(20), icon: "md", label: "lg", helper: "sm" },
   md: { visual: pxToRem(18), icon: "sm", label: "md", helper: "sm" },
   sm: { visual: pxToRem(16), icon: "xs", label: "sm", helper: "xs" },
   xs: { visual: pxToRem(14), icon: "2xs", label: "xs", helper: "xs" },
-};
+} as const;

이렇게 하면 각 사이즈별 값이 더 구체적인 리터럴 타입으로 추론되어, 런타임 오류를 컴파일 타임에 잡을 수 있습니다.

🤖 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/Checkbox/migration/checkbox.variants.ts` around
lines 6 - 14, The checkboxSizeMap object in checkbox.variants.ts would benefit
from stricter type inference. Add an `as const` assertion at the end of the
checkboxSizeMap object definition to narrow each property value to its literal
type. This will enable the TypeScript compiler to catch type mismatches at
compile time rather than runtime by ensuring that icon size values like "md",
"sm", "xs", "2xs" and label sizes are inferred as exact literal types rather
than general string types.
🤖 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/components/Checkbox/migration/checkbox.variants.ts`:
- Around line 6-14: The checkboxSizeMap object in checkbox.variants.ts would
benefit from stricter type inference. Add an `as const` assertion at the end of
the checkboxSizeMap object definition to narrow each property value to its
literal type. This will enable the TypeScript compiler to catch type mismatches
at compile time rather than runtime by ensuring that icon size values like "md",
"sm", "xs", "2xs" and label sizes are inferred as exact literal types rather
than general string types.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e21a2aac-f377-446e-8240-128d602c46e0

📥 Commits

Reviewing files that changed from the base of the PR and between 137db08 and d165ce3.

📒 Files selected for processing (7)
  • .changeset/checkbox-migration.md
  • packages/jds/src/components/Checkbox/migration/Checkbox.stories.tsx
  • packages/jds/src/components/Checkbox/migration/Checkbox.tsx
  • packages/jds/src/components/Checkbox/migration/CheckboxContext.tsx
  • packages/jds/src/components/Checkbox/migration/checkbox.css.ts
  • packages/jds/src/components/Checkbox/migration/checkbox.types.ts
  • packages/jds/src/components/Checkbox/migration/checkbox.variants.ts
✅ Files skipped from review due to trivial changes (1)
  • .changeset/checkbox-migration.md
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/jds/src/components/Checkbox/migration/CheckboxContext.tsx
  • packages/jds/src/components/Checkbox/migration/checkbox.types.ts
  • packages/jds/src/components/Checkbox/migration/Checkbox.stories.tsx
  • packages/jds/src/components/Checkbox/migration/checkbox.css.ts
  • packages/jds/src/components/Checkbox/migration/Checkbox.tsx

@Zero-1016 Zero-1016 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

확인했습니다. 추가로 몇가지 코멘트 남겼으니 확인해주세요!

Comment thread .changeset/checkbox-migration.md Outdated
Comment thread packages/jds/src/components/Checkbox/migration/checkbox.css.ts Outdated
Comment thread packages/jds/src/components/Checkbox/migration/checkbox.css.ts Outdated

@areumH areumH left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

수고하셨습니다!! 간단히 코멘트 남깁니다 ☺️


CheckboxBasic.displayName = "Checkbox.Basic";

const CheckboxLabel = forwardRef<HTMLDivElement, CheckboxLabelProps>(({ children }, ref) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Checkbox.Label이 실제 checkbox input과 연결되어 있지 않아서 라벨 텍스트를 클릭해도 체크박스가 토글되지 않을 것 같아요.

피그마의 하이퍼링크 사용 - 이 때 checkbox 인터렉션에 가려져 하이퍼링크에 접근할 수 없는 경우를 방지해야 합니다. 문구에 따르면 레이블 텍스트나 그룹 컴포넌트를 클릭했을 때 체크박스 토글로 이어져야할 것 같아 코멘트 남겨요!

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.

기존 구현에서도 누락되어 있던 부분이었네요! 789e523 에서 반영했습니다. 하이퍼링크 사용 관련해서는 Checkbox에서 서브 컴포넌트로 제공하는 것과 소비자가 직접 조합하는 것 중 어떤 방식이 더 적절할지 조금 더 검토해봐야 할 것 같아요

Comment on lines +93 to +97
'input[type="checkbox"]:not(:disabled) + &:hover::after': {
opacity: overlayOpacityMap.normal.hover,
},
'input[type="checkbox"]:not(:disabled) + &:active::after': {
opacity: overlayOpacityMap.normal.pressed,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Checkbox.Item 안에서 Checkbox.Basic을 사용할 때 item overlay와 visual overlay가 동시에 켜질 수 있을 것 같아요. 체크박스 visual 영역에 hover될 경우 해당 영역만 색이 더 진해질 수 있어 보이는데, 의도된 스타일인지 궁금합니다!

@itwillbeoptimal itwillbeoptimal Jun 16, 2026

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.

기존에는 visual 영역만 클릭 가능해서 별도 인터랙션 레이어를 두었는데 label과 연결된 이후에는 중복인 것 같아 제거해 두었습니다.

다만 지금은 label 영역에만 id를 연결해서 토글 범위가 제한되어 있는데, 다시 생각해 보니 Checkbox.Item이 hover/press 인터랙션을 위임받는 만큼 토글도 같이 책임지는 편이 더 자연스러울 것 같네요 😅 이 부분은 구조 변경이 꽤 있을 것 같아 별도 PR로 반영해 두겠습니다~

@Zero-1016 Zero-1016 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

conflict 나는 부분 확인해주세요.

@Zero-1016 Zero-1016 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

다음 코멘트들 확인 부탁드려요. 놓친 부분들 다시 코멘트 드립니다.

Comment thread packages/jds/src/components/Checkbox/CheckboxContext.tsx

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

해당 파일을 제거하고 Checkbox.tsx / checkbox.css.ts에서 직접 처리하는 게 가독성(응집도) 면에서 좋아 보여요.

checkboxSizeMap의 필드를 보면 소비처가 완전히 갈립니다:

  • visualcheckbox.css.ts에서만 사용 (recipe의 width/height)
  • icon label helperCheckbox.tsx에서만 사용 (<Icon size>, getLabelClassName)

지금은 한 테이블에 모여 있지만 정작 한 파일이 네 필드를 다 쓰는 곳은 없어요. 그래서 사이즈를 수정하거나 추가할 때 variants.ts로 한 번 더 들어가야 해서, 오히려 depth만 길어지고 불편한 것 같아요.

소비처 기준으로 나누면:

// checkbox.css.ts — visual만
const checkboxSizeMap = {
  lg: { visual: pxToRem(20) },
  md: { visual: pxToRem(18) },
  sm: { visual: pxToRem(16) },
  xs: { visual: pxToRem(14) },
} satisfies Record<CheckboxSize, { visual: string }>;
// Checkbox.tsx — icon / label / helper
const checkboxSizeMap = {
  lg: { icon: "md", label: "lg", helper: "sm" },
  md: { icon: "sm", label: "md", helper: "sm" },
  sm: { icon: "xs", label: "sm", helper: "xs" },
  xs: { icon: "2xs", label: "xs", helper: "xs" },
} satisfies Record<CheckboxSize, { icon: IconSize; label: LabelSize; helper: LabelSize }>;

이러면 각 파일이 자기가 쓰는 토큰만 갖고, pxToRem / IconSize·LabelSize import도 각 소비처로 따라가 정리됩니다.

"사이즈 토큰이 두 군데로 흩어지지 않나"라는 우려는 있을 수 있는데, visual과 나머지는 소비처가 갈려서 실제로 같이 수정할 일이 적습니다. 한 테이블로 묶어둔 응집보다, 각 파일이 쓰는 값만 곁에 두는 쪽이 이 경우엔 더 자연스러워 보여요.

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.

원래는 사이즈 관련 값을 한 객체에 모아 컴포넌트의 사이즈 설정 값을 SSOT로 관리하려는 의도였는데요, 각 서브 컴포넌트가 모두 동일한 size variant에 따라 함께 결정되는 값이라고 생각해서 사이즈를 추가하거나 수정할 때 한 곳만 확인하면 된다고 생각했어요.

다만 말씀해주신 대로 실제 사용 위치가 분리되어 있어서 SSOT의 이점은 살리지 못하고 불필요한 depth만 늘어나는 것처럼 보이기도 하네요 😓


export const CheckboxProvider = CheckboxContext.Provider;

export const useCheckboxContext = () => useContext(CheckboxContext);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

지금 useContext를 바로 반환하고 있어, null 타입이 추론되기 때문에 코드상에서 null 검사를 해주고 있는 것을 확인했어요.

useContext를 사용하는 부분에서 검사를 진행한다면 다음처럼 사용할 수 있어요.

-  const context = useCheckboxContext();
-  const size = context?.size ?? "md";
+  const { size } = useCheckboxContext('Checkbox.Label');
Suggested change
export const useCheckboxContext = () => useContext(CheckboxContext);
export const useCheckboxContext = (componentName: string) => {
const context = useContext(CheckboxContext);
if (!context) {
throw new Error(`${componentName} 컴포넌트는 Checkbox.Root 내부에서 사용해야 합니다`);
}
return context;
};

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.

image

컨텍스트를 nullable로 두고 코드에서 null을 처리하는 건 의도된 부분이었어요. Checkbox.Basic은 컨트롤 단독 사용(문서상으로도 권장되지는 않지만 지원하는 케이스)을 허용하고 있어서, Root/Item 없이 사용되면 컨텍스트가 null이 됩니다.

그리고 컨텍스트 분리 이후 useCheckboxItem()의 반환값이 null인지 여부로 Item 내부에서 사용 중인지도 함께 판별하고 있어서 컨텍스트가 null인 상태가 유효해요. "md" 폴백도 Provider 없이 동작할 수 있도록 둔 기본값이었어요.

다만 Label/HelperItem 외부에서 사용되면 의미가 없어서, 이 둘에만 제약을 둘 수 있을 것 같습니다. 공유 훅은 nullable 상태로 유지하고, Item 컨텍스트가 없으면 throw하는 훅을 별도로 만들어 Label/Helper에만 적용하는 방식을 생각하고 있는데, 혹시 더 좋은 방향이 있을까요?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

내부에 명시적인 플래그/분기 로직을 두고 싶지 않아서, 컨텍스트 존재 여부로 갈라낼 수 있을지 생각해봤어요. 그런데 Checkbox.Basic이 단독·그룹 양쪽에서 공용으로 쓰이다 보니(혼자 쓰거나, Root 안에서 그룹으로 쓰거나) 이 방식으로는 깔끔하게 분리하기 어려워 보여요. useCheckboxItem Provider도 Basic 최상단에서 씌워지는 구조라, "컨텍스트가 있으면 Item 안"이라는 판별이 성립하지 않더라고요.

그래서 Radio와 동일한 컴파운드 패턴을 유지하는 선에서는, 지금처럼 분기 로직을 두는 게 최선이라고 생각합니다. 컨텍스트 존재 여부로 우아하게 처리하려면 결국 Basic을 그룹용/단독용 별도 컴포넌트로 쪼개는 수밖에 없고, 안 쪼갤 거면 지금 방식을 유지할 수밖에 없어 보여요.


다만 만약 쪼갠다면 아래처럼 단독용과 그룹용 진입점을 나누는 형태가 될 것 같아요. 단독은 Checkbox가 직접 상태를 갖고, 그룹은 CheckboxGroup.Item이 그룹 상태를 받는 식이라 각 경로의 Basic이 자기 역할을 위치로 되물을 필요가 없어져요.

// 단독
<Checkbox.Root>
  <Checkbox.Label />
  <Checkbox.Helper />
</Checkbox.Root>
// 그룹
<CheckboxGroup.Root>
  <CheckboxGroup.Item>
    <CheckboxGroup.Label />
    <CheckboxGroup.Helper />
  </CheckboxGroup.Item>
  <CheckboxGroup.Item>
    <CheckboxGroup.Label />
    <CheckboxGroup.Helper />
  </CheckboxGroup.Item>
</CheckboxGroup.Root>

물론 이 방향은 Radio와 맞춰둔 현재 패턴을 벗어나는 거라, 이 PR 범위에서 당장 적용하기보다는 별도로 논의해보면 좋을 것 같아요.

Comment on lines +129 to +140
interface CheckboxBasicGroupedProps {
size: CheckboxSize;
value: string;
isDisabled: boolean;
isInvalid: boolean;
controlId: string;
interaction: "on" | "off";
state: CheckboxGroupState;
onChildCheckedChange?: (checked: CheckedState) => void;
forwardedRef: ForwardedRef<HTMLInputElement>;
restProps: InputHTMLAttributes<HTMLInputElement>;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Props를 선언하는 위치에 규칙이 있을까요? 기존에는 *.types.ts에 선언했던거 같아서요.

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.

외부에 공개되는 컴포넌트의 props만 checkbox.types.ts에서 관리하고, CheckboxControl, CheckboxBasicGrouped, CheckboxBasicStandalone처럼 export되지 않는 내부 헬퍼 컴포넌트의 props는 사용처 바로 위에 인라인으로 선언했습니다. (Radio, Card와 동일) 다만 문서화된 규칙은 아니라서 공통 컨벤션을 정해두어도 좋을 것 같아요

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2팀분들과 함께, JSDoc 수준 논의와 함께 공유되면 좋을 것 같아요.

itwillbeoptimal and others added 18 commits June 20, 2026 17:08
* refactor: Checkbox.Item을 단일 label로 전환해 아이템 전체 토글 통일

* feat: Checkbox.Helper를 aria-describedby로 input에 연결

* fix: CheckboxItemProps 기반 타입을 label로 수정

* fix: Checkbox.Helper를 span으로 변경
@itwillbeoptimal

itwillbeoptimal commented Jun 21, 2026

Copy link
Copy Markdown
Member Author

사용처(Dialog, Select)에서는 빌드가 통과하도록 최소한으로만 수정해 두었습니다

특히 Dialog는 현재 checkboxAction prop(label, checked, onCheckedChange)을 받아 내부에서 Checkbox를 렌더링하고 있는데, 이후 Dialog 마이그레이션 작업 하실 때 DialogCheckbox를 직접 알지 않도록 분리하는 방향도 같이 검토해 주시면 좋을 것 같아요 (c.c. @ccconac)

@itwillbeoptimal itwillbeoptimal merged commit 97d5bf9 into dev Jun 24, 2026
5 of 6 checks passed
@itwillbeoptimal itwillbeoptimal deleted the refactor/451-jds-checkbox-migration branch June 24, 2026 06:45
@github-project-automation github-project-automation Bot moved this from In Progress to Done in JECT Official WebSite Jun 24, 2026
itwillbeoptimal added a commit that referenced this pull request Jun 24, 2026
* chore: @react-aria/checkbox 패키지 의존성 추가

* feat: Checkbox vanilla-extract 마이그레이션 타입 정의

* feat: Checkbox Context 정의

* fix: Checkbox 타입 최신 DS 기준으로 업데이트

* feat: labelTypographyVars CSS vars 유틸리티 추가

* fix: CheckboxContext에서 align 속성 제거

* feat: CheckboxContext에 onChildCheckedChange 콜백 추가

* feat: Checkbox vanilla-extract 스타일 작성

* refactor: checkboxSizeMap을 checkbox.variants로 분리

* refactor: Checkbox prop/타입에서 컴포넌트명 prefix 제거

* fix: Checkbox visual disabled 상태에서 인터랙션 오버레이 제거

* feat: Checkbox vanilla-extract 마이그레이션 구현체 작성

* refactor: Checkbox 스타일 satisfies/어노테이션 표기 통일

* docs: Checkbox 마이그레이션 Storybook 문서 작성

* fix: 그룹 input 요소에 ref 연결

* fix: 그룹 내 Checkbox.Basic의 value 누락 검증 추가

* refactor: Checkbox 타이포그래피를 getLabelClassName으로 통일

* refactor: Checkbox 사이즈 맵을 단일 테이블로 통합

* fix: 체크 상태 타입명을 CheckedState로 복원

* docs: Checkbox 마이그레이션 changeset 추가

* docs: changeset 제목 수정

* refactor: focus ring 억제 로직을 globalStyle에서 variant로 전환

* fix: 라벨 색상을 labelColorVar 주입으로 변경해 cascade 순서 의존 제거

# Conflicts:
#	packages/jds/src/utils/typography.css.ts

* style: ::before/::after 동일 shape를 쉼표 셀렉터로 통합

* feat: Label 클릭 시 체크박스가 토글되도록 controlId 연결

* fix: Item 내부에서 Checkbox visual 오버레이 이중 적용 제거

* fix: Checkbox.Item 클릭 영역 불일치 및 구조 수정 (#471)

* refactor: Checkbox.Item을 단일 label로 전환해 아이템 전체 토글 통일

* feat: Checkbox.Helper를 aria-describedby로 input에 연결

* fix: CheckboxItemProps 기반 타입을 label로 수정

* fix: Checkbox.Helper를 span으로 변경

* refactor: checkbox.variants.ts 제거 및 사이즈맵을 소비처로 분리

* refactor: 클래스명을 역할에 맞게 변경

* refactor: 컨텍스트를 공통 설정과 Item 내부 상태 공유 용도로 분리

* refactor: parentContext를 parentConfig로 수정

* refactor: 마이그레이션 구현체 교체 및 소비처 정리
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

♻refactor 리팩토링

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

refactor: (JDS) Checkbox 컴포넌트 리팩토링

4 participants