UNPKG

reactjs-virtual-keyboard

Version:

A customizable virtual keyboard component for React applications with support for multiple layouts, multi-language support, hardware keyboard sync, and touch devices

889 lines (888 loc) 26.1 kB
import { jsx, jsxs } from "react/jsx-runtime"; import { useRef, useCallback, useEffect, memo, useState } from "react"; const setInputValueAndDispatchEvents = (input, value, options = {}) => { var _a; const { skipValueAssignment = false } = options; if (!skipValueAssignment) { const proto = Object.getPrototypeOf(input); const valueSetter = (_a = Object.getOwnPropertyDescriptor(proto, "value")) == null ? void 0 : _a.set; if (valueSetter) { valueSetter.call(input, value); } } input.dispatchEvent(new InputEvent("input", { bubbles: true, cancelable: true })); input.dispatchEvent(new Event("change", { bubbles: true, cancelable: true })); }; const validateValueUtil = (value, inputType) => { switch (inputType) { case "number": return /^[0-9]*$/.test(value); case "email": return /^[a-zA-Z0-9@._+-]*$/.test(value); case "tel": return /^[0-9+\-() ]*$/.test(value); case "url": return /^[a-zA-Z0-9:/._-]*$/.test(value); case "password": return true; default: return true; } }; const getInitialLayout = (inputType, defaultLayout) => { if (inputType === "number") { return "numbers"; } return defaultLayout; }; const KEYBOARD_HEIGHT_VH = 38; const INPUT_PADDING = 20; const TRANSITION_CLASS = "vk-keyboard-shift-transition"; const TRANSITION_DURATION = 300; let shiftedElements = []; let styleInjected = false; function injectStyles() { if (styleInjected) return; const style = document.createElement("style"); style.id = "vk-keyboard-shift-styles"; style.textContent = ` .${TRANSITION_CLASS} { transition: transform ${TRANSITION_DURATION}ms ease-out; will-change: transform; } `; document.head.appendChild(style); styleInjected = true; } function findContentElements(keyboardContainerRef) { var _a; if (!keyboardContainerRef) return []; return Array.from(((_a = keyboardContainerRef.parentElement) == null ? void 0 : _a.children) ?? []).filter( (child) => { if (child === keyboardContainerRef) return false; const { position } = window.getComputedStyle(child); return position !== "fixed" && position !== "absolute"; } ); } function calculateShiftAmount(input) { const inputBottom = input.getBoundingClientRect().bottom; const visibleHeight = window.innerHeight * (1 - KEYBOARD_HEIGHT_VH / 100); const overflow = inputBottom + INPUT_PADDING - visibleHeight; return overflow > 0 ? overflow : 0; } function scrollInputIntoView(input, keyboardContainerRef) { if (shiftedElements.length > 0) resetScrollPosition(); const shiftAmount = calculateShiftAmount(input); if (shiftAmount === 0) return; const contentElements = findContentElements(keyboardContainerRef); if (contentElements.length === 0) return; injectStyles(); shiftedElements = contentElements; for (const element of contentElements) { element.classList.add(TRANSITION_CLASS); element.style.transform = `translateY(-${shiftAmount}px)`; } } function resetScrollPosition() { if (shiftedElements.length === 0) return; for (const element of shiftedElements) { if (document.body.contains(element)) { element.style.transform = "translateY(0)"; } } const elementsToCleanup = [...shiftedElements]; setTimeout(() => { for (const element of elementsToCleanup) { if (document.body.contains(element)) { element.classList.remove(TRANSITION_CLASS); } } }, TRANSITION_DURATION); shiftedElements = []; } const onEnterClickUtil = (focusedInputRef) => { var _a; if (focusedInputRef.current) { const input = focusedInputRef.current; input.blur(); (_a = input.form) == null ? void 0 : _a.submit(); } }; const handleValueChangeUtil = (focusedInputRef, value) => { const input = focusedInputRef.current; if (!input) return; setInputValueAndDispatchEvents(input, value); }; const validateFocusInputs = (event) => { const target = event.target; const isInput = target.tagName === "INPUT"; const isTextarea = target.tagName === "TEXTAREA"; if (isTextarea) { return target; } if (isInput) { const input = target; const excludedTypes = [ "checkbox", "radio", "range", "date", "time", "color", "month", "week", "file", "hidden", "submit", "reset", "button", "image" ]; if (excludedTypes.includes(input.type)) return null; return input; } return null; }; function createCaretManager(getInputRef) { const insertText = (text) => { const input = getInputRef(); if (!input) return; if (input.readOnly || input.disabled) return; const startRaw = input.selectionStart; const endRaw = input.selectionEnd; const start = startRaw == null ? input.value.length : startRaw; const end = endRaw == null ? input.value.length : endRaw; const scrollTop = input.scrollTop ?? 0; const scrollLeft = input.scrollLeft ?? 0; const newValue = input.value.slice(0, start) + text + input.value.slice(end); const caretAfter = start + text.length; setInputValueAndDispatchEvents(input, newValue); input.focus(); input.setSelectionRange(caretAfter, caretAfter); if ("scrollTop" in input) { input.scrollTop = scrollTop; input.scrollLeft = scrollLeft; } }; const backspace = () => { const input = getInputRef(); if (!input) return; if (input.readOnly || input.disabled) return; const startRaw = input.selectionStart; const endRaw = input.selectionEnd; const start = startRaw == null ? input.value.length : startRaw; const end = endRaw == null ? input.value.length : endRaw; const scrollTop = input.scrollTop ?? 0; const scrollLeft = input.scrollLeft ?? 0; if (start !== end) { const newValue = input.value.slice(0, start) + input.value.slice(end); setInputValueAndDispatchEvents(input, newValue); input.focus(); input.setSelectionRange(start, start); } else if (start > 0) { const newValue = input.value.slice(0, start - 1) + input.value.slice(start); const newCaret = start - 1; setInputValueAndDispatchEvents(input, newValue); input.focus(); input.setSelectionRange(newCaret, newCaret); } if ("scrollTop" in input) { input.scrollTop = scrollTop; input.scrollLeft = scrollLeft; } }; return { insertText, backspace }; } function setupHardwareKeyboard(handlers) { const { onBackspace, onEnter, onSpace, onCapsToggle, onKeyClick } = handlers; const handleKeyboardKeyDown = (event) => { const key = event.key; switch (key) { case "Backspace": event.preventDefault(); event.stopPropagation(); onBackspace(); return; case "Enter": event.preventDefault(); onEnter(); return; case " ": event.preventDefault(); onSpace(); return; case "CapsLock": event.preventDefault(); onCapsToggle(); return; default: if (key.length === 1) { event.preventDefault(); onKeyClick(key); } } }; document.addEventListener("keydown", handleKeyboardKeyDown); return () => { document.removeEventListener("keydown", handleKeyboardKeyDown); }; } const QWERTY_LAYOUT = [ ["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"] ]; const SYMBOLS_LAYOUT = [ ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], ["!", "@", "#", "$", "%", "^", "&", "*", "(", ")"], ["-", "_", "=", "+", "[", "]", "{", "}", "\\", "|"], [";", ":", '"', "'", ",", ".", "<", ">", "/", "?"] ]; const NUMBERS_LAYOUT = [ ["7", "8", "9", "#"], ["4", "5", "6", "-"], ["1", "2", "3"], [",", "0", "."] ]; const DEFAULT_THEME = { backgroundColor: "#1a1a1a", keyColor: "#444444", keyTextColor: "#ffffff", keyActiveColor: "#666666", keyHoverColor: "#555555", activeStateColor: "#4a90e2", keyBorderRadius: "0.5vw", keyFontSize: "32px", keyHeight: "100%" }; const BackspaceIcon = (props) => /* @__PURE__ */ jsx( "svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: /* @__PURE__ */ 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" }) } ); const EnterIcon = (props) => /* @__PURE__ */ jsx( "svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: /* @__PURE__ */ jsx("path", { d: "M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z" }) } ); const SpacebarIcon = (props) => /* @__PURE__ */ jsx( "svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: /* @__PURE__ */ jsx("path", { d: "M18 9v4H6V9H4v6h16V9z" }) } ); const CapsLockIcon = (props) => /* @__PURE__ */ jsx( "svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", style: { transform: "rotate(270deg)" }, ...props, children: /* @__PURE__ */ jsx("path", { d: "M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z" }) } ); function useContinuousPress(onPress, { initialDelay = 500, interval = 50, shouldPreventDefault = true } = {}) { const timeoutRef = useRef(); const intervalRef = useRef(); const clear = useCallback(() => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); timeoutRef.current = void 0; } if (intervalRef.current) { clearInterval(intervalRef.current); intervalRef.current = void 0; } }, []); const start = useCallback(() => { onPress(); timeoutRef.current = setTimeout(() => { intervalRef.current = setInterval(onPress, interval); }, initialDelay); }, [onPress, initialDelay, interval]); return { onMouseDown: (e) => { e.preventDefault(); start(); }, onTouchStart: (e) => { if (shouldPreventDefault) e.preventDefault(); start(); }, onMouseUp: clear, onMouseLeave: clear, onTouchEnd: (e) => { if (shouldPreventDefault) e.preventDefault(); clear(); } }; } function useKeyboardScroll(keyboardContainerRef) { const handleScrollInput = useCallback((input) => { setTimeout(() => { if (!(keyboardContainerRef == null ? void 0 : keyboardContainerRef.current)) return; scrollInputIntoView(input, keyboardContainerRef.current); }, 0); }, [keyboardContainerRef]); const handleResetScroll = useCallback(() => { resetScrollPosition(); }, []); useEffect(() => { return () => { resetScrollPosition(); }; }, []); return { scrollInput: handleScrollInput, resetScroll: handleResetScroll }; } const SpecialKey = memo((props) => { const { type, icon, onClick, extraClass = "", text, capsLock = false, enableContinuousPress = false } = props; const isCapsLockActive = type === "caps" && capsLock; const keyClasses = [ "vk-key", `vk-key--${extraClass}`, isCapsLockActive ? "vk-key--caps-active" : "" ].filter(Boolean).join(" "); const continuousPressHandlers = useContinuousPress(onClick, { initialDelay: 500, interval: 50 }); const buttonHandlers = enableContinuousPress ? continuousPressHandlers : { onClick }; return /* @__PURE__ */ jsxs( "button", { type: "button", className: keyClasses, "data-testid": `${type}${isCapsLockActive ? "-active" : ""}`, "data-key": isCapsLockActive ? `${type}-active` : type, ...buttonHandlers, children: [ icon && icon, text && /* @__PURE__ */ jsx("span", { className: "vk-key__text", children: text }) ] } ); }); SpecialKey.displayName = "SpecialKey"; const VirtualKey = memo(({ keyValue, onClick, className = "" }) => { const keyClasses = ["vk-key", className].filter(Boolean).join(" "); return /* @__PURE__ */ jsx( "button", { type: "button", className: keyClasses, onClick: () => onClick(keyValue), "data-testid": keyValue, children: keyValue } ); }); VirtualKey.displayName = "VirtualKey"; const KeyboardRow = ({ children, className = "" }) => { const rowClasses = ["vk-row", className].filter(Boolean).join(" "); return /* @__PURE__ */ jsx("div", { className: rowClasses, children }); }; const NumbersLayout = ({ currentLayoutData, onBackspace, onEnter, onKeyClick, capsLock }) => { return /* @__PURE__ */ jsx("div", { className: "vk-layout vk-layout--numbers", "data-testid": "keyboard-layout", children: currentLayoutData == null ? void 0 : currentLayoutData.map((row, rowIndex) => /* @__PURE__ */ jsxs(KeyboardRow, { children: [ row == null ? void 0 : row.map((key, keyIndex) => /* @__PURE__ */ jsx( VirtualKey, { keyValue: key, onClick: onKeyClick }, `num-${rowIndex}-${keyIndex}-${key}` )), rowIndex === 3 && /* @__PURE__ */ jsx( SpecialKey, { type: "enter", icon: /* @__PURE__ */ jsx(EnterIcon, {}), onClick: onEnter, extraClass: "enter-num", text: "Enter", capsLock }, "enter-num" ), rowIndex === 2 && /* @__PURE__ */ jsx( SpecialKey, { type: "backspace", icon: /* @__PURE__ */ jsx(BackspaceIcon, {}), onClick: onBackspace, extraClass: "backspace-num", text: "Backspace", capsLock, enableContinuousPress: true }, "backspace-num" ) ] }, `num-row-${rowIndex}`)) }); }; const TextLayout = ({ inputType, currentLayoutData, onBackspace, onEnter, onSpace, onCapsToggle, onLayoutToggle, onKeyClick, capsLock, currentLayout }) => { const renderSpecialKeysLeft = (rowIndex) => { switch (rowIndex) { case 3: return currentLayout === "letters" && /* @__PURE__ */ jsx( SpecialKey, { type: "caps", icon: /* @__PURE__ */ jsx(CapsLockIcon, {}), onClick: onCapsToggle, extraClass: "capsLock", text: "Caps Lock", capsLock }, "caps" ); default: return null; } }; const renderSpecialKeysRight = (rowIndex) => { switch (rowIndex) { case 3: return /* @__PURE__ */ jsx( SpecialKey, { type: "backspace", icon: /* @__PURE__ */ jsx(BackspaceIcon, {}), onClick: onBackspace, extraClass: "backspace", text: "Backspace", enableContinuousPress: true }, "backspace" ); default: return null; } }; return /* @__PURE__ */ jsxs("div", { className: "vk-layout vk-layout--text", "data-testid": "keyboard-layout", children: [ currentLayoutData == null ? void 0 : currentLayoutData.map((row, rowIndex) => /* @__PURE__ */ jsxs(KeyboardRow, { children: [ renderSpecialKeysLeft(rowIndex), row.map((key, keyIndex) => { const displayKey = capsLock ? key.toUpperCase() : key.toLowerCase(); return /* @__PURE__ */ jsx( VirtualKey, { keyValue: displayKey, onClick: onKeyClick }, `${rowIndex}-${keyIndex}-${key}` ); }), renderSpecialKeysRight(rowIndex) ] }, `row-${rowIndex}`)), /* @__PURE__ */ jsxs(KeyboardRow, { children: [ /* @__PURE__ */ jsx( SpecialKey, { type: "layout", icon: currentLayout === "letters" ? "&123" : "ABC", onClick: onLayoutToggle, extraClass: "layout", text: "" }, "layout" ), inputType === "email" && /* @__PURE__ */ jsx( SpecialKey, { type: "dot", onClick: () => onKeyClick("."), extraClass: "dot", icon: "." }, "dot" ), /* @__PURE__ */ jsx( SpecialKey, { type: "space", icon: /* @__PURE__ */ jsx(SpacebarIcon, {}), onClick: onSpace, extraClass: "space", text: "Space" }, "space" ), inputType === "email" && /* @__PURE__ */ jsx( SpecialKey, { type: "at", icon: "@", onClick: () => onKeyClick("@"), extraClass: "at", text: "" }, "at" ), /* @__PURE__ */ jsx( SpecialKey, { type: "enter", icon: /* @__PURE__ */ jsx(EnterIcon, {}), onClick: onEnter, extraClass: "enter", text: "Enter" }, "enter" ) ] }) ] }); }; const KeyboardLayout = ({ currentLayout, capsLock, onKeyClick, onBackspace, onEnter, onSpace, onCapsToggle, onLayoutToggle, inputType, customLayouts }) => { const currentLayoutData = currentLayout === "letters" ? (customLayouts == null ? void 0 : customLayouts.letters) || QWERTY_LAYOUT : currentLayout === "symbols" ? (customLayouts == null ? void 0 : customLayouts.symbols) || SYMBOLS_LAYOUT : (customLayouts == null ? void 0 : customLayouts.numbers) || NUMBERS_LAYOUT; if (currentLayout === "numbers") { return /* @__PURE__ */ jsx( NumbersLayout, { currentLayoutData, onBackspace, onEnter, onKeyClick, capsLock, currentLayout } ); } return /* @__PURE__ */ jsx( TextLayout, { inputType, currentLayoutData, onBackspace, onEnter, onSpace, onCapsToggle, onLayoutToggle, onKeyClick, capsLock, currentLayout } ); }; const VirtualKeyboardContainer = ({ children, className = "" }) => { const handleMouseDown = (e) => { e.preventDefault(); }; const handleClick = (e) => { e.preventDefault(); e.stopPropagation(); }; const containerClasses = ["vk-container", className].filter(Boolean).join(" "); return /* @__PURE__ */ jsx( "div", { className: containerClasses, onMouseDown: handleMouseDown, onClick: handleClick, "data-testid": "keyboard-container", children } ); }; const VirtualKeyboard = ({ focusedInputRef, isInputFocused, inputType = "text", onEnterClick, onChange, className, defaultLayout = "letters", validate, syncWithHardwareKeyboard = true, customLayouts, languages, currentLanguage, onLanguageChange, showLanguageSwitcher = false }) => { const [capsLock, setCapsLock] = useState(false); const [selectedLanguage, setSelectedLanguage] = useState(currentLanguage || Object.keys(languages || {})[0] || "en"); const { insertText, backspace } = createCaretManager(() => focusedInputRef.current); const [currentLayout, setCurrentLayout] = useState( () => getInitialLayout(inputType, defaultLayout) ); const updateValue = useCallback( (next) => { var _a; if (validate && !validate(next)) return; if (!validateValueUtil(next, inputType)) return; insertText(next); onChange == null ? void 0 : onChange(((_a = focusedInputRef.current) == null ? void 0 : _a.value) ?? ""); }, [focusedInputRef, inputType, insertText, onChange, validate] ); const handleKeyClick = useCallback( (key) => { updateValue(key); }, [updateValue] ); const handleBackspace = useCallback(() => { var _a, _b; if (((_a = focusedInputRef.current) == null ? void 0 : _a.value.length) === 0) return; backspace(); onChange == null ? void 0 : onChange(((_b = focusedInputRef.current) == null ? void 0 : _b.value) ?? ""); }, [backspace, focusedInputRef, onChange]); const handleEnter = useCallback(() => { onEnterClick == null ? void 0 : onEnterClick(); }, [onEnterClick]); const handleSpace = useCallback(() => { var _a; updateValue(" "); insertText(" "); onChange == null ? void 0 : onChange(((_a = focusedInputRef.current) == null ? void 0 : _a.value) || ""); }, [insertText, onChange, focusedInputRef]); const handleCapsToggle = useCallback(() => { setCapsLock((prev) => !prev); }, []); useEffect(() => { setCurrentLayout(getInitialLayout(inputType, defaultLayout)); }, [inputType, defaultLayout]); const keysHandlers = { onBackspace: handleBackspace, onEnter: handleEnter, onSpace: handleSpace, onCapsToggle: handleCapsToggle, onKeyClick: handleKeyClick }; useEffect(() => { if (!isInputFocused || !syncWithHardwareKeyboard) return; return setupHardwareKeyboard(keysHandlers); }, [ isInputFocused, syncWithHardwareKeyboard, handleKeyClick, handleBackspace, handleEnter, handleSpace, handleCapsToggle ]); const handleLanguageChange = (lang) => { setSelectedLanguage(lang); onLanguageChange == null ? void 0 : onLanguageChange(lang); }; const activeLayouts = (languages == null ? void 0 : languages[selectedLanguage]) || customLayouts; return /* @__PURE__ */ jsxs(VirtualKeyboardContainer, { className, children: [ showLanguageSwitcher && languages && Object.keys(languages).length > 1 && /* @__PURE__ */ jsx("div", { className: "vk-language-switcher", children: Object.entries(languages).map(([code, config]) => /* @__PURE__ */ jsx( "button", { className: `vk-lang-btn ${selectedLanguage === code ? "active" : ""}`, onClick: () => handleLanguageChange(code), children: config.label || code.toUpperCase() }, code )) }), /* @__PURE__ */ jsx( KeyboardLayout, { capsLock, currentLayout, onKeyClick: handleKeyClick, onBackspace: handleBackspace, onEnter: handleEnter, onSpace: handleSpace, onCapsToggle: handleCapsToggle, onLayoutToggle: () => setCurrentLayout((prev) => prev === "letters" ? "symbols" : "letters"), inputType, customLayouts: activeLayouts } ) ] }); }; const GlobalVirtualKeyboard = ({ enabled = true, className, onVisibilityChange, onEnterClick, onChange }) => { const keyboardContainerRef = useRef(null); const [isVisible, setIsVisible] = useState(false); const [inputType, setInputType] = useState("text"); const focusedInputRef = useRef(null); const originalInputTypeRef = useRef("text"); const { scrollInput, resetScroll } = useKeyboardScroll(keyboardContainerRef); useEffect(() => { if (!enabled) { if (isVisible) { setTimeout(() => { setIsVisible(false); }, 0); onVisibilityChange == null ? void 0 : onVisibilityChange(false); } return; } const handleFocus = (event) => { const input = validateFocusInputs(event); if (!input) return; const isTextarea = input.tagName === "TEXTAREA"; const detectedInputType = isTextarea ? "text" : input.type; setInputType(detectedInputType); setIsVisible(true); onVisibilityChange == null ? void 0 : onVisibilityChange(true); focusedInputRef.current = input; if (!isTextarea) { originalInputTypeRef.current = input.type; if (input.type !== "text") { const selectionStart = input.selectionStart; const selectionEnd = input.selectionEnd; input.type = "text"; const caretPos = selectionStart ?? input.value.length; const caretEnd = selectionEnd ?? caretPos; input.setSelectionRange(caretPos, caretEnd); } } scrollInput(input); }; const handleBlur = (event) => { const input = validateFocusInputs(event); if (!input) return; const isTextarea = input.tagName === "TEXTAREA"; if (!isTextarea) { input.type = originalInputTypeRef.current; } if (focusedInputRef.current === input) { focusedInputRef.current = null; setIsVisible(false); onVisibilityChange == null ? void 0 : onVisibilityChange(false); resetScroll(); } }; document.addEventListener("focusin", handleFocus, true); document.addEventListener("focusout", handleBlur, true); return () => { document.removeEventListener("focusin", handleFocus, true); document.removeEventListener("focusout", handleBlur, true); }; }, [enabled, scrollInput, resetScroll, onVisibilityChange]); const handleEnterClick = () => { setIsVisible(false); onVisibilityChange == null ? void 0 : onVisibilityChange(false); onEnterClickUtil(focusedInputRef); onEnterClick == null ? void 0 : onEnterClick(); resetScroll(); }; if (!isVisible || !enabled) { return null; } return /* @__PURE__ */ jsx("span", { ref: keyboardContainerRef, children: /* @__PURE__ */ jsx( VirtualKeyboard, { focusedInputRef, isInputFocused: isVisible, inputType, onEnterClick: handleEnterClick, onChange, className } ) }); }; export { BackspaceIcon, CapsLockIcon, DEFAULT_THEME, EnterIcon, GlobalVirtualKeyboard, KeyboardLayout, KeyboardRow, NUMBERS_LAYOUT, NumbersLayout, QWERTY_LAYOUT, SYMBOLS_LAYOUT, SpacebarIcon, SpecialKey, TextLayout, VirtualKey, VirtualKeyboard, VirtualKeyboardContainer, createCaretManager, getInitialLayout, handleValueChangeUtil, onEnterClickUtil, resetScrollPosition, scrollInputIntoView, setInputValueAndDispatchEvents, setupHardwareKeyboard, useContinuousPress, useKeyboardScroll, validateFocusInputs, validateValueUtil }; //# sourceMappingURL=index.esm.js.map