Files
headquarter/apps/web/src/components/special-keys-strip.tsx
T
Fusion 12378def4d feat: implement one-shot modifier keys for mobile terminal
- Redesign useSpecialKeys hook with modifier state tracking
- Add one-shot activation for Ctrl and Alt keys
- Visual feedback: active modifiers shown with yellow highlight
- Fix focusInput to use term.focus() instead of hidden input
- Always refocus terminal after sending any special key
- Add requestAnimationFrame for reliable focus restoration
2026-05-24 12:28:36 +02:00

78 lines
2.1 KiB
TypeScript

import React from "react";
import { useSpecialKeys, type SpecialKey, type ModifierKey } from "../hooks/use-special-keys";
interface SpecialKeysStripProps {
onSend: (data: string) => void;
isVisible: boolean;
onMoreClick?: () => void;
onKeepFocus?: () => void;
}
const PRIMARY_KEYS: { key: SpecialKey; label: string; isModifier?: boolean }[] = [
{ key: "escape", label: "Esc" },
{ key: "tab", label: "Tab" },
{ key: "ctrl", label: "Ctrl", isModifier: true },
{ key: "alt", label: "Alt", isModifier: true },
{ key: "up", label: "↑" },
{ key: "down", label: "↓" },
{ key: "left", label: "←" },
{ key: "right", label: "→" },
];
export const SpecialKeysStrip: React.FC<SpecialKeysStripProps> = ({
onSend,
isVisible,
onMoreClick,
onKeepFocus,
}) => {
const { sendKey, activeModifier } = useSpecialKeys({ onSend });
const handlePointerDown = (e: React.PointerEvent, key: SpecialKey) => {
e.preventDefault();
sendKey(key);
// Always refocus terminal after sending
requestAnimationFrame(() => {
onKeepFocus?.();
});
};
const handleMorePointerDown = (e: React.PointerEvent) => {
e.preventDefault();
onMoreClick?.();
requestAnimationFrame(() => {
onKeepFocus?.();
});
};
return (
<div className={`special-keys-strip ${isVisible ? "visible" : "hidden"}`}>
{PRIMARY_KEYS.map(({ key, label, isModifier }) => (
<button
key={key}
className={`special-key-button ${
isModifier && activeModifier === key ? "active-modifier" : ""
}`}
onPointerDown={(e) => handlePointerDown(e, key)}
type="button"
tabIndex={-1}
aria-label={`Send ${label}`}
aria-pressed={isModifier && activeModifier === key}
>
{label}
</button>
))}
{onMoreClick && (
<button
className="special-key-button special-key-more"
onPointerDown={handleMorePointerDown}
type="button"
tabIndex={-1}
aria-label="More special keys"
>
More
</button>
)}
</div>
);
};