@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,374 @@
1
+ import { FieldDecorator, FieldDecoratorProps, SIZE, VALIDATION_STATE } from '@cloud-ru/ds-field-decorator';
2
+ import { useButtonNavigation, useClearButton } from '@cloud-ru/ds-input-private';
3
+ import { BAR_HIDE_STRATEGY, RESIZE, Scroll, SIZE as SCROLL_SIZE } from '@cloud-ru/ds-scroll';
4
+ import { extractSupportProps, useValueControl } from '@cloud-ru/ds-utils';
5
+ import cn from 'classnames';
6
+ import mergeRefs from 'merge-refs';
7
+ import {
8
+ ChangeEvent,
9
+ CSSProperties,
10
+ FocusEvent,
11
+ forwardRef,
12
+ HTMLAttributes,
13
+ KeyboardEvent,
14
+ MouseEvent,
15
+ ReactNode,
16
+ useCallback,
17
+ useMemo,
18
+ useRef,
19
+ useState,
20
+ } from 'react';
21
+ import TextareaAutosize from 'react-textarea-autosize';
22
+
23
+ import { TEST_IDS } from '../../constants';
24
+ import { FieldLayoutPresets, useAdaptiveAutoFocus } from '../../hooks';
25
+ import { copyTextToClipboard, FieldShell, toInputSize, useCopyButton } from '../shared';
26
+ import fieldStyles from '../shared/styles.module.scss';
27
+ import styles from './styles.module.scss';
28
+
29
+ type FieldTextAreaDecoratorProps = Omit<FieldDecoratorProps, 'children'>;
30
+
31
+ type FieldTextAreaOwnProps = {
32
+ /** CSS-класс корня `FieldDecorator` */
33
+ className?: string;
34
+ /** CSS-класс оболочки поля */
35
+ fieldClassName?: string;
36
+ /** Значение (controlled-режим) */
37
+ value?: string;
38
+ /** Начальное значение (uncontrolled-режим) */
39
+ defaultValue?: string;
40
+ /** Колбек смены значения */
41
+ onChange?(value: string, event?: ChangeEvent<HTMLTextAreaElement>): void;
42
+ /** Плейсхолдер */
43
+ placeholder?: string;
44
+ /** HTML id */
45
+ id?: string;
46
+ /** HTML name */
47
+ name?: string;
48
+ /** Максимальное количество символов */
49
+ maxLength?: number;
50
+ /** Поле выключено */
51
+ disabled?: boolean;
52
+ /** Только для чтения */
53
+ readonly?: boolean;
54
+ /** Автофокус. На mobile выключается адаптивно (см. `layoutPresets`) */
55
+ autoFocus?: boolean;
56
+ /**
57
+ * Переопределение адаптивных дефолтов по раскладке. Участвует `autoFocus`: на mobile он выключен
58
+ * (открывает клавиатуру без действия). Вернуть на mobile — `layoutPresets={{ mobile: { autoFocus: true } }}`.
59
+ */
60
+ layoutPresets?: FieldLayoutPresets;
61
+ /** Режим виртуальной клавиатуры (`inputmode` нативного `<textarea>`) */
62
+ inputMode?: HTMLAttributes<HTMLTextAreaElement>['inputMode'];
63
+ /** Проверка орфографии */
64
+ spellCheck?: boolean;
65
+ /**
66
+ * Минимальное количество строк
67
+ * @default 3
68
+ */
69
+ minRows?: number;
70
+ /**
71
+ * Максимальное количество строк (после — появляется скролл)
72
+ * @default 1000
73
+ */
74
+ maxRows?: number;
75
+ /**
76
+ * Разрешить ввод свыше `maxLength` символов (счётчик продолжит расти).
77
+ * @default true
78
+ */
79
+ allowMoreThanMaxLength?: boolean;
80
+ /**
81
+ * Нода над textarea — ряд элементов до контента (Figma `elementWrapperBefore` /
82
+ * `slotBeforeContent`): тулбар с кнопками, чипами и т.п.
83
+ */
84
+ header?: ReactNode;
85
+ /**
86
+ * Нода под textarea — ряд элементов после контента (Figma `elementWrapperAfter` /
87
+ * `slotAfterContent`): действия, счётчик-плагин и т.п.
88
+ */
89
+ footer?: ReactNode;
90
+ /**
91
+ * Можно ли менять высоту мышкой за нижний угол. Игнорируется при `disabled` или `readonly`.
92
+ * @default false
93
+ */
94
+ resizable?: boolean;
95
+ /**
96
+ * Фон поля (acrylic)
97
+ * @default true
98
+ */
99
+ background?: boolean;
100
+ /**
101
+ * Кнопка очистки (видна при value && !readonly)
102
+ * @default true
103
+ */
104
+ showClearButton?: boolean;
105
+ /**
106
+ * Кнопка копирования (видна при value && !disabled, независимо от readonly)
107
+ * @default true
108
+ */
109
+ showCopyButton?: boolean;
110
+ /** Колбек после копирования */
111
+ onCopyButtonClick?(): void;
112
+ /** Колбек фокуса */
113
+ onFocus?(event: FocusEvent<HTMLTextAreaElement>): void;
114
+ /** Колбек блюра */
115
+ onBlur?(event: FocusEvent<HTMLTextAreaElement>): void;
116
+ /** Колбек нажатия клавиши */
117
+ onKeyDown?(event: KeyboardEvent<HTMLTextAreaElement>): void;
118
+ };
119
+
120
+ export type FieldTextAreaProps = FieldTextAreaDecoratorProps & FieldTextAreaOwnProps;
121
+
122
+ export const FieldTextArea = forwardRef<HTMLTextAreaElement, FieldTextAreaProps>(function FieldTextArea(
123
+ {
124
+ label = '',
125
+ labelTooltip,
126
+ caption,
127
+ hint,
128
+ error,
129
+ validationState = VALIDATION_STATE.Default,
130
+ showHintIcon,
131
+ length,
132
+ required,
133
+ size = SIZE.M,
134
+ className,
135
+ fieldClassName,
136
+ background = true,
137
+ value: valueProp,
138
+ defaultValue = '',
139
+ onChange,
140
+ placeholder,
141
+ id,
142
+ name,
143
+ maxLength,
144
+ disabled,
145
+ readonly: readOnly,
146
+ autoFocus,
147
+ layoutPresets,
148
+ inputMode,
149
+ spellCheck,
150
+ minRows = 3,
151
+ maxRows = 1000,
152
+ resizable = false,
153
+ allowMoreThanMaxLength = true,
154
+ header,
155
+ footer,
156
+ showClearButton: showClearButtonProp = true,
157
+ showCopyButton: showCopyButtonProp = true,
158
+ onCopyButtonClick,
159
+ onFocus: onFocusProp,
160
+ onBlur: onBlurProp,
161
+ onKeyDown: onKeyDownProp,
162
+ 'data-test-id': dataTestId,
163
+ ...rest
164
+ },
165
+ ref,
166
+ ) {
167
+ const localRef = useRef<HTMLTextAreaElement>(null);
168
+ const clearButtonRef = useRef<HTMLButtonElement>(null);
169
+ const copyButtonRef = useRef<HTMLButtonElement>(null);
170
+ const [focusVisible, setFocusVisible] = useState(false);
171
+ const [hover, setHover] = useState(false);
172
+
173
+ const resolvedAutoFocus = useAdaptiveAutoFocus(autoFocus, layoutPresets);
174
+
175
+ // controlled/uncontrolled: useValueControl держит внутреннее состояние при отсутствии `value`,
176
+ // событие в `onChange` пробрасываем сами (useValueControl передаёт только значение).
177
+ const [value = '', setValue] = useValueControl<string>({ value: valueProp, defaultValue });
178
+
179
+ const effectiveValidationState = useMemo(
180
+ () => (error ? VALIDATION_STATE.Error : validationState),
181
+ [error, validationState],
182
+ );
183
+
184
+ const stringValue = String(value ?? '');
185
+ const isResizable = resizable && !disabled && !readOnly;
186
+ const showClearUi = Boolean(showClearButtonProp && stringValue && !readOnly && !disabled);
187
+ // Copy не завязан на readonly (паритет с snack-uikit master): виден при любом непустом значении.
188
+ // В editable-режиме показываются обе кнопки (clear + copy), в readonly — только copy.
189
+ const showCopyUi = Boolean(showCopyButtonProp && stringValue && !disabled);
190
+
191
+ const onClear = useCallback(() => {
192
+ setValue('');
193
+ onChange?.('');
194
+ localRef.current?.focus();
195
+ }, [onChange, setValue]);
196
+
197
+ const onCopy = useCallback(async () => {
198
+ const copied = await copyTextToClipboard(stringValue);
199
+ if (copied) {
200
+ onCopyButtonClick?.();
201
+ }
202
+ return copied;
203
+ }, [onCopyButtonClick, stringValue]);
204
+
205
+ const clearButtonSettings = useClearButton({
206
+ clearButtonRef,
207
+ showClearButton: showClearUi,
208
+ size: toInputSize(size),
209
+ onClear,
210
+ disabled: Boolean(disabled || readOnly),
211
+ });
212
+
213
+ const copyButtonSettings = useCopyButton({
214
+ copyButtonRef,
215
+ showCopyButton: showCopyUi,
216
+ size: toInputSize(size),
217
+ onCopy,
218
+ disabled: Boolean(disabled),
219
+ });
220
+
221
+ const { postfixButtons, inputTabIndex, onInputKeyDown } = useButtonNavigation<HTMLTextAreaElement>({
222
+ inputRef: localRef,
223
+ postfixButtons: useMemo(() => [clearButtonSettings, copyButtonSettings], [clearButtonSettings, copyButtonSettings]),
224
+ readonly: Boolean(readOnly),
225
+ submitKeys: ['Tab'],
226
+ });
227
+
228
+ const handleKeyDown = useCallback(
229
+ (event: KeyboardEvent<HTMLTextAreaElement>) => {
230
+ onKeyDownProp?.(event);
231
+ onInputKeyDown(event);
232
+ },
233
+ [onInputKeyDown, onKeyDownProp],
234
+ );
235
+
236
+ const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
237
+ setValue(event.target.value);
238
+ onChange?.(event.target.value, event);
239
+ };
240
+
241
+ // Клик в «пустую» зону поля (под textarea при minRows-резерве, в правый резерв под кнопки)
242
+ // фокусит textarea и ставит курсор в конец — паритет со снеком, где попадание в любую область
243
+ // поля работает как клик по textarea. Намеренно `onClick`, а не `onMouseDown`+preventDefault:
244
+ // resize-ручка scroll-контейнера тоже работает через mousedown-drag, и preventDefault убивал бы
245
+ // нативный CSS-resize. Click после resize-drag не возникает, а клики по textarea, кнопкам
246
+ // clear/copy и DS-скроллбару отсеиваем по target.
247
+ const handleContentClick = useCallback(
248
+ (event: MouseEvent<HTMLDivElement>) => {
249
+ const target = event.target as HTMLElement;
250
+ if (disabled || target === localRef.current || target.closest('button, [class*="os-scrollbar"]')) {
251
+ return;
252
+ }
253
+ const textarea = localRef.current;
254
+ if (textarea) {
255
+ textarea.focus();
256
+ const end = textarea.value.length;
257
+ textarea.setSelectionRange(end, end);
258
+ }
259
+ },
260
+ [disabled],
261
+ );
262
+
263
+ const handleFocus = useCallback(
264
+ (event: FocusEvent<HTMLTextAreaElement>) => {
265
+ setFocusVisible(event.target.matches(':focus-visible'));
266
+ onFocusProp?.(event);
267
+ },
268
+ [onFocusProp],
269
+ );
270
+
271
+ const handleBlur = useCallback(
272
+ (event: FocusEvent<HTMLTextAreaElement>) => {
273
+ setFocusVisible(false);
274
+ onBlurProp?.(event);
275
+ },
276
+ [onBlurProp],
277
+ );
278
+
279
+ const handleMouseEnter = useCallback(() => {
280
+ if (!readOnly) {
281
+ setHover(true);
282
+ }
283
+ }, [readOnly]);
284
+
285
+ const handleMouseLeave = useCallback(() => {
286
+ setHover(false);
287
+ }, []);
288
+
289
+ const shell = (
290
+ <FieldShell
291
+ data-test-id={TEST_IDS.fieldTextAreaShell}
292
+ className={fieldClassName}
293
+ size={size}
294
+ validationState={effectiveValidationState}
295
+ disabled={disabled}
296
+ readonly={readOnly}
297
+ background={background}
298
+ focusVisible={focusVisible}
299
+ hover={hover}
300
+ header={header}
301
+ footer={footer}
302
+ style={{ '--field-textarea-min-rows': minRows, '--field-textarea-max-rows': maxRows } as CSSProperties}
303
+ onMouseEnter={handleMouseEnter}
304
+ onMouseLeave={handleMouseLeave}
305
+ >
306
+ {/* onClick лишь форвардит фокус в textarea (реальный фокусируемый/клавиатурный элемент
307
+ рядом) при клике в пустую зону поля — это не самостоятельный контрол, клавиатурный
308
+ доступ обеспечивает сама textarea, поэтому role/tabIndex здесь не нужны. */}
309
+ {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
310
+ <div className={cn(fieldStyles.contentWrapper, styles.contentArea)} onClick={handleContentClick}>
311
+ {/* Скролл при превышении maxRows — кастомный из @cloud-ru/ds-scroll (по Figma), не нативный
312
+ скроллбар textarea. maxRows задаёт max-height контейнера через CSS-переменные,
313
+ autosize-textarea растёт внутри, Scroll рисует DS-скроллбар. Resize-handle —
314
+ на scroll-контейнере (CSS resize), не на самой textarea. */}
315
+ <Scroll
316
+ className={cn(styles.scrollContainer, { [styles.scrollContainerResizable]: isResizable })}
317
+ size={SCROLL_SIZE.S}
318
+ barHideStrategy={BAR_HIDE_STRATEGY.Never}
319
+ resize={isResizable ? RESIZE.Vertical : RESIZE.None}
320
+ overflow={{ x: 'hidden' }}
321
+ data-test-id={TEST_IDS.fieldTextAreaScrollArea}
322
+ >
323
+ <div className={fieldStyles.inputLine}>
324
+ <TextareaAutosize
325
+ ref={mergeRefs(ref, localRef)}
326
+ className={styles.textarea}
327
+ value={value}
328
+ onChange={handleChange}
329
+ placeholder={placeholder}
330
+ disabled={disabled}
331
+ readOnly={readOnly}
332
+ id={id}
333
+ name={name}
334
+ maxLength={allowMoreThanMaxLength ? undefined : maxLength}
335
+ autoFocus={resolvedAutoFocus}
336
+ inputMode={inputMode}
337
+ spellCheck={spellCheck}
338
+ minRows={minRows}
339
+ tabIndex={inputTabIndex}
340
+ data-test-id={TEST_IDS.fieldTextAreaInput}
341
+ onFocus={handleFocus}
342
+ onBlur={handleBlur}
343
+ onKeyDown={handleKeyDown}
344
+ {...extractSupportProps(rest)}
345
+ />
346
+ </div>
347
+ </Scroll>
348
+ {postfixButtons && <span className={styles.postfixColumn}>{postfixButtons}</span>}
349
+ </div>
350
+ </FieldShell>
351
+ );
352
+
353
+ return (
354
+ <FieldDecorator
355
+ className={className}
356
+ label={label}
357
+ labelTooltip={labelTooltip}
358
+ caption={caption}
359
+ hint={hint}
360
+ error={error}
361
+ validationState={validationState}
362
+ showHintIcon={showHintIcon}
363
+ length={length ?? (maxLength ? { current: stringValue.length, max: maxLength } : undefined)}
364
+ required={required}
365
+ labelFor={id}
366
+ disabled={disabled}
367
+ readonly={readOnly}
368
+ size={size}
369
+ data-test-id={dataTestId}
370
+ >
371
+ {shell}
372
+ </FieldDecorator>
373
+ );
374
+ });
@@ -0,0 +1 @@
1
+ export * from './FieldTextArea';
@@ -0,0 +1,192 @@
1
+ @use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
2
+ @use '@cloud-ru/ds-figma-variables/build/scss/components/field.module' as field;
3
+ @use '@cloud-ru/ds-figma-variables/build/scss/components/scroll.module' as scroll;
4
+
5
+ $sizes: 's', 'm', 'l';
6
+
7
+ // Ширина вертикального скроллбара @cloud-ru/ds-scroll (в компоненте он всегда size=s).
8
+ $scrollbar-width: base.simple-var(scroll.$scroll, 'anatomy', 'container', 'size', 's', 'width');
9
+
10
+ // Контейнер скролла (@cloud-ru/ds-scroll) вокруг textarea: minRows/maxRows клампят его высоту
11
+ // через CSS-переменные (выставляются компонентом на shell), autosize-textarea растёт внутри,
12
+ // скроллбар — кастомный DS, не нативный. Resize-handle (CSS resize) живёт на этом контейнере.
13
+ .scrollContainer {
14
+ flex: 1 1 auto;
15
+ min-width: 0;
16
+ min-height: calc(var(--field-textarea-min-rows, 3) * var(--field-textarea-row-height));
17
+ max-height: calc(var(--field-textarea-max-rows, 1000) * var(--field-textarea-row-height));
18
+
19
+ // Высота строки = line-height DS-типографики body соответствующего size.
20
+ @each $size in $sizes {
21
+ [data-size='#{$size}'] & {
22
+ --field-textarea-row-height: #{base.simple-var(base.$sn-regular, 'body', $size, 'line-height')};
23
+ }
24
+ }
25
+ }
26
+
27
+ // При resizable стартовая высота фиксируется на minRows — иначе CSS resize
28
+ // не от чего отсчитывать (контейнер с auto-высотой схлопывается обратно).
29
+ .scrollContainerResizable {
30
+ height: calc(var(--field-textarea-min-rows, 3) * var(--field-textarea-row-height));
31
+ }
32
+
33
+ .textarea {
34
+ resize: none;
35
+
36
+ // Нативный скроллбар не показывается никогда — скролл рисует обёртка @cloud-ru/ds-scroll.
37
+ overflow: hidden;
38
+
39
+ width: 100%;
40
+ min-width: 0;
41
+ padding: 0;
42
+ border: none;
43
+
44
+ color: base.$sn-theme-color-available-version-textMain;
45
+
46
+ background: transparent;
47
+ outline: none;
48
+
49
+ &::placeholder {
50
+ color: base.$sn-theme-color-available-version-textDisabled;
51
+ opacity: 1;
52
+ }
53
+
54
+ // disabled-поле затемняется opacity 0.4, placeholder уже textDisabled → бледный «призрак».
55
+ // Прячем целиком, как в @cloud-ru/ds-search (единый паттерн disabled в DS).
56
+ // TODO: выяснить у дизайнера ожидаемое поведение placeholder в disabled (скрывать / приглушать).
57
+ &:disabled::placeholder {
58
+ visibility: hidden;
59
+ }
60
+
61
+ // readonly текст приглушается так же, как .fieldInput в FieldText
62
+ // (общий shell, но textarea рендерит свой класс, не .fieldInput).
63
+ &:read-only {
64
+ color: base.$sn-theme-color-available-version-textTertiary;
65
+ }
66
+
67
+ // DS-типографика + min-height multiLine из field-токенов per-size.
68
+ // Без этого textarea наследует Nunito Sans 16/24 от Storybook root и не имеет минимальной высоты.
69
+ @each $size in $sizes {
70
+ [data-size='#{$size}'] & {
71
+ // Резерв справа под колонку clear/copy-кнопок (квадрат centeredWrapper) + скроллбар
72
+ // + горизонтальный паддинг inputLine (отступ слота кнопок от скроллбара по Figma):
73
+ // кнопки позиционируются абсолютно поверх скролл-области (см. .postfixColumn).
74
+ $button-slot: base.simple-var(
75
+ field.$field,
76
+ 'anatomy',
77
+ 'size',
78
+ $size,
79
+ 'fieldContainer',
80
+ 'centeredWrapper',
81
+ 'max-height'
82
+ );
83
+ $input-line-padding: base.simple-var(
84
+ field.$field,
85
+ 'anatomy',
86
+ 'size',
87
+ $size,
88
+ 'fieldContainer',
89
+ 'contentWrapper',
90
+ 'inputLine',
91
+ 'padding-right'
92
+ );
93
+
94
+ min-height: base.simple-var(field.$field, 'anatomy', 'size', $size, 'fieldContainer', 'multiLine', 'min-height');
95
+ padding-right: calc(#{$button-slot} + #{$scrollbar-width} + #{$input-line-padding});
96
+
97
+ @include base.composite-var(base.$sn-regular, 'body', $size);
98
+ }
99
+ }
100
+ }
101
+
102
+ // Якорь для абсолютного позиционирования кнопок: скролл-контейнер занимает всю ширину
103
+ // контента (скроллбар — у правого края поля, по Figma), кнопки накладываются поверх.
104
+ // verticalPadding (Figma contentWrapper py) опускает первую строку текста на свой отступ —
105
+ // без него текст (и центрированная по нему кнопка) прижимается к верхней рамке, и 32px-кнопка
106
+ // выступает за верхний край поля.
107
+ .contentArea {
108
+ position: relative;
109
+
110
+ @each $size in $sizes {
111
+ [data-size='#{$size}'] & {
112
+ padding-top: base.simple-var(
113
+ field.$field,
114
+ 'anatomy',
115
+ 'size',
116
+ $size,
117
+ 'fieldContainer',
118
+ 'contentWrapper',
119
+ 'padding-top'
120
+ );
121
+ padding-bottom: base.simple-var(
122
+ field.$field,
123
+ 'anatomy',
124
+ 'size',
125
+ $size,
126
+ 'fieldContainer',
127
+ 'contentWrapper',
128
+ 'padding-bottom'
129
+ );
130
+ }
131
+ }
132
+ }
133
+
134
+ // Кнопки clear/copy — поверх скролл-области, левее скроллбара (паритет с Figma и легаси:
135
+ // порядок справа налево — край поля, скроллбар, inputLine-паддинг, кнопки). Место под них
136
+ // резервирует padding-right textarea выше. Grid-ячейки клампят слот каждой кнопки до
137
+ // centeredWrapper-квадрата: сама кнопка крупнее слота и симметрично выступает за него
138
+ // (тот же приём, что .postfixButtonsSlot в shared/styles для FieldText), первый слот
139
+ // центрируется по первой строке текста.
140
+ .postfixColumn {
141
+ position: absolute;
142
+
143
+ display: grid;
144
+
145
+ // Единственный явный column-track шириной с контейнер: без него implicit-колонка
146
+ // растягивается (auto) под кнопку, и кнопка перестаёт центрироваться по слоту.
147
+ grid-template-columns: 100%;
148
+ row-gap: base.$sn-primitive-dimension-2;
149
+ place-items: center center;
150
+
151
+ @each $size in $sizes {
152
+ [data-size='#{$size}'] & {
153
+ $square: base.simple-var(
154
+ field.$field,
155
+ 'anatomy',
156
+ 'size',
157
+ $size,
158
+ 'fieldContainer',
159
+ 'centeredWrapper',
160
+ 'max-height'
161
+ );
162
+ $input-line-padding: base.simple-var(
163
+ field.$field,
164
+ 'anatomy',
165
+ 'size',
166
+ $size,
167
+ 'fieldContainer',
168
+ 'contentWrapper',
169
+ 'inputLine',
170
+ 'padding-right'
171
+ );
172
+ $line-height: base.simple-var(base.$sn-regular, 'body', $size, 'line-height');
173
+ $vertical-padding: base.simple-var(
174
+ field.$field,
175
+ 'anatomy',
176
+ 'size',
177
+ $size,
178
+ 'fieldContainer',
179
+ 'contentWrapper',
180
+ 'padding-top'
181
+ );
182
+
183
+ // Кнопка центрируется по первой строке текста: verticalPadding (отступ контента сверху)
184
+ // + центровка слота в line-height. Так 32px-кнопка верхним краем садится ровно на
185
+ // внутреннюю границу поля (Figma), а не выступает над ней.
186
+ top: calc(#{$vertical-padding} + (#{$line-height} - #{$square}) / 2);
187
+ right: calc(#{$scrollbar-width} + #{$input-line-padding});
188
+ grid-auto-rows: $square;
189
+ width: $square;
190
+ }
191
+ }
192
+ }