reactjs-virtual-keyboard 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +327 -0
- package/dist/index.d.ts +346 -0
- package/dist/index.esm.js +678 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/utils/inputEvents.ts","../src/hooks/useCaretManager.ts","../src/hooks/useContinuousPress.ts","../src/hooks/useHardwareKeyboard.ts","../src/utils/scrollUtils.ts","../src/hooks/useKeyboardScroll.ts","../src/utils/validators.ts","../src/utils/globalKeyboardUtils.ts","../src/constants.ts","../src/components/icons/index.tsx","../src/components/SpecialKey.tsx","../src/components/VirtualKey.tsx","../src/components/KeyboardRow.tsx","../src/components/NumbersLayout.tsx","../src/components/TextLayout.tsx","../src/components/KeyboardLayout.tsx","../src/components/VirtualKeyboardContainer.tsx","../src/components/VirtualKeyboard.tsx","../src/components/GlobalVirtualKeyboard.tsx"],"sourcesContent":["import type { InputElement } from '../types';\r\n\r\n/**\r\n * Update an input's value using the native setter (so React tracks it)\r\n * and dispatch bubbled, cancelable input/change events to notify listeners.\r\n */\r\nexport const setInputValueAndDispatchEvents = (\r\n input: InputElement,\r\n value: string,\r\n options: { skipValueAssignment?: boolean } = {}\r\n): void => {\r\n const { skipValueAssignment = false } = options;\r\n\r\n if (!skipValueAssignment) {\r\n const proto = Object.getPrototypeOf(input);\r\n const valueSetter = Object.getOwnPropertyDescriptor(proto, 'value')?.set;\r\n\r\n if (valueSetter) {\r\n valueSetter.call(input, value);\r\n }\r\n }\r\n\r\n input.dispatchEvent(new InputEvent('input', { bubbles: true, cancelable: true }));\r\n input.dispatchEvent(new Event('change', { bubbles: true, cancelable: true }));\r\n};\r\n","import type { RefObject } from 'react';\r\nimport type { InputElement, UseCaretManagerReturn } from '../types';\r\nimport { setInputValueAndDispatchEvents } from '../utils/inputEvents';\r\n\r\n/**\r\n * Hook to manage caret position and text insertion/deletion in input elements\r\n */\r\nexport function useCaretManager(\r\n focusedInputRef: RefObject<InputElement | null>\r\n): UseCaretManagerReturn {\r\n /**\r\n * Insert text at the current caret position or replace selected text\r\n */\r\n const insertText = (text: string): void => {\r\n const input = focusedInputRef.current;\r\n if (!input) return;\r\n if (input.readOnly || input.disabled) return;\r\n\r\n const startRaw = input.selectionStart;\r\n const endRaw = input.selectionEnd;\r\n const start = startRaw == null ? input.value.length : startRaw;\r\n const end = endRaw == null ? input.value.length : endRaw;\r\n\r\n const scrollTop = (input as HTMLTextAreaElement).scrollTop ?? 0;\r\n const scrollLeft = (input as HTMLTextAreaElement).scrollLeft ?? 0;\r\n\r\n // Calculate new value\r\n const newValue = input.value.slice(0, start) + text + input.value.slice(end);\r\n const caretAfter = start + text.length;\r\n\r\n // Set value and dispatch events\r\n setInputValueAndDispatchEvents(input, newValue);\r\n\r\n // Restore focus & selection\r\n input.focus();\r\n input.setSelectionRange(caretAfter, caretAfter);\r\n\r\n if ('scrollTop' in input) {\r\n (input as HTMLTextAreaElement).scrollTop = scrollTop;\r\n (input as HTMLTextAreaElement).scrollLeft = scrollLeft;\r\n }\r\n };\r\n\r\n /**\r\n * Delete selected text or the character before the caret\r\n */\r\n const backspace = (): void => {\r\n const input = focusedInputRef.current;\r\n if (!input) return;\r\n if (input.readOnly || input.disabled) return;\r\n\r\n const startRaw = input.selectionStart;\r\n const endRaw = input.selectionEnd;\r\n const start = startRaw == null ? input.value.length : startRaw;\r\n const end = endRaw == null ? input.value.length : endRaw;\r\n\r\n const scrollTop = (input as HTMLTextAreaElement).scrollTop ?? 0;\r\n const scrollLeft = (input as HTMLTextAreaElement).scrollLeft ?? 0;\r\n\r\n // If selection present -> delete selection\r\n if (start !== end) {\r\n const newValue = input.value.slice(0, start) + input.value.slice(end);\r\n setInputValueAndDispatchEvents(input, newValue);\r\n input.focus();\r\n input.setSelectionRange(start, start);\r\n } else if (start > 0) {\r\n const newValue = input.value.slice(0, start - 1) + input.value.slice(start);\r\n const newCaret = start - 1;\r\n\r\n setInputValueAndDispatchEvents(input, newValue);\r\n input.focus();\r\n input.setSelectionRange(newCaret, newCaret);\r\n }\r\n\r\n if ('scrollTop' in input) {\r\n (input as HTMLTextAreaElement).scrollTop = scrollTop;\r\n (input as HTMLTextAreaElement).scrollLeft = scrollLeft;\r\n }\r\n };\r\n\r\n return {\r\n insertText,\r\n backspace,\r\n };\r\n}\r\n\r\nexport default useCaretManager;\r\n","import { useCallback, useRef } from 'react';\r\nimport type { ContinuousPressOptions } from '../types';\r\n\r\n/**\r\n * Hook for handling continuous press events (like holding backspace to delete multiple characters)\r\n */\r\nexport function useContinuousPress(\r\n onPress: () => void,\r\n {\r\n initialDelay = 500,\r\n interval = 50,\r\n shouldPreventDefault = true,\r\n }: ContinuousPressOptions = {}\r\n) {\r\n const timeoutRef = useRef<ReturnType<typeof setTimeout>>();\r\n const intervalRef = useRef<ReturnType<typeof setInterval>>();\r\n\r\n const clear = useCallback(() => {\r\n if (timeoutRef.current) {\r\n clearTimeout(timeoutRef.current);\r\n timeoutRef.current = undefined;\r\n }\r\n if (intervalRef.current) {\r\n clearInterval(intervalRef.current);\r\n intervalRef.current = undefined;\r\n }\r\n }, []);\r\n\r\n const start = useCallback(() => {\r\n onPress();\r\n timeoutRef.current = setTimeout(() => {\r\n intervalRef.current = setInterval(onPress, interval);\r\n }, initialDelay);\r\n }, [onPress, initialDelay, interval]);\r\n\r\n return {\r\n onMouseDown: (e: React.MouseEvent) => {\r\n e.preventDefault();\r\n start();\r\n },\r\n onTouchStart: (e: React.TouchEvent) => {\r\n if (shouldPreventDefault) e.preventDefault();\r\n start();\r\n },\r\n onMouseUp: clear,\r\n onMouseLeave: clear,\r\n onTouchEnd: (e: React.TouchEvent) => {\r\n if (shouldPreventDefault) e.preventDefault();\r\n clear();\r\n },\r\n };\r\n}\r\n\r\nexport default useContinuousPress;\r\n","import { useEffect } from 'react';\r\nimport type { HardwareKeyboardHandlers } from '../types';\r\n\r\n/**\r\n * Hook to keep virtual keyboard in sync with hardware keyboard events\r\n * (e.g., when pressing caps lock on hardware keyboard, virtual keyboard should reflect it)\r\n */\r\nexport function useHardwareKeyboard({\r\n isInputFocused,\r\n onBackspace,\r\n onEnter,\r\n onSpace,\r\n onCapsToggle,\r\n onKeyClick,\r\n}: HardwareKeyboardHandlers): void {\r\n useEffect(() => {\r\n if (!isInputFocused) return;\r\n\r\n const handleKeyboardKeyDown = (event: KeyboardEvent) => {\r\n const key = event.key;\r\n\r\n switch (key) {\r\n case 'Backspace':\r\n event.preventDefault();\r\n event.stopPropagation();\r\n onBackspace();\r\n return;\r\n case 'Enter':\r\n event.preventDefault();\r\n onEnter();\r\n return;\r\n case ' ':\r\n event.preventDefault();\r\n onSpace();\r\n return;\r\n case 'CapsLock':\r\n event.preventDefault();\r\n onCapsToggle();\r\n return;\r\n default:\r\n if (key.length === 1) {\r\n event.preventDefault();\r\n onKeyClick(key);\r\n }\r\n }\r\n };\r\n\r\n document.addEventListener('keydown', handleKeyboardKeyDown);\r\n\r\n return () => {\r\n document.removeEventListener('keydown', handleKeyboardKeyDown);\r\n };\r\n }, [isInputFocused, onBackspace, onEnter, onSpace, onCapsToggle, onKeyClick]);\r\n}\r\n\r\nexport default useHardwareKeyboard;\r\n","/**\r\n * Utility functions to handle layout shifting when virtual keyboard appears\r\n */\r\n\r\nconst KEYBOARD_HEIGHT_VH = 38;\r\nconst INPUT_PADDING = 20;\r\nconst TRANSITION_CLASS = 'vk-keyboard-shift-transition';\r\nconst TRANSITION_DURATION = 300;\r\n\r\nlet shiftedElements: HTMLElement[] = [];\r\nlet styleInjected = false;\r\n\r\nfunction injectStyles(): void {\r\n if (styleInjected) return;\r\n\r\n const style = document.createElement('style');\r\n style.id = 'vk-keyboard-shift-styles';\r\n style.textContent = `\r\n .${TRANSITION_CLASS} {\r\n transition: transform ${TRANSITION_DURATION}ms ease-out;\r\n will-change: transform;\r\n }\r\n `;\r\n document.head.appendChild(style);\r\n styleInjected = true;\r\n}\r\n\r\nfunction findContentElements(keyboardContainerRef: HTMLSpanElement | null): HTMLElement[] {\r\n if (!keyboardContainerRef) return [];\r\n return Array.from(keyboardContainerRef.parentElement?.children ?? []).filter(\r\n (child): child is HTMLElement => {\r\n if (child === keyboardContainerRef) return false;\r\n const { position } = window.getComputedStyle(child);\r\n return position !== 'fixed' && position !== 'absolute';\r\n }\r\n );\r\n}\r\n\r\nfunction calculateShiftAmount(input: HTMLElement): number {\r\n const inputBottom = input.getBoundingClientRect().bottom;\r\n const visibleHeight = window.innerHeight * (1 - KEYBOARD_HEIGHT_VH / 100);\r\n const overflow = inputBottom + INPUT_PADDING - visibleHeight;\r\n\r\n return overflow > 0 ? overflow : 0;\r\n}\r\n\r\n/**\r\n * Scroll the input into view by shifting content elements up\r\n */\r\nexport function scrollInputIntoView(input: HTMLInputElement | HTMLTextAreaElement, keyboardContainerRef: HTMLSpanElement): void {\r\n if (shiftedElements.length > 0) resetScrollPosition();\r\n\r\n const shiftAmount = calculateShiftAmount(input);\r\n if (shiftAmount === 0) return;\r\n\r\n const contentElements = findContentElements(keyboardContainerRef);\r\n\r\n if (contentElements.length === 0) return;\r\n\r\n injectStyles();\r\n shiftedElements = contentElements;\r\n\r\n for (const element of contentElements) {\r\n element.classList.add(TRANSITION_CLASS);\r\n element.style.transform = `translateY(-${shiftAmount}px)`;\r\n }\r\n}\r\n\r\n/**\r\n * Reset scroll position by removing transforms from shifted elements\r\n */\r\nexport function resetScrollPosition(): void {\r\n if (shiftedElements.length === 0) return;\r\n\r\n for (const element of shiftedElements) {\r\n if (document.body.contains(element)) {\r\n element.style.transform = 'translateY(0)';\r\n }\r\n }\r\n\r\n const elementsToCleanup = [...shiftedElements];\r\n setTimeout(() => {\r\n for (const element of elementsToCleanup) {\r\n if (document.body.contains(element)) {\r\n element.classList.remove(TRANSITION_CLASS);\r\n }\r\n }\r\n }, TRANSITION_DURATION);\r\n\r\n shiftedElements = [];\r\n}\r\n\r\n","import { useCallback, useEffect, RefObject } from 'react';\r\nimport { scrollInputIntoView, resetScrollPosition } from '../utils/scrollUtils';\r\n\r\nexport interface UseKeyboardScrollReturn {\r\n /** Scroll the input into view when keyboard appears */\r\n scrollInput: (input: HTMLInputElement | HTMLTextAreaElement) => void;\r\n /** Reset scroll position when keyboard hides */\r\n resetScroll: () => void;\r\n}\r\n\r\n/**\r\n * Hook to handle keyboard scrolling for input elements.\r\n * Automatically shifts content up when the virtual keyboard would cover the input.\r\n *\r\n * @returns Object with scroll and reset functions\r\n *\r\n * @example\r\n * ```tsx\r\n * const { scrollInput, resetScroll } = useKeyboardScroll();\r\n *\r\n * // When input is focused\r\n * scrollInput(inputElement);\r\n *\r\n * // When keyboard is hidden\r\n * resetScroll();\r\n * ```\r\n */\r\nexport function useKeyboardScroll(keyboardContainerRef: RefObject<HTMLSpanElement | null>): UseKeyboardScrollReturn {\r\n // Scroll input into view when keyboard appears\r\n const handleScrollInput = useCallback((input: HTMLInputElement | HTMLTextAreaElement) => {\r\n setTimeout(() => {\r\n if (!keyboardContainerRef?.current) return;\r\n scrollInputIntoView(input, keyboardContainerRef.current);\r\n }, 0);\r\n }, [keyboardContainerRef]);\r\n\r\n // Reset scroll position\r\n const handleResetScroll = useCallback(() => {\r\n resetScrollPosition();\r\n }, []);\r\n\r\n // Cleanup on unmount\r\n useEffect(() => {\r\n return () => {\r\n resetScrollPosition();\r\n };\r\n }, []);\r\n\r\n return {\r\n scrollInput: handleScrollInput,\r\n resetScroll: handleResetScroll,\r\n };\r\n}\r\n\r\nexport default useKeyboardScroll;\r\n\r\n","import type { HTMLInputTypeAttribute } from 'react';\r\nimport type { LayoutType } from '../types';\r\n\r\n/**\r\n * Validates a single character based on input type\r\n */\r\nexport const validateValueUtil = (\r\n value: string,\r\n inputType: HTMLInputTypeAttribute\r\n): boolean => {\r\n switch (inputType) {\r\n case 'number':\r\n // Only allow digits\r\n return /^[0-9]*$/.test(value);\r\n\r\n case 'email':\r\n // Allow alphanumeric, @, ., _, -, +\r\n return /^[a-zA-Z0-9@._+-]*$/.test(value);\r\n\r\n case 'tel':\r\n // Only allow digits, +, -, (, ), spaces\r\n return /^[0-9+\\-() ]*$/.test(value);\r\n\r\n case 'url':\r\n // Allow basic URL characters\r\n return /^[a-zA-Z0-9:/._-]*$/.test(value);\r\n\r\n case 'password':\r\n // Allow all characters for password\r\n return true;\r\n\r\n default:\r\n return true; // allow all characters for text input\r\n }\r\n};\r\n\r\n/**\r\n * Get the initial layout based on input type\r\n */\r\nexport const getInitialLayout = (\r\n inputType: HTMLInputTypeAttribute,\r\n defaultLayout: LayoutType\r\n): LayoutType => {\r\n if (inputType === 'number') {\r\n return 'numbers';\r\n }\r\n return defaultLayout;\r\n};\r\n","import type { RefObject } from 'react';\r\nimport { setInputValueAndDispatchEvents } from './inputEvents';\r\n\r\ntype FocusedInputRef = RefObject<HTMLInputElement | HTMLTextAreaElement | null>;\r\n\r\n/**\r\n * Handle Enter key click - blur input and submit form if applicable\r\n */\r\nexport const onEnterClickUtil = (focusedInputRef: FocusedInputRef): void => {\r\n if (focusedInputRef.current) {\r\n const input = focusedInputRef.current;\r\n input.blur();\r\n\r\n // If it's a form then submit the form\r\n input.form?.submit();\r\n }\r\n};\r\n\r\n/**\r\n * Handle value change on the focused input\r\n */\r\nexport const handleValueChangeUtil = (focusedInputRef: FocusedInputRef, value: string): void => {\r\n const input = focusedInputRef.current;\r\n if (!input) return;\r\n\r\n setInputValueAndDispatchEvents(input, value);\r\n};\r\n\r\n/**\r\n * Validate if the focused element should show the virtual keyboard\r\n * Returns the input/textarea element or null if it shouldn't show keyboard\r\n */\r\nexport const validateFocusInputs = (\r\n event: Event\r\n): HTMLInputElement | HTMLTextAreaElement | null => {\r\n const target = event.target as HTMLElement;\r\n\r\n // Check if the focused element matches our criteria\r\n const isInput = target.tagName === 'INPUT';\r\n const isTextarea = target.tagName === 'TEXTAREA';\r\n\r\n if (isTextarea) {\r\n return target as HTMLTextAreaElement;\r\n }\r\n\r\n if (isInput) {\r\n const input = target as HTMLInputElement;\r\n const excludedTypes = [\r\n 'checkbox',\r\n 'radio',\r\n 'range',\r\n 'date',\r\n 'time',\r\n 'color',\r\n 'month',\r\n 'week',\r\n 'file',\r\n 'hidden',\r\n 'submit',\r\n 'reset',\r\n 'button',\r\n 'image',\r\n ];\r\n\r\n if (excludedTypes.includes(input.type)) return null;\r\n return input;\r\n }\r\n\r\n return null;\r\n};\r\n\r\n","export const QWERTY_LAYOUT: string[][] = [\r\n ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],\r\n ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'],\r\n ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'],\r\n ['z', 'x', 'c', 'v', 'b', 'n', 'm'],\r\n];\r\n\r\nexport const SYMBOLS_LAYOUT: string[][] = [\r\n ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],\r\n ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')'],\r\n ['-', '_', '=', '+', '[', ']', '{', '}', '\\\\', '|'],\r\n [';', ':', '\"', \"'\", ',', '.', '<', '>', '/', '?'],\r\n];\r\n\r\nexport const NUMBERS_LAYOUT: string[][] = [\r\n ['7', '8', '9', '#'],\r\n ['4', '5', '6', '-'],\r\n ['1', '2', '3'],\r\n [',', '0', '.'],\r\n];\r\n\r\nexport const DEFAULT_THEME = {\r\n backgroundColor: '#1a1a1a',\r\n keyColor: '#444444',\r\n keyTextColor: '#ffffff',\r\n keyActiveColor: '#666666',\r\n keyHoverColor: '#555555',\r\n activeStateColor: '#4a90e2',\r\n keyBorderRadius: '0.5vw',\r\n keyFontSize: '32px',\r\n keyHeight: '100%',\r\n};\r\n","import type { FC, SVGProps } from 'react';\r\n\r\ntype IconProps = SVGProps<SVGSVGElement>;\r\n\r\nexport const BackspaceIcon: FC<IconProps> = (props) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"currentColor\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n {...props}\r\n >\r\n <path d=\"M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H7.07L2.4 12l4.66-7H22v14zm-11.59-2L14 13.41 17.59 17 19 15.59 15.41 12 19 8.41 17.59 7 14 10.59 10.41 7 9 8.41 12.59 12 9 15.59z\" />\r\n </svg>\r\n);\r\n\r\nexport const EnterIcon: FC<IconProps> = (props) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"currentColor\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n {...props}\r\n >\r\n <path d=\"M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z\" />\r\n </svg>\r\n);\r\n\r\nexport const SpacebarIcon: FC<IconProps> = (props) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"currentColor\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n {...props}\r\n >\r\n <path d=\"M18 9v4H6V9H4v6h16V9z\" />\r\n </svg>\r\n);\r\n\r\nexport const CapsLockIcon: FC<IconProps> = (props) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"currentColor\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n style={{ transform: 'rotate(270deg)' }}\r\n {...props}\r\n >\r\n <path d=\"M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z\" />\r\n </svg>\r\n);\r\n","import type { FC } from 'react';\r\nimport type { SpecialKeyProps } from '../types';\r\nimport { useContinuousPress } from '../hooks';\r\n\r\nexport const SpecialKey: FC<SpecialKeyProps> = ({\r\n type,\r\n icon,\r\n onClick,\r\n extraClass = '',\r\n text,\r\n capsLock = false,\r\n enableContinuousPress = false,\r\n}) => {\r\n const isCapsLockActive = type === 'caps' && capsLock;\r\n const keyClasses = [\r\n 'vk-key',\r\n `vk-key--${extraClass}`,\r\n isCapsLockActive ? 'vk-key--caps-active' : '',\r\n ]\r\n .filter(Boolean)\r\n .join(' ');\r\n\r\n // Use continuous press for backspace (hold to delete continuously)\r\n const continuousPressHandlers = useContinuousPress(onClick, {\r\n initialDelay: 500,\r\n interval: 50,\r\n });\r\n\r\n // Use continuous press handlers if enabled, otherwise use regular click\r\n const buttonHandlers = enableContinuousPress ? continuousPressHandlers : { onClick };\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n className={keyClasses}\r\n data-testid={`${type}${isCapsLockActive ? '-active' : ''}`}\r\n data-key={isCapsLockActive ? `${type}-active` : type}\r\n {...buttonHandlers}\r\n >\r\n {icon && icon}\r\n {text && <span className=\"vk-key__text\">{text}</span>}\r\n </button>\r\n );\r\n};\r\n\r\nexport default SpecialKey;\r\n","import type { FC } from 'react';\r\nimport type { VirtualKeyProps } from '../types';\r\n\r\nexport const VirtualKey: FC<VirtualKeyProps> = ({ keyValue, onClick, className = '' }) => {\r\n const keyClasses = ['vk-key', className].filter(Boolean).join(' ');\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n className={keyClasses}\r\n onClick={() => onClick(keyValue)}\r\n data-testid={keyValue}\r\n >\r\n {keyValue}\r\n </button>\r\n );\r\n};\r\n\r\nexport default VirtualKey;\r\n","import type { FC } from 'react';\r\nimport type { KeyboardRowProps } from '../types';\r\n\r\nexport const KeyboardRow: FC<KeyboardRowProps> = ({ children, className = '' }) => {\r\n const rowClasses = ['vk-row', className].filter(Boolean).join(' ');\r\n\r\n return <div className={rowClasses}>{children}</div>;\r\n};\r\n\r\nexport default KeyboardRow;\r\n","import type { FC } from 'react';\r\nimport type { NumbersLayoutProps } from '../types';\r\nimport { BackspaceIcon, EnterIcon } from './icons';\r\nimport { SpecialKey } from './SpecialKey';\r\nimport { VirtualKey } from './VirtualKey';\r\nimport { KeyboardRow } from './KeyboardRow';\r\n\r\nexport const NumbersLayout: FC<NumbersLayoutProps> = ({\r\n currentLayoutData,\r\n onBackspace,\r\n onEnter,\r\n onKeyClick,\r\n capsLock,\r\n}) => {\r\n return (\r\n <div className=\"vk-layout vk-layout--numbers\" data-testid=\"keyboard-layout\">\r\n {currentLayoutData?.map((row, rowIndex) => (\r\n <KeyboardRow key={`num-row-${rowIndex}`}>\r\n {row?.map((key, keyIndex) => (\r\n <VirtualKey\r\n key={`num-${rowIndex}-${keyIndex}-${key}`}\r\n keyValue={key}\r\n onClick={onKeyClick}\r\n />\r\n ))}\r\n {rowIndex === 3 && (\r\n <SpecialKey\r\n key=\"enter-num\"\r\n type=\"enter\"\r\n icon={<EnterIcon />}\r\n onClick={onEnter}\r\n extraClass=\"enter-num\"\r\n text=\"Enter\"\r\n capsLock={capsLock}\r\n />\r\n )}\r\n {rowIndex === 2 && (\r\n <SpecialKey\r\n key=\"backspace-num\"\r\n type=\"backspace\"\r\n icon={<BackspaceIcon />}\r\n onClick={onBackspace}\r\n extraClass=\"backspace-num\"\r\n text=\"Backspace\"\r\n capsLock={capsLock}\r\n enableContinuousPress={true}\r\n />\r\n )}\r\n </KeyboardRow>\r\n ))}\r\n </div>\r\n );\r\n};\r\n\r\nexport default NumbersLayout;\r\n","import type { FC } from 'react';\r\nimport type { TextLayoutProps } from '../types';\r\nimport { BackspaceIcon, EnterIcon, SpacebarIcon, CapsLockIcon } from './icons';\r\nimport { SpecialKey } from './SpecialKey';\r\nimport { VirtualKey } from './VirtualKey';\r\nimport { KeyboardRow } from './KeyboardRow';\r\n\r\nexport const TextLayout: FC<TextLayoutProps> = ({\r\n inputType,\r\n currentLayoutData,\r\n onBackspace,\r\n onEnter,\r\n onSpace,\r\n onCapsToggle,\r\n onLayoutToggle,\r\n onKeyClick,\r\n capsLock,\r\n currentLayout,\r\n}) => {\r\n const renderSpecialKeysLeft = (rowIndex: number) => {\r\n switch (rowIndex) {\r\n case 3:\r\n return (\r\n currentLayout === 'letters' && (\r\n <SpecialKey\r\n key=\"caps\"\r\n type=\"caps\"\r\n icon={<CapsLockIcon />}\r\n onClick={onCapsToggle}\r\n extraClass=\"capsLock\"\r\n text=\"Caps Lock\"\r\n capsLock={capsLock}\r\n />\r\n )\r\n );\r\n default:\r\n return null;\r\n }\r\n };\r\n\r\n const renderSpecialKeysRight = (rowIndex: number) => {\r\n switch (rowIndex) {\r\n case 3:\r\n return (\r\n <SpecialKey\r\n key=\"backspace\"\r\n type=\"backspace\"\r\n icon={<BackspaceIcon />}\r\n onClick={onBackspace}\r\n extraClass=\"backspace\"\r\n text=\"Backspace\"\r\n enableContinuousPress={true}\r\n />\r\n );\r\n default:\r\n return null;\r\n }\r\n };\r\n\r\n return (\r\n <div className=\"vk-layout vk-layout--text\" data-testid=\"keyboard-layout\">\r\n {currentLayoutData?.map((row, rowIndex) => (\r\n <KeyboardRow key={`row-${rowIndex}`}>\r\n {renderSpecialKeysLeft(rowIndex)}\r\n {row.map((key, keyIndex) => {\r\n const displayKey = capsLock ? key.toUpperCase() : key.toLowerCase();\r\n return (\r\n <VirtualKey\r\n key={`${rowIndex}-${keyIndex}-${key}`}\r\n keyValue={displayKey}\r\n onClick={onKeyClick}\r\n />\r\n );\r\n })}\r\n {renderSpecialKeysRight(rowIndex)}\r\n </KeyboardRow>\r\n ))}\r\n\r\n <KeyboardRow>\r\n <SpecialKey\r\n key=\"layout\"\r\n type=\"layout\"\r\n icon={currentLayout === 'letters' ? '&123' : 'ABC'}\r\n onClick={onLayoutToggle}\r\n extraClass=\"layout\"\r\n text=\"\"\r\n />\r\n {inputType === 'email' && (\r\n <SpecialKey\r\n key=\"dot\"\r\n type=\"dot\"\r\n onClick={() => onKeyClick('.')}\r\n extraClass=\"dot\"\r\n icon={\".\"}\r\n />\r\n )}\r\n <SpecialKey\r\n key=\"space\"\r\n type=\"space\"\r\n icon={<SpacebarIcon />}\r\n onClick={onSpace}\r\n extraClass=\"space\"\r\n text=\"Space\"\r\n />\r\n {inputType === 'email' && (\r\n <SpecialKey\r\n key=\"at\"\r\n type=\"at\"\r\n icon={'@'}\r\n onClick={() => onKeyClick('@')}\r\n extraClass=\"at\"\r\n text=\"\"\r\n />\r\n )}\r\n <SpecialKey\r\n key=\"enter\"\r\n type=\"enter\"\r\n icon={<EnterIcon />}\r\n onClick={onEnter}\r\n extraClass=\"enter\"\r\n text=\"Enter\"\r\n />\r\n </KeyboardRow>\r\n </div>\r\n );\r\n};\r\n\r\nexport default TextLayout;\r\n","import type { FC } from 'react';\r\nimport type { KeyboardLayoutProps } from '../types';\r\nimport { NUMBERS_LAYOUT, QWERTY_LAYOUT, SYMBOLS_LAYOUT } from '../constants';\r\nimport { NumbersLayout } from './NumbersLayout';\r\nimport { TextLayout } from './TextLayout';\r\n\r\nexport const KeyboardLayout: FC<KeyboardLayoutProps> = ({\r\n currentLayout,\r\n capsLock,\r\n onKeyClick,\r\n onBackspace,\r\n onEnter,\r\n onSpace,\r\n onCapsToggle,\r\n onLayoutToggle,\r\n inputType,\r\n}) => {\r\n const currentLayoutData =\r\n currentLayout === 'letters'\r\n ? QWERTY_LAYOUT\r\n : currentLayout === 'symbols'\r\n ? SYMBOLS_LAYOUT\r\n : NUMBERS_LAYOUT;\r\n\r\n // Numbers layout has a different structure (4x5 grid)\r\n if (currentLayout === 'numbers') {\r\n return (\r\n <NumbersLayout\r\n currentLayoutData={currentLayoutData}\r\n onBackspace={onBackspace}\r\n onEnter={onEnter}\r\n onKeyClick={onKeyClick}\r\n capsLock={capsLock}\r\n currentLayout={currentLayout}\r\n />\r\n );\r\n }\r\n\r\n return (\r\n <TextLayout\r\n inputType={inputType}\r\n currentLayoutData={currentLayoutData}\r\n onBackspace={onBackspace}\r\n onEnter={onEnter}\r\n onSpace={onSpace}\r\n onCapsToggle={onCapsToggle}\r\n onLayoutToggle={onLayoutToggle}\r\n onKeyClick={onKeyClick}\r\n capsLock={capsLock}\r\n currentLayout={currentLayout}\r\n />\r\n );\r\n};\r\n\r\nexport default KeyboardLayout;\r\n","import type { FC, ReactNode, MouseEvent } from 'react';\r\n\r\ninterface VirtualKeyboardContainerProps {\r\n children: ReactNode;\r\n className?: string;\r\n}\r\n\r\nexport const VirtualKeyboardContainer: FC<VirtualKeyboardContainerProps> = ({\r\n children,\r\n className = '',\r\n}) => {\r\n const handleMouseDown = (e: MouseEvent) => {\r\n // Prevent the input from losing focus when clicking on keyboard\r\n e.preventDefault();\r\n };\r\n\r\n const handleClick = (e: MouseEvent) => {\r\n // Prevent any default click behavior\r\n e.preventDefault();\r\n e.stopPropagation();\r\n };\r\n\r\n const containerClasses = ['vk-container', className].filter(Boolean).join(' ');\r\n\r\n return (\r\n <div\r\n className={containerClasses}\r\n onMouseDown={handleMouseDown}\r\n onClick={handleClick}\r\n data-testid=\"keyboard-container\"\r\n >\r\n {children}\r\n </div>\r\n );\r\n};\r\n\r\nexport default VirtualKeyboardContainer;\r\n","import { useCallback, useEffect, useState, type FC } from 'react';\r\nimport type { VirtualKeyboardProps, LayoutType } from '../types';\r\nimport { useCaretManager, useHardwareKeyboard } from '../hooks';\r\nimport { validateValueUtil, getInitialLayout } from '../utils';\r\nimport { KeyboardLayout } from './KeyboardLayout';\r\nimport { VirtualKeyboardContainer } from './VirtualKeyboardContainer';\r\n\r\n/**\r\n * Virtual Keyboard Component\r\n *\r\n * A customizable on-screen keyboard for React applications.\r\n * Supports multiple layouts (QWERTY, symbols, numbers), hardware keyboard sync,\r\n * and touch device compatibility.\r\n */\r\nexport const VirtualKeyboard: FC<VirtualKeyboardProps> = ({\r\n focusedInputRef,\r\n isInputFocused,\r\n inputType = 'text',\r\n onEnterClick,\r\n onChange,\r\n className,\r\n defaultLayout = 'letters',\r\n validate,\r\n}) => {\r\n const [capsLock, setCapsLock] = useState(false);\r\n const { insertText, backspace } = useCaretManager(focusedInputRef);\r\n\r\n const [currentLayout, setCurrentLayout] = useState<LayoutType>(() =>\r\n getInitialLayout(inputType, defaultLayout)\r\n );\r\n\r\n const updateValue = useCallback(\r\n (next: string) => {\r\n // Run custom validation if provided\r\n if (validate && !validate(next)) return;\r\n\r\n // Run default validation based on input type\r\n if (!validateValueUtil(next, inputType)) return;\r\n\r\n insertText(next);\r\n onChange?.(focusedInputRef.current?.value ?? '');\r\n },\r\n [focusedInputRef, inputType, insertText, onChange, validate]\r\n );\r\n\r\n // Memoized handlers to avoid dependency issues\r\n const handleKeyClick = useCallback(\r\n (key: string) => {\r\n updateValue(key);\r\n },\r\n [updateValue]\r\n );\r\n\r\n const handleBackspace = useCallback(() => {\r\n if (focusedInputRef.current?.value.length === 0) return;\r\n backspace();\r\n onChange?.(focusedInputRef.current?.value ?? '');\r\n }, [backspace, focusedInputRef, onChange]);\r\n\r\n const handleEnter = useCallback(() => {\r\n onEnterClick?.();\r\n }, [onEnterClick]);\r\n\r\n const handleSpace = useCallback(() => {\r\n updateValue(' ');\r\n }, [updateValue]);\r\n\r\n const handleCapsToggle = useCallback(() => {\r\n setCapsLock((prev) => !prev);\r\n }, []);\r\n\r\n const handleLayoutToggle = useCallback(() => {\r\n if (inputType === 'number') {\r\n // For number inputs, don't allow switching away from numbers layout\r\n return;\r\n }\r\n setCurrentLayout((prev) => (prev === 'letters' ? 'symbols' : 'letters'));\r\n }, [inputType]);\r\n\r\n // Update layout when input type changes\r\n\r\n useEffect(() => {\r\n setCurrentLayout(getInitialLayout(inputType, defaultLayout));\r\n // Only update if dependencies change, but functionally mirrors the initial state\r\n }, [inputType, defaultLayout]);\r\n\r\n const keysHandlers = {\r\n onBackspace: handleBackspace,\r\n onEnter: handleEnter,\r\n onSpace: handleSpace,\r\n onCapsToggle: handleCapsToggle,\r\n onKeyClick: handleKeyClick,\r\n };\r\n\r\n useHardwareKeyboard({\r\n isInputFocused,\r\n ...keysHandlers,\r\n });\r\n\r\n return (\r\n <VirtualKeyboardContainer className={className}>\r\n <KeyboardLayout\r\n currentLayout={currentLayout}\r\n capsLock={capsLock}\r\n {...keysHandlers}\r\n onLayoutToggle={handleLayoutToggle}\r\n inputType={inputType}\r\n />\r\n </VirtualKeyboardContainer>\r\n );\r\n};\r\n\r\nexport default VirtualKeyboard;\r\n","import { useEffect, useRef, useState, type FC } from 'react';\r\nimport { VirtualKeyboard } from './VirtualKeyboard';\r\nimport { onEnterClickUtil, validateFocusInputs } from '../utils/globalKeyboardUtils';\r\nimport { useKeyboardScroll } from '../hooks/useKeyboardScroll';\r\n\r\nexport interface GlobalVirtualKeyboardProps {\r\n /**\r\n * Whether the virtual keyboard is enabled.\r\n * When false, the keyboard will not appear on input focus.\r\n * @default true\r\n */\r\n enabled?: boolean;\r\n /**\r\n * Additional CSS class name for the keyboard container\r\n */\r\n className?: string;\r\n /**\r\n * Callback fired when keyboard visibility changes\r\n */\r\n onVisibilityChange?: (isVisible: boolean) => void;\r\n /**\r\n * Callback fired when Enter key is pressed\r\n */\r\n onEnterClick?: () => void;\r\n /**\r\n * Callback fired when value changes\r\n */\r\n onChange?: (value: string) => void;\r\n}\r\n\r\n/**\r\n * GlobalVirtualKeyboard automatically shows a virtual keyboard when any\r\n * text input or textarea is focused. It handles:\r\n * - Automatic show/hide based on focus\r\n * - Scrolling inputs into view\r\n * - Form submission on Enter\r\n * - Input type detection for appropriate layouts\r\n *\r\n * @example\r\n * ```tsx\r\n * // Add once at the root of your app\r\n * function App() {\r\n * return (\r\n * <div>\r\n * <YourAppContent />\r\n * <GlobalVirtualKeyboard />\r\n * </div>\r\n * );\r\n * }\r\n * ```\r\n *\r\n * @example\r\n * ```tsx\r\n * // With controlled visibility\r\n * function App() {\r\n * const [keyboardEnabled, setKeyboardEnabled] = useState(true);\r\n *\r\n * return (\r\n * <div>\r\n * <button onClick={() => setKeyboardEnabled(!keyboardEnabled)}>\r\n * Toggle Keyboard\r\n * </button>\r\n * <GlobalVirtualKeyboard enabled={keyboardEnabled} />\r\n * </div>\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport const GlobalVirtualKeyboard: FC<GlobalVirtualKeyboardProps> = ({\r\n enabled = true,\r\n className,\r\n onVisibilityChange,\r\n onEnterClick,\r\n onChange,\r\n}) => {\r\n const keyboardContainerRef = useRef<HTMLSpanElement | null>(null);\r\n const [isVisible, setIsVisible] = useState(false);\r\n const [inputType, setInputType] = useState<string>('text');\r\n const focusedInputRef = useRef<HTMLInputElement | HTMLTextAreaElement | null>(null);\r\n const originalInputTypeRef = useRef<string>('text');\r\n const { scrollInput, resetScroll } = useKeyboardScroll(keyboardContainerRef);\r\n\r\n useEffect(() => {\r\n if (!enabled) {\r\n // Only update state if visible, to avoid unnecessary renders\r\n if (isVisible) {\r\n setTimeout(() => {\r\n setIsVisible(false);\r\n }, 0);\r\n onVisibilityChange?.(false);\r\n }\r\n return;\r\n }\r\n\r\n // Single global event listener using event delegation\r\n const handleFocus = (event: Event) => {\r\n const input = validateFocusInputs(event);\r\n if (!input) return;\r\n\r\n // Check if it's a textarea or input\r\n const isTextarea = input.tagName === 'TEXTAREA';\r\n // Textareas behave like text inputs\r\n const detectedInputType = isTextarea ? 'text' : (input as HTMLInputElement).type;\r\n\r\n setInputType(detectedInputType);\r\n setIsVisible(true);\r\n onVisibilityChange?.(true);\r\n focusedInputRef.current = input;\r\n\r\n // Temporarily change input type to text for caret to work (only for input elements)\r\n if (!isTextarea) {\r\n originalInputTypeRef.current = (input as HTMLInputElement).type;\r\n if ((input as HTMLInputElement).type !== 'text') {\r\n // Save selection position before changing type (changing type resets caret to 0)\r\n const selectionStart = input.selectionStart;\r\n const selectionEnd = input.selectionEnd;\r\n\r\n (input as HTMLInputElement).type = 'text';\r\n\r\n // Restore caret position after type change\r\n const caretPos = selectionStart ?? input.value.length;\r\n const caretEnd = selectionEnd ?? caretPos;\r\n input.setSelectionRange(caretPos, caretEnd);\r\n }\r\n }\r\n\r\n // Scroll input into view after keyboard is shown\r\n scrollInput(input);\r\n };\r\n\r\n const handleBlur = (event: Event) => {\r\n const input = validateFocusInputs(event);\r\n if (!input) return;\r\n\r\n // Restore input type (only for input elements, not textarea)\r\n const isTextarea = input.tagName === 'TEXTAREA';\r\n if (!isTextarea) {\r\n (input as HTMLInputElement).type = originalInputTypeRef.current;\r\n }\r\n\r\n if (focusedInputRef.current === input) {\r\n focusedInputRef.current = null;\r\n setIsVisible(false);\r\n onVisibilityChange?.(false);\r\n\r\n // Reset scroll position when keyboard is hidden\r\n resetScroll();\r\n }\r\n };\r\n\r\n // Add single event listeners to document (event delegation)\r\n document.addEventListener('focusin', handleFocus, true);\r\n document.addEventListener('focusout', handleBlur, true);\r\n\r\n return () => {\r\n document.removeEventListener('focusin', handleFocus, true);\r\n document.removeEventListener('focusout', handleBlur, true);\r\n };\r\n }, [enabled, scrollInput, resetScroll, onVisibilityChange]);\r\n\r\n const handleEnterClick = () => {\r\n setIsVisible(false);\r\n onVisibilityChange?.(false);\r\n onEnterClickUtil(focusedInputRef);\r\n onEnterClick?.();\r\n\r\n // Reset scroll position when Enter is clicked\r\n resetScroll();\r\n };\r\n\r\n if (!isVisible || !enabled) {\r\n return null;\r\n }\r\n\r\n return (\r\n <span ref={keyboardContainerRef}>\r\n <VirtualKeyboard\r\n focusedInputRef={focusedInputRef}\r\n isInputFocused={isVisible}\r\n inputType={inputType}\r\n onEnterClick={handleEnterClick}\r\n onChange={onChange}\r\n className={className}\r\n />\r\n </span>\r\n );\r\n};\r\n\r\nexport default GlobalVirtualKeyboard;\r\n\r\n"],"names":["setInputValueAndDispatchEvents","input","value","options","skipValueAssignment","proto","valueSetter","_a","useCaretManager","focusedInputRef","text","startRaw","endRaw","start","end","scrollTop","scrollLeft","newValue","caretAfter","newCaret","useContinuousPress","onPress","initialDelay","interval","shouldPreventDefault","timeoutRef","useRef","intervalRef","clear","useCallback","e","useHardwareKeyboard","isInputFocused","onBackspace","onEnter","onSpace","onCapsToggle","onKeyClick","useEffect","handleKeyboardKeyDown","event","key","KEYBOARD_HEIGHT_VH","INPUT_PADDING","TRANSITION_CLASS","TRANSITION_DURATION","shiftedElements","styleInjected","injectStyles","style","findContentElements","keyboardContainerRef","child","position","calculateShiftAmount","inputBottom","visibleHeight","overflow","scrollInputIntoView","resetScrollPosition","shiftAmount","contentElements","element","elementsToCleanup","useKeyboardScroll","handleScrollInput","handleResetScroll","validateValueUtil","inputType","getInitialLayout","defaultLayout","onEnterClickUtil","handleValueChangeUtil","validateFocusInputs","target","isInput","QWERTY_LAYOUT","SYMBOLS_LAYOUT","NUMBERS_LAYOUT","DEFAULT_THEME","BackspaceIcon","props","jsx","EnterIcon","SpacebarIcon","CapsLockIcon","SpecialKey","type","icon","onClick","extraClass","capsLock","enableContinuousPress","isCapsLockActive","keyClasses","continuousPressHandlers","buttonHandlers","jsxs","VirtualKey","keyValue","className","KeyboardRow","children","rowClasses","NumbersLayout","currentLayoutData","row","rowIndex","keyIndex","TextLayout","onLayoutToggle","currentLayout","renderSpecialKeysLeft","renderSpecialKeysRight","displayKey","KeyboardLayout","VirtualKeyboardContainer","handleMouseDown","handleClick","containerClasses","VirtualKeyboard","onEnterClick","onChange","validate","setCapsLock","useState","insertText","backspace","setCurrentLayout","updateValue","next","handleKeyClick","handleBackspace","_b","handleEnter","handleSpace","handleCapsToggle","prev","handleLayoutToggle","keysHandlers","GlobalVirtualKeyboard","enabled","onVisibilityChange","isVisible","setIsVisible","setInputType","originalInputTypeRef","scrollInput","resetScroll","handleFocus","isTextarea","detectedInputType","selectionStart","selectionEnd","caretPos","caretEnd","handleBlur","handleEnterClick"],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("react/jsx-runtime"),i=require("react"),g=(e,r,s={})=>{var n;const{skipValueAssignment:t=!1}=s;if(!t){const a=Object.getPrototypeOf(e),l=(n=Object.getOwnPropertyDescriptor(a,"value"))==null?void 0:n.set;l&&l.call(e,r)}e.dispatchEvent(new InputEvent("input",{bubbles:!0,cancelable:!0})),e.dispatchEvent(new Event("change",{bubbles:!0,cancelable:!0}))};function O(e){return{insertText:t=>{const n=e.current;if(!n||n.readOnly||n.disabled)return;const a=n.selectionStart,l=n.selectionEnd,o=a??n.value.length,u=l??n.value.length,p=n.scrollTop??0,f=n.scrollLeft??0,x=n.value.slice(0,o)+t+n.value.slice(u),v=o+t.length;g(n,x),n.focus(),n.setSelectionRange(v,v),"scrollTop"in n&&(n.scrollTop=p,n.scrollLeft=f)},backspace:()=>{const t=e.current;if(!t||t.readOnly||t.disabled)return;const n=t.selectionStart,a=t.selectionEnd,l=n??t.value.length,o=a??t.value.length,u=t.scrollTop??0,p=t.scrollLeft??0;if(l!==o){const f=t.value.slice(0,l)+t.value.slice(o);g(t,f),t.focus(),t.setSelectionRange(l,l)}else if(l>0){const f=t.value.slice(0,l-1)+t.value.slice(l),x=l-1;g(t,f),t.focus(),t.setSelectionRange(x,x)}"scrollTop"in t&&(t.scrollTop=u,t.scrollLeft=p)}}}function M(e,{initialDelay:r=500,interval:s=50,shouldPreventDefault:t=!0}={}){const n=i.useRef(),a=i.useRef(),l=i.useCallback(()=>{n.current&&(clearTimeout(n.current),n.current=void 0),a.current&&(clearInterval(a.current),a.current=void 0)},[]),o=i.useCallback(()=>{e(),n.current=setTimeout(()=>{a.current=setInterval(e,s)},r)},[e,r,s]);return{onMouseDown:u=>{u.preventDefault(),o()},onTouchStart:u=>{t&&u.preventDefault(),o()},onMouseUp:l,onMouseLeave:l,onTouchEnd:u=>{t&&u.preventDefault(),l()}}}function _({isInputFocused:e,onBackspace:r,onEnter:s,onSpace:t,onCapsToggle:n,onKeyClick:a}){i.useEffect(()=>{if(!e)return;const l=o=>{const u=o.key;switch(u){case"Backspace":o.preventDefault(),o.stopPropagation(),r();return;case"Enter":o.preventDefault(),s();return;case" ":o.preventDefault(),t();return;case"CapsLock":o.preventDefault(),n();return;default:u.length===1&&(o.preventDefault(),a(u))}};return document.addEventListener("keydown",l),()=>{document.removeEventListener("keydown",l)}},[e,r,s,t,n,a])}const ne=38,re=20,H="vk-keyboard-shift-transition",D=300;let j=[],$=!1;function ce(){if($)return;const e=document.createElement("style");e.id="vk-keyboard-shift-styles",e.textContent=`
|
|
2
|
+
.${H} {
|
|
3
|
+
transition: transform ${D}ms ease-out;
|
|
4
|
+
will-change: transform;
|
|
5
|
+
}
|
|
6
|
+
`,document.head.appendChild(e),$=!0}function le(e){var r;return e?Array.from(((r=e.parentElement)==null?void 0:r.children)??[]).filter(s=>{if(s===e)return!1;const{position:t}=window.getComputedStyle(s);return t!=="fixed"&&t!=="absolute"}):[]}function oe(e){const r=e.getBoundingClientRect().bottom,s=window.innerHeight*(1-ne/100),t=r+re-s;return t>0?t:0}function P(e,r){j.length>0&&A();const s=oe(e);if(s===0)return;const t=le(r);if(t.length!==0){ce(),j=t;for(const n of t)n.classList.add(H),n.style.transform=`translateY(-${s}px)`}}function A(){if(j.length===0)return;for(const r of j)document.body.contains(r)&&(r.style.transform="translateY(0)");const e=[...j];setTimeout(()=>{for(const r of e)document.body.contains(r)&&r.classList.remove(H)},D),j=[]}function Y(e){const r=i.useCallback(t=>{setTimeout(()=>{e!=null&&e.current&&P(t,e.current)},0)},[e]),s=i.useCallback(()=>{A()},[]);return i.useEffect(()=>()=>{A()},[]),{scrollInput:r,resetScroll:s}}const z=(e,r)=>{switch(r){case"number":return/^[0-9]*$/.test(e);case"email":return/^[a-zA-Z0-9@._+-]*$/.test(e);case"tel":return/^[0-9+\-() ]*$/.test(e);case"url":return/^[a-zA-Z0-9:/._-]*$/.test(e);case"password":return!0;default:return!0}},B=(e,r)=>e==="number"?"numbers":r,V=e=>{var r;if(e.current){const s=e.current;s.blur(),(r=s.form)==null||r.submit()}},ae=(e,r)=>{const s=e.current;s&&g(s,r)},N=e=>{const r=e.target,s=r.tagName==="INPUT";if(r.tagName==="TEXTAREA")return r;if(s){const n=r;return["checkbox","radio","range","date","time","color","month","week","file","hidden","submit","reset","button","image"].includes(n.type)?null:n}return null},F=[["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"]],G=[["1","2","3","4","5","6","7","8","9","0"],["!","@","#","$","%","^","&","*","(",")"],["-","_","=","+","[","]","{","}","\\","|"],[";",":",'"',"'",",",".","<",">","/","?"]],q=[["7","8","9","#"],["4","5","6","-"],["1","2","3"],[",","0","."]],ue={backgroundColor:"#1a1a1a",keyColor:"#444444",keyTextColor:"#ffffff",keyActiveColor:"#666666",keyHoverColor:"#555555",activeStateColor:"#4a90e2",keyBorderRadius:"0.5vw",keyFontSize:"32px",keyHeight:"100%"},K=e=>c.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",width:"1em",height:"1em",...e,children:c.jsx("path",{d:"M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H7.07L2.4 12l4.66-7H22v14zm-11.59-2L14 13.41 17.59 17 19 15.59 15.41 12 19 8.41 17.59 7 14 10.59 10.41 7 9 8.41 12.59 12 9 15.59z"})}),R=e=>c.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",width:"1em",height:"1em",...e,children:c.jsx("path",{d:"M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"})}),X=e=>c.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",width:"1em",height:"1em",...e,children:c.jsx("path",{d:"M18 9v4H6V9H4v6h16V9z"})}),Q=e=>c.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",width:"1em",height:"1em",style:{transform:"rotate(270deg)"},...e,children:c.jsx("path",{d:"M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"})}),b=({type:e,icon:r,onClick:s,extraClass:t="",text:n,capsLock:a=!1,enableContinuousPress:l=!1})=>{const o=e==="caps"&&a,u=["vk-key",`vk-key--${t}`,o?"vk-key--caps-active":""].filter(Boolean).join(" "),p=M(s,{initialDelay:500,interval:50}),f=l?p:{onClick:s};return c.jsxs("button",{type:"button",className:u,"data-testid":`${e}${o?"-active":""}`,"data-key":o?`${e}-active`:e,...f,children:[r&&r,n&&c.jsx("span",{className:"vk-key__text",children:n})]})},U=({keyValue:e,onClick:r,className:s=""})=>{const t=["vk-key",s].filter(Boolean).join(" ");return c.jsx("button",{type:"button",className:t,onClick:()=>r(e),"data-testid":e,children:e})},C=({children:e,className:r=""})=>{const s=["vk-row",r].filter(Boolean).join(" ");return c.jsx("div",{className:s,children:e})},W=({currentLayoutData:e,onBackspace:r,onEnter:s,onKeyClick:t,capsLock:n})=>c.jsx("div",{className:"vk-layout vk-layout--numbers","data-testid":"keyboard-layout",children:e==null?void 0:e.map((a,l)=>c.jsxs(C,{children:[a==null?void 0:a.map((o,u)=>c.jsx(U,{keyValue:o,onClick:t},`num-${l}-${u}-${o}`)),l===3&&c.jsx(b,{type:"enter",icon:c.jsx(R,{}),onClick:s,extraClass:"enter-num",text:"Enter",capsLock:n},"enter-num"),l===2&&c.jsx(b,{type:"backspace",icon:c.jsx(K,{}),onClick:r,extraClass:"backspace-num",text:"Backspace",capsLock:n,enableContinuousPress:!0},"backspace-num")]},`num-row-${l}`))}),Z=({inputType:e,currentLayoutData:r,onBackspace:s,onEnter:t,onSpace:n,onCapsToggle:a,onLayoutToggle:l,onKeyClick:o,capsLock:u,currentLayout:p})=>{const f=v=>{switch(v){case 3:return p==="letters"&&c.jsx(b,{type:"caps",icon:c.jsx(Q,{}),onClick:a,extraClass:"capsLock",text:"Caps Lock",capsLock:u},"caps");default:return null}},x=v=>{switch(v){case 3:return c.jsx(b,{type:"backspace",icon:c.jsx(K,{}),onClick:s,extraClass:"backspace",text:"Backspace",enableContinuousPress:!0},"backspace");default:return null}};return c.jsxs("div",{className:"vk-layout vk-layout--text","data-testid":"keyboard-layout",children:[r==null?void 0:r.map((v,k)=>c.jsxs(C,{children:[f(k),v.map((h,w)=>{const T=u?h.toUpperCase():h.toLowerCase();return c.jsx(U,{keyValue:T,onClick:o},`${k}-${w}-${h}`)}),x(k)]},`row-${k}`)),c.jsxs(C,{children:[c.jsx(b,{type:"layout",icon:p==="letters"?"&123":"ABC",onClick:l,extraClass:"layout",text:""},"layout"),e==="email"&&c.jsx(b,{type:"dot",onClick:()=>o("."),extraClass:"dot",icon:"."},"dot"),c.jsx(b,{type:"space",icon:c.jsx(X,{}),onClick:n,extraClass:"space",text:"Space"},"space"),e==="email"&&c.jsx(b,{type:"at",icon:"@",onClick:()=>o("@"),extraClass:"at",text:""},"at"),c.jsx(b,{type:"enter",icon:c.jsx(R,{}),onClick:t,extraClass:"enter",text:"Enter"},"enter")]})]})},J=({currentLayout:e,capsLock:r,onKeyClick:s,onBackspace:t,onEnter:n,onSpace:a,onCapsToggle:l,onLayoutToggle:o,inputType:u})=>{const p=e==="letters"?F:e==="symbols"?G:q;return e==="numbers"?c.jsx(W,{currentLayoutData:p,onBackspace:t,onEnter:n,onKeyClick:s,capsLock:r,currentLayout:e}):c.jsx(Z,{inputType:u,currentLayoutData:p,onBackspace:t,onEnter:n,onSpace:a,onCapsToggle:l,onLayoutToggle:o,onKeyClick:s,capsLock:r,currentLayout:e})},ee=({children:e,className:r=""})=>{const s=a=>{a.preventDefault()},t=a=>{a.preventDefault(),a.stopPropagation()},n=["vk-container",r].filter(Boolean).join(" ");return c.jsx("div",{className:n,onMouseDown:s,onClick:t,"data-testid":"keyboard-container",children:e})},te=({focusedInputRef:e,isInputFocused:r,inputType:s="text",onEnterClick:t,onChange:n,className:a,defaultLayout:l="letters",validate:o})=>{const[u,p]=i.useState(!1),{insertText:f,backspace:x}=O(e),[v,k]=i.useState(()=>B(s,l)),h=i.useCallback(m=>{var y;o&&!o(m)||z(m,s)&&(f(m),n==null||n(((y=e.current)==null?void 0:y.value)??""))},[e,s,f,n,o]),w=i.useCallback(m=>{h(m)},[h]),T=i.useCallback(()=>{var m,y;((m=e.current)==null?void 0:m.value.length)!==0&&(x(),n==null||n(((y=e.current)==null?void 0:y.value)??""))},[x,e,n]),S=i.useCallback(()=>{t==null||t()},[t]),d=i.useCallback(()=>{h(" ")},[h]),E=i.useCallback(()=>{p(m=>!m)},[]),I=i.useCallback(()=>{s!=="number"&&k(m=>m==="letters"?"symbols":"letters")},[s]);i.useEffect(()=>{k(B(s,l))},[s,l]);const L={onBackspace:T,onEnter:S,onSpace:d,onCapsToggle:E,onKeyClick:w};return _({isInputFocused:r,...L}),c.jsx(ee,{className:a,children:c.jsx(J,{currentLayout:v,capsLock:u,...L,onLayoutToggle:I,inputType:s})})},ie=({enabled:e=!0,className:r,onVisibilityChange:s,onEnterClick:t,onChange:n})=>{const a=i.useRef(null),[l,o]=i.useState(!1),[u,p]=i.useState("text"),f=i.useRef(null),x=i.useRef("text"),{scrollInput:v,resetScroll:k}=Y(a);i.useEffect(()=>{if(!e){l&&(setTimeout(()=>{o(!1)},0),s==null||s(!1));return}const w=S=>{const d=N(S);if(!d)return;const E=d.tagName==="TEXTAREA",I=E?"text":d.type;if(p(I),o(!0),s==null||s(!0),f.current=d,!E&&(x.current=d.type,d.type!=="text")){const L=d.selectionStart,m=d.selectionEnd;d.type="text";const y=L??d.value.length,se=m??y;d.setSelectionRange(y,se)}v(d)},T=S=>{const d=N(S);if(!d)return;d.tagName==="TEXTAREA"||(d.type=x.current),f.current===d&&(f.current=null,o(!1),s==null||s(!1),k())};return document.addEventListener("focusin",w,!0),document.addEventListener("focusout",T,!0),()=>{document.removeEventListener("focusin",w,!0),document.removeEventListener("focusout",T,!0)}},[e,v,k,s]);const h=()=>{o(!1),s==null||s(!1),V(f),t==null||t(),k()};return!l||!e?null:c.jsx("span",{ref:a,children:c.jsx(te,{focusedInputRef:f,isInputFocused:l,inputType:u,onEnterClick:h,onChange:n,className:r})})};exports.BackspaceIcon=K;exports.CapsLockIcon=Q;exports.DEFAULT_THEME=ue;exports.EnterIcon=R;exports.GlobalVirtualKeyboard=ie;exports.KeyboardLayout=J;exports.KeyboardRow=C;exports.NUMBERS_LAYOUT=q;exports.NumbersLayout=W;exports.QWERTY_LAYOUT=F;exports.SYMBOLS_LAYOUT=G;exports.SpacebarIcon=X;exports.SpecialKey=b;exports.TextLayout=Z;exports.VirtualKey=U;exports.VirtualKeyboard=te;exports.VirtualKeyboardContainer=ee;exports.getInitialLayout=B;exports.handleValueChangeUtil=ae;exports.onEnterClickUtil=V;exports.resetScrollPosition=A;exports.scrollInputIntoView=P;exports.setInputValueAndDispatchEvents=g;exports.useCaretManager=O;exports.useContinuousPress=M;exports.useHardwareKeyboard=_;exports.useKeyboardScroll=Y;exports.validateFocusInputs=N;exports.validateValueUtil=z;
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/utils/inputEvents.ts","../src/hooks/useCaretManager.ts","../src/hooks/useContinuousPress.ts","../src/hooks/useHardwareKeyboard.ts","../src/utils/scrollUtils.ts","../src/hooks/useKeyboardScroll.ts","../src/utils/validators.ts","../src/utils/globalKeyboardUtils.ts","../src/constants.ts","../src/components/icons/index.tsx","../src/components/SpecialKey.tsx","../src/components/VirtualKey.tsx","../src/components/KeyboardRow.tsx","../src/components/NumbersLayout.tsx","../src/components/TextLayout.tsx","../src/components/KeyboardLayout.tsx","../src/components/VirtualKeyboardContainer.tsx","../src/components/VirtualKeyboard.tsx","../src/components/GlobalVirtualKeyboard.tsx"],"sourcesContent":["import type { InputElement } from '../types';\r\n\r\n/**\r\n * Update an input's value using the native setter (so React tracks it)\r\n * and dispatch bubbled, cancelable input/change events to notify listeners.\r\n */\r\nexport const setInputValueAndDispatchEvents = (\r\n input: InputElement,\r\n value: string,\r\n options: { skipValueAssignment?: boolean } = {}\r\n): void => {\r\n const { skipValueAssignment = false } = options;\r\n\r\n if (!skipValueAssignment) {\r\n const proto = Object.getPrototypeOf(input);\r\n const valueSetter = Object.getOwnPropertyDescriptor(proto, 'value')?.set;\r\n\r\n if (valueSetter) {\r\n valueSetter.call(input, value);\r\n }\r\n }\r\n\r\n input.dispatchEvent(new InputEvent('input', { bubbles: true, cancelable: true }));\r\n input.dispatchEvent(new Event('change', { bubbles: true, cancelable: true }));\r\n};\r\n","import type { RefObject } from 'react';\r\nimport type { InputElement, UseCaretManagerReturn } from '../types';\r\nimport { setInputValueAndDispatchEvents } from '../utils/inputEvents';\r\n\r\n/**\r\n * Hook to manage caret position and text insertion/deletion in input elements\r\n */\r\nexport function useCaretManager(\r\n focusedInputRef: RefObject<InputElement | null>\r\n): UseCaretManagerReturn {\r\n /**\r\n * Insert text at the current caret position or replace selected text\r\n */\r\n const insertText = (text: string): void => {\r\n const input = focusedInputRef.current;\r\n if (!input) return;\r\n if (input.readOnly || input.disabled) return;\r\n\r\n const startRaw = input.selectionStart;\r\n const endRaw = input.selectionEnd;\r\n const start = startRaw == null ? input.value.length : startRaw;\r\n const end = endRaw == null ? input.value.length : endRaw;\r\n\r\n const scrollTop = (input as HTMLTextAreaElement).scrollTop ?? 0;\r\n const scrollLeft = (input as HTMLTextAreaElement).scrollLeft ?? 0;\r\n\r\n // Calculate new value\r\n const newValue = input.value.slice(0, start) + text + input.value.slice(end);\r\n const caretAfter = start + text.length;\r\n\r\n // Set value and dispatch events\r\n setInputValueAndDispatchEvents(input, newValue);\r\n\r\n // Restore focus & selection\r\n input.focus();\r\n input.setSelectionRange(caretAfter, caretAfter);\r\n\r\n if ('scrollTop' in input) {\r\n (input as HTMLTextAreaElement).scrollTop = scrollTop;\r\n (input as HTMLTextAreaElement).scrollLeft = scrollLeft;\r\n }\r\n };\r\n\r\n /**\r\n * Delete selected text or the character before the caret\r\n */\r\n const backspace = (): void => {\r\n const input = focusedInputRef.current;\r\n if (!input) return;\r\n if (input.readOnly || input.disabled) return;\r\n\r\n const startRaw = input.selectionStart;\r\n const endRaw = input.selectionEnd;\r\n const start = startRaw == null ? input.value.length : startRaw;\r\n const end = endRaw == null ? input.value.length : endRaw;\r\n\r\n const scrollTop = (input as HTMLTextAreaElement).scrollTop ?? 0;\r\n const scrollLeft = (input as HTMLTextAreaElement).scrollLeft ?? 0;\r\n\r\n // If selection present -> delete selection\r\n if (start !== end) {\r\n const newValue = input.value.slice(0, start) + input.value.slice(end);\r\n setInputValueAndDispatchEvents(input, newValue);\r\n input.focus();\r\n input.setSelectionRange(start, start);\r\n } else if (start > 0) {\r\n const newValue = input.value.slice(0, start - 1) + input.value.slice(start);\r\n const newCaret = start - 1;\r\n\r\n setInputValueAndDispatchEvents(input, newValue);\r\n input.focus();\r\n input.setSelectionRange(newCaret, newCaret);\r\n }\r\n\r\n if ('scrollTop' in input) {\r\n (input as HTMLTextAreaElement).scrollTop = scrollTop;\r\n (input as HTMLTextAreaElement).scrollLeft = scrollLeft;\r\n }\r\n };\r\n\r\n return {\r\n insertText,\r\n backspace,\r\n };\r\n}\r\n\r\nexport default useCaretManager;\r\n","import { useCallback, useRef } from 'react';\r\nimport type { ContinuousPressOptions } from '../types';\r\n\r\n/**\r\n * Hook for handling continuous press events (like holding backspace to delete multiple characters)\r\n */\r\nexport function useContinuousPress(\r\n onPress: () => void,\r\n {\r\n initialDelay = 500,\r\n interval = 50,\r\n shouldPreventDefault = true,\r\n }: ContinuousPressOptions = {}\r\n) {\r\n const timeoutRef = useRef<ReturnType<typeof setTimeout>>();\r\n const intervalRef = useRef<ReturnType<typeof setInterval>>();\r\n\r\n const clear = useCallback(() => {\r\n if (timeoutRef.current) {\r\n clearTimeout(timeoutRef.current);\r\n timeoutRef.current = undefined;\r\n }\r\n if (intervalRef.current) {\r\n clearInterval(intervalRef.current);\r\n intervalRef.current = undefined;\r\n }\r\n }, []);\r\n\r\n const start = useCallback(() => {\r\n onPress();\r\n timeoutRef.current = setTimeout(() => {\r\n intervalRef.current = setInterval(onPress, interval);\r\n }, initialDelay);\r\n }, [onPress, initialDelay, interval]);\r\n\r\n return {\r\n onMouseDown: (e: React.MouseEvent) => {\r\n e.preventDefault();\r\n start();\r\n },\r\n onTouchStart: (e: React.TouchEvent) => {\r\n if (shouldPreventDefault) e.preventDefault();\r\n start();\r\n },\r\n onMouseUp: clear,\r\n onMouseLeave: clear,\r\n onTouchEnd: (e: React.TouchEvent) => {\r\n if (shouldPreventDefault) e.preventDefault();\r\n clear();\r\n },\r\n };\r\n}\r\n\r\nexport default useContinuousPress;\r\n","import { useEffect } from 'react';\r\nimport type { HardwareKeyboardHandlers } from '../types';\r\n\r\n/**\r\n * Hook to keep virtual keyboard in sync with hardware keyboard events\r\n * (e.g., when pressing caps lock on hardware keyboard, virtual keyboard should reflect it)\r\n */\r\nexport function useHardwareKeyboard({\r\n isInputFocused,\r\n onBackspace,\r\n onEnter,\r\n onSpace,\r\n onCapsToggle,\r\n onKeyClick,\r\n}: HardwareKeyboardHandlers): void {\r\n useEffect(() => {\r\n if (!isInputFocused) return;\r\n\r\n const handleKeyboardKeyDown = (event: KeyboardEvent) => {\r\n const key = event.key;\r\n\r\n switch (key) {\r\n case 'Backspace':\r\n event.preventDefault();\r\n event.stopPropagation();\r\n onBackspace();\r\n return;\r\n case 'Enter':\r\n event.preventDefault();\r\n onEnter();\r\n return;\r\n case ' ':\r\n event.preventDefault();\r\n onSpace();\r\n return;\r\n case 'CapsLock':\r\n event.preventDefault();\r\n onCapsToggle();\r\n return;\r\n default:\r\n if (key.length === 1) {\r\n event.preventDefault();\r\n onKeyClick(key);\r\n }\r\n }\r\n };\r\n\r\n document.addEventListener('keydown', handleKeyboardKeyDown);\r\n\r\n return () => {\r\n document.removeEventListener('keydown', handleKeyboardKeyDown);\r\n };\r\n }, [isInputFocused, onBackspace, onEnter, onSpace, onCapsToggle, onKeyClick]);\r\n}\r\n\r\nexport default useHardwareKeyboard;\r\n","/**\r\n * Utility functions to handle layout shifting when virtual keyboard appears\r\n */\r\n\r\nconst KEYBOARD_HEIGHT_VH = 38;\r\nconst INPUT_PADDING = 20;\r\nconst TRANSITION_CLASS = 'vk-keyboard-shift-transition';\r\nconst TRANSITION_DURATION = 300;\r\n\r\nlet shiftedElements: HTMLElement[] = [];\r\nlet styleInjected = false;\r\n\r\nfunction injectStyles(): void {\r\n if (styleInjected) return;\r\n\r\n const style = document.createElement('style');\r\n style.id = 'vk-keyboard-shift-styles';\r\n style.textContent = `\r\n .${TRANSITION_CLASS} {\r\n transition: transform ${TRANSITION_DURATION}ms ease-out;\r\n will-change: transform;\r\n }\r\n `;\r\n document.head.appendChild(style);\r\n styleInjected = true;\r\n}\r\n\r\nfunction findContentElements(keyboardContainerRef: HTMLSpanElement | null): HTMLElement[] {\r\n if (!keyboardContainerRef) return [];\r\n return Array.from(keyboardContainerRef.parentElement?.children ?? []).filter(\r\n (child): child is HTMLElement => {\r\n if (child === keyboardContainerRef) return false;\r\n const { position } = window.getComputedStyle(child);\r\n return position !== 'fixed' && position !== 'absolute';\r\n }\r\n );\r\n}\r\n\r\nfunction calculateShiftAmount(input: HTMLElement): number {\r\n const inputBottom = input.getBoundingClientRect().bottom;\r\n const visibleHeight = window.innerHeight * (1 - KEYBOARD_HEIGHT_VH / 100);\r\n const overflow = inputBottom + INPUT_PADDING - visibleHeight;\r\n\r\n return overflow > 0 ? overflow : 0;\r\n}\r\n\r\n/**\r\n * Scroll the input into view by shifting content elements up\r\n */\r\nexport function scrollInputIntoView(input: HTMLInputElement | HTMLTextAreaElement, keyboardContainerRef: HTMLSpanElement): void {\r\n if (shiftedElements.length > 0) resetScrollPosition();\r\n\r\n const shiftAmount = calculateShiftAmount(input);\r\n if (shiftAmount === 0) return;\r\n\r\n const contentElements = findContentElements(keyboardContainerRef);\r\n\r\n if (contentElements.length === 0) return;\r\n\r\n injectStyles();\r\n shiftedElements = contentElements;\r\n\r\n for (const element of contentElements) {\r\n element.classList.add(TRANSITION_CLASS);\r\n element.style.transform = `translateY(-${shiftAmount}px)`;\r\n }\r\n}\r\n\r\n/**\r\n * Reset scroll position by removing transforms from shifted elements\r\n */\r\nexport function resetScrollPosition(): void {\r\n if (shiftedElements.length === 0) return;\r\n\r\n for (const element of shiftedElements) {\r\n if (document.body.contains(element)) {\r\n element.style.transform = 'translateY(0)';\r\n }\r\n }\r\n\r\n const elementsToCleanup = [...shiftedElements];\r\n setTimeout(() => {\r\n for (const element of elementsToCleanup) {\r\n if (document.body.contains(element)) {\r\n element.classList.remove(TRANSITION_CLASS);\r\n }\r\n }\r\n }, TRANSITION_DURATION);\r\n\r\n shiftedElements = [];\r\n}\r\n\r\n","import { useCallback, useEffect, RefObject } from 'react';\r\nimport { scrollInputIntoView, resetScrollPosition } from '../utils/scrollUtils';\r\n\r\nexport interface UseKeyboardScrollReturn {\r\n /** Scroll the input into view when keyboard appears */\r\n scrollInput: (input: HTMLInputElement | HTMLTextAreaElement) => void;\r\n /** Reset scroll position when keyboard hides */\r\n resetScroll: () => void;\r\n}\r\n\r\n/**\r\n * Hook to handle keyboard scrolling for input elements.\r\n * Automatically shifts content up when the virtual keyboard would cover the input.\r\n *\r\n * @returns Object with scroll and reset functions\r\n *\r\n * @example\r\n * ```tsx\r\n * const { scrollInput, resetScroll } = useKeyboardScroll();\r\n *\r\n * // When input is focused\r\n * scrollInput(inputElement);\r\n *\r\n * // When keyboard is hidden\r\n * resetScroll();\r\n * ```\r\n */\r\nexport function useKeyboardScroll(keyboardContainerRef: RefObject<HTMLSpanElement | null>): UseKeyboardScrollReturn {\r\n // Scroll input into view when keyboard appears\r\n const handleScrollInput = useCallback((input: HTMLInputElement | HTMLTextAreaElement) => {\r\n setTimeout(() => {\r\n if (!keyboardContainerRef?.current) return;\r\n scrollInputIntoView(input, keyboardContainerRef.current);\r\n }, 0);\r\n }, [keyboardContainerRef]);\r\n\r\n // Reset scroll position\r\n const handleResetScroll = useCallback(() => {\r\n resetScrollPosition();\r\n }, []);\r\n\r\n // Cleanup on unmount\r\n useEffect(() => {\r\n return () => {\r\n resetScrollPosition();\r\n };\r\n }, []);\r\n\r\n return {\r\n scrollInput: handleScrollInput,\r\n resetScroll: handleResetScroll,\r\n };\r\n}\r\n\r\nexport default useKeyboardScroll;\r\n\r\n","import type { HTMLInputTypeAttribute } from 'react';\r\nimport type { LayoutType } from '../types';\r\n\r\n/**\r\n * Validates a single character based on input type\r\n */\r\nexport const validateValueUtil = (\r\n value: string,\r\n inputType: HTMLInputTypeAttribute\r\n): boolean => {\r\n switch (inputType) {\r\n case 'number':\r\n // Only allow digits\r\n return /^[0-9]*$/.test(value);\r\n\r\n case 'email':\r\n // Allow alphanumeric, @, ., _, -, +\r\n return /^[a-zA-Z0-9@._+-]*$/.test(value);\r\n\r\n case 'tel':\r\n // Only allow digits, +, -, (, ), spaces\r\n return /^[0-9+\\-() ]*$/.test(value);\r\n\r\n case 'url':\r\n // Allow basic URL characters\r\n return /^[a-zA-Z0-9:/._-]*$/.test(value);\r\n\r\n case 'password':\r\n // Allow all characters for password\r\n return true;\r\n\r\n default:\r\n return true; // allow all characters for text input\r\n }\r\n};\r\n\r\n/**\r\n * Get the initial layout based on input type\r\n */\r\nexport const getInitialLayout = (\r\n inputType: HTMLInputTypeAttribute,\r\n defaultLayout: LayoutType\r\n): LayoutType => {\r\n if (inputType === 'number') {\r\n return 'numbers';\r\n }\r\n return defaultLayout;\r\n};\r\n","import type { RefObject } from 'react';\r\nimport { setInputValueAndDispatchEvents } from './inputEvents';\r\n\r\ntype FocusedInputRef = RefObject<HTMLInputElement | HTMLTextAreaElement | null>;\r\n\r\n/**\r\n * Handle Enter key click - blur input and submit form if applicable\r\n */\r\nexport const onEnterClickUtil = (focusedInputRef: FocusedInputRef): void => {\r\n if (focusedInputRef.current) {\r\n const input = focusedInputRef.current;\r\n input.blur();\r\n\r\n // If it's a form then submit the form\r\n input.form?.submit();\r\n }\r\n};\r\n\r\n/**\r\n * Handle value change on the focused input\r\n */\r\nexport const handleValueChangeUtil = (focusedInputRef: FocusedInputRef, value: string): void => {\r\n const input = focusedInputRef.current;\r\n if (!input) return;\r\n\r\n setInputValueAndDispatchEvents(input, value);\r\n};\r\n\r\n/**\r\n * Validate if the focused element should show the virtual keyboard\r\n * Returns the input/textarea element or null if it shouldn't show keyboard\r\n */\r\nexport const validateFocusInputs = (\r\n event: Event\r\n): HTMLInputElement | HTMLTextAreaElement | null => {\r\n const target = event.target as HTMLElement;\r\n\r\n // Check if the focused element matches our criteria\r\n const isInput = target.tagName === 'INPUT';\r\n const isTextarea = target.tagName === 'TEXTAREA';\r\n\r\n if (isTextarea) {\r\n return target as HTMLTextAreaElement;\r\n }\r\n\r\n if (isInput) {\r\n const input = target as HTMLInputElement;\r\n const excludedTypes = [\r\n 'checkbox',\r\n 'radio',\r\n 'range',\r\n 'date',\r\n 'time',\r\n 'color',\r\n 'month',\r\n 'week',\r\n 'file',\r\n 'hidden',\r\n 'submit',\r\n 'reset',\r\n 'button',\r\n 'image',\r\n ];\r\n\r\n if (excludedTypes.includes(input.type)) return null;\r\n return input;\r\n }\r\n\r\n return null;\r\n};\r\n\r\n","export const QWERTY_LAYOUT: string[][] = [\r\n ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],\r\n ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'],\r\n ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'],\r\n ['z', 'x', 'c', 'v', 'b', 'n', 'm'],\r\n];\r\n\r\nexport const SYMBOLS_LAYOUT: string[][] = [\r\n ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],\r\n ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')'],\r\n ['-', '_', '=', '+', '[', ']', '{', '}', '\\\\', '|'],\r\n [';', ':', '\"', \"'\", ',', '.', '<', '>', '/', '?'],\r\n];\r\n\r\nexport const NUMBERS_LAYOUT: string[][] = [\r\n ['7', '8', '9', '#'],\r\n ['4', '5', '6', '-'],\r\n ['1', '2', '3'],\r\n [',', '0', '.'],\r\n];\r\n\r\nexport const DEFAULT_THEME = {\r\n backgroundColor: '#1a1a1a',\r\n keyColor: '#444444',\r\n keyTextColor: '#ffffff',\r\n keyActiveColor: '#666666',\r\n keyHoverColor: '#555555',\r\n activeStateColor: '#4a90e2',\r\n keyBorderRadius: '0.5vw',\r\n keyFontSize: '32px',\r\n keyHeight: '100%',\r\n};\r\n","import type { FC, SVGProps } from 'react';\r\n\r\ntype IconProps = SVGProps<SVGSVGElement>;\r\n\r\nexport const BackspaceIcon: FC<IconProps> = (props) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"currentColor\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n {...props}\r\n >\r\n <path d=\"M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H7.07L2.4 12l4.66-7H22v14zm-11.59-2L14 13.41 17.59 17 19 15.59 15.41 12 19 8.41 17.59 7 14 10.59 10.41 7 9 8.41 12.59 12 9 15.59z\" />\r\n </svg>\r\n);\r\n\r\nexport const EnterIcon: FC<IconProps> = (props) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"currentColor\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n {...props}\r\n >\r\n <path d=\"M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z\" />\r\n </svg>\r\n);\r\n\r\nexport const SpacebarIcon: FC<IconProps> = (props) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"currentColor\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n {...props}\r\n >\r\n <path d=\"M18 9v4H6V9H4v6h16V9z\" />\r\n </svg>\r\n);\r\n\r\nexport const CapsLockIcon: FC<IconProps> = (props) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"currentColor\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n style={{ transform: 'rotate(270deg)' }}\r\n {...props}\r\n >\r\n <path d=\"M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z\" />\r\n </svg>\r\n);\r\n","import type { FC } from 'react';\r\nimport type { SpecialKeyProps } from '../types';\r\nimport { useContinuousPress } from '../hooks';\r\n\r\nexport const SpecialKey: FC<SpecialKeyProps> = ({\r\n type,\r\n icon,\r\n onClick,\r\n extraClass = '',\r\n text,\r\n capsLock = false,\r\n enableContinuousPress = false,\r\n}) => {\r\n const isCapsLockActive = type === 'caps' && capsLock;\r\n const keyClasses = [\r\n 'vk-key',\r\n `vk-key--${extraClass}`,\r\n isCapsLockActive ? 'vk-key--caps-active' : '',\r\n ]\r\n .filter(Boolean)\r\n .join(' ');\r\n\r\n // Use continuous press for backspace (hold to delete continuously)\r\n const continuousPressHandlers = useContinuousPress(onClick, {\r\n initialDelay: 500,\r\n interval: 50,\r\n });\r\n\r\n // Use continuous press handlers if enabled, otherwise use regular click\r\n const buttonHandlers = enableContinuousPress ? continuousPressHandlers : { onClick };\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n className={keyClasses}\r\n data-testid={`${type}${isCapsLockActive ? '-active' : ''}`}\r\n data-key={isCapsLockActive ? `${type}-active` : type}\r\n {...buttonHandlers}\r\n >\r\n {icon && icon}\r\n {text && <span className=\"vk-key__text\">{text}</span>}\r\n </button>\r\n );\r\n};\r\n\r\nexport default SpecialKey;\r\n","import type { FC } from 'react';\r\nimport type { VirtualKeyProps } from '../types';\r\n\r\nexport const VirtualKey: FC<VirtualKeyProps> = ({ keyValue, onClick, className = '' }) => {\r\n const keyClasses = ['vk-key', className].filter(Boolean).join(' ');\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n className={keyClasses}\r\n onClick={() => onClick(keyValue)}\r\n data-testid={keyValue}\r\n >\r\n {keyValue}\r\n </button>\r\n );\r\n};\r\n\r\nexport default VirtualKey;\r\n","import type { FC } from 'react';\r\nimport type { KeyboardRowProps } from '../types';\r\n\r\nexport const KeyboardRow: FC<KeyboardRowProps> = ({ children, className = '' }) => {\r\n const rowClasses = ['vk-row', className].filter(Boolean).join(' ');\r\n\r\n return <div className={rowClasses}>{children}</div>;\r\n};\r\n\r\nexport default KeyboardRow;\r\n","import type { FC } from 'react';\r\nimport type { NumbersLayoutProps } from '../types';\r\nimport { BackspaceIcon, EnterIcon } from './icons';\r\nimport { SpecialKey } from './SpecialKey';\r\nimport { VirtualKey } from './VirtualKey';\r\nimport { KeyboardRow } from './KeyboardRow';\r\n\r\nexport const NumbersLayout: FC<NumbersLayoutProps> = ({\r\n currentLayoutData,\r\n onBackspace,\r\n onEnter,\r\n onKeyClick,\r\n capsLock,\r\n}) => {\r\n return (\r\n <div className=\"vk-layout vk-layout--numbers\" data-testid=\"keyboard-layout\">\r\n {currentLayoutData?.map((row, rowIndex) => (\r\n <KeyboardRow key={`num-row-${rowIndex}`}>\r\n {row?.map((key, keyIndex) => (\r\n <VirtualKey\r\n key={`num-${rowIndex}-${keyIndex}-${key}`}\r\n keyValue={key}\r\n onClick={onKeyClick}\r\n />\r\n ))}\r\n {rowIndex === 3 && (\r\n <SpecialKey\r\n key=\"enter-num\"\r\n type=\"enter\"\r\n icon={<EnterIcon />}\r\n onClick={onEnter}\r\n extraClass=\"enter-num\"\r\n text=\"Enter\"\r\n capsLock={capsLock}\r\n />\r\n )}\r\n {rowIndex === 2 && (\r\n <SpecialKey\r\n key=\"backspace-num\"\r\n type=\"backspace\"\r\n icon={<BackspaceIcon />}\r\n onClick={onBackspace}\r\n extraClass=\"backspace-num\"\r\n text=\"Backspace\"\r\n capsLock={capsLock}\r\n enableContinuousPress={true}\r\n />\r\n )}\r\n </KeyboardRow>\r\n ))}\r\n </div>\r\n );\r\n};\r\n\r\nexport default NumbersLayout;\r\n","import type { FC } from 'react';\r\nimport type { TextLayoutProps } from '../types';\r\nimport { BackspaceIcon, EnterIcon, SpacebarIcon, CapsLockIcon } from './icons';\r\nimport { SpecialKey } from './SpecialKey';\r\nimport { VirtualKey } from './VirtualKey';\r\nimport { KeyboardRow } from './KeyboardRow';\r\n\r\nexport const TextLayout: FC<TextLayoutProps> = ({\r\n inputType,\r\n currentLayoutData,\r\n onBackspace,\r\n onEnter,\r\n onSpace,\r\n onCapsToggle,\r\n onLayoutToggle,\r\n onKeyClick,\r\n capsLock,\r\n currentLayout,\r\n}) => {\r\n const renderSpecialKeysLeft = (rowIndex: number) => {\r\n switch (rowIndex) {\r\n case 3:\r\n return (\r\n currentLayout === 'letters' && (\r\n <SpecialKey\r\n key=\"caps\"\r\n type=\"caps\"\r\n icon={<CapsLockIcon />}\r\n onClick={onCapsToggle}\r\n extraClass=\"capsLock\"\r\n text=\"Caps Lock\"\r\n capsLock={capsLock}\r\n />\r\n )\r\n );\r\n default:\r\n return null;\r\n }\r\n };\r\n\r\n const renderSpecialKeysRight = (rowIndex: number) => {\r\n switch (rowIndex) {\r\n case 3:\r\n return (\r\n <SpecialKey\r\n key=\"backspace\"\r\n type=\"backspace\"\r\n icon={<BackspaceIcon />}\r\n onClick={onBackspace}\r\n extraClass=\"backspace\"\r\n text=\"Backspace\"\r\n enableContinuousPress={true}\r\n />\r\n );\r\n default:\r\n return null;\r\n }\r\n };\r\n\r\n return (\r\n <div className=\"vk-layout vk-layout--text\" data-testid=\"keyboard-layout\">\r\n {currentLayoutData?.map((row, rowIndex) => (\r\n <KeyboardRow key={`row-${rowIndex}`}>\r\n {renderSpecialKeysLeft(rowIndex)}\r\n {row.map((key, keyIndex) => {\r\n const displayKey = capsLock ? key.toUpperCase() : key.toLowerCase();\r\n return (\r\n <VirtualKey\r\n key={`${rowIndex}-${keyIndex}-${key}`}\r\n keyValue={displayKey}\r\n onClick={onKeyClick}\r\n />\r\n );\r\n })}\r\n {renderSpecialKeysRight(rowIndex)}\r\n </KeyboardRow>\r\n ))}\r\n\r\n <KeyboardRow>\r\n <SpecialKey\r\n key=\"layout\"\r\n type=\"layout\"\r\n icon={currentLayout === 'letters' ? '&123' : 'ABC'}\r\n onClick={onLayoutToggle}\r\n extraClass=\"layout\"\r\n text=\"\"\r\n />\r\n {inputType === 'email' && (\r\n <SpecialKey\r\n key=\"dot\"\r\n type=\"dot\"\r\n onClick={() => onKeyClick('.')}\r\n extraClass=\"dot\"\r\n icon={\".\"}\r\n />\r\n )}\r\n <SpecialKey\r\n key=\"space\"\r\n type=\"space\"\r\n icon={<SpacebarIcon />}\r\n onClick={onSpace}\r\n extraClass=\"space\"\r\n text=\"Space\"\r\n />\r\n {inputType === 'email' && (\r\n <SpecialKey\r\n key=\"at\"\r\n type=\"at\"\r\n icon={'@'}\r\n onClick={() => onKeyClick('@')}\r\n extraClass=\"at\"\r\n text=\"\"\r\n />\r\n )}\r\n <SpecialKey\r\n key=\"enter\"\r\n type=\"enter\"\r\n icon={<EnterIcon />}\r\n onClick={onEnter}\r\n extraClass=\"enter\"\r\n text=\"Enter\"\r\n />\r\n </KeyboardRow>\r\n </div>\r\n );\r\n};\r\n\r\nexport default TextLayout;\r\n","import type { FC } from 'react';\r\nimport type { KeyboardLayoutProps } from '../types';\r\nimport { NUMBERS_LAYOUT, QWERTY_LAYOUT, SYMBOLS_LAYOUT } from '../constants';\r\nimport { NumbersLayout } from './NumbersLayout';\r\nimport { TextLayout } from './TextLayout';\r\n\r\nexport const KeyboardLayout: FC<KeyboardLayoutProps> = ({\r\n currentLayout,\r\n capsLock,\r\n onKeyClick,\r\n onBackspace,\r\n onEnter,\r\n onSpace,\r\n onCapsToggle,\r\n onLayoutToggle,\r\n inputType,\r\n}) => {\r\n const currentLayoutData =\r\n currentLayout === 'letters'\r\n ? QWERTY_LAYOUT\r\n : currentLayout === 'symbols'\r\n ? SYMBOLS_LAYOUT\r\n : NUMBERS_LAYOUT;\r\n\r\n // Numbers layout has a different structure (4x5 grid)\r\n if (currentLayout === 'numbers') {\r\n return (\r\n <NumbersLayout\r\n currentLayoutData={currentLayoutData}\r\n onBackspace={onBackspace}\r\n onEnter={onEnter}\r\n onKeyClick={onKeyClick}\r\n capsLock={capsLock}\r\n currentLayout={currentLayout}\r\n />\r\n );\r\n }\r\n\r\n return (\r\n <TextLayout\r\n inputType={inputType}\r\n currentLayoutData={currentLayoutData}\r\n onBackspace={onBackspace}\r\n onEnter={onEnter}\r\n onSpace={onSpace}\r\n onCapsToggle={onCapsToggle}\r\n onLayoutToggle={onLayoutToggle}\r\n onKeyClick={onKeyClick}\r\n capsLock={capsLock}\r\n currentLayout={currentLayout}\r\n />\r\n );\r\n};\r\n\r\nexport default KeyboardLayout;\r\n","import type { FC, ReactNode, MouseEvent } from 'react';\r\n\r\ninterface VirtualKeyboardContainerProps {\r\n children: ReactNode;\r\n className?: string;\r\n}\r\n\r\nexport const VirtualKeyboardContainer: FC<VirtualKeyboardContainerProps> = ({\r\n children,\r\n className = '',\r\n}) => {\r\n const handleMouseDown = (e: MouseEvent) => {\r\n // Prevent the input from losing focus when clicking on keyboard\r\n e.preventDefault();\r\n };\r\n\r\n const handleClick = (e: MouseEvent) => {\r\n // Prevent any default click behavior\r\n e.preventDefault();\r\n e.stopPropagation();\r\n };\r\n\r\n const containerClasses = ['vk-container', className].filter(Boolean).join(' ');\r\n\r\n return (\r\n <div\r\n className={containerClasses}\r\n onMouseDown={handleMouseDown}\r\n onClick={handleClick}\r\n data-testid=\"keyboard-container\"\r\n >\r\n {children}\r\n </div>\r\n );\r\n};\r\n\r\nexport default VirtualKeyboardContainer;\r\n","import { useCallback, useEffect, useState, type FC } from 'react';\r\nimport type { VirtualKeyboardProps, LayoutType } from '../types';\r\nimport { useCaretManager, useHardwareKeyboard } from '../hooks';\r\nimport { validateValueUtil, getInitialLayout } from '../utils';\r\nimport { KeyboardLayout } from './KeyboardLayout';\r\nimport { VirtualKeyboardContainer } from './VirtualKeyboardContainer';\r\n\r\n/**\r\n * Virtual Keyboard Component\r\n *\r\n * A customizable on-screen keyboard for React applications.\r\n * Supports multiple layouts (QWERTY, symbols, numbers), hardware keyboard sync,\r\n * and touch device compatibility.\r\n */\r\nexport const VirtualKeyboard: FC<VirtualKeyboardProps> = ({\r\n focusedInputRef,\r\n isInputFocused,\r\n inputType = 'text',\r\n onEnterClick,\r\n onChange,\r\n className,\r\n defaultLayout = 'letters',\r\n validate,\r\n}) => {\r\n const [capsLock, setCapsLock] = useState(false);\r\n const { insertText, backspace } = useCaretManager(focusedInputRef);\r\n\r\n const [currentLayout, setCurrentLayout] = useState<LayoutType>(() =>\r\n getInitialLayout(inputType, defaultLayout)\r\n );\r\n\r\n const updateValue = useCallback(\r\n (next: string) => {\r\n // Run custom validation if provided\r\n if (validate && !validate(next)) return;\r\n\r\n // Run default validation based on input type\r\n if (!validateValueUtil(next, inputType)) return;\r\n\r\n insertText(next);\r\n onChange?.(focusedInputRef.current?.value ?? '');\r\n },\r\n [focusedInputRef, inputType, insertText, onChange, validate]\r\n );\r\n\r\n // Memoized handlers to avoid dependency issues\r\n const handleKeyClick = useCallback(\r\n (key: string) => {\r\n updateValue(key);\r\n },\r\n [updateValue]\r\n );\r\n\r\n const handleBackspace = useCallback(() => {\r\n if (focusedInputRef.current?.value.length === 0) return;\r\n backspace();\r\n onChange?.(focusedInputRef.current?.value ?? '');\r\n }, [backspace, focusedInputRef, onChange]);\r\n\r\n const handleEnter = useCallback(() => {\r\n onEnterClick?.();\r\n }, [onEnterClick]);\r\n\r\n const handleSpace = useCallback(() => {\r\n updateValue(' ');\r\n }, [updateValue]);\r\n\r\n const handleCapsToggle = useCallback(() => {\r\n setCapsLock((prev) => !prev);\r\n }, []);\r\n\r\n const handleLayoutToggle = useCallback(() => {\r\n if (inputType === 'number') {\r\n // For number inputs, don't allow switching away from numbers layout\r\n return;\r\n }\r\n setCurrentLayout((prev) => (prev === 'letters' ? 'symbols' : 'letters'));\r\n }, [inputType]);\r\n\r\n // Update layout when input type changes\r\n\r\n useEffect(() => {\r\n setCurrentLayout(getInitialLayout(inputType, defaultLayout));\r\n // Only update if dependencies change, but functionally mirrors the initial state\r\n }, [inputType, defaultLayout]);\r\n\r\n const keysHandlers = {\r\n onBackspace: handleBackspace,\r\n onEnter: handleEnter,\r\n onSpace: handleSpace,\r\n onCapsToggle: handleCapsToggle,\r\n onKeyClick: handleKeyClick,\r\n };\r\n\r\n useHardwareKeyboard({\r\n isInputFocused,\r\n ...keysHandlers,\r\n });\r\n\r\n return (\r\n <VirtualKeyboardContainer className={className}>\r\n <KeyboardLayout\r\n currentLayout={currentLayout}\r\n capsLock={capsLock}\r\n {...keysHandlers}\r\n onLayoutToggle={handleLayoutToggle}\r\n inputType={inputType}\r\n />\r\n </VirtualKeyboardContainer>\r\n );\r\n};\r\n\r\nexport default VirtualKeyboard;\r\n","import { useEffect, useRef, useState, type FC } from 'react';\r\nimport { VirtualKeyboard } from './VirtualKeyboard';\r\nimport { onEnterClickUtil, validateFocusInputs } from '../utils/globalKeyboardUtils';\r\nimport { useKeyboardScroll } from '../hooks/useKeyboardScroll';\r\n\r\nexport interface GlobalVirtualKeyboardProps {\r\n /**\r\n * Whether the virtual keyboard is enabled.\r\n * When false, the keyboard will not appear on input focus.\r\n * @default true\r\n */\r\n enabled?: boolean;\r\n /**\r\n * Additional CSS class name for the keyboard container\r\n */\r\n className?: string;\r\n /**\r\n * Callback fired when keyboard visibility changes\r\n */\r\n onVisibilityChange?: (isVisible: boolean) => void;\r\n /**\r\n * Callback fired when Enter key is pressed\r\n */\r\n onEnterClick?: () => void;\r\n /**\r\n * Callback fired when value changes\r\n */\r\n onChange?: (value: string) => void;\r\n}\r\n\r\n/**\r\n * GlobalVirtualKeyboard automatically shows a virtual keyboard when any\r\n * text input or textarea is focused. It handles:\r\n * - Automatic show/hide based on focus\r\n * - Scrolling inputs into view\r\n * - Form submission on Enter\r\n * - Input type detection for appropriate layouts\r\n *\r\n * @example\r\n * ```tsx\r\n * // Add once at the root of your app\r\n * function App() {\r\n * return (\r\n * <div>\r\n * <YourAppContent />\r\n * <GlobalVirtualKeyboard />\r\n * </div>\r\n * );\r\n * }\r\n * ```\r\n *\r\n * @example\r\n * ```tsx\r\n * // With controlled visibility\r\n * function App() {\r\n * const [keyboardEnabled, setKeyboardEnabled] = useState(true);\r\n *\r\n * return (\r\n * <div>\r\n * <button onClick={() => setKeyboardEnabled(!keyboardEnabled)}>\r\n * Toggle Keyboard\r\n * </button>\r\n * <GlobalVirtualKeyboard enabled={keyboardEnabled} />\r\n * </div>\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport const GlobalVirtualKeyboard: FC<GlobalVirtualKeyboardProps> = ({\r\n enabled = true,\r\n className,\r\n onVisibilityChange,\r\n onEnterClick,\r\n onChange,\r\n}) => {\r\n const keyboardContainerRef = useRef<HTMLSpanElement | null>(null);\r\n const [isVisible, setIsVisible] = useState(false);\r\n const [inputType, setInputType] = useState<string>('text');\r\n const focusedInputRef = useRef<HTMLInputElement | HTMLTextAreaElement | null>(null);\r\n const originalInputTypeRef = useRef<string>('text');\r\n const { scrollInput, resetScroll } = useKeyboardScroll(keyboardContainerRef);\r\n\r\n useEffect(() => {\r\n if (!enabled) {\r\n // Only update state if visible, to avoid unnecessary renders\r\n if (isVisible) {\r\n setTimeout(() => {\r\n setIsVisible(false);\r\n }, 0);\r\n onVisibilityChange?.(false);\r\n }\r\n return;\r\n }\r\n\r\n // Single global event listener using event delegation\r\n const handleFocus = (event: Event) => {\r\n const input = validateFocusInputs(event);\r\n if (!input) return;\r\n\r\n // Check if it's a textarea or input\r\n const isTextarea = input.tagName === 'TEXTAREA';\r\n // Textareas behave like text inputs\r\n const detectedInputType = isTextarea ? 'text' : (input as HTMLInputElement).type;\r\n\r\n setInputType(detectedInputType);\r\n setIsVisible(true);\r\n onVisibilityChange?.(true);\r\n focusedInputRef.current = input;\r\n\r\n // Temporarily change input type to text for caret to work (only for input elements)\r\n if (!isTextarea) {\r\n originalInputTypeRef.current = (input as HTMLInputElement).type;\r\n if ((input as HTMLInputElement).type !== 'text') {\r\n // Save selection position before changing type (changing type resets caret to 0)\r\n const selectionStart = input.selectionStart;\r\n const selectionEnd = input.selectionEnd;\r\n\r\n (input as HTMLInputElement).type = 'text';\r\n\r\n // Restore caret position after type change\r\n const caretPos = selectionStart ?? input.value.length;\r\n const caretEnd = selectionEnd ?? caretPos;\r\n input.setSelectionRange(caretPos, caretEnd);\r\n }\r\n }\r\n\r\n // Scroll input into view after keyboard is shown\r\n scrollInput(input);\r\n };\r\n\r\n const handleBlur = (event: Event) => {\r\n const input = validateFocusInputs(event);\r\n if (!input) return;\r\n\r\n // Restore input type (only for input elements, not textarea)\r\n const isTextarea = input.tagName === 'TEXTAREA';\r\n if (!isTextarea) {\r\n (input as HTMLInputElement).type = originalInputTypeRef.current;\r\n }\r\n\r\n if (focusedInputRef.current === input) {\r\n focusedInputRef.current = null;\r\n setIsVisible(false);\r\n onVisibilityChange?.(false);\r\n\r\n // Reset scroll position when keyboard is hidden\r\n resetScroll();\r\n }\r\n };\r\n\r\n // Add single event listeners to document (event delegation)\r\n document.addEventListener('focusin', handleFocus, true);\r\n document.addEventListener('focusout', handleBlur, true);\r\n\r\n return () => {\r\n document.removeEventListener('focusin', handleFocus, true);\r\n document.removeEventListener('focusout', handleBlur, true);\r\n };\r\n }, [enabled, scrollInput, resetScroll, onVisibilityChange]);\r\n\r\n const handleEnterClick = () => {\r\n setIsVisible(false);\r\n onVisibilityChange?.(false);\r\n onEnterClickUtil(focusedInputRef);\r\n onEnterClick?.();\r\n\r\n // Reset scroll position when Enter is clicked\r\n resetScroll();\r\n };\r\n\r\n if (!isVisible || !enabled) {\r\n return null;\r\n }\r\n\r\n return (\r\n <span ref={keyboardContainerRef}>\r\n <VirtualKeyboard\r\n focusedInputRef={focusedInputRef}\r\n isInputFocused={isVisible}\r\n inputType={inputType}\r\n onEnterClick={handleEnterClick}\r\n onChange={onChange}\r\n className={className}\r\n />\r\n </span>\r\n );\r\n};\r\n\r\nexport default GlobalVirtualKeyboard;\r\n\r\n"],"names":["setInputValueAndDispatchEvents","input","value","options","skipValueAssignment","proto","valueSetter","_a","useCaretManager","focusedInputRef","text","startRaw","endRaw","start","end","scrollTop","scrollLeft","newValue","caretAfter","newCaret","useContinuousPress","onPress","initialDelay","interval","shouldPreventDefault","timeoutRef","useRef","intervalRef","clear","useCallback","e","useHardwareKeyboard","isInputFocused","onBackspace","onEnter","onSpace","onCapsToggle","onKeyClick","useEffect","handleKeyboardKeyDown","event","key","KEYBOARD_HEIGHT_VH","INPUT_PADDING","TRANSITION_CLASS","TRANSITION_DURATION","shiftedElements","styleInjected","injectStyles","style","findContentElements","keyboardContainerRef","child","position","calculateShiftAmount","inputBottom","visibleHeight","overflow","scrollInputIntoView","resetScrollPosition","shiftAmount","contentElements","element","elementsToCleanup","useKeyboardScroll","handleScrollInput","handleResetScroll","validateValueUtil","inputType","getInitialLayout","defaultLayout","onEnterClickUtil","handleValueChangeUtil","validateFocusInputs","target","isInput","QWERTY_LAYOUT","SYMBOLS_LAYOUT","NUMBERS_LAYOUT","DEFAULT_THEME","BackspaceIcon","props","jsx","EnterIcon","SpacebarIcon","CapsLockIcon","SpecialKey","type","icon","onClick","extraClass","capsLock","enableContinuousPress","isCapsLockActive","keyClasses","continuousPressHandlers","buttonHandlers","jsxs","VirtualKey","keyValue","className","KeyboardRow","children","rowClasses","NumbersLayout","currentLayoutData","row","rowIndex","keyIndex","TextLayout","onLayoutToggle","currentLayout","renderSpecialKeysLeft","renderSpecialKeysRight","displayKey","KeyboardLayout","VirtualKeyboardContainer","handleMouseDown","handleClick","containerClasses","VirtualKeyboard","onEnterClick","onChange","validate","setCapsLock","useState","insertText","backspace","setCurrentLayout","updateValue","next","handleKeyClick","handleBackspace","_b","handleEnter","handleSpace","handleCapsToggle","prev","handleLayoutToggle","keysHandlers","GlobalVirtualKeyboard","enabled","onVisibilityChange","isVisible","setIsVisible","setInputType","originalInputTypeRef","scrollInput","resetScroll","handleFocus","isTextarea","detectedInputType","selectionStart","selectionEnd","caretPos","caretEnd","handleBlur","handleEnterClick"],"mappings":"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"}
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--vk-bg-color: #1a1a1a;--vk-key-color: #444444;--vk-key-text-color: #ffffff;--vk-key-active-color: #666666;--vk-key-hover-color: #555555;--vk-active-state-color: #4a90e2;--vk-key-border-radius: clamp(4px, .5vw, 8px);--vk-key-font-size: clamp(14px, 2.5vw, 32px);--vk-special-key-font-size: clamp(20px, 2vw, 28px);--vk-gap: clamp(3px, .6vw, 10px);--vk-padding: clamp(6px, 1vw, 16px);--vk-height: 45vh;--vk-z-index: 2001;--vk-numbers-width: 50%}.vk-container{position:fixed;bottom:0;left:0;right:0;z-index:var(--vk-z-index);height:var(--vk-height);max-height:400px;min-height:180px;background-color:var(--vk-bg-color);box-shadow:0 -2px 12px #00000080;padding:var(--vk-padding);box-sizing:border-box}.vk-container *{box-sizing:border-box}.vk-layout{display:flex;flex-direction:column;gap:var(--vk-gap);justify-content:center;height:100%;max-width:1400px;margin:0 auto}.vk-layout--numbers{width:var(--vk-numbers-width);max-width:400px;min-width:200px;margin-inline:auto}.vk-layout--numbers .vk-key__text{display:none}.vk-row{display:flex;gap:var(--vk-gap);justify-content:center;align-items:center;flex:1;min-height:0}.vk-key{height:100%;min-height:32px;display:flex;font-size:var(--vk-key-font-size);align-items:center;justify-content:center;gap:clamp(2px,.4vw,8px);flex:0 1 100%;background-color:var(--vk-key-color);color:var(--vk-key-text-color);border-radius:var(--vk-key-border-radius);border:none;cursor:pointer;transition:background-color .15s ease,transform .1s ease;font-family:inherit;user-select:none;-webkit-user-select:none;-webkit-tap-highlight-color:transparent;touch-action:manipulation;padding:0 clamp(4px,.5vw,12px)}@media (hover: hover) and (pointer: fine){.vk-key:hover:not(.vk-key--caps-active){background-color:var(--vk-key-hover-color)}}.vk-key:active:not(:disabled){background-color:var(--vk-key-active-color);transform:scale(.97)}.vk-key:disabled{opacity:.5;cursor:not-allowed}.vk-key:focus{outline:none}.vk-key:focus-visible{outline:2px solid var(--vk-active-state-color);outline-offset:2px}.vk-key--space{flex:0 1 300%;font-size:var(--vk-special-key-font-size)}.vk-key--layout,.vk-key--enter,.vk-key--enter-num{flex:0 1 100%;font-size:var(--vk-special-key-font-size)}.vk-key--backspace{flex:0 1 150%;font-size:var(--vk-special-key-font-size)}.vk-key--backspace-num{flex:0 1 100%;font-size:var(--vk-special-key-font-size)}.vk-key--capsLock{flex:0 1 170%;font-size:var(--vk-special-key-font-size)}.vk-key--at,.vk-key--dot{flex:0 1 70%}.vk-key--caps-active{background-color:var(--vk-active-state-color);color:var(--vk-key-text-color);border-color:var(--vk-active-state-color)}.vk-key svg{width:clamp(20px,1.2em,28px);height:clamp(20px,1.2em,28px);flex-shrink:0}.vk-key__text{margin-left:.3em}@media (min-width: 1400px){:root{--vk-height: 38vh}}@media (min-width: 1024px) and (max-width: 1399px){:root{--vk-height: 40vh}}@media (min-width: 768px) and (max-width: 1023px){:root{--vk-height: 38vh;--vk-numbers-width: 60%}.vk-key--space{flex:0 1 100%}}@media (min-width: 600px) and (max-width: 767px){:root{--vk-height: 42vh;--vk-numbers-width: 65%;--vk-special-key-font-size: clamp(10px, 3vw, 24px)}.vk-key--capsLock,.vk-key--backspace{flex:0 1 130%}.vk-key__text{display:none}}@media (min-width: 480px) and (max-width: 599px){:root{--vk-height: 45vh;--vk-numbers-width: 75%}.vk-key--capsLock,.vk-key--backspace{flex:0 1 120%}.vk-key__text{display:none}}@media (max-width: 479px){:root{--vk-height: 48vh;--vk-numbers-width: 85%}.vk-layout--numbers{min-width:160px}.vk-key--capsLock,.vk-key--backspace{flex:0 1 100%}.vk-key__text{display:none}}@media (max-width: 319px){:root{--vk-height: 50vh;--vk-numbers-width: 95%}.vk-key--space{flex:0 1 40%}.vk-key--layout,.vk-key--enter{flex:0 1 22%}.vk-key__text{display:none}}@media (orientation: landscape) and (max-height: 500px){:root{--vk-height: 55vh;--vk-gap: clamp(2px, .4vw, 6px);--vk-padding: clamp(4px, .5vw, 10px)}.vk-container{max-height:280px}.vk-key{min-height:28px}.vk-key__text{display:none}}@media (orientation: landscape) and (max-height: 400px){:root{--vk-height: 65vh}.vk-container{max-height:240px;min-height:140px}.vk-key{min-height:24px}}@media (-webkit-min-device-pixel-ratio: 2),(min-resolution: 192dpi){.vk-key{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}}@media (prefers-color-scheme: light){.vk-container--auto{--vk-bg-color: #f0f0f0;--vk-key-color: #ffffff;--vk-key-text-color: #333333;--vk-key-hover-color: #e8e8e8;--vk-key-active-color: #d0d0d0}}.vk-container--light{--vk-bg-color: #f0f0f0;--vk-key-color: #ffffff;--vk-key-text-color: #333333;--vk-key-hover-color: #e8e8e8;--vk-key-active-color: #d0d0d0;box-shadow:0 -2px 12px #00000026}.vk-container--blue{--vk-bg-color: #1e3a5f;--vk-key-color: #2d5a8c;--vk-key-hover-color: #3a6fa0;--vk-key-active-color: #4a8ab8;--vk-active-state-color: #00d4ff}.vk-container--purple{--vk-bg-color: #2d1b4e;--vk-key-color: #4a2c7a;--vk-key-hover-color: #5d3a94;--vk-key-active-color: #7048ad;--vk-active-state-color: #b388ff}@media (prefers-reduced-motion: reduce){.vk-key{transition:none}.vk-key:active:not(:disabled){transform:none}}@media (prefers-contrast: high){.vk-key{border:1px solid var(--vk-key-text-color)}.vk-key:focus-visible{outline-width:3px}}@media (pointer: coarse){.vk-key{min-height:40px}:root{--vk-gap: clamp(4px, .7vw, 10px)}}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "reactjs-virtual-keyboard",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "A customizable virtual keyboard component for React applications with support for multiple layouts, hardware keyboard sync, and touch devices",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.esm.js",
|
|
11
|
+
"require": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./styles.css": "./dist/styles.css"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "vite build && tsc --emitDeclarationOnly",
|
|
22
|
+
"dev": "vite build --watch",
|
|
23
|
+
"lint": "biome check src/",
|
|
24
|
+
"prepublishOnly": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"virtual-keyboard",
|
|
28
|
+
"keyboard",
|
|
29
|
+
"reactjs-virtual-keyboard",
|
|
30
|
+
"react",
|
|
31
|
+
"react-keyboard",
|
|
32
|
+
"on-screen-keyboard",
|
|
33
|
+
"touch-keyboard",
|
|
34
|
+
"input",
|
|
35
|
+
"typescript"
|
|
36
|
+
],
|
|
37
|
+
"author": "HydraFacial",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://github.com/hydrafacial/virtual-keyboard.git"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"react": ">=17.0.0",
|
|
45
|
+
"react-dom": ">=17.0.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/react": "^18.2.0",
|
|
49
|
+
"@types/react-dom": "^18.2.0",
|
|
50
|
+
"react": "^18.2.0",
|
|
51
|
+
"react-dom": "^18.2.0",
|
|
52
|
+
"typescript": "^5.3.0",
|
|
53
|
+
"vite": "^5.0.0",
|
|
54
|
+
"vite-plugin-dts": "^3.7.0"
|
|
55
|
+
},
|
|
56
|
+
"sideEffects": [
|
|
57
|
+
"*.css"
|
|
58
|
+
]
|
|
59
|
+
}
|