Skip to content

Commit 361b398

Browse files
authored
Merge pull request #24 from bryandino673/modal-cart-dismissal-interaction
Implement Esc key interaction for modal/cart dismissal
2 parents 87ea5e1 + 34e9ad3 commit 361b398

2 files changed

Lines changed: 51 additions & 10 deletions

File tree

src/components/bucket-modal.tsx

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,47 @@
33
import { useStore } from '@/lib/store';
44
import { X, Trash2, Package } from 'lucide-react';
55
import { VersionNote } from './version-note';
6+
import { useEffect, useRef } from 'react';
67

78
interface BucketModalProps {
89
onClose: () => void;
910
}
1011

1112
export function BucketModal({ onClose }: BucketModalProps) {
1213
const { bucket, removeFromBucket, clearBucket, setCurrentStep, updatePackageNote } = useStore();
14+
const modalRef = useRef<HTMLDivElement>(null);
1315

1416
const handleGenerateScript = () => {
1517
onClose();
1618
setCurrentStep('output');
1719
};
1820

21+
useEffect(() => {
22+
const handleKey = (e: KeyboardEvent) => {
23+
if (e.key === 'Escape') onClose();
24+
};
25+
26+
const handleClickOutside = (e: MouseEvent) => {
27+
if (modalRef.current && !modalRef.current.contains(e.target as Node)) {
28+
onClose();
29+
}
30+
};
31+
32+
window.addEventListener('keydown', handleKey);
33+
document.addEventListener('mousedown', handleClickOutside);
34+
35+
return () => {
36+
window.removeEventListener('keydown', handleKey);
37+
document.removeEventListener('mousedown', handleClickOutside);
38+
};
39+
}, [onClose]);
40+
1941
return (
2042
<>
21-
{/* Backdrop */}
22-
<div
23-
className="fixed inset-0 z-40"
24-
onClick={onClose}
25-
/>
26-
2743
{/* Modal */}
28-
<div className="absolute right-0 top-full mt-2 w-88 max-h-[520px]
44+
<div
45+
ref={modalRef}
46+
className="absolute right-0 top-full mt-2 w-88 max-h-[520px]
2947
terminal-card rounded-lg shadow-2xl z-50 border border-border flex flex-col"
3048
style={{ width: '22rem' }}>
3149
{/* Header */}

src/components/presets-modal.tsx

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useStore } from '@/lib/store';
44
import { presets } from '@/lib/presets';
55
import { appCatalog } from '@/lib/apps';
66
import { X, Clock, Layers, Check } from 'lucide-react';
7-
import { useState } from 'react';
7+
import { useState, useEffect, useRef } from 'react';
88
import { estimateInstallTime } from '@/lib/script-generator';
99
import { Package } from '@/types';
1010

@@ -15,6 +15,27 @@ interface PresetsModalProps {
1515
export function PresetsModal({ onClose }: PresetsModalProps) {
1616
const { loadPreset, bucket, os } = useStore();
1717
const [applied, setApplied] = useState<string | null>(null);
18+
const modalRef = useRef<HTMLDivElement>(null);
19+
20+
useEffect(() => {
21+
const handleKey = (e: KeyboardEvent) => {
22+
if (e.key === 'Escape') onClose();
23+
};
24+
25+
const handleClickOutside = (e: MouseEvent) => {
26+
if (modalRef.current && !modalRef.current.contains(e.target as Node)) {
27+
onClose();
28+
}
29+
};
30+
31+
window.addEventListener('keydown', handleKey);
32+
document.addEventListener('mousedown', handleClickOutside);
33+
34+
return () => {
35+
window.removeEventListener('keydown', handleKey);
36+
document.removeEventListener('mousedown', handleClickOutside);
37+
};
38+
}, [onClose]);
1839

1940
const handleApply = (presetId: string, packageIds: string[]) => {
2041
loadPreset(packageIds);
@@ -26,9 +47,11 @@ export function PresetsModal({ onClose }: PresetsModalProps) {
2647

2748
return (
2849
<>
29-
<div className="fixed inset-0 z-40 bg-black/60 backdrop-blur-sm" onClick={onClose} />
50+
<div className="fixed inset-0 z-40 bg-black/60 backdrop-blur-sm" />
3051
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
31-
<div className="w-full max-w-3xl terminal-card rounded-xl overflow-hidden shadow-2xl"
52+
<div
53+
ref={modalRef}
54+
className="w-full max-w-3xl terminal-card rounded-xl overflow-hidden shadow-2xl"
3255
style={{ boxShadow: '0 0 60px rgba(0,255,128,0.15)' }}>
3356
{/* Header */}
3457
<div className="flex items-center justify-between p-5 border-b border-border bg-card">

0 commit comments

Comments
 (0)