@cloud-ru/ds-fields 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (314) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/LICENSE +201 -0
  3. package/README.md +888 -0
  4. package/dist/cjs/components/FieldColor/FieldColor.d.ts +48 -0
  5. package/dist/cjs/components/FieldColor/FieldColor.js +147 -0
  6. package/dist/cjs/components/FieldColor/index.d.ts +1 -0
  7. package/dist/cjs/components/FieldColor/index.js +17 -0
  8. package/dist/cjs/components/FieldColor/styles.module.css +79 -0
  9. package/dist/cjs/components/FieldColor/utils.d.ts +7 -0
  10. package/dist/cjs/components/FieldColor/utils.js +19 -0
  11. package/dist/cjs/components/FieldCombo/FieldCombo.d.ts +91 -0
  12. package/dist/cjs/components/FieldCombo/FieldCombo.js +200 -0
  13. package/dist/cjs/components/FieldCombo/index.d.ts +1 -0
  14. package/dist/cjs/components/FieldCombo/index.js +17 -0
  15. package/dist/cjs/components/FieldDate/FieldDate.d.ts +2 -0
  16. package/dist/cjs/components/FieldDate/FieldDate.js +369 -0
  17. package/dist/cjs/components/FieldDate/constants.d.ts +10 -0
  18. package/dist/cjs/components/FieldDate/constants.js +13 -0
  19. package/dist/cjs/components/FieldDate/index.d.ts +3 -0
  20. package/dist/cjs/components/FieldDate/index.js +19 -0
  21. package/dist/cjs/components/FieldDate/mask.d.ts +20 -0
  22. package/dist/cjs/components/FieldDate/mask.js +117 -0
  23. package/dist/cjs/components/FieldDate/styles.module.css +43 -0
  24. package/dist/cjs/components/FieldDate/types.d.ts +100 -0
  25. package/dist/cjs/components/FieldDate/types.js +2 -0
  26. package/dist/cjs/components/FieldDate/utils.d.ts +3 -0
  27. package/dist/cjs/components/FieldDate/utils.js +8 -0
  28. package/dist/cjs/components/FieldSecure/FieldSecure.d.ts +64 -0
  29. package/dist/cjs/components/FieldSecure/FieldSecure.js +158 -0
  30. package/dist/cjs/components/FieldSecure/index.d.ts +1 -0
  31. package/dist/cjs/components/FieldSecure/index.js +17 -0
  32. package/dist/cjs/components/FieldSelect/FieldSelect.d.ts +2 -0
  33. package/dist/cjs/components/FieldSelect/FieldSelect.js +360 -0
  34. package/dist/cjs/components/FieldSelect/constants.d.ts +4 -0
  35. package/dist/cjs/components/FieldSelect/constants.js +7 -0
  36. package/dist/cjs/components/FieldSelect/index.d.ts +3 -0
  37. package/dist/cjs/components/FieldSelect/index.js +19 -0
  38. package/dist/cjs/components/FieldSelect/styles.module.css +92 -0
  39. package/dist/cjs/components/FieldSelect/types.d.ts +197 -0
  40. package/dist/cjs/components/FieldSelect/types.js +2 -0
  41. package/dist/cjs/components/FieldSelect/utils.d.ts +19 -0
  42. package/dist/cjs/components/FieldSelect/utils.js +104 -0
  43. package/dist/cjs/components/FieldSlider/FieldSlider.d.ts +92 -0
  44. package/dist/cjs/components/FieldSlider/FieldSlider.js +196 -0
  45. package/dist/cjs/components/FieldSlider/index.d.ts +2 -0
  46. package/dist/cjs/components/FieldSlider/index.js +18 -0
  47. package/dist/cjs/components/FieldSlider/styles.module.css +44 -0
  48. package/dist/cjs/components/FieldSlider/types.d.ts +4 -0
  49. package/dist/cjs/components/FieldSlider/types.js +2 -0
  50. package/dist/cjs/components/FieldSlider/utils/generateAllowedValues.d.ts +1 -0
  51. package/dist/cjs/components/FieldSlider/utils/generateAllowedValues.js +16 -0
  52. package/dist/cjs/components/FieldSlider/utils/getClosestMark.d.ts +4 -0
  53. package/dist/cjs/components/FieldSlider/utils/getClosestMark.js +16 -0
  54. package/dist/cjs/components/FieldSlider/utils/getMarkLabel.d.ts +2 -0
  55. package/dist/cjs/components/FieldSlider/utils/getMarkLabel.js +7 -0
  56. package/dist/cjs/components/FieldSlider/utils/getTextFieldValue.d.ts +2 -0
  57. package/dist/cjs/components/FieldSlider/utils/getTextFieldValue.js +9 -0
  58. package/dist/cjs/components/FieldSlider/utils/index.d.ts +5 -0
  59. package/dist/cjs/components/FieldSlider/utils/index.js +21 -0
  60. package/dist/cjs/components/FieldSlider/utils/isMarkObject.d.ts +6 -0
  61. package/dist/cjs/components/FieldSlider/utils/isMarkObject.js +6 -0
  62. package/dist/cjs/components/FieldStepper/FieldStepper.d.ts +81 -0
  63. package/dist/cjs/components/FieldStepper/FieldStepper.js +160 -0
  64. package/dist/cjs/components/FieldStepper/index.d.ts +1 -0
  65. package/dist/cjs/components/FieldStepper/index.js +17 -0
  66. package/dist/cjs/components/FieldStepper/styles.module.css +78 -0
  67. package/dist/cjs/components/FieldStepper/utils.d.ts +14 -0
  68. package/dist/cjs/components/FieldStepper/utils.js +45 -0
  69. package/dist/cjs/components/FieldText/FieldText.d.ts +11 -0
  70. package/dist/cjs/components/FieldText/FieldText.js +14 -0
  71. package/dist/cjs/components/FieldText/index.d.ts +1 -0
  72. package/dist/cjs/components/FieldText/index.js +17 -0
  73. package/dist/cjs/components/FieldTextArea/FieldTextArea.d.ts +95 -0
  74. package/dist/cjs/components/FieldTextArea/FieldTextArea.js +114 -0
  75. package/dist/cjs/components/FieldTextArea/index.d.ts +1 -0
  76. package/dist/cjs/components/FieldTextArea/index.js +17 -0
  77. package/dist/cjs/components/FieldTextArea/styles.module.css +123 -0
  78. package/dist/cjs/components/FieldTime/FieldTime.d.ts +74 -0
  79. package/dist/cjs/components/FieldTime/FieldTime.js +167 -0
  80. package/dist/cjs/components/FieldTime/index.d.ts +2 -0
  81. package/dist/cjs/components/FieldTime/index.js +17 -0
  82. package/dist/cjs/components/FieldTime/mask.d.ts +3 -0
  83. package/dist/cjs/components/FieldTime/mask.js +24 -0
  84. package/dist/cjs/components/FieldTime/styles.module.css +3 -0
  85. package/dist/cjs/components/index.d.ts +14 -0
  86. package/dist/cjs/components/index.js +32 -0
  87. package/dist/cjs/components/shared/helperComponents/FieldElementButton/FieldElementButton.d.ts +35 -0
  88. package/dist/cjs/components/shared/helperComponents/FieldElementButton/FieldElementButton.js +47 -0
  89. package/dist/cjs/components/shared/helperComponents/FieldElementButton/FieldElementButtonList.d.ts +26 -0
  90. package/dist/cjs/components/shared/helperComponents/FieldElementButton/FieldElementButtonList.js +24 -0
  91. package/dist/cjs/components/shared/helperComponents/FieldElementButton/constants.d.ts +9 -0
  92. package/dist/cjs/components/shared/helperComponents/FieldElementButton/constants.js +12 -0
  93. package/dist/cjs/components/shared/helperComponents/FieldElementButton/index.d.ts +4 -0
  94. package/dist/cjs/components/shared/helperComponents/FieldElementButton/index.js +20 -0
  95. package/dist/cjs/components/shared/helperComponents/FieldElementButton/styles.module.css +204 -0
  96. package/dist/cjs/components/shared/helperComponents/FieldElementButton/types.d.ts +4 -0
  97. package/dist/cjs/components/shared/helperComponents/FieldElementButton/types.js +2 -0
  98. package/dist/cjs/components/shared/helperComponents/FieldShell/FieldShell.d.ts +43 -0
  99. package/dist/cjs/components/shared/helperComponents/FieldShell/FieldShell.js +22 -0
  100. package/dist/cjs/components/shared/helperComponents/FieldShell/index.d.ts +1 -0
  101. package/dist/cjs/components/shared/helperComponents/FieldShell/index.js +17 -0
  102. package/dist/cjs/components/shared/helperComponents/FieldShell/styles.module.css +11 -0
  103. package/dist/cjs/components/shared/hooks/useCopyButton.d.ts +20 -0
  104. package/dist/cjs/components/shared/hooks/useCopyButton.js +58 -0
  105. package/dist/cjs/components/shared/index.d.ts +4 -0
  106. package/dist/cjs/components/shared/index.js +20 -0
  107. package/dist/cjs/components/shared/styles.module.css +673 -0
  108. package/dist/cjs/components/shared/utils.d.ts +69 -0
  109. package/dist/cjs/components/shared/utils.js +104 -0
  110. package/dist/cjs/constants.d.ts +61 -0
  111. package/dist/cjs/constants.js +76 -0
  112. package/dist/cjs/hooks/index.d.ts +1 -0
  113. package/dist/cjs/hooks/index.js +17 -0
  114. package/dist/cjs/hooks/useAdaptiveAutoFocus.d.ts +7 -0
  115. package/dist/cjs/hooks/useAdaptiveAutoFocus.js +10 -0
  116. package/dist/cjs/index.d.ts +3 -0
  117. package/dist/cjs/index.js +19 -0
  118. package/dist/cjs/package.json +3 -0
  119. package/dist/cjs/segments/index.d.ts +2 -0
  120. package/dist/cjs/segments/index.js +18 -0
  121. package/dist/cjs/segments/segments.d.ts +22 -0
  122. package/dist/cjs/segments/segments.js +46 -0
  123. package/dist/cjs/segments/useSegmentedMask.d.ts +43 -0
  124. package/dist/cjs/segments/useSegmentedMask.js +282 -0
  125. package/dist/cjs/style.css +1350 -0
  126. package/dist/esm/components/FieldColor/FieldColor.d.ts +48 -0
  127. package/dist/esm/components/FieldColor/FieldColor.js +141 -0
  128. package/dist/esm/components/FieldColor/index.d.ts +1 -0
  129. package/dist/esm/components/FieldColor/index.js +1 -0
  130. package/dist/esm/components/FieldColor/styles.module.css +79 -0
  131. package/dist/esm/components/FieldColor/utils.d.ts +7 -0
  132. package/dist/esm/components/FieldColor/utils.js +16 -0
  133. package/dist/esm/components/FieldCombo/FieldCombo.d.ts +91 -0
  134. package/dist/esm/components/FieldCombo/FieldCombo.js +194 -0
  135. package/dist/esm/components/FieldCombo/index.d.ts +1 -0
  136. package/dist/esm/components/FieldCombo/index.js +1 -0
  137. package/dist/esm/components/FieldDate/FieldDate.d.ts +2 -0
  138. package/dist/esm/components/FieldDate/FieldDate.js +363 -0
  139. package/dist/esm/components/FieldDate/constants.d.ts +10 -0
  140. package/dist/esm/components/FieldDate/constants.js +10 -0
  141. package/dist/esm/components/FieldDate/index.d.ts +3 -0
  142. package/dist/esm/components/FieldDate/index.js +3 -0
  143. package/dist/esm/components/FieldDate/mask.d.ts +20 -0
  144. package/dist/esm/components/FieldDate/mask.js +111 -0
  145. package/dist/esm/components/FieldDate/styles.module.css +43 -0
  146. package/dist/esm/components/FieldDate/types.d.ts +100 -0
  147. package/dist/esm/components/FieldDate/types.js +1 -0
  148. package/dist/esm/components/FieldDate/utils.d.ts +3 -0
  149. package/dist/esm/components/FieldDate/utils.js +5 -0
  150. package/dist/esm/components/FieldSecure/FieldSecure.d.ts +64 -0
  151. package/dist/esm/components/FieldSecure/FieldSecure.js +152 -0
  152. package/dist/esm/components/FieldSecure/index.d.ts +1 -0
  153. package/dist/esm/components/FieldSecure/index.js +1 -0
  154. package/dist/esm/components/FieldSelect/FieldSelect.d.ts +2 -0
  155. package/dist/esm/components/FieldSelect/FieldSelect.js +354 -0
  156. package/dist/esm/components/FieldSelect/constants.d.ts +4 -0
  157. package/dist/esm/components/FieldSelect/constants.js +4 -0
  158. package/dist/esm/components/FieldSelect/index.d.ts +3 -0
  159. package/dist/esm/components/FieldSelect/index.js +3 -0
  160. package/dist/esm/components/FieldSelect/styles.module.css +92 -0
  161. package/dist/esm/components/FieldSelect/types.d.ts +197 -0
  162. package/dist/esm/components/FieldSelect/types.js +1 -0
  163. package/dist/esm/components/FieldSelect/utils.d.ts +19 -0
  164. package/dist/esm/components/FieldSelect/utils.js +93 -0
  165. package/dist/esm/components/FieldSlider/FieldSlider.d.ts +92 -0
  166. package/dist/esm/components/FieldSlider/FieldSlider.js +190 -0
  167. package/dist/esm/components/FieldSlider/index.d.ts +2 -0
  168. package/dist/esm/components/FieldSlider/index.js +2 -0
  169. package/dist/esm/components/FieldSlider/styles.module.css +44 -0
  170. package/dist/esm/components/FieldSlider/types.d.ts +4 -0
  171. package/dist/esm/components/FieldSlider/types.js +1 -0
  172. package/dist/esm/components/FieldSlider/utils/generateAllowedValues.d.ts +1 -0
  173. package/dist/esm/components/FieldSlider/utils/generateAllowedValues.js +13 -0
  174. package/dist/esm/components/FieldSlider/utils/getClosestMark.d.ts +4 -0
  175. package/dist/esm/components/FieldSlider/utils/getClosestMark.js +13 -0
  176. package/dist/esm/components/FieldSlider/utils/getMarkLabel.d.ts +2 -0
  177. package/dist/esm/components/FieldSlider/utils/getMarkLabel.js +4 -0
  178. package/dist/esm/components/FieldSlider/utils/getTextFieldValue.d.ts +2 -0
  179. package/dist/esm/components/FieldSlider/utils/getTextFieldValue.js +6 -0
  180. package/dist/esm/components/FieldSlider/utils/index.d.ts +5 -0
  181. package/dist/esm/components/FieldSlider/utils/index.js +5 -0
  182. package/dist/esm/components/FieldSlider/utils/isMarkObject.d.ts +6 -0
  183. package/dist/esm/components/FieldSlider/utils/isMarkObject.js +3 -0
  184. package/dist/esm/components/FieldStepper/FieldStepper.d.ts +81 -0
  185. package/dist/esm/components/FieldStepper/FieldStepper.js +154 -0
  186. package/dist/esm/components/FieldStepper/index.d.ts +1 -0
  187. package/dist/esm/components/FieldStepper/index.js +1 -0
  188. package/dist/esm/components/FieldStepper/styles.module.css +78 -0
  189. package/dist/esm/components/FieldStepper/utils.d.ts +14 -0
  190. package/dist/esm/components/FieldStepper/utils.js +38 -0
  191. package/dist/esm/components/FieldText/FieldText.d.ts +11 -0
  192. package/dist/esm/components/FieldText/FieldText.js +11 -0
  193. package/dist/esm/components/FieldText/index.d.ts +1 -0
  194. package/dist/esm/components/FieldText/index.js +1 -0
  195. package/dist/esm/components/FieldTextArea/FieldTextArea.d.ts +95 -0
  196. package/dist/esm/components/FieldTextArea/FieldTextArea.js +108 -0
  197. package/dist/esm/components/FieldTextArea/index.d.ts +1 -0
  198. package/dist/esm/components/FieldTextArea/index.js +1 -0
  199. package/dist/esm/components/FieldTextArea/styles.module.css +123 -0
  200. package/dist/esm/components/FieldTime/FieldTime.d.ts +74 -0
  201. package/dist/esm/components/FieldTime/FieldTime.js +161 -0
  202. package/dist/esm/components/FieldTime/index.d.ts +2 -0
  203. package/dist/esm/components/FieldTime/index.js +1 -0
  204. package/dist/esm/components/FieldTime/mask.d.ts +3 -0
  205. package/dist/esm/components/FieldTime/mask.js +20 -0
  206. package/dist/esm/components/FieldTime/styles.module.css +3 -0
  207. package/dist/esm/components/index.d.ts +14 -0
  208. package/dist/esm/components/index.js +12 -0
  209. package/dist/esm/components/shared/helperComponents/FieldElementButton/FieldElementButton.d.ts +35 -0
  210. package/dist/esm/components/shared/helperComponents/FieldElementButton/FieldElementButton.js +41 -0
  211. package/dist/esm/components/shared/helperComponents/FieldElementButton/FieldElementButtonList.d.ts +26 -0
  212. package/dist/esm/components/shared/helperComponents/FieldElementButton/FieldElementButtonList.js +21 -0
  213. package/dist/esm/components/shared/helperComponents/FieldElementButton/constants.d.ts +9 -0
  214. package/dist/esm/components/shared/helperComponents/FieldElementButton/constants.js +9 -0
  215. package/dist/esm/components/shared/helperComponents/FieldElementButton/index.d.ts +4 -0
  216. package/dist/esm/components/shared/helperComponents/FieldElementButton/index.js +4 -0
  217. package/dist/esm/components/shared/helperComponents/FieldElementButton/styles.module.css +204 -0
  218. package/dist/esm/components/shared/helperComponents/FieldElementButton/types.d.ts +4 -0
  219. package/dist/esm/components/shared/helperComponents/FieldElementButton/types.js +1 -0
  220. package/dist/esm/components/shared/helperComponents/FieldShell/FieldShell.d.ts +43 -0
  221. package/dist/esm/components/shared/helperComponents/FieldShell/FieldShell.js +16 -0
  222. package/dist/esm/components/shared/helperComponents/FieldShell/index.d.ts +1 -0
  223. package/dist/esm/components/shared/helperComponents/FieldShell/index.js +1 -0
  224. package/dist/esm/components/shared/helperComponents/FieldShell/styles.module.css +11 -0
  225. package/dist/esm/components/shared/hooks/useCopyButton.d.ts +20 -0
  226. package/dist/esm/components/shared/hooks/useCopyButton.js +55 -0
  227. package/dist/esm/components/shared/index.d.ts +4 -0
  228. package/dist/esm/components/shared/index.js +4 -0
  229. package/dist/esm/components/shared/styles.module.css +673 -0
  230. package/dist/esm/components/shared/utils.d.ts +69 -0
  231. package/dist/esm/components/shared/utils.js +91 -0
  232. package/dist/esm/constants.d.ts +61 -0
  233. package/dist/esm/constants.js +73 -0
  234. package/dist/esm/hooks/index.d.ts +1 -0
  235. package/dist/esm/hooks/index.js +1 -0
  236. package/dist/esm/hooks/useAdaptiveAutoFocus.d.ts +7 -0
  237. package/dist/esm/hooks/useAdaptiveAutoFocus.js +7 -0
  238. package/dist/esm/index.d.ts +3 -0
  239. package/dist/esm/index.js +3 -0
  240. package/dist/esm/segments/index.d.ts +2 -0
  241. package/dist/esm/segments/index.js +2 -0
  242. package/dist/esm/segments/segments.d.ts +22 -0
  243. package/dist/esm/segments/segments.js +43 -0
  244. package/dist/esm/segments/useSegmentedMask.d.ts +43 -0
  245. package/dist/esm/segments/useSegmentedMask.js +279 -0
  246. package/dist/esm/style.css +1350 -0
  247. package/dist/tsconfig.cjs.tsbuildinfo +1 -0
  248. package/dist/tsconfig.esm.tsbuildinfo +1 -0
  249. package/package.json +62 -0
  250. package/src/components/FieldColor/FieldColor.tsx +426 -0
  251. package/src/components/FieldColor/index.ts +1 -0
  252. package/src/components/FieldColor/styles.module.scss +120 -0
  253. package/src/components/FieldColor/utils.ts +17 -0
  254. package/src/components/FieldCombo/FieldCombo.tsx +495 -0
  255. package/src/components/FieldCombo/index.ts +1 -0
  256. package/src/components/FieldDate/FieldDate.tsx +658 -0
  257. package/src/components/FieldDate/constants.ts +11 -0
  258. package/src/components/FieldDate/index.ts +3 -0
  259. package/src/components/FieldDate/mask.ts +123 -0
  260. package/src/components/FieldDate/styles.module.scss +56 -0
  261. package/src/components/FieldDate/types.ts +124 -0
  262. package/src/components/FieldDate/utils.ts +7 -0
  263. package/src/components/FieldSecure/FieldSecure.tsx +398 -0
  264. package/src/components/FieldSecure/index.ts +1 -0
  265. package/src/components/FieldSelect/FieldSelect.tsx +689 -0
  266. package/src/components/FieldSelect/constants.ts +4 -0
  267. package/src/components/FieldSelect/index.ts +3 -0
  268. package/src/components/FieldSelect/styles.module.scss +104 -0
  269. package/src/components/FieldSelect/types.ts +212 -0
  270. package/src/components/FieldSelect/utils.ts +134 -0
  271. package/src/components/FieldSlider/FieldSlider.tsx +502 -0
  272. package/src/components/FieldSlider/index.ts +2 -0
  273. package/src/components/FieldSlider/styles.module.scss +47 -0
  274. package/src/components/FieldSlider/types.ts +5 -0
  275. package/src/components/FieldSlider/utils/generateAllowedValues.ts +13 -0
  276. package/src/components/FieldSlider/utils/getClosestMark.ts +21 -0
  277. package/src/components/FieldSlider/utils/getMarkLabel.ts +7 -0
  278. package/src/components/FieldSlider/utils/getTextFieldValue.ts +8 -0
  279. package/src/components/FieldSlider/utils/index.ts +5 -0
  280. package/src/components/FieldSlider/utils/isMarkObject.ts +7 -0
  281. package/src/components/FieldStepper/FieldStepper.tsx +457 -0
  282. package/src/components/FieldStepper/index.ts +1 -0
  283. package/src/components/FieldStepper/styles.module.scss +98 -0
  284. package/src/components/FieldStepper/utils.ts +44 -0
  285. package/src/components/FieldText/FieldText.tsx +27 -0
  286. package/src/components/FieldText/index.ts +1 -0
  287. package/src/components/FieldTextArea/FieldTextArea.tsx +374 -0
  288. package/src/components/FieldTextArea/index.ts +1 -0
  289. package/src/components/FieldTextArea/styles.module.scss +192 -0
  290. package/src/components/FieldTime/FieldTime.tsx +401 -0
  291. package/src/components/FieldTime/index.ts +2 -0
  292. package/src/components/FieldTime/mask.ts +22 -0
  293. package/src/components/FieldTime/styles.module.scss +3 -0
  294. package/src/components/index.ts +14 -0
  295. package/src/components/shared/helperComponents/FieldElementButton/FieldElementButton.tsx +127 -0
  296. package/src/components/shared/helperComponents/FieldElementButton/FieldElementButtonList.tsx +72 -0
  297. package/src/components/shared/helperComponents/FieldElementButton/constants.ts +10 -0
  298. package/src/components/shared/helperComponents/FieldElementButton/index.ts +4 -0
  299. package/src/components/shared/helperComponents/FieldElementButton/styles.module.scss +137 -0
  300. package/src/components/shared/helperComponents/FieldElementButton/types.ts +6 -0
  301. package/src/components/shared/helperComponents/FieldShell/FieldShell.tsx +100 -0
  302. package/src/components/shared/helperComponents/FieldShell/index.ts +1 -0
  303. package/src/components/shared/helperComponents/FieldShell/styles.module.scss +13 -0
  304. package/src/components/shared/hooks/useCopyButton.tsx +103 -0
  305. package/src/components/shared/index.ts +4 -0
  306. package/src/components/shared/styles.module.scss +409 -0
  307. package/src/components/shared/utils.ts +128 -0
  308. package/src/constants.ts +73 -0
  309. package/src/hooks/index.ts +1 -0
  310. package/src/hooks/useAdaptiveAutoFocus.ts +16 -0
  311. package/src/index.ts +3 -0
  312. package/src/segments/index.ts +2 -0
  313. package/src/segments/segments.ts +74 -0
  314. package/src/segments/useSegmentedMask.ts +361 -0
@@ -0,0 +1,74 @@
1
+ export type SegmentKey = 'day' | 'month' | 'year' | 'hours' | 'minutes' | 'seconds';
2
+
3
+ /** Описание одного сегмента маски: его границы в строке + допустимые значения + плейсхолдер. */
4
+ export type SlotMeta = {
5
+ key: SegmentKey;
6
+ /** Индекс начала сегмента в строке маски (включительно). */
7
+ start: number;
8
+ /** Индекс конца сегмента в строке маски (исключительно). */
9
+ end: number;
10
+ min: number;
11
+ max: number;
12
+ /** Текст-плейсхолдер сегмента (`ДД`, `чч`, …), длина = `end - start`. */
13
+ placeholder: string;
14
+ };
15
+
16
+ export type SegmentsMode = 'date' | 'date-time' | 'time';
17
+
18
+ type SegmentDef = {
19
+ key: SegmentKey;
20
+ len: number;
21
+ min: number;
22
+ max: number;
23
+ placeholder: string;
24
+ /** Разделитель ПЕРЕД сегментом (отрисовывается в маске между предыдущим и текущим). */
25
+ separator: string;
26
+ };
27
+
28
+ const DATE_DEFS: SegmentDef[] = [
29
+ { key: 'day', len: 2, min: 1, max: 31, placeholder: 'ДД', separator: '' },
30
+ { key: 'month', len: 2, min: 1, max: 12, placeholder: 'ММ', separator: '.' },
31
+ { key: 'year', len: 4, min: 1, max: 9999, placeholder: 'ГГГГ', separator: '.' },
32
+ ];
33
+
34
+ // Дату и время разделяет запятой (легаси `ДД.ММ.ГГГГ, чч:мм:сс`).
35
+ const DATE_TIME_SEPARATOR = ', ';
36
+
37
+ function timeDefs(showSeconds: boolean, firstSeparator: string): SegmentDef[] {
38
+ const defs: SegmentDef[] = [
39
+ { key: 'hours', len: 2, min: 0, max: 23, placeholder: 'чч', separator: firstSeparator },
40
+ { key: 'minutes', len: 2, min: 0, max: 59, placeholder: 'мм', separator: ':' },
41
+ ];
42
+ if (showSeconds) {
43
+ defs.push({ key: 'seconds', len: 2, min: 0, max: 59, placeholder: 'сс', separator: ':' });
44
+ }
45
+ return defs;
46
+ }
47
+
48
+ function defsForMode(mode: SegmentsMode, showSeconds: boolean): SegmentDef[] {
49
+ if (mode === 'date') {
50
+ return DATE_DEFS;
51
+ }
52
+ if (mode === 'time') {
53
+ return timeDefs(showSeconds, '');
54
+ }
55
+ return [...DATE_DEFS, ...timeDefs(showSeconds, DATE_TIME_SEPARATOR)];
56
+ }
57
+
58
+ /**
59
+ * Строит строку-маску и список сегментов с их границами/границами значений для заданного режима.
60
+ * Границы (`start`/`end`) считаются по позиции плейсхолдера сегмента в собранной маске.
61
+ */
62
+ export function buildSegments(mode: SegmentsMode, showSeconds = true): { mask: string; slots: SlotMeta[] } {
63
+ const defs = defsForMode(mode, showSeconds);
64
+ let mask = '';
65
+ const slots: SlotMeta[] = [];
66
+ for (const def of defs) {
67
+ mask += def.separator;
68
+ const start = mask.length;
69
+ mask += def.placeholder;
70
+ const end = mask.length;
71
+ slots.push({ key: def.key, start, end, min: def.min, max: def.max, placeholder: def.placeholder });
72
+ }
73
+ return { mask, slots };
74
+ }
@@ -0,0 +1,361 @@
1
+ import { ClipboardEvent, KeyboardEvent, MouseEvent, RefObject, useCallback, useRef } from 'react';
2
+
3
+ import { SlotMeta } from './segments';
4
+
5
+ type UseSegmentedMaskParams = {
6
+ inputRef: RefObject<HTMLInputElement | null>;
7
+ /** Полная строка-маска (плейсхолдеры всех сегментов + разделители). */
8
+ mask: string;
9
+ /** Сегменты в порядке следования. */
10
+ slots: SlotMeta[];
11
+ readonly?: boolean;
12
+ disabled?: boolean;
13
+ /**
14
+ * Записать новое значение в контролируемый input. InputPrivate — controlled, поэтому после
15
+ * императивной правки DOM (`input.value = …`) синхронизируем React-state тем же значением:
16
+ * `value === DOM` → React не перезаписывает input и сохраняет `setSelectionRange` (подсветку сегмента).
17
+ */
18
+ setValue(masked: string): void;
19
+ /** Текущее значение маски после правки — для парсинга в `Date`/`TimeValue` (пустая строка, если не заполнено). */
20
+ onMaskedChange(masked: string): void;
21
+ /** ArrowDown — открыть пикер / передать фокус в него. */
22
+ onArrowDown?(): void;
23
+ /** ArrowUp — закрыть пикер, если он открыт. */
24
+ onArrowUp?(): void;
25
+ /** Escape — закрыть пикер. */
26
+ onEscape?(): void;
27
+ /** Любая правка ввода (паритет с легаси — закрывает пикер). */
28
+ onEdit?(): void;
29
+ };
30
+
31
+ /**
32
+ * Сегментный ввод даты/времени (порт `useDateField` из @snack-uikit/fields). Каретка ходит по
33
+ * сегментам (`setSelectionRange` подсвечивает текущий), цифры заполняют сегмент с авто-переходом,
34
+ * стрелки двигают по сегментам, Backspace очищает сегмент до плейсхолдера.
35
+ */
36
+ export function useSegmentedMask({
37
+ inputRef,
38
+ mask,
39
+ slots,
40
+ readonly,
41
+ disabled,
42
+ setValue,
43
+ onMaskedChange,
44
+ onArrowDown,
45
+ onArrowUp,
46
+ onEscape,
47
+ onEdit,
48
+ }: UseSegmentedMaskParams) {
49
+ const firstSlot = slots[0];
50
+ const lastSlot = slots[slots.length - 1];
51
+
52
+ const indexOf = useCallback((slot: SlotMeta) => slots.indexOf(slot), [slots]);
53
+ const nextSlot = useCallback(
54
+ (slot: SlotMeta) => slots[Math.min(indexOf(slot) + 1, slots.length - 1)],
55
+ [indexOf, slots],
56
+ );
57
+ const prevSlot = useCallback((slot: SlotMeta) => slots[Math.max(indexOf(slot) - 1, 0)], [indexOf, slots]);
58
+
59
+ const selectSlot = useCallback(
60
+ (slot: SlotMeta) => {
61
+ inputRef.current?.setSelectionRange(slot.start, slot.end);
62
+ },
63
+ [inputRef],
64
+ );
65
+
66
+ const slotFromIndex = useCallback(
67
+ (index: number | null): SlotMeta => {
68
+ if (index == null) return firstSlot;
69
+ const found = slots.find(slot => index >= slot.start && index <= slot.end);
70
+ if (found) return found;
71
+ return index < firstSlot.start ? firstSlot : lastSlot;
72
+ },
73
+ [firstSlot, lastSlot, slots],
74
+ );
75
+
76
+ const getSlotText = useCallback(
77
+ (slot: SlotMeta) => inputRef.current?.value.slice(slot.start, slot.end) ?? '',
78
+ [inputRef],
79
+ );
80
+ const isSlotFilled = useCallback((slot: SlotMeta) => /^\d+$/.test(getSlotText(slot)), [getSlotText]);
81
+ const isFilled = useCallback(() => slots.every(isSlotFilled), [isSlotFilled, slots]);
82
+
83
+ const ensureMask = useCallback(() => {
84
+ const input = inputRef.current;
85
+ if (input && !input.value) {
86
+ input.value = mask;
87
+ setValue(mask);
88
+ }
89
+ }, [inputRef, mask, setValue]);
90
+
91
+ const updateSlot = useCallback(
92
+ (slot: SlotMeta, slotValue: number | string) => {
93
+ const input = inputRef.current;
94
+ if (!input) return;
95
+ const len = slot.end - slot.start;
96
+ const padded = slotValue.toString().padStart(len, '0').slice(-len);
97
+ input.value = input.value.slice(0, slot.start) + padded + input.value.slice(slot.end);
98
+ setValue(input.value);
99
+ selectSlot(slot);
100
+ },
101
+ [inputRef, selectSlot, setValue],
102
+ );
103
+
104
+ const clearSlot = useCallback(
105
+ (slot: SlotMeta) => {
106
+ const input = inputRef.current;
107
+ if (!input) return;
108
+ input.value = input.value.slice(0, slot.start) + slot.placeholder + input.value.slice(slot.end);
109
+ setValue(input.value);
110
+ selectSlot(slot);
111
+ },
112
+ [inputRef, selectSlot, setValue],
113
+ );
114
+
115
+ // Корректность даты: день должен существовать в выбранном месяце/году. Для time-only — всегда true.
116
+ const isValidDate = useCallback(() => {
117
+ const daySlot = slots.find(s => s.key === 'day');
118
+ const monthSlot = slots.find(s => s.key === 'month');
119
+ const yearSlot = slots.find(s => s.key === 'year');
120
+ if (!daySlot || !monthSlot || !yearSlot) return true;
121
+ const day = parseInt(getSlotText(daySlot), 10);
122
+ const month = parseInt(getSlotText(monthSlot), 10);
123
+ const year = parseInt(getSlotText(yearSlot), 10);
124
+ if (!month || !day) return true;
125
+ // Високосный 2020 как fallback, если год ещё не введён.
126
+ const date = new Date(year || 2020, month - 1, day);
127
+ return date.getDate() === day;
128
+ }, [getSlotText, slots]);
129
+
130
+ const tryToComplete = useCallback(() => {
131
+ const input = inputRef.current;
132
+ if (input && isFilled() && isValidDate()) {
133
+ const end = input.value.length;
134
+ input.setSelectionRange(end, end);
135
+ return true;
136
+ }
137
+ return false;
138
+ }, [inputRef, isFilled, isValidDate]);
139
+
140
+ // Эмитим только при РЕАЛЬНОЙ смене строки: неполный ввод даёт '' один раз, а не на каждый
141
+ // промежуточный keydown — иначе многократный onChange(undefined) каскадит через picker
142
+ // (TimePickerDropdown value↔dateAndTime sync) и упирается в max-update-depth.
143
+ const lastEmittedRef = useRef<string | null>(null);
144
+ const emit = useCallback(() => {
145
+ const input = inputRef.current;
146
+ const current = input && isFilled() ? input.value : '';
147
+ if (current === lastEmittedRef.current) return;
148
+ lastEmittedRef.current = current;
149
+ onMaskedChange(current);
150
+ }, [inputRef, isFilled, onMaskedChange]);
151
+
152
+ const checkInputAndGoNext = useCallback(
153
+ (slot: SlotMeta) => {
154
+ if (slot === lastSlot && tryToComplete()) {
155
+ return;
156
+ }
157
+ if (isValidDate()) {
158
+ selectSlot(nextSlot(slot));
159
+ return;
160
+ }
161
+ // Дата невалидна — откатываем зависимый сегмент к плейсхолдеру и возвращаем туда фокус.
162
+ const daySlot = slots.find(s => s.key === 'day');
163
+ const monthSlot = slots.find(s => s.key === 'month');
164
+ if (slot.key === 'day' && monthSlot) {
165
+ clearSlot(monthSlot);
166
+ return;
167
+ }
168
+ if ((slot.key === 'month' || slot.key === 'year') && daySlot) {
169
+ clearSlot(daySlot);
170
+ return;
171
+ }
172
+ selectSlot(nextSlot(slot));
173
+ },
174
+ [clearSlot, isValidDate, lastSlot, nextSlot, selectSlot, slots, tryToComplete],
175
+ );
176
+
177
+ const typeDigit = useCallback(
178
+ (slot: SlotMeta, key: string) => {
179
+ const text = getSlotText(slot);
180
+ const numberValue = Number(text) || 0;
181
+ const digit = Number(key);
182
+ const slotValue = parseInt(numberValue.toString() + key, 10) || 0;
183
+ const valueLength = slotValue.toString().length;
184
+ const maxLength = slot.max.toString().length;
185
+ const isTheLastInput = /^0+$/.test(text) && maxLength === 2 && digit === 0;
186
+
187
+ if (valueLength < maxLength) {
188
+ if (slotValue || slotValue >= slot.min) {
189
+ updateSlot(slot, slotValue);
190
+ if (isTheLastInput) checkInputAndGoNext(slot);
191
+ }
192
+ if (slotValue * 10 > slot.max) {
193
+ checkInputAndGoNext(slot);
194
+ }
195
+ } else if (valueLength > maxLength) {
196
+ if (digit * 10 > slot.max) {
197
+ updateSlot(slot, key);
198
+ checkInputAndGoNext(slot);
199
+ } else if (digit || digit >= slot.min) {
200
+ updateSlot(slot, key);
201
+ }
202
+ } else if (slotValue <= slot.max) {
203
+ updateSlot(slot, slotValue);
204
+ checkInputAndGoNext(slot);
205
+ } else if (digit * 10 > slot.max) {
206
+ updateSlot(slot, key);
207
+ checkInputAndGoNext(slot);
208
+ } else if (digit || digit >= slot.min) {
209
+ updateSlot(slot, key);
210
+ }
211
+ },
212
+ [checkInputAndGoNext, getSlotText, updateSlot],
213
+ );
214
+
215
+ const handleFocus = useCallback(() => {
216
+ if (readonly || disabled) return;
217
+ ensureMask();
218
+ // На фокус всегда выбираем ПЕРВЫЙ сегмент (паритет с легаси). При клике мышью `handleClick`
219
+ // отработает следом и перевыберет сегмент под кареткой; при Tab остаётся первый.
220
+ selectSlot(firstSlot);
221
+ }, [disabled, ensureMask, firstSlot, readonly, selectSlot]);
222
+
223
+ const handleClick = useCallback(
224
+ (event: MouseEvent<HTMLInputElement>) => {
225
+ if (readonly || disabled) return;
226
+ ensureMask();
227
+ selectSlot(slotFromIndex(event.currentTarget.selectionStart));
228
+ },
229
+ [disabled, ensureMask, readonly, selectSlot, slotFromIndex],
230
+ );
231
+
232
+ const handleBlur = useCallback(() => {
233
+ const input = inputRef.current;
234
+ if (input && input.value === mask) {
235
+ input.value = '';
236
+ setValue('');
237
+ }
238
+ }, [inputRef, mask, setValue]);
239
+
240
+ const handleKeyDown = useCallback(
241
+ (event: KeyboardEvent<HTMLInputElement>) => {
242
+ const input = inputRef.current;
243
+ if (!input || readonly || disabled) return;
244
+
245
+ // Tab уводит фокус из поля — не перехватываем.
246
+ if (event.key === 'Tab') return;
247
+
248
+ if (event.key === 'ArrowDown') {
249
+ event.preventDefault();
250
+ onArrowDown?.();
251
+ return;
252
+ }
253
+
254
+ // ArrowUp закрывает открытый пикер (фокус остаётся в поле на текущем сегменте).
255
+ if (event.key === 'ArrowUp') {
256
+ event.preventDefault();
257
+ onArrowUp?.();
258
+ return;
259
+ }
260
+
261
+ onEdit?.();
262
+
263
+ if (event.key === 'Escape') {
264
+ event.preventDefault();
265
+ onEscape?.();
266
+ input.blur();
267
+ return;
268
+ }
269
+
270
+ event.preventDefault();
271
+ event.stopPropagation();
272
+ ensureMask();
273
+
274
+ const slot = slotFromIndex(input.selectionStart);
275
+
276
+ if (event.key === 'ArrowRight') {
277
+ // На последнем сегменте каретка уходит в конец строки (паритет с легаси useDateField):
278
+ // цепной useButtonNavigation в том же keydown видит cursor-at-end и забирает фокус
279
+ // на postfix-кнопку (clear/copy).
280
+ if (slot === lastSlot) {
281
+ const end = input.value.length;
282
+ input.setSelectionRange(end, end);
283
+ return;
284
+ }
285
+ selectSlot(nextSlot(slot));
286
+ return;
287
+ }
288
+ if (event.key === 'ArrowLeft') {
289
+ selectSlot(prevSlot(slot));
290
+ return;
291
+ }
292
+ if (event.key === 'Backspace') {
293
+ clearSlot(slot);
294
+ emit();
295
+ return;
296
+ }
297
+ if (event.key === 'Enter') {
298
+ tryToComplete();
299
+ emit();
300
+ return;
301
+ }
302
+ if (/^\d$/.test(event.key)) {
303
+ typeDigit(slot, event.key);
304
+ emit();
305
+ }
306
+ },
307
+ [
308
+ clearSlot,
309
+ disabled,
310
+ emit,
311
+ ensureMask,
312
+ inputRef,
313
+ lastSlot,
314
+ nextSlot,
315
+ onArrowDown,
316
+ onArrowUp,
317
+ onEdit,
318
+ onEscape,
319
+ prevSlot,
320
+ readonly,
321
+ selectSlot,
322
+ slotFromIndex,
323
+ tryToComplete,
324
+ typeDigit,
325
+ ],
326
+ );
327
+
328
+ // Вставка (Ctrl+V) полной строки даты/времени: вытаскиваем цифры и заполняем сегменты
329
+ // слева направо. Нативный onChange у поля игнорируется (движок controlled), поэтому без
330
+ // этого обработчика вставка не работала бы вовсе.
331
+ const handlePaste = useCallback(
332
+ (event: ClipboardEvent<HTMLInputElement>) => {
333
+ if (readonly || disabled) return;
334
+ event.preventDefault();
335
+ const digits = event.clipboardData.getData('text').replace(/\D/g, '');
336
+ if (!digits) return;
337
+ ensureMask();
338
+
339
+ let cursor = 0;
340
+ let lastFilled: SlotMeta | undefined;
341
+ for (const slot of slots) {
342
+ const len = slot.end - slot.start;
343
+ const chunk = digits.slice(cursor, cursor + len);
344
+ if (chunk.length < len) break;
345
+ updateSlot(slot, chunk);
346
+ lastFilled = slot;
347
+ cursor += len;
348
+ }
349
+
350
+ if (lastFilled === lastSlot) {
351
+ tryToComplete();
352
+ } else if (lastFilled) {
353
+ selectSlot(nextSlot(lastFilled));
354
+ }
355
+ emit();
356
+ },
357
+ [disabled, emit, ensureMask, lastSlot, nextSlot, readonly, selectSlot, slots, tryToComplete, updateSlot],
358
+ );
359
+
360
+ return { handleKeyDown, handleClick, handleFocus, handleBlur, handlePaste, selectSlot, firstSlot, lastSlot };
361
+ }