@composy/keyboard-core 0.0.1 → 0.0.2

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 (339) hide show
  1. package/README.md +156 -37
  2. package/dist/index.js +1540 -1395
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.min.js +2981 -1
  5. package/dist/index.min.js.map +1 -0
  6. package/es/.dts-output-manifest.json +1 -0
  7. package/es/.dts.tsbuildinfo +1 -0
  8. package/es/icons.d.ts +0 -1
  9. package/es/icons.js +1 -1
  10. package/es/icons.js.map +1 -1
  11. package/es/index.d.ts +3 -4
  12. package/es/index.js +15 -15
  13. package/es/layouts/amount.d.ts +0 -1
  14. package/es/layouts/amount.js +1 -1
  15. package/es/layouts/amount.js.map +1 -1
  16. package/es/layouts/bankcard.d.ts +0 -1
  17. package/es/layouts/bankcard.js +1 -1
  18. package/es/layouts/bankcard.js.map +1 -1
  19. package/es/layouts/email.d.ts +0 -1
  20. package/es/layouts/email.js +1 -1
  21. package/es/layouts/email.js.map +1 -1
  22. package/es/layouts/idcard.d.ts +0 -1
  23. package/es/layouts/idcard.js +1 -1
  24. package/es/layouts/idcard.js.map +1 -1
  25. package/es/layouts/index.d.ts +11 -12
  26. package/es/layouts/index.js +23 -23
  27. package/es/layouts/index.js.map +1 -1
  28. package/es/layouts/license-plate.d.ts +0 -1
  29. package/es/layouts/license-plate.js +1 -1
  30. package/es/layouts/license-plate.js.map +1 -1
  31. package/es/layouts/number.d.ts +0 -1
  32. package/es/layouts/number.js +1 -1
  33. package/es/layouts/number.js.map +1 -1
  34. package/es/layouts/phone.d.ts +0 -1
  35. package/es/layouts/phone.js +1 -1
  36. package/es/layouts/phone.js.map +1 -1
  37. package/es/layouts/punct.d.ts +0 -1
  38. package/es/layouts/punct.js +1 -1
  39. package/es/layouts/punct.js.map +1 -1
  40. package/es/layouts/qwerty.d.ts +0 -1
  41. package/es/layouts/qwerty.js +1 -1
  42. package/es/layouts/qwerty.js.map +1 -1
  43. package/es/layouts/search.d.ts +0 -1
  44. package/es/layouts/search.js +1 -1
  45. package/es/layouts/search.js.map +1 -1
  46. package/es/layouts/symbol.d.ts +0 -1
  47. package/es/layouts/symbol.js +1 -1
  48. package/es/layouts/symbol.js.map +1 -1
  49. package/es/layouts/url.d.ts +0 -1
  50. package/es/layouts/url.js +1 -1
  51. package/es/layouts/url.js.map +1 -1
  52. package/es/layouts/verifycode.d.ts +0 -1
  53. package/es/layouts/verifycode.js +1 -1
  54. package/es/layouts/verifycode.js.map +1 -1
  55. package/es/managers/index.d.ts +1 -2
  56. package/es/managers/index.js +1 -1
  57. package/es/managers/keyboard-manager.d.ts +2 -1
  58. package/es/managers/keyboard-manager.js +79 -22
  59. package/es/managers/keyboard-manager.js.map +1 -1
  60. package/es/managers/keyboard-renderer.d.ts +3 -2
  61. package/es/managers/keyboard-renderer.js +81 -39
  62. package/es/managers/keyboard-renderer.js.map +1 -1
  63. package/es/managers/position-manager.d.ts +4 -3
  64. package/es/managers/position-manager.js +42 -21
  65. package/es/managers/position-manager.js.map +1 -1
  66. package/es/themes/index.d.ts +1 -2
  67. package/es/themes/index.js +2 -1
  68. package/es/themes/index.js.map +1 -1
  69. package/es/themes/presets.d.ts +0 -1
  70. package/es/themes/presets.js +1 -1
  71. package/es/themes/presets.js.map +1 -1
  72. package/es/themes/types.d.ts +1 -1
  73. package/es/themes/types.js +1 -1
  74. package/es/types/index.d.ts +0 -1
  75. package/es/types/index.js +1 -1
  76. package/es/types/keyboard.d.ts +0 -1
  77. package/es/types/keyboard.js +1 -1
  78. package/es/types/position.d.ts +0 -1
  79. package/es/types/position.js +1 -1
  80. package/es/utils/device.d.ts +0 -1
  81. package/es/utils/device.js +11 -7
  82. package/es/utils/device.js.map +1 -1
  83. package/es/utils/dom.d.ts +4 -1
  84. package/es/utils/dom.js +25 -7
  85. package/es/utils/dom.js.map +1 -1
  86. package/es/utils/event-emitter.d.ts +0 -1
  87. package/es/utils/event-emitter.js +2 -1
  88. package/es/utils/event-emitter.js.map +1 -1
  89. package/es/utils/formatters.d.ts +0 -1
  90. package/es/utils/formatters.js +4 -4
  91. package/es/utils/formatters.js.map +1 -1
  92. package/es/utils/index.d.ts +2 -3
  93. package/es/utils/index.js +5 -5
  94. package/es/utils/random.d.ts +4 -1
  95. package/es/utils/random.js +2 -2
  96. package/es/utils/random.js.map +1 -1
  97. package/esm/icons.js +1 -1
  98. package/esm/icons.js.map +1 -1
  99. package/esm/index.js +15 -15
  100. package/esm/layouts/amount.js +1 -1
  101. package/esm/layouts/amount.js.map +1 -1
  102. package/esm/layouts/bankcard.js +1 -1
  103. package/esm/layouts/bankcard.js.map +1 -1
  104. package/esm/layouts/email.js +1 -1
  105. package/esm/layouts/email.js.map +1 -1
  106. package/esm/layouts/idcard.js +1 -1
  107. package/esm/layouts/idcard.js.map +1 -1
  108. package/esm/layouts/index.js +23 -23
  109. package/esm/layouts/index.js.map +1 -1
  110. package/esm/layouts/license-plate.js +1 -1
  111. package/esm/layouts/license-plate.js.map +1 -1
  112. package/esm/layouts/number.js +1 -1
  113. package/esm/layouts/number.js.map +1 -1
  114. package/esm/layouts/phone.js +1 -1
  115. package/esm/layouts/phone.js.map +1 -1
  116. package/esm/layouts/punct.js +1 -1
  117. package/esm/layouts/punct.js.map +1 -1
  118. package/esm/layouts/qwerty.js +1 -1
  119. package/esm/layouts/qwerty.js.map +1 -1
  120. package/esm/layouts/search.js +1 -1
  121. package/esm/layouts/search.js.map +1 -1
  122. package/esm/layouts/symbol.js +1 -1
  123. package/esm/layouts/symbol.js.map +1 -1
  124. package/esm/layouts/url.js +1 -1
  125. package/esm/layouts/url.js.map +1 -1
  126. package/esm/layouts/verifycode.js +1 -1
  127. package/esm/layouts/verifycode.js.map +1 -1
  128. package/esm/managers/index.js +1 -1
  129. package/esm/managers/keyboard-manager.js +79 -22
  130. package/esm/managers/keyboard-manager.js.map +1 -1
  131. package/esm/managers/keyboard-renderer.js +81 -39
  132. package/esm/managers/keyboard-renderer.js.map +1 -1
  133. package/esm/managers/position-manager.js +42 -21
  134. package/esm/managers/position-manager.js.map +1 -1
  135. package/esm/themes/index.js +2 -1
  136. package/esm/themes/index.js.map +1 -1
  137. package/esm/themes/presets.js +1 -1
  138. package/esm/themes/presets.js.map +1 -1
  139. package/esm/utils/device.js +11 -7
  140. package/esm/utils/device.js.map +1 -1
  141. package/esm/utils/dom.js +25 -7
  142. package/esm/utils/dom.js.map +1 -1
  143. package/esm/utils/event-emitter.js +2 -1
  144. package/esm/utils/event-emitter.js.map +1 -1
  145. package/esm/utils/formatters.js +4 -4
  146. package/esm/utils/formatters.js.map +1 -1
  147. package/esm/utils/random.js +2 -2
  148. package/esm/utils/random.js.map +1 -1
  149. package/lib/icons.cjs +1 -1
  150. package/lib/icons.cjs.map +1 -1
  151. package/{esm/icons.d.ts → lib/icons.d.cts} +0 -1
  152. package/lib/index.cjs +14 -13
  153. package/{esm/index.d.ts → lib/index.d.cts} +3 -4
  154. package/lib/layouts/amount.cjs +1 -1
  155. package/lib/layouts/amount.cjs.map +1 -1
  156. package/{esm/layouts/amount.d.ts → lib/layouts/amount.d.cts} +0 -1
  157. package/lib/layouts/bankcard.cjs +1 -1
  158. package/lib/layouts/bankcard.cjs.map +1 -1
  159. package/{esm/layouts/bankcard.d.ts → lib/layouts/bankcard.d.cts} +0 -1
  160. package/lib/layouts/email.cjs +1 -1
  161. package/lib/layouts/email.cjs.map +1 -1
  162. package/lib/layouts/{email.d.ts → email.d.cts} +0 -1
  163. package/lib/layouts/idcard.cjs +1 -1
  164. package/lib/layouts/idcard.cjs.map +1 -1
  165. package/{esm/layouts/idcard.d.ts → lib/layouts/idcard.d.cts} +0 -1
  166. package/lib/layouts/index.cjs +23 -23
  167. package/lib/layouts/index.cjs.map +1 -1
  168. package/{esm/layouts/index.d.ts → lib/layouts/index.d.cts} +11 -12
  169. package/lib/layouts/license-plate.cjs +1 -1
  170. package/lib/layouts/license-plate.cjs.map +1 -1
  171. package/{esm/layouts/license-plate.d.ts → lib/layouts/license-plate.d.cts} +0 -1
  172. package/lib/layouts/number.cjs +1 -1
  173. package/lib/layouts/number.cjs.map +1 -1
  174. package/{esm/layouts/number.d.ts → lib/layouts/number.d.cts} +0 -1
  175. package/lib/layouts/phone.cjs +1 -1
  176. package/lib/layouts/phone.cjs.map +1 -1
  177. package/lib/layouts/{phone.d.ts → phone.d.cts} +0 -1
  178. package/lib/layouts/punct.cjs +1 -1
  179. package/lib/layouts/punct.cjs.map +1 -1
  180. package/lib/layouts/{punct.d.ts → punct.d.cts} +0 -1
  181. package/lib/layouts/qwerty.cjs +1 -1
  182. package/lib/layouts/qwerty.cjs.map +1 -1
  183. package/{esm/layouts/qwerty.d.ts → lib/layouts/qwerty.d.cts} +0 -1
  184. package/lib/layouts/search.cjs +1 -1
  185. package/lib/layouts/search.cjs.map +1 -1
  186. package/{esm/layouts/search.d.ts → lib/layouts/search.d.cts} +0 -1
  187. package/lib/layouts/symbol.cjs +1 -1
  188. package/lib/layouts/symbol.cjs.map +1 -1
  189. package/{esm/layouts/symbol.d.ts → lib/layouts/symbol.d.cts} +0 -1
  190. package/lib/layouts/url.cjs +1 -1
  191. package/lib/layouts/url.cjs.map +1 -1
  192. package/{esm/layouts/url.d.ts → lib/layouts/url.d.cts} +0 -1
  193. package/lib/layouts/verifycode.cjs +1 -1
  194. package/lib/layouts/verifycode.cjs.map +1 -1
  195. package/lib/layouts/{verifycode.d.ts → verifycode.d.cts} +0 -1
  196. package/lib/managers/index.cjs +1 -1
  197. package/lib/managers/{index.d.ts → index.d.cts} +1 -2
  198. package/lib/managers/keyboard-manager.cjs +79 -22
  199. package/lib/managers/keyboard-manager.cjs.map +1 -1
  200. package/lib/managers/{keyboard-manager.d.ts → keyboard-manager.d.cts} +2 -1
  201. package/lib/managers/keyboard-renderer.cjs +80 -38
  202. package/lib/managers/keyboard-renderer.cjs.map +1 -1
  203. package/lib/managers/{keyboard-renderer.d.ts → keyboard-renderer.d.cts} +3 -2
  204. package/lib/managers/position-manager.cjs +42 -21
  205. package/lib/managers/position-manager.cjs.map +1 -1
  206. package/lib/managers/{position-manager.d.ts → position-manager.d.cts} +4 -3
  207. package/lib/themes/index.cjs +2 -1
  208. package/lib/themes/index.cjs.map +1 -1
  209. package/lib/themes/{index.d.ts → index.d.cts} +1 -2
  210. package/lib/themes/presets.cjs +1 -1
  211. package/lib/themes/presets.cjs.map +1 -1
  212. package/lib/themes/{presets.d.ts → presets.d.cts} +0 -1
  213. package/lib/themes/types.cjs +1 -1
  214. package/{esm/themes/types.d.ts → lib/themes/types.d.cts} +1 -1
  215. package/lib/types/index.cjs +1 -1
  216. package/{esm/types/index.d.ts → lib/types/index.d.cts} +0 -1
  217. package/lib/types/keyboard.cjs +1 -1
  218. package/{esm/types/keyboard.d.ts → lib/types/keyboard.d.cts} +0 -1
  219. package/lib/types/position.cjs +1 -1
  220. package/lib/types/{position.d.ts → position.d.cts} +0 -1
  221. package/lib/utils/device.cjs +11 -7
  222. package/lib/utils/device.cjs.map +1 -1
  223. package/{esm/utils/device.d.ts → lib/utils/device.d.cts} +0 -1
  224. package/lib/utils/dom.cjs +25 -6
  225. package/lib/utils/dom.cjs.map +1 -1
  226. package/{esm/utils/dom.d.ts → lib/utils/dom.d.cts} +4 -1
  227. package/lib/utils/event-emitter.cjs +2 -1
  228. package/lib/utils/event-emitter.cjs.map +1 -1
  229. package/{esm/utils/event-emitter.d.ts → lib/utils/event-emitter.d.cts} +0 -1
  230. package/lib/utils/formatters.cjs +4 -4
  231. package/lib/utils/formatters.cjs.map +1 -1
  232. package/{esm/utils/formatters.d.ts → lib/utils/formatters.d.cts} +0 -1
  233. package/lib/utils/index.cjs +4 -3
  234. package/{esm/utils/index.d.ts → lib/utils/index.d.cts} +2 -3
  235. package/lib/utils/random.cjs +2 -2
  236. package/lib/utils/random.cjs.map +1 -1
  237. package/{esm/utils/random.d.ts → lib/utils/random.d.cts} +4 -1
  238. package/package.json +28 -14
  239. package/es/icons.d.ts.map +0 -1
  240. package/es/index.d.ts.map +0 -1
  241. package/es/layouts/amount.d.ts.map +0 -1
  242. package/es/layouts/bankcard.d.ts.map +0 -1
  243. package/es/layouts/email.d.ts.map +0 -1
  244. package/es/layouts/idcard.d.ts.map +0 -1
  245. package/es/layouts/index.d.ts.map +0 -1
  246. package/es/layouts/license-plate.d.ts.map +0 -1
  247. package/es/layouts/number.d.ts.map +0 -1
  248. package/es/layouts/phone.d.ts.map +0 -1
  249. package/es/layouts/punct.d.ts.map +0 -1
  250. package/es/layouts/qwerty.d.ts.map +0 -1
  251. package/es/layouts/search.d.ts.map +0 -1
  252. package/es/layouts/symbol.d.ts.map +0 -1
  253. package/es/layouts/url.d.ts.map +0 -1
  254. package/es/layouts/verifycode.d.ts.map +0 -1
  255. package/es/managers/index.d.ts.map +0 -1
  256. package/es/managers/keyboard-manager.d.ts.map +0 -1
  257. package/es/managers/keyboard-renderer.d.ts.map +0 -1
  258. package/es/managers/position-manager.d.ts.map +0 -1
  259. package/es/themes/index.d.ts.map +0 -1
  260. package/es/themes/presets.d.ts.map +0 -1
  261. package/es/themes/types.d.ts.map +0 -1
  262. package/es/types/index.d.ts.map +0 -1
  263. package/es/types/keyboard.d.ts.map +0 -1
  264. package/es/types/position.d.ts.map +0 -1
  265. package/es/utils/device.d.ts.map +0 -1
  266. package/es/utils/dom.d.ts.map +0 -1
  267. package/es/utils/event-emitter.d.ts.map +0 -1
  268. package/es/utils/formatters.d.ts.map +0 -1
  269. package/es/utils/index.d.ts.map +0 -1
  270. package/es/utils/random.d.ts.map +0 -1
  271. package/esm/icons.d.ts.map +0 -1
  272. package/esm/index.d.ts.map +0 -1
  273. package/esm/layouts/amount.d.ts.map +0 -1
  274. package/esm/layouts/bankcard.d.ts.map +0 -1
  275. package/esm/layouts/email.d.ts +0 -11
  276. package/esm/layouts/email.d.ts.map +0 -1
  277. package/esm/layouts/idcard.d.ts.map +0 -1
  278. package/esm/layouts/index.d.ts.map +0 -1
  279. package/esm/layouts/license-plate.d.ts.map +0 -1
  280. package/esm/layouts/number.d.ts.map +0 -1
  281. package/esm/layouts/phone.d.ts +0 -15
  282. package/esm/layouts/phone.d.ts.map +0 -1
  283. package/esm/layouts/punct.d.ts +0 -7
  284. package/esm/layouts/punct.d.ts.map +0 -1
  285. package/esm/layouts/qwerty.d.ts.map +0 -1
  286. package/esm/layouts/search.d.ts.map +0 -1
  287. package/esm/layouts/symbol.d.ts.map +0 -1
  288. package/esm/layouts/url.d.ts.map +0 -1
  289. package/esm/layouts/verifycode.d.ts +0 -15
  290. package/esm/layouts/verifycode.d.ts.map +0 -1
  291. package/esm/managers/index.d.ts +0 -8
  292. package/esm/managers/index.d.ts.map +0 -1
  293. package/esm/managers/keyboard-manager.d.ts +0 -130
  294. package/esm/managers/keyboard-manager.d.ts.map +0 -1
  295. package/esm/managers/keyboard-renderer.d.ts +0 -115
  296. package/esm/managers/keyboard-renderer.d.ts.map +0 -1
  297. package/esm/managers/position-manager.d.ts +0 -72
  298. package/esm/managers/position-manager.d.ts.map +0 -1
  299. package/esm/themes/index.d.ts +0 -70
  300. package/esm/themes/index.d.ts.map +0 -1
  301. package/esm/themes/presets.d.ts +0 -39
  302. package/esm/themes/presets.d.ts.map +0 -1
  303. package/esm/themes/types.d.ts.map +0 -1
  304. package/esm/themes/types.js +0 -10
  305. package/esm/types/index.d.ts.map +0 -1
  306. package/esm/types/index.js +0 -10
  307. package/esm/types/keyboard.d.ts.map +0 -1
  308. package/esm/types/keyboard.js +0 -10
  309. package/esm/types/position.d.ts +0 -139
  310. package/esm/types/position.d.ts.map +0 -1
  311. package/esm/types/position.js +0 -10
  312. package/esm/utils/device.d.ts.map +0 -1
  313. package/esm/utils/dom.d.ts.map +0 -1
  314. package/esm/utils/event-emitter.d.ts.map +0 -1
  315. package/esm/utils/formatters.d.ts.map +0 -1
  316. package/esm/utils/index.d.ts.map +0 -1
  317. package/esm/utils/index.js +0 -16
  318. package/esm/utils/random.d.ts.map +0 -1
  319. package/lib/icons.d.ts +0 -58
  320. package/lib/index.d.ts +0 -12
  321. package/lib/layouts/amount.d.ts +0 -14
  322. package/lib/layouts/bankcard.d.ts +0 -15
  323. package/lib/layouts/idcard.d.ts +0 -16
  324. package/lib/layouts/index.d.ts +0 -54
  325. package/lib/layouts/license-plate.d.ts +0 -35
  326. package/lib/layouts/number.d.ts +0 -14
  327. package/lib/layouts/qwerty.d.ts +0 -10
  328. package/lib/layouts/search.d.ts +0 -7
  329. package/lib/layouts/symbol.d.ts +0 -14
  330. package/lib/layouts/url.d.ts +0 -7
  331. package/lib/themes/types.d.ts +0 -118
  332. package/lib/types/index.d.ts +0 -7
  333. package/lib/types/keyboard.d.ts +0 -253
  334. package/lib/utils/device.d.ts +0 -45
  335. package/lib/utils/dom.d.ts +0 -69
  336. package/lib/utils/event-emitter.d.ts +0 -52
  337. package/lib/utils/formatters.d.ts +0 -51
  338. package/lib/utils/index.d.ts +0 -10
  339. package/lib/utils/random.d.ts +0 -71
@@ -1 +1 @@
1
- {"version":3,"file":"symbol.js","names":[],"sources":["../../src/layouts/symbol.ts"],"sourcesContent":["/**\n * 符号键盘布局\n * @module layouts/symbol\n */\n\nimport type { KeyboardConfig, KeyDefinition } from '../types'\n\n/**\n * 创建符号按键\n */\nfunction createSymbolKey(symbol: string, id?: string): KeyDefinition {\n return {\n id: id || `symbol-${symbol.charCodeAt(0)}`,\n type: 'char',\n label: symbol,\n value: symbol,\n }\n}\n\n/**\n * 符号键盘配置\n */\nexport const symbolLayout: KeyboardConfig = {\n type: 'symbol',\n name: '符号键盘',\n supportShift: false,\n switchable: ['qwerty', 'number'],\n rows: [\n {\n keys: [\n createSymbolKey('1'),\n createSymbolKey('2'),\n createSymbolKey('3'),\n createSymbolKey('4'),\n createSymbolKey('5'),\n createSymbolKey('6'),\n createSymbolKey('7'),\n createSymbolKey('8'),\n createSymbolKey('9'),\n createSymbolKey('0'),\n ],\n },\n {\n keys: [\n createSymbolKey('-'),\n createSymbolKey('/'),\n createSymbolKey(':'),\n createSymbolKey(';'),\n createSymbolKey('('),\n createSymbolKey(')'),\n createSymbolKey('¥', 'yen'),\n createSymbolKey('@'),\n createSymbolKey('\"', 'quote'),\n ],\n },\n {\n keys: [\n {\n id: 'switch-symbol-2',\n type: 'tab',\n label: '#+= ',\n width: 1.5,\n className: 'key-switch',\n data: { targetType: 'symbol-2' },\n },\n createSymbolKey('.'),\n createSymbolKey(','),\n createSymbolKey('?'),\n createSymbolKey('!'),\n createSymbolKey('\\'', 'apostrophe'),\n {\n id: 'backspace',\n type: 'backspace',\n label: '⌫',\n width: 1.5,\n className: 'key-backspace',\n },\n ],\n },\n {\n keys: [\n {\n id: 'switch-qwerty',\n type: 'tab',\n label: 'ABC',\n width: 1.5,\n className: 'key-switch',\n data: { targetType: 'qwerty' },\n },\n {\n id: 'switch-number',\n type: 'tab',\n label: '123',\n width: 1.25,\n className: 'key-switch',\n data: { targetType: 'number' },\n },\n {\n id: 'space',\n type: 'space',\n label: '空格',\n value: ' ',\n width: 4,\n className: 'key-space',\n },\n {\n id: 'done',\n type: 'done',\n label: '完成',\n width: 2,\n className: 'key-done',\n },\n ],\n },\n ],\n}\n\n/**\n * 符号键盘第二页\n */\nexport const symbolLayout2: KeyboardConfig = {\n type: 'symbol',\n name: '符号键盘2',\n supportShift: false,\n switchable: ['qwerty', 'number'],\n rows: [\n {\n keys: [\n createSymbolKey('['),\n createSymbolKey(']'),\n createSymbolKey('{'),\n createSymbolKey('}'),\n createSymbolKey('#'),\n createSymbolKey('%'),\n createSymbolKey('^'),\n createSymbolKey('*'),\n createSymbolKey('+'),\n createSymbolKey('='),\n ],\n },\n {\n keys: [\n createSymbolKey('_'),\n createSymbolKey('\\\\'),\n createSymbolKey('|'),\n createSymbolKey('~'),\n createSymbolKey('<'),\n createSymbolKey('>'),\n createSymbolKey('€', 'euro'),\n createSymbolKey('$'),\n createSymbolKey('&'),\n ],\n },\n {\n keys: [\n {\n id: 'switch-symbol-1',\n type: 'tab',\n label: '123',\n width: 1.5,\n className: 'key-switch',\n data: { targetType: 'symbol' },\n },\n createSymbolKey('`', 'backtick'),\n createSymbolKey('·', 'middle-dot'),\n createSymbolKey('…', 'ellipsis'),\n createSymbolKey('°', 'degree'),\n createSymbolKey('•', 'bullet'),\n {\n id: 'backspace',\n type: 'backspace',\n label: '⌫',\n width: 1.5,\n className: 'key-backspace',\n },\n ],\n },\n {\n keys: [\n {\n id: 'switch-qwerty',\n type: 'tab',\n label: 'ABC',\n width: 1.5,\n className: 'key-switch',\n data: { targetType: 'qwerty' },\n },\n {\n id: 'switch-number',\n type: 'tab',\n label: '123',\n width: 1.25,\n className: 'key-switch',\n data: { targetType: 'number' },\n },\n {\n id: 'space',\n type: 'space',\n label: '空格',\n value: ' ',\n width: 4,\n className: 'key-space',\n },\n {\n id: 'done',\n type: 'done',\n label: '完成',\n width: 2,\n className: 'key-done',\n },\n ],\n },\n ],\n}\n"],"mappings":";;;;;;;;;;AAUA,SAAS,gBAAgB,QAAgB,IAA4B;CACnE,OAAO;EACL,IAAI,MAAM,UAAU,OAAO,WAAW,CAAC;EACvC,MAAM;EACN,OAAO;EACP,OAAO;CACT;AACF;AAKO,MAAM,eAA+B;CAC1C,MAAM;CACN,MAAM;CACN,cAAc;CACd,YAAY,CAAC,UAAU,QAAQ;CAC/B,MAAM;EACJ,EACE,MAAM;GACJ,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;EACrB,EACF;EACA,EACE,MAAM;GACJ,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,KAAK,KAAK;GAC1B,gBAAgB,GAAG;GACnB,gBAAgB,MAAK,OAAO;EAC9B,EACF;EACA,EACE,MAAM;GACJ;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;IACX,MAAM,EAAE,YAAY,WAAW;GACjC;GACA,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,KAAM,YAAY;GAClC;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;GACb;EACF,EACF;EACA,EACE,MAAM;GACJ;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;IACX,MAAM,EAAE,YAAY,SAAS;GAC/B;GACA;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;IACX,MAAM,EAAE,YAAY,SAAS;GAC/B;GACA;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,WAAW;GACb;GACA;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;GACb;EACF,EACF;CACF;AACF;AAKO,MAAM,gBAAgC;CAC3C,MAAM;CACN,MAAM;CACN,cAAc;CACd,YAAY,CAAC,UAAU,QAAQ;CAC/B,MAAM;EACJ,EACE,MAAM;GACJ,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;EACrB,EACF;EACA,EACE,MAAM;GACJ,gBAAgB,GAAG;GACnB,gBAAgB,IAAI;GACpB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;GACnB,gBAAgB,KAAK,MAAM;GAC3B,gBAAgB,GAAG;GACnB,gBAAgB,GAAG;EACrB,EACF;EACA,EACE,MAAM;GACJ;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;IACX,MAAM,EAAE,YAAY,SAAS;GAC/B;GACA,gBAAgB,KAAK,UAAU;GAC/B,gBAAgB,KAAK,YAAY;GACjC,gBAAgB,KAAK,UAAU;GAC/B,gBAAgB,KAAK,QAAQ;GAC7B,gBAAgB,KAAK,QAAQ;GAC7B;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;GACb;EACF,EACF;EACA,EACE,MAAM;GACJ;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;IACX,MAAM,EAAE,YAAY,SAAS;GAC/B;GACA;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;IACX,MAAM,EAAE,YAAY,SAAS;GAC/B;GACA;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,WAAW;GACb;GACA;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;GACb;EACF,EACF;CACF;AACF"}
1
+ {"version":3,"file":"symbol.js","names":[],"sources":["../../src/layouts/symbol.ts"],"sourcesContent":["/**\r\n * 符号键盘布局\r\n * @module layouts/symbol\r\n */\r\n\r\nimport type { KeyboardConfig, KeyDefinition } from '../types'\r\n\r\n/**\r\n * 创建符号按键\r\n */\r\nfunction createSymbolKey(symbol: string, id?: string): KeyDefinition {\r\n return {\r\n id: id || `symbol-${symbol.charCodeAt(0)}`,\r\n type: 'char',\r\n label: symbol,\r\n value: symbol,\r\n }\r\n}\r\n\r\n/**\r\n * 符号键盘配置\r\n */\r\nexport const symbolLayout: KeyboardConfig = {\r\n type: 'symbol',\r\n name: '符号键盘',\r\n supportShift: false,\r\n switchable: ['qwerty', 'number'],\r\n rows: [\r\n {\r\n keys: [\r\n createSymbolKey('1'),\r\n createSymbolKey('2'),\r\n createSymbolKey('3'),\r\n createSymbolKey('4'),\r\n createSymbolKey('5'),\r\n createSymbolKey('6'),\r\n createSymbolKey('7'),\r\n createSymbolKey('8'),\r\n createSymbolKey('9'),\r\n createSymbolKey('0'),\r\n ],\r\n },\r\n {\r\n keys: [\r\n createSymbolKey('-'),\r\n createSymbolKey('/'),\r\n createSymbolKey(':'),\r\n createSymbolKey(';'),\r\n createSymbolKey('('),\r\n createSymbolKey(')'),\r\n createSymbolKey('¥', 'yen'),\r\n createSymbolKey('@'),\r\n createSymbolKey('\"', 'quote'),\r\n ],\r\n },\r\n {\r\n keys: [\r\n {\r\n id: 'switch-symbol-2',\r\n type: 'tab',\r\n label: '#+= ',\r\n width: 1.5,\r\n className: 'key-switch',\r\n data: { targetType: 'symbol-2' },\r\n },\r\n createSymbolKey('.'),\r\n createSymbolKey(','),\r\n createSymbolKey('?'),\r\n createSymbolKey('!'),\r\n createSymbolKey(\"'\", 'apostrophe'),\r\n {\r\n id: 'backspace',\r\n type: 'backspace',\r\n label: '⌫',\r\n width: 1.5,\r\n className: 'key-backspace',\r\n },\r\n ],\r\n },\r\n {\r\n keys: [\r\n {\r\n id: 'switch-qwerty',\r\n type: 'tab',\r\n label: 'ABC',\r\n width: 1.5,\r\n className: 'key-switch',\r\n data: { targetType: 'qwerty' },\r\n },\r\n {\r\n id: 'switch-number',\r\n type: 'tab',\r\n label: '123',\r\n width: 1.25,\r\n className: 'key-switch',\r\n data: { targetType: 'number' },\r\n },\r\n {\r\n id: 'space',\r\n type: 'space',\r\n label: '空格',\r\n value: ' ',\r\n width: 4,\r\n className: 'key-space',\r\n },\r\n {\r\n id: 'done',\r\n type: 'done',\r\n label: '完成',\r\n width: 2,\r\n className: 'key-done',\r\n },\r\n ],\r\n },\r\n ],\r\n}\r\n\r\n/**\r\n * 符号键盘第二页\r\n */\r\nexport const symbolLayout2: KeyboardConfig = {\r\n type: 'symbol',\r\n name: '符号键盘2',\r\n supportShift: false,\r\n switchable: ['qwerty', 'number'],\r\n rows: [\r\n {\r\n keys: [\r\n createSymbolKey('['),\r\n createSymbolKey(']'),\r\n createSymbolKey('{'),\r\n createSymbolKey('}'),\r\n createSymbolKey('#'),\r\n createSymbolKey('%'),\r\n createSymbolKey('^'),\r\n createSymbolKey('*'),\r\n createSymbolKey('+'),\r\n createSymbolKey('='),\r\n ],\r\n },\r\n {\r\n keys: [\r\n createSymbolKey('_'),\r\n createSymbolKey('\\\\'),\r\n createSymbolKey('|'),\r\n createSymbolKey('~'),\r\n createSymbolKey('<'),\r\n createSymbolKey('>'),\r\n createSymbolKey('€', 'euro'),\r\n createSymbolKey('$'),\r\n createSymbolKey('&'),\r\n ],\r\n },\r\n {\r\n keys: [\r\n {\r\n id: 'switch-symbol-1',\r\n type: 'tab',\r\n label: '123',\r\n width: 1.5,\r\n className: 'key-switch',\r\n data: { targetType: 'symbol' },\r\n },\r\n createSymbolKey('`', 'backtick'),\r\n createSymbolKey('·', 'middle-dot'),\r\n createSymbolKey('…', 'ellipsis'),\r\n createSymbolKey('°', 'degree'),\r\n createSymbolKey('•', 'bullet'),\r\n {\r\n id: 'backspace',\r\n type: 'backspace',\r\n label: '⌫',\r\n width: 1.5,\r\n className: 'key-backspace',\r\n },\r\n ],\r\n },\r\n {\r\n keys: [\r\n {\r\n id: 'switch-qwerty',\r\n type: 'tab',\r\n label: 'ABC',\r\n width: 1.5,\r\n className: 'key-switch',\r\n data: { targetType: 'qwerty' },\r\n },\r\n {\r\n id: 'switch-number',\r\n type: 'tab',\r\n label: '123',\r\n width: 1.25,\r\n className: 'key-switch',\r\n data: { targetType: 'number' },\r\n },\r\n {\r\n id: 'space',\r\n type: 'space',\r\n label: '空格',\r\n value: ' ',\r\n width: 4,\r\n className: 'key-space',\r\n },\r\n {\r\n id: 'done',\r\n type: 'done',\r\n label: '完成',\r\n width: 2,\r\n className: 'key-done',\r\n },\r\n ],\r\n },\r\n ],\r\n}\r\n"],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  * ***********************************
3
3
  * @composy/keyboard-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:33:29 *
5
+ * Build time: 2024-10-12 17:29:15 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
@@ -1 +1 @@
1
- {"version":3,"file":"url.js","names":[],"sources":["../../src/layouts/url.ts"],"sourcesContent":["/**\n * URL/链接键盘布局\n * @module layouts/url\n */\n\n// 导入键盘配置和按键定义的类型\nimport type { KeyboardConfig, KeyDefinition } from '../types'\n// 导入删除和Shift图标资源\nimport { ICON_DELETE, ICON_SHIFT } from '../icons'\n\n/**\n * 创建字符按键(支持大小写)\n * @param char - 字符,用于生成大小写标签和值\n * @returns 返回一个按键定义对象\n */\nfunction createCharKey(char: string): KeyDefinition {\n return {\n id: `url-char-${char.toLowerCase()}`, // 按键唯一标识,格式为 url-char-x\n type: 'char', // 按键类型为字符键\n label: { lower: char.toLowerCase(), upper: char.toUpperCase() }, // 显示标签:小写/大写\n value: { lower: char.toLowerCase(), upper: char.toUpperCase() }, // 输出值:小写/大写\n }\n}\n\n/**\n * 创建快捷片段按键\n * 用于URL键盘中常用的符号和域名后缀\n * @param label - 按键显示文本\n * @param width - 可选,按键宽度倍数\n * @returns 返回一个片段按键定义对象\n */\nfunction snippet(label: string, width?: number): KeyDefinition {\n // 生成唯一 ID:用 label 的字符编码(去除非法字符后拼接)\n const idSuffix = label.replace(/[^a-z0-9]/gi, '') || label.split('').map(c => c.charCodeAt(0)).join('')\n return {\n id: `url-snippet-${idSuffix}`, // 按键唯一标识,格式为 url-snippet-xxx\n type: 'char', // 按键类型为字符键\n label, // 显示文本\n value: label, // 输出值与显示文本相同\n width, // 按键宽度倍数\n className: 'key-snippet', // 自定义CSS类名,用于样式控制\n }\n}\n\n// 导出URL键盘布局配置\nexport const urlLayout: KeyboardConfig = {\n type: 'url', // 布局类型标识为 url\n name: '网址键盘', // 布局显示名称\n supportShift: true, // 支持Shift切换大小写\n defaultUpperCase: false, // 默认为小写状态\n switchable: ['symbol', 'number'], // 可切换到符号键盘和数字键盘\n rows: [\n // QWERTY 第一行:q w e r t y u i o p\n {\n keys: 'qwertyuiop'.split('').map(createCharKey), // 将字符串拆分为字符数组,逐个创建按键\n },\n // QWERTY 第二行:a s d f g h j k l\n {\n keys: 'asdfghjkl'.split('').map(createCharKey), // 将字符串拆分为字符数组,逐个创建按键\n },\n // QWERTY 第三行 + Shift + 退格\n {\n keys: [\n {\n id: 'shift', // Shift键标识\n type: 'shift', // 按键类型为Shift\n icon: ICON_SHIFT, // 使用Shift图标\n label: '', // 无文字标签,仅显示图标\n width: 1.5, // 宽度为1.5倍\n className: 'key-shift', // CSS类名\n },\n ...'zxcvbnm'.split('').map(createCharKey), // 展开第三行字母 z x c v b n m 的按键定义\n {\n id: 'backspace', // 退格键标识\n type: 'backspace', // 按键类型为退格\n icon: ICON_DELETE, // 使用删除图标\n label: '', // 无文字标签,仅显示图标\n width: 1.5, // 宽度为1.5倍\n className: 'key-backspace', // CSS类名\n },\n ],\n },\n // 底部行:切换 + 符号 + 域名后缀 + 前往\n {\n keys: [\n { id: 'switch-number', type: 'tab', label: '123', width: 1.2, className: 'key-switch', data: { targetType: 'number' } }, // 切换到数字键盘\n snippet('/', 0.8), // 斜杠快捷键,宽度0.8倍\n snippet('.', 0.8), // 点号快捷键,宽度0.8倍\n snippet('-', 0.8), // 横杠快捷键,宽度0.8倍\n snippet('.com', 1.5), // .com域名后缀快捷键,宽度1.5倍\n snippet('.cn', 1.2), // .cn域名后缀快捷键,宽度1.2倍\n { id: 'space', type: 'space', label: '', value: ' ', width: 1.5, className: 'key-space' }, // 空格键,宽度1.5倍\n { id: 'url-go', type: 'done', label: '前往', width: 1.5, className: 'key-done' }, // 前往/完成按钮,宽度1.5倍\n ],\n },\n ],\n}\n"],"mappings":";;;;;;;;;;;AAeA,SAAS,cAAc,MAA6B;CAClD,OAAO;EACL,IAAI,YAAY,KAAK,YAAY;EACjC,MAAM;EACN,OAAO;GAAE,OAAO,KAAK,YAAY;GAAG,OAAO,KAAK,YAAY;EAAE;EAC9D,OAAO;GAAE,OAAO,KAAK,YAAY;GAAG,OAAO,KAAK,YAAY;EAAE;CAChE;AACF;AASA,SAAS,QAAQ,OAAe,OAA+B;CAG7D,OAAO;EACL,IAAI,eAFW,MAAM,QAAQ,eAAe,EAAE,KAAK,MAAM,MAAM,EAAE,CAAA,CAAE,KAAI,MAAK,EAAE,WAAW,CAAC,CAAC,CAAA,CAAE,KAAK,EAAE;EAGpG,MAAM;EACN;EACA,OAAO;EACP;EACA,WAAW;CACb;AACF;AAGO,MAAM,YAA4B;CACvC,MAAM;CACN,MAAM;CACN,cAAc;CACd,kBAAkB;CAClB,YAAY,CAAC,UAAU,QAAQ;CAC/B,MAAM;EAEJ,EACE,MAAM,aAAa,MAAM,EAAE,CAAA,CAAE,IAAI,aAAa,EAChD;EAEA,EACE,MAAM,YAAY,MAAM,EAAE,CAAA,CAAE,IAAI,aAAa,EAC/C;EAEA,EACE,MAAM;GACJ;IACE,IAAI;IACJ,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;GACb;GACA,GAAG,UAAU,MAAM,EAAE,CAAA,CAAE,IAAI,aAAa;GACxC;IACE,IAAI;IACJ,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;GACb;EACF,EACF;EAEA,EACE,MAAM;GACJ;IAAE,IAAI;IAAiB,MAAM;IAAO,OAAO;IAAO,OAAO;IAAK,WAAW;IAAc,MAAM,EAAE,YAAY,SAAS;GAAE;GACtH,QAAQ,KAAK,EAAG;GAChB,QAAQ,KAAK,EAAG;GAChB,QAAQ,KAAK,EAAG;GAChB,QAAQ,QAAQ,GAAG;GACnB,QAAQ,OAAO,GAAG;GAClB;IAAE,IAAI;IAAS,MAAM;IAAS,OAAO;IAAI,OAAO;IAAK,OAAO;IAAK,WAAW;GAAY;GACxF;IAAE,IAAI;IAAU,MAAM;IAAQ,OAAO;IAAM,OAAO;IAAK,WAAW;GAAW;EAC/E,EACF;CACF;AACF"}
1
+ {"version":3,"file":"url.js","names":[],"sources":["../../src/layouts/url.ts"],"sourcesContent":["/**\r\n * URL/链接键盘布局\r\n * @module layouts/url\r\n */\r\n\r\n// 导入键盘配置和按键定义的类型\r\nimport type { KeyboardConfig, KeyDefinition } from '../types'\r\n// 导入删除和Shift图标资源\r\nimport { ICON_DELETE, ICON_SHIFT } from '../icons'\r\n\r\n/**\r\n * 创建字符按键(支持大小写)\r\n * @param char - 字符,用于生成大小写标签和值\r\n * @returns 返回一个按键定义对象\r\n */\r\nfunction createCharKey(char: string): KeyDefinition {\r\n return {\r\n id: `url-char-${char.toLowerCase()}`, // 按键唯一标识,格式为 url-char-x\r\n type: 'char', // 按键类型为字符键\r\n label: { lower: char.toLowerCase(), upper: char.toUpperCase() }, // 显示标签:小写/大写\r\n value: { lower: char.toLowerCase(), upper: char.toUpperCase() }, // 输出值:小写/大写\r\n }\r\n}\r\n\r\n/**\r\n * 创建快捷片段按键\r\n * 用于URL键盘中常用的符号和域名后缀\r\n * @param label - 按键显示文本\r\n * @param width - 可选,按键宽度倍数\r\n * @returns 返回一个片段按键定义对象\r\n */\r\nfunction snippet(label: string, width?: number): KeyDefinition {\r\n // 生成唯一 ID:用 label 的字符编码(去除非法字符后拼接)\r\n const idSuffix =\r\n label.replace(/[^a-z0-9]/gi, '') ||\r\n label\r\n .split('')\r\n .map(c => c.charCodeAt(0))\r\n .join('')\r\n return {\r\n id: `url-snippet-${idSuffix}`, // 按键唯一标识,格式为 url-snippet-xxx\r\n type: 'char', // 按键类型为字符键\r\n label, // 显示文本\r\n value: label, // 输出值与显示文本相同\r\n width, // 按键宽度倍数\r\n className: 'key-snippet', // 自定义CSS类名,用于样式控制\r\n }\r\n}\r\n\r\n// 导出URL键盘布局配置\r\nexport const urlLayout: KeyboardConfig = {\r\n type: 'url', // 布局类型标识为 url\r\n name: '网址键盘', // 布局显示名称\r\n supportShift: true, // 支持Shift切换大小写\r\n defaultUpperCase: false, // 默认为小写状态\r\n switchable: ['symbol', 'number'], // 可切换到符号键盘和数字键盘\r\n rows: [\r\n // QWERTY 第一行:q w e r t y u i o p\r\n {\r\n keys: 'qwertyuiop'.split('').map(createCharKey), // 将字符串拆分为字符数组,逐个创建按键\r\n },\r\n // QWERTY 第二行:a s d f g h j k l\r\n {\r\n keys: 'asdfghjkl'.split('').map(createCharKey), // 将字符串拆分为字符数组,逐个创建按键\r\n },\r\n // QWERTY 第三行 + Shift + 退格\r\n {\r\n keys: [\r\n {\r\n id: 'shift', // Shift键标识\r\n type: 'shift', // 按键类型为Shift\r\n icon: ICON_SHIFT, // 使用Shift图标\r\n label: '', // 无文字标签,仅显示图标\r\n width: 1.5, // 宽度为1.5倍\r\n className: 'key-shift', // CSS类名\r\n },\r\n ...'zxcvbnm'.split('').map(createCharKey), // 展开第三行字母 z x c v b n m 的按键定义\r\n {\r\n id: 'backspace', // 退格键标识\r\n type: 'backspace', // 按键类型为退格\r\n icon: ICON_DELETE, // 使用删除图标\r\n label: '', // 无文字标签,仅显示图标\r\n width: 1.5, // 宽度为1.5倍\r\n className: 'key-backspace', // CSS类名\r\n },\r\n ],\r\n },\r\n // 底部行:切换 + 符号 + 域名后缀 + 前往\r\n {\r\n keys: [\r\n {\r\n id: 'switch-number',\r\n type: 'tab',\r\n label: '123',\r\n width: 1.2,\r\n className: 'key-switch',\r\n data: { targetType: 'number' },\r\n }, // 切换到数字键盘\r\n snippet('/', 0.8), // 斜杠快捷键,宽度0.8倍\r\n snippet('.', 0.8), // 点号快捷键,宽度0.8倍\r\n snippet('-', 0.8), // 横杠快捷键,宽度0.8倍\r\n snippet('.com', 1.5), // .com域名后缀快捷键,宽度1.5倍\r\n snippet('.cn', 1.2), // .cn域名后缀快捷键,宽度1.2倍\r\n {\r\n id: 'space',\r\n type: 'space',\r\n label: '',\r\n value: ' ',\r\n width: 1.5,\r\n className: 'key-space',\r\n }, // 空格键,宽度1.5倍\r\n {\r\n id: 'url-go',\r\n type: 'done',\r\n label: '前往',\r\n width: 1.5,\r\n className: 'key-done',\r\n }, // 前往/完成按钮,宽度1.5倍\r\n ],\r\n },\r\n ],\r\n}\r\n"],"mappings":";;;;;;;;;;;AAeA,SAAS,cAAc,MAA6B;CAClD,OAAO;EACL,IAAI,YAAY,KAAK,YAAY;EACjC,MAAM;EACN,OAAO;GAAE,OAAO,KAAK,YAAY;GAAG,OAAO,KAAK,YAAY;EAAE;EAC9D,OAAO;GAAE,OAAO,KAAK,YAAY;GAAG,OAAO,KAAK,YAAY;EAAE;CAChE;AACF;AASA,SAAS,QAAQ,OAAe,OAA+B;CAQ7D,OAAO;EACL,IAAI,eANJ,MAAM,QAAQ,eAAe,EAAE,KAC/B,MACG,MAAM,EAAE,CAAA,CACR,KAAI,MAAK,EAAE,WAAW,CAAC,CAAC,CAAA,CACxB,KAAK,EAAE;EAGV,MAAM;EACN;EACA,OAAO;EACP;EACA,WAAW;CACb;AACF;AAGO,MAAM,YAA4B;CACvC,MAAM;CACN,MAAM;CACN,cAAc;CACd,kBAAkB;CAClB,YAAY,CAAC,UAAU,QAAQ;CAC/B,MAAM;EAEJ,EACE,MAAM,aAAa,MAAM,EAAE,CAAA,CAAE,IAAI,aAAa,EAChD;EAEA,EACE,MAAM,YAAY,MAAM,EAAE,CAAA,CAAE,IAAI,aAAa,EAC/C;EAEA,EACE,MAAM;GACJ;IACE,IAAI;IACJ,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;GACb;GACA,GAAG,UAAU,MAAM,EAAE,CAAA,CAAE,IAAI,aAAa;GACxC;IACE,IAAI;IACJ,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;GACb;EACF,EACF;EAEA,EACE,MAAM;GACJ;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;IACX,MAAM,EAAE,YAAY,SAAS;GAC/B;GACA,QAAQ,KAAK,EAAG;GAChB,QAAQ,KAAK,EAAG;GAChB,QAAQ,KAAK,EAAG;GAChB,QAAQ,QAAQ,GAAG;GACnB,QAAQ,OAAO,GAAG;GAClB;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,WAAW;GACb;GACA;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;GACb;EACF,EACF;CACF;AACF"}
@@ -2,7 +2,7 @@
2
2
  * ***********************************
3
3
  * @composy/keyboard-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:33:29 *
5
+ * Build time: 2024-10-12 17:29:15 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
@@ -1 +1 @@
1
- {"version":3,"file":"verifycode.js","names":[],"sources":["../../src/layouts/verifycode.ts"],"sourcesContent":["/**\n * 验证码键盘布局\n * @module layouts/verifycode\n */\n\n// 从类型定义文件中导入 KeyboardConfig(键盘配置)和 KeyDefinition(按键定义)类型\nimport type { KeyboardConfig, KeyDefinition } from '../types'\n// 从图标模块中导入删除键图标和清除键图标\nimport { ICON_DELETE, ICON_CLEAR } from '../icons'\n\n/**\n * 创建数字按键\n * @param num - 数字字符串(如 '0'-'9')\n * @returns 返回一个按键定义对象\n */\nfunction createNumberKey(num: string): KeyDefinition {\n return {\n id: `verify-${num}`, // 按键唯一标识符,格式为 verify-数字\n type: 'char', // 按键类型为字符键\n label: num, // 按键上显示的文本\n value: num, // 按键按下后输出的值\n className: 'key-num', // 按键的 CSS 类名,用于样式定制\n }\n}\n\n/**\n * 验证码键盘配置 - 4x4布局(与其他数字键盘一致)\n * 布局结构:\n * 第1行: 1 2 3 [退格]\n * 第2行: 4 5 6 [清除]\n * 第3行: 7 8 9 [关闭]\n * 第4行: [空] 0 [确定(占2格)]\n */\nexport const verifycodeLayout: KeyboardConfig = {\n type: 'verifycode', // 键盘类型标识\n name: '验证码键盘', // 键盘的显示名称\n supportShift: false, // 不支持 Shift 切换(纯数字键盘无需切换)\n rows: [ // 键盘的行数组\n // ---- 第1行 ----\n {\n className: 'numpad-row', // 行的 CSS 类名\n keys: [ // 该行包含的按键数组\n createNumberKey('1'), // 数字键 1\n createNumberKey('2'), // 数字键 2\n createNumberKey('3'), // 数字键 3\n {\n id: 'backspace', // 退格键的唯一标识\n type: 'backspace', // 按键类型为退格,删除最后一个字符\n icon: ICON_DELETE, // 使用删除图标作为显示内容\n label: '', // 无文本标签(由图标替代)\n className: 'key-numpad-fn', // 功能键的 CSS 类名\n },\n ],\n },\n // ---- 第2行 ----\n {\n className: 'numpad-row', // 行的 CSS 类名\n keys: [\n createNumberKey('4'), // 数字键 4\n createNumberKey('5'), // 数字键 5\n createNumberKey('6'), // 数字键 6\n {\n id: 'clear', // 清除键的唯一标识\n type: 'clear', // 按键类型为清除,清空所有输入\n icon: ICON_CLEAR, // 使用清除图标作为显示内容\n label: '', // 无文本标签\n className: 'key-numpad-fn', // 功能键的 CSS 类名\n },\n ],\n },\n // ---- 第3行 ----\n {\n className: 'numpad-row', // 行的 CSS 类名\n keys: [\n createNumberKey('7'), // 数字键 7\n createNumberKey('8'), // 数字键 8\n createNumberKey('9'), // 数字键 9\n {\n id: 'close', // 关闭键的唯一标识\n type: 'close', // 按键类型为关闭,收起键盘\n label: '关闭', // 按钮上显示的文本\n className: 'key-numpad-fn', // 功能键的 CSS 类名\n },\n ],\n },\n // ---- 第4行 ----\n {\n className: 'numpad-row', // 行的 CSS 类名\n keys: [\n {\n id: 'empty', // 占位空键的唯一标识\n type: 'char', // 类型为字符键(但被禁用)\n label: '', // 无显示文本\n value: '', // 无输出值\n disabled: true, // 禁用状态,不可点击\n className: 'key-numpad-empty', // 空占位键的 CSS 类名\n },\n createNumberKey('0'), // 数字键 0\n {\n id: 'done', // 确定键的唯一标识\n type: 'done', // 按键类型为确定,完成输入\n label: '确定', // 按钮上显示的文本\n width: 2, // 占据 2 个键的宽度\n className: 'key-numpad-done', // 确定键的 CSS 类名\n },\n ],\n },\n ],\n data: { // 键盘的附加数据\n maxLength: 6, // 验证码最大输入长度为 6 位\n inputType: 'verifycode', // 输入类型标识,用于外部判断\n },\n}\n"],"mappings":";;;;;;;;;;;AAeA,SAAS,gBAAgB,KAA4B;CACnD,OAAO;EACL,IAAI,UAAU;EACd,MAAM;EACN,OAAO;EACP,OAAO;EACP,WAAW;CACb;AACF;AAUO,MAAM,mBAAmC;CAC9C,MAAM;CACN,MAAM;CACN,cAAc;CACd,MAAM;EAEJ;GACE,WAAW;GACX,MAAM;IACJ,gBAAgB,GAAG;IACnB,gBAAgB,GAAG;IACnB,gBAAgB,GAAG;IACnB;KACE,IAAI;KACJ,MAAM;KACN,MAAM;KACN,OAAO;KACP,WAAW;IACb;GACF;EACF;EAEA;GACE,WAAW;GACX,MAAM;IACJ,gBAAgB,GAAG;IACnB,gBAAgB,GAAG;IACnB,gBAAgB,GAAG;IACnB;KACE,IAAI;KACJ,MAAM;KACN,MAAM;KACN,OAAO;KACP,WAAW;IACb;GACF;EACF;EAEA;GACE,WAAW;GACX,MAAM;IACJ,gBAAgB,GAAG;IACnB,gBAAgB,GAAG;IACnB,gBAAgB,GAAG;IACnB;KACE,IAAI;KACJ,MAAM;KACN,OAAO;KACP,WAAW;IACb;GACF;EACF;EAEA;GACE,WAAW;GACX,MAAM;IACJ;KACE,IAAI;KACJ,MAAM;KACN,OAAO;KACP,OAAO;KACP,UAAU;KACV,WAAW;IACb;IACA,gBAAgB,GAAG;IACnB;KACE,IAAI;KACJ,MAAM;KACN,OAAO;KACP,OAAO;KACP,WAAW;IACb;GACF;EACF;CACF;CACA,MAAM;EACJ,WAAW;EACX,WAAW;CACb;AACF"}
1
+ {"version":3,"file":"verifycode.js","names":[],"sources":["../../src/layouts/verifycode.ts"],"sourcesContent":["/**\r\n * 验证码键盘布局\r\n * @module layouts/verifycode\r\n */\r\n\r\n// 从类型定义文件中导入 KeyboardConfig(键盘配置)和 KeyDefinition(按键定义)类型\r\nimport type { KeyboardConfig, KeyDefinition } from '../types'\r\n// 从图标模块中导入删除键图标和清除键图标\r\nimport { ICON_CLEAR, ICON_DELETE } from '../icons'\r\n\r\n/**\r\n * 创建数字按键\r\n * @param num - 数字字符串(如 '0'-'9')\r\n * @returns 返回一个按键定义对象\r\n */\r\nfunction createNumberKey(num: string): KeyDefinition {\r\n return {\r\n id: `verify-${num}`, // 按键唯一标识符,格式为 verify-数字\r\n type: 'char', // 按键类型为字符键\r\n label: num, // 按键上显示的文本\r\n value: num, // 按键按下后输出的值\r\n className: 'key-num', // 按键的 CSS 类名,用于样式定制\r\n }\r\n}\r\n\r\n/**\r\n * 验证码键盘配置 - 4x4布局(与其他数字键盘一致)\r\n * 布局结构:\r\n * 第1行: 1 2 3 [退格]\r\n * 第2行: 4 5 6 [清除]\r\n * 第3行: 7 8 9 [关闭]\r\n * 第4行: [空] 0 [确定(占2格)]\r\n */\r\nexport const verifycodeLayout: KeyboardConfig = {\r\n type: 'verifycode', // 键盘类型标识\r\n name: '验证码键盘', // 键盘的显示名称\r\n supportShift: false, // 不支持 Shift 切换(纯数字键盘无需切换)\r\n rows: [\r\n // 键盘的行数组\r\n // ---- 第1行 ----\r\n {\r\n className: 'numpad-row', // 行的 CSS 类名\r\n keys: [\r\n // 该行包含的按键数组\r\n createNumberKey('1'), // 数字键 1\r\n createNumberKey('2'), // 数字键 2\r\n createNumberKey('3'), // 数字键 3\r\n {\r\n id: 'backspace', // 退格键的唯一标识\r\n type: 'backspace', // 按键类型为退格,删除最后一个字符\r\n icon: ICON_DELETE, // 使用删除图标作为显示内容\r\n label: '', // 无文本标签(由图标替代)\r\n className: 'key-numpad-fn', // 功能键的 CSS 类名\r\n },\r\n ],\r\n },\r\n // ---- 第2行 ----\r\n {\r\n className: 'numpad-row', // 行的 CSS 类名\r\n keys: [\r\n createNumberKey('4'), // 数字键 4\r\n createNumberKey('5'), // 数字键 5\r\n createNumberKey('6'), // 数字键 6\r\n {\r\n id: 'clear', // 清除键的唯一标识\r\n type: 'clear', // 按键类型为清除,清空所有输入\r\n icon: ICON_CLEAR, // 使用清除图标作为显示内容\r\n label: '', // 无文本标签\r\n className: 'key-numpad-fn', // 功能键的 CSS 类名\r\n },\r\n ],\r\n },\r\n // ---- 第3行 ----\r\n {\r\n className: 'numpad-row', // 行的 CSS 类名\r\n keys: [\r\n createNumberKey('7'), // 数字键 7\r\n createNumberKey('8'), // 数字键 8\r\n createNumberKey('9'), // 数字键 9\r\n {\r\n id: 'close', // 关闭键的唯一标识\r\n type: 'close', // 按键类型为关闭,收起键盘\r\n label: '关闭', // 按钮上显示的文本\r\n className: 'key-numpad-fn', // 功能键的 CSS 类名\r\n },\r\n ],\r\n },\r\n // ---- 第4行 ----\r\n {\r\n className: 'numpad-row', // 行的 CSS 类名\r\n keys: [\r\n {\r\n id: 'empty', // 占位空键的唯一标识\r\n type: 'char', // 类型为字符键(但被禁用)\r\n label: '', // 无显示文本\r\n value: '', // 无输出值\r\n disabled: true, // 禁用状态,不可点击\r\n className: 'key-numpad-empty', // 空占位键的 CSS 类名\r\n },\r\n createNumberKey('0'), // 数字键 0\r\n {\r\n id: 'done', // 确定键的唯一标识\r\n type: 'done', // 按键类型为确定,完成输入\r\n label: '确定', // 按钮上显示的文本\r\n width: 2, // 占据 2 个键的宽度\r\n className: 'key-numpad-done', // 确定键的 CSS 类名\r\n },\r\n ],\r\n },\r\n ],\r\n data: {\r\n // 键盘的附加数据\r\n maxLength: 6, // 验证码最大输入长度为 6 位\r\n inputType: 'verifycode', // 输入类型标识,用于外部判断\r\n },\r\n}\r\n"],"mappings":";;;;;;;;;;;AAeA,SAAS,gBAAgB,KAA4B;CACnD,OAAO;EACL,IAAI,UAAU;EACd,MAAM;EACN,OAAO;EACP,OAAO;EACP,WAAW;CACb;AACF;AAUO,MAAM,mBAAmC;CAC9C,MAAM;CACN,MAAM;CACN,cAAc;CACd,MAAM;EAGJ;GACE,WAAW;GACX,MAAM;IAEJ,gBAAgB,GAAG;IACnB,gBAAgB,GAAG;IACnB,gBAAgB,GAAG;IACnB;KACE,IAAI;KACJ,MAAM;KACN,MAAM;KACN,OAAO;KACP,WAAW;IACb;GACF;EACF;EAEA;GACE,WAAW;GACX,MAAM;IACJ,gBAAgB,GAAG;IACnB,gBAAgB,GAAG;IACnB,gBAAgB,GAAG;IACnB;KACE,IAAI;KACJ,MAAM;KACN,MAAM;KACN,OAAO;KACP,WAAW;IACb;GACF;EACF;EAEA;GACE,WAAW;GACX,MAAM;IACJ,gBAAgB,GAAG;IACnB,gBAAgB,GAAG;IACnB,gBAAgB,GAAG;IACnB;KACE,IAAI;KACJ,MAAM;KACN,OAAO;KACP,WAAW;IACb;GACF;EACF;EAEA;GACE,WAAW;GACX,MAAM;IACJ;KACE,IAAI;KACJ,MAAM;KACN,OAAO;KACP,OAAO;KACP,UAAU;KACV,WAAW;IACb;IACA,gBAAgB,GAAG;IACnB;KACE,IAAI;KACJ,MAAM;KACN,OAAO;KACP,OAAO;KACP,WAAW;IACb;GACF;EACF;CACF;CACA,MAAM;EAEJ,WAAW;EACX,WAAW;CACb;AACF"}
@@ -2,7 +2,7 @@
2
2
  * ***********************************
3
3
  * @composy/keyboard-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:33:29 *
5
+ * Build time: 2024-10-12 17:29:15 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
@@ -2,15 +2,15 @@
2
2
  * ***********************************
3
3
  * @composy/keyboard-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:33:29 *
5
+ * Build time: 2024-10-12 17:29:15 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
9
9
  */
10
10
  import { getLayout } from "../layouts/index.js";
11
- import { EventEmitter } from "../utils/event-emitter.js";
12
11
  import { isMobile, vibrate } from "../utils/device.js";
13
12
  import { deleteCharBeforeCursor, getInputCursorPosition, insertTextAtCursor, setInputCursorPosition } from "../utils/dom.js";
13
+ import { EventEmitter } from "../utils/event-emitter.js";
14
14
  //#region src/managers/keyboard-manager.ts
15
15
  const DEFAULT_OPTIONS = {
16
16
  type: "qwerty",
@@ -22,14 +22,28 @@ const DEFAULT_OPTIONS = {
22
22
  enableVibrate: true,
23
23
  customLayouts: {}
24
24
  };
25
+ function normalizeMaxLength(value) {
26
+ if (value === void 0 || !Number.isFinite(value)) return void 0;
27
+ return Math.max(0, Math.floor(value));
28
+ }
29
+ function clampValue(value, maxLength) {
30
+ return maxLength === void 0 ? value : value.slice(0, maxLength);
31
+ }
25
32
  var KeyboardManager = class extends EventEmitter {
26
33
  constructor(options = {}) {
27
34
  super();
28
35
  /** 当前布局配置 */
29
36
  this.currentLayout = null;
37
+ this.destroyed = false;
38
+ const maxLength = normalizeMaxLength(options.maxLength);
30
39
  this.options = {
31
40
  ...DEFAULT_OPTIONS,
32
- ...options
41
+ ...options,
42
+ maxLength,
43
+ customLayouts: {
44
+ ...DEFAULT_OPTIONS.customLayouts,
45
+ ...options.customLayouts ?? {}
46
+ }
33
47
  };
34
48
  if (options.customLayouts) Object.entries(options.customLayouts).forEach(([name, layout]) => {
35
49
  this.options.customLayouts[name] = layout;
@@ -38,8 +52,8 @@ var KeyboardManager = class extends EventEmitter {
38
52
  visible: false,
39
53
  type: this.options.type,
40
54
  isUpperCase: this.options.defaultUpperCase,
41
- value: this.options.value,
42
- cursorPosition: this.options.value.length,
55
+ value: clampValue(this.options.value, this.options.maxLength),
56
+ cursorPosition: clampValue(this.options.value, this.options.maxLength).length,
43
57
  maxLength: this.options.maxLength,
44
58
  inputElement: null
45
59
  };
@@ -61,7 +75,10 @@ var KeyboardManager = class extends EventEmitter {
61
75
  * 获取配置选项
62
76
  */
63
77
  getOptions() {
64
- return { ...this.options };
78
+ return {
79
+ ...this.options,
80
+ customLayouts: { ...this.options.customLayouts }
81
+ };
65
82
  }
66
83
  /**
67
84
  * 加载键盘布局
@@ -81,7 +98,11 @@ var KeyboardManager = class extends EventEmitter {
81
98
  * 显示键盘
82
99
  */
83
100
  show(inputElement) {
84
- if (this.state.visible) return;
101
+ if (this.destroyed) return;
102
+ if (this.state.visible) {
103
+ if (inputElement && this.state.inputElement !== inputElement) this.bindInput(inputElement);
104
+ return;
105
+ }
85
106
  this.state.visible = true;
86
107
  this.state.inputElement = inputElement ?? null;
87
108
  if (inputElement) {
@@ -95,6 +116,7 @@ var KeyboardManager = class extends EventEmitter {
95
116
  * 隐藏键盘
96
117
  */
97
118
  hide() {
119
+ if (this.destroyed) return;
98
120
  if (!this.state.visible) return;
99
121
  const prevType = this.state.type;
100
122
  this.state.visible = false;
@@ -106,6 +128,7 @@ var KeyboardManager = class extends EventEmitter {
106
128
  * 切换键盘显示/隐藏
107
129
  */
108
130
  toggle(inputElement) {
131
+ if (this.destroyed) return;
109
132
  if (this.state.visible) this.hide();
110
133
  else this.show(inputElement);
111
134
  }
@@ -113,6 +136,7 @@ var KeyboardManager = class extends EventEmitter {
113
136
  * 切换键盘类型
114
137
  */
115
138
  switchType(type) {
139
+ if (this.destroyed) return;
116
140
  if (this.state.type === type) return;
117
141
  const fromType = this.state.type;
118
142
  if (!this.loadLayout(type)) return;
@@ -127,6 +151,7 @@ var KeyboardManager = class extends EventEmitter {
127
151
  * 切换大小写
128
152
  */
129
153
  toggleShift() {
154
+ if (this.destroyed) return;
130
155
  if (!this.currentLayout?.supportShift) return;
131
156
  this.state.isUpperCase = !this.state.isUpperCase;
132
157
  this.emitStateChange();
@@ -136,6 +161,7 @@ var KeyboardManager = class extends EventEmitter {
136
161
  * 设置大小写状态
137
162
  */
138
163
  setShift(isUpperCase) {
164
+ if (this.destroyed) return;
139
165
  if (!this.currentLayout?.supportShift) return;
140
166
  if (this.state.isUpperCase === isUpperCase) return;
141
167
  this.state.isUpperCase = isUpperCase;
@@ -146,6 +172,7 @@ var KeyboardManager = class extends EventEmitter {
146
172
  * 处理按键
147
173
  */
148
174
  handleKey(key) {
175
+ if (this.destroyed) return;
149
176
  if (this.options.enableVibrate && isMobile()) vibrate(10);
150
177
  this.emit("keypress", {
151
178
  key,
@@ -191,12 +218,15 @@ var KeyboardManager = class extends EventEmitter {
191
218
  setInputCursorPosition(input, result.cursorPosition);
192
219
  this.state.value = result.value;
193
220
  this.state.cursorPosition = result.cursorPosition;
194
- input.dispatchEvent(new Event("input", { bubbles: true }));
221
+ this.dispatchInputEvent(input);
195
222
  } else {
196
- if (this.state.maxLength && this.state.value.length >= this.state.maxLength) return;
197
- const newValue = this.state.value.slice(0, this.state.cursorPosition) + keyValue + this.state.value.slice(this.state.cursorPosition);
223
+ if (this.state.maxLength !== void 0 && this.state.value.length >= this.state.maxLength) return;
224
+ const availableLength = this.state.maxLength === void 0 ? keyValue.length : this.state.maxLength - this.state.value.length;
225
+ const valueToInsert = keyValue.slice(0, Math.max(0, availableLength));
226
+ if (!valueToInsert) return;
227
+ const newValue = this.state.value.slice(0, this.state.cursorPosition) + valueToInsert + this.state.value.slice(this.state.cursorPosition);
198
228
  this.state.value = newValue;
199
- this.state.cursorPosition += keyValue.length;
229
+ this.state.cursorPosition += valueToInsert.length;
200
230
  }
201
231
  this.emitStateChange();
202
232
  this.emit("input", {
@@ -216,7 +246,7 @@ var KeyboardManager = class extends EventEmitter {
216
246
  setInputCursorPosition(input, result.cursorPosition);
217
247
  this.state.value = result.value;
218
248
  this.state.cursorPosition = result.cursorPosition;
219
- input.dispatchEvent(new Event("input", { bubbles: true }));
249
+ this.dispatchInputEvent(input);
220
250
  this.emitStateChange();
221
251
  this.emit("backspace", {
222
252
  deletedChar: result.deletedChar,
@@ -255,7 +285,7 @@ var KeyboardManager = class extends EventEmitter {
255
285
  const previousValue = this.state.value;
256
286
  if (this.state.inputElement) {
257
287
  this.state.inputElement.value = "";
258
- this.state.inputElement.dispatchEvent(new Event("input", { bubbles: true }));
288
+ this.dispatchInputEvent(this.state.inputElement);
259
289
  }
260
290
  this.state.value = "";
261
291
  this.state.cursorPosition = 0;
@@ -297,11 +327,14 @@ var KeyboardManager = class extends EventEmitter {
297
327
  * 设置值
298
328
  */
299
329
  setValue(value) {
300
- this.state.value = value;
301
- this.state.cursorPosition = value.length;
330
+ if (this.destroyed) return;
331
+ const nextValue = clampValue(value, this.state.maxLength);
332
+ this.state.value = nextValue;
333
+ this.state.cursorPosition = nextValue.length;
302
334
  if (this.state.inputElement) {
303
- this.state.inputElement.value = value;
304
- setInputCursorPosition(this.state.inputElement, value.length);
335
+ this.state.inputElement.value = nextValue;
336
+ setInputCursorPosition(this.state.inputElement, nextValue.length);
337
+ this.dispatchInputEvent(this.state.inputElement);
305
338
  }
306
339
  this.emitStateChange();
307
340
  this.autoSwitchLicensePlate();
@@ -310,6 +343,7 @@ var KeyboardManager = class extends EventEmitter {
310
343
  * 追加值(在光标位置插入文本)
311
344
  */
312
345
  appendValue(text) {
346
+ if (this.destroyed) return;
313
347
  if (!text) return;
314
348
  const input = this.state.inputElement;
315
349
  if (input) {
@@ -318,9 +352,10 @@ var KeyboardManager = class extends EventEmitter {
318
352
  setInputCursorPosition(input, result.cursorPosition);
319
353
  this.state.value = result.value;
320
354
  this.state.cursorPosition = result.cursorPosition;
321
- input.dispatchEvent(new Event("input", { bubbles: true }));
355
+ this.dispatchInputEvent(input);
322
356
  } else {
323
- if (this.state.maxLength && this.state.value.length + text.length > this.state.maxLength) text = text.slice(0, this.state.maxLength - this.state.value.length);
357
+ if (this.state.maxLength !== void 0) text = text.slice(0, Math.max(0, this.state.maxLength - this.state.value.length));
358
+ if (!text) return;
324
359
  const newValue = this.state.value.slice(0, this.state.cursorPosition) + text + this.state.value.slice(this.state.cursorPosition);
325
360
  this.state.value = newValue;
326
361
  this.state.cursorPosition += text.length;
@@ -331,22 +366,38 @@ var KeyboardManager = class extends EventEmitter {
331
366
  * 设置最大长度
332
367
  */
333
368
  setMaxLength(maxLength) {
334
- this.state.maxLength = maxLength;
369
+ if (this.destroyed) return;
370
+ const normalizedMaxLength = normalizeMaxLength(maxLength);
371
+ this.state.maxLength = normalizedMaxLength;
372
+ const nextValue = clampValue(this.state.value, normalizedMaxLength);
373
+ const changed = nextValue !== this.state.value;
374
+ this.state.value = nextValue;
375
+ this.state.cursorPosition = Math.min(this.state.cursorPosition, nextValue.length);
376
+ if (this.state.inputElement && this.state.inputElement.value !== nextValue) {
377
+ this.state.inputElement.value = nextValue;
378
+ setInputCursorPosition(this.state.inputElement, this.state.cursorPosition);
379
+ this.dispatchInputEvent(this.state.inputElement);
380
+ }
335
381
  this.emitStateChange();
382
+ if (changed) this.autoSwitchLicensePlate();
336
383
  }
337
384
  /**
338
385
  * 绑定输入框
339
386
  */
340
387
  bindInput(input) {
388
+ if (this.destroyed) return;
341
389
  this.state.inputElement = input;
342
- this.state.value = input.value;
343
- this.state.cursorPosition = getInputCursorPosition(input);
390
+ const nextValue = clampValue(input.value, this.state.maxLength);
391
+ if (input.value !== nextValue) input.value = nextValue;
392
+ this.state.value = nextValue;
393
+ this.state.cursorPosition = Math.min(getInputCursorPosition(input), nextValue.length);
344
394
  this.emitStateChange();
345
395
  }
346
396
  /**
347
397
  * 解绑输入框
348
398
  */
349
399
  unbindInput() {
400
+ if (this.destroyed) return;
350
401
  this.state.inputElement = null;
351
402
  this.emitStateChange();
352
403
  }
@@ -356,13 +407,19 @@ var KeyboardManager = class extends EventEmitter {
356
407
  emitStateChange() {
357
408
  this.emit("stateChange", { ...this.state });
358
409
  }
410
+ dispatchInputEvent(input) {
411
+ const EventConstructor = input.ownerDocument.defaultView?.Event ?? Event;
412
+ input.dispatchEvent(new EventConstructor("input", { bubbles: true }));
413
+ }
359
414
  /**
360
415
  * 销毁
361
416
  */
362
417
  destroy() {
418
+ if (this.destroyed) return;
363
419
  this.hide();
364
420
  this.clear();
365
421
  this.state.inputElement = null;
422
+ this.destroyed = true;
366
423
  }
367
424
  };
368
425
  function createKeyboardManager(options) {
@@ -1 +1 @@
1
- {"version":3,"file":"keyboard-manager.js","names":[],"sources":["../../src/managers/keyboard-manager.ts"],"sourcesContent":["/**\n * 键盘管理器\n * @module managers/keyboard-manager\n */\n\nimport type {\n KeyboardConfig,\n KeyboardEventMap,\n KeyboardOptions,\n KeyboardState,\n KeyboardType,\n KeyDefinition,\n} from '../types'\nimport { getLayout } from '../layouts'\nimport { EventEmitter } from '../utils/event-emitter'\nimport { isMobile, vibrate } from '../utils/device'\nimport {\n deleteCharBeforeCursor,\n getInputCursorPosition,\n insertTextAtCursor,\n setInputCursorPosition,\n} from '../utils/dom'\n\n/**\n * 默认键盘选项\n */\nconst DEFAULT_OPTIONS: Required<KeyboardOptions> = {\n type: 'qwerty',\n value: '',\n maxLength: undefined as unknown as number,\n defaultUpperCase: false,\n closeOnClickOutside: true,\n enableSound: false,\n enableVibrate: true,\n customLayouts: {},\n}\n\n/**\n * 键盘管理器类\n * 处理键盘状态管理、输入处理等核心逻辑\n */\nexport class KeyboardManager extends EventEmitter<KeyboardEventMap> {\n /** 配置选项 */\n private options: Required<KeyboardOptions>\n\n /** 当前状态 */\n private state: KeyboardState\n\n /** 当前布局配置 */\n private currentLayout: KeyboardConfig | null = null\n\n constructor(options: KeyboardOptions = {}) {\n super()\n this.options = { ...DEFAULT_OPTIONS, ...options }\n\n // 注册自定义布局\n if (options.customLayouts) {\n Object.entries(options.customLayouts).forEach(([name, layout]) => {\n // 这里不用 registerLayout 以避免覆盖内置布局的警告\n this.options.customLayouts[name] = layout\n })\n }\n\n // 初始化状态\n this.state = {\n visible: false,\n type: this.options.type,\n isUpperCase: this.options.defaultUpperCase,\n value: this.options.value,\n cursorPosition: this.options.value.length,\n maxLength: this.options.maxLength,\n inputElement: null,\n }\n\n // 加载初始布局\n this.loadLayout(this.options.type)\n }\n\n /**\n * 获取当前状态\n */\n getState(): Readonly<KeyboardState> {\n return { ...this.state }\n }\n\n /**\n * 获取当前布局配置\n */\n getLayout(): KeyboardConfig | null {\n return this.currentLayout\n }\n\n /**\n * 获取配置选项\n */\n getOptions(): Readonly<Required<KeyboardOptions>> {\n return { ...this.options }\n }\n\n /**\n * 加载键盘布局\n */\n private loadLayout(type: KeyboardType | string): boolean {\n // 先从自定义布局查找\n let layout = this.options.customLayouts[type]\n\n // 再从内置布局查找\n if (!layout) {\n layout = getLayout(type) as KeyboardConfig\n }\n\n if (!layout) {\n console.error(`[KeyboardManager] Layout \"${type}\" not found`)\n return false\n }\n\n this.currentLayout = layout\n\n // 更新大小写状态\n if (layout.supportShift) {\n this.state.isUpperCase = layout.defaultUpperCase ?? this.options.defaultUpperCase\n }\n\n return true\n }\n\n /**\n * 显示键盘\n */\n show(inputElement?: HTMLInputElement | HTMLTextAreaElement): void {\n if (this.state.visible) return\n\n this.state.visible = true\n this.state.inputElement = inputElement ?? null\n\n // 同步输入框的值\n if (inputElement) {\n this.state.value = inputElement.value\n this.state.cursorPosition = getInputCursorPosition(inputElement)\n }\n\n this.emitStateChange()\n this.emit('show', { type: this.state.type })\n }\n\n /**\n * 隐藏键盘\n */\n hide(): void {\n if (!this.state.visible) return\n\n const prevType = this.state.type\n this.state.visible = false\n this.state.inputElement = null\n\n this.emitStateChange()\n this.emit('hide', { type: prevType })\n }\n\n /**\n * 切换键盘显示/隐藏\n */\n toggle(inputElement?: HTMLInputElement | HTMLTextAreaElement): void {\n if (this.state.visible) {\n this.hide()\n }\n else {\n this.show(inputElement)\n }\n }\n\n /**\n * 切换键盘类型\n */\n switchType(type: KeyboardType | string): void {\n if (this.state.type === type) return\n\n const fromType = this.state.type\n if (!this.loadLayout(type)) return\n\n this.state.type = type as KeyboardType\n\n this.emitStateChange()\n this.emit('switch', { from: fromType, to: type as KeyboardType })\n }\n\n /**\n * 切换大小写\n */\n toggleShift(): void {\n if (!this.currentLayout?.supportShift) return\n\n this.state.isUpperCase = !this.state.isUpperCase\n this.emitStateChange()\n this.emit('shift', { isUpperCase: this.state.isUpperCase })\n }\n\n /**\n * 设置大小写状态\n */\n setShift(isUpperCase: boolean): void {\n if (!this.currentLayout?.supportShift) return\n if (this.state.isUpperCase === isUpperCase) return\n\n this.state.isUpperCase = isUpperCase\n this.emitStateChange()\n this.emit('shift', { isUpperCase })\n }\n\n /**\n * 处理按键\n */\n handleKey(key: KeyDefinition): void {\n // 触发震动反馈\n if (this.options.enableVibrate && isMobile()) {\n vibrate(10)\n }\n\n this.emit('keypress', { key, value: this.state.value })\n\n switch (key.type) {\n case 'char':\n case 'space':\n this.handleCharKey(key)\n break\n case 'backspace':\n this.handleBackspace()\n break\n case 'shift':\n this.toggleShift()\n break\n case 'clear':\n this.handleClear()\n break\n case 'enter':\n case 'done':\n this.handleConfirm()\n break\n case 'close':\n this.hide()\n break\n case 'tab':\n this.handleTab(key)\n break\n case 'custom':\n // 自定义按键,只触发事件\n break\n }\n }\n\n /**\n * 处理字符输入\n */\n private handleCharKey(key: KeyDefinition): void {\n const keyValue = this.getKeyValue(key)\n if (!keyValue) return\n\n const input = this.state.inputElement\n\n if (input) {\n // 如果有绑定输入框,直接操作输入框\n const result = insertTextAtCursor(input, keyValue, this.state.maxLength)\n input.value = result.value\n setInputCursorPosition(input, result.cursorPosition)\n this.state.value = result.value\n this.state.cursorPosition = result.cursorPosition\n\n // 触发原生 input 事件\n input.dispatchEvent(new Event('input', { bubbles: true }))\n }\n else {\n // 没有输入框,直接修改内部值\n if (this.state.maxLength && this.state.value.length >= this.state.maxLength) {\n return\n }\n const newValue = this.state.value.slice(0, this.state.cursorPosition)\n + keyValue\n + this.state.value.slice(this.state.cursorPosition)\n this.state.value = newValue\n this.state.cursorPosition += keyValue.length\n }\n\n this.emitStateChange()\n this.emit('input', { value: this.state.value, key })\n\n // 车牌号智能切换\n this.autoSwitchLicensePlate()\n }\n\n /**\n * 处理退格\n */\n private handleBackspace(): void {\n const input = this.state.inputElement\n\n if (input) {\n const result = deleteCharBeforeCursor(input)\n input.value = result.value\n setInputCursorPosition(input, result.cursorPosition)\n this.state.value = result.value\n this.state.cursorPosition = result.cursorPosition\n\n // 触发原生 input 事件\n input.dispatchEvent(new Event('input', { bubbles: true }))\n\n this.emitStateChange()\n this.emit('backspace', { deletedChar: result.deletedChar, value: this.state.value })\n }\n else {\n if (this.state.cursorPosition === 0) return\n\n const deletedChar = this.state.value.charAt(this.state.cursorPosition - 1)\n this.state.value = this.state.value.slice(0, this.state.cursorPosition - 1)\n + this.state.value.slice(this.state.cursorPosition)\n this.state.cursorPosition--\n\n this.emitStateChange()\n this.emit('backspace', { deletedChar, value: this.state.value })\n }\n\n // 车牌号智能切换\n this.autoSwitchLicensePlate()\n }\n\n /**\n * 车牌号智能切换逻辑\n * 根据当前值长度自动切换键盘布局\n * 只有 2 种布局:省份键盘(第1位)和 字母+数字混合键盘(第2-8位)\n */\n private autoSwitchLicensePlate(): void {\n // 只在车牌键盘类型时生效\n if (!this.state.type.startsWith('license-plate')) return\n\n const len = this.state.value.length\n let targetType: string | null = null\n\n if (len === 0) {\n // 第1位:省份简称\n targetType = 'license-plate-province'\n }\n else {\n // 第2-8位:字母+数字混合键盘\n // (第2位虽然只能输入字母,但显示混合键盘,用户自己知道不能输入数字)\n targetType = 'license-plate-alphanumeric'\n }\n\n // 如果需要切换\n if (targetType && this.state.type !== targetType) {\n this.switchType(targetType)\n }\n }\n\n /**\n * 处理清空\n */\n private handleClear(): void {\n const previousValue = this.state.value\n\n if (this.state.inputElement) {\n this.state.inputElement.value = ''\n this.state.inputElement.dispatchEvent(new Event('input', { bubbles: true }))\n }\n\n this.state.value = ''\n this.state.cursorPosition = 0\n\n this.emitStateChange()\n this.emit('clear', { previousValue })\n \n // 车牌号智能切换\n this.autoSwitchLicensePlate()\n }\n\n /**\n * 处理确认\n */\n private handleConfirm(): void {\n this.emit('confirm', { value: this.state.value })\n this.hide()\n }\n\n /**\n * 处理切换键盘\n */\n private handleTab(key: KeyDefinition): void {\n const targetType = key.data?.targetType as KeyboardType | string | undefined\n if (targetType) {\n this.switchType(targetType)\n }\n }\n\n /**\n * 获取按键的实际输出值\n */\n private getKeyValue(key: KeyDefinition): string {\n const value = key.value ?? key.label\n\n if (typeof value === 'string') {\n return value\n }\n\n return this.state.isUpperCase ? value.upper : value.lower\n }\n\n /**\n * 获取按键的显示文本\n */\n getKeyLabel(key: KeyDefinition): string {\n const label = key.label\n\n if (typeof label === 'string') {\n return label\n }\n\n return this.state.isUpperCase ? label.upper : label.lower\n }\n\n /**\n * 设置值\n */\n setValue(value: string): void {\n this.state.value = value\n this.state.cursorPosition = value.length\n\n if (this.state.inputElement) {\n this.state.inputElement.value = value\n setInputCursorPosition(this.state.inputElement, value.length)\n }\n\n this.emitStateChange()\n \n // 车牌号智能切换\n this.autoSwitchLicensePlate()\n }\n\n /**\n * 追加值(在光标位置插入文本)\n */\n appendValue(text: string): void {\n if (!text) return\n\n const input = this.state.inputElement\n\n if (input) {\n const result = insertTextAtCursor(input, text, this.state.maxLength)\n input.value = result.value\n setInputCursorPosition(input, result.cursorPosition)\n this.state.value = result.value\n this.state.cursorPosition = result.cursorPosition\n\n // 触发原生 input 事件\n input.dispatchEvent(new Event('input', { bubbles: true }))\n }\n else {\n if (this.state.maxLength && this.state.value.length + text.length > this.state.maxLength) {\n text = text.slice(0, this.state.maxLength - this.state.value.length)\n }\n const newValue = this.state.value.slice(0, this.state.cursorPosition)\n + text\n + this.state.value.slice(this.state.cursorPosition)\n this.state.value = newValue\n this.state.cursorPosition += text.length\n }\n\n this.emitStateChange()\n }\n\n /**\n * 设置最大长度\n */\n setMaxLength(maxLength?: number): void {\n this.state.maxLength = maxLength\n this.emitStateChange()\n }\n\n /**\n * 绑定输入框\n */\n bindInput(input: HTMLInputElement | HTMLTextAreaElement): void {\n this.state.inputElement = input\n this.state.value = input.value\n this.state.cursorPosition = getInputCursorPosition(input)\n this.emitStateChange()\n }\n\n /**\n * 解绑输入框\n */\n unbindInput(): void {\n this.state.inputElement = null\n this.emitStateChange()\n }\n\n /**\n * 发送状态变化事件\n */\n private emitStateChange(): void {\n this.emit('stateChange', { ...this.state })\n }\n\n /**\n * 销毁\n */\n destroy(): void {\n this.hide()\n this.clear()\n this.state.inputElement = null\n }\n}\n\n/**\n * 创建键盘管理器实例\n */\nexport function createKeyboardManager(options?: KeyboardOptions): KeyboardManager {\n return new KeyboardManager(options)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"keyboard-manager.js","names":[],"sources":["../../src/managers/keyboard-manager.ts"],"sourcesContent":["/**\r\n * 键盘管理器\r\n * @module managers/keyboard-manager\r\n */\r\n\r\nimport type {\r\n KeyboardConfig,\r\n KeyboardEventMap,\r\n KeyboardOptions,\r\n KeyboardState,\r\n KeyboardType,\r\n KeyDefinition,\r\n} from '../types'\r\nimport { getLayout } from '../layouts'\r\nimport { isMobile, vibrate } from '../utils/device'\r\nimport {\r\n deleteCharBeforeCursor,\r\n getInputCursorPosition,\r\n insertTextAtCursor,\r\n setInputCursorPosition,\r\n} from '../utils/dom'\r\nimport { EventEmitter } from '../utils/event-emitter'\r\n\r\n/**\r\n * 默认键盘选项\r\n */\r\nconst DEFAULT_OPTIONS: Required<KeyboardOptions> = {\r\n type: 'qwerty',\r\n value: '',\r\n maxLength: undefined as unknown as number,\r\n defaultUpperCase: false,\r\n closeOnClickOutside: true,\r\n enableSound: false,\r\n enableVibrate: true,\r\n customLayouts: {},\r\n}\r\n\r\nfunction normalizeMaxLength(value: number | undefined): number | undefined {\r\n if (value === undefined || !Number.isFinite(value)) return undefined\r\n return Math.max(0, Math.floor(value))\r\n}\r\n\r\nfunction clampValue(value: string, maxLength: number | undefined): string {\r\n return maxLength === undefined ? value : value.slice(0, maxLength)\r\n}\r\n\r\n/**\r\n * 键盘管理器类\r\n * 处理键盘状态管理、输入处理等核心逻辑\r\n */\r\nexport class KeyboardManager extends EventEmitter<KeyboardEventMap> {\r\n /** 配置选项 */\r\n private options: Required<KeyboardOptions>\r\n\r\n /** 当前状态 */\r\n private state: KeyboardState\r\n\r\n /** 当前布局配置 */\r\n private currentLayout: KeyboardConfig | null = null\r\n\r\n private destroyed = false\r\n\r\n constructor(options: KeyboardOptions = {}) {\r\n super()\r\n const maxLength = normalizeMaxLength(options.maxLength)\r\n this.options = {\r\n ...DEFAULT_OPTIONS,\r\n ...options,\r\n maxLength,\r\n customLayouts: {\r\n ...DEFAULT_OPTIONS.customLayouts,\r\n ...(options.customLayouts ?? {}),\r\n },\r\n }\r\n\r\n // 注册自定义布局\r\n if (options.customLayouts) {\r\n Object.entries(options.customLayouts).forEach(([name, layout]) => {\r\n // 这里不用 registerLayout 以避免覆盖内置布局的警告\r\n this.options.customLayouts[name] = layout\r\n })\r\n }\r\n\r\n // 初始化状态\r\n this.state = {\r\n visible: false,\r\n type: this.options.type,\r\n isUpperCase: this.options.defaultUpperCase,\r\n value: clampValue(this.options.value, this.options.maxLength),\r\n cursorPosition: clampValue(this.options.value, this.options.maxLength)\r\n .length,\r\n maxLength: this.options.maxLength,\r\n inputElement: null,\r\n }\r\n\r\n // 加载初始布局\r\n this.loadLayout(this.options.type)\r\n }\r\n\r\n /**\r\n * 获取当前状态\r\n */\r\n getState(): Readonly<KeyboardState> {\r\n return { ...this.state }\r\n }\r\n\r\n /**\r\n * 获取当前布局配置\r\n */\r\n getLayout(): KeyboardConfig | null {\r\n return this.currentLayout\r\n }\r\n\r\n /**\r\n * 获取配置选项\r\n */\r\n getOptions(): Readonly<Required<KeyboardOptions>> {\r\n return { ...this.options, customLayouts: { ...this.options.customLayouts } }\r\n }\r\n\r\n /**\r\n * 加载键盘布局\r\n */\r\n private loadLayout(type: KeyboardType | string): boolean {\r\n // 先从自定义布局查找\r\n let layout = this.options.customLayouts[type]\r\n\r\n // 再从内置布局查找\r\n if (!layout) {\r\n layout = getLayout(type) as KeyboardConfig\r\n }\r\n\r\n if (!layout) {\r\n console.error(`[KeyboardManager] Layout \"${type}\" not found`)\r\n return false\r\n }\r\n\r\n this.currentLayout = layout\r\n\r\n // 更新大小写状态\r\n if (layout.supportShift) {\r\n this.state.isUpperCase =\r\n layout.defaultUpperCase ?? this.options.defaultUpperCase\r\n }\r\n\r\n return true\r\n }\r\n\r\n /**\r\n * 显示键盘\r\n */\r\n show(inputElement?: HTMLInputElement | HTMLTextAreaElement): void {\r\n if (this.destroyed) return\r\n if (this.state.visible) {\r\n if (inputElement && this.state.inputElement !== inputElement) {\r\n this.bindInput(inputElement)\r\n }\r\n return\r\n }\r\n\r\n this.state.visible = true\r\n this.state.inputElement = inputElement ?? null\r\n\r\n // 同步输入框的值\r\n if (inputElement) {\r\n this.state.value = inputElement.value\r\n this.state.cursorPosition = getInputCursorPosition(inputElement)\r\n }\r\n\r\n this.emitStateChange()\r\n this.emit('show', { type: this.state.type })\r\n }\r\n\r\n /**\r\n * 隐藏键盘\r\n */\r\n hide(): void {\r\n if (this.destroyed) return\r\n if (!this.state.visible) return\r\n\r\n const prevType = this.state.type\r\n this.state.visible = false\r\n this.state.inputElement = null\r\n\r\n this.emitStateChange()\r\n this.emit('hide', { type: prevType })\r\n }\r\n\r\n /**\r\n * 切换键盘显示/隐藏\r\n */\r\n toggle(inputElement?: HTMLInputElement | HTMLTextAreaElement): void {\r\n if (this.destroyed) return\r\n if (this.state.visible) {\r\n this.hide()\r\n } else {\r\n this.show(inputElement)\r\n }\r\n }\r\n\r\n /**\r\n * 切换键盘类型\r\n */\r\n switchType(type: KeyboardType | string): void {\r\n if (this.destroyed) return\r\n if (this.state.type === type) return\r\n\r\n const fromType = this.state.type\r\n if (!this.loadLayout(type)) return\r\n\r\n this.state.type = type as KeyboardType\r\n\r\n this.emitStateChange()\r\n this.emit('switch', { from: fromType, to: type as KeyboardType })\r\n }\r\n\r\n /**\r\n * 切换大小写\r\n */\r\n toggleShift(): void {\r\n if (this.destroyed) return\r\n if (!this.currentLayout?.supportShift) return\r\n\r\n this.state.isUpperCase = !this.state.isUpperCase\r\n this.emitStateChange()\r\n this.emit('shift', { isUpperCase: this.state.isUpperCase })\r\n }\r\n\r\n /**\r\n * 设置大小写状态\r\n */\r\n setShift(isUpperCase: boolean): void {\r\n if (this.destroyed) return\r\n if (!this.currentLayout?.supportShift) return\r\n if (this.state.isUpperCase === isUpperCase) return\r\n\r\n this.state.isUpperCase = isUpperCase\r\n this.emitStateChange()\r\n this.emit('shift', { isUpperCase })\r\n }\r\n\r\n /**\r\n * 处理按键\r\n */\r\n handleKey(key: KeyDefinition): void {\r\n if (this.destroyed) return\r\n // 触发震动反馈\r\n if (this.options.enableVibrate && isMobile()) {\r\n vibrate(10)\r\n }\r\n\r\n this.emit('keypress', { key, value: this.state.value })\r\n\r\n switch (key.type) {\r\n case 'char':\r\n case 'space':\r\n this.handleCharKey(key)\r\n break\r\n case 'backspace':\r\n this.handleBackspace()\r\n break\r\n case 'shift':\r\n this.toggleShift()\r\n break\r\n case 'clear':\r\n this.handleClear()\r\n break\r\n case 'enter':\r\n case 'done':\r\n this.handleConfirm()\r\n break\r\n case 'close':\r\n this.hide()\r\n break\r\n case 'tab':\r\n this.handleTab(key)\r\n break\r\n case 'custom':\r\n // 自定义按键,只触发事件\r\n break\r\n }\r\n }\r\n\r\n /**\r\n * 处理字符输入\r\n */\r\n private handleCharKey(key: KeyDefinition): void {\r\n const keyValue = this.getKeyValue(key)\r\n if (!keyValue) return\r\n\r\n const input = this.state.inputElement\r\n\r\n if (input) {\r\n // 如果有绑定输入框,直接操作输入框\r\n const result = insertTextAtCursor(input, keyValue, this.state.maxLength)\r\n input.value = result.value\r\n setInputCursorPosition(input, result.cursorPosition)\r\n this.state.value = result.value\r\n this.state.cursorPosition = result.cursorPosition\r\n\r\n // 触发原生 input 事件\r\n this.dispatchInputEvent(input)\r\n } else {\r\n // 没有输入框,直接修改内部值\r\n if (\r\n this.state.maxLength !== undefined &&\r\n this.state.value.length >= this.state.maxLength\r\n ) {\r\n return\r\n }\r\n const availableLength =\r\n this.state.maxLength === undefined\r\n ? keyValue.length\r\n : this.state.maxLength - this.state.value.length\r\n const valueToInsert = keyValue.slice(0, Math.max(0, availableLength))\r\n if (!valueToInsert) return\r\n const newValue =\r\n this.state.value.slice(0, this.state.cursorPosition) +\r\n valueToInsert +\r\n this.state.value.slice(this.state.cursorPosition)\r\n this.state.value = newValue\r\n this.state.cursorPosition += valueToInsert.length\r\n }\r\n\r\n this.emitStateChange()\r\n this.emit('input', { value: this.state.value, key })\r\n\r\n // 车牌号智能切换\r\n this.autoSwitchLicensePlate()\r\n }\r\n\r\n /**\r\n * 处理退格\r\n */\r\n private handleBackspace(): void {\r\n const input = this.state.inputElement\r\n\r\n if (input) {\r\n const result = deleteCharBeforeCursor(input)\r\n input.value = result.value\r\n setInputCursorPosition(input, result.cursorPosition)\r\n this.state.value = result.value\r\n this.state.cursorPosition = result.cursorPosition\r\n\r\n // 触发原生 input 事件\r\n this.dispatchInputEvent(input)\r\n\r\n this.emitStateChange()\r\n this.emit('backspace', {\r\n deletedChar: result.deletedChar,\r\n value: this.state.value,\r\n })\r\n } else {\r\n if (this.state.cursorPosition === 0) return\r\n\r\n const deletedChar = this.state.value.charAt(this.state.cursorPosition - 1)\r\n this.state.value =\r\n this.state.value.slice(0, this.state.cursorPosition - 1) +\r\n this.state.value.slice(this.state.cursorPosition)\r\n this.state.cursorPosition--\r\n\r\n this.emitStateChange()\r\n this.emit('backspace', { deletedChar, value: this.state.value })\r\n }\r\n\r\n // 车牌号智能切换\r\n this.autoSwitchLicensePlate()\r\n }\r\n\r\n /**\r\n * 车牌号智能切换逻辑\r\n * 根据当前值长度自动切换键盘布局\r\n * 只有 2 种布局:省份键盘(第1位)和 字母+数字混合键盘(第2-8位)\r\n */\r\n private autoSwitchLicensePlate(): void {\r\n // 只在车牌键盘类型时生效\r\n if (!this.state.type.startsWith('license-plate')) return\r\n\r\n const len = this.state.value.length\r\n let targetType: string | null = null\r\n\r\n if (len === 0) {\r\n // 第1位:省份简称\r\n targetType = 'license-plate-province'\r\n } else {\r\n // 第2-8位:字母+数字混合键盘\r\n // (第2位虽然只能输入字母,但显示混合键盘,用户自己知道不能输入数字)\r\n targetType = 'license-plate-alphanumeric'\r\n }\r\n\r\n // 如果需要切换\r\n if (targetType && this.state.type !== targetType) {\r\n this.switchType(targetType)\r\n }\r\n }\r\n\r\n /**\r\n * 处理清空\r\n */\r\n private handleClear(): void {\r\n const previousValue = this.state.value\r\n\r\n if (this.state.inputElement) {\r\n this.state.inputElement.value = ''\r\n this.dispatchInputEvent(this.state.inputElement)\r\n }\r\n\r\n this.state.value = ''\r\n this.state.cursorPosition = 0\r\n\r\n this.emitStateChange()\r\n this.emit('clear', { previousValue })\r\n\r\n // 车牌号智能切换\r\n this.autoSwitchLicensePlate()\r\n }\r\n\r\n /**\r\n * 处理确认\r\n */\r\n private handleConfirm(): void {\r\n this.emit('confirm', { value: this.state.value })\r\n this.hide()\r\n }\r\n\r\n /**\r\n * 处理切换键盘\r\n */\r\n private handleTab(key: KeyDefinition): void {\r\n const targetType = key.data?.targetType as KeyboardType | string | undefined\r\n if (targetType) {\r\n this.switchType(targetType)\r\n }\r\n }\r\n\r\n /**\r\n * 获取按键的实际输出值\r\n */\r\n private getKeyValue(key: KeyDefinition): string {\r\n const value = key.value ?? key.label\r\n\r\n if (typeof value === 'string') {\r\n return value\r\n }\r\n\r\n return this.state.isUpperCase ? value.upper : value.lower\r\n }\r\n\r\n /**\r\n * 获取按键的显示文本\r\n */\r\n getKeyLabel(key: KeyDefinition): string {\r\n const label = key.label\r\n\r\n if (typeof label === 'string') {\r\n return label\r\n }\r\n\r\n return this.state.isUpperCase ? label.upper : label.lower\r\n }\r\n\r\n /**\r\n * 设置值\r\n */\r\n setValue(value: string): void {\r\n if (this.destroyed) return\r\n const nextValue = clampValue(value, this.state.maxLength)\r\n this.state.value = nextValue\r\n this.state.cursorPosition = nextValue.length\r\n\r\n if (this.state.inputElement) {\r\n this.state.inputElement.value = nextValue\r\n setInputCursorPosition(this.state.inputElement, nextValue.length)\r\n this.dispatchInputEvent(this.state.inputElement)\r\n }\r\n\r\n this.emitStateChange()\r\n\r\n // 车牌号智能切换\r\n this.autoSwitchLicensePlate()\r\n }\r\n\r\n /**\r\n * 追加值(在光标位置插入文本)\r\n */\r\n appendValue(text: string): void {\r\n if (this.destroyed) return\r\n if (!text) return\r\n\r\n const input = this.state.inputElement\r\n\r\n if (input) {\r\n const result = insertTextAtCursor(input, text, this.state.maxLength)\r\n input.value = result.value\r\n setInputCursorPosition(input, result.cursorPosition)\r\n this.state.value = result.value\r\n this.state.cursorPosition = result.cursorPosition\r\n\r\n // 触发原生 input 事件\r\n this.dispatchInputEvent(input)\r\n } else {\r\n if (this.state.maxLength !== undefined) {\r\n text = text.slice(\r\n 0,\r\n Math.max(0, this.state.maxLength - this.state.value.length)\r\n )\r\n }\r\n if (!text) return\r\n const newValue =\r\n this.state.value.slice(0, this.state.cursorPosition) +\r\n text +\r\n this.state.value.slice(this.state.cursorPosition)\r\n this.state.value = newValue\r\n this.state.cursorPosition += text.length\r\n }\r\n\r\n this.emitStateChange()\r\n }\r\n\r\n /**\r\n * 设置最大长度\r\n */\r\n setMaxLength(maxLength?: number): void {\r\n if (this.destroyed) return\r\n const normalizedMaxLength = normalizeMaxLength(maxLength)\r\n this.state.maxLength = normalizedMaxLength\r\n const nextValue = clampValue(this.state.value, normalizedMaxLength)\r\n const changed = nextValue !== this.state.value\r\n this.state.value = nextValue\r\n this.state.cursorPosition = Math.min(\r\n this.state.cursorPosition,\r\n nextValue.length\r\n )\r\n if (\r\n this.state.inputElement &&\r\n this.state.inputElement.value !== nextValue\r\n ) {\r\n this.state.inputElement.value = nextValue\r\n setInputCursorPosition(this.state.inputElement, this.state.cursorPosition)\r\n this.dispatchInputEvent(this.state.inputElement)\r\n }\r\n this.emitStateChange()\r\n if (changed) this.autoSwitchLicensePlate()\r\n }\r\n\r\n /**\r\n * 绑定输入框\r\n */\r\n bindInput(input: HTMLInputElement | HTMLTextAreaElement): void {\r\n if (this.destroyed) return\r\n this.state.inputElement = input\r\n const nextValue = clampValue(input.value, this.state.maxLength)\r\n if (input.value !== nextValue) input.value = nextValue\r\n this.state.value = nextValue\r\n this.state.cursorPosition = Math.min(\r\n getInputCursorPosition(input),\r\n nextValue.length\r\n )\r\n this.emitStateChange()\r\n }\r\n\r\n /**\r\n * 解绑输入框\r\n */\r\n unbindInput(): void {\r\n if (this.destroyed) return\r\n this.state.inputElement = null\r\n this.emitStateChange()\r\n }\r\n\r\n /**\r\n * 发送状态变化事件\r\n */\r\n private emitStateChange(): void {\r\n this.emit('stateChange', { ...this.state })\r\n }\r\n\r\n private dispatchInputEvent(\r\n input: HTMLInputElement | HTMLTextAreaElement\r\n ): void {\r\n const EventConstructor = input.ownerDocument.defaultView?.Event ?? Event\r\n input.dispatchEvent(new EventConstructor('input', { bubbles: true }))\r\n }\r\n\r\n /**\r\n * 销毁\r\n */\r\n destroy(): void {\r\n if (this.destroyed) return\r\n this.hide()\r\n this.clear()\r\n this.state.inputElement = null\r\n this.destroyed = true\r\n }\r\n}\r\n\r\n/**\r\n * 创建键盘管理器实例\r\n */\r\nexport function createKeyboardManager(\r\n options?: KeyboardOptions\r\n): KeyboardManager {\r\n return new KeyboardManager(options)\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;AA0BA,MAAM,kBAA6C;CACjD,MAAM;CACN,OAAO;CACP,WAAW,KAAA;CACX,kBAAkB;CAClB,qBAAqB;CACrB,aAAa;CACb,eAAe;CACf,eAAe,CAAC;AAClB;AAEA,SAAS,mBAAmB,OAA+C;CACzE,IAAI,UAAU,KAAA,KAAa,CAAC,OAAO,SAAS,KAAK,GAAG,OAAO,KAAA;CAC3D,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,CAAC;AACtC;AAEA,SAAS,WAAW,OAAe,WAAuC;CACxE,OAAO,cAAc,KAAA,IAAY,QAAQ,MAAM,MAAM,GAAG,SAAS;AACnE;AAMO,IAAM,kBAAN,cAA8B,aAA+B;CAYlE,YAAY,UAA2B,CAAC,GAAG;EACzC,MAAM;;EALR,KAAQ,gBAAuC;EAE/C,KAAQ,YAAY;EAIlB,MAAM,YAAY,mBAAmB,QAAQ,SAAS;EACtD,KAAK,UAAU;GACb,GAAG;GACH,GAAG;GACH;GACA,eAAe;IACb,GAAG,gBAAgB;IACnB,GAAI,QAAQ,iBAAiB,CAAC;GAChC;EACF;EAGA,IAAI,QAAQ,eACV,OAAO,QAAQ,QAAQ,aAAa,CAAA,CAAE,SAAS,CAAC,MAAM,YAAY;GAEhE,KAAK,QAAQ,cAAc,QAAQ;EACrC,CAAC;EAIH,KAAK,QAAQ;GACX,SAAS;GACT,MAAM,KAAK,QAAQ;GACnB,aAAa,KAAK,QAAQ;GAC1B,OAAO,WAAW,KAAK,QAAQ,OAAO,KAAK,QAAQ,SAAS;GAC5D,gBAAgB,WAAW,KAAK,QAAQ,OAAO,KAAK,QAAQ,SAAS,CAAA,CAClE;GACH,WAAW,KAAK,QAAQ;GACxB,cAAc;EAChB;EAGA,KAAK,WAAW,KAAK,QAAQ,IAAI;CACnC;;;;CAKA,WAAoC;EAClC,OAAO,EAAE,GAAG,KAAK,MAAM;CACzB;;;;CAKA,YAAmC;EACjC,OAAO,KAAK;CACd;;;;CAKA,aAAkD;EAChD,OAAO;GAAE,GAAG,KAAK;GAAS,eAAe,EAAE,GAAG,KAAK,QAAQ,cAAc;EAAE;CAC7E;;;;CAKQ,WAAW,MAAsC;EAEvD,IAAI,SAAS,KAAK,QAAQ,cAAc;EAGxC,IAAI,CAAC,QACH,SAAS,UAAU,IAAI;EAGzB,IAAI,CAAC,QAAQ;GACX,QAAQ,MAAM,6BAA6B,KAAI,YAAa;GAC5D,OAAO;EACT;EAEA,KAAK,gBAAgB;EAGrB,IAAI,OAAO,cACT,KAAK,MAAM,cACT,OAAO,oBAAoB,KAAK,QAAQ;EAG5C,OAAO;CACT;;;;CAKA,KAAK,cAA6D;EAChE,IAAI,KAAK,WAAW;EACpB,IAAI,KAAK,MAAM,SAAS;GACtB,IAAI,gBAAgB,KAAK,MAAM,iBAAiB,cAC9C,KAAK,UAAU,YAAY;GAE7B;EACF;EAEA,KAAK,MAAM,UAAU;EACrB,KAAK,MAAM,eAAe,gBAAgB;EAG1C,IAAI,cAAc;GAChB,KAAK,MAAM,QAAQ,aAAa;GAChC,KAAK,MAAM,iBAAiB,uBAAuB,YAAY;EACjE;EAEA,KAAK,gBAAgB;EACrB,KAAK,KAAK,QAAQ,EAAE,MAAM,KAAK,MAAM,KAAK,CAAC;CAC7C;;;;CAKA,OAAa;EACX,IAAI,KAAK,WAAW;EACpB,IAAI,CAAC,KAAK,MAAM,SAAS;EAEzB,MAAM,WAAW,KAAK,MAAM;EAC5B,KAAK,MAAM,UAAU;EACrB,KAAK,MAAM,eAAe;EAE1B,KAAK,gBAAgB;EACrB,KAAK,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;CACtC;;;;CAKA,OAAO,cAA6D;EAClE,IAAI,KAAK,WAAW;EACpB,IAAI,KAAK,MAAM,SACb,KAAK,KAAK;OAEV,KAAK,KAAK,YAAY;CAE1B;;;;CAKA,WAAW,MAAmC;EAC5C,IAAI,KAAK,WAAW;EACpB,IAAI,KAAK,MAAM,SAAS,MAAM;EAE9B,MAAM,WAAW,KAAK,MAAM;EAC5B,IAAI,CAAC,KAAK,WAAW,IAAI,GAAG;EAE5B,KAAK,MAAM,OAAO;EAElB,KAAK,gBAAgB;EACrB,KAAK,KAAK,UAAU;GAAE,MAAM;GAAU,IAAI;EAAqB,CAAC;CAClE;;;;CAKA,cAAoB;EAClB,IAAI,KAAK,WAAW;EACpB,IAAI,CAAC,KAAK,eAAe,cAAc;EAEvC,KAAK,MAAM,cAAc,CAAC,KAAK,MAAM;EACrC,KAAK,gBAAgB;EACrB,KAAK,KAAK,SAAS,EAAE,aAAa,KAAK,MAAM,YAAY,CAAC;CAC5D;;;;CAKA,SAAS,aAA4B;EACnC,IAAI,KAAK,WAAW;EACpB,IAAI,CAAC,KAAK,eAAe,cAAc;EACvC,IAAI,KAAK,MAAM,gBAAgB,aAAa;EAE5C,KAAK,MAAM,cAAc;EACzB,KAAK,gBAAgB;EACrB,KAAK,KAAK,SAAS,EAAE,YAAY,CAAC;CACpC;;;;CAKA,UAAU,KAA0B;EAClC,IAAI,KAAK,WAAW;EAEpB,IAAI,KAAK,QAAQ,iBAAiB,SAAS,GACzC,QAAQ,EAAE;EAGZ,KAAK,KAAK,YAAY;GAAE;GAAK,OAAO,KAAK,MAAM;EAAM,CAAC;EAEtD,QAAQ,IAAI,MAAZ;GACE,KAAK;GACL,KAAK;IACH,KAAK,cAAc,GAAG;IACtB;GACF,KAAK;IACH,KAAK,gBAAgB;IACrB;GACF,KAAK;IACH,KAAK,YAAY;IACjB;GACF,KAAK;IACH,KAAK,YAAY;IACjB;GACF,KAAK;GACL,KAAK;IACH,KAAK,cAAc;IACnB;GACF,KAAK;IACH,KAAK,KAAK;IACV;GACF,KAAK;IACH,KAAK,UAAU,GAAG;IAClB;GACF,KAAK,UAEH;EACJ;CACF;;;;CAKQ,cAAc,KAA0B;EAC9C,MAAM,WAAW,KAAK,YAAY,GAAG;EACrC,IAAI,CAAC,UAAU;EAEf,MAAM,QAAQ,KAAK,MAAM;EAEzB,IAAI,OAAO;GAET,MAAM,SAAS,mBAAmB,OAAO,UAAU,KAAK,MAAM,SAAS;GACvE,MAAM,QAAQ,OAAO;GACrB,uBAAuB,OAAO,OAAO,cAAc;GACnD,KAAK,MAAM,QAAQ,OAAO;GAC1B,KAAK,MAAM,iBAAiB,OAAO;GAGnC,KAAK,mBAAmB,KAAK;EAC/B,OAAO;GAEL,IACE,KAAK,MAAM,cAAc,KAAA,KACzB,KAAK,MAAM,MAAM,UAAU,KAAK,MAAM,WAEtC;GAEF,MAAM,kBACJ,KAAK,MAAM,cAAc,KAAA,IACrB,SAAS,SACT,KAAK,MAAM,YAAY,KAAK,MAAM,MAAM;GAC9C,MAAM,gBAAgB,SAAS,MAAM,GAAG,KAAK,IAAI,GAAG,eAAe,CAAC;GACpE,IAAI,CAAC,eAAe;GACpB,MAAM,WACJ,KAAK,MAAM,MAAM,MAAM,GAAG,KAAK,MAAM,cAAc,IACnD,gBACA,KAAK,MAAM,MAAM,MAAM,KAAK,MAAM,cAAc;GAClD,KAAK,MAAM,QAAQ;GACnB,KAAK,MAAM,kBAAkB,cAAc;EAC7C;EAEA,KAAK,gBAAgB;EACrB,KAAK,KAAK,SAAS;GAAE,OAAO,KAAK,MAAM;GAAO;EAAI,CAAC;EAGnD,KAAK,uBAAuB;CAC9B;;;;CAKQ,kBAAwB;EAC9B,MAAM,QAAQ,KAAK,MAAM;EAEzB,IAAI,OAAO;GACT,MAAM,SAAS,uBAAuB,KAAK;GAC3C,MAAM,QAAQ,OAAO;GACrB,uBAAuB,OAAO,OAAO,cAAc;GACnD,KAAK,MAAM,QAAQ,OAAO;GAC1B,KAAK,MAAM,iBAAiB,OAAO;GAGnC,KAAK,mBAAmB,KAAK;GAE7B,KAAK,gBAAgB;GACrB,KAAK,KAAK,aAAa;IACrB,aAAa,OAAO;IACpB,OAAO,KAAK,MAAM;GACpB,CAAC;EACH,OAAO;GACL,IAAI,KAAK,MAAM,mBAAmB,GAAG;GAErC,MAAM,cAAc,KAAK,MAAM,MAAM,OAAO,KAAK,MAAM,iBAAiB,CAAC;GACzE,KAAK,MAAM,QACT,KAAK,MAAM,MAAM,MAAM,GAAG,KAAK,MAAM,iBAAiB,CAAC,IACvD,KAAK,MAAM,MAAM,MAAM,KAAK,MAAM,cAAc;GAClD,KAAK,MAAM;GAEX,KAAK,gBAAgB;GACrB,KAAK,KAAK,aAAa;IAAE;IAAa,OAAO,KAAK,MAAM;GAAM,CAAC;EACjE;EAGA,KAAK,uBAAuB;CAC9B;;;;;;CAOQ,yBAA+B;EAErC,IAAI,CAAC,KAAK,MAAM,KAAK,WAAW,eAAe,GAAG;EAElD,MAAM,MAAM,KAAK,MAAM,MAAM;EAC7B,IAAI,aAA4B;EAEhC,IAAI,QAAQ,GAEV,aAAa;OAIb,aAAa;EAIf,IAAI,cAAc,KAAK,MAAM,SAAS,YACpC,KAAK,WAAW,UAAU;CAE9B;;;;CAKQ,cAAoB;EAC1B,MAAM,gBAAgB,KAAK,MAAM;EAEjC,IAAI,KAAK,MAAM,cAAc;GAC3B,KAAK,MAAM,aAAa,QAAQ;GAChC,KAAK,mBAAmB,KAAK,MAAM,YAAY;EACjD;EAEA,KAAK,MAAM,QAAQ;EACnB,KAAK,MAAM,iBAAiB;EAE5B,KAAK,gBAAgB;EACrB,KAAK,KAAK,SAAS,EAAE,cAAc,CAAC;EAGpC,KAAK,uBAAuB;CAC9B;;;;CAKQ,gBAAsB;EAC5B,KAAK,KAAK,WAAW,EAAE,OAAO,KAAK,MAAM,MAAM,CAAC;EAChD,KAAK,KAAK;CACZ;;;;CAKQ,UAAU,KAA0B;EAC1C,MAAM,aAAa,IAAI,MAAM;EAC7B,IAAI,YACF,KAAK,WAAW,UAAU;CAE9B;;;;CAKQ,YAAY,KAA4B;EAC9C,MAAM,QAAQ,IAAI,SAAS,IAAI;EAE/B,IAAI,OAAO,UAAU,UACnB,OAAO;EAGT,OAAO,KAAK,MAAM,cAAc,MAAM,QAAQ,MAAM;CACtD;;;;CAKA,YAAY,KAA4B;EACtC,MAAM,QAAQ,IAAI;EAElB,IAAI,OAAO,UAAU,UACnB,OAAO;EAGT,OAAO,KAAK,MAAM,cAAc,MAAM,QAAQ,MAAM;CACtD;;;;CAKA,SAAS,OAAqB;EAC5B,IAAI,KAAK,WAAW;EACpB,MAAM,YAAY,WAAW,OAAO,KAAK,MAAM,SAAS;EACxD,KAAK,MAAM,QAAQ;EACnB,KAAK,MAAM,iBAAiB,UAAU;EAEtC,IAAI,KAAK,MAAM,cAAc;GAC3B,KAAK,MAAM,aAAa,QAAQ;GAChC,uBAAuB,KAAK,MAAM,cAAc,UAAU,MAAM;GAChE,KAAK,mBAAmB,KAAK,MAAM,YAAY;EACjD;EAEA,KAAK,gBAAgB;EAGrB,KAAK,uBAAuB;CAC9B;;;;CAKA,YAAY,MAAoB;EAC9B,IAAI,KAAK,WAAW;EACpB,IAAI,CAAC,MAAM;EAEX,MAAM,QAAQ,KAAK,MAAM;EAEzB,IAAI,OAAO;GACT,MAAM,SAAS,mBAAmB,OAAO,MAAM,KAAK,MAAM,SAAS;GACnE,MAAM,QAAQ,OAAO;GACrB,uBAAuB,OAAO,OAAO,cAAc;GACnD,KAAK,MAAM,QAAQ,OAAO;GAC1B,KAAK,MAAM,iBAAiB,OAAO;GAGnC,KAAK,mBAAmB,KAAK;EAC/B,OAAO;GACL,IAAI,KAAK,MAAM,cAAc,KAAA,GAC3B,OAAO,KAAK,MACV,GACA,KAAK,IAAI,GAAG,KAAK,MAAM,YAAY,KAAK,MAAM,MAAM,MAAM,CAC5D;GAEF,IAAI,CAAC,MAAM;GACX,MAAM,WACJ,KAAK,MAAM,MAAM,MAAM,GAAG,KAAK,MAAM,cAAc,IACnD,OACA,KAAK,MAAM,MAAM,MAAM,KAAK,MAAM,cAAc;GAClD,KAAK,MAAM,QAAQ;GACnB,KAAK,MAAM,kBAAkB,KAAK;EACpC;EAEA,KAAK,gBAAgB;CACvB;;;;CAKA,aAAa,WAA0B;EACrC,IAAI,KAAK,WAAW;EACpB,MAAM,sBAAsB,mBAAmB,SAAS;EACxD,KAAK,MAAM,YAAY;EACvB,MAAM,YAAY,WAAW,KAAK,MAAM,OAAO,mBAAmB;EAClE,MAAM,UAAU,cAAc,KAAK,MAAM;EACzC,KAAK,MAAM,QAAQ;EACnB,KAAK,MAAM,iBAAiB,KAAK,IAC/B,KAAK,MAAM,gBACX,UAAU,MACZ;EACA,IACE,KAAK,MAAM,gBACX,KAAK,MAAM,aAAa,UAAU,WAClC;GACA,KAAK,MAAM,aAAa,QAAQ;GAChC,uBAAuB,KAAK,MAAM,cAAc,KAAK,MAAM,cAAc;GACzE,KAAK,mBAAmB,KAAK,MAAM,YAAY;EACjD;EACA,KAAK,gBAAgB;EACrB,IAAI,SAAS,KAAK,uBAAuB;CAC3C;;;;CAKA,UAAU,OAAqD;EAC7D,IAAI,KAAK,WAAW;EACpB,KAAK,MAAM,eAAe;EAC1B,MAAM,YAAY,WAAW,MAAM,OAAO,KAAK,MAAM,SAAS;EAC9D,IAAI,MAAM,UAAU,WAAW,MAAM,QAAQ;EAC7C,KAAK,MAAM,QAAQ;EACnB,KAAK,MAAM,iBAAiB,KAAK,IAC/B,uBAAuB,KAAK,GAC5B,UAAU,MACZ;EACA,KAAK,gBAAgB;CACvB;;;;CAKA,cAAoB;EAClB,IAAI,KAAK,WAAW;EACpB,KAAK,MAAM,eAAe;EAC1B,KAAK,gBAAgB;CACvB;;;;CAKQ,kBAAwB;EAC9B,KAAK,KAAK,eAAe,EAAE,GAAG,KAAK,MAAM,CAAC;CAC5C;CAEQ,mBACN,OACM;EACN,MAAM,mBAAmB,MAAM,cAAc,aAAa,SAAS;EACnE,MAAM,cAAc,IAAI,iBAAiB,SAAS,EAAE,SAAS,KAAK,CAAC,CAAC;CACtE;;;;CAKA,UAAgB;EACd,IAAI,KAAK,WAAW;EACpB,KAAK,KAAK;EACV,KAAK,MAAM;EACX,KAAK,MAAM,eAAe;EAC1B,KAAK,YAAY;CACnB;AACF;AAKO,SAAS,sBACd,SACiB;CACjB,OAAO,IAAI,gBAAgB,OAAO;AACpC"}