Refactor VPN proxy client implementation
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
export function useDiagnosticsFeature() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const panelRef = useRef<HTMLElement>(null);
|
||||
const toggleRef = useRef<HTMLButtonElement>(null);
|
||||
const closeRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) return undefined;
|
||||
const frame = requestAnimationFrame(() => closeRef.current?.focus());
|
||||
const closeDiagnostics = (event: PointerEvent | KeyboardEvent) => {
|
||||
if (event.type === 'keydown' && (event as KeyboardEvent).key !== 'Escape') return;
|
||||
if (event.type !== 'keydown' && (
|
||||
panelRef.current?.contains(event.target as Node) || toggleRef.current?.contains(event.target as Node)
|
||||
)) return;
|
||||
setIsOpen(false);
|
||||
};
|
||||
document.addEventListener('pointerdown', closeDiagnostics);
|
||||
document.addEventListener('keydown', closeDiagnostics);
|
||||
return () => {
|
||||
cancelAnimationFrame(frame);
|
||||
document.removeEventListener('pointerdown', closeDiagnostics);
|
||||
document.removeEventListener('keydown', closeDiagnostics);
|
||||
requestAnimationFrame(() => {
|
||||
if (panelRef.current?.contains(document.activeElement)) toggleRef.current?.focus();
|
||||
});
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
return {
|
||||
isOpen,
|
||||
panelRef,
|
||||
toggleRef,
|
||||
closeRef,
|
||||
close: () => setIsOpen(false),
|
||||
toggle: () => setIsOpen((open) => !open),
|
||||
};
|
||||
}
|
||||
|
||||
export type DiagnosticsFeature = ReturnType<typeof useDiagnosticsFeature>;
|
||||
|
||||
export function DiagnosticsToggle({
|
||||
feature,
|
||||
onToggle,
|
||||
}: {
|
||||
feature: DiagnosticsFeature;
|
||||
onToggle: () => void;
|
||||
}) {
|
||||
return <button
|
||||
ref={feature.toggleRef}
|
||||
className={`client-instructions-toggle client-diagnostics-toggle${feature.isOpen ? ' is-open' : ''}`}
|
||||
type="button"
|
||||
aria-expanded={feature.isOpen}
|
||||
aria-controls="client-diagnostics"
|
||||
aria-label={feature.isOpen ? 'Закрыть диагностику' : 'Проверить маршруты'}
|
||||
onClick={onToggle}
|
||||
>
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path className="client-rail-diagnostics-base" d="M3 12h4l2.2-5 4.2 10 2.1-5H21" />
|
||||
<path className="client-rail-diagnostics-pulse" pathLength="1" d="M3 12h4l2.2-5 4.2 10 2.1-5H21" />
|
||||
</svg>
|
||||
<span>Диагностика</span>
|
||||
</button>;
|
||||
}
|
||||
Reference in New Issue
Block a user