@composy/keyboard-core 0.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.
Files changed (337) hide show
  1. package/README.md +37 -0
  2. package/dist/index.js +3605 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/index.min.js +1 -0
  5. package/es/icons.d.ts +58 -0
  6. package/es/icons.d.ts.map +1 -0
  7. package/es/icons.js +34 -0
  8. package/es/icons.js.map +1 -0
  9. package/es/index.d.ts +12 -0
  10. package/es/index.d.ts.map +1 -0
  11. package/es/index.js +36 -0
  12. package/es/layouts/amount.d.ts +14 -0
  13. package/es/layouts/amount.d.ts.map +1 -0
  14. package/es/layouts/amount.js +175 -0
  15. package/es/layouts/amount.js.map +1 -0
  16. package/es/layouts/bankcard.d.ts +15 -0
  17. package/es/layouts/bankcard.d.ts.map +1 -0
  18. package/es/layouts/bankcard.js +99 -0
  19. package/es/layouts/bankcard.js.map +1 -0
  20. package/es/layouts/email.d.ts +11 -0
  21. package/es/layouts/email.d.ts.map +1 -0
  22. package/es/layouts/email.js +126 -0
  23. package/es/layouts/email.js.map +1 -0
  24. package/es/layouts/idcard.d.ts +16 -0
  25. package/es/layouts/idcard.d.ts.map +1 -0
  26. package/es/layouts/idcard.js +99 -0
  27. package/es/layouts/idcard.js.map +1 -0
  28. package/es/layouts/index.d.ts +54 -0
  29. package/es/layouts/index.d.ts.map +1 -0
  30. package/es/layouts/index.js +78 -0
  31. package/es/layouts/index.js.map +1 -0
  32. package/es/layouts/license-plate.d.ts +35 -0
  33. package/es/layouts/license-plate.d.ts.map +1 -0
  34. package/es/layouts/license-plate.js +290 -0
  35. package/es/layouts/license-plate.js.map +1 -0
  36. package/es/layouts/number.d.ts +14 -0
  37. package/es/layouts/number.d.ts.map +1 -0
  38. package/es/layouts/number.js +168 -0
  39. package/es/layouts/number.js.map +1 -0
  40. package/es/layouts/phone.d.ts +15 -0
  41. package/es/layouts/phone.d.ts.map +1 -0
  42. package/es/layouts/phone.js +175 -0
  43. package/es/layouts/phone.js.map +1 -0
  44. package/es/layouts/punct.d.ts +7 -0
  45. package/es/layouts/punct.d.ts.map +1 -0
  46. package/es/layouts/punct.js +112 -0
  47. package/es/layouts/punct.js.map +1 -0
  48. package/es/layouts/qwerty.d.ts +10 -0
  49. package/es/layouts/qwerty.d.ts.map +1 -0
  50. package/es/layouts/qwerty.js +116 -0
  51. package/es/layouts/qwerty.js.map +1 -0
  52. package/es/layouts/search.d.ts +7 -0
  53. package/es/layouts/search.d.ts.map +1 -0
  54. package/es/layouts/search.js +101 -0
  55. package/es/layouts/search.js.map +1 -0
  56. package/es/layouts/symbol.d.ts +14 -0
  57. package/es/layouts/symbol.d.ts.map +1 -0
  58. package/es/layouts/symbol.js +194 -0
  59. package/es/layouts/symbol.js.map +1 -0
  60. package/es/layouts/url.d.ts +7 -0
  61. package/es/layouts/url.d.ts.map +1 -0
  62. package/es/layouts/url.js +99 -0
  63. package/es/layouts/url.js.map +1 -0
  64. package/es/layouts/verifycode.d.ts +15 -0
  65. package/es/layouts/verifycode.d.ts.map +1 -0
  66. package/es/layouts/verifycode.js +100 -0
  67. package/es/layouts/verifycode.js.map +1 -0
  68. package/es/managers/index.d.ts +8 -0
  69. package/es/managers/index.d.ts.map +1 -0
  70. package/es/managers/index.js +14 -0
  71. package/es/managers/keyboard-manager.d.ts +130 -0
  72. package/es/managers/keyboard-manager.d.ts.map +1 -0
  73. package/es/managers/keyboard-manager.js +374 -0
  74. package/es/managers/keyboard-manager.js.map +1 -0
  75. package/es/managers/keyboard-renderer.d.ts +115 -0
  76. package/es/managers/keyboard-renderer.d.ts.map +1 -0
  77. package/es/managers/keyboard-renderer.js +283 -0
  78. package/es/managers/keyboard-renderer.js.map +1 -0
  79. package/es/managers/position-manager.d.ts +72 -0
  80. package/es/managers/position-manager.d.ts.map +1 -0
  81. package/es/managers/position-manager.js +199 -0
  82. package/es/managers/position-manager.js.map +1 -0
  83. package/es/themes/index.d.ts +70 -0
  84. package/es/themes/index.d.ts.map +1 -0
  85. package/es/themes/index.js +99 -0
  86. package/es/themes/index.js.map +1 -0
  87. package/es/themes/presets.d.ts +39 -0
  88. package/es/themes/presets.d.ts.map +1 -0
  89. package/es/themes/presets.js +207 -0
  90. package/es/themes/presets.js.map +1 -0
  91. package/es/themes/types.d.ts +118 -0
  92. package/es/themes/types.d.ts.map +1 -0
  93. package/es/themes/types.js +10 -0
  94. package/es/types/index.d.ts +7 -0
  95. package/es/types/index.d.ts.map +1 -0
  96. package/es/types/index.js +10 -0
  97. package/es/types/keyboard.d.ts +253 -0
  98. package/es/types/keyboard.d.ts.map +1 -0
  99. package/es/types/keyboard.js +10 -0
  100. package/es/types/position.d.ts +139 -0
  101. package/es/types/position.d.ts.map +1 -0
  102. package/es/types/position.js +10 -0
  103. package/es/utils/device.d.ts +45 -0
  104. package/es/utils/device.d.ts.map +1 -0
  105. package/es/utils/device.js +111 -0
  106. package/es/utils/device.js.map +1 -0
  107. package/es/utils/dom.d.ts +69 -0
  108. package/es/utils/dom.d.ts.map +1 -0
  109. package/es/utils/dom.js +134 -0
  110. package/es/utils/dom.js.map +1 -0
  111. package/es/utils/event-emitter.d.ts +52 -0
  112. package/es/utils/event-emitter.d.ts.map +1 -0
  113. package/es/utils/event-emitter.js +99 -0
  114. package/es/utils/event-emitter.js.map +1 -0
  115. package/es/utils/formatters.d.ts +51 -0
  116. package/es/utils/formatters.d.ts.map +1 -0
  117. package/es/utils/formatters.js +57 -0
  118. package/es/utils/formatters.js.map +1 -0
  119. package/es/utils/index.d.ts +10 -0
  120. package/es/utils/index.d.ts.map +1 -0
  121. package/es/utils/index.js +16 -0
  122. package/es/utils/random.d.ts +71 -0
  123. package/es/utils/random.d.ts.map +1 -0
  124. package/es/utils/random.js +292 -0
  125. package/es/utils/random.js.map +1 -0
  126. package/esm/icons.d.ts +58 -0
  127. package/esm/icons.d.ts.map +1 -0
  128. package/esm/icons.js +34 -0
  129. package/esm/icons.js.map +1 -0
  130. package/esm/index.d.ts +12 -0
  131. package/esm/index.d.ts.map +1 -0
  132. package/esm/index.js +37 -0
  133. package/esm/layouts/amount.d.ts +14 -0
  134. package/esm/layouts/amount.d.ts.map +1 -0
  135. package/esm/layouts/amount.js +175 -0
  136. package/esm/layouts/amount.js.map +1 -0
  137. package/esm/layouts/bankcard.d.ts +15 -0
  138. package/esm/layouts/bankcard.d.ts.map +1 -0
  139. package/esm/layouts/bankcard.js +99 -0
  140. package/esm/layouts/bankcard.js.map +1 -0
  141. package/esm/layouts/email.d.ts +11 -0
  142. package/esm/layouts/email.d.ts.map +1 -0
  143. package/esm/layouts/email.js +126 -0
  144. package/esm/layouts/email.js.map +1 -0
  145. package/esm/layouts/idcard.d.ts +16 -0
  146. package/esm/layouts/idcard.d.ts.map +1 -0
  147. package/esm/layouts/idcard.js +99 -0
  148. package/esm/layouts/idcard.js.map +1 -0
  149. package/esm/layouts/index.d.ts +54 -0
  150. package/esm/layouts/index.d.ts.map +1 -0
  151. package/esm/layouts/index.js +78 -0
  152. package/esm/layouts/index.js.map +1 -0
  153. package/esm/layouts/license-plate.d.ts +35 -0
  154. package/esm/layouts/license-plate.d.ts.map +1 -0
  155. package/esm/layouts/license-plate.js +290 -0
  156. package/esm/layouts/license-plate.js.map +1 -0
  157. package/esm/layouts/number.d.ts +14 -0
  158. package/esm/layouts/number.d.ts.map +1 -0
  159. package/esm/layouts/number.js +168 -0
  160. package/esm/layouts/number.js.map +1 -0
  161. package/esm/layouts/phone.d.ts +15 -0
  162. package/esm/layouts/phone.d.ts.map +1 -0
  163. package/esm/layouts/phone.js +175 -0
  164. package/esm/layouts/phone.js.map +1 -0
  165. package/esm/layouts/punct.d.ts +7 -0
  166. package/esm/layouts/punct.d.ts.map +1 -0
  167. package/esm/layouts/punct.js +112 -0
  168. package/esm/layouts/punct.js.map +1 -0
  169. package/esm/layouts/qwerty.d.ts +10 -0
  170. package/esm/layouts/qwerty.d.ts.map +1 -0
  171. package/esm/layouts/qwerty.js +116 -0
  172. package/esm/layouts/qwerty.js.map +1 -0
  173. package/esm/layouts/search.d.ts +7 -0
  174. package/esm/layouts/search.d.ts.map +1 -0
  175. package/esm/layouts/search.js +101 -0
  176. package/esm/layouts/search.js.map +1 -0
  177. package/esm/layouts/symbol.d.ts +14 -0
  178. package/esm/layouts/symbol.d.ts.map +1 -0
  179. package/esm/layouts/symbol.js +194 -0
  180. package/esm/layouts/symbol.js.map +1 -0
  181. package/esm/layouts/url.d.ts +7 -0
  182. package/esm/layouts/url.d.ts.map +1 -0
  183. package/esm/layouts/url.js +99 -0
  184. package/esm/layouts/url.js.map +1 -0
  185. package/esm/layouts/verifycode.d.ts +15 -0
  186. package/esm/layouts/verifycode.d.ts.map +1 -0
  187. package/esm/layouts/verifycode.js +100 -0
  188. package/esm/layouts/verifycode.js.map +1 -0
  189. package/esm/managers/index.d.ts +8 -0
  190. package/esm/managers/index.d.ts.map +1 -0
  191. package/esm/managers/index.js +14 -0
  192. package/esm/managers/keyboard-manager.d.ts +130 -0
  193. package/esm/managers/keyboard-manager.d.ts.map +1 -0
  194. package/esm/managers/keyboard-manager.js +374 -0
  195. package/esm/managers/keyboard-manager.js.map +1 -0
  196. package/esm/managers/keyboard-renderer.d.ts +115 -0
  197. package/esm/managers/keyboard-renderer.d.ts.map +1 -0
  198. package/esm/managers/keyboard-renderer.js +283 -0
  199. package/esm/managers/keyboard-renderer.js.map +1 -0
  200. package/esm/managers/position-manager.d.ts +72 -0
  201. package/esm/managers/position-manager.d.ts.map +1 -0
  202. package/esm/managers/position-manager.js +199 -0
  203. package/esm/managers/position-manager.js.map +1 -0
  204. package/esm/themes/index.d.ts +70 -0
  205. package/esm/themes/index.d.ts.map +1 -0
  206. package/esm/themes/index.js +99 -0
  207. package/esm/themes/index.js.map +1 -0
  208. package/esm/themes/presets.d.ts +39 -0
  209. package/esm/themes/presets.d.ts.map +1 -0
  210. package/esm/themes/presets.js +207 -0
  211. package/esm/themes/presets.js.map +1 -0
  212. package/esm/themes/types.d.ts +118 -0
  213. package/esm/themes/types.d.ts.map +1 -0
  214. package/esm/themes/types.js +10 -0
  215. package/esm/types/index.d.ts +7 -0
  216. package/esm/types/index.d.ts.map +1 -0
  217. package/esm/types/index.js +10 -0
  218. package/esm/types/keyboard.d.ts +253 -0
  219. package/esm/types/keyboard.d.ts.map +1 -0
  220. package/esm/types/keyboard.js +10 -0
  221. package/esm/types/position.d.ts +139 -0
  222. package/esm/types/position.d.ts.map +1 -0
  223. package/esm/types/position.js +10 -0
  224. package/esm/utils/device.d.ts +45 -0
  225. package/esm/utils/device.d.ts.map +1 -0
  226. package/esm/utils/device.js +111 -0
  227. package/esm/utils/device.js.map +1 -0
  228. package/esm/utils/dom.d.ts +69 -0
  229. package/esm/utils/dom.d.ts.map +1 -0
  230. package/esm/utils/dom.js +134 -0
  231. package/esm/utils/dom.js.map +1 -0
  232. package/esm/utils/event-emitter.d.ts +52 -0
  233. package/esm/utils/event-emitter.d.ts.map +1 -0
  234. package/esm/utils/event-emitter.js +99 -0
  235. package/esm/utils/event-emitter.js.map +1 -0
  236. package/esm/utils/formatters.d.ts +51 -0
  237. package/esm/utils/formatters.d.ts.map +1 -0
  238. package/esm/utils/formatters.js +57 -0
  239. package/esm/utils/formatters.js.map +1 -0
  240. package/esm/utils/index.d.ts +10 -0
  241. package/esm/utils/index.d.ts.map +1 -0
  242. package/esm/utils/index.js +16 -0
  243. package/esm/utils/random.d.ts +71 -0
  244. package/esm/utils/random.d.ts.map +1 -0
  245. package/esm/utils/random.js +292 -0
  246. package/esm/utils/random.js.map +1 -0
  247. package/lib/icons.cjs +44 -0
  248. package/lib/icons.cjs.map +1 -0
  249. package/lib/icons.d.ts +58 -0
  250. package/lib/index.cjs +141 -0
  251. package/lib/index.d.ts +12 -0
  252. package/lib/layouts/amount.cjs +177 -0
  253. package/lib/layouts/amount.cjs.map +1 -0
  254. package/lib/layouts/amount.d.ts +14 -0
  255. package/lib/layouts/bankcard.cjs +100 -0
  256. package/lib/layouts/bankcard.cjs.map +1 -0
  257. package/lib/layouts/bankcard.d.ts +15 -0
  258. package/lib/layouts/email.cjs +128 -0
  259. package/lib/layouts/email.cjs.map +1 -0
  260. package/lib/layouts/email.d.ts +11 -0
  261. package/lib/layouts/idcard.cjs +100 -0
  262. package/lib/layouts/idcard.cjs.map +1 -0
  263. package/lib/layouts/idcard.d.ts +16 -0
  264. package/lib/layouts/index.cjs +107 -0
  265. package/lib/layouts/index.cjs.map +1 -0
  266. package/lib/layouts/index.d.ts +54 -0
  267. package/lib/layouts/license-plate.cjs +296 -0
  268. package/lib/layouts/license-plate.cjs.map +1 -0
  269. package/lib/layouts/license-plate.d.ts +35 -0
  270. package/lib/layouts/number.cjs +170 -0
  271. package/lib/layouts/number.cjs.map +1 -0
  272. package/lib/layouts/number.d.ts +14 -0
  273. package/lib/layouts/phone.cjs +177 -0
  274. package/lib/layouts/phone.cjs.map +1 -0
  275. package/lib/layouts/phone.d.ts +15 -0
  276. package/lib/layouts/punct.cjs +113 -0
  277. package/lib/layouts/punct.cjs.map +1 -0
  278. package/lib/layouts/punct.d.ts +7 -0
  279. package/lib/layouts/qwerty.cjs +117 -0
  280. package/lib/layouts/qwerty.cjs.map +1 -0
  281. package/lib/layouts/qwerty.d.ts +10 -0
  282. package/lib/layouts/search.cjs +102 -0
  283. package/lib/layouts/search.cjs.map +1 -0
  284. package/lib/layouts/search.d.ts +7 -0
  285. package/lib/layouts/symbol.cjs +196 -0
  286. package/lib/layouts/symbol.cjs.map +1 -0
  287. package/lib/layouts/symbol.d.ts +14 -0
  288. package/lib/layouts/url.cjs +100 -0
  289. package/lib/layouts/url.cjs.map +1 -0
  290. package/lib/layouts/url.d.ts +7 -0
  291. package/lib/layouts/verifycode.cjs +101 -0
  292. package/lib/layouts/verifycode.cjs.map +1 -0
  293. package/lib/layouts/verifycode.d.ts +15 -0
  294. package/lib/managers/index.cjs +20 -0
  295. package/lib/managers/index.d.ts +8 -0
  296. package/lib/managers/keyboard-manager.cjs +376 -0
  297. package/lib/managers/keyboard-manager.cjs.map +1 -0
  298. package/lib/managers/keyboard-manager.d.ts +130 -0
  299. package/lib/managers/keyboard-renderer.cjs +285 -0
  300. package/lib/managers/keyboard-renderer.cjs.map +1 -0
  301. package/lib/managers/keyboard-renderer.d.ts +115 -0
  302. package/lib/managers/position-manager.cjs +201 -0
  303. package/lib/managers/position-manager.cjs.map +1 -0
  304. package/lib/managers/position-manager.d.ts +72 -0
  305. package/lib/package.json +3 -0
  306. package/lib/themes/index.cjs +117 -0
  307. package/lib/themes/index.cjs.map +1 -0
  308. package/lib/themes/index.d.ts +70 -0
  309. package/lib/themes/presets.cjs +214 -0
  310. package/lib/themes/presets.cjs.map +1 -0
  311. package/lib/themes/presets.d.ts +39 -0
  312. package/lib/themes/types.cjs +11 -0
  313. package/lib/themes/types.d.ts +118 -0
  314. package/lib/types/index.cjs +11 -0
  315. package/lib/types/index.d.ts +7 -0
  316. package/lib/types/keyboard.cjs +11 -0
  317. package/lib/types/keyboard.d.ts +253 -0
  318. package/lib/types/position.cjs +11 -0
  319. package/lib/types/position.d.ts +139 -0
  320. package/lib/utils/device.cjs +120 -0
  321. package/lib/utils/device.cjs.map +1 -0
  322. package/lib/utils/device.d.ts +45 -0
  323. package/lib/utils/dom.cjs +148 -0
  324. package/lib/utils/dom.cjs.map +1 -0
  325. package/lib/utils/dom.d.ts +69 -0
  326. package/lib/utils/event-emitter.cjs +100 -0
  327. package/lib/utils/event-emitter.cjs.map +1 -0
  328. package/lib/utils/event-emitter.d.ts +52 -0
  329. package/lib/utils/formatters.cjs +66 -0
  330. package/lib/utils/formatters.cjs.map +1 -0
  331. package/lib/utils/formatters.d.ts +51 -0
  332. package/lib/utils/index.cjs +58 -0
  333. package/lib/utils/index.d.ts +10 -0
  334. package/lib/utils/random.cjs +301 -0
  335. package/lib/utils/random.cjs.map +1 -0
  336. package/lib/utils/random.d.ts +71 -0
  337. package/package.json +121 -0
package/dist/index.js ADDED
@@ -0,0 +1,3605 @@
1
+ /*!
2
+ * ***********************************
3
+ * @composy/keyboard-core v0.0.1 *
4
+ * Built with rollup *
5
+ * Build time: 2024-08-17 11:33:29 *
6
+ * Build mode: production *
7
+ * Minified: No *
8
+ * ***********************************
9
+ */
10
+ (function(global, factory) {
11
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.LDesignKeyboardCore = {}));
12
+ })(this, function(exports) {
13
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
14
+ //#region src/layouts/qwerty.ts
15
+ function createCharKey$4(char) {
16
+ return {
17
+ id: `char-${char.toLowerCase()}`,
18
+ type: "char",
19
+ label: {
20
+ lower: char.toLowerCase(),
21
+ upper: char.toUpperCase()
22
+ },
23
+ value: {
24
+ lower: char.toLowerCase(),
25
+ upper: char.toUpperCase()
26
+ }
27
+ };
28
+ }
29
+ const qwertyLayout = {
30
+ type: "qwerty",
31
+ name: "字母键盘",
32
+ supportShift: true,
33
+ defaultUpperCase: false,
34
+ switchable: ["number", "symbol"],
35
+ rows: [
36
+ { keys: [
37
+ createCharKey$4("Q"),
38
+ createCharKey$4("W"),
39
+ createCharKey$4("E"),
40
+ createCharKey$4("R"),
41
+ createCharKey$4("T"),
42
+ createCharKey$4("Y"),
43
+ createCharKey$4("U"),
44
+ createCharKey$4("I"),
45
+ createCharKey$4("O"),
46
+ createCharKey$4("P")
47
+ ] },
48
+ { keys: [
49
+ createCharKey$4("A"),
50
+ createCharKey$4("S"),
51
+ createCharKey$4("D"),
52
+ createCharKey$4("F"),
53
+ createCharKey$4("G"),
54
+ createCharKey$4("H"),
55
+ createCharKey$4("J"),
56
+ createCharKey$4("K"),
57
+ createCharKey$4("L")
58
+ ] },
59
+ { keys: [
60
+ {
61
+ id: "shift",
62
+ type: "shift",
63
+ label: "⇧",
64
+ width: 1.5,
65
+ className: "key-shift"
66
+ },
67
+ createCharKey$4("Z"),
68
+ createCharKey$4("X"),
69
+ createCharKey$4("C"),
70
+ createCharKey$4("V"),
71
+ createCharKey$4("B"),
72
+ createCharKey$4("N"),
73
+ createCharKey$4("M"),
74
+ {
75
+ id: "backspace",
76
+ type: "backspace",
77
+ label: "⌫",
78
+ width: 1.5,
79
+ className: "key-backspace"
80
+ }
81
+ ] },
82
+ { keys: [
83
+ {
84
+ id: "switch-number",
85
+ type: "tab",
86
+ label: "123",
87
+ width: 1.5,
88
+ className: "key-switch",
89
+ data: { targetType: "number" }
90
+ },
91
+ {
92
+ id: "switch-symbol",
93
+ type: "tab",
94
+ label: "#+=",
95
+ width: 1.25,
96
+ className: "key-switch",
97
+ data: { targetType: "symbol" }
98
+ },
99
+ {
100
+ id: "space",
101
+ type: "space",
102
+ label: "空格",
103
+ value: " ",
104
+ width: 4,
105
+ className: "key-space"
106
+ },
107
+ {
108
+ id: "done",
109
+ type: "done",
110
+ label: "完成",
111
+ width: 2,
112
+ className: "key-done"
113
+ }
114
+ ] }
115
+ ]
116
+ };
117
+ //#endregion
118
+ //#region src/icons.ts
119
+ const ICON_DELETE = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 5a2 2 0 0 0-1.344.519l-6.328 5.74a1 1 0 0 0 0 1.481l6.328 5.741A2 2 0 0 0 10 19h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2z"/><path d="m12 9 6 6"/><path d="m18 9-6 6"/></svg>`;
120
+ const ICON_CLEAR = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>`;
121
+ const ICON_CLOSE = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>`;
122
+ const ICON_CHECK = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>`;
123
+ const ICON_ENTER = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 10 4 15 9 20"/><path d="M20 4v7a4 4 0 0 1-4 4H4"/></svg>`;
124
+ const ICON_SHIFT = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18v-6H5l7-7 7 7h-4v6H9z"/></svg>`;
125
+ const ICON_SPACE = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 17v1c0 .5-.5 1-1 1H3c-.5 0-1-.5-1-1v-1"/></svg>`;
126
+ const ICON_KEYBOARD = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="16" x="2" y="4" rx="2"/><path d="M6 8h.001"/><path d="M10 8h.001"/><path d="M14 8h.001"/><path d="M18 8h.001"/><path d="M8 12h.001"/><path d="M12 12h.001"/><path d="M16 12h.001"/><path d="M7 16h10"/></svg>`;
127
+ const ICON_VOICE = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" x2="12" y1="19" y2="22"/></svg>`;
128
+ const ICONS = {
129
+ delete: ICON_DELETE,
130
+ clear: ICON_CLEAR,
131
+ close: ICON_CLOSE,
132
+ check: ICON_CHECK,
133
+ enter: ICON_ENTER,
134
+ shift: ICON_SHIFT,
135
+ space: ICON_SPACE,
136
+ keyboard: ICON_KEYBOARD,
137
+ voice: ICON_VOICE
138
+ };
139
+ //#endregion
140
+ //#region src/layouts/number.ts
141
+ function createNumberKey$6(num) {
142
+ return {
143
+ id: `num-${num}`,
144
+ type: "char",
145
+ label: num,
146
+ value: num,
147
+ className: "key-num"
148
+ };
149
+ }
150
+ const numberLayout = {
151
+ type: "number",
152
+ name: "数字键盘",
153
+ supportShift: false,
154
+ switchable: ["qwerty", "symbol"],
155
+ rows: [
156
+ {
157
+ className: "numpad-row",
158
+ keys: [
159
+ createNumberKey$6("1"),
160
+ createNumberKey$6("2"),
161
+ createNumberKey$6("3"),
162
+ {
163
+ id: "backspace",
164
+ type: "backspace",
165
+ icon: ICON_DELETE,
166
+ label: "",
167
+ className: "key-numpad-fn"
168
+ }
169
+ ]
170
+ },
171
+ {
172
+ className: "numpad-row",
173
+ keys: [
174
+ createNumberKey$6("4"),
175
+ createNumberKey$6("5"),
176
+ createNumberKey$6("6"),
177
+ {
178
+ id: "clear",
179
+ type: "clear",
180
+ icon: ICON_CLEAR,
181
+ label: "",
182
+ className: "key-numpad-fn"
183
+ }
184
+ ]
185
+ },
186
+ {
187
+ className: "numpad-row",
188
+ keys: [
189
+ createNumberKey$6("7"),
190
+ createNumberKey$6("8"),
191
+ createNumberKey$6("9"),
192
+ {
193
+ id: "close",
194
+ type: "close",
195
+ label: "关闭",
196
+ className: "key-numpad-fn"
197
+ }
198
+ ]
199
+ },
200
+ {
201
+ className: "numpad-row",
202
+ keys: [
203
+ {
204
+ id: "decimal",
205
+ type: "char",
206
+ label: ".",
207
+ value: ".",
208
+ className: "key-num"
209
+ },
210
+ createNumberKey$6("0"),
211
+ {
212
+ id: "done",
213
+ type: "done",
214
+ label: "确定",
215
+ width: 2,
216
+ className: "key-numpad-done"
217
+ }
218
+ ]
219
+ }
220
+ ]
221
+ };
222
+ const integerLayout = {
223
+ type: "integer",
224
+ name: "整数键盘",
225
+ supportShift: false,
226
+ switchable: ["qwerty"],
227
+ rows: [
228
+ {
229
+ className: "numpad-row",
230
+ keys: [
231
+ createNumberKey$6("1"),
232
+ createNumberKey$6("2"),
233
+ createNumberKey$6("3"),
234
+ {
235
+ id: "backspace",
236
+ type: "backspace",
237
+ icon: ICON_DELETE,
238
+ label: "",
239
+ className: "key-numpad-fn"
240
+ }
241
+ ]
242
+ },
243
+ {
244
+ className: "numpad-row",
245
+ keys: [
246
+ createNumberKey$6("4"),
247
+ createNumberKey$6("5"),
248
+ createNumberKey$6("6"),
249
+ {
250
+ id: "clear",
251
+ type: "clear",
252
+ icon: ICON_CLEAR,
253
+ label: "",
254
+ className: "key-numpad-fn"
255
+ }
256
+ ]
257
+ },
258
+ {
259
+ className: "numpad-row",
260
+ keys: [
261
+ createNumberKey$6("7"),
262
+ createNumberKey$6("8"),
263
+ createNumberKey$6("9"),
264
+ {
265
+ id: "close",
266
+ type: "close",
267
+ label: "关闭",
268
+ className: "key-numpad-fn"
269
+ }
270
+ ]
271
+ },
272
+ {
273
+ className: "numpad-row",
274
+ keys: [
275
+ {
276
+ id: "switch-qwerty",
277
+ type: "tab",
278
+ label: "ABC",
279
+ className: "key-numpad-fn",
280
+ data: { targetType: "qwerty" }
281
+ },
282
+ createNumberKey$6("0"),
283
+ {
284
+ id: "done",
285
+ type: "done",
286
+ label: "确定",
287
+ width: 2,
288
+ className: "key-numpad-done"
289
+ }
290
+ ]
291
+ }
292
+ ]
293
+ };
294
+ //#endregion
295
+ //#region src/layouts/symbol.ts
296
+ function createSymbolKey(symbol, id) {
297
+ return {
298
+ id: id || `symbol-${symbol.charCodeAt(0)}`,
299
+ type: "char",
300
+ label: symbol,
301
+ value: symbol
302
+ };
303
+ }
304
+ const symbolLayout = {
305
+ type: "symbol",
306
+ name: "符号键盘",
307
+ supportShift: false,
308
+ switchable: ["qwerty", "number"],
309
+ rows: [
310
+ { keys: [
311
+ createSymbolKey("1"),
312
+ createSymbolKey("2"),
313
+ createSymbolKey("3"),
314
+ createSymbolKey("4"),
315
+ createSymbolKey("5"),
316
+ createSymbolKey("6"),
317
+ createSymbolKey("7"),
318
+ createSymbolKey("8"),
319
+ createSymbolKey("9"),
320
+ createSymbolKey("0")
321
+ ] },
322
+ { keys: [
323
+ createSymbolKey("-"),
324
+ createSymbolKey("/"),
325
+ createSymbolKey(":"),
326
+ createSymbolKey(";"),
327
+ createSymbolKey("("),
328
+ createSymbolKey(")"),
329
+ createSymbolKey("¥", "yen"),
330
+ createSymbolKey("@"),
331
+ createSymbolKey("\"", "quote")
332
+ ] },
333
+ { keys: [
334
+ {
335
+ id: "switch-symbol-2",
336
+ type: "tab",
337
+ label: "#+= ",
338
+ width: 1.5,
339
+ className: "key-switch",
340
+ data: { targetType: "symbol-2" }
341
+ },
342
+ createSymbolKey("."),
343
+ createSymbolKey(","),
344
+ createSymbolKey("?"),
345
+ createSymbolKey("!"),
346
+ createSymbolKey("'", "apostrophe"),
347
+ {
348
+ id: "backspace",
349
+ type: "backspace",
350
+ label: "⌫",
351
+ width: 1.5,
352
+ className: "key-backspace"
353
+ }
354
+ ] },
355
+ { keys: [
356
+ {
357
+ id: "switch-qwerty",
358
+ type: "tab",
359
+ label: "ABC",
360
+ width: 1.5,
361
+ className: "key-switch",
362
+ data: { targetType: "qwerty" }
363
+ },
364
+ {
365
+ id: "switch-number",
366
+ type: "tab",
367
+ label: "123",
368
+ width: 1.25,
369
+ className: "key-switch",
370
+ data: { targetType: "number" }
371
+ },
372
+ {
373
+ id: "space",
374
+ type: "space",
375
+ label: "空格",
376
+ value: " ",
377
+ width: 4,
378
+ className: "key-space"
379
+ },
380
+ {
381
+ id: "done",
382
+ type: "done",
383
+ label: "完成",
384
+ width: 2,
385
+ className: "key-done"
386
+ }
387
+ ] }
388
+ ]
389
+ };
390
+ const symbolLayout2 = {
391
+ type: "symbol",
392
+ name: "符号键盘2",
393
+ supportShift: false,
394
+ switchable: ["qwerty", "number"],
395
+ rows: [
396
+ { keys: [
397
+ createSymbolKey("["),
398
+ createSymbolKey("]"),
399
+ createSymbolKey("{"),
400
+ createSymbolKey("}"),
401
+ createSymbolKey("#"),
402
+ createSymbolKey("%"),
403
+ createSymbolKey("^"),
404
+ createSymbolKey("*"),
405
+ createSymbolKey("+"),
406
+ createSymbolKey("=")
407
+ ] },
408
+ { keys: [
409
+ createSymbolKey("_"),
410
+ createSymbolKey("\\"),
411
+ createSymbolKey("|"),
412
+ createSymbolKey("~"),
413
+ createSymbolKey("<"),
414
+ createSymbolKey(">"),
415
+ createSymbolKey("€", "euro"),
416
+ createSymbolKey("$"),
417
+ createSymbolKey("&")
418
+ ] },
419
+ { keys: [
420
+ {
421
+ id: "switch-symbol-1",
422
+ type: "tab",
423
+ label: "123",
424
+ width: 1.5,
425
+ className: "key-switch",
426
+ data: { targetType: "symbol" }
427
+ },
428
+ createSymbolKey("`", "backtick"),
429
+ createSymbolKey("·", "middle-dot"),
430
+ createSymbolKey("…", "ellipsis"),
431
+ createSymbolKey("°", "degree"),
432
+ createSymbolKey("•", "bullet"),
433
+ {
434
+ id: "backspace",
435
+ type: "backspace",
436
+ label: "⌫",
437
+ width: 1.5,
438
+ className: "key-backspace"
439
+ }
440
+ ] },
441
+ { keys: [
442
+ {
443
+ id: "switch-qwerty",
444
+ type: "tab",
445
+ label: "ABC",
446
+ width: 1.5,
447
+ className: "key-switch",
448
+ data: { targetType: "qwerty" }
449
+ },
450
+ {
451
+ id: "switch-number",
452
+ type: "tab",
453
+ label: "123",
454
+ width: 1.25,
455
+ className: "key-switch",
456
+ data: { targetType: "number" }
457
+ },
458
+ {
459
+ id: "space",
460
+ type: "space",
461
+ label: "空格",
462
+ value: " ",
463
+ width: 4,
464
+ className: "key-space"
465
+ },
466
+ {
467
+ id: "done",
468
+ type: "done",
469
+ label: "完成",
470
+ width: 2,
471
+ className: "key-done"
472
+ }
473
+ ] }
474
+ ]
475
+ };
476
+ //#endregion
477
+ //#region src/layouts/license-plate.ts
478
+ const PROVINCES = [
479
+ "京",
480
+ "津",
481
+ "沪",
482
+ "渝",
483
+ "冀",
484
+ "豫",
485
+ "云",
486
+ "辽",
487
+ "黑",
488
+ "湘",
489
+ "皖",
490
+ "鲁",
491
+ "新",
492
+ "苏",
493
+ "浙",
494
+ "赣",
495
+ "鄂",
496
+ "桂",
497
+ "甘",
498
+ "晋",
499
+ "蒙",
500
+ "陕",
501
+ "吉",
502
+ "闽",
503
+ "贵",
504
+ "粤",
505
+ "青",
506
+ "藏",
507
+ "川",
508
+ "宁",
509
+ "琼",
510
+ "港",
511
+ "澳"
512
+ ];
513
+ const PLATE_LETTERS = [
514
+ "A",
515
+ "B",
516
+ "C",
517
+ "D",
518
+ "E",
519
+ "F",
520
+ "G",
521
+ "H",
522
+ "J",
523
+ "K",
524
+ "L",
525
+ "M",
526
+ "N",
527
+ "P",
528
+ "Q",
529
+ "R",
530
+ "S",
531
+ "T",
532
+ "U",
533
+ "V",
534
+ "W",
535
+ "X",
536
+ "Y",
537
+ "Z"
538
+ ];
539
+ function createProvinceKey(province) {
540
+ return {
541
+ id: `province-${province}`,
542
+ type: "char",
543
+ label: province,
544
+ value: province,
545
+ className: "key-plate-province",
546
+ data: { switchAfterInput: "license-plate-alphanumeric" }
547
+ };
548
+ }
549
+ function createLetterKey(letter) {
550
+ return {
551
+ id: `letter-${letter}`,
552
+ type: "char",
553
+ label: letter,
554
+ value: letter,
555
+ className: "key-plate-letter"
556
+ };
557
+ }
558
+ function createNumberKey$5(num) {
559
+ return {
560
+ id: `num-${num}`,
561
+ type: "char",
562
+ label: num,
563
+ value: num,
564
+ className: "key-plate-number"
565
+ };
566
+ }
567
+ const licensePlateProvinceLayout = {
568
+ type: "license-plate-province",
569
+ name: "省份简称",
570
+ supportShift: false,
571
+ rows: [
572
+ {
573
+ className: "plate-keyboard-row",
574
+ keys: PROVINCES.slice(0, 10).map(createProvinceKey)
575
+ },
576
+ {
577
+ className: "plate-keyboard-row",
578
+ keys: PROVINCES.slice(10, 20).map(createProvinceKey)
579
+ },
580
+ {
581
+ className: "plate-keyboard-row",
582
+ keys: PROVINCES.slice(20, 30).map(createProvinceKey)
583
+ },
584
+ {
585
+ className: "plate-keyboard-row",
586
+ keys: [
587
+ ...PROVINCES.slice(30, 33).map(createProvinceKey),
588
+ {
589
+ id: "plate-xue",
590
+ type: "char",
591
+ label: "学",
592
+ value: "学",
593
+ className: "key-plate-special",
594
+ data: { switchAfterInput: "license-plate-alphanumeric" }
595
+ },
596
+ {
597
+ id: "plate-jing",
598
+ type: "char",
599
+ label: "警",
600
+ value: "警",
601
+ className: "key-plate-special",
602
+ data: { switchAfterInput: "license-plate-alphanumeric" }
603
+ },
604
+ {
605
+ id: "backspace",
606
+ type: "backspace",
607
+ icon: ICON_DELETE,
608
+ label: "",
609
+ width: 1.5,
610
+ className: "key-plate-fn"
611
+ },
612
+ {
613
+ id: "done",
614
+ type: "done",
615
+ label: "确定",
616
+ width: 2.5,
617
+ className: "key-plate-done"
618
+ }
619
+ ]
620
+ }
621
+ ],
622
+ data: {
623
+ maxLength: 8,
624
+ inputType: "license-plate"
625
+ }
626
+ };
627
+ const licensePlateAlphanumericLayout = {
628
+ type: "license-plate-alphanumeric",
629
+ name: "字母数字",
630
+ supportShift: false,
631
+ rows: [
632
+ {
633
+ className: "plate-keyboard-row",
634
+ keys: "1234567890".split("").map(createNumberKey$5)
635
+ },
636
+ {
637
+ className: "plate-keyboard-row",
638
+ keys: PLATE_LETTERS.slice(0, 10).map(createLetterKey)
639
+ },
640
+ {
641
+ className: "plate-keyboard-row",
642
+ keys: [...PLATE_LETTERS.slice(10, 19).map(createLetterKey), {
643
+ id: "backspace",
644
+ type: "backspace",
645
+ icon: ICON_DELETE,
646
+ label: "",
647
+ className: "key-plate-fn"
648
+ }]
649
+ },
650
+ {
651
+ className: "plate-keyboard-row",
652
+ keys: [
653
+ {
654
+ id: "switch-province",
655
+ type: "tab",
656
+ label: "省份",
657
+ width: 1.5,
658
+ className: "key-plate-switch",
659
+ data: { targetType: "license-plate-province" }
660
+ },
661
+ ...PLATE_LETTERS.slice(19, 24).map(createLetterKey),
662
+ {
663
+ id: "plate-xue",
664
+ type: "char",
665
+ label: "学",
666
+ value: "学",
667
+ className: "key-plate-special"
668
+ },
669
+ {
670
+ id: "plate-jing",
671
+ type: "char",
672
+ label: "警",
673
+ value: "警",
674
+ className: "key-plate-special"
675
+ },
676
+ {
677
+ id: "done",
678
+ type: "done",
679
+ label: "确定",
680
+ width: 1.5,
681
+ className: "key-plate-done"
682
+ }
683
+ ]
684
+ }
685
+ ],
686
+ data: {
687
+ maxLength: 8,
688
+ inputType: "license-plate"
689
+ }
690
+ };
691
+ const licensePlateLetterLayout = {
692
+ type: "license-plate-letter",
693
+ name: "字母",
694
+ supportShift: false,
695
+ rows: [
696
+ {
697
+ className: "plate-keyboard-row",
698
+ keys: PLATE_LETTERS.slice(0, 8).map(createLetterKey)
699
+ },
700
+ {
701
+ className: "plate-keyboard-row",
702
+ keys: PLATE_LETTERS.slice(8, 16).map(createLetterKey)
703
+ },
704
+ {
705
+ className: "plate-keyboard-row",
706
+ keys: [...PLATE_LETTERS.slice(16, 24).map(createLetterKey)]
707
+ },
708
+ {
709
+ className: "plate-keyboard-row",
710
+ keys: [
711
+ {
712
+ id: "switch-province",
713
+ type: "tab",
714
+ label: "省份",
715
+ width: 2,
716
+ className: "key-plate-switch",
717
+ data: { targetType: "license-plate-province" }
718
+ },
719
+ {
720
+ id: "backspace",
721
+ type: "backspace",
722
+ icon: ICON_DELETE,
723
+ label: "",
724
+ width: 2,
725
+ className: "key-plate-fn"
726
+ },
727
+ {
728
+ id: "done",
729
+ type: "done",
730
+ label: "确定",
731
+ width: 2,
732
+ className: "key-plate-done"
733
+ }
734
+ ]
735
+ }
736
+ ],
737
+ data: {
738
+ maxLength: 8,
739
+ inputType: "license-plate"
740
+ }
741
+ };
742
+ const licensePlateLayout = {
743
+ type: "license-plate",
744
+ name: "车牌号键盘",
745
+ supportShift: false,
746
+ data: {
747
+ autoSwitch: true,
748
+ maxLength: 8,
749
+ inputType: "license-plate"
750
+ },
751
+ rows: licensePlateProvinceLayout.rows
752
+ };
753
+ //#endregion
754
+ //#region src/layouts/idcard.ts
755
+ function createNumberKey$4(num) {
756
+ return {
757
+ id: `idcard-${num}`,
758
+ type: "char",
759
+ label: num,
760
+ value: num,
761
+ className: "key-num"
762
+ };
763
+ }
764
+ const idcardLayout = {
765
+ type: "idcard",
766
+ name: "身份证键盘",
767
+ supportShift: false,
768
+ rows: [
769
+ {
770
+ className: "numpad-row",
771
+ keys: [
772
+ createNumberKey$4("1"),
773
+ createNumberKey$4("2"),
774
+ createNumberKey$4("3"),
775
+ {
776
+ id: "backspace",
777
+ type: "backspace",
778
+ icon: ICON_DELETE,
779
+ label: "",
780
+ className: "key-numpad-fn"
781
+ }
782
+ ]
783
+ },
784
+ {
785
+ className: "numpad-row",
786
+ keys: [
787
+ createNumberKey$4("4"),
788
+ createNumberKey$4("5"),
789
+ createNumberKey$4("6"),
790
+ {
791
+ id: "clear",
792
+ type: "clear",
793
+ icon: ICON_CLEAR,
794
+ label: "",
795
+ className: "key-numpad-fn"
796
+ }
797
+ ]
798
+ },
799
+ {
800
+ className: "numpad-row",
801
+ keys: [
802
+ createNumberKey$4("7"),
803
+ createNumberKey$4("8"),
804
+ createNumberKey$4("9"),
805
+ {
806
+ id: "idcard-x",
807
+ type: "char",
808
+ label: "X",
809
+ value: "X",
810
+ className: "key-num"
811
+ }
812
+ ]
813
+ },
814
+ {
815
+ className: "numpad-row",
816
+ keys: [
817
+ {
818
+ id: "close",
819
+ type: "close",
820
+ label: "关闭",
821
+ className: "key-numpad-fn"
822
+ },
823
+ createNumberKey$4("0"),
824
+ {
825
+ id: "done",
826
+ type: "done",
827
+ label: "确定",
828
+ width: 2,
829
+ className: "key-numpad-done"
830
+ }
831
+ ]
832
+ }
833
+ ],
834
+ data: {
835
+ maxLength: 18,
836
+ inputType: "idcard"
837
+ }
838
+ };
839
+ //#endregion
840
+ //#region src/layouts/phone.ts
841
+ function createNumberKey$3(num) {
842
+ return {
843
+ id: `phone-${num}`,
844
+ type: "char",
845
+ label: num,
846
+ value: num,
847
+ className: "key-num"
848
+ };
849
+ }
850
+ const phoneLayout = {
851
+ type: "phone",
852
+ name: "手机号键盘",
853
+ supportShift: false,
854
+ rows: [
855
+ {
856
+ className: "numpad-row",
857
+ keys: [
858
+ createNumberKey$3("1"),
859
+ createNumberKey$3("2"),
860
+ createNumberKey$3("3"),
861
+ {
862
+ id: "backspace",
863
+ type: "backspace",
864
+ icon: ICON_DELETE,
865
+ label: "",
866
+ className: "key-numpad-fn"
867
+ }
868
+ ]
869
+ },
870
+ {
871
+ className: "numpad-row",
872
+ keys: [
873
+ createNumberKey$3("4"),
874
+ createNumberKey$3("5"),
875
+ createNumberKey$3("6"),
876
+ {
877
+ id: "clear",
878
+ type: "clear",
879
+ icon: ICON_CLEAR,
880
+ label: "",
881
+ className: "key-numpad-fn"
882
+ }
883
+ ]
884
+ },
885
+ {
886
+ className: "numpad-row",
887
+ keys: [
888
+ createNumberKey$3("7"),
889
+ createNumberKey$3("8"),
890
+ createNumberKey$3("9"),
891
+ {
892
+ id: "close",
893
+ type: "close",
894
+ label: "关闭",
895
+ className: "key-numpad-fn"
896
+ }
897
+ ]
898
+ },
899
+ {
900
+ className: "numpad-row",
901
+ keys: [
902
+ {
903
+ id: "phone-plus",
904
+ type: "char",
905
+ label: "+",
906
+ value: "+",
907
+ className: "key-num"
908
+ },
909
+ createNumberKey$3("0"),
910
+ {
911
+ id: "done",
912
+ type: "done",
913
+ label: "确定",
914
+ width: 2,
915
+ className: "key-numpad-done"
916
+ }
917
+ ]
918
+ }
919
+ ],
920
+ data: {
921
+ maxLength: 11,
922
+ inputType: "phone"
923
+ }
924
+ };
925
+ const phoneSimpleLayout = {
926
+ type: "phone-simple",
927
+ name: "拨号键盘",
928
+ supportShift: false,
929
+ rows: [
930
+ {
931
+ className: "numpad-row",
932
+ keys: [
933
+ createNumberKey$3("1"),
934
+ createNumberKey$3("2"),
935
+ createNumberKey$3("3"),
936
+ {
937
+ id: "backspace",
938
+ type: "backspace",
939
+ icon: ICON_DELETE,
940
+ label: "",
941
+ className: "key-numpad-fn"
942
+ }
943
+ ]
944
+ },
945
+ {
946
+ className: "numpad-row",
947
+ keys: [
948
+ createNumberKey$3("4"),
949
+ createNumberKey$3("5"),
950
+ createNumberKey$3("6"),
951
+ {
952
+ id: "clear",
953
+ type: "clear",
954
+ icon: ICON_CLEAR,
955
+ label: "",
956
+ className: "key-numpad-fn"
957
+ }
958
+ ]
959
+ },
960
+ {
961
+ className: "numpad-row",
962
+ keys: [
963
+ createNumberKey$3("7"),
964
+ createNumberKey$3("8"),
965
+ createNumberKey$3("9"),
966
+ {
967
+ id: "phone-hash",
968
+ type: "char",
969
+ label: "#",
970
+ value: "#",
971
+ className: "key-num"
972
+ }
973
+ ]
974
+ },
975
+ {
976
+ className: "numpad-row",
977
+ keys: [
978
+ {
979
+ id: "phone-star",
980
+ type: "char",
981
+ label: "*",
982
+ value: "*",
983
+ className: "key-num"
984
+ },
985
+ createNumberKey$3("0"),
986
+ {
987
+ id: "done",
988
+ type: "done",
989
+ label: "拨打",
990
+ width: 2,
991
+ className: "key-numpad-done"
992
+ }
993
+ ]
994
+ }
995
+ ],
996
+ data: {
997
+ maxLength: 13,
998
+ inputType: "phone"
999
+ }
1000
+ };
1001
+ //#endregion
1002
+ //#region src/layouts/amount.ts
1003
+ function createNumberKey$2(num) {
1004
+ return {
1005
+ id: `amount-${num}`,
1006
+ type: "char",
1007
+ label: num,
1008
+ value: num,
1009
+ className: "key-num"
1010
+ };
1011
+ }
1012
+ const amountLayout = {
1013
+ type: "amount",
1014
+ name: "金额键盘",
1015
+ supportShift: false,
1016
+ rows: [
1017
+ {
1018
+ className: "numpad-row",
1019
+ keys: [
1020
+ createNumberKey$2("1"),
1021
+ createNumberKey$2("2"),
1022
+ createNumberKey$2("3"),
1023
+ {
1024
+ id: "backspace",
1025
+ type: "backspace",
1026
+ icon: ICON_DELETE,
1027
+ label: "",
1028
+ className: "key-numpad-fn"
1029
+ }
1030
+ ]
1031
+ },
1032
+ {
1033
+ className: "numpad-row",
1034
+ keys: [
1035
+ createNumberKey$2("4"),
1036
+ createNumberKey$2("5"),
1037
+ createNumberKey$2("6"),
1038
+ {
1039
+ id: "clear",
1040
+ type: "clear",
1041
+ icon: ICON_CLEAR,
1042
+ label: "",
1043
+ className: "key-numpad-fn"
1044
+ }
1045
+ ]
1046
+ },
1047
+ {
1048
+ className: "numpad-row",
1049
+ keys: [
1050
+ createNumberKey$2("7"),
1051
+ createNumberKey$2("8"),
1052
+ createNumberKey$2("9"),
1053
+ {
1054
+ id: "double-zero",
1055
+ type: "char",
1056
+ label: "00",
1057
+ value: "00",
1058
+ className: "key-num"
1059
+ }
1060
+ ]
1061
+ },
1062
+ {
1063
+ className: "numpad-row",
1064
+ keys: [
1065
+ {
1066
+ id: "decimal",
1067
+ type: "char",
1068
+ label: ".",
1069
+ value: ".",
1070
+ className: "key-num"
1071
+ },
1072
+ createNumberKey$2("0"),
1073
+ {
1074
+ id: "done",
1075
+ type: "done",
1076
+ label: "确定",
1077
+ width: 2,
1078
+ className: "key-numpad-done"
1079
+ }
1080
+ ]
1081
+ }
1082
+ ],
1083
+ data: {
1084
+ inputType: "amount",
1085
+ decimalPlaces: 2
1086
+ }
1087
+ };
1088
+ const amountSimpleLayout = {
1089
+ type: "amount-simple",
1090
+ name: "金额键盘",
1091
+ supportShift: false,
1092
+ rows: [
1093
+ {
1094
+ className: "numpad-row",
1095
+ keys: [
1096
+ createNumberKey$2("1"),
1097
+ createNumberKey$2("2"),
1098
+ createNumberKey$2("3"),
1099
+ {
1100
+ id: "backspace",
1101
+ type: "backspace",
1102
+ icon: ICON_DELETE,
1103
+ label: "",
1104
+ className: "key-numpad-fn"
1105
+ }
1106
+ ]
1107
+ },
1108
+ {
1109
+ className: "numpad-row",
1110
+ keys: [
1111
+ createNumberKey$2("4"),
1112
+ createNumberKey$2("5"),
1113
+ createNumberKey$2("6"),
1114
+ {
1115
+ id: "clear",
1116
+ type: "clear",
1117
+ icon: ICON_CLEAR,
1118
+ label: "",
1119
+ className: "key-numpad-fn"
1120
+ }
1121
+ ]
1122
+ },
1123
+ {
1124
+ className: "numpad-row",
1125
+ keys: [
1126
+ createNumberKey$2("7"),
1127
+ createNumberKey$2("8"),
1128
+ createNumberKey$2("9"),
1129
+ {
1130
+ id: "close",
1131
+ type: "close",
1132
+ label: "关闭",
1133
+ className: "key-numpad-fn"
1134
+ }
1135
+ ]
1136
+ },
1137
+ {
1138
+ className: "numpad-row",
1139
+ keys: [
1140
+ {
1141
+ id: "decimal",
1142
+ type: "char",
1143
+ label: ".",
1144
+ value: ".",
1145
+ className: "key-num"
1146
+ },
1147
+ createNumberKey$2("0"),
1148
+ {
1149
+ id: "done",
1150
+ type: "done",
1151
+ label: "确定",
1152
+ width: 2,
1153
+ className: "key-numpad-done"
1154
+ }
1155
+ ]
1156
+ }
1157
+ ],
1158
+ data: {
1159
+ inputType: "amount",
1160
+ decimalPlaces: 2
1161
+ }
1162
+ };
1163
+ //#endregion
1164
+ //#region src/layouts/bankcard.ts
1165
+ function createNumberKey$1(num) {
1166
+ return {
1167
+ id: `bankcard-${num}`,
1168
+ type: "char",
1169
+ label: num,
1170
+ value: num,
1171
+ className: "key-num"
1172
+ };
1173
+ }
1174
+ const bankcardLayout = {
1175
+ type: "bankcard",
1176
+ name: "银行卡键盘",
1177
+ supportShift: false,
1178
+ rows: [
1179
+ {
1180
+ className: "numpad-row",
1181
+ keys: [
1182
+ createNumberKey$1("1"),
1183
+ createNumberKey$1("2"),
1184
+ createNumberKey$1("3"),
1185
+ {
1186
+ id: "backspace",
1187
+ type: "backspace",
1188
+ icon: ICON_DELETE,
1189
+ label: "",
1190
+ className: "key-numpad-fn"
1191
+ }
1192
+ ]
1193
+ },
1194
+ {
1195
+ className: "numpad-row",
1196
+ keys: [
1197
+ createNumberKey$1("4"),
1198
+ createNumberKey$1("5"),
1199
+ createNumberKey$1("6"),
1200
+ {
1201
+ id: "clear",
1202
+ type: "clear",
1203
+ icon: ICON_CLEAR,
1204
+ label: "",
1205
+ className: "key-numpad-fn"
1206
+ }
1207
+ ]
1208
+ },
1209
+ {
1210
+ className: "numpad-row",
1211
+ keys: [
1212
+ createNumberKey$1("7"),
1213
+ createNumberKey$1("8"),
1214
+ createNumberKey$1("9"),
1215
+ {
1216
+ id: "close",
1217
+ type: "close",
1218
+ label: "关闭",
1219
+ className: "key-numpad-fn"
1220
+ }
1221
+ ]
1222
+ },
1223
+ {
1224
+ className: "numpad-row",
1225
+ keys: [
1226
+ {
1227
+ id: "switch-qwerty",
1228
+ type: "tab",
1229
+ label: "ABC",
1230
+ className: "key-numpad-fn",
1231
+ data: { targetType: "qwerty" }
1232
+ },
1233
+ createNumberKey$1("0"),
1234
+ {
1235
+ id: "done",
1236
+ type: "done",
1237
+ label: "确定",
1238
+ width: 2,
1239
+ className: "key-numpad-done"
1240
+ }
1241
+ ]
1242
+ }
1243
+ ],
1244
+ data: {
1245
+ maxLength: 19,
1246
+ inputType: "bankcard"
1247
+ }
1248
+ };
1249
+ //#endregion
1250
+ //#region src/layouts/verifycode.ts
1251
+ function createNumberKey(num) {
1252
+ return {
1253
+ id: `verify-${num}`,
1254
+ type: "char",
1255
+ label: num,
1256
+ value: num,
1257
+ className: "key-num"
1258
+ };
1259
+ }
1260
+ const verifycodeLayout = {
1261
+ type: "verifycode",
1262
+ name: "验证码键盘",
1263
+ supportShift: false,
1264
+ rows: [
1265
+ {
1266
+ className: "numpad-row",
1267
+ keys: [
1268
+ createNumberKey("1"),
1269
+ createNumberKey("2"),
1270
+ createNumberKey("3"),
1271
+ {
1272
+ id: "backspace",
1273
+ type: "backspace",
1274
+ icon: ICON_DELETE,
1275
+ label: "",
1276
+ className: "key-numpad-fn"
1277
+ }
1278
+ ]
1279
+ },
1280
+ {
1281
+ className: "numpad-row",
1282
+ keys: [
1283
+ createNumberKey("4"),
1284
+ createNumberKey("5"),
1285
+ createNumberKey("6"),
1286
+ {
1287
+ id: "clear",
1288
+ type: "clear",
1289
+ icon: ICON_CLEAR,
1290
+ label: "",
1291
+ className: "key-numpad-fn"
1292
+ }
1293
+ ]
1294
+ },
1295
+ {
1296
+ className: "numpad-row",
1297
+ keys: [
1298
+ createNumberKey("7"),
1299
+ createNumberKey("8"),
1300
+ createNumberKey("9"),
1301
+ {
1302
+ id: "close",
1303
+ type: "close",
1304
+ label: "关闭",
1305
+ className: "key-numpad-fn"
1306
+ }
1307
+ ]
1308
+ },
1309
+ {
1310
+ className: "numpad-row",
1311
+ keys: [
1312
+ {
1313
+ id: "empty",
1314
+ type: "char",
1315
+ label: "",
1316
+ value: "",
1317
+ disabled: true,
1318
+ className: "key-numpad-empty"
1319
+ },
1320
+ createNumberKey("0"),
1321
+ {
1322
+ id: "done",
1323
+ type: "done",
1324
+ label: "确定",
1325
+ width: 2,
1326
+ className: "key-numpad-done"
1327
+ }
1328
+ ]
1329
+ }
1330
+ ],
1331
+ data: {
1332
+ maxLength: 6,
1333
+ inputType: "verifycode"
1334
+ }
1335
+ };
1336
+ //#endregion
1337
+ //#region src/layouts/email.ts
1338
+ function createCharKey$3(char) {
1339
+ return {
1340
+ id: `email-char-${char.toLowerCase()}`,
1341
+ type: "char",
1342
+ label: {
1343
+ lower: char.toLowerCase(),
1344
+ upper: char.toUpperCase()
1345
+ },
1346
+ value: {
1347
+ lower: char.toLowerCase(),
1348
+ upper: char.toUpperCase()
1349
+ }
1350
+ };
1351
+ }
1352
+ function snippet$1(label, id) {
1353
+ return {
1354
+ id: id || `email-snippet-${label.replace(/[^a-z0-9]/gi, "")}`,
1355
+ type: "char",
1356
+ label,
1357
+ value: label,
1358
+ className: "key-snippet"
1359
+ };
1360
+ }
1361
+ const EMAIL_SUFFIXES = [
1362
+ "@qq.com",
1363
+ "@163.com",
1364
+ "@126.com",
1365
+ "@gmail.com",
1366
+ "@outlook.com",
1367
+ "@hotmail.com",
1368
+ "@sina.com",
1369
+ "@sohu.com",
1370
+ "@icloud.com",
1371
+ "@foxmail.com",
1372
+ "@yeah.net",
1373
+ "@139.com"
1374
+ ];
1375
+ const emailLayout = {
1376
+ type: "email",
1377
+ name: "邮箱键盘",
1378
+ supportShift: true,
1379
+ defaultUpperCase: false,
1380
+ switchable: ["symbol", "number"],
1381
+ rows: [
1382
+ { keys: "qwertyuiop".split("").map(createCharKey$3) },
1383
+ { keys: "asdfghjkl".split("").map(createCharKey$3) },
1384
+ { keys: [
1385
+ {
1386
+ id: "shift",
1387
+ type: "shift",
1388
+ icon: ICON_SHIFT,
1389
+ label: "",
1390
+ width: 1.5,
1391
+ className: "key-shift"
1392
+ },
1393
+ ..."zxcvbnm".split("").map(createCharKey$3),
1394
+ {
1395
+ id: "backspace",
1396
+ type: "backspace",
1397
+ icon: ICON_DELETE,
1398
+ label: "",
1399
+ width: 1.5,
1400
+ className: "key-backspace"
1401
+ }
1402
+ ] },
1403
+ { keys: [
1404
+ {
1405
+ id: "switch-number",
1406
+ type: "tab",
1407
+ label: "123",
1408
+ width: 1.25,
1409
+ className: "key-switch",
1410
+ data: { targetType: "number" }
1411
+ },
1412
+ {
1413
+ id: "email-at",
1414
+ type: "char",
1415
+ label: "@",
1416
+ value: "@",
1417
+ className: "key-at"
1418
+ },
1419
+ {
1420
+ id: "email-suffix",
1421
+ type: "char",
1422
+ label: ".com",
1423
+ value: "",
1424
+ width: 1.5,
1425
+ className: "key-suffix",
1426
+ options: EMAIL_SUFFIXES
1427
+ },
1428
+ snippet$1(".", "email-dot"),
1429
+ snippet$1("-", "email-dash"),
1430
+ snippet$1("_", "email-underscore"),
1431
+ {
1432
+ id: "space",
1433
+ type: "space",
1434
+ label: "",
1435
+ value: " ",
1436
+ width: 2,
1437
+ className: "key-space"
1438
+ },
1439
+ {
1440
+ id: "email-done",
1441
+ type: "done",
1442
+ label: "确定",
1443
+ width: 1.5,
1444
+ className: "key-done"
1445
+ }
1446
+ ] }
1447
+ ]
1448
+ };
1449
+ //#endregion
1450
+ //#region src/layouts/url.ts
1451
+ function createCharKey$2(char) {
1452
+ return {
1453
+ id: `url-char-${char.toLowerCase()}`,
1454
+ type: "char",
1455
+ label: {
1456
+ lower: char.toLowerCase(),
1457
+ upper: char.toUpperCase()
1458
+ },
1459
+ value: {
1460
+ lower: char.toLowerCase(),
1461
+ upper: char.toUpperCase()
1462
+ }
1463
+ };
1464
+ }
1465
+ function snippet(label, width) {
1466
+ return {
1467
+ id: `url-snippet-${label.replace(/[^a-z0-9]/gi, "") || label.split("").map((c) => c.charCodeAt(0)).join("")}`,
1468
+ type: "char",
1469
+ label,
1470
+ value: label,
1471
+ width,
1472
+ className: "key-snippet"
1473
+ };
1474
+ }
1475
+ const urlLayout = {
1476
+ type: "url",
1477
+ name: "网址键盘",
1478
+ supportShift: true,
1479
+ defaultUpperCase: false,
1480
+ switchable: ["symbol", "number"],
1481
+ rows: [
1482
+ { keys: "qwertyuiop".split("").map(createCharKey$2) },
1483
+ { keys: "asdfghjkl".split("").map(createCharKey$2) },
1484
+ { keys: [
1485
+ {
1486
+ id: "shift",
1487
+ type: "shift",
1488
+ icon: ICON_SHIFT,
1489
+ label: "",
1490
+ width: 1.5,
1491
+ className: "key-shift"
1492
+ },
1493
+ ..."zxcvbnm".split("").map(createCharKey$2),
1494
+ {
1495
+ id: "backspace",
1496
+ type: "backspace",
1497
+ icon: ICON_DELETE,
1498
+ label: "",
1499
+ width: 1.5,
1500
+ className: "key-backspace"
1501
+ }
1502
+ ] },
1503
+ { keys: [
1504
+ {
1505
+ id: "switch-number",
1506
+ type: "tab",
1507
+ label: "123",
1508
+ width: 1.2,
1509
+ className: "key-switch",
1510
+ data: { targetType: "number" }
1511
+ },
1512
+ snippet("/", .8),
1513
+ snippet(".", .8),
1514
+ snippet("-", .8),
1515
+ snippet(".com", 1.5),
1516
+ snippet(".cn", 1.2),
1517
+ {
1518
+ id: "space",
1519
+ type: "space",
1520
+ label: "",
1521
+ value: " ",
1522
+ width: 1.5,
1523
+ className: "key-space"
1524
+ },
1525
+ {
1526
+ id: "url-go",
1527
+ type: "done",
1528
+ label: "前往",
1529
+ width: 1.5,
1530
+ className: "key-done"
1531
+ }
1532
+ ] }
1533
+ ]
1534
+ };
1535
+ //#endregion
1536
+ //#region src/layouts/search.ts
1537
+ function createCharKey$1(char) {
1538
+ return {
1539
+ id: `search-char-${char.toLowerCase()}`,
1540
+ type: "char",
1541
+ label: {
1542
+ lower: char.toLowerCase(),
1543
+ upper: char.toUpperCase()
1544
+ },
1545
+ value: {
1546
+ lower: char.toLowerCase(),
1547
+ upper: char.toUpperCase()
1548
+ }
1549
+ };
1550
+ }
1551
+ const searchLayout = {
1552
+ type: "search",
1553
+ name: "搜索键盘",
1554
+ supportShift: true,
1555
+ defaultUpperCase: false,
1556
+ switchable: ["symbol", "number"],
1557
+ rows: [
1558
+ { keys: "qwertyuiop".split("").map(createCharKey$1) },
1559
+ { keys: "asdfghjkl".split("").map(createCharKey$1) },
1560
+ { keys: [
1561
+ {
1562
+ id: "shift",
1563
+ type: "shift",
1564
+ icon: ICON_SHIFT,
1565
+ label: "",
1566
+ width: 1.5,
1567
+ className: "key-shift"
1568
+ },
1569
+ ..."zxcvbnm".split("").map(createCharKey$1),
1570
+ {
1571
+ id: "backspace",
1572
+ type: "backspace",
1573
+ icon: ICON_DELETE,
1574
+ label: "",
1575
+ width: 1.5,
1576
+ className: "key-backspace"
1577
+ }
1578
+ ] },
1579
+ { keys: [
1580
+ {
1581
+ id: "switch-number",
1582
+ type: "tab",
1583
+ label: "123",
1584
+ width: 1.25,
1585
+ className: "key-switch",
1586
+ data: { targetType: "number" }
1587
+ },
1588
+ {
1589
+ id: "switch-symbol",
1590
+ type: "tab",
1591
+ label: "#+=",
1592
+ width: 1.25,
1593
+ className: "key-switch",
1594
+ data: { targetType: "symbol" }
1595
+ },
1596
+ {
1597
+ id: "space",
1598
+ type: "space",
1599
+ label: "",
1600
+ value: " ",
1601
+ width: 4,
1602
+ className: "key-space"
1603
+ },
1604
+ {
1605
+ id: "voice",
1606
+ type: "custom",
1607
+ icon: ICON_VOICE,
1608
+ label: "",
1609
+ width: 1,
1610
+ className: "key-voice",
1611
+ data: { action: "voice" }
1612
+ },
1613
+ {
1614
+ id: "search-done",
1615
+ type: "done",
1616
+ label: "搜索",
1617
+ width: 2,
1618
+ className: "key-done"
1619
+ }
1620
+ ] }
1621
+ ]
1622
+ };
1623
+ //#endregion
1624
+ //#region src/layouts/punct.ts
1625
+ function p(label, value) {
1626
+ return {
1627
+ id: `punct-${label}`,
1628
+ type: "char",
1629
+ label,
1630
+ value: value ?? label,
1631
+ className: "key-num"
1632
+ };
1633
+ }
1634
+ const punctLayout = {
1635
+ type: "punct",
1636
+ name: "中文标点",
1637
+ supportShift: false,
1638
+ switchable: ["qwerty", "punct-en"],
1639
+ rows: [
1640
+ {
1641
+ className: "virtual-keyboard__row",
1642
+ keys: [
1643
+ ",",
1644
+ "。",
1645
+ "?",
1646
+ "!",
1647
+ ":",
1648
+ ";",
1649
+ "\"",
1650
+ "\""
1651
+ ].map((s) => p(s))
1652
+ },
1653
+ {
1654
+ className: "virtual-keyboard__row",
1655
+ keys: [
1656
+ "(",
1657
+ ")",
1658
+ "【",
1659
+ "】",
1660
+ "《",
1661
+ "》",
1662
+ "……",
1663
+ "——"
1664
+ ].map((s) => p(s))
1665
+ },
1666
+ {
1667
+ className: "virtual-keyboard__row",
1668
+ keys: [
1669
+ p("·"),
1670
+ p("、"),
1671
+ p("「"),
1672
+ p("」"),
1673
+ p("『"),
1674
+ p("』"),
1675
+ p("~"),
1676
+ {
1677
+ id: "backspace",
1678
+ type: "backspace",
1679
+ icon: ICON_DELETE,
1680
+ label: "",
1681
+ className: "key-numpad-fn"
1682
+ }
1683
+ ]
1684
+ },
1685
+ {
1686
+ className: "virtual-keyboard__row",
1687
+ keys: [
1688
+ {
1689
+ id: "switch-punct-en",
1690
+ type: "tab",
1691
+ label: "英",
1692
+ data: { targetType: "punct-en" },
1693
+ className: "key-numpad-fn"
1694
+ },
1695
+ {
1696
+ id: "switch-qwerty",
1697
+ type: "tab",
1698
+ label: "ABC",
1699
+ data: { targetType: "qwerty" },
1700
+ className: "key-numpad-fn"
1701
+ },
1702
+ {
1703
+ id: "space",
1704
+ type: "space",
1705
+ label: "空格",
1706
+ value: " ",
1707
+ width: 4,
1708
+ className: "key-num"
1709
+ },
1710
+ {
1711
+ id: "done",
1712
+ type: "done",
1713
+ icon: ICON_CHECK,
1714
+ label: "",
1715
+ width: 2,
1716
+ className: "key-numpad-done"
1717
+ }
1718
+ ]
1719
+ }
1720
+ ]
1721
+ };
1722
+ //#endregion
1723
+ //#region src/layouts/index.ts
1724
+ const builtinLayouts = {
1725
+ "qwerty": qwertyLayout,
1726
+ "number": numberLayout,
1727
+ "integer": integerLayout,
1728
+ "symbol": symbolLayout,
1729
+ "symbol-2": symbolLayout2,
1730
+ "license-plate": licensePlateLayout,
1731
+ "license-plate-province": licensePlateProvinceLayout,
1732
+ "license-plate-letter": licensePlateLetterLayout,
1733
+ "license-plate-alphanumeric": licensePlateAlphanumericLayout,
1734
+ "idcard": idcardLayout,
1735
+ "phone": phoneLayout,
1736
+ "phone-simple": phoneSimpleLayout,
1737
+ "amount": amountLayout,
1738
+ "amount-simple": amountSimpleLayout,
1739
+ "bankcard": bankcardLayout,
1740
+ "verifycode": verifycodeLayout,
1741
+ "email": emailLayout,
1742
+ "url": urlLayout,
1743
+ "search": searchLayout,
1744
+ "punct": punctLayout
1745
+ };
1746
+ const customLayouts = {};
1747
+ function registerLayout(name, layout) {
1748
+ if (builtinLayouts[name]) {
1749
+ console.warn(`[Keyboard] Cannot override builtin layout "${name}"`);
1750
+ return;
1751
+ }
1752
+ customLayouts[name] = layout;
1753
+ }
1754
+ function getLayout(type) {
1755
+ return customLayouts[type] || builtinLayouts[type];
1756
+ }
1757
+ function getAvailableLayouts() {
1758
+ return [...Object.keys(builtinLayouts), ...Object.keys(customLayouts)];
1759
+ }
1760
+ function hasLayout(name) {
1761
+ return name in builtinLayouts || name in customLayouts;
1762
+ }
1763
+ function unregisterLayout(name) {
1764
+ if (name in customLayouts) {
1765
+ delete customLayouts[name];
1766
+ return true;
1767
+ }
1768
+ return false;
1769
+ }
1770
+ function registerLayouts(layouts) {
1771
+ Object.entries(layouts).forEach(([name, layout]) => {
1772
+ registerLayout(name, layout);
1773
+ });
1774
+ }
1775
+ //#endregion
1776
+ //#region src/utils/event-emitter.ts
1777
+ var EventEmitter = class {
1778
+ constructor() {
1779
+ this.handlers = /* @__PURE__ */ new Map();
1780
+ }
1781
+ /**
1782
+ * 订阅事件
1783
+ */
1784
+ on(event, handler, options = {}) {
1785
+ if (!this.handlers.has(event)) this.handlers.set(event, /* @__PURE__ */ new Set());
1786
+ const handlers = this.handlers.get(event);
1787
+ const wrapper = {
1788
+ handler,
1789
+ options
1790
+ };
1791
+ handlers.add(wrapper);
1792
+ return () => {
1793
+ handlers.delete(wrapper);
1794
+ if (handlers.size === 0) this.handlers.delete(event);
1795
+ };
1796
+ }
1797
+ /**
1798
+ * 订阅事件(仅触发一次)
1799
+ */
1800
+ once(event, handler, options = {}) {
1801
+ return this.on(event, handler, {
1802
+ ...options,
1803
+ once: true
1804
+ });
1805
+ }
1806
+ /**
1807
+ * 取消订阅事件
1808
+ */
1809
+ off(event, handler) {
1810
+ if (!handler) {
1811
+ this.handlers.delete(event);
1812
+ return;
1813
+ }
1814
+ const handlers = this.handlers.get(event);
1815
+ if (handlers) {
1816
+ handlers.forEach((wrapper) => {
1817
+ if (wrapper.handler === handler) handlers.delete(wrapper);
1818
+ });
1819
+ if (handlers.size === 0) this.handlers.delete(event);
1820
+ }
1821
+ }
1822
+ /**
1823
+ * 发布事件
1824
+ */
1825
+ emit(event, data) {
1826
+ const handlers = this.handlers.get(event);
1827
+ if (!handlers || handlers.size === 0) return;
1828
+ const sortedHandlers = Array.from(handlers).sort((a, b) => {
1829
+ const priorityA = a.options.priority ?? 0;
1830
+ return (b.options.priority ?? 0) - priorityA;
1831
+ });
1832
+ const toRemove = [];
1833
+ sortedHandlers.forEach((wrapper) => {
1834
+ try {
1835
+ wrapper.handler(data);
1836
+ if (wrapper.options.once) toRemove.push(wrapper);
1837
+ } catch (error) {
1838
+ console.error(`[KeyboardEventEmitter] Error in event handler for "${String(event)}":`, error);
1839
+ }
1840
+ });
1841
+ toRemove.forEach((wrapper) => handlers.delete(wrapper));
1842
+ if (handlers.size === 0) this.handlers.delete(event);
1843
+ }
1844
+ /**
1845
+ * 清除所有事件订阅
1846
+ */
1847
+ clear() {
1848
+ this.handlers.clear();
1849
+ }
1850
+ /**
1851
+ * 获取事件订阅数量
1852
+ */
1853
+ listenerCount(event) {
1854
+ if (event !== void 0) return this.handlers.get(event)?.size ?? 0;
1855
+ let count = 0;
1856
+ this.handlers.forEach((handlers) => {
1857
+ count += handlers.size;
1858
+ });
1859
+ return count;
1860
+ }
1861
+ };
1862
+ //#endregion
1863
+ //#region src/utils/device.ts
1864
+ const MOBILE_UA_REGEX = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
1865
+ let cachedIsTouchDevice = null;
1866
+ function isTouchDevice() {
1867
+ if (cachedIsTouchDevice !== null) return cachedIsTouchDevice;
1868
+ if (typeof window === "undefined") {
1869
+ cachedIsTouchDevice = false;
1870
+ return false;
1871
+ }
1872
+ cachedIsTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
1873
+ return cachedIsTouchDevice;
1874
+ }
1875
+ function isMobileUA() {
1876
+ if (typeof navigator === "undefined") return false;
1877
+ return MOBILE_UA_REGEX.test(navigator.userAgent);
1878
+ }
1879
+ function isMobile() {
1880
+ if (typeof window === "undefined") return false;
1881
+ if (isMobileUA()) return true;
1882
+ if ((window.innerWidth || document.documentElement.clientWidth) <= 768) return true;
1883
+ return isTouchDevice();
1884
+ }
1885
+ function getDeviceType() {
1886
+ return isMobile() ? "mobile" : "desktop";
1887
+ }
1888
+ function getViewportInfo() {
1889
+ if (typeof window === "undefined") return {
1890
+ width: 0,
1891
+ height: 0,
1892
+ scrollX: 0,
1893
+ scrollY: 0,
1894
+ isMobile: false
1895
+ };
1896
+ const width = window.innerWidth || document.documentElement.clientWidth;
1897
+ const height = window.innerHeight || document.documentElement.clientHeight;
1898
+ const safeArea = getSafeAreaInsets();
1899
+ return {
1900
+ width,
1901
+ height,
1902
+ scrollX: window.scrollX || window.pageXOffset,
1903
+ scrollY: window.scrollY || window.pageYOffset,
1904
+ isMobile: isMobile(),
1905
+ safeArea
1906
+ };
1907
+ }
1908
+ function getSafeAreaInsets() {
1909
+ if (typeof window === "undefined" || typeof CSS === "undefined" || !CSS.supports) return {
1910
+ top: 0,
1911
+ right: 0,
1912
+ bottom: 0,
1913
+ left: 0
1914
+ };
1915
+ if (!CSS.supports("padding-top", "env(safe-area-inset-top)")) return {
1916
+ top: 0,
1917
+ right: 0,
1918
+ bottom: 0,
1919
+ left: 0
1920
+ };
1921
+ const div = document.createElement("div");
1922
+ div.style.cssText = `
1923
+ position: fixed;
1924
+ top: env(safe-area-inset-top);
1925
+ right: env(safe-area-inset-right);
1926
+ bottom: env(safe-area-inset-bottom);
1927
+ left: env(safe-area-inset-left);
1928
+ pointer-events: none;
1929
+ visibility: hidden;
1930
+ `;
1931
+ document.body.appendChild(div);
1932
+ const computed = getComputedStyle(div);
1933
+ const safeArea = {
1934
+ top: Number.parseFloat(computed.top) || 0,
1935
+ right: Number.parseFloat(computed.right) || 0,
1936
+ bottom: Number.parseFloat(computed.bottom) || 0,
1937
+ left: Number.parseFloat(computed.left) || 0
1938
+ };
1939
+ document.body.removeChild(div);
1940
+ return safeArea;
1941
+ }
1942
+ function supportsVibrate() {
1943
+ return typeof navigator !== "undefined" && "vibrate" in navigator;
1944
+ }
1945
+ function vibrate(pattern = 10) {
1946
+ if (supportsVibrate()) return navigator.vibrate(pattern);
1947
+ return false;
1948
+ }
1949
+ function onViewportChange(callback) {
1950
+ if (typeof window === "undefined") return () => {};
1951
+ const handler = () => {
1952
+ callback(getViewportInfo());
1953
+ };
1954
+ window.addEventListener("resize", handler);
1955
+ window.addEventListener("orientationchange", handler);
1956
+ return () => {
1957
+ window.removeEventListener("resize", handler);
1958
+ window.removeEventListener("orientationchange", handler);
1959
+ };
1960
+ }
1961
+ //#endregion
1962
+ //#region src/utils/dom.ts
1963
+ function getBoundingRect(element) {
1964
+ const rect = element.getBoundingClientRect();
1965
+ return {
1966
+ x: rect.left,
1967
+ y: rect.top,
1968
+ width: rect.width,
1969
+ height: rect.height
1970
+ };
1971
+ }
1972
+ function getElementOffset(element) {
1973
+ const rect = element.getBoundingClientRect();
1974
+ const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
1975
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
1976
+ return {
1977
+ x: rect.left + scrollLeft,
1978
+ y: rect.top + scrollTop
1979
+ };
1980
+ }
1981
+ function isElementInViewport(element) {
1982
+ const rect = element.getBoundingClientRect();
1983
+ return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
1984
+ }
1985
+ function isClickOutside(event, element) {
1986
+ const target = event.target;
1987
+ return !element.contains(target);
1988
+ }
1989
+ function preventDefaultAndStopPropagation(event) {
1990
+ event.preventDefault();
1991
+ event.stopPropagation();
1992
+ }
1993
+ function onClickOutside(element, callback) {
1994
+ const handler = (event) => {
1995
+ if (isClickOutside(event, element)) callback(event);
1996
+ };
1997
+ document.addEventListener("mousedown", handler);
1998
+ document.addEventListener("touchstart", handler);
1999
+ return () => {
2000
+ document.removeEventListener("mousedown", handler);
2001
+ document.removeEventListener("touchstart", handler);
2002
+ };
2003
+ }
2004
+ function scrollIntoViewIfNeeded(element, container) {
2005
+ if (!container) {
2006
+ element.scrollIntoView({
2007
+ behavior: "smooth",
2008
+ block: "nearest"
2009
+ });
2010
+ return;
2011
+ }
2012
+ const elementRect = element.getBoundingClientRect();
2013
+ const containerRect = container.getBoundingClientRect();
2014
+ if (elementRect.bottom > containerRect.bottom) container.scrollTop += elementRect.bottom - containerRect.bottom;
2015
+ else if (elementRect.top < containerRect.top) container.scrollTop -= containerRect.top - elementRect.top;
2016
+ }
2017
+ function getInputCursorPosition(input) {
2018
+ return input.selectionStart ?? input.value.length;
2019
+ }
2020
+ function setInputCursorPosition(input, position) {
2021
+ input.setSelectionRange(position, position);
2022
+ }
2023
+ function insertTextAtCursor(input, text, maxLength) {
2024
+ const start = input.selectionStart ?? input.value.length;
2025
+ const end = input.selectionEnd ?? input.value.length;
2026
+ const currentValue = input.value;
2027
+ let newValue = currentValue.substring(0, start) + text + currentValue.substring(end);
2028
+ if (maxLength !== void 0 && newValue.length > maxLength) {
2029
+ const allowedLength = maxLength - (currentValue.length - (end - start));
2030
+ if (allowedLength <= 0) return {
2031
+ value: currentValue,
2032
+ cursorPosition: start
2033
+ };
2034
+ newValue = currentValue.substring(0, start) + text.substring(0, allowedLength) + currentValue.substring(end);
2035
+ }
2036
+ const newCursorPosition = start + text.length;
2037
+ return {
2038
+ value: newValue,
2039
+ cursorPosition: Math.min(newCursorPosition, newValue.length)
2040
+ };
2041
+ }
2042
+ function deleteCharBeforeCursor(input) {
2043
+ const start = input.selectionStart ?? input.value.length;
2044
+ const end = input.selectionEnd ?? input.value.length;
2045
+ const currentValue = input.value;
2046
+ if (start !== end) {
2047
+ const deletedChar2 = currentValue.substring(start, end);
2048
+ return {
2049
+ value: currentValue.substring(0, start) + currentValue.substring(end),
2050
+ deletedChar: deletedChar2,
2051
+ cursorPosition: start
2052
+ };
2053
+ }
2054
+ if (start === 0) return {
2055
+ value: currentValue,
2056
+ deletedChar: "",
2057
+ cursorPosition: 0
2058
+ };
2059
+ const deletedChar = currentValue.charAt(start - 1);
2060
+ return {
2061
+ value: currentValue.substring(0, start - 1) + currentValue.substring(start),
2062
+ deletedChar,
2063
+ cursorPosition: start - 1
2064
+ };
2065
+ }
2066
+ function createElement(tag, attrs, children) {
2067
+ const element = document.createElement(tag);
2068
+ if (attrs) Object.entries(attrs).forEach(([key, value]) => {
2069
+ element.setAttribute(key, value);
2070
+ });
2071
+ if (children) children.forEach((child) => {
2072
+ if (typeof child === "string") element.appendChild(document.createTextNode(child));
2073
+ else element.appendChild(child);
2074
+ });
2075
+ return element;
2076
+ }
2077
+ function toggleClass(element, className, force) {
2078
+ element.classList.toggle(className, force);
2079
+ }
2080
+ function setStyles(element, styles) {
2081
+ Object.assign(element.style, styles);
2082
+ }
2083
+ //#endregion
2084
+ //#region src/managers/keyboard-manager.ts
2085
+ const DEFAULT_OPTIONS = {
2086
+ type: "qwerty",
2087
+ value: "",
2088
+ maxLength: void 0,
2089
+ defaultUpperCase: false,
2090
+ closeOnClickOutside: true,
2091
+ enableSound: false,
2092
+ enableVibrate: true,
2093
+ customLayouts: {}
2094
+ };
2095
+ var KeyboardManager = class extends EventEmitter {
2096
+ constructor(options = {}) {
2097
+ super();
2098
+ /** 当前布局配置 */
2099
+ this.currentLayout = null;
2100
+ this.options = {
2101
+ ...DEFAULT_OPTIONS,
2102
+ ...options
2103
+ };
2104
+ if (options.customLayouts) Object.entries(options.customLayouts).forEach(([name, layout]) => {
2105
+ this.options.customLayouts[name] = layout;
2106
+ });
2107
+ this.state = {
2108
+ visible: false,
2109
+ type: this.options.type,
2110
+ isUpperCase: this.options.defaultUpperCase,
2111
+ value: this.options.value,
2112
+ cursorPosition: this.options.value.length,
2113
+ maxLength: this.options.maxLength,
2114
+ inputElement: null
2115
+ };
2116
+ this.loadLayout(this.options.type);
2117
+ }
2118
+ /**
2119
+ * 获取当前状态
2120
+ */
2121
+ getState() {
2122
+ return { ...this.state };
2123
+ }
2124
+ /**
2125
+ * 获取当前布局配置
2126
+ */
2127
+ getLayout() {
2128
+ return this.currentLayout;
2129
+ }
2130
+ /**
2131
+ * 获取配置选项
2132
+ */
2133
+ getOptions() {
2134
+ return { ...this.options };
2135
+ }
2136
+ /**
2137
+ * 加载键盘布局
2138
+ */
2139
+ loadLayout(type) {
2140
+ let layout = this.options.customLayouts[type];
2141
+ if (!layout) layout = getLayout(type);
2142
+ if (!layout) {
2143
+ console.error(`[KeyboardManager] Layout "${type}" not found`);
2144
+ return false;
2145
+ }
2146
+ this.currentLayout = layout;
2147
+ if (layout.supportShift) this.state.isUpperCase = layout.defaultUpperCase ?? this.options.defaultUpperCase;
2148
+ return true;
2149
+ }
2150
+ /**
2151
+ * 显示键盘
2152
+ */
2153
+ show(inputElement) {
2154
+ if (this.state.visible) return;
2155
+ this.state.visible = true;
2156
+ this.state.inputElement = inputElement ?? null;
2157
+ if (inputElement) {
2158
+ this.state.value = inputElement.value;
2159
+ this.state.cursorPosition = getInputCursorPosition(inputElement);
2160
+ }
2161
+ this.emitStateChange();
2162
+ this.emit("show", { type: this.state.type });
2163
+ }
2164
+ /**
2165
+ * 隐藏键盘
2166
+ */
2167
+ hide() {
2168
+ if (!this.state.visible) return;
2169
+ const prevType = this.state.type;
2170
+ this.state.visible = false;
2171
+ this.state.inputElement = null;
2172
+ this.emitStateChange();
2173
+ this.emit("hide", { type: prevType });
2174
+ }
2175
+ /**
2176
+ * 切换键盘显示/隐藏
2177
+ */
2178
+ toggle(inputElement) {
2179
+ if (this.state.visible) this.hide();
2180
+ else this.show(inputElement);
2181
+ }
2182
+ /**
2183
+ * 切换键盘类型
2184
+ */
2185
+ switchType(type) {
2186
+ if (this.state.type === type) return;
2187
+ const fromType = this.state.type;
2188
+ if (!this.loadLayout(type)) return;
2189
+ this.state.type = type;
2190
+ this.emitStateChange();
2191
+ this.emit("switch", {
2192
+ from: fromType,
2193
+ to: type
2194
+ });
2195
+ }
2196
+ /**
2197
+ * 切换大小写
2198
+ */
2199
+ toggleShift() {
2200
+ if (!this.currentLayout?.supportShift) return;
2201
+ this.state.isUpperCase = !this.state.isUpperCase;
2202
+ this.emitStateChange();
2203
+ this.emit("shift", { isUpperCase: this.state.isUpperCase });
2204
+ }
2205
+ /**
2206
+ * 设置大小写状态
2207
+ */
2208
+ setShift(isUpperCase) {
2209
+ if (!this.currentLayout?.supportShift) return;
2210
+ if (this.state.isUpperCase === isUpperCase) return;
2211
+ this.state.isUpperCase = isUpperCase;
2212
+ this.emitStateChange();
2213
+ this.emit("shift", { isUpperCase });
2214
+ }
2215
+ /**
2216
+ * 处理按键
2217
+ */
2218
+ handleKey(key) {
2219
+ if (this.options.enableVibrate && isMobile()) vibrate(10);
2220
+ this.emit("keypress", {
2221
+ key,
2222
+ value: this.state.value
2223
+ });
2224
+ switch (key.type) {
2225
+ case "char":
2226
+ case "space":
2227
+ this.handleCharKey(key);
2228
+ break;
2229
+ case "backspace":
2230
+ this.handleBackspace();
2231
+ break;
2232
+ case "shift":
2233
+ this.toggleShift();
2234
+ break;
2235
+ case "clear":
2236
+ this.handleClear();
2237
+ break;
2238
+ case "enter":
2239
+ case "done":
2240
+ this.handleConfirm();
2241
+ break;
2242
+ case "close":
2243
+ this.hide();
2244
+ break;
2245
+ case "tab":
2246
+ this.handleTab(key);
2247
+ break;
2248
+ case "custom": break;
2249
+ }
2250
+ }
2251
+ /**
2252
+ * 处理字符输入
2253
+ */
2254
+ handleCharKey(key) {
2255
+ const keyValue = this.getKeyValue(key);
2256
+ if (!keyValue) return;
2257
+ const input = this.state.inputElement;
2258
+ if (input) {
2259
+ const result = insertTextAtCursor(input, keyValue, this.state.maxLength);
2260
+ input.value = result.value;
2261
+ setInputCursorPosition(input, result.cursorPosition);
2262
+ this.state.value = result.value;
2263
+ this.state.cursorPosition = result.cursorPosition;
2264
+ input.dispatchEvent(new Event("input", { bubbles: true }));
2265
+ } else {
2266
+ if (this.state.maxLength && this.state.value.length >= this.state.maxLength) return;
2267
+ const newValue = this.state.value.slice(0, this.state.cursorPosition) + keyValue + this.state.value.slice(this.state.cursorPosition);
2268
+ this.state.value = newValue;
2269
+ this.state.cursorPosition += keyValue.length;
2270
+ }
2271
+ this.emitStateChange();
2272
+ this.emit("input", {
2273
+ value: this.state.value,
2274
+ key
2275
+ });
2276
+ this.autoSwitchLicensePlate();
2277
+ }
2278
+ /**
2279
+ * 处理退格
2280
+ */
2281
+ handleBackspace() {
2282
+ const input = this.state.inputElement;
2283
+ if (input) {
2284
+ const result = deleteCharBeforeCursor(input);
2285
+ input.value = result.value;
2286
+ setInputCursorPosition(input, result.cursorPosition);
2287
+ this.state.value = result.value;
2288
+ this.state.cursorPosition = result.cursorPosition;
2289
+ input.dispatchEvent(new Event("input", { bubbles: true }));
2290
+ this.emitStateChange();
2291
+ this.emit("backspace", {
2292
+ deletedChar: result.deletedChar,
2293
+ value: this.state.value
2294
+ });
2295
+ } else {
2296
+ if (this.state.cursorPosition === 0) return;
2297
+ const deletedChar = this.state.value.charAt(this.state.cursorPosition - 1);
2298
+ this.state.value = this.state.value.slice(0, this.state.cursorPosition - 1) + this.state.value.slice(this.state.cursorPosition);
2299
+ this.state.cursorPosition--;
2300
+ this.emitStateChange();
2301
+ this.emit("backspace", {
2302
+ deletedChar,
2303
+ value: this.state.value
2304
+ });
2305
+ }
2306
+ this.autoSwitchLicensePlate();
2307
+ }
2308
+ /**
2309
+ * 车牌号智能切换逻辑
2310
+ * 根据当前值长度自动切换键盘布局
2311
+ * 只有 2 种布局:省份键盘(第1位)和 字母+数字混合键盘(第2-8位)
2312
+ */
2313
+ autoSwitchLicensePlate() {
2314
+ if (!this.state.type.startsWith("license-plate")) return;
2315
+ const len = this.state.value.length;
2316
+ let targetType = null;
2317
+ if (len === 0) targetType = "license-plate-province";
2318
+ else targetType = "license-plate-alphanumeric";
2319
+ if (targetType && this.state.type !== targetType) this.switchType(targetType);
2320
+ }
2321
+ /**
2322
+ * 处理清空
2323
+ */
2324
+ handleClear() {
2325
+ const previousValue = this.state.value;
2326
+ if (this.state.inputElement) {
2327
+ this.state.inputElement.value = "";
2328
+ this.state.inputElement.dispatchEvent(new Event("input", { bubbles: true }));
2329
+ }
2330
+ this.state.value = "";
2331
+ this.state.cursorPosition = 0;
2332
+ this.emitStateChange();
2333
+ this.emit("clear", { previousValue });
2334
+ this.autoSwitchLicensePlate();
2335
+ }
2336
+ /**
2337
+ * 处理确认
2338
+ */
2339
+ handleConfirm() {
2340
+ this.emit("confirm", { value: this.state.value });
2341
+ this.hide();
2342
+ }
2343
+ /**
2344
+ * 处理切换键盘
2345
+ */
2346
+ handleTab(key) {
2347
+ const targetType = key.data?.targetType;
2348
+ if (targetType) this.switchType(targetType);
2349
+ }
2350
+ /**
2351
+ * 获取按键的实际输出值
2352
+ */
2353
+ getKeyValue(key) {
2354
+ const value = key.value ?? key.label;
2355
+ if (typeof value === "string") return value;
2356
+ return this.state.isUpperCase ? value.upper : value.lower;
2357
+ }
2358
+ /**
2359
+ * 获取按键的显示文本
2360
+ */
2361
+ getKeyLabel(key) {
2362
+ const label = key.label;
2363
+ if (typeof label === "string") return label;
2364
+ return this.state.isUpperCase ? label.upper : label.lower;
2365
+ }
2366
+ /**
2367
+ * 设置值
2368
+ */
2369
+ setValue(value) {
2370
+ this.state.value = value;
2371
+ this.state.cursorPosition = value.length;
2372
+ if (this.state.inputElement) {
2373
+ this.state.inputElement.value = value;
2374
+ setInputCursorPosition(this.state.inputElement, value.length);
2375
+ }
2376
+ this.emitStateChange();
2377
+ this.autoSwitchLicensePlate();
2378
+ }
2379
+ /**
2380
+ * 追加值(在光标位置插入文本)
2381
+ */
2382
+ appendValue(text) {
2383
+ if (!text) return;
2384
+ const input = this.state.inputElement;
2385
+ if (input) {
2386
+ const result = insertTextAtCursor(input, text, this.state.maxLength);
2387
+ input.value = result.value;
2388
+ setInputCursorPosition(input, result.cursorPosition);
2389
+ this.state.value = result.value;
2390
+ this.state.cursorPosition = result.cursorPosition;
2391
+ input.dispatchEvent(new Event("input", { bubbles: true }));
2392
+ } else {
2393
+ if (this.state.maxLength && this.state.value.length + text.length > this.state.maxLength) text = text.slice(0, this.state.maxLength - this.state.value.length);
2394
+ const newValue = this.state.value.slice(0, this.state.cursorPosition) + text + this.state.value.slice(this.state.cursorPosition);
2395
+ this.state.value = newValue;
2396
+ this.state.cursorPosition += text.length;
2397
+ }
2398
+ this.emitStateChange();
2399
+ }
2400
+ /**
2401
+ * 设置最大长度
2402
+ */
2403
+ setMaxLength(maxLength) {
2404
+ this.state.maxLength = maxLength;
2405
+ this.emitStateChange();
2406
+ }
2407
+ /**
2408
+ * 绑定输入框
2409
+ */
2410
+ bindInput(input) {
2411
+ this.state.inputElement = input;
2412
+ this.state.value = input.value;
2413
+ this.state.cursorPosition = getInputCursorPosition(input);
2414
+ this.emitStateChange();
2415
+ }
2416
+ /**
2417
+ * 解绑输入框
2418
+ */
2419
+ unbindInput() {
2420
+ this.state.inputElement = null;
2421
+ this.emitStateChange();
2422
+ }
2423
+ /**
2424
+ * 发送状态变化事件
2425
+ */
2426
+ emitStateChange() {
2427
+ this.emit("stateChange", { ...this.state });
2428
+ }
2429
+ /**
2430
+ * 销毁
2431
+ */
2432
+ destroy() {
2433
+ this.hide();
2434
+ this.clear();
2435
+ this.state.inputElement = null;
2436
+ }
2437
+ };
2438
+ function createKeyboardManager(options) {
2439
+ return new KeyboardManager(options);
2440
+ }
2441
+ //#endregion
2442
+ //#region src/managers/position-manager.ts
2443
+ const DEFAULT_CONFIG = {
2444
+ offset: {
2445
+ x: 0,
2446
+ y: 8
2447
+ },
2448
+ autoAdjust: true,
2449
+ viewportPadding: 8,
2450
+ desktopPlacement: "bottom",
2451
+ mobilePlacement: "bottom-sheet",
2452
+ showMask: true,
2453
+ maskClosable: true,
2454
+ animationDuration: 300
2455
+ };
2456
+ var PositionManager = class {
2457
+ constructor(config = {}) {
2458
+ this.config = {
2459
+ ...DEFAULT_CONFIG,
2460
+ ...config
2461
+ };
2462
+ }
2463
+ /**
2464
+ * 更新配置
2465
+ */
2466
+ updateConfig(config) {
2467
+ Object.assign(this.config, config);
2468
+ }
2469
+ /**
2470
+ * 获取配置
2471
+ */
2472
+ getConfig() {
2473
+ return { ...this.config };
2474
+ }
2475
+ /**
2476
+ * 计算弹出位置
2477
+ * @param targetElement - 目标元素(如 input)
2478
+ * @param popupSize - 弹出层尺寸
2479
+ * @returns 位置计算结果
2480
+ */
2481
+ calculate(targetElement, popupSize) {
2482
+ const viewport = getViewportInfo();
2483
+ const isMobileDevice = isMobile();
2484
+ if (isMobileDevice && this.config.mobilePlacement === "bottom-sheet") return this.calculateBottomSheet(viewport, popupSize);
2485
+ if (!targetElement) return this.calculateCentered(viewport, popupSize);
2486
+ const targetRect = getBoundingRect(targetElement);
2487
+ const placement = isMobileDevice ? this.config.mobilePlacement : this.config.desktopPlacement;
2488
+ const relativePlace = placement === "bottom-sheet" ? "bottom" : placement;
2489
+ return this.calculateRelativeToTarget(targetRect, popupSize, viewport, relativePlace);
2490
+ }
2491
+ /**
2492
+ * 计算 bottom-sheet 位置(移动端从底部滑出)
2493
+ */
2494
+ calculateBottomSheet(viewport, popupSize) {
2495
+ const safeAreaBottom = viewport.safeArea?.bottom ?? 0;
2496
+ return {
2497
+ position: {
2498
+ x: 0,
2499
+ y: viewport.height - popupSize.height - safeAreaBottom
2500
+ },
2501
+ placement: "bottom-sheet",
2502
+ flipped: false,
2503
+ maxHeight: viewport.height * .6,
2504
+ maxWidth: viewport.width,
2505
+ transform: "translateY(0)"
2506
+ };
2507
+ }
2508
+ /**
2509
+ * 计算居中位置
2510
+ */
2511
+ calculateCentered(viewport, popupSize) {
2512
+ return {
2513
+ position: {
2514
+ x: (viewport.width - popupSize.width) / 2,
2515
+ y: (viewport.height - popupSize.height) / 2
2516
+ },
2517
+ placement: "bottom",
2518
+ flipped: false
2519
+ };
2520
+ }
2521
+ /**
2522
+ * 计算相对于目标元素的位置
2523
+ */
2524
+ calculateRelativeToTarget(targetRect, popupSize, viewport, preferredPlacement) {
2525
+ const { offset, viewportPadding, autoAdjust } = this.config;
2526
+ let position;
2527
+ let placement = preferredPlacement;
2528
+ let flipped = false;
2529
+ const bottomPosition = {
2530
+ x: targetRect.x + (offset.x ?? 0),
2531
+ y: targetRect.y + targetRect.height + (offset.y ?? 8)
2532
+ };
2533
+ const topPosition = {
2534
+ x: targetRect.x + (offset.x ?? 0),
2535
+ y: targetRect.y - popupSize.height - (offset.y ?? 8)
2536
+ };
2537
+ if (preferredPlacement === "bottom") {
2538
+ position = bottomPosition;
2539
+ if (autoAdjust && position.y + popupSize.height > viewport.height - viewportPadding) {
2540
+ if (topPosition.y >= viewportPadding) {
2541
+ position = topPosition;
2542
+ placement = "top";
2543
+ flipped = true;
2544
+ }
2545
+ }
2546
+ } else {
2547
+ position = topPosition;
2548
+ if (autoAdjust && position.y < viewportPadding) {
2549
+ if (bottomPosition.y + popupSize.height <= viewport.height - viewportPadding) {
2550
+ position = bottomPosition;
2551
+ placement = "bottom";
2552
+ flipped = true;
2553
+ }
2554
+ }
2555
+ }
2556
+ if (autoAdjust) {
2557
+ if (position.x < viewportPadding) position.x = viewportPadding;
2558
+ if (position.x + popupSize.width > viewport.width - viewportPadding) position.x = viewport.width - popupSize.width - viewportPadding;
2559
+ }
2560
+ const maxHeight = placement === "bottom" ? viewport.height - position.y - viewportPadding : targetRect.y - viewportPadding;
2561
+ return {
2562
+ position,
2563
+ placement,
2564
+ flipped,
2565
+ maxHeight: Math.max(200, maxHeight),
2566
+ maxWidth: viewport.width - viewportPadding * 2
2567
+ };
2568
+ }
2569
+ /**
2570
+ * 获取弹出层初始样式(用于动画)
2571
+ */
2572
+ getInitialStyles(placement) {
2573
+ switch (placement) {
2574
+ case "bottom-sheet": return {
2575
+ transform: "translateY(100%)",
2576
+ opacity: "1"
2577
+ };
2578
+ case "bottom": return {
2579
+ transform: "translateY(-10px)",
2580
+ opacity: "0"
2581
+ };
2582
+ case "top": return {
2583
+ transform: "translateY(10px)",
2584
+ opacity: "0"
2585
+ };
2586
+ default: return { opacity: "0" };
2587
+ }
2588
+ }
2589
+ /**
2590
+ * 获取弹出层最终样式(动画结束)
2591
+ */
2592
+ getFinalStyles(placement) {
2593
+ return {
2594
+ transform: "translateY(0)",
2595
+ opacity: "1"
2596
+ };
2597
+ }
2598
+ /**
2599
+ * 获取弹出层退出样式
2600
+ */
2601
+ getExitStyles(placement) {
2602
+ return this.getInitialStyles(placement);
2603
+ }
2604
+ /**
2605
+ * 获取动画时长
2606
+ */
2607
+ getAnimationDuration() {
2608
+ return this.config.animationDuration;
2609
+ }
2610
+ /**
2611
+ * 检查是否显示遮罩
2612
+ */
2613
+ shouldShowMask() {
2614
+ return isMobile() && this.config.showMask;
2615
+ }
2616
+ /**
2617
+ * 检查遮罩是否可点击关闭
2618
+ */
2619
+ isMaskClosable() {
2620
+ return this.config.maskClosable;
2621
+ }
2622
+ };
2623
+ function createPositionManager(config) {
2624
+ return new PositionManager(config);
2625
+ }
2626
+ //#endregion
2627
+ //#region src/themes/presets.ts
2628
+ const miuiTheme = {
2629
+ name: "miui",
2630
+ displayName: "MIUI",
2631
+ description: "小米风格 - 纯净简洁",
2632
+ isDark: false,
2633
+ colors: {
2634
+ background: "#f5f5f5",
2635
+ keyBackground: "#ffffff",
2636
+ keyColor: "#1a1a1a",
2637
+ keyActiveBackground: "#e8e8e8",
2638
+ fnKeyBackground: "#e0e0e0",
2639
+ fnKeyColor: "#666666",
2640
+ fnKeyActiveBackground: "#d0d0d0",
2641
+ primaryBackground: "#ff6700",
2642
+ primaryActiveBackground: "#e55d00",
2643
+ primaryColor: "#ffffff",
2644
+ borderColor: "transparent",
2645
+ dividerColor: "#eeeeee"
2646
+ },
2647
+ sizes: {
2648
+ keyHeight: 46,
2649
+ keyRadius: 8,
2650
+ keyGap: 6,
2651
+ fontSize: 18,
2652
+ fnFontSize: 14,
2653
+ padding: 8
2654
+ },
2655
+ effects: {
2656
+ keyShadow: "none",
2657
+ keyActiveShadow: "none",
2658
+ keyActiveScale: .96,
2659
+ transitionDuration: 100,
2660
+ enableBlur: false,
2661
+ blurAmount: 0,
2662
+ enableRipple: false
2663
+ }
2664
+ };
2665
+ const iosTheme = {
2666
+ name: "ios",
2667
+ displayName: "iOS",
2668
+ description: "Apple 风格 - 精致优雅",
2669
+ isDark: false,
2670
+ colors: {
2671
+ background: "#d1d3d9",
2672
+ keyBackground: "#ffffff",
2673
+ keyColor: "#000000",
2674
+ keyActiveBackground: "#b8bac2",
2675
+ fnKeyBackground: "#a8aab4",
2676
+ fnKeyColor: "#000000",
2677
+ fnKeyActiveBackground: "#9699a3",
2678
+ primaryBackground: "#007aff",
2679
+ primaryActiveBackground: "#0062cc",
2680
+ primaryColor: "#ffffff",
2681
+ borderColor: "transparent",
2682
+ dividerColor: "#c8cad0"
2683
+ },
2684
+ sizes: {
2685
+ keyHeight: 43,
2686
+ keyRadius: 5,
2687
+ keyGap: 6,
2688
+ fontSize: 22,
2689
+ fnFontSize: 15,
2690
+ padding: 4
2691
+ },
2692
+ effects: {
2693
+ keyShadow: "0 1px 0 rgba(0,0,0,0.35)",
2694
+ keyActiveShadow: "0 0 0 rgba(0,0,0,0)",
2695
+ keyActiveScale: 1,
2696
+ transitionDuration: 80,
2697
+ enableBlur: true,
2698
+ blurAmount: 20,
2699
+ enableRipple: false
2700
+ }
2701
+ };
2702
+ const materialTheme = {
2703
+ name: "material",
2704
+ displayName: "Material",
2705
+ description: "Google 风格 - 深邃现代",
2706
+ isDark: true,
2707
+ colors: {
2708
+ background: "#263238",
2709
+ keyBackground: "#37474f",
2710
+ keyColor: "#ffffff",
2711
+ keyActiveBackground: "#455a64",
2712
+ fnKeyBackground: "#455a64",
2713
+ fnKeyColor: "#b0bec5",
2714
+ fnKeyActiveBackground: "#546e7a",
2715
+ primaryBackground: "#4caf50",
2716
+ primaryActiveBackground: "#43a047",
2717
+ primaryColor: "#ffffff",
2718
+ borderColor: "transparent",
2719
+ dividerColor: "#37474f"
2720
+ },
2721
+ sizes: {
2722
+ keyHeight: 48,
2723
+ keyRadius: 4,
2724
+ keyGap: 4,
2725
+ fontSize: 20,
2726
+ fnFontSize: 14,
2727
+ padding: 6
2728
+ },
2729
+ effects: {
2730
+ keyShadow: "0 1px 3px rgba(0,0,0,0.2)",
2731
+ keyActiveShadow: "0 2px 6px rgba(0,0,0,0.3)",
2732
+ keyActiveScale: 1,
2733
+ transitionDuration: 150,
2734
+ enableBlur: false,
2735
+ blurAmount: 0,
2736
+ enableRipple: true
2737
+ }
2738
+ };
2739
+ const minimalTheme = {
2740
+ name: "minimal",
2741
+ displayName: "Minimal",
2742
+ description: "极简风格 - 轻盈透明",
2743
+ isDark: false,
2744
+ colors: {
2745
+ background: "rgba(250, 250, 250, 0.95)",
2746
+ keyBackground: "transparent",
2747
+ keyColor: "#333333",
2748
+ keyActiveBackground: "rgba(0, 0, 0, 0.08)",
2749
+ fnKeyBackground: "transparent",
2750
+ fnKeyColor: "#888888",
2751
+ fnKeyActiveBackground: "rgba(0, 0, 0, 0.08)",
2752
+ primaryBackground: "#333333",
2753
+ primaryActiveBackground: "#000000",
2754
+ primaryColor: "#ffffff",
2755
+ borderColor: "#eeeeee",
2756
+ dividerColor: "#eeeeee"
2757
+ },
2758
+ sizes: {
2759
+ keyHeight: 44,
2760
+ keyRadius: 12,
2761
+ keyGap: 8,
2762
+ fontSize: 17,
2763
+ fnFontSize: 13,
2764
+ padding: 12
2765
+ },
2766
+ effects: {
2767
+ keyShadow: "none",
2768
+ keyActiveShadow: "none",
2769
+ keyActiveScale: .92,
2770
+ transitionDuration: 120,
2771
+ enableBlur: true,
2772
+ blurAmount: 30,
2773
+ enableRipple: false
2774
+ }
2775
+ };
2776
+ const darkTheme = {
2777
+ name: "dark",
2778
+ displayName: "Dark",
2779
+ description: "深色模式 - 护眼舒适",
2780
+ isDark: true,
2781
+ colors: {
2782
+ background: "#1c1c1e",
2783
+ keyBackground: "#3a3a3c",
2784
+ keyColor: "#ffffff",
2785
+ keyActiveBackground: "#4a4a4c",
2786
+ fnKeyBackground: "#2c2c2e",
2787
+ fnKeyColor: "#ebebf5",
2788
+ fnKeyActiveBackground: "#3c3c3e",
2789
+ primaryBackground: "#0a84ff",
2790
+ primaryActiveBackground: "#0070e0",
2791
+ primaryColor: "#ffffff",
2792
+ borderColor: "#3a3a3c",
2793
+ dividerColor: "#3a3a3c"
2794
+ },
2795
+ sizes: {
2796
+ keyHeight: 45,
2797
+ keyRadius: 8,
2798
+ keyGap: 6,
2799
+ fontSize: 18,
2800
+ fnFontSize: 14,
2801
+ padding: 8
2802
+ },
2803
+ effects: {
2804
+ keyShadow: "0 1px 2px rgba(0,0,0,0.4)",
2805
+ keyActiveShadow: "0 0 8px rgba(10,132,255,0.3)",
2806
+ keyActiveScale: .97,
2807
+ transitionDuration: 100,
2808
+ enableBlur: true,
2809
+ blurAmount: 20,
2810
+ enableRipple: false
2811
+ }
2812
+ };
2813
+ const presetThemes = {
2814
+ miui: miuiTheme,
2815
+ ios: iosTheme,
2816
+ material: materialTheme,
2817
+ minimal: minimalTheme,
2818
+ dark: darkTheme
2819
+ };
2820
+ const defaultTheme = miuiTheme;
2821
+ //#endregion
2822
+ //#region src/themes/index.ts
2823
+ const customThemes = /* @__PURE__ */ new Map();
2824
+ let currentTheme = defaultTheme;
2825
+ function getTheme(name) {
2826
+ return customThemes.get(name) || presetThemes[name] || defaultTheme;
2827
+ }
2828
+ function registerTheme(theme) {
2829
+ customThemes.set(theme.name, theme);
2830
+ }
2831
+ function getAvailableThemes() {
2832
+ return [...Object.keys(presetThemes), ...customThemes.keys()];
2833
+ }
2834
+ function getAllThemes() {
2835
+ return [...Object.values(presetThemes), ...customThemes.values()];
2836
+ }
2837
+ function setCurrentTheme(name) {
2838
+ currentTheme = getTheme(name);
2839
+ return currentTheme;
2840
+ }
2841
+ function getCurrentTheme() {
2842
+ return currentTheme;
2843
+ }
2844
+ function themeToCSS(theme) {
2845
+ return {
2846
+ "--keyboard-bg": theme.colors.background,
2847
+ "--keyboard-key-bg": theme.colors.keyBackground,
2848
+ "--keyboard-key-color": theme.colors.keyColor,
2849
+ "--keyboard-key-active-bg": theme.colors.keyActiveBackground,
2850
+ "--keyboard-fn-key-bg": theme.colors.fnKeyBackground,
2851
+ "--keyboard-fn-key-color": theme.colors.fnKeyColor,
2852
+ "--keyboard-fn-key-active-bg": theme.colors.fnKeyActiveBackground,
2853
+ "--keyboard-primary-bg": theme.colors.primaryBackground,
2854
+ "--keyboard-primary-active-bg": theme.colors.primaryActiveBackground,
2855
+ "--keyboard-primary-color": theme.colors.primaryColor,
2856
+ "--keyboard-key-height": `${theme.sizes.keyHeight}px`,
2857
+ "--keyboard-key-radius": `${theme.sizes.keyRadius}px`,
2858
+ "--keyboard-key-gap": `${theme.sizes.keyGap}px`,
2859
+ "--keyboard-font-size": `${theme.sizes.fontSize}px`,
2860
+ "--keyboard-fn-font-size": `${theme.sizes.fnFontSize}px`,
2861
+ "--keyboard-padding": `${theme.sizes.padding}px`,
2862
+ "--keyboard-key-shadow": theme.effects.keyShadow,
2863
+ "--keyboard-transition-duration": `${theme.effects.transitionDuration}ms`,
2864
+ "--keyboard-border-color": theme.colors.borderColor,
2865
+ "--keyboard-divider-color": theme.colors.dividerColor
2866
+ };
2867
+ }
2868
+ function applyTheme(element, theme) {
2869
+ const cssVars = themeToCSS(theme);
2870
+ Object.entries(cssVars).forEach(([key, value]) => {
2871
+ if (value) element.style.setProperty(key, value);
2872
+ });
2873
+ element.classList.remove("keyboard-theme-light", "keyboard-theme-dark");
2874
+ element.classList.add(theme.isDark ? "keyboard-theme-dark" : "keyboard-theme-light");
2875
+ element.dataset.theme = theme.name;
2876
+ }
2877
+ function generateThemeStyle(theme) {
2878
+ const cssVars = themeToCSS(theme);
2879
+ return Object.entries(cssVars).filter(([, value]) => value).map(([key, value]) => `${key}: ${value}`).join("; ");
2880
+ }
2881
+ function mergeTheme(base, overrides) {
2882
+ return {
2883
+ ...base,
2884
+ ...overrides,
2885
+ colors: {
2886
+ ...base.colors,
2887
+ ...overrides.colors
2888
+ },
2889
+ sizes: {
2890
+ ...base.sizes,
2891
+ ...overrides.sizes
2892
+ },
2893
+ effects: {
2894
+ ...base.effects,
2895
+ ...overrides.effects
2896
+ }
2897
+ };
2898
+ }
2899
+ function createTheme(name, baseTheme, customization) {
2900
+ const theme = mergeTheme(getTheme(baseTheme), {
2901
+ ...customization,
2902
+ name
2903
+ });
2904
+ registerTheme(theme);
2905
+ return theme;
2906
+ }
2907
+ //#endregion
2908
+ //#region src/managers/keyboard-renderer.ts
2909
+ var KeyboardRenderer = class {
2910
+ constructor(options = {}) {
2911
+ /** DOM 元素 */
2912
+ this.rootEl = null;
2913
+ this.maskEl = null;
2914
+ this.keyboardEl = null;
2915
+ /** 当前目标元素 */
2916
+ this.targetEl = null;
2917
+ /** 清理函数 */
2918
+ this.cleanupFns = [];
2919
+ /** 是否已销毁 */
2920
+ this.destroyed = false;
2921
+ this.options = options;
2922
+ this.container = options.container || document.body;
2923
+ this.manager = new KeyboardManager(options);
2924
+ this.positionManager = new PositionManager(options.position);
2925
+ if (typeof options.theme === "string") this.theme = getTheme(options.theme);
2926
+ else if (options.theme) this.theme = options.theme;
2927
+ else this.theme = defaultTheme;
2928
+ this.setupEvents();
2929
+ }
2930
+ /**
2931
+ * 设置事件监听
2932
+ */
2933
+ setupEvents() {
2934
+ this.manager.on("stateChange", (state) => {
2935
+ if (state.visible) this.render();
2936
+ else this.unmount();
2937
+ });
2938
+ this.manager.on("input", ({ value }) => {
2939
+ this.options.onInput?.(value);
2940
+ });
2941
+ this.manager.on("confirm", ({ value }) => {
2942
+ this.options.onConfirm?.(value);
2943
+ });
2944
+ this.manager.on("switch", () => {
2945
+ if (this.manager.getState().visible) this.render();
2946
+ });
2947
+ this.manager.on("shift", () => {
2948
+ if (this.manager.getState().visible) this.render();
2949
+ });
2950
+ }
2951
+ /**
2952
+ * 打开键盘
2953
+ */
2954
+ open(target) {
2955
+ this.targetEl = target ?? null;
2956
+ this.manager.show(target);
2957
+ }
2958
+ /**
2959
+ * 关闭键盘
2960
+ */
2961
+ close() {
2962
+ this.manager.hide();
2963
+ this.options.onClose?.();
2964
+ }
2965
+ /**
2966
+ * 切换键盘类型
2967
+ */
2968
+ switchType(type) {
2969
+ this.manager.switchType(type);
2970
+ }
2971
+ /**
2972
+ * 设置主题
2973
+ */
2974
+ setTheme(theme) {
2975
+ if (typeof theme === "string") this.theme = getTheme(theme);
2976
+ else this.theme = theme;
2977
+ if (this.manager.getState().visible) this.render();
2978
+ }
2979
+ /**
2980
+ * 获取当前值
2981
+ */
2982
+ getValue() {
2983
+ return this.manager.getState().value;
2984
+ }
2985
+ /**
2986
+ * 设置值
2987
+ */
2988
+ setValue(value) {
2989
+ this.manager.setValue(value);
2990
+ }
2991
+ /**
2992
+ * 渲染键盘 DOM
2993
+ */
2994
+ render() {
2995
+ const layout = this.manager.getLayout();
2996
+ if (!layout) return;
2997
+ this.unmount();
2998
+ this.rootEl = document.createElement("div");
2999
+ this.rootEl.className = "lk-renderer-root";
3000
+ const isMobileDevice = isMobile();
3001
+ if (isMobileDevice) {
3002
+ this.maskEl = document.createElement("div");
3003
+ this.maskEl.className = "lk-mask";
3004
+ this.maskEl.addEventListener("click", () => this.close());
3005
+ this.rootEl.appendChild(this.maskEl);
3006
+ }
3007
+ this.keyboardEl = document.createElement("div");
3008
+ this.keyboardEl.className = `lk-popup lk-popup--${isMobileDevice ? "mobile" : "desktop"}`;
3009
+ const cssVars = themeToCSS(this.theme);
3010
+ Object.entries(cssVars).forEach(([key, value]) => {
3011
+ if (value) this.keyboardEl.style.setProperty(key, value);
3012
+ });
3013
+ const contentEl = this.renderKeyboard(layout);
3014
+ this.keyboardEl.appendChild(contentEl);
3015
+ this.rootEl.appendChild(this.keyboardEl);
3016
+ this.container.appendChild(this.rootEl);
3017
+ if (!isMobileDevice && this.targetEl) {
3018
+ const rect = this.keyboardEl.getBoundingClientRect();
3019
+ const result = this.positionManager.calculate(this.targetEl, {
3020
+ width: rect.width,
3021
+ height: rect.height
3022
+ });
3023
+ this.keyboardEl.style.position = "fixed";
3024
+ this.keyboardEl.style.left = `${result.position.x}px`;
3025
+ this.keyboardEl.style.top = `${result.position.y}px`;
3026
+ this.keyboardEl.style.zIndex = "10000";
3027
+ } else if (isMobileDevice) {
3028
+ this.keyboardEl.style.position = "fixed";
3029
+ this.keyboardEl.style.left = "0";
3030
+ this.keyboardEl.style.right = "0";
3031
+ this.keyboardEl.style.bottom = "0";
3032
+ this.keyboardEl.style.zIndex = "10000";
3033
+ }
3034
+ requestAnimationFrame(() => {
3035
+ this.keyboardEl?.classList.add("lk-popup--visible");
3036
+ this.maskEl?.classList.add("lk-mask--visible");
3037
+ });
3038
+ if (this.options.closeOnClickOutside !== false && this.keyboardEl) {
3039
+ const cleanup = onClickOutside(this.keyboardEl, (event) => {
3040
+ if (this.targetEl && this.targetEl.contains(event.target)) return;
3041
+ this.close();
3042
+ });
3043
+ this.cleanupFns.push(cleanup);
3044
+ }
3045
+ this.injectStyles();
3046
+ }
3047
+ /**
3048
+ * 渲染键盘内容
3049
+ */
3050
+ renderKeyboard(layout) {
3051
+ const el = document.createElement("div");
3052
+ el.className = "lk-keyboard";
3053
+ const state = this.manager.getState();
3054
+ layout.rows.forEach((row) => {
3055
+ const rowEl = document.createElement("div");
3056
+ rowEl.className = `lk-row ${row.className || ""}`;
3057
+ const isNumpad = row.className === "numpad-row";
3058
+ row.keys.forEach((key) => {
3059
+ const wrapperEl = document.createElement("div");
3060
+ wrapperEl.className = "lk-key-wrapper";
3061
+ if (isNumpad) wrapperEl.style.flex = String(key.width ?? 1);
3062
+ else if (key.width) {
3063
+ const baseW = 36;
3064
+ const gap = this.theme.sizes?.keyGap ?? 6;
3065
+ const w = baseW * key.width + (key.width - 1) * gap;
3066
+ wrapperEl.style.width = `${w}px`;
3067
+ }
3068
+ const btnEl = document.createElement("button");
3069
+ btnEl.type = "button";
3070
+ btnEl.className = this.getKeyClass(key, state.isUpperCase);
3071
+ if (key.disabled) btnEl.disabled = true;
3072
+ if (key.icon) btnEl.innerHTML = key.icon;
3073
+ else btnEl.textContent = typeof key.label === "string" ? key.label : state.isUpperCase ? key.label.upper : key.label.lower;
3074
+ const handler = (e) => {
3075
+ e.preventDefault();
3076
+ e.stopPropagation();
3077
+ if (!key.disabled) this.manager.handleKey(key);
3078
+ };
3079
+ btnEl.addEventListener("mousedown", handler);
3080
+ btnEl.addEventListener("touchstart", handler, { passive: false });
3081
+ wrapperEl.appendChild(btnEl);
3082
+ rowEl.appendChild(wrapperEl);
3083
+ });
3084
+ el.appendChild(rowEl);
3085
+ });
3086
+ return el;
3087
+ }
3088
+ /**
3089
+ * 获取按键 CSS 类名
3090
+ */
3091
+ getKeyClass(key, isUpperCase) {
3092
+ const classes = ["lk-key", `lk-key--${key.type}`];
3093
+ if (key.className) classes.push(key.className);
3094
+ if (key.disabled) classes.push("lk-key--disabled");
3095
+ if (key.type === "shift" && isUpperCase) classes.push("lk-key--active");
3096
+ return classes.join(" ");
3097
+ }
3098
+ /**
3099
+ * 卸载 DOM
3100
+ */
3101
+ unmount() {
3102
+ this.cleanupFns.forEach((fn) => fn());
3103
+ this.cleanupFns = [];
3104
+ if (this.rootEl && this.rootEl.parentNode) this.rootEl.parentNode.removeChild(this.rootEl);
3105
+ this.rootEl = null;
3106
+ this.maskEl = null;
3107
+ this.keyboardEl = null;
3108
+ }
3109
+ /**
3110
+ * 注入样式(单例)
3111
+ */
3112
+ injectStyles() {
3113
+ if (document.getElementById("lk-renderer-styles")) return;
3114
+ const style = document.createElement("style");
3115
+ style.id = "lk-renderer-styles";
3116
+ style.textContent = `
3117
+ .lk-renderer-root { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
3118
+ .lk-mask { position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 9999; opacity: 0; transition: opacity 0.3s ease; }
3119
+ .lk-mask--visible { opacity: 1; }
3120
+ .lk-popup { background: var(--keyboard-bg, #d1d5db); box-shadow: 0 -2px 16px rgba(0,0,0,0.15); overflow: hidden; transform: translateY(20px); opacity: 0; transition: transform 0.3s cubic-bezier(0.4,0,0.2,1), opacity 0.2s ease; }
3121
+ .lk-popup--visible { transform: translateY(0); opacity: 1; }
3122
+ .lk-popup--desktop { border-radius: 12px; box-shadow: 0 8px 32px rgba(0,0,0,0.18), 0 2px 8px rgba(0,0,0,0.1); min-width: 320px; }
3123
+ .lk-popup--mobile { border-top-left-radius: 16px; border-top-right-radius: 16px; padding-bottom: env(safe-area-inset-bottom, 0); }
3124
+ .lk-keyboard { display: flex; flex-direction: column; gap: var(--keyboard-key-gap, 6px); padding: var(--keyboard-padding, 6px); user-select: none; -webkit-user-select: none; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; }
3125
+ .lk-row { display: flex; justify-content: center; gap: var(--keyboard-key-gap, 6px); padding: 0 2px; }
3126
+ .lk-row.numpad-row { justify-content: stretch; }
3127
+ .lk-row.numpad-row .lk-key-wrapper { flex: 1; }
3128
+ .lk-key-wrapper { position: relative; display: inline-flex; }
3129
+ .lk-key { display: inline-flex; align-items: center; justify-content: center; height: var(--keyboard-key-height, 42px); min-width: 32px; width: 100%; padding: 0 6px; border: none; border-radius: var(--keyboard-key-radius, 6px); background: var(--keyboard-key-bg, #fff); color: var(--keyboard-key-color, #333); font-size: var(--keyboard-font-size, 16px); font-weight: 500; cursor: pointer; touch-action: manipulation; box-shadow: var(--keyboard-key-shadow, 0 1px 3px rgba(0,0,0,0.1)); transition: background-color 0.1s, transform 0.1s; }
3130
+ .lk-key:active { background: var(--keyboard-key-active-bg, #e0e0e0); transform: scale(0.95); }
3131
+ .lk-key--disabled { opacity: 0.4; cursor: not-allowed; }
3132
+ .lk-key--disabled:active { transform: none; background: var(--keyboard-key-bg, #fff); }
3133
+ .lk-key--backspace, .lk-key--shift, .lk-key--tab, .lk-key--clear, .lk-key--close { background: var(--keyboard-fn-key-bg, #d4d6dc); color: var(--keyboard-fn-key-color, #333); font-size: var(--keyboard-fn-font-size, 14px); }
3134
+ .lk-key--backspace:active, .lk-key--shift:active, .lk-key--tab:active, .lk-key--clear:active, .lk-key--close:active { background: var(--keyboard-fn-key-active-bg, #b8bac0); }
3135
+ .lk-key--active { background: var(--keyboard-key-active-bg, #007aff) !important; color: #fff !important; }
3136
+ .lk-key--done, .lk-key--enter { background: var(--keyboard-primary-bg, #007aff); color: var(--keyboard-primary-color, #fff); font-size: var(--keyboard-fn-font-size, 14px); }
3137
+ .lk-key--done:active, .lk-key--enter:active { background: var(--keyboard-primary-active-bg, #0062cc); }
3138
+ .lk-key--space { background: var(--keyboard-key-bg, #fff); }
3139
+ .lk-key svg { pointer-events: none; }
3140
+ `;
3141
+ document.head.appendChild(style);
3142
+ }
3143
+ /**
3144
+ * 绑定到输入框(聚焦时自动打开键盘)
3145
+ */
3146
+ bindInput(input) {
3147
+ const handleFocus = () => this.open(input);
3148
+ input.addEventListener("focus", handleFocus);
3149
+ input.setAttribute("readonly", "readonly");
3150
+ input.style.caretColor = "transparent";
3151
+ return () => {
3152
+ input.removeEventListener("focus", handleFocus);
3153
+ input.removeAttribute("readonly");
3154
+ input.style.caretColor = "";
3155
+ };
3156
+ }
3157
+ /**
3158
+ * 销毁渲染器
3159
+ */
3160
+ destroy() {
3161
+ if (this.destroyed) return;
3162
+ this.destroyed = true;
3163
+ this.unmount();
3164
+ this.manager.destroy();
3165
+ const styleEl = document.getElementById("lk-renderer-styles");
3166
+ if (styleEl) styleEl.remove();
3167
+ }
3168
+ };
3169
+ function createKeyboardRenderer(options) {
3170
+ return new KeyboardRenderer(options);
3171
+ }
3172
+ //#endregion
3173
+ //#region src/utils/random.ts
3174
+ function shuffleArray(array) {
3175
+ const result = [...array];
3176
+ for (let i = result.length - 1; i > 0; i--) {
3177
+ const j = Math.floor(Math.random() * (i + 1));
3178
+ [result[i], result[j]] = [result[j], result[i]];
3179
+ }
3180
+ return result;
3181
+ }
3182
+ function getRandomNumbers() {
3183
+ return shuffleArray([
3184
+ "0",
3185
+ "1",
3186
+ "2",
3187
+ "3",
3188
+ "4",
3189
+ "5",
3190
+ "6",
3191
+ "7",
3192
+ "8",
3193
+ "9"
3194
+ ]);
3195
+ }
3196
+ function getRandomLetters() {
3197
+ return shuffleArray(Array.from({ length: 26 }, (_, i) => String.fromCharCode(65 + i)));
3198
+ }
3199
+ function getRandomAlphanumeric() {
3200
+ const numbers = [
3201
+ "0",
3202
+ "1",
3203
+ "2",
3204
+ "3",
3205
+ "4",
3206
+ "5",
3207
+ "6",
3208
+ "7",
3209
+ "8",
3210
+ "9"
3211
+ ];
3212
+ const letters = Array.from({ length: 26 }, (_, i) => String.fromCharCode(65 + i));
3213
+ return shuffleArray([...numbers, ...letters]);
3214
+ }
3215
+ function createCharKey(char, index) {
3216
+ return {
3217
+ id: `random-${char}-${index}`,
3218
+ type: "char",
3219
+ label: char,
3220
+ value: char,
3221
+ className: "key-random"
3222
+ };
3223
+ }
3224
+ function chunkArray(array, chunkSize) {
3225
+ const chunks = [];
3226
+ for (let i = 0; i < array.length; i += chunkSize) chunks.push(array.slice(i, i + chunkSize));
3227
+ return chunks;
3228
+ }
3229
+ function createRandomNumberLayout(options) {
3230
+ const { keysPerRow = 3, includeBackspace = true, includeDone = true, includeClear = false } = options || {};
3231
+ const rows = chunkArray(getRandomNumbers().map((n, i) => createCharKey(n, i)), keysPerRow).map((keys, index) => ({
3232
+ className: "numpad-row",
3233
+ keys
3234
+ }));
3235
+ const fnKeys = [];
3236
+ if (includeClear) fnKeys.push({
3237
+ id: "clear",
3238
+ type: "clear",
3239
+ label: "清空",
3240
+ className: "key-clear key-fn"
3241
+ });
3242
+ if (includeBackspace) fnKeys.push({
3243
+ id: "backspace",
3244
+ type: "backspace",
3245
+ label: "⌫",
3246
+ className: "key-backspace key-fn"
3247
+ });
3248
+ if (includeDone) fnKeys.push({
3249
+ id: "done",
3250
+ type: "done",
3251
+ label: "确定",
3252
+ className: "key-done key-fn"
3253
+ });
3254
+ if (fnKeys.length > 0) rows.push({
3255
+ className: "numpad-row",
3256
+ keys: fnKeys
3257
+ });
3258
+ return {
3259
+ type: "custom",
3260
+ name: "随机数字键盘",
3261
+ supportShift: false,
3262
+ rows,
3263
+ data: {
3264
+ isRandom: true,
3265
+ randomType: "number"
3266
+ }
3267
+ };
3268
+ }
3269
+ function createRandomPinLayout(options) {
3270
+ const { includeBackspace = true, includeDone = true } = options || {};
3271
+ const randomNumbers = getRandomNumbers();
3272
+ const rows = [
3273
+ {
3274
+ className: "numpad-row",
3275
+ keys: randomNumbers.slice(0, 3).map((n, i) => createCharKey(n, i))
3276
+ },
3277
+ {
3278
+ className: "numpad-row",
3279
+ keys: randomNumbers.slice(3, 6).map((n, i) => createCharKey(n, i + 3))
3280
+ },
3281
+ {
3282
+ className: "numpad-row",
3283
+ keys: randomNumbers.slice(6, 9).map((n, i) => createCharKey(n, i + 6))
3284
+ }
3285
+ ];
3286
+ const lastRow = [];
3287
+ if (includeBackspace) lastRow.push({
3288
+ id: "backspace",
3289
+ type: "backspace",
3290
+ label: "⌫",
3291
+ className: "key-backspace key-fn"
3292
+ });
3293
+ else lastRow.push({
3294
+ id: "empty-1",
3295
+ type: "char",
3296
+ label: "",
3297
+ value: "",
3298
+ disabled: true,
3299
+ className: "key-placeholder"
3300
+ });
3301
+ lastRow.push(createCharKey(randomNumbers[9], 9));
3302
+ if (includeDone) lastRow.push({
3303
+ id: "done",
3304
+ type: "done",
3305
+ label: "确定",
3306
+ className: "key-done key-fn"
3307
+ });
3308
+ else lastRow.push({
3309
+ id: "empty-2",
3310
+ type: "char",
3311
+ label: "",
3312
+ value: "",
3313
+ disabled: true,
3314
+ className: "key-placeholder"
3315
+ });
3316
+ rows.push({
3317
+ className: "numpad-row",
3318
+ keys: lastRow
3319
+ });
3320
+ return {
3321
+ type: "custom",
3322
+ name: "随机PIN键盘",
3323
+ supportShift: false,
3324
+ rows,
3325
+ data: {
3326
+ isRandom: true,
3327
+ randomType: "pin"
3328
+ }
3329
+ };
3330
+ }
3331
+ function createRandomLetterLayout(options) {
3332
+ const { uppercase = true, rowDistribution = [
3333
+ 10,
3334
+ 9,
3335
+ 7
3336
+ ] } = options || {};
3337
+ let randomLetters = getRandomLetters();
3338
+ if (!uppercase) randomLetters = randomLetters.map((l) => l.toLowerCase());
3339
+ const letterKeys = randomLetters.map((l, i) => createCharKey(l, i));
3340
+ const rows = [];
3341
+ let offset = 0;
3342
+ for (const count of rowDistribution) {
3343
+ rows.push({
3344
+ className: "numpad-row",
3345
+ keys: letterKeys.slice(offset, offset + count)
3346
+ });
3347
+ offset += count;
3348
+ }
3349
+ if (offset < letterKeys.length) rows.push({
3350
+ className: "numpad-row",
3351
+ keys: letterKeys.slice(offset)
3352
+ });
3353
+ rows.push({
3354
+ className: "numpad-row",
3355
+ keys: [
3356
+ {
3357
+ id: "clear",
3358
+ type: "clear",
3359
+ label: "清空",
3360
+ className: "key-clear key-fn"
3361
+ },
3362
+ {
3363
+ id: "backspace",
3364
+ type: "backspace",
3365
+ label: "⌫",
3366
+ className: "key-backspace key-fn"
3367
+ },
3368
+ {
3369
+ id: "done",
3370
+ type: "done",
3371
+ label: "确定",
3372
+ className: "key-done key-fn"
3373
+ }
3374
+ ]
3375
+ });
3376
+ return {
3377
+ type: "custom",
3378
+ name: "随机字母键盘",
3379
+ supportShift: false,
3380
+ rows,
3381
+ data: {
3382
+ isRandom: true,
3383
+ randomType: "letter"
3384
+ }
3385
+ };
3386
+ }
3387
+ function createRandomMixedLayout(options) {
3388
+ const { rowDistribution = [
3389
+ 10,
3390
+ 10,
3391
+ 9,
3392
+ 7
3393
+ ] } = options || {};
3394
+ const charKeys = getRandomAlphanumeric().map((c, i) => createCharKey(c, i));
3395
+ const rows = [];
3396
+ let offset = 0;
3397
+ for (const count of rowDistribution) {
3398
+ if (offset >= charKeys.length) break;
3399
+ rows.push({
3400
+ className: "numpad-row",
3401
+ keys: charKeys.slice(offset, offset + count)
3402
+ });
3403
+ offset += count;
3404
+ }
3405
+ if (offset < charKeys.length) rows.push({
3406
+ className: "numpad-row",
3407
+ keys: charKeys.slice(offset)
3408
+ });
3409
+ rows.push({
3410
+ className: "numpad-row",
3411
+ keys: [
3412
+ {
3413
+ id: "clear",
3414
+ type: "clear",
3415
+ label: "清空",
3416
+ className: "key-clear key-fn"
3417
+ },
3418
+ {
3419
+ id: "backspace",
3420
+ type: "backspace",
3421
+ label: "⌫",
3422
+ className: "key-backspace key-fn"
3423
+ },
3424
+ {
3425
+ id: "done",
3426
+ type: "done",
3427
+ label: "确定",
3428
+ className: "key-done key-fn"
3429
+ }
3430
+ ]
3431
+ });
3432
+ return {
3433
+ type: "custom",
3434
+ name: "随机混合键盘",
3435
+ supportShift: false,
3436
+ rows,
3437
+ data: {
3438
+ isRandom: true,
3439
+ randomType: "mixed"
3440
+ }
3441
+ };
3442
+ }
3443
+ function refreshRandomLayout(layout) {
3444
+ switch (layout.data?.randomType) {
3445
+ case "number": return createRandomNumberLayout();
3446
+ case "pin": return createRandomPinLayout();
3447
+ case "letter": return createRandomLetterLayout();
3448
+ case "mixed": return createRandomMixedLayout();
3449
+ default: return layout;
3450
+ }
3451
+ }
3452
+ //#endregion
3453
+ //#region src/utils/formatters.ts
3454
+ function formatPhone(value) {
3455
+ const digits = value.replace(/\D/g, "").slice(0, 11);
3456
+ if (digits.length <= 3) return digits;
3457
+ if (digits.length <= 7) return `${digits.slice(0, 3)} ${digits.slice(3)}`;
3458
+ return `${digits.slice(0, 3)} ${digits.slice(3, 7)} ${digits.slice(7)}`;
3459
+ }
3460
+ function formatBankCard(value) {
3461
+ return value.replace(/\D/g, "").slice(0, 19).replace(/(\d{4})(?=\d)/g, "$1 ");
3462
+ }
3463
+ function formatAmount(value, decimalPlaces = 2) {
3464
+ let result = value.replace(/[^\d.]/g, "");
3465
+ const parts = result.split(".");
3466
+ if (parts.length > 2) result = parts[0] + "." + parts.slice(1).join("");
3467
+ if (parts.length === 2 && parts[1].length > decimalPlaces) result = parts[0] + "." + parts[1].slice(0, decimalPlaces);
3468
+ if (result.length > 1 && result.startsWith("0") && result[1] !== ".") result = result.replace(/^0+/, "") || "0";
3469
+ return result;
3470
+ }
3471
+ function formatIdCard(value) {
3472
+ return value.replace(/[^\dXx]/g, "").slice(0, 18).toUpperCase();
3473
+ }
3474
+ function formatLicensePlate(value) {
3475
+ return value.toUpperCase().slice(0, 8);
3476
+ }
3477
+ function formatVerifyCode(value, length = 6) {
3478
+ return value.replace(/\D/g, "").slice(0, length);
3479
+ }
3480
+ const formatters = /* @__PURE__ */ new Map([
3481
+ ["phone", formatPhone],
3482
+ ["bankcard", formatBankCard],
3483
+ ["idcard", formatIdCard],
3484
+ ["license-plate", formatLicensePlate],
3485
+ ["verifycode", formatVerifyCode]
3486
+ ]);
3487
+ function registerFormatter(name, formatter) {
3488
+ formatters.set(name, formatter);
3489
+ }
3490
+ function getFormatter(name) {
3491
+ return formatters.get(name);
3492
+ }
3493
+ function applyFormatter(name, value) {
3494
+ const formatter = formatters.get(name);
3495
+ return formatter ? formatter(value) : value;
3496
+ }
3497
+ //#endregion
3498
+ exports.EMAIL_SUFFIXES = EMAIL_SUFFIXES;
3499
+ exports.EventEmitter = EventEmitter;
3500
+ exports.ICONS = ICONS;
3501
+ exports.ICON_CHECK = ICON_CHECK;
3502
+ exports.ICON_CLEAR = ICON_CLEAR;
3503
+ exports.ICON_CLOSE = ICON_CLOSE;
3504
+ exports.ICON_DELETE = ICON_DELETE;
3505
+ exports.ICON_ENTER = ICON_ENTER;
3506
+ exports.ICON_KEYBOARD = ICON_KEYBOARD;
3507
+ exports.ICON_SHIFT = ICON_SHIFT;
3508
+ exports.ICON_SPACE = ICON_SPACE;
3509
+ exports.ICON_VOICE = ICON_VOICE;
3510
+ exports.KeyboardManager = KeyboardManager;
3511
+ exports.KeyboardRenderer = KeyboardRenderer;
3512
+ exports.PLATE_LETTERS = PLATE_LETTERS;
3513
+ exports.PROVINCES = PROVINCES;
3514
+ exports.PositionManager = PositionManager;
3515
+ exports.amountLayout = amountLayout;
3516
+ exports.amountSimpleLayout = amountSimpleLayout;
3517
+ exports.applyFormatter = applyFormatter;
3518
+ exports.applyTheme = applyTheme;
3519
+ exports.bankcardLayout = bankcardLayout;
3520
+ exports.createElement = createElement;
3521
+ exports.createKeyboardManager = createKeyboardManager;
3522
+ exports.createKeyboardRenderer = createKeyboardRenderer;
3523
+ exports.createPositionManager = createPositionManager;
3524
+ exports.createRandomLetterLayout = createRandomLetterLayout;
3525
+ exports.createRandomMixedLayout = createRandomMixedLayout;
3526
+ exports.createRandomNumberLayout = createRandomNumberLayout;
3527
+ exports.createRandomPinLayout = createRandomPinLayout;
3528
+ exports.createTheme = createTheme;
3529
+ exports.darkTheme = darkTheme;
3530
+ exports.defaultTheme = defaultTheme;
3531
+ exports.deleteCharBeforeCursor = deleteCharBeforeCursor;
3532
+ exports.emailLayout = emailLayout;
3533
+ exports.formatAmount = formatAmount;
3534
+ exports.formatBankCard = formatBankCard;
3535
+ exports.formatIdCard = formatIdCard;
3536
+ exports.formatLicensePlate = formatLicensePlate;
3537
+ exports.formatPhone = formatPhone;
3538
+ exports.formatVerifyCode = formatVerifyCode;
3539
+ exports.generateThemeStyle = generateThemeStyle;
3540
+ exports.getAllThemes = getAllThemes;
3541
+ exports.getAvailableLayouts = getAvailableLayouts;
3542
+ exports.getAvailableThemes = getAvailableThemes;
3543
+ exports.getBoundingRect = getBoundingRect;
3544
+ exports.getCurrentTheme = getCurrentTheme;
3545
+ exports.getDeviceType = getDeviceType;
3546
+ exports.getElementOffset = getElementOffset;
3547
+ exports.getFormatter = getFormatter;
3548
+ exports.getInputCursorPosition = getInputCursorPosition;
3549
+ exports.getLayout = getLayout;
3550
+ exports.getRandomAlphanumeric = getRandomAlphanumeric;
3551
+ exports.getRandomLetters = getRandomLetters;
3552
+ exports.getRandomNumbers = getRandomNumbers;
3553
+ exports.getSafeAreaInsets = getSafeAreaInsets;
3554
+ exports.getTheme = getTheme;
3555
+ exports.getViewportInfo = getViewportInfo;
3556
+ exports.hasLayout = hasLayout;
3557
+ exports.idcardLayout = idcardLayout;
3558
+ exports.insertTextAtCursor = insertTextAtCursor;
3559
+ exports.integerLayout = integerLayout;
3560
+ exports.iosTheme = iosTheme;
3561
+ exports.isClickOutside = isClickOutside;
3562
+ exports.isElementInViewport = isElementInViewport;
3563
+ exports.isMobile = isMobile;
3564
+ exports.isMobileUA = isMobileUA;
3565
+ exports.isTouchDevice = isTouchDevice;
3566
+ exports.licensePlateAlphanumericLayout = licensePlateAlphanumericLayout;
3567
+ exports.licensePlateLayout = licensePlateLayout;
3568
+ exports.licensePlateLetterLayout = licensePlateLetterLayout;
3569
+ exports.licensePlateProvinceLayout = licensePlateProvinceLayout;
3570
+ exports.materialTheme = materialTheme;
3571
+ exports.mergeTheme = mergeTheme;
3572
+ exports.minimalTheme = minimalTheme;
3573
+ exports.miuiTheme = miuiTheme;
3574
+ exports.numberLayout = numberLayout;
3575
+ exports.onClickOutside = onClickOutside;
3576
+ exports.onViewportChange = onViewportChange;
3577
+ exports.phoneLayout = phoneLayout;
3578
+ exports.phoneSimpleLayout = phoneSimpleLayout;
3579
+ exports.presetThemes = presetThemes;
3580
+ exports.preventDefaultAndStopPropagation = preventDefaultAndStopPropagation;
3581
+ exports.punctLayout = punctLayout;
3582
+ exports.qwertyLayout = qwertyLayout;
3583
+ exports.refreshRandomLayout = refreshRandomLayout;
3584
+ exports.registerFormatter = registerFormatter;
3585
+ exports.registerLayout = registerLayout;
3586
+ exports.registerLayouts = registerLayouts;
3587
+ exports.registerTheme = registerTheme;
3588
+ exports.scrollIntoViewIfNeeded = scrollIntoViewIfNeeded;
3589
+ exports.searchLayout = searchLayout;
3590
+ exports.setCurrentTheme = setCurrentTheme;
3591
+ exports.setInputCursorPosition = setInputCursorPosition;
3592
+ exports.setStyles = setStyles;
3593
+ exports.shuffleArray = shuffleArray;
3594
+ exports.supportsVibrate = supportsVibrate;
3595
+ exports.symbolLayout = symbolLayout;
3596
+ exports.symbolLayout2 = symbolLayout2;
3597
+ exports.themeToCSS = themeToCSS;
3598
+ exports.toggleClass = toggleClass;
3599
+ exports.unregisterLayout = unregisterLayout;
3600
+ exports.urlLayout = urlLayout;
3601
+ exports.verifycodeLayout = verifycodeLayout;
3602
+ exports.vibrate = vibrate;
3603
+ });
3604
+ /*! End of @composy/keyboard-core | Powered by @composy/builder */
3605
+ //# sourceMappingURL=index.js.map