Skip to content

Commit 4a508c3

Browse files
committed
feat: PartDetailModalにキーボードサポートを追加
- ESCキーでモーダルを閉じる機能を追加 - Enterキーでモーダルを閉じる機能を追加(フォーカス可能な要素がない場合) - モーダル開閉時の適切なフォーカス管理を実装 - ユーザビリティとアクセシビリティの向上 Closes #8
1 parent 4704bd6 commit 4a508c3

File tree

1 file changed

+39
-2
lines changed

1 file changed

+39
-2
lines changed

src/components/PartDetailModal.tsx

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { useEffect, useRef } from 'react';
22
import { PartWithInventory, Category } from '../types';
33
import { X, ExternalLink } from 'lucide-react';
44
import { getCategoryName } from '../utils/categoryUtils';
@@ -16,6 +16,39 @@ export const PartDetailModal: React.FC<PartDetailModalProps> = ({
1616
onClose,
1717
categories
1818
}) => {
19+
const modalRef = useRef<HTMLDivElement>(null);
20+
21+
// キーボードイベントハンドラー
22+
useEffect(() => {
23+
if (!isOpen) return;
24+
25+
const handleKeyDown = (event: KeyboardEvent) => {
26+
if (event.key === 'Escape') {
27+
onClose();
28+
} else if (event.key === 'Enter') {
29+
// フォーカス可能な要素がない場合、Enterキーでも閉じる
30+
const focusableElements = modalRef.current?.querySelectorAll(
31+
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
32+
);
33+
if (!focusableElements || focusableElements.length === 0 ||
34+
!Array.from(focusableElements).some(el => el === document.activeElement)) {
35+
onClose();
36+
}
37+
}
38+
};
39+
40+
document.addEventListener('keydown', handleKeyDown);
41+
42+
// モーダル要素にフォーカスを設定
43+
if (modalRef.current) {
44+
modalRef.current.focus();
45+
}
46+
47+
return () => {
48+
document.removeEventListener('keydown', handleKeyDown);
49+
};
50+
}, [isOpen, onClose]);
51+
1952
if (!isOpen || !part) return null;
2053

2154
// カテゴリIDからカテゴリ名を取得
@@ -54,7 +87,11 @@ export const PartDetailModal: React.FC<PartDetailModalProps> = ({
5487

5588
return (
5689
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
57-
<div className="bg-white rounded-lg max-w-2xl w-full max-h-[90vh] overflow-y-auto">
90+
<div
91+
ref={modalRef}
92+
tabIndex={-1}
93+
className="bg-white rounded-lg max-w-2xl w-full max-h-[90vh] overflow-y-auto outline-none"
94+
>
5895
<div className="flex items-center justify-between p-6 border-b">
5996
<h2 className="text-xl font-semibold text-gray-900">パーツ詳細情報</h2>
6097
<button

0 commit comments

Comments
 (0)