✨ feat(input): 再利用 hooks の named export と triggerProps による ARIA フォワード (v1.0.3) - #272
Conversation
closes #263 closes #268 - ♻️ `useMergeRefs` と `useInputContainerFocus` を `src/hooks/` 配下に切り出し、 `sparkle-design/hooks` から named export - InputSearch などの派生コンポーネントから ref マージ / コンテナクリック→入力 フォーカスのロジックを直接利用できるようにする (#263) - 既存 Input の挙動は変えず、内部実装をこれらの hook に置き換えた(後方互換維持) - ✨ Input に `triggerProps?: ButtonHTMLAttributes<HTMLButtonElement>` を追加 - `isTrigger` 時にトリガー `<button>` へ `aria-haspopup` / `aria-expanded` / `aria-controls` などの HTML / ARIA 属性を宣言的にフォワード可能に (#268) - 既存の `triggerAriaLabel` / `onIconButtonClick` が優先される実装で後方互換を維持 - ✅ hooks の単体テストと Input の triggerProps フォワードテストを追加(全 606 unit test 通過) - 📦 `package.json` の `exports` に `./hooks` サブパスを追加 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
レビュー指摘 (#268) への対応: - `triggerProps` で渡しても無視される Input 内部制御属性(`ref` / `onFocus` / `onBlur` / `type` / `disabled` / `aria-label`、および見た目 props `icon` / `theme` / `variant` / `size`)を JSDoc に明記 - `onClick` は `onIconButtonClick` が未指定なら `triggerProps.onClick` に フォールバックする挙動も併記 - 現挙動を pin するテストを追加(`triggerProps.onFocus` / `onBlur` / `type` / `disabled` が Input 内部値で上書きされることを検証) 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)
🚧 Files skipped from review as they are similar to previous changes (2)
WalkthroughInput の内部 ref マージとコンテナクリック→フォーカス処理を外部 hook 化し、トリガーボタンへ任意の HTML/ARIA 属性を渡す ChangesInput Hook Extraction & triggerProps API
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 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.
Pull request overview
Input 内部の useMergeRefs とコンテナフォーカスロジックを src/hooks/ に切り出し sparkle-design/hooks から named export し(#263)、Input に triggerProps を追加してトリガーボタンへ ARIA / HTML 属性を宣言的にフォワードできるようにする(#268)。v1.0.3 リリース。
Changes:
src/hooks/配下にuseMergeRefs/useInputContainerFocusを切り出し、sparkle-design/hooksサブパスから export(テスト付き)InputにtriggerProps?: ButtonHTMLAttributes<HTMLButtonElement>を追加。triggerAriaLabel/onIconButtonClickを優先、ref/onFocus/onBlur/type/disabled等は内部制御を維持package.jsonを 1.0.3 に bump し./hooksexports を追加
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/hooks/useMergeRefs.ts | Input から抽出した汎用 ref マージ hook |
| src/hooks/useMergeRefs.test.tsx | RefObject / callback ref / undefined ケースのテスト |
| src/hooks/useInputContainerFocus.ts | コンテナクリック→ターゲット要素フォーカスを返す hook(excludeRefs 対応) |
| src/hooks/useInputContainerFocus.test.tsx | フォーカス遷移・除外・disabled の振る舞いをテスト |
| src/hooks/index.ts | hooks barrel export |
| src/index.ts | ルートからの ./hooks 再 export |
| src/components/ui/input/index.tsx | 内製ロジックを新 hooks に置換し、triggerProps を実装。precedence は JSDoc 明記 |
| src/components/ui/input/index.test.tsx | triggerProps フォワード / precedence / pin テスト 6 件追加 |
| package.json | version 1.0.3、exports."./hooks" 追加 |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@src/components/ui/input/index.test.tsx`:
- Around line 548-549: Tests call button.focus() and button.blur() directly
which bypasses the shared event utilities; replace direct DOM calls with the
EventHelpers wrapper by invoking EventHelpers.focus(button) and
EventHelpers.blur(button) in the test where button.focus()/button.blur() appear
so focus/blur flows go through the common EventHelpers path used for other
interactions.
In `@src/hooks/useInputContainerFocus.test.tsx`:
- Around line 28-33: The test markup uses a clickable div with
onClick={handleContainerClick} but lacks keyboard accessibility; update the
container element used in the test to include role="button", tabIndex={0}, and
an onKeyDown handler that calls the same handler (handleContainerClick) for
Enter and Space keys so keyboard users trigger the same behavior; ensure you
reference the same refs (inputRef, buttonRef) and keep the existing
onClick={handleContainerClick} intact so both mouse and keyboard interactions
are covered.
In `@src/hooks/useMergeRefs.ts`:
- Around line 26-32: Update the ref callback in useMergeRefs so its parameter
accepts null (change the arrow function argument from value: T to value: T |
null) and adjust the cast for object refs to React.MutableRefObject<T | null>;
ensure the callback signature matches React.RefCallback<T> and the line that
assigns to (ref as React.MutableRefObject<...>).current uses the T | null
variant.
🪄 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: c3cc3e95-6d39-4cde-a07a-60b934c68500
⛔ Files ignored due to path filters (1)
package.jsonis excluded by!**/*.json
📒 Files selected for processing (8)
src/components/ui/input/index.test.tsxsrc/components/ui/input/index.tsxsrc/hooks/index.tssrc/hooks/useInputContainerFocus.test.tsxsrc/hooks/useInputContainerFocus.tssrc/hooks/useMergeRefs.test.tsxsrc/hooks/useMergeRefs.tssrc/index.ts
| <div data-testid="container" onClick={handleContainerClick}> | ||
| <input ref={inputRef} data-testid="input" /> | ||
| <button ref={buttonRef} data-testid="button" type="button"> | ||
| btn | ||
| </button> | ||
| </div> |
There was a problem hiding this comment.
CI 失敗中: クリック可能な div にキーボード操作対応が不足しています。
Line 28 の div は onClick を持つのにキーボードハンドラがなく、提示されている lint エラーの原因になっています。role/tabIndex/onKeyDown を追加して解消してください。
💡 修正案
+ const handleContainerKeyDown = React.useCallback(
+ (e: React.KeyboardEvent<HTMLDivElement>) => {
+ if (e.key === "Enter" || e.key === " ") {
+ e.preventDefault();
+ inputRef.current?.focus();
+ }
+ },
+ []
+ );
+
return (
- <div data-testid="container" onClick={handleContainerClick}>
+ <div
+ data-testid="container"
+ onClick={handleContainerClick}
+ role="button"
+ tabIndex={0}
+ onKeyDown={handleContainerKeyDown}
+ >
<input ref={inputRef} data-testid="input" />
<button ref={buttonRef} data-testid="button" type="button">
btn
</button>
</div>
);As per coding guidelines **/*.{ts,tsx}: Use semantic HTML and ARIA labels for accessibility in React components.
🧰 Tools
🪛 GitHub Actions: CI / 0_lint-and-test.txt
[error] 28-28: ESLint (jsx-a11y): Visible, non-interactive elements with click handlers must have at least one keyboard listener. (jsx-a11y/click-events-have-key-events)
[error] 28-28: ESLint (jsx-a11y): Avoid non-native interactive elements. If using native HTML is not possible, add an appropriate role and support for tabbing, mouse, keyboard, and touch inputs to an interactive content element. (jsx-a11y/no-static-element-interactions)
🪛 GitHub Actions: CI / lint-and-test
[error] 28-28: next lint (ESLint) error: Visible, non-interactive elements with click handlers must have at least one keyboard listener. (jsx-a11y/click-events-have-key-events)
[error] 28-28: next lint (ESLint) error: Avoid non-native interactive elements. If using native HTML is not possible, add an appropriate role and support for tabbing, mouse, keyboard, and touch inputs. (jsx-a11y/no-static-element-interactions)
🤖 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 `@src/hooks/useInputContainerFocus.test.tsx` around lines 28 - 33, The test
markup uses a clickable div with onClick={handleContainerClick} but lacks
keyboard accessibility; update the container element used in the test to include
role="button", tabIndex={0}, and an onKeyDown handler that calls the same
handler (handleContainerClick) for Enter and Space keys so keyboard users
trigger the same behavior; ensure you reference the same refs (inputRef,
buttonRef) and keep the existing onClick={handleContainerClick} intact so both
mouse and keyboard interactions are covered.
- テストハーネスの div に Input 本体と同じ role="presentation" + tabIndex={-1}
を付与し、jsx-a11y/click-events-have-key-events と
jsx-a11y/no-static-element-interactions の lint エラーを解消
- 挙動・テスト結果は変わらず(3 件 pass)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- useMergeRefs: 引数を React.RefCallback<T> シグネチャに正確に合わせて
`T | null` を受け取れるよう修正。MutableRefObject 型も `T | null` に。
- Input テスト: `button.focus()` / `button.blur()` を直接呼んでいたものを
プロジェクト共通の `EventHelpers.focus` / `EventHelpers.blur` 経由に統一。
- useInputContainerFocus テストハーネスは Input 本体と同じ
`role="presentation"` + `tabIndex={-1}` パターンを維持(実利用と整合)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
useMergeRefsとuseInputContainerFocusをsrc/hooks/配下に切り出し、sparkle-design/hooksから named export。InputSearch等の派生コンポーネントから直接利用できるようになる。InputにtriggerProps?: ButtonHTMLAttributes<HTMLButtonElement>を追加。isTrigger時にトリガー<button>へaria-haspopup/aria-expanded/aria-controls等を宣言的にフォワード可能。後付けquerySelector+setAttributeが不要に。triggerAriaLabel/onIconButtonClickを含む全 props はそのまま動作。triggerPropsは optional。Input内部実装を新しい hooks 経由に置き換えたが挙動は同一。変更点
新しい public hooks (
sparkle-design/hooksから import)useMergeRefs(...refs)— 複数の ref を 1 つの ref callback にまとめるuseInputContainerFocus({ targetRef, isDisabled?, excludeRefs? })— コンテナクリック時に内側の input にフォーカスを移すクリックハンドラを返す。excludeRefsで除外要素を指定可能Input.triggerProps
優先順位は JSDoc に明記:
triggerAriaLabel>triggerProps["aria-label"]onIconButtonClick>triggerProps.onClicktriggerPropsで渡しても無視される:ref/onFocus/onBlur/type/disabled/icon/theme/variant/size(pin テスト済み)package.json
version: 1.0.2 → 1.0.3exports."./hooks"を追加Test plan
pnpm test— 全 607 unit test pass(hooks 6 件 + Input triggerProps forwarding 6 件を新規追加)tsc --noEmit— 型エラーなしnext lint— エラーなし(ローカル worktree でのプラグイン衝突警告は環境要因)prettier --check— cleanリリース手順
マージ後:
gh workflow run "Publish to GitHub Packages"を実行v1.0.3タグの作成(ワークフローが行う/手動)🤖 Generated with Claude Code