reactjs-virtual-keyboard
Version:
A customizable virtual keyboard component for React applications with support for multiple layouts, multi-language support, hardware keyboard sync, and touch devices
428 lines (377 loc) • 14.1 kB
TypeScript
import { FC } from 'react';
import { HTMLInputTypeAttribute } from 'react';
import { ReactNode } from 'react';
import { RefObject } from 'react';
import { SVGProps } from 'react';
export declare const BackspaceIcon: FC<IconProps>;
export declare const CapsLockIcon: FC<IconProps>;
export declare interface ContinuousPressConfig {
/** Delay before continuous press starts (ms) */
initialDelay?: number;
/** Interval between repeated presses (ms) */
interval?: number;
}
export declare interface ContinuousPressOptions {
initialDelay?: number;
interval?: number;
shouldPreventDefault?: boolean;
}
/**
* Creates a caret manager for manipulating text in input elements.
* This is a pure utility that doesn't use React hooks.
*
* @param getInputRef - Function that returns the current input element ref
* @returns Object with insertText and backspace functions
*
* @example
* ```tsx
* const inputRef = useRef<HTMLInputElement>(null);
* const { insertText, backspace } = createCaretManager(() => inputRef.current);
* ```
*/
export declare function createCaretManager(getInputRef: () => InputElement | null): UseCaretManagerReturn;
export declare const DEFAULT_THEME: {
readonly backgroundColor: "#1a1a1a";
readonly keyColor: "#444444";
readonly keyTextColor: "#ffffff";
readonly keyActiveColor: "#666666";
readonly keyHoverColor: "#555555";
readonly activeStateColor: "#4a90e2";
readonly keyBorderRadius: "0.5vw";
readonly keyFontSize: "32px";
readonly keyHeight: "100%";
};
export declare const EnterIcon: FC<IconProps>;
declare type FocusedInputRef = RefObject<HTMLInputElement | HTMLTextAreaElement | null>;
/**
* Get the initial layout based on input type
*/
export declare const getInitialLayout: (inputType: HTMLInputTypeAttribute, defaultLayout: LayoutType) => LayoutType;
/**
* GlobalVirtualKeyboard automatically shows a virtual keyboard when any
* text input or textarea is focused. It handles:
* - Automatic show/hide based on focus
* - Scrolling inputs into view
* - Form submission on Enter
* - Input type detection for appropriate layouts
*
* @example
* ```tsx
* // Add once at the root of your app
* function App() {
* return (
* <div>
* <YourAppContent />
* <GlobalVirtualKeyboard />
* </div>
* );
* }
* ```
*
* @example
* ```tsx
* // With controlled visibility
* function App() {
* const [keyboardEnabled, setKeyboardEnabled] = useState(true);
*
* return (
* <div>
* <button onClick={() => setKeyboardEnabled(!keyboardEnabled)}>
* Toggle Keyboard
* </button>
* <GlobalVirtualKeyboard enabled={keyboardEnabled} />
* </div>
* );
* }
* ```
*/
export declare const GlobalVirtualKeyboard: FC<GlobalVirtualKeyboardProps>;
export declare interface GlobalVirtualKeyboardProps {
/**
* Whether the virtual keyboard is enabled.
* When false, the keyboard will not appear on input focus.
* @default true
*/
enabled?: boolean;
/**
* Additional CSS class name for the keyboard container
*/
className?: string;
/**
* Callback fired when keyboard visibility changes
*/
onVisibilityChange?: (isVisible: boolean) => void;
/**
* Callback fired when Enter key is pressed
*/
onEnterClick?: () => void;
/**
* Callback fired when value changes
*/
onChange?: (value: string) => void;
}
/**
* Handle value change on the focused input
*/
export declare const handleValueChangeUtil: (focusedInputRef: FocusedInputRef, value: string) => void;
export declare interface HardwareKeyboardHandlers {
isInputFocused: boolean;
onBackspace: () => void;
onEnter: () => void;
onSpace: () => void;
onCapsToggle: () => void;
onKeyClick: (key: string) => void;
}
declare type IconProps = SVGProps<SVGSVGElement>;
export declare type InputElement = HTMLInputElement | HTMLTextAreaElement;
export declare const KeyboardLayout: FC<KeyboardLayoutProps>;
export declare interface KeyboardLayoutProps {
currentLayout: LayoutType;
capsLock: boolean;
onKeyClick: (key: string) => void;
onBackspace: () => void;
onEnter: () => void;
onSpace: () => void;
onCapsToggle: () => void;
onLayoutToggle: () => void;
inputType?: HTMLInputTypeAttribute;
customLayouts?: {
letters?: string[][];
symbols?: string[][];
numbers?: string[][];
};
}
export declare const KeyboardRow: FC<KeyboardRowProps>;
export declare interface KeyboardRowProps {
children: ReactNode;
className?: string;
}
export declare type LayoutType = 'letters' | 'symbols' | 'numbers';
export declare const NUMBERS_LAYOUT: readonly [readonly ["7", "8", "9", "#"], readonly ["4", "5", "6", "-"], readonly ["1", "2", "3"], readonly [",", "0", "."]];
export declare const NumbersLayout: FC<NumbersLayoutProps>;
export declare interface NumbersLayoutProps {
currentLayoutData: ReadonlyArray<ReadonlyArray<string>> | string[][];
onBackspace: () => void;
onEnter: () => void;
onKeyClick: (key: string) => void;
capsLock: boolean;
currentLayout: LayoutType;
}
/**
* Handle Enter key click - blur input and submit form if applicable
*/
export declare const onEnterClickUtil: (focusedInputRef: FocusedInputRef) => void;
export declare const QWERTY_LAYOUT: readonly [readonly ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], readonly ["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"], readonly ["a", "s", "d", "f", "g", "h", "j", "k", "l"], readonly ["z", "x", "c", "v", "b", "n", "m"]];
/**
* Reset scroll position by removing transforms from shifted elements
*/
export declare function resetScrollPosition(): void;
export declare interface ScrollConfig {
/** Enable automatic scrolling when keyboard appears */
enabled?: boolean;
/** Additional offset padding (px) */
offset?: number;
}
/**
* Utility functions to handle layout shifting when virtual keyboard appears
*/
/**
* Scroll the input into view by shifting content elements up
*/
export declare function scrollInputIntoView(input: HTMLInputElement | HTMLTextAreaElement, keyboardContainerRef: HTMLSpanElement): void;
/**
* Update an input's value using the native setter (so React tracks it)
* and dispatch bubbled, cancelable input/change events to notify listeners.
*/
export declare const setInputValueAndDispatchEvents: (input: InputElement, value: string, options?: {
skipValueAssignment?: boolean;
}) => void;
/**
* Sets up hardware keyboard event listeners to sync with virtual keyboard.
* This is a pure utility that returns a cleanup function.
*
* @param handlers - Handlers for keyboard events
* @returns Cleanup function to remove event listeners
*
* @example
* ```tsx
* useEffect(() => {
* if (!isInputFocused) return;
* return setupHardwareKeyboard({
* onBackspace: handleBackspace,
* onEnter: handleEnter,
* // ...
* });
* }, [isInputFocused, handleBackspace, handleEnter]);
* ```
*/
export declare function setupHardwareKeyboard(handlers: Omit<HardwareKeyboardHandlers, 'isInputFocused'>): () => void;
export declare const SpacebarIcon: FC<IconProps>;
export declare const SpecialKey: FC<SpecialKeyProps>;
export declare interface SpecialKeyProps {
type: string;
onClick: () => void;
extraClass?: string;
text?: string | null;
icon?: ReactNode;
capsLock?: boolean;
enableContinuousPress?: boolean;
}
export declare const SYMBOLS_LAYOUT: readonly [readonly ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], readonly ["!", "@", "#", "$", "%", "^", "&", "*", "(", ")"], readonly ["-", "_", "=", "+", "[", "]", "{", "}", "\\", "|"], readonly [";", ":", "\"", "'", ",", ".", "<", ">", "/", "?"]];
export declare const TextLayout: FC<TextLayoutProps>;
export declare interface TextLayoutProps {
inputType?: HTMLInputTypeAttribute;
currentLayoutData: ReadonlyArray<ReadonlyArray<string>> | string[][];
onBackspace: () => void;
onEnter: () => void;
onSpace: () => void;
onCapsToggle: () => void;
onLayoutToggle: () => void;
onKeyClick: (key: string) => void;
capsLock: boolean;
currentLayout: LayoutType;
}
export declare interface UseCaretManagerReturn {
insertText: (text: string) => void;
backspace: () => void;
}
/**
* Hook for handling continuous press events (like holding backspace to delete multiple characters)
*/
export declare function useContinuousPress(onPress: () => void, { initialDelay, interval, shouldPreventDefault, }?: ContinuousPressOptions): {
onMouseDown: (e: React.MouseEvent) => void;
onTouchStart: (e: React.TouchEvent) => void;
onMouseUp: () => void;
onMouseLeave: () => void;
onTouchEnd: (e: React.TouchEvent) => void;
};
/**
* Hook to handle keyboard scrolling for input elements.
* Automatically shifts content up when the virtual keyboard would cover the input.
*
* @returns Object with scroll and reset functions
*
* @example
* ```tsx
* const { scrollInput, resetScroll } = useKeyboardScroll();
*
* // When input is focused
* scrollInput(inputElement);
*
* // When keyboard is hidden
* resetScroll();
* ```
*/
export declare function useKeyboardScroll(keyboardContainerRef: RefObject<HTMLSpanElement | null>): UseKeyboardScrollReturn;
export declare interface UseKeyboardScrollReturn {
/** Scroll the input into view when keyboard appears */
scrollInput: (input: HTMLInputElement | HTMLTextAreaElement) => void;
/** Reset scroll position when keyboard hides */
resetScroll: () => void;
}
/**
* Validate if the focused element should show the virtual keyboard
* Returns the input/textarea element or null if it shouldn't show keyboard
*/
export declare const validateFocusInputs: (event: Event) => HTMLInputElement | HTMLTextAreaElement | null;
/**
* Validates a single character based on input type
*/
export declare const validateValueUtil: (value: string, inputType: HTMLInputTypeAttribute) => boolean;
export declare const VirtualKey: FC<VirtualKeyProps>;
/**
* Virtual Keyboard Component
*
* A customizable on-screen keyboard for React applications.
* Supports multiple layouts (QWERTY, symbols, numbers), hardware keyboard sync,
* and touch device compatibility.
*/
export declare const VirtualKeyboard: FC<VirtualKeyboardProps>;
export declare const VirtualKeyboardContainer: FC<VirtualKeyboardContainerProps>;
declare interface VirtualKeyboardContainerProps {
children: ReactNode;
className?: string;
}
export declare interface VirtualKeyboardProps {
/** Ref to the currently focused input element */
focusedInputRef: RefObject<HTMLInputElement | HTMLTextAreaElement | null>;
/** Whether an input is currently focused */
isInputFocused: boolean;
/** Type of the input element (affects layout and validation) */
inputType?: HTMLInputTypeAttribute;
/** Callback fired when Enter key is pressed */
onEnterClick?: () => void;
/** Callback fired when value changes */
onChange?: (value: string) => void;
/** Additional CSS class name */
className?: string;
/** Default layout to show ('letters' | 'symbols' | 'numbers') */
defaultLayout?: LayoutType;
/** Custom validation function */
validate?: (value: string) => boolean;
/** Theme configuration */
theme?: VirtualKeyboardTheme;
/** Custom keyboard layouts (overrides default layouts) */
customLayouts?: {
letters?: string[][];
symbols?: string[][];
numbers?: string[][];
};
/** Continuous press configuration for backspace */
continuousPressConfig?: ContinuousPressConfig;
/** Scroll behavior configuration */
scrollConfig?: ScrollConfig;
/** Enable/disable hardware keyboard synchronization */
syncWithHardwareKeyboard?: boolean;
/** Custom key labels (e.g., { 'enter': 'Submit', 'space': 'Space Bar' }) */
keyLabels?: Record<string, string>;
/** Keys to hide from the keyboard */
hiddenKeys?: string[];
/** Keys to disable (grayed out and non-clickable) */
disabledKeys?: string[];
/** Custom render function for individual keys */
renderKey?: (key: string, defaultRender: ReactNode) => ReactNode;
/** Custom render function for special keys */
renderSpecialKey?: (type: string, defaultRender: ReactNode) => ReactNode;
/** Multi-language keyboard layouts */
languages?: {
[languageCode: string]: {
letters?: string[][];
symbols?: string[][];
numbers?: string[][];
label?: string;
};
};
/** Currently selected language code */
currentLanguage?: string;
/** Callback when language changes */
onLanguageChange?: (languageCode: string) => void;
/** Show language switcher button */
showLanguageSwitcher?: boolean;
}
export declare interface VirtualKeyboardTheme {
/** Background color of the keyboard container */
backgroundColor?: string;
/** Color of the keys */
keyColor?: string;
/** Text color on keys */
keyTextColor?: string;
/** Active/pressed key background color */
keyActiveColor?: string;
/** Hover key background color */
keyHoverColor?: string;
/** Active state color (e.g., caps lock on) */
activeStateColor?: string;
/** Border radius for keys */
keyBorderRadius?: string;
/** Font size for keys */
keyFontSize?: string;
/** Key height */
keyHeight?: string;
}
export declare interface VirtualKeyProps {
keyValue: string;
onClick: (key: string) => void;
className?: string;
}
export { }