UNPKG

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
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 { }