@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,108 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { FieldDecorator, SIZE, VALIDATION_STATE } from '@cloud-ru/ds-field-decorator';
3
+ import { useButtonNavigation, useClearButton } from '@cloud-ru/ds-input-private';
4
+ import { BAR_HIDE_STRATEGY, RESIZE, Scroll, SIZE as SCROLL_SIZE } from '@cloud-ru/ds-scroll';
5
+ import { extractSupportProps, useValueControl } from '@cloud-ru/ds-utils';
6
+ import cn from 'classnames';
7
+ import mergeRefs from 'merge-refs';
8
+ import { forwardRef, useCallback, useMemo, useRef, useState, } from 'react';
9
+ import TextareaAutosize from 'react-textarea-autosize';
10
+ import { TEST_IDS } from '../../constants.js';
11
+ import { useAdaptiveAutoFocus } from '../../hooks/index.js';
12
+ import { copyTextToClipboard, FieldShell, toInputSize, useCopyButton } from '../shared/index.js';
13
+ import fieldStyles from '../shared/styles.module.css';
14
+ import styles from './styles.module.css';
15
+ export const FieldTextArea = forwardRef(function FieldTextArea({ label = '', labelTooltip, caption, hint, error, validationState = VALIDATION_STATE.Default, showHintIcon, length, required, size = SIZE.M, className, fieldClassName, background = true, value: valueProp, defaultValue = '', onChange, placeholder, id, name, maxLength, disabled, readonly: readOnly, autoFocus, layoutPresets, inputMode, spellCheck, minRows = 3, maxRows = 1000, resizable = false, allowMoreThanMaxLength = true, header, footer, showClearButton: showClearButtonProp = true, showCopyButton: showCopyButtonProp = true, onCopyButtonClick, onFocus: onFocusProp, onBlur: onBlurProp, onKeyDown: onKeyDownProp, 'data-test-id': dataTestId, ...rest }, ref) {
16
+ const localRef = useRef(null);
17
+ const clearButtonRef = useRef(null);
18
+ const copyButtonRef = useRef(null);
19
+ const [focusVisible, setFocusVisible] = useState(false);
20
+ const [hover, setHover] = useState(false);
21
+ const resolvedAutoFocus = useAdaptiveAutoFocus(autoFocus, layoutPresets);
22
+ // controlled/uncontrolled: useValueControl держит внутреннее состояние при отсутствии `value`,
23
+ // событие в `onChange` пробрасываем сами (useValueControl передаёт только значение).
24
+ const [value = '', setValue] = useValueControl({ value: valueProp, defaultValue });
25
+ const effectiveValidationState = useMemo(() => (error ? VALIDATION_STATE.Error : validationState), [error, validationState]);
26
+ const stringValue = String(value ?? '');
27
+ const isResizable = resizable && !disabled && !readOnly;
28
+ const showClearUi = Boolean(showClearButtonProp && stringValue && !readOnly && !disabled);
29
+ // Copy не завязан на readonly (паритет с snack-uikit master): виден при любом непустом значении.
30
+ // В editable-режиме показываются обе кнопки (clear + copy), в readonly — только copy.
31
+ const showCopyUi = Boolean(showCopyButtonProp && stringValue && !disabled);
32
+ const onClear = useCallback(() => {
33
+ setValue('');
34
+ onChange?.('');
35
+ localRef.current?.focus();
36
+ }, [onChange, setValue]);
37
+ const onCopy = useCallback(async () => {
38
+ const copied = await copyTextToClipboard(stringValue);
39
+ if (copied) {
40
+ onCopyButtonClick?.();
41
+ }
42
+ return copied;
43
+ }, [onCopyButtonClick, stringValue]);
44
+ const clearButtonSettings = useClearButton({
45
+ clearButtonRef,
46
+ showClearButton: showClearUi,
47
+ size: toInputSize(size),
48
+ onClear,
49
+ disabled: Boolean(disabled || readOnly),
50
+ });
51
+ const copyButtonSettings = useCopyButton({
52
+ copyButtonRef,
53
+ showCopyButton: showCopyUi,
54
+ size: toInputSize(size),
55
+ onCopy,
56
+ disabled: Boolean(disabled),
57
+ });
58
+ const { postfixButtons, inputTabIndex, onInputKeyDown } = useButtonNavigation({
59
+ inputRef: localRef,
60
+ postfixButtons: useMemo(() => [clearButtonSettings, copyButtonSettings], [clearButtonSettings, copyButtonSettings]),
61
+ readonly: Boolean(readOnly),
62
+ submitKeys: ['Tab'],
63
+ });
64
+ const handleKeyDown = useCallback((event) => {
65
+ onKeyDownProp?.(event);
66
+ onInputKeyDown(event);
67
+ }, [onInputKeyDown, onKeyDownProp]);
68
+ const handleChange = (event) => {
69
+ setValue(event.target.value);
70
+ onChange?.(event.target.value, event);
71
+ };
72
+ // Клик в «пустую» зону поля (под textarea при minRows-резерве, в правый резерв под кнопки)
73
+ // фокусит textarea и ставит курсор в конец — паритет со снеком, где попадание в любую область
74
+ // поля работает как клик по textarea. Намеренно `onClick`, а не `onMouseDown`+preventDefault:
75
+ // resize-ручка scroll-контейнера тоже работает через mousedown-drag, и preventDefault убивал бы
76
+ // нативный CSS-resize. Click после resize-drag не возникает, а клики по textarea, кнопкам
77
+ // clear/copy и DS-скроллбару отсеиваем по target.
78
+ const handleContentClick = useCallback((event) => {
79
+ const target = event.target;
80
+ if (disabled || target === localRef.current || target.closest('button, [class*="os-scrollbar"]')) {
81
+ return;
82
+ }
83
+ const textarea = localRef.current;
84
+ if (textarea) {
85
+ textarea.focus();
86
+ const end = textarea.value.length;
87
+ textarea.setSelectionRange(end, end);
88
+ }
89
+ }, [disabled]);
90
+ const handleFocus = useCallback((event) => {
91
+ setFocusVisible(event.target.matches(':focus-visible'));
92
+ onFocusProp?.(event);
93
+ }, [onFocusProp]);
94
+ const handleBlur = useCallback((event) => {
95
+ setFocusVisible(false);
96
+ onBlurProp?.(event);
97
+ }, [onBlurProp]);
98
+ const handleMouseEnter = useCallback(() => {
99
+ if (!readOnly) {
100
+ setHover(true);
101
+ }
102
+ }, [readOnly]);
103
+ const handleMouseLeave = useCallback(() => {
104
+ setHover(false);
105
+ }, []);
106
+ const shell = (_jsx(FieldShell, { "data-test-id": TEST_IDS.fieldTextAreaShell, className: fieldClassName, size: size, validationState: effectiveValidationState, disabled: disabled, readonly: readOnly, background: background, focusVisible: focusVisible, hover: hover, header: header, footer: footer, style: { '--field-textarea-min-rows': minRows, '--field-textarea-max-rows': maxRows }, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: _jsxs("div", { className: cn(fieldStyles.contentWrapper, styles.contentArea), onClick: handleContentClick, children: [_jsx(Scroll, { className: cn(styles.scrollContainer, { [styles.scrollContainerResizable]: isResizable }), size: SCROLL_SIZE.S, barHideStrategy: BAR_HIDE_STRATEGY.Never, resize: isResizable ? RESIZE.Vertical : RESIZE.None, overflow: { x: 'hidden' }, "data-test-id": TEST_IDS.fieldTextAreaScrollArea, children: _jsx("div", { className: fieldStyles.inputLine, children: _jsx(TextareaAutosize, { ref: mergeRefs(ref, localRef), className: styles.textarea, value: value, onChange: handleChange, placeholder: placeholder, disabled: disabled, readOnly: readOnly, id: id, name: name, maxLength: allowMoreThanMaxLength ? undefined : maxLength, autoFocus: resolvedAutoFocus, inputMode: inputMode, spellCheck: spellCheck, minRows: minRows, tabIndex: inputTabIndex, "data-test-id": TEST_IDS.fieldTextAreaInput, onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown, ...extractSupportProps(rest) }) }) }), postfixButtons && _jsx("span", { className: styles.postfixColumn, children: postfixButtons })] }) }));
107
+ return (_jsx(FieldDecorator, { className: className, label: label, labelTooltip: labelTooltip, caption: caption, hint: hint, error: error, validationState: validationState, showHintIcon: showHintIcon, length: length ?? (maxLength ? { current: stringValue.length, max: maxLength } : undefined), required: required, labelFor: id, disabled: disabled, readonly: readOnly, size: size, "data-test-id": dataTestId, children: shell }));
108
+ });
@@ -0,0 +1 @@
1
+ export * from './FieldTextArea.js';
@@ -0,0 +1 @@
1
+ export * from './FieldTextArea.js';
@@ -0,0 +1,123 @@
1
+ .scrollContainer{
2
+ flex:1 1 auto;
3
+ min-width:0;
4
+ min-height:calc(var(--field-textarea-min-rows, 3) * var(--field-textarea-row-height));
5
+ max-height:calc(var(--field-textarea-max-rows, 1000) * var(--field-textarea-row-height));
6
+ }
7
+ [data-size=s] .scrollContainer{
8
+ --field-textarea-row-height:var(--sn-regular-body-s-lineHeight, var(--sn-density-typography-roleBody-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px)));
9
+ }
10
+ [data-size=m] .scrollContainer{
11
+ --field-textarea-row-height:var(--sn-regular-body-m-lineHeight, var(--sn-density-typography-roleBody-lineHeightM, var(--sn-primitive-font-lineHeight-by16, 24px)));
12
+ }
13
+ [data-size=l] .scrollContainer{
14
+ --field-textarea-row-height:var(--sn-regular-body-l-lineHeight, var(--sn-density-typography-roleBody-lineHeightL, var(--sn-primitive-font-lineHeight-by20, 28px)));
15
+ }
16
+
17
+ .scrollContainerResizable{
18
+ height:calc(var(--field-textarea-min-rows, 3) * var(--field-textarea-row-height));
19
+ }
20
+
21
+ .textarea{
22
+ resize:none;
23
+ overflow:hidden;
24
+ width:100%;
25
+ min-width:0;
26
+ padding:0;
27
+ border:none;
28
+ color:var(--sn-theme-color-available-version-textMain, var(--sn-brand-color-text-version-main, #41424e));
29
+ background:transparent;
30
+ outline:none;
31
+ }
32
+ .textarea::-moz-placeholder{
33
+ color:var(--sn-theme-color-available-version-textDisabled, var(--sn-brand-color-text-version-disabled, rgba(65, 66, 78, 0.3490196078)));
34
+ opacity:1;
35
+ }
36
+ .textarea::placeholder{
37
+ color:var(--sn-theme-color-available-version-textDisabled, var(--sn-brand-color-text-version-disabled, rgba(65, 66, 78, 0.3490196078)));
38
+ opacity:1;
39
+ }
40
+ .textarea:disabled::-moz-placeholder{
41
+ visibility:hidden;
42
+ }
43
+ .textarea:disabled::placeholder{
44
+ visibility:hidden;
45
+ }
46
+ .textarea:-moz-read-only{
47
+ color:var(--sn-theme-color-available-version-textTertiary, var(--sn-brand-color-text-version-tertiary, rgba(65, 66, 78, 0.5490196078)));
48
+ }
49
+ .textarea:read-only{
50
+ color:var(--sn-theme-color-available-version-textTertiary, var(--sn-brand-color-text-version-tertiary, rgba(65, 66, 78, 0.5490196078)));
51
+ }
52
+ [data-size=s] .textarea{
53
+ min-height:var(--sn-field-anatomy-size-s-fieldContainer-multiLine-minHeight, var(--sn-primitive-dimension-56, 56px));
54
+ padding-right:calc(var(--sn-field-anatomy-size-s-fieldContainer-centeredWrapper-maxHeight, var(--sn-density-typography-roleBody-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px))) + var(--sn-scroll-anatomy-container-size-s-square, var(--sn-primitive-dimension-8, 8px)) + var(--sn-field-anatomy-size-s-fieldContainer-contentWrapper-inputLine-horizontalPadding, var(--sn-density-spacing-control-wrapper-horizontal-s, var(--sn-primitive-dimension-8, 8px))));
55
+ font-family:var(--sn-regular-body-s-fontFamily, var(--sn-brand-font-fontFamily-regular-body, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
56
+ font-weight:var(--sn-regular-body-s-fontWeight, var(--sn-theme-typography-fontWeight-regular-body-s, var(--sn-brand-font-fontWeight-light-regular-body-s, var(--sn-primitive-font-fontWeightValue-400, 400))));
57
+ line-height:var(--sn-regular-body-s-lineHeight, var(--sn-density-typography-roleBody-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px)));
58
+ font-size:var(--sn-regular-body-s-fontSize, var(--sn-density-typography-roleBody-fontSizeS, var(--sn-primitive-font-fontSize-14, 14px)));
59
+ letter-spacing:var(--sn-regular-body-s-letterSpacing, var(--sn-primitive-font-letterSpacing-m, 0.1px));
60
+ paragraph-spacing:var(--sn-regular-body-s-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize12, 6px));
61
+ }
62
+ [data-size=m] .textarea{
63
+ min-height:var(--sn-field-anatomy-size-m-fieldContainer-multiLine-minHeight, var(--sn-primitive-dimension-68, 68px));
64
+ padding-right:calc(var(--sn-field-anatomy-size-m-fieldContainer-centeredWrapper-maxHeight, var(--sn-density-typography-roleBody-lineHeightM, var(--sn-primitive-font-lineHeight-by16, 24px))) + var(--sn-scroll-anatomy-container-size-s-square, var(--sn-primitive-dimension-8, 8px)) + var(--sn-field-anatomy-size-m-fieldContainer-contentWrapper-inputLine-horizontalPadding, var(--sn-density-spacing-control-wrapper-horizontal-m, var(--sn-primitive-dimension-8, 8px))));
65
+ font-family:var(--sn-regular-body-m-fontFamily, var(--sn-brand-font-fontFamily-regular-body, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
66
+ font-weight:var(--sn-regular-body-m-fontWeight, var(--sn-theme-typography-fontWeight-regular-body-m, var(--sn-brand-font-fontWeight-light-regular-body-m, var(--sn-primitive-font-fontWeightValue-400, 400))));
67
+ line-height:var(--sn-regular-body-m-lineHeight, var(--sn-density-typography-roleBody-lineHeightM, var(--sn-primitive-font-lineHeight-by16, 24px)));
68
+ font-size:var(--sn-regular-body-m-fontSize, var(--sn-density-typography-roleBody-fontSizeM, var(--sn-primitive-font-fontSize-16, 16px)));
69
+ letter-spacing:var(--sn-regular-body-m-letterSpacing, var(--sn-primitive-font-letterSpacing-m, 0.1px));
70
+ paragraph-spacing:var(--sn-regular-body-m-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize14, 7px));
71
+ }
72
+ [data-size=l] .textarea{
73
+ min-height:var(--sn-field-anatomy-size-l-fieldContainer-multiLine-minHeight, var(--sn-primitive-dimension-88, 88px));
74
+ padding-right:calc(var(--sn-field-anatomy-size-l-fieldContainer-centeredWrapper-maxHeight, var(--sn-density-typography-roleBody-lineHeightL, var(--sn-primitive-font-lineHeight-by20, 28px))) + var(--sn-scroll-anatomy-container-size-s-square, var(--sn-primitive-dimension-8, 8px)) + var(--sn-field-anatomy-size-l-fieldContainer-contentWrapper-inputLine-horizontalPadding, var(--sn-density-spacing-control-wrapper-horizontal-l, var(--sn-primitive-dimension-12, 12px))));
75
+ font-family:var(--sn-regular-body-l-fontFamily, var(--sn-brand-font-fontFamily-regular-body, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
76
+ font-weight:var(--sn-regular-body-l-fontWeight, var(--sn-theme-typography-fontWeight-regular-body-l, var(--sn-brand-font-fontWeight-light-regular-body-l, var(--sn-primitive-font-fontWeightValue-400, 400))));
77
+ line-height:var(--sn-regular-body-l-lineHeight, var(--sn-density-typography-roleBody-lineHeightL, var(--sn-primitive-font-lineHeight-by20, 28px)));
78
+ font-size:var(--sn-regular-body-l-fontSize, var(--sn-density-typography-roleBody-fontSizeL, var(--sn-primitive-font-fontSize-20, 20px)));
79
+ letter-spacing:var(--sn-regular-body-l-letterSpacing, var(--sn-primitive-font-letterSpacing-m, 0.1px));
80
+ paragraph-spacing:var(--sn-regular-body-l-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize16, 8px));
81
+ }
82
+
83
+ .contentArea{
84
+ position:relative;
85
+ }
86
+ [data-size=s] .contentArea{
87
+ padding-top:var(--sn-field-anatomy-size-s-fieldContainer-contentWrapper-verticalPadding, var(--sn-density-spacing-control-wrapper-vertical-s, var(--sn-primitive-dimension-8, 8px)));
88
+ padding-bottom:var(--sn-field-anatomy-size-s-fieldContainer-contentWrapper-verticalPadding, var(--sn-density-spacing-control-wrapper-vertical-s, var(--sn-primitive-dimension-8, 8px)));
89
+ }
90
+ [data-size=m] .contentArea{
91
+ padding-top:var(--sn-field-anatomy-size-m-fieldContainer-contentWrapper-verticalPadding, var(--sn-density-spacing-control-wrapper-vertical-m, var(--sn-primitive-dimension-8, 8px)));
92
+ padding-bottom:var(--sn-field-anatomy-size-m-fieldContainer-contentWrapper-verticalPadding, var(--sn-density-spacing-control-wrapper-vertical-m, var(--sn-primitive-dimension-8, 8px)));
93
+ }
94
+ [data-size=l] .contentArea{
95
+ padding-top:var(--sn-field-anatomy-size-l-fieldContainer-contentWrapper-verticalPadding, var(--sn-density-spacing-control-wrapper-vertical-l, var(--sn-primitive-dimension-8, 8px)));
96
+ padding-bottom:var(--sn-field-anatomy-size-l-fieldContainer-contentWrapper-verticalPadding, var(--sn-density-spacing-control-wrapper-vertical-l, var(--sn-primitive-dimension-8, 8px)));
97
+ }
98
+
99
+ .postfixColumn{
100
+ position:absolute;
101
+ display:grid;
102
+ grid-template-columns:100%;
103
+ row-gap:var(--sn-primitive-dimension-2, 2px);
104
+ place-items:center center;
105
+ }
106
+ [data-size=s] .postfixColumn{
107
+ top:calc(var(--sn-field-anatomy-size-s-fieldContainer-contentWrapper-verticalPadding, var(--sn-density-spacing-control-wrapper-vertical-s, var(--sn-primitive-dimension-8, 8px))) + (var(--sn-regular-body-s-lineHeight, var(--sn-density-typography-roleBody-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px))) - var(--sn-field-anatomy-size-s-fieldContainer-centeredWrapper-maxHeight, var(--sn-density-typography-roleBody-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px)))) / 2);
108
+ right:calc(var(--sn-scroll-anatomy-container-size-s-square, var(--sn-primitive-dimension-8, 8px)) + var(--sn-field-anatomy-size-s-fieldContainer-contentWrapper-inputLine-horizontalPadding, var(--sn-density-spacing-control-wrapper-horizontal-s, var(--sn-primitive-dimension-8, 8px))));
109
+ grid-auto-rows:var(--sn-field-anatomy-size-s-fieldContainer-centeredWrapper-maxHeight, var(--sn-density-typography-roleBody-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px)));
110
+ width:var(--sn-field-anatomy-size-s-fieldContainer-centeredWrapper-maxHeight, var(--sn-density-typography-roleBody-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px)));
111
+ }
112
+ [data-size=m] .postfixColumn{
113
+ top:calc(var(--sn-field-anatomy-size-m-fieldContainer-contentWrapper-verticalPadding, var(--sn-density-spacing-control-wrapper-vertical-m, var(--sn-primitive-dimension-8, 8px))) + (var(--sn-regular-body-m-lineHeight, var(--sn-density-typography-roleBody-lineHeightM, var(--sn-primitive-font-lineHeight-by16, 24px))) - var(--sn-field-anatomy-size-m-fieldContainer-centeredWrapper-maxHeight, var(--sn-density-typography-roleBody-lineHeightM, var(--sn-primitive-font-lineHeight-by16, 24px)))) / 2);
114
+ right:calc(var(--sn-scroll-anatomy-container-size-s-square, var(--sn-primitive-dimension-8, 8px)) + var(--sn-field-anatomy-size-m-fieldContainer-contentWrapper-inputLine-horizontalPadding, var(--sn-density-spacing-control-wrapper-horizontal-m, var(--sn-primitive-dimension-8, 8px))));
115
+ grid-auto-rows:var(--sn-field-anatomy-size-m-fieldContainer-centeredWrapper-maxHeight, var(--sn-density-typography-roleBody-lineHeightM, var(--sn-primitive-font-lineHeight-by16, 24px)));
116
+ width:var(--sn-field-anatomy-size-m-fieldContainer-centeredWrapper-maxHeight, var(--sn-density-typography-roleBody-lineHeightM, var(--sn-primitive-font-lineHeight-by16, 24px)));
117
+ }
118
+ [data-size=l] .postfixColumn{
119
+ top:calc(var(--sn-field-anatomy-size-l-fieldContainer-contentWrapper-verticalPadding, var(--sn-density-spacing-control-wrapper-vertical-l, var(--sn-primitive-dimension-8, 8px))) + (var(--sn-regular-body-l-lineHeight, var(--sn-density-typography-roleBody-lineHeightL, var(--sn-primitive-font-lineHeight-by20, 28px))) - var(--sn-field-anatomy-size-l-fieldContainer-centeredWrapper-maxHeight, var(--sn-density-typography-roleBody-lineHeightL, var(--sn-primitive-font-lineHeight-by20, 28px)))) / 2);
120
+ right:calc(var(--sn-scroll-anatomy-container-size-s-square, var(--sn-primitive-dimension-8, 8px)) + var(--sn-field-anatomy-size-l-fieldContainer-contentWrapper-inputLine-horizontalPadding, var(--sn-density-spacing-control-wrapper-horizontal-l, var(--sn-primitive-dimension-12, 12px))));
121
+ grid-auto-rows:var(--sn-field-anatomy-size-l-fieldContainer-centeredWrapper-maxHeight, var(--sn-density-typography-roleBody-lineHeightL, var(--sn-primitive-font-lineHeight-by20, 28px)));
122
+ width:var(--sn-field-anatomy-size-l-fieldContainer-centeredWrapper-maxHeight, var(--sn-density-typography-roleBody-lineHeightL, var(--sn-primitive-font-lineHeight-by20, 28px)));
123
+ }
@@ -0,0 +1,74 @@
1
+ import { TimeValue } from '@cloud-ru/ds-calendar';
2
+ import { FieldDecoratorProps } from '@cloud-ru/ds-field-decorator';
3
+ import { FocusEvent } from 'react';
4
+ import { FieldLayoutPresets } from '../../hooks/index.js';
5
+ type FieldTimeDecoratorProps = Omit<FieldDecoratorProps, 'children'>;
6
+ type FieldTimeOwnProps = {
7
+ /** CSS-класс корня `FieldDecorator` */
8
+ className?: string;
9
+ /** CSS-класс оболочки поля */
10
+ fieldClassName?: string;
11
+ /** Значение */
12
+ value?: TimeValue;
13
+ /** Дефолтное значение для uncontrolled-режима */
14
+ defaultValue?: TimeValue;
15
+ /** Колбек смены значения */
16
+ onChange?(value: TimeValue | undefined): void;
17
+ /** Плейсхолдер маски; по умолчанию `чч:мм:сс` или `чч:мм` в зависимости от `showSeconds`. */
18
+ placeholder?: string;
19
+ /** Открыт ли picker (controlled) */
20
+ open?: boolean;
21
+ /** Колбек смены состояния открытия */
22
+ onOpenChange?(open: boolean): void;
23
+ /**
24
+ * Показывать секунды в picker и в маске input.
25
+ * @default true
26
+ */
27
+ showSeconds?: boolean;
28
+ /**
29
+ * Закрыть picker после Apply.
30
+ * @default true
31
+ */
32
+ closeOnApply?: boolean;
33
+ /**
34
+ * Показывать кнопку очистки (видна при value && !readonly && !disabled).
35
+ * @default true
36
+ */
37
+ showClearButton?: boolean;
38
+ /** Колбек после клика по кнопке очистки. */
39
+ onClearButtonClick?(): void;
40
+ /**
41
+ * Показывать кнопку копирования (видна при readonly && value && !disabled).
42
+ * @default true
43
+ */
44
+ showCopyButton?: boolean;
45
+ /** Колбек после копирования значения. */
46
+ onCopyButtonClick?(): void;
47
+ /**
48
+ * Фон поля (acrylic).
49
+ * @default true
50
+ */
51
+ background?: boolean;
52
+ /** Отключено */
53
+ disabled?: boolean;
54
+ /** Только для чтения */
55
+ readonly?: boolean;
56
+ /** Автофокус. На mobile выключается адаптивно (см. `layoutPresets`) */
57
+ autoFocus?: boolean;
58
+ /**
59
+ * Переопределение адаптивных дефолтов по раскладке. Участвует `autoFocus`: на mobile он выключен
60
+ * (открывает клавиатуру без действия). Вернуть на mobile — `layoutPresets={{ mobile: { autoFocus: true } }}`.
61
+ */
62
+ layoutPresets?: FieldLayoutPresets;
63
+ /** HTML id */
64
+ id?: string;
65
+ /** HTML name */
66
+ name?: string;
67
+ /** Колбек фокуса input */
68
+ onFocus?(event: FocusEvent<HTMLInputElement>): void;
69
+ /** Колбек блюра input */
70
+ onBlur?(event: FocusEvent<HTMLInputElement>): void;
71
+ };
72
+ export type FieldTimeProps = FieldTimeDecoratorProps & FieldTimeOwnProps;
73
+ export declare const FieldTime: import("react").ForwardRefExoticComponent<FieldTimeDecoratorProps & FieldTimeOwnProps & import("react").RefAttributes<HTMLInputElement>>;
74
+ export {};
@@ -0,0 +1,161 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { TimePickerDropdown } from '@cloud-ru/ds-calendar';
3
+ import { FieldDecorator, SIZE, VALIDATION_STATE } from '@cloud-ru/ds-field-decorator';
4
+ import { WatchSVG } from '@cloud-ru/ds-icons/interface/system';
5
+ import { INPUT_MODE, InputPrivate, useButtonNavigation, useClearButton } from '@cloud-ru/ds-input-private';
6
+ import { extractSupportProps } from '@cloud-ru/ds-utils';
7
+ import cn from 'classnames';
8
+ import mergeRefs from 'merge-refs';
9
+ import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
10
+ import { TEST_IDS } from '../../constants.js';
11
+ import { useAdaptiveAutoFocus } from '../../hooks/index.js';
12
+ import { buildSegments, useSegmentedMask } from '../../segments/index.js';
13
+ import { copyTextToClipboard, getAcrylicProps, toInputSize, useCopyButton } from '../shared/index.js';
14
+ import fieldStyles from '../shared/styles.module.css';
15
+ import { parseTimeMask, timeToMaskString } from './mask.js';
16
+ import styles from './styles.module.css';
17
+ export const FieldTime = forwardRef(function FieldTime({ label = '', labelTooltip, caption, hint, error, validationState = VALIDATION_STATE.Default, showHintIcon, length, required, size = SIZE.M, className, fieldClassName, background = true, value: valueProp, defaultValue, onChange, open: openProp, onOpenChange, showSeconds = true, closeOnApply = true, showClearButton: showClearButtonProp = true, onClearButtonClick, showCopyButton: showCopyButtonProp = true, onCopyButtonClick, disabled, readonly: readOnly, autoFocus, layoutPresets, id, name, placeholder, onFocus: onFocusProp, onBlur: onBlurProp, 'data-test-id': dataTestId = TEST_IDS.fieldTime, ...rest }, ref) {
18
+ const localRef = useRef(null);
19
+ const clearButtonRef = useRef(null);
20
+ const copyButtonRef = useRef(null);
21
+ const navigationStartRef = useRef(null);
22
+ const [hover, setHover] = useState(false);
23
+ const [focusVisible, setFocusVisible] = useState(false);
24
+ const [openLocal, setOpenLocal] = useState(false);
25
+ const open = openProp ?? openLocal;
26
+ const [valueLocal, setValueLocal] = useState(defaultValue);
27
+ const value = valueProp ?? valueLocal;
28
+ const resolvedAutoFocus = useAdaptiveAutoFocus(autoFocus, layoutPresets);
29
+ const { mask: segMask, slots: segSlots } = useMemo(() => buildSegments('time', showSeconds), [showSeconds]);
30
+ const placeholderMask = placeholder ?? segMask;
31
+ const effectiveValidationState = useMemo(() => (error ? VALIDATION_STATE.Error : validationState), [error, validationState]);
32
+ const [inputValue, setInputValue] = useState(value ? timeToMaskString(value, showSeconds) : '');
33
+ useEffect(() => {
34
+ // Пока поле в фокусе — значением владеет сегментный движок (keydown), внешний sync пропускаем,
35
+ // иначе setInputValue из эффекта дерётся с движком и зацикливает рендер.
36
+ if (localRef.current && document.activeElement === localRef.current)
37
+ return;
38
+ setInputValue(value ? timeToMaskString(value, showSeconds) : '');
39
+ }, [value, showSeconds]);
40
+ const emitChange = useCallback((next) => {
41
+ if (valueProp === undefined)
42
+ setValueLocal(next);
43
+ onChange?.(next);
44
+ }, [onChange, valueProp]);
45
+ const handleOpenChange = useCallback((next) => {
46
+ if (openProp === undefined)
47
+ setOpenLocal(next);
48
+ onOpenChange?.(next);
49
+ }, [openProp, onOpenChange]);
50
+ const timeSeg = useSegmentedMask({
51
+ inputRef: localRef,
52
+ mask: segMask,
53
+ slots: segSlots,
54
+ readonly: readOnly,
55
+ disabled,
56
+ setValue: setInputValue,
57
+ onMaskedChange: masked => {
58
+ if (masked === '') {
59
+ emitChange(undefined);
60
+ return;
61
+ }
62
+ const parsed = parseTimeMask(masked, showSeconds);
63
+ if (parsed)
64
+ emitChange(parsed);
65
+ },
66
+ onArrowDown: () => {
67
+ handleOpenChange(true);
68
+ // Клавиатурный handoff в picker (барабаны времени), паритет с легаси.
69
+ setTimeout(() => navigationStartRef.current?.focus(), 0);
70
+ },
71
+ // ArrowUp в поле закрывает открытый picker (фокус остаётся в input на текущем сегменте).
72
+ onArrowUp: () => handleOpenChange(false),
73
+ onEscape: () => handleOpenChange(false),
74
+ onEdit: () => handleOpenChange(false),
75
+ });
76
+ const onClear = useCallback(() => {
77
+ setInputValue('');
78
+ emitChange(undefined);
79
+ onClearButtonClick?.();
80
+ if (required) {
81
+ localRef.current?.focus();
82
+ handleOpenChange(true);
83
+ }
84
+ else {
85
+ localRef.current?.blur();
86
+ handleOpenChange(false);
87
+ }
88
+ }, [emitChange, handleOpenChange, onClearButtonClick, required]);
89
+ const onCopy = useCallback(async () => {
90
+ const copied = Boolean(inputValue) && (await copyTextToClipboard(inputValue));
91
+ if (copied) {
92
+ onCopyButtonClick?.();
93
+ }
94
+ return copied;
95
+ }, [inputValue, onCopyButtonClick]);
96
+ const showClearUi = Boolean(showClearButtonProp && inputValue && !disabled && !readOnly);
97
+ const showCopyUi = Boolean(showCopyButtonProp && inputValue && !disabled && readOnly);
98
+ const clearButtonSettings = useClearButton({
99
+ clearButtonRef,
100
+ showClearButton: showClearUi,
101
+ size: toInputSize(size),
102
+ onClear,
103
+ disabled: Boolean(disabled || readOnly),
104
+ });
105
+ const copyButtonSettings = useCopyButton({
106
+ copyButtonRef,
107
+ showCopyButton: showCopyUi,
108
+ size: toInputSize(size),
109
+ onCopy,
110
+ disabled: Boolean(disabled),
111
+ });
112
+ const { postfixButtons, inputTabIndex, onInputKeyDown } = useButtonNavigation({
113
+ inputRef: localRef,
114
+ postfixButtons: useMemo(() => [clearButtonSettings, copyButtonSettings], [clearButtonSettings, copyButtonSettings]),
115
+ readonly: Boolean(readOnly),
116
+ submitKeys: ['Enter', 'Space', 'Tab'],
117
+ });
118
+ const handleMouseEnter = useCallback(() => {
119
+ if (!readOnly && !disabled) {
120
+ setHover(true);
121
+ }
122
+ }, [readOnly, disabled]);
123
+ const handleMouseLeave = useCallback(() => {
124
+ setHover(false);
125
+ }, []);
126
+ const handleInputKeyDown = useCallback((event) => {
127
+ timeSeg.handleKeyDown(event);
128
+ // Нав-цепочка бежит безусловно ПОСЛЕ движка (легаси-порядок useHandlers): движок мутирует
129
+ // selection синхронно (ArrowRight на последнем сегменте ставит каретку в конец), nav читает
130
+ // её в том же keydown и забирает фокус на postfix-кнопки. Гейт по defaultPrevented оставлял
131
+ // clear/copy недостижимыми со стрелок — движок всегда делает preventDefault на ArrowRight.
132
+ onInputKeyDown(event);
133
+ }, [onInputKeyDown, timeSeg]);
134
+ // value ведёт сегментный движок (keydown); нативный onChange input'а игнорируем.
135
+ const handleInputChange = useCallback(() => undefined, []);
136
+ const handleInputFocus = useCallback((event) => {
137
+ setFocusVisible(event.target.matches(':focus-visible'));
138
+ timeSeg.handleFocus();
139
+ onFocusProp?.(event);
140
+ }, [onFocusProp, timeSeg]);
141
+ const handleInputBlur = useCallback((event) => {
142
+ setFocusVisible(false);
143
+ timeSeg.handleBlur();
144
+ onBlurProp?.(event);
145
+ }, [onBlurProp, timeSeg]);
146
+ const trigger = (_jsxs("div", { className: cn(fieldStyles.fieldWrapper, styles.trigger, fieldClassName), "data-size": size, "data-validation-state": effectiveValidationState, "data-disabled": disabled || undefined, "data-readonly": readOnly || undefined, "data-withbackground": background || undefined, "data-focusvisible": focusVisible || open || undefined, "data-hover": !readOnly && !disabled && hover ? true : undefined, "data-test-id": dataTestId, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [_jsxs("div", { className: fieldStyles.backgroundWrapper, children: [_jsx("div", { className: fieldStyles.materialLayer, ...getAcrylicProps({
147
+ validationState: effectiveValidationState,
148
+ disabled,
149
+ readonly: readOnly,
150
+ hover,
151
+ focusVisible: focusVisible || open,
152
+ }), children: _jsx("div", { className: fieldStyles.acrylicBg, "aria-hidden": true }) }), _jsx("div", { className: fieldStyles.borderStateLayer, "data-state": 'borderOnBackground' }), _jsx("div", { className: fieldStyles.focusLayer })] }), _jsx("div", { className: fieldStyles.fieldContainer, children: _jsxs("div", { className: fieldStyles.contentWrapper, children: [_jsx("div", { className: fieldStyles.inputLine, children: _jsxs("div", { className: fieldStyles.inputArea, children: [_jsx(InputPrivate, { ref: mergeRefs(ref, localRef), className: fieldStyles.fieldInput, value: inputValue, onChange: handleInputChange, disabled: disabled, readonly: readOnly, placeholder: placeholderMask, inputMode: INPUT_MODE.Numeric, tabIndex: inputTabIndex, onClick: timeSeg.handleClick, onPaste: timeSeg.handlePaste, onFocus: handleInputFocus, onBlur: handleInputBlur, onKeyDown: handleInputKeyDown, id: id, name: name, autoFocus: resolvedAutoFocus, "aria-haspopup": 'dialog', "aria-expanded": open, ...extractSupportProps(rest), "data-test-id": TEST_IDS.fieldTimeInput }), postfixButtons && _jsx("span", { className: fieldStyles.postfixButtonsSlot, children: postfixButtons })] }) }), _jsx("div", { className: fieldStyles.iconSlot, "data-test-id": TEST_IDS.fieldTimeIcon, "aria-hidden": true, children: _jsx(WatchSVG, {}) })] }) })] }));
153
+ return (_jsx(FieldDecorator, { className: className, label: label, labelTooltip: labelTooltip, caption: caption, hint: hint, error: error, validationState: validationState, showHintIcon: showHintIcon, length: length, required: required, labelFor: id, disabled: disabled, readonly: readOnly, size: size, children: _jsx(TimePickerDropdown
154
+ // Явный data-test-id на дропдауне → детерминированный id портального контента:
155
+ // `getTestIdBuilder` строит `content-${id}`, так контент адресуем для open-picker-снимка
156
+ // (без него контент рисуется без data-test-id, а в @cloud-ru/ds-fields::TEST_IDS такого слота нет).
157
+ , { "data-test-id": `${dataTestId}__picker`, size: size, value: value, onChangeValue: emitChange, showSeconds: showSeconds, closeOnApply: closeOnApply, open: open && !disabled && !readOnly, onOpenChange: handleOpenChange, trigger: 'click', placement: 'bottom-start', navigationStartRef: navigationStartRef, onFocusLeave: () => {
158
+ localRef.current?.focus();
159
+ handleOpenChange(false);
160
+ }, children: trigger }) }));
161
+ });
@@ -0,0 +1,2 @@
1
+ export * from './FieldTime.js';
2
+ export type { TimeValue } from '@cloud-ru/ds-calendar';
@@ -0,0 +1 @@
1
+ export * from './FieldTime.js';
@@ -0,0 +1,3 @@
1
+ import { TimeValue } from '@cloud-ru/ds-calendar';
2
+ export declare function parseTimeMask(input: string, showSeconds: boolean): TimeValue | undefined;
3
+ export declare function timeToMaskString(value: TimeValue, showSeconds: boolean): string;
@@ -0,0 +1,20 @@
1
+ function getMaxLen(showSeconds) {
2
+ return showSeconds ? 6 : 4;
3
+ }
4
+ export function parseTimeMask(input, showSeconds) {
5
+ const digits = input.replace(/\D/g, '');
6
+ const expected = getMaxLen(showSeconds);
7
+ if (digits.length !== expected)
8
+ return undefined;
9
+ const hours = Number(digits.slice(0, 2));
10
+ const minutes = Number(digits.slice(2, 4));
11
+ const seconds = showSeconds ? Number(digits.slice(4, 6)) : 0;
12
+ if (hours > 23 || minutes > 59 || seconds > 59)
13
+ return undefined;
14
+ return showSeconds ? { hours, minutes, seconds } : { hours, minutes };
15
+ }
16
+ export function timeToMaskString(value, showSeconds) {
17
+ const pad = (n) => String(n ?? 0).padStart(2, '0');
18
+ const head = `${pad(value.hours)}:${pad(value.minutes)}`;
19
+ return showSeconds ? `${head}:${pad(value.seconds)}` : head;
20
+ }
@@ -0,0 +1,3 @@
1
+ .trigger{
2
+ cursor:text;
3
+ }
@@ -0,0 +1,14 @@
1
+ export * from './FieldColor/index.js';
2
+ export * from './FieldCombo/index.js';
3
+ export * from './FieldDate/index.js';
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/index.js';
7
+ export * from './FieldSelect/index.js';
8
+ export * from './FieldSlider/index.js';
9
+ export * from './FieldStepper/index.js';
10
+ export * from './FieldText/index.js';
11
+ export * from './FieldTextArea/index.js';
12
+ export * from './FieldTime/index.js';
13
+ export { FieldShell } from './shared/index.js';
14
+ export type { FieldElementButtonProps, FieldShellProps } from './shared/index.js';
@@ -0,0 +1,12 @@
1
+ export * from './FieldColor/index.js';
2
+ export * from './FieldCombo/index.js';
3
+ export * from './FieldDate/index.js';
4
+ export { SIZE, VALIDATION_STATE } from '@cloud-ru/ds-field-decorator';
5
+ export * from './FieldSecure/index.js';
6
+ export * from './FieldSelect/index.js';
7
+ export * from './FieldSlider/index.js';
8
+ export * from './FieldStepper/index.js';
9
+ export * from './FieldText/index.js';
10
+ export * from './FieldTextArea/index.js';
11
+ export * from './FieldTime/index.js';
12
+ export { FieldShell } from './shared/index.js';
@@ -0,0 +1,35 @@
1
+ import { KeyboardEvent, ReactNode } from 'react';
2
+ import { ButtonSize, Variant } from './types.js';
3
+ export type FieldElementButtonProps = {
4
+ /** Положение относительно поля */
5
+ variant: Variant;
6
+ /**
7
+ * Размер (совпадает с размером поля)
8
+ * @default 'm'
9
+ */
10
+ size?: ButtonSize;
11
+ /** Состояние загрузки */
12
+ loading?: boolean;
13
+ /** Деактивировано */
14
+ disabled?: boolean;
15
+ /** Содержимое (иконка и т.д.) */
16
+ action: ReactNode;
17
+ /** Показать шеврон раскрытия */
18
+ withDropdownList?: boolean;
19
+ /**
20
+ * Контролируемое состояние раскрытия (используется обёрткой `FieldElementButtonList`).
21
+ * Если задано — шеврон отражает это значение; иначе кнопка управляет шевроном сама.
22
+ */
23
+ open?: boolean;
24
+ /** Обработчик нажатия клавиш (передаётся обёрткой `Droplist` для ArrowDown/ArrowUp) */
25
+ onKeyDown?(event: KeyboardEvent<HTMLButtonElement>): void;
26
+ /** Обработчик клика */
27
+ onClick?(): void;
28
+ /** HTML tabIndex (`-1` — исключить кнопку из tab-order, фокус по Tab уходит в поле) */
29
+ tabIndex?: number;
30
+ /** CSS-класс (передаётся обёрткой `Droplist` / `PopoverPrivate` на триггер) */
31
+ className?: string;
32
+ /** data-test-id кнопки-слота */
33
+ 'data-test-id'?: string;
34
+ };
35
+ export declare const FieldElementButton: import("react").ForwardRefExoticComponent<FieldElementButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,41 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ChevronDownSVG, ChevronUpSVG } from '@cloud-ru/ds-icons/interface/system';
3
+ import { Sun, SUN_SIZE } from '@cloud-ru/ds-loader';
4
+ import cn from 'classnames';
5
+ import { forwardRef, useCallback, useState } from 'react';
6
+ import { BUTTON_SIZE } from './constants.js';
7
+ import styles from './styles.module.css';
8
+ const SUN_SIZE_MAP = {
9
+ [BUTTON_SIZE.S]: SUN_SIZE.XS,
10
+ [BUTTON_SIZE.M]: SUN_SIZE.S,
11
+ [BUTTON_SIZE.L]: SUN_SIZE.S,
12
+ };
13
+ export const FieldElementButton = forwardRef(function FieldElementButton({ size = BUTTON_SIZE.M, loading = false, disabled = false, onClick, onKeyDown, withDropdownList, open, variant, action, className, tabIndex, 'data-test-id': dataTestId, }, ref) {
14
+ const [isListOpen, setListOpen] = useState(false);
15
+ const [stateLayerPressed, setStateLayerPressed] = useState(false);
16
+ // Если `open` контролируется снаружи (FieldElementButtonList) — шеврон следует за ним,
17
+ // иначе кнопка хранит состояние раскрытия сама.
18
+ const listOpen = open ?? isListOpen;
19
+ const handleListToggleClick = useCallback(() => {
20
+ setListOpen(prevOpen => !prevOpen);
21
+ onClick?.();
22
+ }, [onClick]);
23
+ const handleKeyDown = useCallback((event) => {
24
+ if (disabled || loading) {
25
+ return;
26
+ }
27
+ if (event.key === 'Enter' && !event.repeat) {
28
+ setStateLayerPressed(true);
29
+ }
30
+ onKeyDown?.(event);
31
+ }, [disabled, loading, onKeyDown]);
32
+ const handleKeyUp = useCallback((event) => {
33
+ if (event.key === 'Enter') {
34
+ setStateLayerPressed(false);
35
+ }
36
+ }, []);
37
+ const handleBlur = useCallback(() => {
38
+ setStateLayerPressed(false);
39
+ }, []);
40
+ return (_jsxs("button", { ref: ref, type: 'button', className: cn(styles.buttonContainer, className), onClick: loading || disabled ? undefined : handleListToggleClick, onKeyDown: handleKeyDown, onKeyUp: handleKeyUp, onBlur: handleBlur, disabled: disabled || loading || undefined, tabIndex: tabIndex, "data-size": size, "data-variant": variant, "data-loading": loading || undefined, "data-disabled": disabled || undefined, "data-pressed": stateLayerPressed ? true : undefined, "data-test-id": dataTestId, children: [_jsx("div", { className: styles.backgroundStateLayer, "data-state": 'emptyNeutralOnBackground' }), _jsx("div", { className: styles.focusLayer, "aria-hidden": true }), _jsxs("div", { className: styles.elementWrapper, children: [loading && !disabled ? _jsx(Sun, { size: SUN_SIZE_MAP[size] }) : action, withDropdownList && _jsx("div", { className: styles.chevron, children: listOpen ? _jsx(ChevronUpSVG, {}) : _jsx(ChevronDownSVG, {}) })] })] }));
41
+ });