UNPKG

move.gl

Version:

Motion and Animation Library for Stylescape.

196 lines (181 loc) 6.65 kB
// ============================================================================ // move.gl | Virtual Keyboard // ============================================================================ // Copyright 2025 Scape Agency BV // Licensed under MIT License // ============================================================================ /** * Keyboard layout configuration */ export interface KeyboardLayout { [mode: string]: string[][]; } /** * Virtual Keyboard Configuration Options */ export interface VirtualKeyboardOptions { /** Custom keyboard layout */ layout?: KeyboardLayout; /** Callback when a key is pressed */ onKeyPress?: (key: string) => void; } /** * Virtual Keyboard * * Manages the rendering and interaction of a virtual keyboard on the web. * Supports multiple layouts (default, shift, special) and handles both * mouse and keyboard inputs, including touch support. * * @example * ```typescript * const keyboard = new VirtualKeyboard('textInput', 'keyboard'); * keyboard.switchMode('special'); * ``` */ export class VirtualKeyboard { private keys: { [mode: string]: string[][] } = { "default": [ ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], ["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"], ["a", "s", "d", "f", "g", "h", "j", "k", "l"], ["z", "x", "c", "v", "b", "n", "m", "Backspace"] ], "shift": [ ["!", "@", "#", "$", "%", "^", "&", "*", "(", ")"], ["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"], ["A", "S", "D", "F", "G", "H", "J", "K", "L"], ["Z", "X", "C", "V", "B", "N", "M", "Backspace"] ], "special": [ ["[", "]", "{", "}", "#", "%", "^", "*", "+", "="], ["_", "\\", "|", "~", "<", ">", "€", "£", "¥"], [".", ",", "?", "!", "'", '"', ":", ";", "Backspace"] ] }; private currentMode = "default"; private inputElement: HTMLInputElement; private keyboardElement: HTMLElement; /** * @notice Initializes the virtual keyboard with specific input and * keyboard element IDs. * @param inputId The ID of the HTML input element to which the keyboard * will be linked. * @param keyboardId The ID of the container element where the keyboard * will be rendered. */ constructor(inputId: string, keyboardId: string) { this.inputElement = document.getElementById( inputId ) as HTMLInputElement; this.keyboardElement = document.getElementById( keyboardId ) as HTMLElement; this.renderKeyboard(); this.attachEventListeners(); } /** * @notice Renders the keyboard based on the current mode (default, shift, * or special). * @dev Dynamically creates HTML for keyboard keys and appends them to the * keyboardElement. */ private renderKeyboard() { // Clear existing keys this.keyboardElement.innerHTML = ""; this.keys[this.currentMode].forEach(row => { const rowElement = document.createElement("div"); rowElement.className = "keyboard__row"; row.forEach(key => { const keyElement = document.createElement("div"); keyElement.textContent = key; // Assign a class for easier CSS styling keyElement.className = "key"; keyElement.addEventListener( "click", () => this.handleKeyPress(key) ); rowElement.appendChild(keyElement); }); this.keyboardElement.appendChild(rowElement); }); } /** * @notice Handles key presses on the virtual keyboard. * @param key The key character or function (like "Backspace") that was * pressed. */ private handleKeyPress(key: string) { if (key === "Backspace") { this.inputElement.value = this.inputElement.value.slice(0, -1); } else if (key === "Shift" || key === "CapsLock") { this.toggleShift(); } else { this.inputElement.value += key; } } /** * @notice Toggles the keyboard between "default" and "shift" modes. * @dev This method is called when the "Shift" or "CapsLock" key is pressed. */ private toggleShift() { this.currentMode = this.currentMode === "default" ? "shift" : "default"; this.renderKeyboard(); } /** * @notice Attaches necessary event listeners to handle both physical * keyboard and touch inputs. */ private attachEventListeners() { document.addEventListener("keydown", this.handlePhysicalKeyPress); this.keyboardElement.addEventListener( "touchstart", this.handleTouchStart, false ); } /** * @notice Handles physical keyboard events and maps them to virtual key * presses. * @param event The keyboard event captured from the user"s physical * keyboard. */ private handlePhysicalKeyPress = (event: KeyboardEvent) => { const key = event.key; if (key === "Shift" || key === "CapsLock") { this.toggleShift(); event.preventDefault(); } else if (key === "Enter" || key === "Tab") { // Optional: Implement behavior for Enter and Tab if needed } else { this.handleKeyPress(key); } }; /** * @notice Handles touch events on the keyboard element. * @param event The touch event on the virtual keyboard. */ private handleTouchStart = (event: TouchEvent) => { event.preventDefault(); // Prevents emulating mouse events const keyElement = event.target as HTMLElement; if (keyElement.classList.contains("key")) { this.handleKeyPress(keyElement.textContent || ""); } }; /** * @notice Switches the keyboard layout to a specified mode. * @param mode The mode to which the keyboard layout should switch * ("default", "shift", or "special"). */ public switchMode(mode: string) { if (this.keys[mode]) { this.currentMode = mode; this.renderKeyboard(); } } /** * Removes all event listeners and cleans up. */ public destroy(): void { document.removeEventListener('keydown', this.handlePhysicalKeyPress); this.keyboardElement.removeEventListener('touchstart', this.handleTouchStart); this.keyboardElement.innerHTML = ''; } } export default VirtualKeyboard;