react-miui 0.34.0 → 0.36.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 (427) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/CHANGELOG.md +17 -0
  3. package/dist/components/form/index.d.ts +1 -0
  4. package/dist/components/form/index.d.ts.map +1 -1
  5. package/dist/components/form/index.js +1 -0
  6. package/dist/components/form/index.js.map +1 -1
  7. package/dist/components/form/input/Input.d.ts.map +1 -1
  8. package/dist/components/form/input/Input.js +9 -5
  9. package/dist/components/form/input/Input.js.map +1 -1
  10. package/dist/components/form/timepicker/TimePicker.css.d.ts +99 -0
  11. package/dist/components/form/timepicker/TimePicker.css.d.ts.map +1 -0
  12. package/dist/components/form/timepicker/TimePicker.css.js +116 -0
  13. package/dist/components/form/timepicker/TimePicker.css.js.map +1 -0
  14. package/dist/components/form/timepicker/TimePicker.d.ts +22 -0
  15. package/dist/components/form/timepicker/TimePicker.d.ts.map +1 -0
  16. package/dist/components/form/timepicker/TimePicker.js +141 -0
  17. package/dist/components/form/timepicker/TimePicker.js.map +1 -0
  18. package/dist/components/form/timepicker/TimePicker.styled.d.ts +936 -0
  19. package/dist/components/form/timepicker/TimePicker.styled.d.ts.map +1 -0
  20. package/dist/components/form/timepicker/TimePicker.styled.js +29 -0
  21. package/dist/components/form/timepicker/TimePicker.styled.js.map +1 -0
  22. package/dist/components/form/timepicker/TimePickerModal.d.ts +17 -0
  23. package/dist/components/form/timepicker/TimePickerModal.d.ts.map +1 -0
  24. package/dist/components/form/timepicker/TimePickerModal.js +92 -0
  25. package/dist/components/form/timepicker/TimePickerModal.js.map +1 -0
  26. package/dist/components/form/timepicker/Wheel.d.ts +12 -0
  27. package/dist/components/form/timepicker/Wheel.d.ts.map +1 -0
  28. package/dist/components/form/timepicker/Wheel.js +187 -0
  29. package/dist/components/form/timepicker/Wheel.js.map +1 -0
  30. package/dist/components/form/timepicker/utils.d.ts +4 -0
  31. package/dist/components/form/timepicker/utils.d.ts.map +1 -0
  32. package/dist/components/form/timepicker/utils.js +62 -0
  33. package/dist/components/form/timepicker/utils.js.map +1 -0
  34. package/dist/components/icons/Clock.d.ts +7 -0
  35. package/dist/components/icons/Clock.d.ts.map +1 -0
  36. package/dist/components/icons/Clock.js +45 -0
  37. package/dist/components/icons/Clock.js.map +1 -0
  38. package/dist/components/icons/Icon.d.ts +2 -1
  39. package/dist/components/icons/Icon.d.ts.map +1 -1
  40. package/dist/components/icons/Icon.js +3 -0
  41. package/dist/components/icons/Icon.js.map +1 -1
  42. package/dist/components/layout/header/HeaderIconAction.d.ts.map +1 -1
  43. package/dist/components/layout/header/HeaderIconAction.js +13 -3
  44. package/dist/components/layout/header/HeaderIconAction.js.map +1 -1
  45. package/dist/components/layout/header/HeaderIconAction.styled.d.ts.map +1 -1
  46. package/dist/components/layout/header/HeaderIconAction.styled.js +11 -17
  47. package/dist/components/layout/header/HeaderIconAction.styled.js.map +1 -1
  48. package/dist/components/layout/list/Item.d.ts.map +1 -1
  49. package/dist/components/layout/list/Item.js +17 -7
  50. package/dist/components/layout/list/Item.js.map +1 -1
  51. package/dist/components/layout/list/Item.styled.d.ts.map +1 -1
  52. package/dist/components/layout/list/Item.styled.js +2 -1
  53. package/dist/components/layout/list/Item.styled.js.map +1 -1
  54. package/dist/components/ui/button/Button.d.ts +94 -1
  55. package/dist/components/ui/button/Button.d.ts.map +1 -1
  56. package/dist/components/ui/button/Button.js +59 -2
  57. package/dist/components/ui/button/Button.js.map +1 -1
  58. package/dist/components/ui/button/Button.styled.d.ts +2 -2
  59. package/dist/components/ui/button/Button.styled.d.ts.map +1 -1
  60. package/dist/components/ui/button/Button.styled.js +4 -3
  61. package/dist/components/ui/button/Button.styled.js.map +1 -1
  62. package/dist/components/ui/directionPad/Button.d.ts.map +1 -1
  63. package/dist/components/ui/directionPad/Button.js +7 -2
  64. package/dist/components/ui/directionPad/Button.js.map +1 -1
  65. package/dist/components/ui/directionPad/Button.styled.d.ts.map +1 -1
  66. package/dist/components/ui/directionPad/Button.styled.js +2 -1
  67. package/dist/components/ui/directionPad/Button.styled.js.map +1 -1
  68. package/dist/components/ui/directionPad/Middle.d.ts.map +1 -1
  69. package/dist/components/ui/directionPad/Middle.js +7 -1
  70. package/dist/components/ui/directionPad/Middle.js.map +1 -1
  71. package/dist/components/ui/directionPad/Middle.styled.d.ts.map +1 -1
  72. package/dist/components/ui/directionPad/Middle.styled.js +2 -1
  73. package/dist/components/ui/directionPad/Middle.styled.js.map +1 -1
  74. package/dist/components/ui/modal/Modal.d.ts +1 -2
  75. package/dist/components/ui/modal/Modal.d.ts.map +1 -1
  76. package/dist/components/ui/modal/Modal.js +114 -42
  77. package/dist/components/ui/modal/Modal.js.map +1 -1
  78. package/dist/components/ui/modal/Modal.styled.d.ts +1 -1
  79. package/dist/components/ui/modal/Modal.styled.d.ts.map +1 -1
  80. package/dist/components/ui/modal/Modal.styled.js +40 -25
  81. package/dist/components/ui/modal/Modal.styled.js.map +1 -1
  82. package/dist/components/ui/modal/ModalButtons.d.ts +179 -1
  83. package/dist/components/ui/modal/ModalButtons.d.ts.map +1 -1
  84. package/dist/components/ui/modal/ModalButtons.js +63 -2
  85. package/dist/components/ui/modal/ModalButtons.js.map +1 -1
  86. package/dist/components/ui/modal/ModalButtons.styled.d.ts +90 -91
  87. package/dist/components/ui/modal/ModalButtons.styled.d.ts.map +1 -1
  88. package/dist/components/ui/modal/ModalButtons.styled.js +5 -7
  89. package/dist/components/ui/modal/ModalButtons.styled.js.map +1 -1
  90. package/dist/components/ui/pop/Pop.styled.d.ts.map +1 -1
  91. package/dist/components/ui/pop/Pop.styled.js +15 -17
  92. package/dist/components/ui/pop/Pop.styled.js.map +1 -1
  93. package/dist/components/ui/pop/PopOption.d.ts.map +1 -1
  94. package/dist/components/ui/pop/PopOption.js +7 -2
  95. package/dist/components/ui/pop/PopOption.js.map +1 -1
  96. package/dist/components/ui/toolButton/ToolButton.d.ts +94 -1
  97. package/dist/components/ui/toolButton/ToolButton.d.ts.map +1 -1
  98. package/dist/components/ui/toolButton/ToolButton.js +59 -2
  99. package/dist/components/ui/toolButton/ToolButton.js.map +1 -1
  100. package/dist/components/ui/toolButton/ToolButton.styled.d.ts +2 -2
  101. package/dist/components/ui/toolButton/ToolButton.styled.d.ts.map +1 -1
  102. package/dist/components/ui/toolButton/ToolButton.styled.js +20 -25
  103. package/dist/components/ui/toolButton/ToolButton.styled.js.map +1 -1
  104. package/dist/theme.css-global.d.ts.map +1 -1
  105. package/dist/theme.css-global.js +0 -1
  106. package/dist/theme.css-global.js.map +1 -1
  107. package/dist/utils/index.d.ts +1 -0
  108. package/dist/utils/index.d.ts.map +1 -1
  109. package/dist/utils/index.js +1 -0
  110. package/dist/utils/index.js.map +1 -1
  111. package/dist/utils/useNativeValidity.d.ts +11 -0
  112. package/dist/utils/useNativeValidity.d.ts.map +1 -0
  113. package/dist/utils/useNativeValidity.js +32 -0
  114. package/dist/utils/useNativeValidity.js.map +1 -0
  115. package/dist/utils/useRipple.d.ts +15 -0
  116. package/dist/utils/useRipple.d.ts.map +1 -0
  117. package/dist/utils/useRipple.js +120 -0
  118. package/dist/utils/useRipple.js.map +1 -0
  119. package/dist/utils/useRipple.styled.d.ts +28 -0
  120. package/dist/utils/useRipple.styled.d.ts.map +1 -0
  121. package/dist/utils/useRipple.styled.js +36 -0
  122. package/dist/utils/useRipple.styled.js.map +1 -0
  123. package/docs/assets/navigation.js +1 -1
  124. package/docs/assets/search.js +1 -1
  125. package/docs/classes/index.Pop.html +7 -7
  126. package/docs/documents/Test.html +2 -2
  127. package/docs/enums/index.ICON.html +3 -2
  128. package/docs/functions/index.Action.html +3 -3
  129. package/docs/functions/index.Button.html +3 -9
  130. package/docs/functions/index.Card.html +2 -2
  131. package/docs/functions/index.Checkbox.html +3 -3
  132. package/docs/functions/index.Choice.html +2 -2
  133. package/docs/functions/index.ColorPicker.html +3 -3
  134. package/docs/functions/index.CoveringLoader.html +3 -3
  135. package/docs/functions/index.DirectionPad.html +2 -2
  136. package/docs/functions/index.Drawer.html +2 -2
  137. package/docs/functions/index.EqualActions.html +2 -2
  138. package/docs/functions/index.FullLoader.html +3 -3
  139. package/docs/functions/index.Gap.html +2 -2
  140. package/docs/functions/index.HandleEsc.html +3 -3
  141. package/docs/functions/index.Header.html +3 -3
  142. package/docs/functions/index.HeaderIconAction.html +3 -3
  143. package/docs/functions/index.Icon-1.html +2 -2
  144. package/docs/functions/index.If.html +3 -3
  145. package/docs/functions/index.Input.html +1 -1
  146. package/docs/functions/index.KeyValue.html +2 -2
  147. package/docs/functions/index.Label.html +2 -2
  148. package/docs/functions/index.Line.html +3 -3
  149. package/docs/functions/index.List.html +2 -2
  150. package/docs/functions/index.Loader.html +3 -3
  151. package/docs/functions/index.Loading.html +3 -3
  152. package/docs/functions/index.Message.html +3 -3
  153. package/docs/functions/index.Modal.html +2 -2
  154. package/docs/functions/index.ModalButtons.html +3 -3
  155. package/docs/functions/index.PopLoader.html +3 -3
  156. package/docs/functions/index.PopOption.html +2 -2
  157. package/docs/functions/index.Progress.html +2 -2
  158. package/docs/functions/index.SearchContainer.html +2 -2
  159. package/docs/functions/index.Section.html +4 -4
  160. package/docs/functions/index.Select.html +2 -2
  161. package/docs/functions/index.Selector.html +2 -2
  162. package/docs/functions/index.Spacer.html +2 -2
  163. package/docs/functions/index.Stats.html +2 -2
  164. package/docs/functions/index.StickyHeader.html +4 -4
  165. package/docs/functions/index.Table.html +2 -2
  166. package/docs/functions/index.TextArea.html +2 -2
  167. package/docs/functions/index.TimePicker.html +10 -0
  168. package/docs/functions/index.ToasterProvider.html +3 -3
  169. package/docs/functions/index.Toggle.html +3 -3
  170. package/docs/functions/index.ToolButton.html +3 -9
  171. package/docs/functions/index.Tooltip.html +3 -3
  172. package/docs/functions/index.TooltipProvider.html +2 -2
  173. package/docs/functions/index.borderPxToRem.html +1 -1
  174. package/docs/functions/index.createTheme.html +1 -1
  175. package/docs/functions/index.css.html +1 -1
  176. package/docs/functions/index.dimensionsPxToRem.html +1 -1
  177. package/docs/functions/index.fontPxToRem.html +1 -1
  178. package/docs/functions/index.getCssText.html +1 -1
  179. package/docs/functions/index.globalCss.html +2 -2
  180. package/docs/functions/index.injectGlobalStyles.html +1 -1
  181. package/docs/functions/index.keyframes.html +1 -1
  182. package/docs/functions/index.pxToRem.html +1 -1
  183. package/docs/functions/index.styled.html +1 -1
  184. package/docs/functions/index.toast.html +2 -2
  185. package/docs/functions/index.useToaster.html +1 -1
  186. package/docs/index.html +2 -2
  187. package/docs/interfaces/index.IconProps.html +2 -2
  188. package/docs/interfaces/index.InputCustomProps.html +3 -3
  189. package/docs/interfaces/index.LoaderProps.html +6 -6
  190. package/docs/interfaces/index.StickyHeaderProps.html +4 -4
  191. package/docs/interfaces/index.ToasterProviderProps.html +3 -3
  192. package/docs/interfaces/index.TooltipProps.html +14 -14
  193. package/docs/interfaces/index.TooltipProviderProps.html +5 -5
  194. package/docs/modules/index.html +1 -1
  195. package/docs/modules.html +1 -1
  196. package/docs/types/index.ActionProps.html +1 -1
  197. package/docs/types/index.CardProps.html +1 -1
  198. package/docs/types/index.CheckboxProps.html +2 -2
  199. package/docs/types/index.ChoiceProps.html +1 -1
  200. package/docs/types/index.ColorPickerProps.html +1 -1
  201. package/docs/types/index.DirectionPadProps.html +1 -1
  202. package/docs/types/index.DrawerFrom.html +1 -1
  203. package/docs/types/index.DrawerProps.html +2 -2
  204. package/docs/types/index.EqualActionsProps.html +1 -1
  205. package/docs/types/index.HeaderProps.html +1 -1
  206. package/docs/types/index.InputProps.html +1 -1
  207. package/docs/types/index.KeyValueProps.html +1 -1
  208. package/docs/types/index.LabelProps.html +1 -1
  209. package/docs/types/index.OverwriteProps.html +1 -1
  210. package/docs/types/index.ProgressProps.html +2 -2
  211. package/docs/types/index.SelectProps.html +1 -1
  212. package/docs/types/index.SelectorProps.html +1 -1
  213. package/docs/types/index.Stat.html +1 -1
  214. package/docs/types/index.StatsProps.html +1 -1
  215. package/docs/types/index.TextAreaProps.html +1 -1
  216. package/docs/types/index.ThemeCSS.html +1 -1
  217. package/docs/types/index.TimePickerProps.html +1 -0
  218. package/docs/types/index.ToggleProps.html +2 -2
  219. package/docs/variables/index.ActionBadgeSelector.html +1 -1
  220. package/docs/variables/index.ActionCircleSelector.html +1 -1
  221. package/docs/variables/index.CheckboxCheckmarkWrapperSelector.html +1 -1
  222. package/docs/variables/index.CheckboxTextLabelSelector.html +1 -1
  223. package/docs/variables/index.ChoiceItemSelector.html +1 -1
  224. package/docs/variables/index.ColorPickerColorDisplaySelector.html +1 -1
  225. package/docs/variables/index.DirectionPadButtonDotSelector.html +1 -1
  226. package/docs/variables/index.DirectionPadButtonSelector.html +1 -1
  227. package/docs/variables/index.DirectionPadLineSelector.html +1 -1
  228. package/docs/variables/index.DirectionPadMiddleSelector.html +1 -1
  229. package/docs/variables/index.DrawerContentSelector.html +1 -1
  230. package/docs/variables/index.HeaderAfterSelector.html +1 -1
  231. package/docs/variables/index.HeaderBeforeSelector.html +1 -1
  232. package/docs/variables/index.HeaderContentsSelector.html +1 -1
  233. package/docs/variables/index.HeaderIconActionIconSelector.html +1 -1
  234. package/docs/variables/index.InputContainerSelector.html +1 -1
  235. package/docs/variables/index.InputInputSelector.html +1 -1
  236. package/docs/variables/index.InputLabelSelector.html +1 -1
  237. package/docs/variables/index.InputPrefixSelector.html +1 -1
  238. package/docs/variables/index.InputSuffixSelector.html +1 -1
  239. package/docs/variables/index.KeyValueIconSelector.html +1 -1
  240. package/docs/variables/index.KeyValueItemSelector.html +1 -1
  241. package/docs/variables/index.KeyValueKeySelector.html +1 -1
  242. package/docs/variables/index.KeyValuePairSelector.html +1 -1
  243. package/docs/variables/index.KeyValueValueSelector.html +1 -1
  244. package/docs/variables/index.LabelTextSelector.html +1 -1
  245. package/docs/variables/index.ListItemInnerContainerClassNameSelector.html +1 -1
  246. package/docs/variables/index.ModalContainerSelector.html +1 -1
  247. package/docs/variables/index.ModalRemovePaddingSelector.html +1 -1
  248. package/docs/variables/index.ModalTitleSelector.html +1 -1
  249. package/docs/variables/index.PopListSelector.html +1 -1
  250. package/docs/variables/index.PopOptionButtonSelector.html +1 -1
  251. package/docs/variables/index.PopOptionIconSelector.html +1 -1
  252. package/docs/variables/index.PopOverlaySelector.html +1 -1
  253. package/docs/variables/index.ProgressBackgroundSelector.html +1 -1
  254. package/docs/variables/index.ProgressValueSelector.html +1 -1
  255. package/docs/variables/index.SelectorItemSelector.html +1 -1
  256. package/docs/variables/index.StatsItemSelector.html +1 -1
  257. package/docs/variables/index.StatsLabelSelector.html +1 -1
  258. package/docs/variables/index.StatsSeparatorSelector.html +1 -1
  259. package/docs/variables/index.StatsValueSelector.html +1 -1
  260. package/docs/variables/index.TextAreaLabelSelector.html +1 -1
  261. package/docs/variables/index.TextAreaTextAreaSelector.html +1 -1
  262. package/docs/variables/index.TextAreaWrapperSelector.html +1 -1
  263. package/docs/variables/index.ToggleStyledToggleSelector.html +1 -1
  264. package/docs/variables/index.TooltipContentSelector.html +1 -1
  265. package/docs/variables/index.config.html +1 -1
  266. package/docs/variables/index.cssReset.html +2 -2
  267. package/docs/variables/index.darkTheme.html +1 -1
  268. package/docs/variables/index.miuiScrollbars.html +1 -1
  269. package/docs/variables/index.theme.html +1 -1
  270. package/esm/components/form/index.d.ts +1 -0
  271. package/esm/components/form/index.d.ts.map +1 -1
  272. package/esm/components/form/index.js +1 -0
  273. package/esm/components/form/index.js.map +1 -1
  274. package/esm/components/form/input/Input.d.ts.map +1 -1
  275. package/esm/components/form/input/Input.js +9 -5
  276. package/esm/components/form/input/Input.js.map +1 -1
  277. package/esm/components/form/timepicker/TimePicker.css.d.ts +99 -0
  278. package/esm/components/form/timepicker/TimePicker.css.d.ts.map +1 -0
  279. package/esm/components/form/timepicker/TimePicker.css.js +102 -0
  280. package/esm/components/form/timepicker/TimePicker.css.js.map +1 -0
  281. package/esm/components/form/timepicker/TimePicker.d.ts +22 -0
  282. package/esm/components/form/timepicker/TimePicker.d.ts.map +1 -0
  283. package/esm/components/form/timepicker/TimePicker.js +93 -0
  284. package/esm/components/form/timepicker/TimePicker.js.map +1 -0
  285. package/esm/components/form/timepicker/TimePicker.styled.d.ts +936 -0
  286. package/esm/components/form/timepicker/TimePicker.styled.d.ts.map +1 -0
  287. package/esm/components/form/timepicker/TimePicker.styled.js +20 -0
  288. package/esm/components/form/timepicker/TimePicker.styled.js.map +1 -0
  289. package/esm/components/form/timepicker/TimePickerModal.d.ts +17 -0
  290. package/esm/components/form/timepicker/TimePickerModal.d.ts.map +1 -0
  291. package/esm/components/form/timepicker/TimePickerModal.js +56 -0
  292. package/esm/components/form/timepicker/TimePickerModal.js.map +1 -0
  293. package/esm/components/form/timepicker/Wheel.d.ts +12 -0
  294. package/esm/components/form/timepicker/Wheel.d.ts.map +1 -0
  295. package/esm/components/form/timepicker/Wheel.js +151 -0
  296. package/esm/components/form/timepicker/Wheel.js.map +1 -0
  297. package/esm/components/form/timepicker/utils.d.ts +4 -0
  298. package/esm/components/form/timepicker/utils.d.ts.map +1 -0
  299. package/esm/components/form/timepicker/utils.js +58 -0
  300. package/esm/components/form/timepicker/utils.js.map +1 -0
  301. package/esm/components/icons/Clock.d.ts +7 -0
  302. package/esm/components/icons/Clock.d.ts.map +1 -0
  303. package/esm/components/icons/Clock.js +9 -0
  304. package/esm/components/icons/Clock.js.map +1 -0
  305. package/esm/components/icons/Icon.d.ts +2 -1
  306. package/esm/components/icons/Icon.d.ts.map +1 -1
  307. package/esm/components/icons/Icon.js +3 -0
  308. package/esm/components/icons/Icon.js.map +1 -1
  309. package/esm/components/layout/header/HeaderIconAction.d.ts.map +1 -1
  310. package/esm/components/layout/header/HeaderIconAction.js +13 -3
  311. package/esm/components/layout/header/HeaderIconAction.js.map +1 -1
  312. package/esm/components/layout/header/HeaderIconAction.styled.d.ts.map +1 -1
  313. package/esm/components/layout/header/HeaderIconAction.styled.js +11 -17
  314. package/esm/components/layout/header/HeaderIconAction.styled.js.map +1 -1
  315. package/esm/components/layout/list/Item.d.ts.map +1 -1
  316. package/esm/components/layout/list/Item.js +18 -8
  317. package/esm/components/layout/list/Item.js.map +1 -1
  318. package/esm/components/layout/list/Item.styled.d.ts.map +1 -1
  319. package/esm/components/layout/list/Item.styled.js +2 -1
  320. package/esm/components/layout/list/Item.styled.js.map +1 -1
  321. package/esm/components/ui/button/Button.d.ts +94 -1
  322. package/esm/components/ui/button/Button.d.ts.map +1 -1
  323. package/esm/components/ui/button/Button.js +15 -1
  324. package/esm/components/ui/button/Button.js.map +1 -1
  325. package/esm/components/ui/button/Button.styled.d.ts +2 -2
  326. package/esm/components/ui/button/Button.styled.d.ts.map +1 -1
  327. package/esm/components/ui/button/Button.styled.js +3 -2
  328. package/esm/components/ui/button/Button.styled.js.map +1 -1
  329. package/esm/components/ui/directionPad/Button.d.ts.map +1 -1
  330. package/esm/components/ui/directionPad/Button.js +7 -2
  331. package/esm/components/ui/directionPad/Button.js.map +1 -1
  332. package/esm/components/ui/directionPad/Button.styled.d.ts.map +1 -1
  333. package/esm/components/ui/directionPad/Button.styled.js +2 -1
  334. package/esm/components/ui/directionPad/Button.styled.js.map +1 -1
  335. package/esm/components/ui/directionPad/Middle.d.ts.map +1 -1
  336. package/esm/components/ui/directionPad/Middle.js +7 -1
  337. package/esm/components/ui/directionPad/Middle.js.map +1 -1
  338. package/esm/components/ui/directionPad/Middle.styled.d.ts.map +1 -1
  339. package/esm/components/ui/directionPad/Middle.styled.js +2 -1
  340. package/esm/components/ui/directionPad/Middle.styled.js.map +1 -1
  341. package/esm/components/ui/modal/Modal.d.ts +1 -2
  342. package/esm/components/ui/modal/Modal.d.ts.map +1 -1
  343. package/esm/components/ui/modal/Modal.js +103 -43
  344. package/esm/components/ui/modal/Modal.js.map +1 -1
  345. package/esm/components/ui/modal/Modal.styled.d.ts +1 -1
  346. package/esm/components/ui/modal/Modal.styled.d.ts.map +1 -1
  347. package/esm/components/ui/modal/Modal.styled.js +40 -25
  348. package/esm/components/ui/modal/Modal.styled.js.map +1 -1
  349. package/esm/components/ui/modal/ModalButtons.d.ts +179 -1
  350. package/esm/components/ui/modal/ModalButtons.d.ts.map +1 -1
  351. package/esm/components/ui/modal/ModalButtons.js +19 -1
  352. package/esm/components/ui/modal/ModalButtons.js.map +1 -1
  353. package/esm/components/ui/modal/ModalButtons.styled.d.ts +90 -91
  354. package/esm/components/ui/modal/ModalButtons.styled.d.ts.map +1 -1
  355. package/esm/components/ui/modal/ModalButtons.styled.js +3 -6
  356. package/esm/components/ui/modal/ModalButtons.styled.js.map +1 -1
  357. package/esm/components/ui/pop/Pop.styled.d.ts.map +1 -1
  358. package/esm/components/ui/pop/Pop.styled.js +15 -17
  359. package/esm/components/ui/pop/Pop.styled.js.map +1 -1
  360. package/esm/components/ui/pop/PopOption.d.ts.map +1 -1
  361. package/esm/components/ui/pop/PopOption.js +7 -2
  362. package/esm/components/ui/pop/PopOption.js.map +1 -1
  363. package/esm/components/ui/toolButton/ToolButton.d.ts +94 -1
  364. package/esm/components/ui/toolButton/ToolButton.d.ts.map +1 -1
  365. package/esm/components/ui/toolButton/ToolButton.js +15 -1
  366. package/esm/components/ui/toolButton/ToolButton.js.map +1 -1
  367. package/esm/components/ui/toolButton/ToolButton.styled.d.ts +2 -2
  368. package/esm/components/ui/toolButton/ToolButton.styled.d.ts.map +1 -1
  369. package/esm/components/ui/toolButton/ToolButton.styled.js +19 -24
  370. package/esm/components/ui/toolButton/ToolButton.styled.js.map +1 -1
  371. package/esm/theme.css-global.d.ts.map +1 -1
  372. package/esm/theme.css-global.js +0 -1
  373. package/esm/theme.css-global.js.map +1 -1
  374. package/esm/utils/index.d.ts +1 -0
  375. package/esm/utils/index.d.ts.map +1 -1
  376. package/esm/utils/index.js +1 -0
  377. package/esm/utils/index.js.map +1 -1
  378. package/esm/utils/useNativeValidity.d.ts +11 -0
  379. package/esm/utils/useNativeValidity.d.ts.map +1 -0
  380. package/esm/utils/useNativeValidity.js +29 -0
  381. package/esm/utils/useNativeValidity.js.map +1 -0
  382. package/esm/utils/useRipple.d.ts +15 -0
  383. package/esm/utils/useRipple.d.ts.map +1 -0
  384. package/esm/utils/useRipple.js +84 -0
  385. package/esm/utils/useRipple.js.map +1 -0
  386. package/esm/utils/useRipple.styled.d.ts +28 -0
  387. package/esm/utils/useRipple.styled.d.ts.map +1 -0
  388. package/esm/utils/useRipple.styled.js +33 -0
  389. package/esm/utils/useRipple.styled.js.map +1 -0
  390. package/package.json +1 -1
  391. package/src/components/form/index.ts +1 -0
  392. package/src/components/form/input/Input.stories.tsx +47 -1
  393. package/src/components/form/input/Input.tsx +11 -5
  394. package/src/components/form/timepicker/TimePicker.css.ts +132 -0
  395. package/src/components/form/timepicker/TimePicker.stories.tsx +107 -0
  396. package/src/components/form/timepicker/TimePicker.styled.ts +52 -0
  397. package/src/components/form/timepicker/TimePicker.tsx +229 -0
  398. package/src/components/form/timepicker/TimePickerModal.tsx +131 -0
  399. package/src/components/form/timepicker/Wheel.tsx +201 -0
  400. package/src/components/form/timepicker/utils.ts +66 -0
  401. package/src/components/icons/Clock.tsx +38 -0
  402. package/src/components/icons/Icon.tsx +3 -0
  403. package/src/components/layout/header/HeaderIconAction.styled.ts +11 -18
  404. package/src/components/layout/header/HeaderIconAction.tsx +32 -5
  405. package/src/components/layout/list/Item.styled.ts +2 -1
  406. package/src/components/layout/list/Item.tsx +38 -5
  407. package/src/components/ui/button/Button.styled.ts +3 -2
  408. package/src/components/ui/button/Button.tsx +33 -1
  409. package/src/components/ui/directionPad/Button.styled.ts +2 -1
  410. package/src/components/ui/directionPad/Button.tsx +13 -1
  411. package/src/components/ui/directionPad/Middle.styled.ts +2 -1
  412. package/src/components/ui/directionPad/Middle.tsx +13 -1
  413. package/src/components/ui/modal/Modal.stories.tsx +43 -7
  414. package/src/components/ui/modal/Modal.styled.ts +46 -25
  415. package/src/components/ui/modal/Modal.tsx +135 -52
  416. package/src/components/ui/modal/ModalButtons.styled.ts +4 -7
  417. package/src/components/ui/modal/ModalButtons.tsx +38 -1
  418. package/src/components/ui/pop/Pop.styled.ts +15 -18
  419. package/src/components/ui/pop/PopOption.tsx +15 -1
  420. package/src/components/ui/toolButton/ToolButton.styled.ts +20 -26
  421. package/src/components/ui/toolButton/ToolButton.tsx +33 -0
  422. package/src/theme.css-global.ts +0 -1
  423. package/src/utils/index.ts +1 -0
  424. package/src/utils/useNativeValidity.ts +57 -0
  425. package/src/utils/useRipple.styled.ts +56 -0
  426. package/src/utils/useRipple.tsx +139 -0
  427. package/src/components/ui/toolButton/ToolButton.ts +0 -1
@@ -103,8 +103,54 @@ const InputRef: Story = {
103
103
  },
104
104
  };
105
105
 
106
+ const Validation: Story = {
107
+ render: () => {
108
+ const [submitted, setSubmitted] = React.useState<Record<string, string> | null>(null);
109
+ return (
110
+ <form
111
+ onSubmit={(e) => {
112
+ e.preventDefault();
113
+ const data = new FormData(e.currentTarget);
114
+ const result: Record<string, string> = {};
115
+ data.forEach((v, k) => {
116
+ if (typeof v === "string") {
117
+ result[k] = v;
118
+ }
119
+ });
120
+ setSubmitted(result);
121
+ }}
122
+ >
123
+ <Gap>
124
+ <div>
125
+ {"Every input reads native validity (pattern / required / type)."
126
+ + " Type something, blur the field or hit Submit — invalid fields turn red on their own."}
127
+ </div>
128
+ <Input name={"email"} label={"Email"} type={"email"} required={true} />
129
+ <Input name={"required"} label={"Required text"} required={true} />
130
+ <Input
131
+ name={"digits"}
132
+ label={"4 digits only"}
133
+ pattern={"\\d{4}"}
134
+ placeholder={"1234"}
135
+ />
136
+ <Input
137
+ name={"short"}
138
+ label={"Min 5 characters"}
139
+ minLength={5}
140
+ defaultValue={"abc"}
141
+ />
142
+ <Button type={"submit"}>{"Submit"}</Button>
143
+ {submitted
144
+ ? <div>{"Submitted: " + JSON.stringify(submitted)}</div>
145
+ : null}
146
+ </Gap>
147
+ </form>
148
+ );
149
+ },
150
+ };
151
+
106
152
  export {
107
- Primary, Mixed, WithLabel, FloatingLabel, InputRef,
153
+ Primary, Mixed, WithLabel, FloatingLabel, InputRef, Validation,
108
154
  };
109
155
 
110
156
  export default meta;
@@ -2,6 +2,7 @@ import React, { useCallback, useId, useRef, useState } from "react";
2
2
 
3
3
  import type { ObjectValue, Value } from "../../../types/form";
4
4
 
5
+ import { useNativeValidity } from "../../../utils";
5
6
  import { Suggestions } from "../Suggestions";
6
7
  import {
7
8
  StyledInput,
@@ -53,6 +54,8 @@ const InputInner = <T extends string>({ // eslint-disable-line max-lines-per-fun
53
54
  const isControlled = props.value !== undefined;
54
55
  const hasValue = isControlled ? Boolean(props.value) : internalHasValue;
55
56
 
57
+ const validity = useNativeValidity(error);
58
+
56
59
  const suggestionsId = useId();
57
60
  const generatedInputId = useId();
58
61
  const inputId = id ?? (label ? generatedInputId : undefined);
@@ -65,8 +68,9 @@ const InputInner = <T extends string>({ // eslint-disable-line max-lines-per-fun
65
68
 
66
69
  const handleBlur = useCallback((e: React.FocusEvent<HTMLInputElement>) => {
67
70
  setFocused(false);
71
+ validity.onBlur(e);
68
72
  onBlur?.(e);
69
- }, [onBlur]);
73
+ }, [onBlur, validity]);
70
74
 
71
75
  const handleKeyDown: React.KeyboardEventHandler<HTMLInputElement> = useCallback((e) => {
72
76
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@@ -80,6 +84,7 @@ const InputInner = <T extends string>({ // eslint-disable-line max-lines-per-fun
80
84
  if (!isControlled) {
81
85
  setInternalHasValue(Boolean(e.currentTarget.value));
82
86
  }
87
+ validity.onChange(e);
83
88
  if (!suggestions) {
84
89
  onChange?.(e);
85
90
  return;
@@ -96,7 +101,7 @@ const InputInner = <T extends string>({ // eslint-disable-line max-lines-per-fun
96
101
  }
97
102
  infoRef.current.picked = false;
98
103
  onChange?.(e);
99
- }, [isControlled, suggestions, onChange, onSuggestionMatch]);
104
+ }, [isControlled, suggestions, onChange, onSuggestionMatch, validity]);
100
105
 
101
106
  const prefixElem = prefix ? <StyledPrefix>{prefix}</StyledPrefix> : null;
102
107
  const suffixElem = suffix ? <StyledSuffix>{suffix}</StyledSuffix> : null;
@@ -115,7 +120,7 @@ const InputInner = <T extends string>({ // eslint-disable-line max-lines-per-fun
115
120
  <StyledLabel
116
121
  htmlFor={inputId}
117
122
  floating={floating}
118
- error={Boolean(error)}
123
+ error={validity.finalError}
119
124
  >
120
125
  {label}
121
126
  </StyledLabel>
@@ -128,7 +133,7 @@ const InputInner = <T extends string>({ // eslint-disable-line max-lines-per-fun
128
133
  focused={focused}
129
134
  disabled={Boolean(props.disabled)}
130
135
  readOnly={Boolean(props.readOnly)}
131
- error={Boolean(error)}
136
+ error={validity.finalError}
132
137
  >
133
138
  {prefixElem}
134
139
  <StyledInputContainer>
@@ -143,7 +148,8 @@ const InputInner = <T extends string>({ // eslint-disable-line max-lines-per-fun
143
148
  onKeyDown={handleKeyDown}
144
149
  onFocus={handleFocus}
145
150
  onBlur={handleBlur}
146
- data-error={Boolean(error)}
151
+ onInvalid={validity.onInvalid}
152
+ data-error={validity.finalError}
147
153
  />
148
154
  <Suggestions id={suggestionsId} suggestions={suggestions} />
149
155
  </StyledInputContainer>
@@ -0,0 +1,132 @@
1
+ import type { ThemeCSS } from "../../../theme";
2
+
3
+ import { borderPxToRem, dimensionsPxToRem, fontPxToRem } from "../../../theme";
4
+
5
+ const ITEM_HEIGHT_PX = 200;
6
+ const VISIBLE_ITEMS = 5;
7
+
8
+ const wheelViewport = {
9
+ "position": "relative",
10
+ "height": dimensionsPxToRem(ITEM_HEIGHT_PX * VISIBLE_ITEMS),
11
+ "width": dimensionsPxToRem(360),
12
+ "overflowY": "scroll",
13
+ "scrollSnapType": "y mandatory",
14
+ "scrollbarWidth": "none",
15
+ "WebkitMaskImage":
16
+ "linear-gradient(to bottom, transparent 0%, transparent 10%, black 45%,"
17
+ + " black 55%, transparent 90%, transparent 100%)",
18
+ "maskImage":
19
+ "linear-gradient(to bottom, transparent 0%, transparent 10%, black 45%,"
20
+ + " black 55%, transparent 90%, transparent 100%)",
21
+ "overscrollBehavior": "contain",
22
+
23
+ "&::-webkit-scrollbar": {
24
+ display: "none",
25
+ },
26
+ "&:focus": {
27
+ outline: "none",
28
+ },
29
+ } satisfies ThemeCSS;
30
+
31
+ const wheelWrapper = {
32
+ position: "relative",
33
+ display: "flex",
34
+ } satisfies ThemeCSS;
35
+
36
+ const wheelFocusRing = {
37
+ position: "absolute",
38
+ top: "50%",
39
+ left: 0,
40
+ right: 0,
41
+ height: dimensionsPxToRem(ITEM_HEIGHT_PX),
42
+ transform: "translateY(-50%)",
43
+ pointerEvents: "none",
44
+ border: `${borderPxToRem(2)} solid transparent`,
45
+ borderRadius: dimensionsPxToRem(16),
46
+ boxSizing: "border-box",
47
+ transition: "border-color 0.15s",
48
+ } satisfies ThemeCSS;
49
+
50
+ const wheelPadder = {
51
+ height: dimensionsPxToRem(ITEM_HEIGHT_PX * 2),
52
+ } satisfies ThemeCSS;
53
+
54
+ const wheelItem = {
55
+ height: dimensionsPxToRem(ITEM_HEIGHT_PX),
56
+ display: "flex",
57
+ alignItems: "center",
58
+ justifyContent: "center",
59
+ scrollSnapAlign: "center",
60
+ scrollSnapStop: "always",
61
+ fontSize: fontPxToRem(80),
62
+ fontVariantNumeric: "tabular-nums",
63
+ color: "$text",
64
+ userSelect: "none",
65
+ fontWeight: 500,
66
+ } satisfies ThemeCSS;
67
+
68
+ const wheelHighlight = {
69
+ position: "absolute",
70
+ top: "50%",
71
+ left: 0,
72
+ right: 0,
73
+ height: dimensionsPxToRem(ITEM_HEIGHT_PX),
74
+ transform: "translateY(-50%)",
75
+ pointerEvents: "none",
76
+ borderTop: "1px solid $border",
77
+ borderBottom: "1px solid $border",
78
+ } satisfies ThemeCSS;
79
+
80
+ const wheelsContainer = {
81
+ display: "flex",
82
+ justifyContent: "center",
83
+ alignItems: "center",
84
+ gap: dimensionsPxToRem(36),
85
+ position: "relative",
86
+ } satisfies ThemeCSS;
87
+
88
+ const wheelSeparator = {
89
+ fontSize: fontPxToRem(80),
90
+ color: "$text",
91
+ fontWeight: 500,
92
+ userSelect: "none",
93
+ pointerEvents: "none",
94
+ } satisfies ThemeCSS;
95
+
96
+ const suffixButton = {
97
+ "display": "flex",
98
+ "alignItems": "center",
99
+ "justifyContent": "center",
100
+ "background": "none",
101
+ "border": "none",
102
+ "padding": dimensionsPxToRem(24),
103
+ "margin": `0 -${dimensionsPxToRem(24)}`,
104
+ "cursor": "pointer",
105
+ "color": "$text",
106
+
107
+ "&:disabled": {
108
+ cursor: "not-allowed",
109
+ opacity: 0.5,
110
+ },
111
+ } satisfies ThemeCSS;
112
+
113
+ const timeInput = {
114
+ fontVariantNumeric: "tabular-nums",
115
+ letterSpacing: "0.05em",
116
+ caretColor: "$mainColor",
117
+ } satisfies ThemeCSS;
118
+
119
+ export {
120
+ ITEM_HEIGHT_PX,
121
+ VISIBLE_ITEMS,
122
+ wheelViewport,
123
+ wheelWrapper,
124
+ wheelFocusRing,
125
+ wheelPadder,
126
+ wheelItem,
127
+ wheelHighlight,
128
+ wheelsContainer,
129
+ wheelSeparator,
130
+ suffixButton,
131
+ timeInput,
132
+ };
@@ -0,0 +1,107 @@
1
+ import React, { useState } from "react";
2
+
3
+ import type { Meta, StoryObj } from "@storybook/react-vite";
4
+
5
+ import { Gap } from "../../utils/Gap";
6
+ import { TimePicker } from "./TimePicker";
7
+
8
+ const meta: Meta<typeof TimePicker> = {
9
+ title: "Components/Form/TimePicker",
10
+ component: TimePicker,
11
+ tags: ["autodocs", "form"],
12
+ argTypes: {
13
+ error: { type: "boolean" },
14
+ disabled: { type: "boolean" },
15
+ readOnly: { type: "boolean" },
16
+ withSeconds: { type: "boolean" },
17
+ minuteStep: { type: "number" },
18
+ secondStep: { type: "number" },
19
+ },
20
+ };
21
+
22
+ type Story = StoryObj<typeof TimePicker>;
23
+
24
+ const Primary: Story = {
25
+ args: {
26
+ label: "Time",
27
+ },
28
+ };
29
+
30
+ const Controlled: Story = {
31
+ render: () => {
32
+ const [value, setValue] = useState("14:30");
33
+ return (
34
+ <Gap>
35
+ <TimePicker label={"Time"} value={value} onChange={setValue} />
36
+ <div>{"Value: " + (value || "(empty)")}</div>
37
+ </Gap>
38
+ );
39
+ },
40
+ };
41
+
42
+ const Uncontrolled: Story = {
43
+ args: {
44
+ label: "Time",
45
+ defaultValue: "08:00",
46
+ },
47
+ };
48
+
49
+ const WithSeconds: Story = {
50
+ args: {
51
+ label: "Time with seconds",
52
+ withSeconds: true,
53
+ defaultValue: "12:34:56",
54
+ },
55
+ };
56
+
57
+ const MinuteStep5: Story = {
58
+ args: {
59
+ label: "Time (5 min step)",
60
+ minuteStep: 5,
61
+ },
62
+ };
63
+
64
+ const Validation: Story = {
65
+ render: () => {
66
+ const [submitted, setSubmitted] = useState<string | null>(null);
67
+ return (
68
+ <form
69
+ onSubmit={(e) => {
70
+ e.preventDefault();
71
+ const data = new FormData(e.currentTarget);
72
+ const v = data.get("time");
73
+ setSubmitted(typeof v === "string" ? v : "");
74
+ }}
75
+ >
76
+ <Gap>
77
+ <div>
78
+ {"Type something invalid (e.g. \"9:5\" or \"abc\") and blur — TimePicker"
79
+ + " reads native validity and auto-applies its error variant."}
80
+ </div>
81
+ <TimePicker name={"time"} label={"Time"} required={true} />
82
+ <button type={"submit"}>{"Submit"}</button>
83
+ {submitted !== null
84
+ ? <div>{"Submitted: " + (submitted || "(empty)")}</div>
85
+ : null}
86
+ </Gap>
87
+ </form>
88
+ );
89
+ },
90
+ };
91
+
92
+ const Mixed: Story = {
93
+ render: () => (
94
+ <Gap>
95
+ <TimePicker label={"Default"} />
96
+ <TimePicker label={"With value"} defaultValue={"09:15"} />
97
+ <TimePicker label={"With seconds"} withSeconds={true} defaultValue={"23:59:30"} />
98
+ <TimePicker label={"Every 15 min"} minuteStep={15} />
99
+ <TimePicker label={"Disabled"} defaultValue={"10:00"} disabled={true} />
100
+ <TimePicker label={"Read only"} defaultValue={"10:00"} readOnly={true} />
101
+ <TimePicker label={"Error"} defaultValue={"10:00"} error={true} />
102
+ </Gap>
103
+ ),
104
+ };
105
+
106
+ export default meta;
107
+ export { Primary, Controlled, Uncontrolled, WithSeconds, MinuteStep5, Validation, Mixed };
@@ -0,0 +1,52 @@
1
+ import { styled } from "../../../theme";
2
+ import { StyledInput } from "../input/Input.styled";
3
+ import {
4
+ suffixButton,
5
+ timeInput,
6
+ wheelFocusRing,
7
+ wheelHighlight,
8
+ wheelItem,
9
+ wheelPadder,
10
+ wheelsContainer,
11
+ wheelSeparator,
12
+ wheelViewport,
13
+ wheelWrapper,
14
+ } from "./TimePicker.css";
15
+
16
+ const StyledTimeInput = styled(StyledInput, timeInput);
17
+
18
+ const StyledSuffixButton = styled("button", suffixButton);
19
+
20
+ const StyledWheelsContainer = styled("div", wheelsContainer);
21
+
22
+ const StyledWheelViewport = styled("div", wheelViewport);
23
+
24
+ const StyledWheelWrapper = styled("div", wheelWrapper);
25
+
26
+ const StyledWheelPadder = styled("div", wheelPadder);
27
+
28
+ const StyledWheelItem = styled("div", wheelItem);
29
+
30
+ const StyledWheelHighlight = styled("div", wheelHighlight);
31
+
32
+ const StyledWheelSeparator = styled("div", wheelSeparator);
33
+
34
+ const StyledWheelFocusRing = styled("div", {
35
+ ...wheelFocusRing,
36
+ [StyledWheelViewport.toString() + ":focus-visible + &"]: {
37
+ borderColor: "$focusColor",
38
+ },
39
+ });
40
+
41
+ export {
42
+ StyledTimeInput,
43
+ StyledSuffixButton,
44
+ StyledWheelsContainer,
45
+ StyledWheelViewport,
46
+ StyledWheelWrapper,
47
+ StyledWheelPadder,
48
+ StyledWheelItem,
49
+ StyledWheelHighlight,
50
+ StyledWheelSeparator,
51
+ StyledWheelFocusRing,
52
+ };
@@ -0,0 +1,229 @@
1
+ import React, {
2
+ forwardRef,
3
+ useCallback,
4
+ useEffect,
5
+ useId,
6
+ useState,
7
+ } from "react";
8
+
9
+ import { useForwardedRef } from "@bedrock-layout/use-forwarded-ref";
10
+
11
+ import { useNativeValidity } from "../../../utils/useNativeValidity";
12
+ import { Clock } from "../../icons/Clock";
13
+ import {
14
+ StyledInputContainer,
15
+ StyledLabel,
16
+ StyledSuffix,
17
+ StyledWrapper,
18
+ } from "../input/Input.styled";
19
+ import {
20
+ StyledSuffixButton,
21
+ StyledTimeInput,
22
+ } from "./TimePicker.styled";
23
+ import { TimePickerModal } from "./TimePickerModal";
24
+
25
+ const PATTERN_HHMM = "(?:[01]\\d|2[0-3]):[0-5]\\d";
26
+ const PATTERN_HHMMSS = "(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
27
+ const MAX_LEN_HHMM = 5;
28
+ const MAX_LEN_HHMMSS = 8;
29
+
30
+ const assertStep = (name: string, step: number): void => {
31
+ if (!Number.isInteger(step) || step < 1 || step > 60) {
32
+ throw new Error(
33
+ `TimePicker: \`${name}\` must be an integer between 1 and 60, got ${String(step)}`,
34
+ );
35
+ }
36
+ };
37
+
38
+ interface CustomProps {
39
+ children?: never;
40
+ label?: string;
41
+ pinnedLabel?: boolean;
42
+ error?: boolean;
43
+ withSeconds?: boolean;
44
+ minuteStep?: number;
45
+ secondStep?: number;
46
+ value?: string;
47
+ defaultValue?: string;
48
+ onChange?: (value: string) => void;
49
+ modalTitle?: React.ReactNode;
50
+ okLabel?: React.ReactNode;
51
+ cancelLabel?: React.ReactNode;
52
+ }
53
+
54
+ type InputAttrs = Omit<
55
+ React.InputHTMLAttributes<HTMLInputElement>,
56
+ "value" | "defaultValue" | "onChange" | "type" | "prefix" | "pattern" | "placeholder" | "maxLength"
57
+ >;
58
+
59
+ type Props = InputAttrs & CustomProps;
60
+
61
+ // eslint-disable-next-line max-lines-per-function,max-statements
62
+ const TimePickerInner = ({
63
+ className,
64
+ label,
65
+ pinnedLabel = false,
66
+ error,
67
+ withSeconds = false,
68
+ minuteStep = 1,
69
+ secondStep = 1,
70
+ value,
71
+ defaultValue,
72
+ onChange,
73
+ onFocus,
74
+ onBlur,
75
+ disabled,
76
+ readOnly,
77
+ id,
78
+ modalTitle,
79
+ okLabel = "OK",
80
+ cancelLabel = "Cancel",
81
+ ...rest
82
+ }: Props, ref: React.Ref<HTMLInputElement>) => {
83
+ assertStep("minuteStep", minuteStep);
84
+ if (withSeconds) {
85
+ assertStep("secondStep", secondStep);
86
+ }
87
+
88
+ const isControlled = value !== undefined;
89
+ const [internalValue, setInternalValue] = useState(defaultValue ?? "");
90
+ const currentValue = isControlled ? (value ?? "") : internalValue;
91
+
92
+ const [focused, setFocused] = useState(false);
93
+ const validity = useNativeValidity(error);
94
+ const { revalidate } = validity;
95
+ const inputRef = useForwardedRef(ref);
96
+ const generatedId = useId();
97
+ const inputId = id ?? (label ? generatedId : undefined);
98
+
99
+ const [modalOpen, setModalOpen] = useState(false);
100
+
101
+ const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
102
+ const next = e.target.value;
103
+ if (!isControlled) {
104
+ setInternalValue(next);
105
+ }
106
+ validity.onChange(e);
107
+ onChange?.(next);
108
+ }, [isControlled, onChange, validity]);
109
+
110
+ const handleFocus = useCallback((e: React.FocusEvent<HTMLInputElement>) => {
111
+ setFocused(true);
112
+ onFocus?.(e);
113
+ }, [onFocus]);
114
+
115
+ const handleBlur = useCallback((e: React.FocusEvent<HTMLInputElement>) => {
116
+ setFocused(false);
117
+ validity.onBlur(e);
118
+ onBlur?.(e);
119
+ }, [onBlur, validity]);
120
+
121
+ useEffect(() => {
122
+ revalidate(inputRef.current);
123
+ }, [currentValue, revalidate, inputRef]);
124
+
125
+ const openModal = useCallback(() => {
126
+ setModalOpen(true);
127
+ }, []);
128
+
129
+ const closeModal = useCallback(() => {
130
+ setModalOpen(false);
131
+ inputRef.current?.focus();
132
+ }, [inputRef]);
133
+
134
+ const confirmModal = useCallback((next: string) => {
135
+ if (!isControlled) {
136
+ setInternalValue(next);
137
+ }
138
+ onChange?.(next);
139
+ setModalOpen(false);
140
+ inputRef.current?.focus();
141
+ }, [isControlled, onChange, inputRef]);
142
+
143
+ const hasValue = currentValue.length > 0;
144
+ const floating = Boolean(label) && (pinnedLabel || focused || hasValue);
145
+ const placeholder = withSeconds ? "--:--:--" : "--:--";
146
+ const pattern = withSeconds ? PATTERN_HHMMSS : PATTERN_HHMM;
147
+ const maxLength = withSeconds ? MAX_LEN_HHMMSS : MAX_LEN_HHMM;
148
+ const finalError = validity.finalError;
149
+
150
+ const labelElem = label
151
+ ? (
152
+ <StyledLabel
153
+ htmlFor={inputId}
154
+ floating={floating}
155
+ error={finalError}
156
+ >
157
+ {label}
158
+ </StyledLabel>
159
+ )
160
+ : null;
161
+
162
+ return (
163
+ <>
164
+ <StyledWrapper
165
+ className={className}
166
+ focused={focused}
167
+ disabled={Boolean(disabled)}
168
+ readOnly={Boolean(readOnly)}
169
+ error={finalError}
170
+ >
171
+ <StyledInputContainer>
172
+ {labelElem}
173
+ <StyledTimeInput
174
+ ref={inputRef}
175
+ {...rest}
176
+ id={inputId}
177
+ type={"text"}
178
+ inputMode={"numeric"}
179
+ autoComplete={"off"}
180
+ value={currentValue}
181
+ placeholder={placeholder}
182
+ pattern={pattern}
183
+ maxLength={maxLength}
184
+ disabled={disabled}
185
+ readOnly={readOnly}
186
+ onChange={handleChange}
187
+ onFocus={handleFocus}
188
+ onBlur={handleBlur}
189
+ onInvalid={validity.onInvalid}
190
+ data-error={finalError}
191
+ />
192
+ </StyledInputContainer>
193
+ <StyledSuffix>
194
+ <StyledSuffixButton
195
+ type={"button"}
196
+ onClick={openModal}
197
+ disabled={disabled}
198
+ aria-label={"Open time picker"}
199
+ >
200
+ <Clock />
201
+ </StyledSuffixButton>
202
+ </StyledSuffix>
203
+ </StyledWrapper>
204
+ <TimePickerModal
205
+ isOpen={modalOpen}
206
+ initialValue={currentValue}
207
+ withSeconds={withSeconds}
208
+ minuteStep={minuteStep}
209
+ secondStep={secondStep}
210
+ readOnly={Boolean(readOnly)}
211
+ title={modalTitle}
212
+ okLabel={okLabel}
213
+ cancelLabel={cancelLabel}
214
+ onClose={closeModal}
215
+ onConfirm={confirmModal}
216
+ />
217
+ </>
218
+ );
219
+ };
220
+
221
+ const TimePickerRef = forwardRef(TimePickerInner);
222
+ TimePickerRef.displayName = "TimePicker";
223
+ TimePickerRef.toString = () => StyledWrapper.toString();
224
+
225
+ const TimePicker = TimePickerRef;
226
+
227
+ export { TimePicker };
228
+
229
+ export type { Props as TimePickerProps };