1
- import React from 'react' ;
1
+ import React , { useEffect , useRef } from 'react' ;
2
2
import { PartWithInventory , Category } from '../types' ;
3
3
import { X , ExternalLink } from 'lucide-react' ;
4
4
import { getCategoryName } from '../utils/categoryUtils' ;
@@ -16,6 +16,39 @@ export const PartDetailModal: React.FC<PartDetailModalProps> = ({
16
16
onClose,
17
17
categories
18
18
} ) => {
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
+
19
52
if ( ! isOpen || ! part ) return null ;
20
53
21
54
// カテゴリIDからカテゴリ名を取得
@@ -54,7 +87,11 @@ export const PartDetailModal: React.FC<PartDetailModalProps> = ({
54
87
55
88
return (
56
89
< 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
+ >
58
95
< div className = "flex items-center justify-between p-6 border-b" >
59
96
< h2 className = "text-xl font-semibold text-gray-900" > パーツ詳細情報</ h2 >
60
97
< button
0 commit comments