♻️ refactor: Button を React.forwardRef 対応にする (#270)#275
Conversation
PopoverTrigger 等で `asChild` 合成する際に Button へ直接 ref を渡せるよう、 `React.forwardRef<HTMLButtonElement, ButtonProps>` でラップする。 - 既存の関数本体ロジックには変更なし - ref を内部の `<Comp>` 要素に渡す - React 18 ランタイム互換のため、ref-as-prop ではなく forwardRef を採用 ref: sparkle-design-internal#182(PopoverTriggerButton workaround の削除につながる) closes #270 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
ウォークスルーButton を通常の関数定義から React.forwardRef でラップした関数式に置き換え、ref 引数を受け取り内部の Comp 要素へキャストして渡すよう変更しました。ref 転送の挙動を検証するテストが追加されています。 変更内容Button の forwardRef 対応
推定レビュー所要時間🎯 3 (Moderate) | ⏱️ ~20 minutes ポエム
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e9d14d14ba
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| children, | ||
| ...props | ||
| }: ButtonProps) { | ||
| const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(function Button( |
There was a problem hiding this comment.
When asChild slots a non-button element such as the documented Link/anchor pattern, this forwardRef<HTMLButtonElement, ...> signature exposes only Ref<HTMLButtonElement>. A consumer using the new direct-ref API as <Button asChild ref={anchorRef}><a ... /></Button> (or an integration whose trigger ref is typed as HTMLElement/HTMLAnchorElement) is rejected by TypeScript even though Slot forwards the ref at runtime. Please make the ref typing compatible with slotted elements instead of hard-coding it to HTMLButtonElement.
Useful? React with 👍 / 👎.
| const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(function Button( | ||
| { | ||
| className, | ||
| variant, | ||
| size, | ||
| theme, | ||
| isLoading = false, | ||
| isDisabled = false, | ||
| asChild = false, | ||
| disabled, | ||
| prefixIcon, | ||
| suffixIcon, | ||
| children, | ||
| ...props | ||
| }, | ||
| ref | ||
| ) { |
レビュー指摘(PR #275)への対応: - `forwardRef<HTMLButtonElement, ButtonProps>` だと `asChild` で <a> 等の 非 button 要素を渡した際に ref 型が実体と不整合になり TypeScript で弾かれる問題があった - 公開 API としての ref 型を `HTMLElement` に広げ、Link/anchor 等の slot 先にも対応 - 内部 `<Comp>` の union 型整合のため、ref を `HTMLButtonElement` に narrow する キャストを 1 箇所追加(実行時は Slot が ref を適切に転送するので問題なし) 加えて Ref Forwarding describe ブロックを追加: - 通常の <button> への ref forwarding - `asChild` + <a> への ref forwarding(Slot 経由) refs: PR #275 review (Codex, Copilot) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@chatgpt-codex-connector @copilot レビューありがとうございます。指摘いただいた commit 33c4db9 で以下を修正しました:
vitest 41 件 pass(うち新規 ref forwarding 2 件)、 |
|
対応内容を確認しました。現在のローカルブランチはすでに そのため今回は 新規コード変更・追加コミット・ 確認コマンド
|
Summary
ButtonをReact.forwardRefでラップし、外からrefを直接渡せるようにする (closes ♻️ refactor: Button を React.forwardRef 対応にしてほしい(PopoverTrigger 等で asChild 合成するため) #270)sparkle-design-internalのPopoverTriggerButtonworkaround(Button asChild+PopoverPrimitive.Trigger)が不要になるforwardRefを採用なぜ forwardRef なのか
issue #270 のコメントで「React 19 流の ref-as-prop が望ましい」と提案されていますが、ref-as-prop は React 19 ランタイム機能 で、React 18 では
refprop が剥がされて機能しません。sparkle-design の peerDep は^18 || ^19の両対応のため、現状の互換性を保ちつつ issue 解決を優先しました。React 19 への完全移行(ref-as-prop 化)は別 PR #274 で全コンポーネント一括で進める想定です。そちらは breaking change として塩漬けし、モーション系等の他の大規模アップデートとまとめてリリースする方針です。
変更点
src/components/ui/button/index.tsxのみ:function Button({...}: ButtonProps)をReact.forwardRef<HTMLButtonElement, ButtonProps>(function Button({...}, ref))でラップ<Comp>要素にref={ref}を渡すasChild分岐、disabled ハンドリング、a11y warning など)には一切変更なしTest plan
PopoverTriggerButtonworkaround を削除して問題なく動作することを確認関連
🤖 Generated with Claude Code