@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,401 @@
1
+ import { TimePickerDropdown, TimeValue } from '@cloud-ru/ds-calendar';
2
+ import { FieldDecorator, FieldDecoratorProps, SIZE, VALIDATION_STATE } from '@cloud-ru/ds-field-decorator';
3
+ import { WatchSVG } from '@cloud-ru/ds-icons/interface/system';
4
+ import { INPUT_MODE, InputPrivate, useButtonNavigation, useClearButton } from '@cloud-ru/ds-input-private';
5
+ import { extractSupportProps } from '@cloud-ru/ds-utils';
6
+ import cn from 'classnames';
7
+ import mergeRefs from 'merge-refs';
8
+ import { FocusEvent, forwardRef, KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
9
+
10
+ import { TEST_IDS } from '../../constants';
11
+ import { FieldLayoutPresets, useAdaptiveAutoFocus } from '../../hooks';
12
+ import { buildSegments, useSegmentedMask } from '../../segments';
13
+ import { copyTextToClipboard, getAcrylicProps, toInputSize, useCopyButton } from '../shared';
14
+ import fieldStyles from '../shared/styles.module.scss';
15
+ import { parseTimeMask, timeToMaskString } from './mask';
16
+ import styles from './styles.module.scss';
17
+
18
+ type FieldTimeDecoratorProps = Omit<FieldDecoratorProps, 'children'>;
19
+
20
+ type FieldTimeOwnProps = {
21
+ /** CSS-класс корня `FieldDecorator` */
22
+ className?: string;
23
+ /** CSS-класс оболочки поля */
24
+ fieldClassName?: string;
25
+ /** Значение */
26
+ value?: TimeValue;
27
+ /** Дефолтное значение для uncontrolled-режима */
28
+ defaultValue?: TimeValue;
29
+ /** Колбек смены значения */
30
+ onChange?(value: TimeValue | undefined): void;
31
+ /** Плейсхолдер маски; по умолчанию `чч:мм:сс` или `чч:мм` в зависимости от `showSeconds`. */
32
+ placeholder?: string;
33
+ /** Открыт ли picker (controlled) */
34
+ open?: boolean;
35
+ /** Колбек смены состояния открытия */
36
+ onOpenChange?(open: boolean): void;
37
+ /**
38
+ * Показывать секунды в picker и в маске input.
39
+ * @default true
40
+ */
41
+ showSeconds?: boolean;
42
+ /**
43
+ * Закрыть picker после Apply.
44
+ * @default true
45
+ */
46
+ closeOnApply?: boolean;
47
+ /**
48
+ * Показывать кнопку очистки (видна при value && !readonly && !disabled).
49
+ * @default true
50
+ */
51
+ showClearButton?: boolean;
52
+ /** Колбек после клика по кнопке очистки. */
53
+ onClearButtonClick?(): void;
54
+ /**
55
+ * Показывать кнопку копирования (видна при readonly && value && !disabled).
56
+ * @default true
57
+ */
58
+ showCopyButton?: boolean;
59
+ /** Колбек после копирования значения. */
60
+ onCopyButtonClick?(): void;
61
+ /**
62
+ * Фон поля (acrylic).
63
+ * @default true
64
+ */
65
+ background?: boolean;
66
+ /** Отключено */
67
+ disabled?: boolean;
68
+ /** Только для чтения */
69
+ readonly?: boolean;
70
+ /** Автофокус. На mobile выключается адаптивно (см. `layoutPresets`) */
71
+ autoFocus?: boolean;
72
+ /**
73
+ * Переопределение адаптивных дефолтов по раскладке. Участвует `autoFocus`: на mobile он выключен
74
+ * (открывает клавиатуру без действия). Вернуть на mobile — `layoutPresets={{ mobile: { autoFocus: true } }}`.
75
+ */
76
+ layoutPresets?: FieldLayoutPresets;
77
+ /** HTML id */
78
+ id?: string;
79
+ /** HTML name */
80
+ name?: string;
81
+ /** Колбек фокуса input */
82
+ onFocus?(event: FocusEvent<HTMLInputElement>): void;
83
+ /** Колбек блюра input */
84
+ onBlur?(event: FocusEvent<HTMLInputElement>): void;
85
+ };
86
+
87
+ export type FieldTimeProps = FieldTimeDecoratorProps & FieldTimeOwnProps;
88
+
89
+ export const FieldTime = forwardRef<HTMLInputElement, FieldTimeProps>(function FieldTime(
90
+ {
91
+ label = '',
92
+ labelTooltip,
93
+ caption,
94
+ hint,
95
+ error,
96
+ validationState = VALIDATION_STATE.Default,
97
+ showHintIcon,
98
+ length,
99
+ required,
100
+ size = SIZE.M,
101
+ className,
102
+ fieldClassName,
103
+ background = true,
104
+ value: valueProp,
105
+ defaultValue,
106
+ onChange,
107
+ open: openProp,
108
+ onOpenChange,
109
+ showSeconds = true,
110
+ closeOnApply = true,
111
+ showClearButton: showClearButtonProp = true,
112
+ onClearButtonClick,
113
+ showCopyButton: showCopyButtonProp = true,
114
+ onCopyButtonClick,
115
+ disabled,
116
+ readonly: readOnly,
117
+ autoFocus,
118
+ layoutPresets,
119
+ id,
120
+ name,
121
+ placeholder,
122
+ onFocus: onFocusProp,
123
+ onBlur: onBlurProp,
124
+ 'data-test-id': dataTestId = TEST_IDS.fieldTime,
125
+ ...rest
126
+ },
127
+ ref,
128
+ ) {
129
+ const localRef = useRef<HTMLInputElement>(null);
130
+ const clearButtonRef = useRef<HTMLButtonElement>(null);
131
+ const copyButtonRef = useRef<HTMLButtonElement>(null);
132
+ const navigationStartRef = useRef<{ focus(): void }>(null);
133
+ const [hover, setHover] = useState(false);
134
+ const [focusVisible, setFocusVisible] = useState(false);
135
+ const [openLocal, setOpenLocal] = useState(false);
136
+ const open = openProp ?? openLocal;
137
+
138
+ const [valueLocal, setValueLocal] = useState<TimeValue | undefined>(defaultValue);
139
+ const value = valueProp ?? valueLocal;
140
+
141
+ const resolvedAutoFocus = useAdaptiveAutoFocus(autoFocus, layoutPresets);
142
+
143
+ const { mask: segMask, slots: segSlots } = useMemo(() => buildSegments('time', showSeconds), [showSeconds]);
144
+ const placeholderMask = placeholder ?? segMask;
145
+ const effectiveValidationState = useMemo(
146
+ () => (error ? VALIDATION_STATE.Error : validationState),
147
+ [error, validationState],
148
+ );
149
+
150
+ const [inputValue, setInputValue] = useState<string>(value ? timeToMaskString(value, showSeconds) : '');
151
+
152
+ useEffect(() => {
153
+ // Пока поле в фокусе — значением владеет сегментный движок (keydown), внешний sync пропускаем,
154
+ // иначе setInputValue из эффекта дерётся с движком и зацикливает рендер.
155
+ if (localRef.current && document.activeElement === localRef.current) return;
156
+ setInputValue(value ? timeToMaskString(value, showSeconds) : '');
157
+ }, [value, showSeconds]);
158
+
159
+ const emitChange = useCallback(
160
+ (next: TimeValue | undefined) => {
161
+ if (valueProp === undefined) setValueLocal(next);
162
+ onChange?.(next);
163
+ },
164
+ [onChange, valueProp],
165
+ );
166
+
167
+ const handleOpenChange = useCallback(
168
+ (next: boolean) => {
169
+ if (openProp === undefined) setOpenLocal(next);
170
+ onOpenChange?.(next);
171
+ },
172
+ [openProp, onOpenChange],
173
+ );
174
+
175
+ const timeSeg = useSegmentedMask({
176
+ inputRef: localRef,
177
+ mask: segMask,
178
+ slots: segSlots,
179
+ readonly: readOnly,
180
+ disabled,
181
+ setValue: setInputValue,
182
+ onMaskedChange: masked => {
183
+ if (masked === '') {
184
+ emitChange(undefined);
185
+ return;
186
+ }
187
+ const parsed = parseTimeMask(masked, showSeconds);
188
+ if (parsed) emitChange(parsed);
189
+ },
190
+ onArrowDown: () => {
191
+ handleOpenChange(true);
192
+ // Клавиатурный handoff в picker (барабаны времени), паритет с легаси.
193
+ setTimeout(() => navigationStartRef.current?.focus(), 0);
194
+ },
195
+ // ArrowUp в поле закрывает открытый picker (фокус остаётся в input на текущем сегменте).
196
+ onArrowUp: () => handleOpenChange(false),
197
+ onEscape: () => handleOpenChange(false),
198
+ onEdit: () => handleOpenChange(false),
199
+ });
200
+
201
+ const onClear = useCallback(() => {
202
+ setInputValue('');
203
+ emitChange(undefined);
204
+ onClearButtonClick?.();
205
+ if (required) {
206
+ localRef.current?.focus();
207
+ handleOpenChange(true);
208
+ } else {
209
+ localRef.current?.blur();
210
+ handleOpenChange(false);
211
+ }
212
+ }, [emitChange, handleOpenChange, onClearButtonClick, required]);
213
+
214
+ const onCopy = useCallback(async () => {
215
+ const copied = Boolean(inputValue) && (await copyTextToClipboard(inputValue));
216
+ if (copied) {
217
+ onCopyButtonClick?.();
218
+ }
219
+ return copied;
220
+ }, [inputValue, onCopyButtonClick]);
221
+
222
+ const showClearUi = Boolean(showClearButtonProp && inputValue && !disabled && !readOnly);
223
+ const showCopyUi = Boolean(showCopyButtonProp && inputValue && !disabled && readOnly);
224
+
225
+ const clearButtonSettings = useClearButton({
226
+ clearButtonRef,
227
+ showClearButton: showClearUi,
228
+ size: toInputSize(size),
229
+ onClear,
230
+ disabled: Boolean(disabled || readOnly),
231
+ });
232
+
233
+ const copyButtonSettings = useCopyButton({
234
+ copyButtonRef,
235
+ showCopyButton: showCopyUi,
236
+ size: toInputSize(size),
237
+ onCopy,
238
+ disabled: Boolean(disabled),
239
+ });
240
+
241
+ const { postfixButtons, inputTabIndex, onInputKeyDown } = useButtonNavigation({
242
+ inputRef: localRef,
243
+ postfixButtons: useMemo(() => [clearButtonSettings, copyButtonSettings], [clearButtonSettings, copyButtonSettings]),
244
+ readonly: Boolean(readOnly),
245
+ submitKeys: ['Enter', 'Space', 'Tab'],
246
+ });
247
+
248
+ const handleMouseEnter = useCallback(() => {
249
+ if (!readOnly && !disabled) {
250
+ setHover(true);
251
+ }
252
+ }, [readOnly, disabled]);
253
+
254
+ const handleMouseLeave = useCallback(() => {
255
+ setHover(false);
256
+ }, []);
257
+
258
+ const handleInputKeyDown = useCallback(
259
+ (event: KeyboardEvent<HTMLInputElement>) => {
260
+ timeSeg.handleKeyDown(event);
261
+ // Нав-цепочка бежит безусловно ПОСЛЕ движка (легаси-порядок useHandlers): движок мутирует
262
+ // selection синхронно (ArrowRight на последнем сегменте ставит каретку в конец), nav читает
263
+ // её в том же keydown и забирает фокус на postfix-кнопки. Гейт по defaultPrevented оставлял
264
+ // clear/copy недостижимыми со стрелок — движок всегда делает preventDefault на ArrowRight.
265
+ onInputKeyDown(event);
266
+ },
267
+ [onInputKeyDown, timeSeg],
268
+ );
269
+
270
+ // value ведёт сегментный движок (keydown); нативный onChange input'а игнорируем.
271
+ const handleInputChange = useCallback(() => undefined, []);
272
+
273
+ const handleInputFocus = useCallback(
274
+ (event: FocusEvent<HTMLInputElement>) => {
275
+ setFocusVisible(event.target.matches(':focus-visible'));
276
+ timeSeg.handleFocus();
277
+ onFocusProp?.(event);
278
+ },
279
+ [onFocusProp, timeSeg],
280
+ );
281
+
282
+ const handleInputBlur = useCallback(
283
+ (event: FocusEvent<HTMLInputElement>) => {
284
+ setFocusVisible(false);
285
+ timeSeg.handleBlur();
286
+ onBlurProp?.(event);
287
+ },
288
+ [onBlurProp, timeSeg],
289
+ );
290
+
291
+ const trigger = (
292
+ <div
293
+ className={cn(fieldStyles.fieldWrapper, styles.trigger, fieldClassName)}
294
+ data-size={size}
295
+ data-validation-state={effectiveValidationState}
296
+ data-disabled={disabled || undefined}
297
+ data-readonly={readOnly || undefined}
298
+ data-withbackground={background || undefined}
299
+ data-focusvisible={focusVisible || open || undefined}
300
+ data-hover={!readOnly && !disabled && hover ? true : undefined}
301
+ data-test-id={dataTestId}
302
+ onMouseEnter={handleMouseEnter}
303
+ onMouseLeave={handleMouseLeave}
304
+ >
305
+ <div className={fieldStyles.backgroundWrapper}>
306
+ <div
307
+ className={fieldStyles.materialLayer}
308
+ {...getAcrylicProps({
309
+ validationState: effectiveValidationState,
310
+ disabled,
311
+ readonly: readOnly,
312
+ hover,
313
+ focusVisible: focusVisible || open,
314
+ })}
315
+ >
316
+ <div className={fieldStyles.acrylicBg} aria-hidden />
317
+ </div>
318
+ <div className={fieldStyles.borderStateLayer} data-state='borderOnBackground' />
319
+ <div className={fieldStyles.focusLayer} />
320
+ </div>
321
+ <div className={fieldStyles.fieldContainer}>
322
+ <div className={fieldStyles.contentWrapper}>
323
+ <div className={fieldStyles.inputLine}>
324
+ <div className={fieldStyles.inputArea}>
325
+ <InputPrivate
326
+ ref={mergeRefs(ref, localRef)}
327
+ className={fieldStyles.fieldInput}
328
+ value={inputValue}
329
+ onChange={handleInputChange}
330
+ disabled={disabled}
331
+ readonly={readOnly}
332
+ placeholder={placeholderMask}
333
+ inputMode={INPUT_MODE.Numeric}
334
+ tabIndex={inputTabIndex}
335
+ onClick={timeSeg.handleClick}
336
+ onPaste={timeSeg.handlePaste}
337
+ onFocus={handleInputFocus}
338
+ onBlur={handleInputBlur}
339
+ onKeyDown={handleInputKeyDown}
340
+ id={id}
341
+ name={name}
342
+ autoFocus={resolvedAutoFocus}
343
+ aria-haspopup='dialog'
344
+ aria-expanded={open}
345
+ {...extractSupportProps(rest)}
346
+ data-test-id={TEST_IDS.fieldTimeInput}
347
+ />
348
+ {postfixButtons && <span className={fieldStyles.postfixButtonsSlot}>{postfixButtons}</span>}
349
+ </div>
350
+ </div>
351
+ {/* Иконка часов — декоративная; дроплист открывается кликом по полю. */}
352
+ <div className={fieldStyles.iconSlot} data-test-id={TEST_IDS.fieldTimeIcon} aria-hidden>
353
+ <WatchSVG />
354
+ </div>
355
+ </div>
356
+ </div>
357
+ </div>
358
+ );
359
+
360
+ return (
361
+ <FieldDecorator
362
+ className={className}
363
+ label={label}
364
+ labelTooltip={labelTooltip}
365
+ caption={caption}
366
+ hint={hint}
367
+ error={error}
368
+ validationState={validationState}
369
+ showHintIcon={showHintIcon}
370
+ length={length}
371
+ required={required}
372
+ labelFor={id}
373
+ disabled={disabled}
374
+ readonly={readOnly}
375
+ size={size}
376
+ >
377
+ <TimePickerDropdown
378
+ // Явный data-test-id на дропдауне → детерминированный id портального контента:
379
+ // `getTestIdBuilder` строит `content-${id}`, так контент адресуем для open-picker-снимка
380
+ // (без него контент рисуется без data-test-id, а в @cloud-ru/ds-fields::TEST_IDS такого слота нет).
381
+ data-test-id={`${dataTestId}__picker`}
382
+ size={size}
383
+ value={value}
384
+ onChangeValue={emitChange}
385
+ showSeconds={showSeconds}
386
+ closeOnApply={closeOnApply}
387
+ open={open && !disabled && !readOnly}
388
+ onOpenChange={handleOpenChange}
389
+ trigger='click'
390
+ placement='bottom-start'
391
+ navigationStartRef={navigationStartRef}
392
+ onFocusLeave={() => {
393
+ localRef.current?.focus();
394
+ handleOpenChange(false);
395
+ }}
396
+ >
397
+ {trigger}
398
+ </TimePickerDropdown>
399
+ </FieldDecorator>
400
+ );
401
+ });
@@ -0,0 +1,2 @@
1
+ export * from './FieldTime';
2
+ export type { TimeValue } from '@cloud-ru/ds-calendar';
@@ -0,0 +1,22 @@
1
+ import { TimeValue } from '@cloud-ru/ds-calendar';
2
+
3
+ function getMaxLen(showSeconds: boolean): number {
4
+ return showSeconds ? 6 : 4;
5
+ }
6
+
7
+ export function parseTimeMask(input: string, showSeconds: boolean): TimeValue | undefined {
8
+ const digits = input.replace(/\D/g, '');
9
+ const expected = getMaxLen(showSeconds);
10
+ if (digits.length !== expected) return undefined;
11
+ const hours = Number(digits.slice(0, 2));
12
+ const minutes = Number(digits.slice(2, 4));
13
+ const seconds = showSeconds ? Number(digits.slice(4, 6)) : 0;
14
+ if (hours > 23 || minutes > 59 || seconds > 59) return undefined;
15
+ return showSeconds ? { hours, minutes, seconds } : { hours, minutes };
16
+ }
17
+
18
+ export function timeToMaskString(value: TimeValue, showSeconds: boolean): string {
19
+ const pad = (n?: number) => String(n ?? 0).padStart(2, '0');
20
+ const head = `${pad(value.hours)}:${pad(value.minutes)}`;
21
+ return showSeconds ? `${head}:${pad(value.seconds)}` : head;
22
+ }
@@ -0,0 +1,3 @@
1
+ .trigger {
2
+ cursor: text;
3
+ }
@@ -0,0 +1,14 @@
1
+ export * from './FieldColor';
2
+ export * from './FieldCombo';
3
+ export * from './FieldDate';
4
+ export { SIZE, VALIDATION_STATE } from '@cloud-ru/ds-field-decorator';
5
+ export type { Size, ValidationState } from '@cloud-ru/ds-field-decorator';
6
+ export * from './FieldSecure';
7
+ export * from './FieldSelect';
8
+ export * from './FieldSlider';
9
+ export * from './FieldStepper';
10
+ export * from './FieldText';
11
+ export * from './FieldTextArea';
12
+ export * from './FieldTime';
13
+ export { FieldShell } from './shared';
14
+ export type { FieldElementButtonProps, FieldShellProps } from './shared';
@@ -0,0 +1,127 @@
1
+ import { ChevronDownSVG, ChevronUpSVG } from '@cloud-ru/ds-icons/interface/system';
2
+ import { Sun, SUN_SIZE } from '@cloud-ru/ds-loader';
3
+ import cn from 'classnames';
4
+ import { forwardRef, KeyboardEvent, ReactNode, useCallback, useState } from 'react';
5
+
6
+ import { BUTTON_SIZE } from './constants';
7
+ import styles from './styles.module.scss';
8
+ import { ButtonSize, Variant } from './types';
9
+
10
+ export type FieldElementButtonProps = {
11
+ /** Положение относительно поля */
12
+ variant: Variant;
13
+ /**
14
+ * Размер (совпадает с размером поля)
15
+ * @default 'm'
16
+ */
17
+ size?: ButtonSize;
18
+ /** Состояние загрузки */
19
+ loading?: boolean;
20
+ /** Деактивировано */
21
+ disabled?: boolean;
22
+ /** Содержимое (иконка и т.д.) */
23
+ action: ReactNode;
24
+ /** Показать шеврон раскрытия */
25
+ withDropdownList?: boolean;
26
+ /**
27
+ * Контролируемое состояние раскрытия (используется обёрткой `FieldElementButtonList`).
28
+ * Если задано — шеврон отражает это значение; иначе кнопка управляет шевроном сама.
29
+ */
30
+ open?: boolean;
31
+ /** Обработчик нажатия клавиш (передаётся обёрткой `Droplist` для ArrowDown/ArrowUp) */
32
+ onKeyDown?(event: KeyboardEvent<HTMLButtonElement>): void;
33
+ /** Обработчик клика */
34
+ onClick?(): void;
35
+ /** HTML tabIndex (`-1` — исключить кнопку из tab-order, фокус по Tab уходит в поле) */
36
+ tabIndex?: number;
37
+ /** CSS-класс (передаётся обёрткой `Droplist` / `PopoverPrivate` на триггер) */
38
+ className?: string;
39
+ /** data-test-id кнопки-слота */
40
+ 'data-test-id'?: string;
41
+ };
42
+
43
+ const SUN_SIZE_MAP = {
44
+ [BUTTON_SIZE.S]: SUN_SIZE.XS,
45
+ [BUTTON_SIZE.M]: SUN_SIZE.S,
46
+ [BUTTON_SIZE.L]: SUN_SIZE.S,
47
+ };
48
+
49
+ export const FieldElementButton = forwardRef<HTMLButtonElement, FieldElementButtonProps>(function FieldElementButton(
50
+ {
51
+ size = BUTTON_SIZE.M,
52
+ loading = false,
53
+ disabled = false,
54
+ onClick,
55
+ onKeyDown,
56
+ withDropdownList,
57
+ open,
58
+ variant,
59
+ action,
60
+ className,
61
+ tabIndex,
62
+ 'data-test-id': dataTestId,
63
+ },
64
+ ref,
65
+ ) {
66
+ const [isListOpen, setListOpen] = useState(false);
67
+ const [stateLayerPressed, setStateLayerPressed] = useState(false);
68
+
69
+ // Если `open` контролируется снаружи (FieldElementButtonList) — шеврон следует за ним,
70
+ // иначе кнопка хранит состояние раскрытия сама.
71
+ const listOpen = open ?? isListOpen;
72
+
73
+ const handleListToggleClick = useCallback(() => {
74
+ setListOpen(prevOpen => !prevOpen);
75
+ onClick?.();
76
+ }, [onClick]);
77
+
78
+ const handleKeyDown = useCallback(
79
+ (event: KeyboardEvent<HTMLButtonElement>) => {
80
+ if (disabled || loading) {
81
+ return;
82
+ }
83
+ if (event.key === 'Enter' && !event.repeat) {
84
+ setStateLayerPressed(true);
85
+ }
86
+ onKeyDown?.(event);
87
+ },
88
+ [disabled, loading, onKeyDown],
89
+ );
90
+
91
+ const handleKeyUp = useCallback((event: KeyboardEvent<HTMLButtonElement>) => {
92
+ if (event.key === 'Enter') {
93
+ setStateLayerPressed(false);
94
+ }
95
+ }, []);
96
+
97
+ const handleBlur = useCallback(() => {
98
+ setStateLayerPressed(false);
99
+ }, []);
100
+
101
+ return (
102
+ <button
103
+ ref={ref}
104
+ type='button'
105
+ className={cn(styles.buttonContainer, className)}
106
+ onClick={loading || disabled ? undefined : handleListToggleClick}
107
+ onKeyDown={handleKeyDown}
108
+ onKeyUp={handleKeyUp}
109
+ onBlur={handleBlur}
110
+ disabled={disabled || loading || undefined}
111
+ tabIndex={tabIndex}
112
+ data-size={size}
113
+ data-variant={variant}
114
+ data-loading={loading || undefined}
115
+ data-disabled={disabled || undefined}
116
+ data-pressed={stateLayerPressed ? true : undefined}
117
+ data-test-id={dataTestId}
118
+ >
119
+ <div className={styles.backgroundStateLayer} data-state='emptyNeutralOnBackground' />
120
+ <div className={styles.focusLayer} aria-hidden />
121
+ <div className={styles.elementWrapper}>
122
+ {loading && !disabled ? <Sun size={SUN_SIZE_MAP[size]} /> : action}
123
+ {withDropdownList && <div className={styles.chevron}>{listOpen ? <ChevronUpSVG /> : <ChevronDownSVG />}</div>}
124
+ </div>
125
+ </button>
126
+ );
127
+ });
@@ -0,0 +1,72 @@
1
+ import { Droplist, DroplistProps } from '@cloud-ru/ds-list';
2
+ import { useValueControl } from '@cloud-ru/ds-utils';
3
+ import { forwardRef, KeyboardEvent } from 'react';
4
+
5
+ import { FieldElementButton, FieldElementButtonProps } from './FieldElementButton';
6
+
7
+ /**
8
+ * Конфигурация встроенного выпадающего списка (действия / выбор) на `@cloud-ru/ds-list` `Droplist`.
9
+ */
10
+ export type FieldElementDroplistProps = Pick<
11
+ DroplistProps,
12
+ | 'items'
13
+ | 'pinTop'
14
+ | 'pinBottom'
15
+ | 'selection'
16
+ | 'search'
17
+ | 'scroll'
18
+ | 'scrollToSelectedItem'
19
+ | 'placement'
20
+ | 'widthStrategy'
21
+ | 'virtualized'
22
+ | 'closeDroplistOnItemClick'
23
+ > & {
24
+ /** Контролируемое состояние раскрытия */
25
+ open?: boolean;
26
+ /** Колбек смены состояния раскрытия */
27
+ onOpenChange?(open: boolean): void;
28
+ };
29
+
30
+ export type FieldElementButtonListProps = Omit<FieldElementButtonProps, 'open' | 'withDropdownList'> & {
31
+ /** Параметры встроенного выпадающего списка */
32
+ droplist: FieldElementDroplistProps;
33
+ };
34
+
35
+ /**
36
+ * Кнопка-слот поля со встроенным выпадающим списком на `@cloud-ru/ds-list` `Droplist`.
37
+ *
38
+ * Триггером выступает `FieldElementButton`, список раскрывается кликом (`trigger='click'`),
39
+ * шеврон следует за фактическим `open`, навигация ArrowDown/ArrowUp передаётся `Droplist`'ом
40
+ * в триггер.
41
+ */
42
+ export const FieldElementButtonList = forwardRef<HTMLButtonElement, FieldElementButtonListProps>(
43
+ function FieldElementButtonList({ droplist, size, onKeyDown, ...buttonProps }, ref) {
44
+ const { open: openProp, onOpenChange, closeDroplistOnItemClick, ...droplistProps } = droplist;
45
+
46
+ const [open = false, setOpen] = useValueControl<boolean>({
47
+ value: openProp,
48
+ defaultValue: false,
49
+ onChange: onOpenChange,
50
+ });
51
+
52
+ return (
53
+ <Droplist
54
+ {...droplistProps}
55
+ trigger='click'
56
+ size={size}
57
+ open={open}
58
+ onOpenChange={setOpen}
59
+ closeDroplistOnItemClick={closeDroplistOnItemClick ?? true}
60
+ >
61
+ <FieldElementButton
62
+ {...buttonProps}
63
+ ref={ref}
64
+ size={size}
65
+ withDropdownList
66
+ open={open}
67
+ onKeyDown={(event: KeyboardEvent<HTMLButtonElement>) => onKeyDown?.(event)}
68
+ />
69
+ </Droplist>
70
+ );
71
+ },
72
+ );
@@ -0,0 +1,10 @@
1
+ export const VARIANT = {
2
+ Before: 'before',
3
+ After: 'after',
4
+ } as const;
5
+
6
+ export const BUTTON_SIZE = {
7
+ S: 's',
8
+ M: 'm',
9
+ L: 'l',
10
+ } as const;
@@ -0,0 +1,4 @@
1
+ export * from './FieldElementButton';
2
+ export * from './FieldElementButtonList';
3
+ export * from './constants';
4
+ export * from './types';