Skip to content

[FEAT] Dropdown 컴포넌트 구현 #78

Open
ehye1 wants to merge 3 commits into
developfrom
feat/ui/74-dropdown-component
Open

[FEAT] Dropdown 컴포넌트 구현 #78
ehye1 wants to merge 3 commits into
developfrom
feat/ui/74-dropdown-component

Conversation

@ehye1

@ehye1 ehye1 commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

ISSUE 🔗

close #74



What is this PR? 🔍

피그마 dropdown_view 스펙에 맞춰 Dropdown 컴포넌트를 구현했습니다.

  • Portal 방식 → 인라인 column 레이아웃으로 변경 (피그마 구조와 동일)
  • 트리거: h-8, px-2, rounded-[4px], typo-headline-m-14
  • 아이콘: 16×8 chevron SVG, open/close 시 경로 즉시 교체 (애니메이션 없음)
  • 리스트: 트리거 하단 인라인 연결, border-x border-b, 아이템 사이 divider
  • open 시 컨테이너 전체에 shadow-timo 적용
  • 외부 클릭 / Escape 키로 닫힘 처리
  • --shadow-timo 토큰 tailwind-config/theme.css에 추가

코드래빗 반영

  • openisOpen 네이밍 컨벤션 수정
  • Escape/외부 클릭 후 트리거 버튼으로 포커스 복귀



To Reviewers



Screenshot 📷

image



Test Checklist ✔

  • 드롭다운 클릭 시 리스트 열림/닫힘 확인
  • 항목 선택 시 트리거 텍스트 업데이트 확인
  • 외부 클릭 / Escape 키로 닫힘 확인
  • Storybook에서 Components/Dropdown 렌더링 확인

ehye1 and others added 2 commits July 2, 2026 16:32
드롭다운 open 상태 그림자용 --shadow-timo CSS 변수를 추가했습니다.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
피그마 디자인 스펙에 맞춰 Dropdown 컴포넌트를 구현했습니다.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 2, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
timo Ready Ready Preview, Comment Jul 2, 2026 8:00am

@github-actions github-actions Bot added the ⌚ Timo-Design-system Timo 디자인 시스템 label Jul 2, 2026
@github-actions github-actions Bot added the ♥️ 혜원 혜원양 label Jul 2, 2026
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Dropdown 공통 컴포넌트와 Storybook 예시가 추가되었고, 컴포넌트 진입점에서 재export됩니다. Tailwind 테마에는 새 그림자 토큰이 정의되고 import 순서가 조정되었습니다.

Changes

Dropdown 컴포넌트 및 테마 토큰

Layer / File(s) Summary
테마 토큰 추가
packages/tailwind-config/theme.css
@import "./scrollbar.css"; 위치가 재배치되고 @theme 블록에 --shadow-timo 변수가 추가됩니다.
Dropdown 컴포넌트 구현
packages/timo-design-system/src/components/dropdown/Dropdown.tsx
DropdownProps와 열림 상태, 외부 클릭/Escape 처리, 접근 가능한 목록 렌더링과 선택 동작이 추가됩니다.
Storybook 스토리 및 export 등록
packages/timo-design-system/src/components/dropdown/Dropdown.stories.tsx, packages/timo-design-system/src/components/index.ts
Default 스토리가 useState로 상태를 관리하며 Dropdown을 렌더링하고, index.ts에서 Dropdown이 재export됩니다.

Estimated code review effort: 2 (Simple) | ~12 minutes

Possibly related PRs

Suggested reviewers: kimminna, yumin-kim2

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning #74의 Controlled 입력과 Storybook, re-export는 반영됐지만 Portal 기반 backdrop 오버레이와 반응형 요구는 충족되지 않았습니다. Portal backdrop 오버레이와 화면 어두워짐, 반응형 처리를 추가하고 외부 클릭 닫힘을 backdrop 기준으로 맞춰주세요.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Dropdown 컴포넌트 구현이라는 핵심 변경을 잘 드러내고 있습니다.
Out of Scope Changes check ✅ Passed story, re-export, shadow 토큰 추가는 Dropdown 구현 범위와 직접 연결되어 보이며 뚜렷한 불필요 변경은 없습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed 드롭다운 컴포넌트 구현과 theme 토큰 추가 등 변경 내용이 PR 설명과 일치합니다.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ui/74-dropdown-component

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

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

Storybook Preview

항목 링크
Storybook 열기
Chromatic 빌드 확인

마지막 업데이트: 2026-07-02 08:00 UTC

@ehye1 ehye1 changed the title feat(design-system): Dropdown 컴포넌트 구현 (#74) [FEAT] Dropdown 컴포넌트 구현 Jul 2, 2026
@github-actions github-actions Bot added the ✨ Feature 새로운 기능(기능성) 구현 label Jul 2, 2026
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

Timo Performance Report

Bundle Size — timo-web
라우트 크기 First Load JS
/ 0 B 🟡 205.49 kB
/focus 0 B 🟡 205.49 kB
/home 0 B 🟡 205.49 kB
/login 0 B 🟡 205.49 kB
/onboarding 0 B 🟡 205.49 kB
/settings 0 B 🟡 205.49 kB
/settings/account 0 B 🟡 205.49 kB
/settings/policy 0 B 🟡 205.49 kB
/statistics 0 B 🟡 205.49 kB
/today 0 B 🟡 205.49 kB

공유 번들: 205.49 kB
🟢 < 200kB  |  🟡 < 350kB  |  🔴 ≥ 350kB (First Load JS · gzip)

Lighthouse — timo-web

⚠️ Lighthouse 결과를 가져오지 못했습니다.

Image Optimization — timo-web

public/ 디렉토리에 이미지가 없습니다.

측정 커밋: 166d76e

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

🤖 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/tailwind-config/theme.css`:
- Around line 6-8: Tailwind v4 token CSS in theme.css is being flagged by
Biome/Stylelint because the parser/plugin config is still treating `@theme` as
invalid. Update the lint/config setup used for packages/tailwind-config so it
recognizes Tailwind v4 `@theme` syntax, matching the other token CSS files in this
package. Check the Biome and Stylelint configuration entries that parse
CSS/Tailwind directives, and align them with tailwindcss@^4.3.1 rather than
changing the `@theme` block itself.

In `@packages/timo-design-system/src/components/dropdown/Dropdown.stories.tsx`:
- Around line 16-24: Default story state is hardcoded in DefaultStory, so the
Storybook args for Dropdown are ignored and Controls do not reflect the rendered
UI. Update Default and DefaultStory so the rendered dropdown is driven by args
from the Storybook story, using DropdownProps and the existing Dropdown
component props (items, value, onChange) instead of fixed ["기본", "7일"] values,
keeping args and render in sync.

In `@packages/timo-design-system/src/components/dropdown/Dropdown.tsx`:
- Around line 87-112: The Dropdown listbox currently makes every option
tabbable, which breaks the expected WAI-ARIA listbox keyboard pattern. Update
Dropdown.tsx so only a single element participates in tab order (the trigger or
listbox container), and move option focus management to roving tabindex or
aria-activedescendant within the listbox. Keep the option rendering in the
items.map block, but change the interaction logic in the option handling so
arrow keys navigate between items and Enter/Space selects the active item.
- Line 19: Rename the boolean state in Dropdown.tsx from open to isOpen and
update the setter to setIsOpen so it follows the boolean naming convention. Make
sure every reference in the Dropdown component that uses open or setOpen is
updated consistently, including any JSX conditions or event handlers tied to the
state.
- Around line 27-46: The Dropdown close handling in the open-state effect does
not restore focus to the trigger button, so keyboard users can lose focus after
Escape or outside click. Update the Dropdown component to keep a trigger button
ref (for the trigger <button> and any related handler logic), and in both the
Escape key path and the outside-click path call triggerRef.current?.focus()
immediately after setOpen(false). Use the existing useEffect, handleKeyDown, and
handleClickOutside logic in Dropdown.tsx to place the focus restore
consistently.
- Around line 92-93: `Dropdown`의 리스트 key가 `key={item}`이라 중복 문자열이 들어오면 충돌할 수
있습니다. `items.map`에서 렌더링하는 `li`의 key를 문자열 값 대신 고유하게 만들도록 수정하세요: 가능하면
`DropdownProps.items`를 `{ id, label }` 형태로 바꾸고 `Dropdown` 컴포넌트에서 `id`를 key로
사용하며, 구조 변경이 어렵다면 최소한 `item`과 `i`를 조합한 key로 방어적으로 처리하세요.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b0806be5-1ee4-483b-98a6-aee28433358b

📥 Commits

Reviewing files that changed from the base of the PR and between 293536e and 762c92f.

📒 Files selected for processing (4)
  • packages/tailwind-config/theme.css
  • packages/timo-design-system/src/components/dropdown/Dropdown.stories.tsx
  • packages/timo-design-system/src/components/dropdown/Dropdown.tsx
  • packages/timo-design-system/src/components/index.ts

Comment on lines +6 to +8
@theme {
--shadow-timo: 0px 0px 3px 0px rgba(0, 0, 0, 0.12);
} No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Tailwind 버전 확인 및 다른 tokens 파일의 `@theme` 사용 여부 확인
fd package.json --exec grep -l '"tailwindcss"' {} \;
fd . packages/tailwind-config -e css --exec grep -n "`@theme`\|`@tailwind`\|`@import`" {} \;

Repository: Team-Timo/Timo-client

Length of output: 418


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== package.json files =="
sed -n '1,220p' packages/tailwind-config/package.json
echo
sed -n '1,220p' packages/timo-design-system/package.json
echo

echo "== tailwind-config css files =="
for f in packages/tailwind-config/*.css packages/tailwind-config/tokens/*.css; do
  [ -f "$f" ] || continue
  echo "--- $f ---"
  nl -ba "$f" | sed -n '1,220p'
  echo
done

Repository: Team-Timo/Timo-client

Length of output: 2160


Biome/Stylelint 설정을 Tailwind v4 기준으로 맞춰주세요.
이 저장소는 tailwindcss@^4.3.1를 사용하고, packages/tailwind-config의 다른 token CSS들도 모두 @theme 문법을 씁니다. 따라서 경고는 코드보다는 파서/플러그인 설정 문제일 가능성이 큽니다.
Tailwind v4 @theme 문서: https://tailwindcss.com/docs/theme

🧰 Tools
🪛 Biome (2.5.1)

[error] 6-8: Tailwind-specific syntax is disabled.

(parse)

🪛 Stylelint (17.14.0)

[error] 6-6: Unexpected unknown at-rule "@theme" (scss/at-rule-no-unknown)

(scss/at-rule-no-unknown)

🤖 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/tailwind-config/theme.css` around lines 6 - 8, Tailwind v4 token CSS
in theme.css is being flagged by Biome/Stylelint because the parser/plugin
config is still treating `@theme` as invalid. Update the lint/config setup used
for packages/tailwind-config so it recognizes Tailwind v4 `@theme` syntax,
matching the other token CSS files in this package. Check the Biome and
Stylelint configuration entries that parse CSS/Tailwind directives, and align
them with tailwindcss@^4.3.1 rather than changing the `@theme` block itself.

Source: Linters/SAST tools

Comment thread packages/timo-design-system/src/components/dropdown/Dropdown.tsx Outdated
Comment thread packages/timo-design-system/src/components/dropdown/Dropdown.tsx Outdated
Comment thread packages/timo-design-system/src/components/dropdown/Dropdown.tsx Outdated
Comment on lines +92 to +93
{items.map((item, i) => (
<li key={item} className="flex flex-col gap-1">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

key={item}은 중복 항목이 있으면 충돌합니다.

itemsstring[]이라 값이 중복되면(예: ["기본", "기본"]) React key가 중복되어 리스트 렌더링이 꼬일 수 있습니다. 현재는 고유 id가 없는 문자열 배열이므로, 상위에서 { id, label } 형태로 넘기거나 최소한 key={${item}-${i}}로 방어하는 게 안전합니다.

As per path instructions, "동적 리스트의 key prop: 반드시 고유 id 사용 (index 금지)" — 현재 문자열 자체를 key로 쓰고 있어 고유성이 보장되지 않습니다.

🔑 제안 diff (임시 방어)
-          {items.map((item, i) => (
-            <li key={item} className="flex flex-col gap-1">
+          {items.map((item, i) => (
+            <li key={`${item}-${i}`} className="flex flex-col gap-1">

근본적으로는 DropdownProps.items{ id: string; label: string }[]로 바꾸는 것을 권장합니다.

📝 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
{items.map((item, i) => (
<li key={item} className="flex flex-col gap-1">
{items.map((item, i) => (
<li key={`${item}-${i}`} className="flex flex-col gap-1">
🤖 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/timo-design-system/src/components/dropdown/Dropdown.tsx` around
lines 92 - 93, `Dropdown`의 리스트 key가 `key={item}`이라 중복 문자열이 들어오면 충돌할 수 있습니다.
`items.map`에서 렌더링하는 `li`의 key를 문자열 값 대신 고유하게 만들도록 수정하세요: 가능하면
`DropdownProps.items`를 `{ id, label }` 형태로 바꾸고 `Dropdown` 컴포넌트에서 `id`를 key로
사용하며, 구조 변경이 어렵다면 최소한 `item`과 `i`를 조합한 key로 방어적으로 처리하세요.

Source: Path instructions

open을 isOpen으로 변경하고 닫힐 때 트리거 버튼으로 포커스를 복귀했습니다.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

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

♻️ Duplicate comments (2)
packages/timo-design-system/src/components/dropdown/Dropdown.tsx (2)

99-100: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

key={item}은 여전히 중복 항목에 취약합니다.

이전 리뷰에서 동일하게 지적된 이슈가 아직 반영되지 않았습니다. itemsstring[]이라 중복 값이 있으면 React key 충돌이 발생할 수 있습니다.

As per path instructions, "동적 리스트의 key prop: 반드시 고유 id 사용 (index 금지)".

🔑 제안 diff (임시 방어)
-          {items.map((item, i) => (
-            <li key={item} className="flex flex-col gap-1">
+          {items.map((item, i) => (
+            <li key={`${item}-${i}`} className="flex flex-col gap-1">
🤖 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/timo-design-system/src/components/dropdown/Dropdown.tsx` around
lines 99 - 100, The Dropdown item list still uses a non-unique React key, so
duplicate string values in items can collide. Update the items.map render in
Dropdown to use a truly unique stable identifier for each item instead of
key={item}; if the list only has strings, derive or pass a unique id alongside
each item rather than relying on the label value or index. Make sure the change
is applied in the Dropdown component’s list rendering.

Source: Path instructions


99-116: 🩺 Stability & Availability | 🔵 Trivial | ⚖️ Poor tradeoff

Listbox 키보드 탐색(roving tabindex/aria-activedescendant) 여전히 미반영.

모든 옵션에 tabIndex={0}을 부여하는 구조가 그대로 유지되어 있습니다. 이전 리뷰에서 지적된 대로 WAI-ARIA Listbox 패턴은 단일 탭스톱 + 방향키 탐색을 권장합니다. 지금 당장 필수는 아니지만 디자인 시스템 컴포넌트인 만큼 추후 개선을 검토해주세요.

참고: WAI-ARIA APG Listbox Pattern

🤖 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/timo-design-system/src/components/dropdown/Dropdown.tsx` around
lines 99 - 116, The Dropdown listbox still uses a tabbable span for every
option, so the WAI-ARIA listbox keyboard pattern is not implemented. Update
Dropdown’s option rendering in the items.map block to use a single tab stop on
the listbox container and manage focus with roving tabindex or
aria-activedescendant, while keeping handleSelect and the existing option
selection behavior intact. Ensure the component’s keyboard handling supports
arrow-key navigation through options instead of leaving tabIndex={0} on each
item.
🤖 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/timo-design-system/src/components/dropdown/Dropdown.tsx`:
- Around line 38-45: The outside-click handler in Dropdown is forcing focus back
to the trigger via closeWithFocus(), which can override the user’s intended
focus target. Update handleClickOutside in Dropdown.tsx so outside mouse clicks
only close the menu without restoring focus, and reserve trigger focus
restoration for Escape-driven closes or other explicit keyboard-dismiss paths.
Keep the logic localized around handleClickOutside and closeWithFocus so the
dropdown still closes correctly while preserving browser-default focus movement.
- Around line 23-26: `handleSelect` in `Dropdown` closes the menu without
restoring focus, so keyboard users lose their place after choosing an option.
Update the selection flow to use `closeWithFocus()` instead of only
`setIsOpen(false)`, and make sure `closeWithFocus` is declared before
`handleSelect` so it can be called there. Keep `onChange(item)` in the same
selection path, but ensure focus returns to the trigger after the dropdown
closes.

---

Duplicate comments:
In `@packages/timo-design-system/src/components/dropdown/Dropdown.tsx`:
- Around line 99-100: The Dropdown item list still uses a non-unique React key,
so duplicate string values in items can collide. Update the items.map render in
Dropdown to use a truly unique stable identifier for each item instead of
key={item}; if the list only has strings, derive or pass a unique id alongside
each item rather than relying on the label value or index. Make sure the change
is applied in the Dropdown component’s list rendering.
- Around line 99-116: The Dropdown listbox still uses a tabbable span for every
option, so the WAI-ARIA listbox keyboard pattern is not implemented. Update
Dropdown’s option rendering in the items.map block to use a single tab stop on
the listbox container and manage focus with roving tabindex or
aria-activedescendant, while keeping handleSelect and the existing option
selection behavior intact. Ensure the component’s keyboard handling supports
arrow-key navigation through options instead of leaving tabIndex={0} on each
item.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 30063e32-39ad-4fda-bc46-e8acd2b2a7cf

📥 Commits

Reviewing files that changed from the base of the PR and between 762c92f and db3ca56.

📒 Files selected for processing (1)
  • packages/timo-design-system/src/components/dropdown/Dropdown.tsx

Comment on lines +23 to +26
const handleSelect = (item: string) => {
onChange(item);
setIsOpen(false);
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

옵션 선택 후 포커스가 돌아오지 않아요.

Escape/외부 클릭 시에는 closeWithFocus()로 트리거에 포커스를 복원하지만, handleSelectsetIsOpen(false)만 호출합니다. 옵션(span[role="option"])에 있던 포커스가 리스트 언마운트와 함께 사라져 키보드 사용자는 포커스를 잃게 됩니다. 접근성 가이드에서도 선택 후 트리거로 포커스를 복귀시키도록 권장합니다.

🎯 제안 diff
   const handleSelect = (item: string) => {
     onChange(item);
-    setIsOpen(false);
+    closeWithFocus();
   };

(단, closeWithFocushandleSelect 아래에 정의되어 있으므로 함수 선언 순서 조정 필요 — closeWithFocushandleSelect보다 먼저 선언하세요.)

관련 문서: Accessible Combobox Pattern: ARIA + Keyboard Guide

🤖 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/timo-design-system/src/components/dropdown/Dropdown.tsx` around
lines 23 - 26, `handleSelect` in `Dropdown` closes the menu without restoring
focus, so keyboard users lose their place after choosing an option. Update the
selection flow to use `closeWithFocus()` instead of only `setIsOpen(false)`, and
make sure `closeWithFocus` is declared before `handleSelect` so it can be called
there. Keep `onChange(item)` in the same selection path, but ensure focus
returns to the trigger after the dropdown closes.

Comment on lines +38 to +45
const handleClickOutside = (e: MouseEvent) => {
if (
containerRef.current &&
!containerRef.current.contains(e.target as Node)
) {
closeWithFocus();
}
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

외부 클릭 시 강제 포커스 복귀가 오히려 사용자 의도를 방해할 수 있어요.

mousedown이 컨테이너 밖에서 발생하면 무조건 closeWithFocus()를 호출해 트리거로 포커스를 되돌립니다. 하지만 사용자가 다른 포커스 가능한 요소(예: 다음 입력창, 다른 버튼)를 클릭해 드롭다운을 닫으려 한 경우에도 포커스가 트리거로 강제 이동해, 사용자가 클릭한 대상으로 포커스가 이동하지 못할 수 있습니다. Escape로 닫을 때만 트리거로 포커스를 복귀시키고, 외부 클릭 시에는 브라우저 기본 포커스 이동에 맡기는 편이 자연스러운 흐름입니다.

💡 제안 diff
     const handleClickOutside = (e: MouseEvent) => {
       if (
         containerRef.current &&
         !containerRef.current.contains(e.target as Node)
       ) {
-        closeWithFocus();
+        setIsOpen(false);
       }
     };
📝 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
const handleClickOutside = (e: MouseEvent) => {
if (
containerRef.current &&
!containerRef.current.contains(e.target as Node)
) {
closeWithFocus();
}
};
const handleClickOutside = (e: MouseEvent) => {
if (
containerRef.current &&
!containerRef.current.contains(e.target as Node)
) {
setIsOpen(false);
}
};
🤖 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/timo-design-system/src/components/dropdown/Dropdown.tsx` around
lines 38 - 45, The outside-click handler in Dropdown is forcing focus back to
the trigger via closeWithFocus(), which can override the user’s intended focus
target. Update handleClickOutside in Dropdown.tsx so outside mouse clicks only
close the menu without restoring focus, and reserve trigger focus restoration
for Escape-driven closes or other explicit keyboard-dismiss paths. Keep the
logic localized around handleClickOutside and closeWithFocus so the dropdown
still closes correctly while preserving browser-default focus movement.

@@ -0,0 +1,24 @@
import { useState } from "react";

import { Dropdown } from "./Dropdown";

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.

요거 절대 경로로 통일해 줍시당

className?: string;
}

export const Dropdown = ({

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.

제가 작성해 둔 이전 PR을 구현해 놓고 보니 해당 뷰 드롭다운 컴포넌트도 컴파운드 패턴 적용해서 구현해 볼 수 있을 것 같네요!
해당 PR 머지하고, 뷰 전용 드롭다운으로 네이밍 교체해서 구현해 보면 좋을 것 같아요.

구현해 주신 선택 시 자동 닫힘 & 닫힌 후 트리거로 포커스 복귀 기능은 컴파운드 패턴 전용 컴포넌트에 제가 구현해 놓겠습니다!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

그렇네요 너무 좋습니다🫰🏻💍 폴더도 그에 맞춰 수정하겠습니다!

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

Labels

✨ Feature 새로운 기능(기능성) 구현 ⌚ Timo-Design-system Timo 디자인 시스템 ♥️ 혜원 혜원양

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] Dropdown 컴포넌트 구현

2 participants