reactjs-virtual-keyboard 1.0.2 → 2.0.0

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/dist/index.esm.js CHANGED
@@ -1,190 +1,129 @@
1
- import { jsx as a, jsxs as L } from "react/jsx-runtime";
2
- import { useRef as A, useCallback as k, useEffect as $, useState as H } from "react";
3
- const B = (e, r, n = {}) => {
4
- var s;
5
- const { skipValueAssignment: t = !1 } = n;
6
- if (!t) {
7
- const l = Object.getPrototypeOf(e), c = (s = Object.getOwnPropertyDescriptor(l, "value")) == null ? void 0 : s.set;
8
- c && c.call(e, r);
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useRef, useCallback, useEffect, memo, useState } from "react";
3
+ const setInputValueAndDispatchEvents = (input, value, options = {}) => {
4
+ var _a;
5
+ const { skipValueAssignment = false } = options;
6
+ if (!skipValueAssignment) {
7
+ const proto = Object.getPrototypeOf(input);
8
+ const valueSetter = (_a = Object.getOwnPropertyDescriptor(proto, "value")) == null ? void 0 : _a.set;
9
+ if (valueSetter) {
10
+ valueSetter.call(input, value);
11
+ }
9
12
  }
10
- e.dispatchEvent(new InputEvent("input", { bubbles: !0, cancelable: !0 })), e.dispatchEvent(new Event("change", { bubbles: !0, cancelable: !0 }));
13
+ input.dispatchEvent(new InputEvent("input", { bubbles: true, cancelable: true }));
14
+ input.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
11
15
  };
12
- function Y(e) {
13
- return {
14
- insertText: (t) => {
15
- const s = e.current;
16
- if (!s || s.readOnly || s.disabled) return;
17
- const l = s.selectionStart, c = s.selectionEnd, o = l ?? s.value.length, u = c ?? s.value.length, f = s.scrollTop ?? 0, d = s.scrollLeft ?? 0, v = s.value.slice(0, o) + t + s.value.slice(u), m = o + t.length;
18
- B(s, v), s.focus(), s.setSelectionRange(m, m), "scrollTop" in s && (s.scrollTop = f, s.scrollLeft = d);
19
- },
20
- backspace: () => {
21
- const t = e.current;
22
- if (!t || t.readOnly || t.disabled) return;
23
- const s = t.selectionStart, l = t.selectionEnd, c = s ?? t.value.length, o = l ?? t.value.length, u = t.scrollTop ?? 0, f = t.scrollLeft ?? 0;
24
- if (c !== o) {
25
- const d = t.value.slice(0, c) + t.value.slice(o);
26
- B(t, d), t.focus(), t.setSelectionRange(c, c);
27
- } else if (c > 0) {
28
- const d = t.value.slice(0, c - 1) + t.value.slice(c), v = c - 1;
29
- B(t, d), t.focus(), t.setSelectionRange(v, v);
30
- }
31
- "scrollTop" in t && (t.scrollTop = u, t.scrollLeft = f);
32
- }
33
- };
34
- }
35
- function F(e, {
36
- initialDelay: r = 500,
37
- interval: n = 50,
38
- shouldPreventDefault: t = !0
39
- } = {}) {
40
- const s = A(), l = A(), c = k(() => {
41
- s.current && (clearTimeout(s.current), s.current = void 0), l.current && (clearInterval(l.current), l.current = void 0);
42
- }, []), o = k(() => {
43
- e(), s.current = setTimeout(() => {
44
- l.current = setInterval(e, n);
45
- }, r);
46
- }, [e, r, n]);
47
- return {
48
- onMouseDown: (u) => {
49
- u.preventDefault(), o();
50
- },
51
- onTouchStart: (u) => {
52
- t && u.preventDefault(), o();
53
- },
54
- onMouseUp: c,
55
- onMouseLeave: c,
56
- onTouchEnd: (u) => {
57
- t && u.preventDefault(), c();
58
- }
59
- };
60
- }
61
- function G({
62
- isInputFocused: e,
63
- onBackspace: r,
64
- onEnter: n,
65
- onSpace: t,
66
- onCapsToggle: s,
67
- onKeyClick: l
68
- }) {
69
- $(() => {
70
- if (!e) return;
71
- const c = (o) => {
72
- const u = o.key;
73
- switch (u) {
74
- case "Backspace":
75
- o.preventDefault(), o.stopPropagation(), r();
76
- return;
77
- case "Enter":
78
- o.preventDefault(), n();
79
- return;
80
- case " ":
81
- o.preventDefault(), t();
82
- return;
83
- case "CapsLock":
84
- o.preventDefault(), s();
85
- return;
86
- default:
87
- u.length === 1 && (o.preventDefault(), l(u));
88
- }
89
- };
90
- return document.addEventListener("keydown", c), () => {
91
- document.removeEventListener("keydown", c);
92
- };
93
- }, [e, r, n, t, s, l]);
94
- }
95
- const X = 38, Z = 20, _ = "vk-keyboard-shift-transition", R = 300;
96
- let g = [], D = !1;
97
- function q() {
98
- if (D) return;
99
- const e = document.createElement("style");
100
- e.id = "vk-keyboard-shift-styles", e.textContent = `
101
- .${_} {
102
- transition: transform ${R}ms ease-out;
16
+ const validateValueUtil = (value, inputType) => {
17
+ switch (inputType) {
18
+ case "number":
19
+ return /^[0-9]*$/.test(value);
20
+ case "email":
21
+ return /^[a-zA-Z0-9@._+-]*$/.test(value);
22
+ case "tel":
23
+ return /^[0-9+\-() ]*$/.test(value);
24
+ case "url":
25
+ return /^[a-zA-Z0-9:/._-]*$/.test(value);
26
+ case "password":
27
+ return true;
28
+ default:
29
+ return true;
30
+ }
31
+ };
32
+ const getInitialLayout = (inputType, defaultLayout) => {
33
+ if (inputType === "number") {
34
+ return "numbers";
35
+ }
36
+ return defaultLayout;
37
+ };
38
+ const KEYBOARD_HEIGHT_VH = 38;
39
+ const INPUT_PADDING = 20;
40
+ const TRANSITION_CLASS = "vk-keyboard-shift-transition";
41
+ const TRANSITION_DURATION = 300;
42
+ let shiftedElements = [];
43
+ let styleInjected = false;
44
+ function injectStyles() {
45
+ if (styleInjected) return;
46
+ const style = document.createElement("style");
47
+ style.id = "vk-keyboard-shift-styles";
48
+ style.textContent = `
49
+ .${TRANSITION_CLASS} {
50
+ transition: transform ${TRANSITION_DURATION}ms ease-out;
103
51
  will-change: transform;
104
52
  }
105
- `, document.head.appendChild(e), D = !0;
53
+ `;
54
+ document.head.appendChild(style);
55
+ styleInjected = true;
106
56
  }
107
- function Q(e) {
108
- var r;
109
- return e ? Array.from(((r = e.parentElement) == null ? void 0 : r.children) ?? []).filter(
110
- (n) => {
111
- if (n === e) return !1;
112
- const { position: t } = window.getComputedStyle(n);
113
- return t !== "fixed" && t !== "absolute";
57
+ function findContentElements(keyboardContainerRef) {
58
+ var _a;
59
+ if (!keyboardContainerRef) return [];
60
+ return Array.from(((_a = keyboardContainerRef.parentElement) == null ? void 0 : _a.children) ?? []).filter(
61
+ (child) => {
62
+ if (child === keyboardContainerRef) return false;
63
+ const { position } = window.getComputedStyle(child);
64
+ return position !== "fixed" && position !== "absolute";
114
65
  }
115
- ) : [];
66
+ );
116
67
  }
117
- function W(e) {
118
- const r = e.getBoundingClientRect().bottom, n = window.innerHeight * (1 - X / 100), t = r + Z - n;
119
- return t > 0 ? t : 0;
68
+ function calculateShiftAmount(input) {
69
+ const inputBottom = input.getBoundingClientRect().bottom;
70
+ const visibleHeight = window.innerHeight * (1 - KEYBOARD_HEIGHT_VH / 100);
71
+ const overflow = inputBottom + INPUT_PADDING - visibleHeight;
72
+ return overflow > 0 ? overflow : 0;
120
73
  }
121
- function J(e, r) {
122
- g.length > 0 && C();
123
- const n = W(e);
124
- if (n === 0) return;
125
- const t = Q(r);
126
- if (t.length !== 0) {
127
- q(), g = t;
128
- for (const s of t)
129
- s.classList.add(_), s.style.transform = `translateY(-${n}px)`;
74
+ function scrollInputIntoView(input, keyboardContainerRef) {
75
+ if (shiftedElements.length > 0) resetScrollPosition();
76
+ const shiftAmount = calculateShiftAmount(input);
77
+ if (shiftAmount === 0) return;
78
+ const contentElements = findContentElements(keyboardContainerRef);
79
+ if (contentElements.length === 0) return;
80
+ injectStyles();
81
+ shiftedElements = contentElements;
82
+ for (const element of contentElements) {
83
+ element.classList.add(TRANSITION_CLASS);
84
+ element.style.transform = `translateY(-${shiftAmount}px)`;
130
85
  }
131
86
  }
132
- function C() {
133
- if (g.length === 0) return;
134
- for (const r of g)
135
- document.body.contains(r) && (r.style.transform = "translateY(0)");
136
- const e = [...g];
87
+ function resetScrollPosition() {
88
+ if (shiftedElements.length === 0) return;
89
+ for (const element of shiftedElements) {
90
+ if (document.body.contains(element)) {
91
+ element.style.transform = "translateY(0)";
92
+ }
93
+ }
94
+ const elementsToCleanup = [...shiftedElements];
137
95
  setTimeout(() => {
138
- for (const r of e)
139
- document.body.contains(r) && r.classList.remove(_);
140
- }, R), g = [];
141
- }
142
- function V(e) {
143
- const r = k((t) => {
144
- setTimeout(() => {
145
- e != null && e.current && J(t, e.current);
146
- }, 0);
147
- }, [e]), n = k(() => {
148
- C();
149
- }, []);
150
- return $(() => () => {
151
- C();
152
- }, []), {
153
- scrollInput: r,
154
- resetScroll: n
155
- };
96
+ for (const element of elementsToCleanup) {
97
+ if (document.body.contains(element)) {
98
+ element.classList.remove(TRANSITION_CLASS);
99
+ }
100
+ }
101
+ }, TRANSITION_DURATION);
102
+ shiftedElements = [];
156
103
  }
157
- const ee = (e, r) => {
158
- switch (r) {
159
- case "number":
160
- return /^[0-9]*$/.test(e);
161
- case "email":
162
- return /^[a-zA-Z0-9@._+-]*$/.test(e);
163
- case "tel":
164
- return /^[0-9+\-() ]*$/.test(e);
165
- case "url":
166
- return /^[a-zA-Z0-9:/._-]*$/.test(e);
167
- case "password":
168
- return !0;
169
- default:
170
- return !0;
104
+ const onEnterClickUtil = (focusedInputRef) => {
105
+ var _a;
106
+ if (focusedInputRef.current) {
107
+ const input = focusedInputRef.current;
108
+ input.blur();
109
+ (_a = input.form) == null ? void 0 : _a.submit();
171
110
  }
172
- }, K = (e, r) => e === "number" ? "numbers" : r, te = (e) => {
173
- var r;
174
- if (e.current) {
175
- const n = e.current;
176
- n.blur(), (r = n.form) == null || r.submit();
111
+ };
112
+ const handleValueChangeUtil = (focusedInputRef, value) => {
113
+ const input = focusedInputRef.current;
114
+ if (!input) return;
115
+ setInputValueAndDispatchEvents(input, value);
116
+ };
117
+ const validateFocusInputs = (event) => {
118
+ const target = event.target;
119
+ const isInput = target.tagName === "INPUT";
120
+ const isTextarea = target.tagName === "TEXTAREA";
121
+ if (isTextarea) {
122
+ return target;
177
123
  }
178
- }, me = (e, r) => {
179
- const n = e.current;
180
- n && B(n, r);
181
- }, M = (e) => {
182
- const r = e.target, n = r.tagName === "INPUT";
183
- if (r.tagName === "TEXTAREA")
184
- return r;
185
- if (n) {
186
- const s = r;
187
- return [
124
+ if (isInput) {
125
+ const input = target;
126
+ const excludedTypes = [
188
127
  "checkbox",
189
128
  "radio",
190
129
  "range",
@@ -199,25 +138,118 @@ const ee = (e, r) => {
199
138
  "reset",
200
139
  "button",
201
140
  "image"
202
- ].includes(s.type) ? null : s;
141
+ ];
142
+ if (excludedTypes.includes(input.type)) return null;
143
+ return input;
203
144
  }
204
145
  return null;
205
- }, ne = [
146
+ };
147
+ function createCaretManager(getInputRef) {
148
+ const insertText = (text) => {
149
+ const input = getInputRef();
150
+ if (!input) return;
151
+ if (input.readOnly || input.disabled) return;
152
+ const startRaw = input.selectionStart;
153
+ const endRaw = input.selectionEnd;
154
+ const start = startRaw == null ? input.value.length : startRaw;
155
+ const end = endRaw == null ? input.value.length : endRaw;
156
+ const scrollTop = input.scrollTop ?? 0;
157
+ const scrollLeft = input.scrollLeft ?? 0;
158
+ const newValue = input.value.slice(0, start) + text + input.value.slice(end);
159
+ const caretAfter = start + text.length;
160
+ setInputValueAndDispatchEvents(input, newValue);
161
+ input.focus();
162
+ input.setSelectionRange(caretAfter, caretAfter);
163
+ if ("scrollTop" in input) {
164
+ input.scrollTop = scrollTop;
165
+ input.scrollLeft = scrollLeft;
166
+ }
167
+ };
168
+ const backspace = () => {
169
+ const input = getInputRef();
170
+ if (!input) return;
171
+ if (input.readOnly || input.disabled) return;
172
+ const startRaw = input.selectionStart;
173
+ const endRaw = input.selectionEnd;
174
+ const start = startRaw == null ? input.value.length : startRaw;
175
+ const end = endRaw == null ? input.value.length : endRaw;
176
+ const scrollTop = input.scrollTop ?? 0;
177
+ const scrollLeft = input.scrollLeft ?? 0;
178
+ if (start !== end) {
179
+ const newValue = input.value.slice(0, start) + input.value.slice(end);
180
+ setInputValueAndDispatchEvents(input, newValue);
181
+ input.focus();
182
+ input.setSelectionRange(start, start);
183
+ } else if (start > 0) {
184
+ const newValue = input.value.slice(0, start - 1) + input.value.slice(start);
185
+ const newCaret = start - 1;
186
+ setInputValueAndDispatchEvents(input, newValue);
187
+ input.focus();
188
+ input.setSelectionRange(newCaret, newCaret);
189
+ }
190
+ if ("scrollTop" in input) {
191
+ input.scrollTop = scrollTop;
192
+ input.scrollLeft = scrollLeft;
193
+ }
194
+ };
195
+ return {
196
+ insertText,
197
+ backspace
198
+ };
199
+ }
200
+ function setupHardwareKeyboard(handlers) {
201
+ const { onBackspace, onEnter, onSpace, onCapsToggle, onKeyClick } = handlers;
202
+ const handleKeyboardKeyDown = (event) => {
203
+ const key = event.key;
204
+ switch (key) {
205
+ case "Backspace":
206
+ event.preventDefault();
207
+ event.stopPropagation();
208
+ onBackspace();
209
+ return;
210
+ case "Enter":
211
+ event.preventDefault();
212
+ onEnter();
213
+ return;
214
+ case " ":
215
+ event.preventDefault();
216
+ onSpace();
217
+ return;
218
+ case "CapsLock":
219
+ event.preventDefault();
220
+ onCapsToggle();
221
+ return;
222
+ default:
223
+ if (key.length === 1) {
224
+ event.preventDefault();
225
+ onKeyClick(key);
226
+ }
227
+ }
228
+ };
229
+ document.addEventListener("keydown", handleKeyboardKeyDown);
230
+ return () => {
231
+ document.removeEventListener("keydown", handleKeyboardKeyDown);
232
+ };
233
+ }
234
+ const QWERTY_LAYOUT = [
206
235
  ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"],
207
236
  ["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"],
208
237
  ["a", "s", "d", "f", "g", "h", "j", "k", "l"],
209
238
  ["z", "x", "c", "v", "b", "n", "m"]
210
- ], se = [
239
+ ];
240
+ const SYMBOLS_LAYOUT = [
211
241
  ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"],
212
242
  ["!", "@", "#", "$", "%", "^", "&", "*", "(", ")"],
213
243
  ["-", "_", "=", "+", "[", "]", "{", "}", "\\", "|"],
214
244
  [";", ":", '"', "'", ",", ".", "<", ">", "/", "?"]
215
- ], re = [
245
+ ];
246
+ const NUMBERS_LAYOUT = [
216
247
  ["7", "8", "9", "#"],
217
248
  ["4", "5", "6", "-"],
218
249
  ["1", "2", "3"],
219
250
  [",", "0", "."]
220
- ], ve = {
251
+ ];
252
+ const DEFAULT_THEME = {
221
253
  backgroundColor: "#1a1a1a",
222
254
  keyColor: "#444444",
223
255
  keyTextColor: "#ffffff",
@@ -227,7 +259,8 @@ const ee = (e, r) => {
227
259
  keyBorderRadius: "0.5vw",
228
260
  keyFontSize: "32px",
229
261
  keyHeight: "100%"
230
- }, U = (e) => /* @__PURE__ */ a(
262
+ };
263
+ const BackspaceIcon = (props) => /* @__PURE__ */ jsx(
231
264
  "svg",
232
265
  {
233
266
  xmlns: "http://www.w3.org/2000/svg",
@@ -235,10 +268,11 @@ const ee = (e, r) => {
235
268
  fill: "currentColor",
236
269
  width: "1em",
237
270
  height: "1em",
238
- ...e,
239
- children: /* @__PURE__ */ a("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" })
271
+ ...props,
272
+ 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" })
240
273
  }
241
- ), j = (e) => /* @__PURE__ */ a(
274
+ );
275
+ const EnterIcon = (props) => /* @__PURE__ */ jsx(
242
276
  "svg",
243
277
  {
244
278
  xmlns: "http://www.w3.org/2000/svg",
@@ -246,10 +280,11 @@ const ee = (e, r) => {
246
280
  fill: "currentColor",
247
281
  width: "1em",
248
282
  height: "1em",
249
- ...e,
250
- children: /* @__PURE__ */ a("path", { d: "M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z" })
283
+ ...props,
284
+ children: /* @__PURE__ */ jsx("path", { d: "M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z" })
251
285
  }
252
- ), ce = (e) => /* @__PURE__ */ a(
286
+ );
287
+ const SpacebarIcon = (props) => /* @__PURE__ */ jsx(
253
288
  "svg",
254
289
  {
255
290
  xmlns: "http://www.w3.org/2000/svg",
@@ -257,10 +292,11 @@ const ee = (e, r) => {
257
292
  fill: "currentColor",
258
293
  width: "1em",
259
294
  height: "1em",
260
- ...e,
261
- children: /* @__PURE__ */ a("path", { d: "M18 9v4H6V9H4v6h16V9z" })
295
+ ...props,
296
+ children: /* @__PURE__ */ jsx("path", { d: "M18 9v4H6V9H4v6h16V9z" })
262
297
  }
263
- ), oe = (e) => /* @__PURE__ */ a(
298
+ );
299
+ const CapsLockIcon = (props) => /* @__PURE__ */ jsx(
264
300
  "svg",
265
301
  {
266
302
  xmlns: "http://www.w3.org/2000/svg",
@@ -269,137 +305,211 @@ const ee = (e, r) => {
269
305
  width: "1em",
270
306
  height: "1em",
271
307
  style: { transform: "rotate(270deg)" },
272
- ...e,
273
- children: /* @__PURE__ */ a("path", { d: "M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z" })
308
+ ...props,
309
+ children: /* @__PURE__ */ jsx("path", { d: "M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z" })
274
310
  }
275
- ), T = ({
276
- type: e,
277
- icon: r,
278
- onClick: n,
279
- extraClass: t = "",
280
- text: s,
281
- capsLock: l = !1,
282
- enableContinuousPress: c = !1
283
- }) => {
284
- const o = e === "caps" && l, u = [
311
+ );
312
+ function useContinuousPress(onPress, {
313
+ initialDelay = 500,
314
+ interval = 50,
315
+ shouldPreventDefault = true
316
+ } = {}) {
317
+ const timeoutRef = useRef();
318
+ const intervalRef = useRef();
319
+ const clear = useCallback(() => {
320
+ if (timeoutRef.current) {
321
+ clearTimeout(timeoutRef.current);
322
+ timeoutRef.current = void 0;
323
+ }
324
+ if (intervalRef.current) {
325
+ clearInterval(intervalRef.current);
326
+ intervalRef.current = void 0;
327
+ }
328
+ }, []);
329
+ const start = useCallback(() => {
330
+ onPress();
331
+ timeoutRef.current = setTimeout(() => {
332
+ intervalRef.current = setInterval(onPress, interval);
333
+ }, initialDelay);
334
+ }, [onPress, initialDelay, interval]);
335
+ return {
336
+ onMouseDown: (e) => {
337
+ e.preventDefault();
338
+ start();
339
+ },
340
+ onTouchStart: (e) => {
341
+ if (shouldPreventDefault) e.preventDefault();
342
+ start();
343
+ },
344
+ onMouseUp: clear,
345
+ onMouseLeave: clear,
346
+ onTouchEnd: (e) => {
347
+ if (shouldPreventDefault) e.preventDefault();
348
+ clear();
349
+ }
350
+ };
351
+ }
352
+ function useKeyboardScroll(keyboardContainerRef) {
353
+ const handleScrollInput = useCallback((input) => {
354
+ setTimeout(() => {
355
+ if (!(keyboardContainerRef == null ? void 0 : keyboardContainerRef.current)) return;
356
+ scrollInputIntoView(input, keyboardContainerRef.current);
357
+ }, 0);
358
+ }, [keyboardContainerRef]);
359
+ const handleResetScroll = useCallback(() => {
360
+ resetScrollPosition();
361
+ }, []);
362
+ useEffect(() => {
363
+ return () => {
364
+ resetScrollPosition();
365
+ };
366
+ }, []);
367
+ return {
368
+ scrollInput: handleScrollInput,
369
+ resetScroll: handleResetScroll
370
+ };
371
+ }
372
+ const SpecialKey = memo((props) => {
373
+ const {
374
+ type,
375
+ icon,
376
+ onClick,
377
+ extraClass = "",
378
+ text,
379
+ capsLock = false,
380
+ enableContinuousPress = false
381
+ } = props;
382
+ const isCapsLockActive = type === "caps" && capsLock;
383
+ const keyClasses = [
285
384
  "vk-key",
286
- `vk-key--${t}`,
287
- o ? "vk-key--caps-active" : ""
288
- ].filter(Boolean).join(" "), f = F(n, {
385
+ `vk-key--${extraClass}`,
386
+ isCapsLockActive ? "vk-key--caps-active" : ""
387
+ ].filter(Boolean).join(" ");
388
+ const continuousPressHandlers = useContinuousPress(onClick, {
289
389
  initialDelay: 500,
290
390
  interval: 50
291
- }), d = c ? f : { onClick: n };
292
- return /* @__PURE__ */ L(
391
+ });
392
+ const buttonHandlers = enableContinuousPress ? continuousPressHandlers : { onClick };
393
+ return /* @__PURE__ */ jsxs(
293
394
  "button",
294
395
  {
295
396
  type: "button",
296
- className: u,
297
- "data-testid": `${e}${o ? "-active" : ""}`,
298
- "data-key": o ? `${e}-active` : e,
299
- ...d,
397
+ className: keyClasses,
398
+ "data-testid": `${type}${isCapsLockActive ? "-active" : ""}`,
399
+ "data-key": isCapsLockActive ? `${type}-active` : type,
400
+ ...buttonHandlers,
300
401
  children: [
301
- r && r,
302
- s && /* @__PURE__ */ a("span", { className: "vk-key__text", children: s })
402
+ icon && icon,
403
+ text && /* @__PURE__ */ jsx("span", { className: "vk-key__text", children: text })
303
404
  ]
304
405
  }
305
406
  );
306
- }, z = ({ keyValue: e, onClick: r, className: n = "" }) => {
307
- const t = ["vk-key", n].filter(Boolean).join(" ");
308
- return /* @__PURE__ */ a(
407
+ });
408
+ SpecialKey.displayName = "SpecialKey";
409
+ const VirtualKey = memo(({ keyValue, onClick, className = "" }) => {
410
+ const keyClasses = ["vk-key", className].filter(Boolean).join(" ");
411
+ return /* @__PURE__ */ jsx(
309
412
  "button",
310
413
  {
311
414
  type: "button",
312
- className: t,
313
- onClick: () => r(e),
314
- "data-testid": e,
315
- children: e
415
+ className: keyClasses,
416
+ onClick: () => onClick(keyValue),
417
+ "data-testid": keyValue,
418
+ children: keyValue
316
419
  }
317
420
  );
318
- }, O = ({ children: e, className: r = "" }) => {
319
- const n = ["vk-row", r].filter(Boolean).join(" ");
320
- return /* @__PURE__ */ a("div", { className: n, children: e });
321
- }, le = ({
322
- currentLayoutData: e,
323
- onBackspace: r,
324
- onEnter: n,
325
- onKeyClick: t,
326
- capsLock: s
327
- }) => /* @__PURE__ */ a("div", { className: "vk-layout vk-layout--numbers", "data-testid": "keyboard-layout", children: e == null ? void 0 : e.map((l, c) => /* @__PURE__ */ L(O, { children: [
328
- l == null ? void 0 : l.map((o, u) => /* @__PURE__ */ a(
329
- z,
330
- {
331
- keyValue: o,
332
- onClick: t
333
- },
334
- `num-${c}-${u}-${o}`
335
- )),
336
- c === 3 && /* @__PURE__ */ a(
337
- T,
338
- {
339
- type: "enter",
340
- icon: /* @__PURE__ */ a(j, {}),
341
- onClick: n,
342
- extraClass: "enter-num",
343
- text: "Enter",
344
- capsLock: s
345
- },
346
- "enter-num"
347
- ),
348
- c === 2 && /* @__PURE__ */ a(
349
- T,
350
- {
351
- type: "backspace",
352
- icon: /* @__PURE__ */ a(U, {}),
353
- onClick: r,
354
- extraClass: "backspace-num",
355
- text: "Backspace",
356
- capsLock: s,
357
- enableContinuousPress: !0
358
- },
359
- "backspace-num"
360
- )
361
- ] }, `num-row-${c}`)) }), ae = ({
362
- inputType: e,
363
- currentLayoutData: r,
364
- onBackspace: n,
365
- onEnter: t,
366
- onSpace: s,
367
- onCapsToggle: l,
368
- onLayoutToggle: c,
369
- onKeyClick: o,
370
- capsLock: u,
371
- currentLayout: f
421
+ });
422
+ VirtualKey.displayName = "VirtualKey";
423
+ const KeyboardRow = ({ children, className = "" }) => {
424
+ const rowClasses = ["vk-row", className].filter(Boolean).join(" ");
425
+ return /* @__PURE__ */ jsx("div", { className: rowClasses, children });
426
+ };
427
+ const NumbersLayout = ({
428
+ currentLayoutData,
429
+ onBackspace,
430
+ onEnter,
431
+ onKeyClick,
432
+ capsLock
372
433
  }) => {
373
- const d = (m) => {
374
- switch (m) {
434
+ 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: [
435
+ row == null ? void 0 : row.map((key, keyIndex) => /* @__PURE__ */ jsx(
436
+ VirtualKey,
437
+ {
438
+ keyValue: key,
439
+ onClick: onKeyClick
440
+ },
441
+ `num-${rowIndex}-${keyIndex}-${key}`
442
+ )),
443
+ rowIndex === 3 && /* @__PURE__ */ jsx(
444
+ SpecialKey,
445
+ {
446
+ type: "enter",
447
+ icon: /* @__PURE__ */ jsx(EnterIcon, {}),
448
+ onClick: onEnter,
449
+ extraClass: "enter-num",
450
+ text: "Enter",
451
+ capsLock
452
+ },
453
+ "enter-num"
454
+ ),
455
+ rowIndex === 2 && /* @__PURE__ */ jsx(
456
+ SpecialKey,
457
+ {
458
+ type: "backspace",
459
+ icon: /* @__PURE__ */ jsx(BackspaceIcon, {}),
460
+ onClick: onBackspace,
461
+ extraClass: "backspace-num",
462
+ text: "Backspace",
463
+ capsLock,
464
+ enableContinuousPress: true
465
+ },
466
+ "backspace-num"
467
+ )
468
+ ] }, `num-row-${rowIndex}`)) });
469
+ };
470
+ const TextLayout = ({
471
+ inputType,
472
+ currentLayoutData,
473
+ onBackspace,
474
+ onEnter,
475
+ onSpace,
476
+ onCapsToggle,
477
+ onLayoutToggle,
478
+ onKeyClick,
479
+ capsLock,
480
+ currentLayout
481
+ }) => {
482
+ const renderSpecialKeysLeft = (rowIndex) => {
483
+ switch (rowIndex) {
375
484
  case 3:
376
- return f === "letters" && /* @__PURE__ */ a(
377
- T,
485
+ return currentLayout === "letters" && /* @__PURE__ */ jsx(
486
+ SpecialKey,
378
487
  {
379
488
  type: "caps",
380
- icon: /* @__PURE__ */ a(oe, {}),
381
- onClick: l,
489
+ icon: /* @__PURE__ */ jsx(CapsLockIcon, {}),
490
+ onClick: onCapsToggle,
382
491
  extraClass: "capsLock",
383
492
  text: "Caps Lock",
384
- capsLock: u
493
+ capsLock
385
494
  },
386
495
  "caps"
387
496
  );
388
497
  default:
389
498
  return null;
390
499
  }
391
- }, v = (m) => {
392
- switch (m) {
500
+ };
501
+ const renderSpecialKeysRight = (rowIndex) => {
502
+ switch (rowIndex) {
393
503
  case 3:
394
- return /* @__PURE__ */ a(
395
- T,
504
+ return /* @__PURE__ */ jsx(
505
+ SpecialKey,
396
506
  {
397
507
  type: "backspace",
398
- icon: /* @__PURE__ */ a(U, {}),
399
- onClick: n,
508
+ icon: /* @__PURE__ */ jsx(BackspaceIcon, {}),
509
+ onClick: onBackspace,
400
510
  extraClass: "backspace",
401
511
  text: "Backspace",
402
- enableContinuousPress: !0
512
+ enableContinuousPress: true
403
513
  },
404
514
  "backspace"
405
515
  );
@@ -407,72 +517,72 @@ const ee = (e, r) => {
407
517
  return null;
408
518
  }
409
519
  };
410
- return /* @__PURE__ */ L("div", { className: "vk-layout vk-layout--text", "data-testid": "keyboard-layout", children: [
411
- r == null ? void 0 : r.map((m, h) => /* @__PURE__ */ L(O, { children: [
412
- d(h),
413
- m.map((w, y) => {
414
- const b = u ? w.toUpperCase() : w.toLowerCase();
415
- return /* @__PURE__ */ a(
416
- z,
520
+ return /* @__PURE__ */ jsxs("div", { className: "vk-layout vk-layout--text", "data-testid": "keyboard-layout", children: [
521
+ currentLayoutData == null ? void 0 : currentLayoutData.map((row, rowIndex) => /* @__PURE__ */ jsxs(KeyboardRow, { children: [
522
+ renderSpecialKeysLeft(rowIndex),
523
+ row.map((key, keyIndex) => {
524
+ const displayKey = capsLock ? key.toUpperCase() : key.toLowerCase();
525
+ return /* @__PURE__ */ jsx(
526
+ VirtualKey,
417
527
  {
418
- keyValue: b,
419
- onClick: o
528
+ keyValue: displayKey,
529
+ onClick: onKeyClick
420
530
  },
421
- `${h}-${y}-${w}`
531
+ `${rowIndex}-${keyIndex}-${key}`
422
532
  );
423
533
  }),
424
- v(h)
425
- ] }, `row-${h}`)),
426
- /* @__PURE__ */ L(O, { children: [
427
- /* @__PURE__ */ a(
428
- T,
534
+ renderSpecialKeysRight(rowIndex)
535
+ ] }, `row-${rowIndex}`)),
536
+ /* @__PURE__ */ jsxs(KeyboardRow, { children: [
537
+ /* @__PURE__ */ jsx(
538
+ SpecialKey,
429
539
  {
430
540
  type: "layout",
431
- icon: f === "letters" ? "&123" : "ABC",
432
- onClick: c,
541
+ icon: currentLayout === "letters" ? "&123" : "ABC",
542
+ onClick: onLayoutToggle,
433
543
  extraClass: "layout",
434
544
  text: ""
435
545
  },
436
546
  "layout"
437
547
  ),
438
- e === "email" && /* @__PURE__ */ a(
439
- T,
548
+ inputType === "email" && /* @__PURE__ */ jsx(
549
+ SpecialKey,
440
550
  {
441
551
  type: "dot",
442
- onClick: () => o("."),
552
+ onClick: () => onKeyClick("."),
443
553
  extraClass: "dot",
444
554
  icon: "."
445
555
  },
446
556
  "dot"
447
557
  ),
448
- /* @__PURE__ */ a(
449
- T,
558
+ /* @__PURE__ */ jsx(
559
+ SpecialKey,
450
560
  {
451
561
  type: "space",
452
- icon: /* @__PURE__ */ a(ce, {}),
453
- onClick: s,
562
+ icon: /* @__PURE__ */ jsx(SpacebarIcon, {}),
563
+ onClick: onSpace,
454
564
  extraClass: "space",
455
565
  text: "Space"
456
566
  },
457
567
  "space"
458
568
  ),
459
- e === "email" && /* @__PURE__ */ a(
460
- T,
569
+ inputType === "email" && /* @__PURE__ */ jsx(
570
+ SpecialKey,
461
571
  {
462
572
  type: "at",
463
573
  icon: "@",
464
- onClick: () => o("@"),
574
+ onClick: () => onKeyClick("@"),
465
575
  extraClass: "at",
466
576
  text: ""
467
577
  },
468
578
  "at"
469
579
  ),
470
- /* @__PURE__ */ a(
471
- T,
580
+ /* @__PURE__ */ jsx(
581
+ SpecialKey,
472
582
  {
473
583
  type: "enter",
474
- icon: /* @__PURE__ */ a(j, {}),
475
- onClick: t,
584
+ icon: /* @__PURE__ */ jsx(EnterIcon, {}),
585
+ onClick: onEnter,
476
586
  extraClass: "enter",
477
587
  text: "Enter"
478
588
  },
@@ -480,199 +590,299 @@ const ee = (e, r) => {
480
590
  )
481
591
  ] })
482
592
  ] });
483
- }, ue = ({
484
- currentLayout: e,
485
- capsLock: r,
486
- onKeyClick: n,
487
- onBackspace: t,
488
- onEnter: s,
489
- onSpace: l,
490
- onCapsToggle: c,
491
- onLayoutToggle: o,
492
- inputType: u
593
+ };
594
+ const KeyboardLayout = ({
595
+ currentLayout,
596
+ capsLock,
597
+ onKeyClick,
598
+ onBackspace,
599
+ onEnter,
600
+ onSpace,
601
+ onCapsToggle,
602
+ onLayoutToggle,
603
+ inputType,
604
+ customLayouts
493
605
  }) => {
494
- const f = e === "letters" ? ne : e === "symbols" ? se : re;
495
- return e === "numbers" ? /* @__PURE__ */ a(
496
- le,
497
- {
498
- currentLayoutData: f,
499
- onBackspace: t,
500
- onEnter: s,
501
- onKeyClick: n,
502
- capsLock: r,
503
- currentLayout: e
504
- }
505
- ) : /* @__PURE__ */ a(
506
- ae,
606
+ 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;
607
+ if (currentLayout === "numbers") {
608
+ return /* @__PURE__ */ jsx(
609
+ NumbersLayout,
610
+ {
611
+ currentLayoutData,
612
+ onBackspace,
613
+ onEnter,
614
+ onKeyClick,
615
+ capsLock,
616
+ currentLayout
617
+ }
618
+ );
619
+ }
620
+ return /* @__PURE__ */ jsx(
621
+ TextLayout,
507
622
  {
508
- inputType: u,
509
- currentLayoutData: f,
510
- onBackspace: t,
511
- onEnter: s,
512
- onSpace: l,
513
- onCapsToggle: c,
514
- onLayoutToggle: o,
515
- onKeyClick: n,
516
- capsLock: r,
517
- currentLayout: e
623
+ inputType,
624
+ currentLayoutData,
625
+ onBackspace,
626
+ onEnter,
627
+ onSpace,
628
+ onCapsToggle,
629
+ onLayoutToggle,
630
+ onKeyClick,
631
+ capsLock,
632
+ currentLayout
518
633
  }
519
634
  );
520
- }, ie = ({
521
- children: e,
522
- className: r = ""
635
+ };
636
+ const VirtualKeyboardContainer = ({
637
+ children,
638
+ className = ""
523
639
  }) => {
524
- const n = (l) => {
525
- l.preventDefault();
526
- }, t = (l) => {
527
- l.preventDefault(), l.stopPropagation();
528
- }, s = ["vk-container", r].filter(Boolean).join(" ");
529
- return /* @__PURE__ */ a(
640
+ const handleMouseDown = (e) => {
641
+ e.preventDefault();
642
+ };
643
+ const handleClick = (e) => {
644
+ e.preventDefault();
645
+ e.stopPropagation();
646
+ };
647
+ const containerClasses = ["vk-container", className].filter(Boolean).join(" ");
648
+ return /* @__PURE__ */ jsx(
530
649
  "div",
531
650
  {
532
- className: s,
533
- onMouseDown: n,
534
- onClick: t,
651
+ className: containerClasses,
652
+ onMouseDown: handleMouseDown,
653
+ onClick: handleClick,
535
654
  "data-testid": "keyboard-container",
536
- children: e
655
+ children
537
656
  }
538
657
  );
539
- }, de = ({
540
- focusedInputRef: e,
541
- isInputFocused: r,
542
- inputType: n = "text",
543
- onEnterClick: t,
544
- onChange: s,
545
- className: l,
546
- defaultLayout: c = "letters",
547
- validate: o
658
+ };
659
+ const VirtualKeyboard = ({
660
+ focusedInputRef,
661
+ isInputFocused,
662
+ inputType = "text",
663
+ onEnterClick,
664
+ onChange,
665
+ className,
666
+ defaultLayout = "letters",
667
+ validate,
668
+ syncWithHardwareKeyboard = true,
669
+ customLayouts,
670
+ languages,
671
+ currentLanguage,
672
+ onLanguageChange,
673
+ showLanguageSwitcher = false
548
674
  }) => {
549
- const [u, f] = H(!1), { insertText: d, backspace: v } = Y(e), [m, h] = H(
550
- () => K(n, c)
551
- ), w = k(
552
- (p) => {
553
- var x;
554
- o && !o(p) || ee(p, n) && (d(p), s == null || s(((x = e.current) == null ? void 0 : x.value) ?? ""));
675
+ const [capsLock, setCapsLock] = useState(false);
676
+ const [selectedLanguage, setSelectedLanguage] = useState(currentLanguage || Object.keys(languages || {})[0] || "en");
677
+ const { insertText, backspace } = createCaretManager(() => focusedInputRef.current);
678
+ const [currentLayout, setCurrentLayout] = useState(
679
+ () => getInitialLayout(inputType, defaultLayout)
680
+ );
681
+ const updateValue = useCallback(
682
+ (next) => {
683
+ var _a;
684
+ if (validate && !validate(next)) return;
685
+ if (!validateValueUtil(next, inputType)) return;
686
+ insertText(next);
687
+ onChange == null ? void 0 : onChange(((_a = focusedInputRef.current) == null ? void 0 : _a.value) ?? "");
555
688
  },
556
- [e, n, d, s, o]
557
- ), y = k(
558
- (p) => {
559
- w(p);
689
+ [focusedInputRef, inputType, insertText, onChange, validate]
690
+ );
691
+ const handleKeyClick = useCallback(
692
+ (key) => {
693
+ updateValue(key);
560
694
  },
561
- [w]
562
- ), b = k(() => {
563
- var p, x;
564
- ((p = e.current) == null ? void 0 : p.value.length) !== 0 && (v(), s == null || s(((x = e.current) == null ? void 0 : x.value) ?? ""));
565
- }, [v, e, s]), S = k(() => {
566
- t == null || t();
567
- }, [t]), i = k(() => {
568
- w(" ");
569
- }, [w]), E = k(() => {
570
- f((p) => !p);
571
- }, []), I = k(() => {
572
- n !== "number" && h((p) => p === "letters" ? "symbols" : "letters");
573
- }, [n]);
574
- $(() => {
575
- h(K(n, c));
576
- }, [n, c]);
577
- const N = {
578
- onBackspace: b,
579
- onEnter: S,
580
- onSpace: i,
581
- onCapsToggle: E,
582
- onKeyClick: y
695
+ [updateValue]
696
+ );
697
+ const handleBackspace = useCallback(() => {
698
+ var _a, _b;
699
+ if (((_a = focusedInputRef.current) == null ? void 0 : _a.value.length) === 0) return;
700
+ backspace();
701
+ onChange == null ? void 0 : onChange(((_b = focusedInputRef.current) == null ? void 0 : _b.value) ?? "");
702
+ }, [backspace, focusedInputRef, onChange]);
703
+ const handleEnter = useCallback(() => {
704
+ onEnterClick == null ? void 0 : onEnterClick();
705
+ }, [onEnterClick]);
706
+ const handleSpace = useCallback(() => {
707
+ var _a;
708
+ updateValue(" ");
709
+ insertText(" ");
710
+ onChange == null ? void 0 : onChange(((_a = focusedInputRef.current) == null ? void 0 : _a.value) || "");
711
+ }, [insertText, onChange, focusedInputRef]);
712
+ const handleCapsToggle = useCallback(() => {
713
+ setCapsLock((prev) => !prev);
714
+ }, []);
715
+ useEffect(() => {
716
+ setCurrentLayout(getInitialLayout(inputType, defaultLayout));
717
+ }, [inputType, defaultLayout]);
718
+ const keysHandlers = {
719
+ onBackspace: handleBackspace,
720
+ onEnter: handleEnter,
721
+ onSpace: handleSpace,
722
+ onCapsToggle: handleCapsToggle,
723
+ onKeyClick: handleKeyClick
583
724
  };
584
- return G({
585
- isInputFocused: r,
586
- ...N
587
- }), /* @__PURE__ */ a(ie, { className: l, children: /* @__PURE__ */ a(
588
- ue,
589
- {
590
- currentLayout: m,
591
- capsLock: u,
592
- ...N,
593
- onLayoutToggle: I,
594
- inputType: n
595
- }
596
- ) });
597
- }, he = ({
598
- enabled: e = !0,
599
- className: r,
600
- onVisibilityChange: n,
601
- onEnterClick: t,
602
- onChange: s
725
+ useEffect(() => {
726
+ if (!isInputFocused || !syncWithHardwareKeyboard) return;
727
+ return setupHardwareKeyboard(keysHandlers);
728
+ }, [
729
+ isInputFocused,
730
+ syncWithHardwareKeyboard,
731
+ handleKeyClick,
732
+ handleBackspace,
733
+ handleEnter,
734
+ handleSpace,
735
+ handleCapsToggle
736
+ ]);
737
+ const handleLanguageChange = (lang) => {
738
+ setSelectedLanguage(lang);
739
+ onLanguageChange == null ? void 0 : onLanguageChange(lang);
740
+ };
741
+ const activeLayouts = (languages == null ? void 0 : languages[selectedLanguage]) || customLayouts;
742
+ return /* @__PURE__ */ jsxs(VirtualKeyboardContainer, { className, children: [
743
+ showLanguageSwitcher && languages && Object.keys(languages).length > 1 && /* @__PURE__ */ jsx("div", { className: "vk-language-switcher", children: Object.entries(languages).map(([code, config]) => /* @__PURE__ */ jsx(
744
+ "button",
745
+ {
746
+ className: `vk-lang-btn ${selectedLanguage === code ? "active" : ""}`,
747
+ onClick: () => handleLanguageChange(code),
748
+ children: config.label || code.toUpperCase()
749
+ },
750
+ code
751
+ )) }),
752
+ /* @__PURE__ */ jsx(
753
+ KeyboardLayout,
754
+ {
755
+ capsLock,
756
+ currentLayout,
757
+ onKeyClick: handleKeyClick,
758
+ onBackspace: handleBackspace,
759
+ onEnter: handleEnter,
760
+ onSpace: handleSpace,
761
+ onCapsToggle: handleCapsToggle,
762
+ onLayoutToggle: () => setCurrentLayout((prev) => prev === "letters" ? "symbols" : "letters"),
763
+ inputType,
764
+ customLayouts: activeLayouts
765
+ }
766
+ )
767
+ ] });
768
+ };
769
+ const GlobalVirtualKeyboard = ({
770
+ enabled = true,
771
+ className,
772
+ onVisibilityChange,
773
+ onEnterClick,
774
+ onChange
603
775
  }) => {
604
- const l = A(null), [c, o] = H(!1), [u, f] = H("text"), d = A(null), v = A("text"), { scrollInput: m, resetScroll: h } = V(l);
605
- $(() => {
606
- if (!e) {
607
- c && (setTimeout(() => {
608
- o(!1);
609
- }, 0), n == null || n(!1));
776
+ const keyboardContainerRef = useRef(null);
777
+ const [isVisible, setIsVisible] = useState(false);
778
+ const [inputType, setInputType] = useState("text");
779
+ const focusedInputRef = useRef(null);
780
+ const originalInputTypeRef = useRef("text");
781
+ const { scrollInput, resetScroll } = useKeyboardScroll(keyboardContainerRef);
782
+ useEffect(() => {
783
+ if (!enabled) {
784
+ if (isVisible) {
785
+ setTimeout(() => {
786
+ setIsVisible(false);
787
+ }, 0);
788
+ onVisibilityChange == null ? void 0 : onVisibilityChange(false);
789
+ }
610
790
  return;
611
791
  }
612
- const y = (S) => {
613
- const i = M(S);
614
- if (!i) return;
615
- const E = i.tagName === "TEXTAREA", I = E ? "text" : i.type;
616
- if (f(I), o(!0), n == null || n(!0), d.current = i, !E && (v.current = i.type, i.type !== "text")) {
617
- const N = i.selectionStart, p = i.selectionEnd;
618
- i.type = "text";
619
- const x = N ?? i.value.length, P = p ?? x;
620
- i.setSelectionRange(x, P);
792
+ const handleFocus = (event) => {
793
+ const input = validateFocusInputs(event);
794
+ if (!input) return;
795
+ const isTextarea = input.tagName === "TEXTAREA";
796
+ const detectedInputType = isTextarea ? "text" : input.type;
797
+ setInputType(detectedInputType);
798
+ setIsVisible(true);
799
+ onVisibilityChange == null ? void 0 : onVisibilityChange(true);
800
+ focusedInputRef.current = input;
801
+ if (!isTextarea) {
802
+ originalInputTypeRef.current = input.type;
803
+ if (input.type !== "text") {
804
+ const selectionStart = input.selectionStart;
805
+ const selectionEnd = input.selectionEnd;
806
+ input.type = "text";
807
+ const caretPos = selectionStart ?? input.value.length;
808
+ const caretEnd = selectionEnd ?? caretPos;
809
+ input.setSelectionRange(caretPos, caretEnd);
810
+ }
621
811
  }
622
- m(i);
623
- }, b = (S) => {
624
- const i = M(S);
625
- if (!i) return;
626
- i.tagName === "TEXTAREA" || (i.type = v.current), d.current === i && (d.current = null, o(!1), n == null || n(!1), h());
812
+ scrollInput(input);
627
813
  };
628
- return document.addEventListener("focusin", y, !0), document.addEventListener("focusout", b, !0), () => {
629
- document.removeEventListener("focusin", y, !0), document.removeEventListener("focusout", b, !0);
814
+ const handleBlur = (event) => {
815
+ const input = validateFocusInputs(event);
816
+ if (!input) return;
817
+ const isTextarea = input.tagName === "TEXTAREA";
818
+ if (!isTextarea) {
819
+ input.type = originalInputTypeRef.current;
820
+ }
821
+ if (focusedInputRef.current === input) {
822
+ focusedInputRef.current = null;
823
+ setIsVisible(false);
824
+ onVisibilityChange == null ? void 0 : onVisibilityChange(false);
825
+ resetScroll();
826
+ }
827
+ };
828
+ document.addEventListener("focusin", handleFocus, true);
829
+ document.addEventListener("focusout", handleBlur, true);
830
+ return () => {
831
+ document.removeEventListener("focusin", handleFocus, true);
832
+ document.removeEventListener("focusout", handleBlur, true);
630
833
  };
631
- }, [e, m, h, n]);
632
- const w = () => {
633
- o(!1), n == null || n(!1), te(d), t == null || t(), h();
834
+ }, [enabled, scrollInput, resetScroll, onVisibilityChange]);
835
+ const handleEnterClick = () => {
836
+ setIsVisible(false);
837
+ onVisibilityChange == null ? void 0 : onVisibilityChange(false);
838
+ onEnterClickUtil(focusedInputRef);
839
+ onEnterClick == null ? void 0 : onEnterClick();
840
+ resetScroll();
634
841
  };
635
- return !c || !e ? null : /* @__PURE__ */ a("span", { ref: l, children: /* @__PURE__ */ a(
636
- de,
842
+ if (!isVisible || !enabled) {
843
+ return null;
844
+ }
845
+ return /* @__PURE__ */ jsx("span", { ref: keyboardContainerRef, children: /* @__PURE__ */ jsx(
846
+ VirtualKeyboard,
637
847
  {
638
- focusedInputRef: d,
639
- isInputFocused: c,
640
- inputType: u,
641
- onEnterClick: w,
642
- onChange: s,
643
- className: r
848
+ focusedInputRef,
849
+ isInputFocused: isVisible,
850
+ inputType,
851
+ onEnterClick: handleEnterClick,
852
+ onChange,
853
+ className
644
854
  }
645
855
  ) });
646
856
  };
647
857
  export {
648
- U as BackspaceIcon,
649
- oe as CapsLockIcon,
650
- ve as DEFAULT_THEME,
651
- j as EnterIcon,
652
- he as GlobalVirtualKeyboard,
653
- ue as KeyboardLayout,
654
- O as KeyboardRow,
655
- re as NUMBERS_LAYOUT,
656
- le as NumbersLayout,
657
- ne as QWERTY_LAYOUT,
658
- se as SYMBOLS_LAYOUT,
659
- ce as SpacebarIcon,
660
- T as SpecialKey,
661
- ae as TextLayout,
662
- z as VirtualKey,
663
- de as VirtualKeyboard,
664
- ie as VirtualKeyboardContainer,
665
- K as getInitialLayout,
666
- me as handleValueChangeUtil,
667
- te as onEnterClickUtil,
668
- C as resetScrollPosition,
669
- J as scrollInputIntoView,
670
- B as setInputValueAndDispatchEvents,
671
- Y as useCaretManager,
672
- F as useContinuousPress,
673
- G as useHardwareKeyboard,
674
- V as useKeyboardScroll,
675
- M as validateFocusInputs,
676
- ee as validateValueUtil
858
+ BackspaceIcon,
859
+ CapsLockIcon,
860
+ DEFAULT_THEME,
861
+ EnterIcon,
862
+ GlobalVirtualKeyboard,
863
+ KeyboardLayout,
864
+ KeyboardRow,
865
+ NUMBERS_LAYOUT,
866
+ NumbersLayout,
867
+ QWERTY_LAYOUT,
868
+ SYMBOLS_LAYOUT,
869
+ SpacebarIcon,
870
+ SpecialKey,
871
+ TextLayout,
872
+ VirtualKey,
873
+ VirtualKeyboard,
874
+ VirtualKeyboardContainer,
875
+ createCaretManager,
876
+ getInitialLayout,
877
+ handleValueChangeUtil,
878
+ onEnterClickUtil,
879
+ resetScrollPosition,
880
+ scrollInputIntoView,
881
+ setInputValueAndDispatchEvents,
882
+ setupHardwareKeyboard,
883
+ useContinuousPress,
884
+ useKeyboardScroll,
885
+ validateFocusInputs,
886
+ validateValueUtil
677
887
  };
678
888
  //# sourceMappingURL=index.esm.js.map