73 lines
2.4 KiB
TypeScript
73 lines
2.4 KiB
TypeScript
import { useEffect, useRef, useState } from 'react';
|
|
import { RailAction } from '../../ui/RailAction.js';
|
|
|
|
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,
|
|
open,
|
|
onToggle,
|
|
}: {
|
|
feature: DiagnosticsFeature;
|
|
open: boolean;
|
|
onToggle: () => void;
|
|
}) {
|
|
return <RailAction
|
|
buttonRef={feature.toggleRef}
|
|
className="client-instructions-toggle client-diagnostics-toggle"
|
|
open={open}
|
|
controls="client-diagnostics"
|
|
ariaLabel={open ? 'Закрыть диагностику' : 'Проверить маршруты'}
|
|
label="Диагностика"
|
|
onClick={onToggle}
|
|
>
|
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
<path className="client-rail-diagnostics-trace" d="M4.5 10h2l1.2-2.4 2.2 4.8 1.2-2.4h3.4" />
|
|
<g className="client-rail-diagnostics-position">
|
|
<g className="client-rail-diagnostics-glass">
|
|
<circle cx="9.5" cy="9.5" r="6.5" />
|
|
<path d="m14.2 14.2 6.3 6.3" />
|
|
</g>
|
|
</g>
|
|
</svg>
|
|
</RailAction>;
|
|
}
|