react-miui 0.33.0 → 0.35.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 (343) hide show
  1. package/.claude/settings.json +12 -0
  2. package/.claude/settings.local.json +5 -1
  3. package/.storybook/preview.tsx +10 -4
  4. package/CHANGELOG.md +22 -0
  5. package/dist/components/form/index.d.ts +1 -0
  6. package/dist/components/form/index.d.ts.map +1 -1
  7. package/dist/components/form/index.js +1 -0
  8. package/dist/components/form/index.js.map +1 -1
  9. package/dist/components/form/input/Input.d.ts.map +1 -1
  10. package/dist/components/form/input/Input.js +9 -5
  11. package/dist/components/form/input/Input.js.map +1 -1
  12. package/dist/components/form/timepicker/TimePicker.css.d.ts +99 -0
  13. package/dist/components/form/timepicker/TimePicker.css.d.ts.map +1 -0
  14. package/dist/components/form/timepicker/TimePicker.css.js +116 -0
  15. package/dist/components/form/timepicker/TimePicker.css.js.map +1 -0
  16. package/dist/components/form/timepicker/TimePicker.d.ts +22 -0
  17. package/dist/components/form/timepicker/TimePicker.d.ts.map +1 -0
  18. package/dist/components/form/timepicker/TimePicker.js +141 -0
  19. package/dist/components/form/timepicker/TimePicker.js.map +1 -0
  20. package/dist/components/form/timepicker/TimePicker.styled.d.ts +936 -0
  21. package/dist/components/form/timepicker/TimePicker.styled.d.ts.map +1 -0
  22. package/dist/components/form/timepicker/TimePicker.styled.js +29 -0
  23. package/dist/components/form/timepicker/TimePicker.styled.js.map +1 -0
  24. package/dist/components/form/timepicker/TimePickerModal.d.ts +17 -0
  25. package/dist/components/form/timepicker/TimePickerModal.d.ts.map +1 -0
  26. package/dist/components/form/timepicker/TimePickerModal.js +92 -0
  27. package/dist/components/form/timepicker/TimePickerModal.js.map +1 -0
  28. package/dist/components/form/timepicker/Wheel.d.ts +12 -0
  29. package/dist/components/form/timepicker/Wheel.d.ts.map +1 -0
  30. package/dist/components/form/timepicker/Wheel.js +187 -0
  31. package/dist/components/form/timepicker/Wheel.js.map +1 -0
  32. package/dist/components/form/timepicker/utils.d.ts +4 -0
  33. package/dist/components/form/timepicker/utils.d.ts.map +1 -0
  34. package/dist/components/form/timepicker/utils.js +62 -0
  35. package/dist/components/form/timepicker/utils.js.map +1 -0
  36. package/dist/components/icons/Clock.d.ts +7 -0
  37. package/dist/components/icons/Clock.d.ts.map +1 -0
  38. package/dist/components/icons/Clock.js +45 -0
  39. package/dist/components/icons/Clock.js.map +1 -0
  40. package/dist/components/icons/Icon.d.ts +2 -1
  41. package/dist/components/icons/Icon.d.ts.map +1 -1
  42. package/dist/components/icons/Icon.js +3 -0
  43. package/dist/components/icons/Icon.js.map +1 -1
  44. package/dist/components/ui/drawer/Drawer.d.ts +10 -1
  45. package/dist/components/ui/drawer/Drawer.d.ts.map +1 -1
  46. package/dist/components/ui/drawer/Drawer.js +135 -15
  47. package/dist/components/ui/drawer/Drawer.js.map +1 -1
  48. package/dist/components/ui/drawer/Drawer.styled.d.ts +86 -1
  49. package/dist/components/ui/drawer/Drawer.styled.d.ts.map +1 -1
  50. package/dist/components/ui/drawer/Drawer.styled.js +13 -1
  51. package/dist/components/ui/drawer/Drawer.styled.js.map +1 -1
  52. package/dist/components/ui/modal/Modal.d.ts +1 -2
  53. package/dist/components/ui/modal/Modal.d.ts.map +1 -1
  54. package/dist/components/ui/modal/Modal.js +114 -42
  55. package/dist/components/ui/modal/Modal.js.map +1 -1
  56. package/dist/components/ui/modal/Modal.styled.d.ts +1 -1
  57. package/dist/components/ui/modal/Modal.styled.d.ts.map +1 -1
  58. package/dist/components/ui/modal/Modal.styled.js +40 -25
  59. package/dist/components/ui/modal/Modal.styled.js.map +1 -1
  60. package/dist/components/ui/toaster/Toaster.d.ts.map +1 -1
  61. package/dist/components/ui/toaster/Toaster.js +7 -1
  62. package/dist/components/ui/toaster/Toaster.js.map +1 -1
  63. package/dist/components/ui/tooltip/Tooltip.d.ts +30 -0
  64. package/dist/components/ui/tooltip/Tooltip.d.ts.map +1 -0
  65. package/dist/components/ui/tooltip/Tooltip.js +81 -0
  66. package/dist/components/ui/tooltip/Tooltip.js.map +1 -0
  67. package/dist/components/ui/tooltip/Tooltip.styled.d.ts +173 -0
  68. package/dist/components/ui/tooltip/Tooltip.styled.d.ts.map +1 -0
  69. package/dist/components/ui/tooltip/Tooltip.styled.js +65 -0
  70. package/dist/components/ui/tooltip/Tooltip.styled.js.map +1 -0
  71. package/dist/index.d.ts +1 -0
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +1 -0
  74. package/dist/index.js.map +1 -1
  75. package/dist/theme.css-global.d.ts.map +1 -1
  76. package/dist/theme.css-global.js +0 -1
  77. package/dist/theme.css-global.js.map +1 -1
  78. package/dist/utils/index.d.ts +1 -0
  79. package/dist/utils/index.d.ts.map +1 -1
  80. package/dist/utils/index.js +1 -0
  81. package/dist/utils/index.js.map +1 -1
  82. package/dist/utils/useNativeValidity.d.ts +11 -0
  83. package/dist/utils/useNativeValidity.d.ts.map +1 -0
  84. package/dist/utils/useNativeValidity.js +32 -0
  85. package/dist/utils/useNativeValidity.js.map +1 -0
  86. package/docs/assets/highlight.css +7 -0
  87. package/docs/assets/navigation.js +1 -1
  88. package/docs/assets/search.js +1 -1
  89. package/docs/classes/index.Pop.html +7 -7
  90. package/docs/documents/Test.html +2 -2
  91. package/docs/enums/index.ICON.html +3 -2
  92. package/docs/functions/index.Action.html +3 -3
  93. package/docs/functions/index.Button.html +4 -4
  94. package/docs/functions/index.Card.html +3 -3
  95. package/docs/functions/index.Checkbox.html +3 -3
  96. package/docs/functions/index.Choice.html +2 -2
  97. package/docs/functions/index.ColorPicker.html +3 -3
  98. package/docs/functions/index.CoveringLoader.html +3 -3
  99. package/docs/functions/index.DirectionPad.html +2 -2
  100. package/docs/functions/index.Drawer.html +2 -2
  101. package/docs/functions/index.EqualActions.html +2 -2
  102. package/docs/functions/index.FullLoader.html +3 -3
  103. package/docs/functions/index.Gap.html +3 -3
  104. package/docs/functions/index.HandleEsc.html +3 -3
  105. package/docs/functions/index.Header.html +3 -3
  106. package/docs/functions/index.HeaderIconAction.html +3 -3
  107. package/docs/functions/index.Icon-1.html +2 -2
  108. package/docs/functions/index.If.html +3 -3
  109. package/docs/functions/index.Input.html +1 -1
  110. package/docs/functions/index.KeyValue.html +2 -2
  111. package/docs/functions/index.Label.html +2 -2
  112. package/docs/functions/index.Line.html +4 -4
  113. package/docs/functions/index.List.html +2 -2
  114. package/docs/functions/index.Loader.html +3 -3
  115. package/docs/functions/index.Loading.html +3 -3
  116. package/docs/functions/index.Message.html +4 -4
  117. package/docs/functions/index.Modal.html +2 -2
  118. package/docs/functions/index.ModalButtons.html +3 -3
  119. package/docs/functions/index.PopLoader.html +3 -3
  120. package/docs/functions/index.PopOption.html +2 -2
  121. package/docs/functions/index.Progress.html +2 -2
  122. package/docs/functions/index.SearchContainer.html +3 -3
  123. package/docs/functions/index.Section.html +4 -4
  124. package/docs/functions/index.Select.html +3 -3
  125. package/docs/functions/index.Selector.html +2 -2
  126. package/docs/functions/index.Spacer.html +3 -3
  127. package/docs/functions/index.Stats.html +2 -2
  128. package/docs/functions/index.StickyHeader.html +4 -4
  129. package/docs/functions/index.Table.html +3 -3
  130. package/docs/functions/index.TextArea.html +2 -2
  131. package/docs/functions/index.TimePicker.html +10 -0
  132. package/docs/functions/index.ToasterProvider.html +3 -3
  133. package/docs/functions/index.Toggle.html +3 -3
  134. package/docs/functions/index.ToolButton.html +4 -4
  135. package/docs/functions/index.Tooltip.html +18 -0
  136. package/docs/functions/index.TooltipProvider.html +6 -0
  137. package/docs/functions/index.borderPxToRem.html +1 -1
  138. package/docs/functions/index.createTheme.html +1 -1
  139. package/docs/functions/index.css.html +1 -1
  140. package/docs/functions/index.dimensionsPxToRem.html +1 -1
  141. package/docs/functions/index.fontPxToRem.html +1 -1
  142. package/docs/functions/index.getCssText.html +1 -1
  143. package/docs/functions/index.globalCss.html +2 -2
  144. package/docs/functions/index.injectGlobalStyles.html +1 -1
  145. package/docs/functions/index.keyframes.html +1 -1
  146. package/docs/functions/index.pxToRem.html +1 -1
  147. package/docs/functions/index.styled.html +1 -1
  148. package/docs/functions/index.toast.html +2 -2
  149. package/docs/functions/index.useToaster.html +1 -1
  150. package/docs/index.html +2 -2
  151. package/docs/interfaces/index.IconProps.html +2 -2
  152. package/docs/interfaces/index.InputCustomProps.html +3 -3
  153. package/docs/interfaces/index.LoaderProps.html +6 -6
  154. package/docs/interfaces/index.StickyHeaderProps.html +4 -4
  155. package/docs/interfaces/index.ToasterProviderProps.html +3 -3
  156. package/docs/interfaces/index.TooltipProps.html +36 -0
  157. package/docs/interfaces/index.TooltipProviderProps.html +13 -0
  158. package/docs/modules/index.html +1 -1
  159. package/docs/modules.html +1 -1
  160. package/docs/types/index.ActionProps.html +1 -1
  161. package/docs/types/index.CardProps.html +1 -1
  162. package/docs/types/index.CheckboxProps.html +2 -2
  163. package/docs/types/index.ChoiceProps.html +1 -1
  164. package/docs/types/index.ColorPickerProps.html +1 -1
  165. package/docs/types/index.DirectionPadProps.html +1 -1
  166. package/docs/types/index.DrawerFrom.html +1 -0
  167. package/docs/types/index.DrawerProps.html +28 -1
  168. package/docs/types/index.EqualActionsProps.html +1 -1
  169. package/docs/types/index.HeaderProps.html +1 -1
  170. package/docs/types/index.InputProps.html +1 -1
  171. package/docs/types/index.KeyValueProps.html +1 -1
  172. package/docs/types/index.LabelProps.html +1 -1
  173. package/docs/types/index.OverwriteProps.html +1 -1
  174. package/docs/types/index.ProgressProps.html +2 -2
  175. package/docs/types/index.SelectProps.html +1 -1
  176. package/docs/types/index.SelectorProps.html +1 -1
  177. package/docs/types/index.Stat.html +1 -1
  178. package/docs/types/index.StatsProps.html +1 -1
  179. package/docs/types/index.TextAreaProps.html +1 -1
  180. package/docs/types/index.ThemeCSS.html +1 -1
  181. package/docs/types/index.TimePickerProps.html +1 -0
  182. package/docs/types/index.ToggleProps.html +2 -2
  183. package/docs/variables/index.ActionBadgeSelector.html +1 -1
  184. package/docs/variables/index.ActionCircleSelector.html +1 -1
  185. package/docs/variables/index.CheckboxCheckmarkWrapperSelector.html +1 -1
  186. package/docs/variables/index.CheckboxTextLabelSelector.html +1 -1
  187. package/docs/variables/index.ChoiceItemSelector.html +1 -1
  188. package/docs/variables/index.ColorPickerColorDisplaySelector.html +1 -1
  189. package/docs/variables/index.DirectionPadButtonDotSelector.html +1 -1
  190. package/docs/variables/index.DirectionPadButtonSelector.html +1 -1
  191. package/docs/variables/index.DirectionPadLineSelector.html +1 -1
  192. package/docs/variables/index.DirectionPadMiddleSelector.html +1 -1
  193. package/docs/variables/index.DrawerContentSelector.html +1 -1
  194. package/docs/variables/index.HeaderAfterSelector.html +1 -1
  195. package/docs/variables/index.HeaderBeforeSelector.html +1 -1
  196. package/docs/variables/index.HeaderContentsSelector.html +1 -1
  197. package/docs/variables/index.HeaderIconActionIconSelector.html +1 -1
  198. package/docs/variables/index.InputContainerSelector.html +1 -1
  199. package/docs/variables/index.InputInputSelector.html +1 -1
  200. package/docs/variables/index.InputLabelSelector.html +1 -1
  201. package/docs/variables/index.InputPrefixSelector.html +1 -1
  202. package/docs/variables/index.InputSuffixSelector.html +1 -1
  203. package/docs/variables/index.KeyValueIconSelector.html +1 -1
  204. package/docs/variables/index.KeyValueItemSelector.html +1 -1
  205. package/docs/variables/index.KeyValueKeySelector.html +1 -1
  206. package/docs/variables/index.KeyValuePairSelector.html +1 -1
  207. package/docs/variables/index.KeyValueValueSelector.html +1 -1
  208. package/docs/variables/index.LabelTextSelector.html +1 -1
  209. package/docs/variables/index.ListItemInnerContainerClassNameSelector.html +1 -1
  210. package/docs/variables/index.ModalContainerSelector.html +1 -1
  211. package/docs/variables/index.ModalRemovePaddingSelector.html +1 -1
  212. package/docs/variables/index.ModalTitleSelector.html +1 -1
  213. package/docs/variables/index.PopListSelector.html +1 -1
  214. package/docs/variables/index.PopOptionButtonSelector.html +1 -1
  215. package/docs/variables/index.PopOptionIconSelector.html +1 -1
  216. package/docs/variables/index.PopOverlaySelector.html +1 -1
  217. package/docs/variables/index.ProgressBackgroundSelector.html +1 -1
  218. package/docs/variables/index.ProgressValueSelector.html +1 -1
  219. package/docs/variables/index.SelectorItemSelector.html +1 -1
  220. package/docs/variables/index.StatsItemSelector.html +1 -1
  221. package/docs/variables/index.StatsLabelSelector.html +1 -1
  222. package/docs/variables/index.StatsSeparatorSelector.html +1 -1
  223. package/docs/variables/index.StatsValueSelector.html +1 -1
  224. package/docs/variables/index.TextAreaLabelSelector.html +1 -1
  225. package/docs/variables/index.TextAreaTextAreaSelector.html +1 -1
  226. package/docs/variables/index.TextAreaWrapperSelector.html +1 -1
  227. package/docs/variables/index.ToggleStyledToggleSelector.html +1 -1
  228. package/docs/variables/index.TooltipContentSelector.html +1 -0
  229. package/docs/variables/index.config.html +1 -1
  230. package/docs/variables/index.cssReset.html +2 -2
  231. package/docs/variables/index.darkTheme.html +1 -1
  232. package/docs/variables/index.miuiScrollbars.html +1 -1
  233. package/docs/variables/index.theme.html +1 -1
  234. package/esm/components/form/index.d.ts +1 -0
  235. package/esm/components/form/index.d.ts.map +1 -1
  236. package/esm/components/form/index.js +1 -0
  237. package/esm/components/form/index.js.map +1 -1
  238. package/esm/components/form/input/Input.d.ts.map +1 -1
  239. package/esm/components/form/input/Input.js +9 -5
  240. package/esm/components/form/input/Input.js.map +1 -1
  241. package/esm/components/form/timepicker/TimePicker.css.d.ts +99 -0
  242. package/esm/components/form/timepicker/TimePicker.css.d.ts.map +1 -0
  243. package/esm/components/form/timepicker/TimePicker.css.js +102 -0
  244. package/esm/components/form/timepicker/TimePicker.css.js.map +1 -0
  245. package/esm/components/form/timepicker/TimePicker.d.ts +22 -0
  246. package/esm/components/form/timepicker/TimePicker.d.ts.map +1 -0
  247. package/esm/components/form/timepicker/TimePicker.js +93 -0
  248. package/esm/components/form/timepicker/TimePicker.js.map +1 -0
  249. package/esm/components/form/timepicker/TimePicker.styled.d.ts +936 -0
  250. package/esm/components/form/timepicker/TimePicker.styled.d.ts.map +1 -0
  251. package/esm/components/form/timepicker/TimePicker.styled.js +20 -0
  252. package/esm/components/form/timepicker/TimePicker.styled.js.map +1 -0
  253. package/esm/components/form/timepicker/TimePickerModal.d.ts +17 -0
  254. package/esm/components/form/timepicker/TimePickerModal.d.ts.map +1 -0
  255. package/esm/components/form/timepicker/TimePickerModal.js +56 -0
  256. package/esm/components/form/timepicker/TimePickerModal.js.map +1 -0
  257. package/esm/components/form/timepicker/Wheel.d.ts +12 -0
  258. package/esm/components/form/timepicker/Wheel.d.ts.map +1 -0
  259. package/esm/components/form/timepicker/Wheel.js +151 -0
  260. package/esm/components/form/timepicker/Wheel.js.map +1 -0
  261. package/esm/components/form/timepicker/utils.d.ts +4 -0
  262. package/esm/components/form/timepicker/utils.d.ts.map +1 -0
  263. package/esm/components/form/timepicker/utils.js +58 -0
  264. package/esm/components/form/timepicker/utils.js.map +1 -0
  265. package/esm/components/icons/Clock.d.ts +7 -0
  266. package/esm/components/icons/Clock.d.ts.map +1 -0
  267. package/esm/components/icons/Clock.js +9 -0
  268. package/esm/components/icons/Clock.js.map +1 -0
  269. package/esm/components/icons/Icon.d.ts +2 -1
  270. package/esm/components/icons/Icon.d.ts.map +1 -1
  271. package/esm/components/icons/Icon.js +3 -0
  272. package/esm/components/icons/Icon.js.map +1 -1
  273. package/esm/components/ui/drawer/Drawer.d.ts +10 -1
  274. package/esm/components/ui/drawer/Drawer.d.ts.map +1 -1
  275. package/esm/components/ui/drawer/Drawer.js +139 -15
  276. package/esm/components/ui/drawer/Drawer.js.map +1 -1
  277. package/esm/components/ui/drawer/Drawer.styled.d.ts +86 -1
  278. package/esm/components/ui/drawer/Drawer.styled.d.ts.map +1 -1
  279. package/esm/components/ui/drawer/Drawer.styled.js +12 -1
  280. package/esm/components/ui/drawer/Drawer.styled.js.map +1 -1
  281. package/esm/components/ui/modal/Modal.d.ts +1 -2
  282. package/esm/components/ui/modal/Modal.d.ts.map +1 -1
  283. package/esm/components/ui/modal/Modal.js +103 -43
  284. package/esm/components/ui/modal/Modal.js.map +1 -1
  285. package/esm/components/ui/modal/Modal.styled.d.ts +1 -1
  286. package/esm/components/ui/modal/Modal.styled.d.ts.map +1 -1
  287. package/esm/components/ui/modal/Modal.styled.js +40 -25
  288. package/esm/components/ui/modal/Modal.styled.js.map +1 -1
  289. package/esm/components/ui/toaster/Toaster.d.ts.map +1 -1
  290. package/esm/components/ui/toaster/Toaster.js +8 -2
  291. package/esm/components/ui/toaster/Toaster.js.map +1 -1
  292. package/esm/components/ui/tooltip/Tooltip.d.ts +30 -0
  293. package/esm/components/ui/tooltip/Tooltip.d.ts.map +1 -0
  294. package/esm/components/ui/tooltip/Tooltip.js +43 -0
  295. package/esm/components/ui/tooltip/Tooltip.js.map +1 -0
  296. package/esm/components/ui/tooltip/Tooltip.styled.d.ts +173 -0
  297. package/esm/components/ui/tooltip/Tooltip.styled.d.ts.map +1 -0
  298. package/esm/components/ui/tooltip/Tooltip.styled.js +28 -0
  299. package/esm/components/ui/tooltip/Tooltip.styled.js.map +1 -0
  300. package/esm/index.d.ts +1 -0
  301. package/esm/index.d.ts.map +1 -1
  302. package/esm/index.js +1 -0
  303. package/esm/index.js.map +1 -1
  304. package/esm/theme.css-global.d.ts.map +1 -1
  305. package/esm/theme.css-global.js +0 -1
  306. package/esm/theme.css-global.js.map +1 -1
  307. package/esm/utils/index.d.ts +1 -0
  308. package/esm/utils/index.d.ts.map +1 -1
  309. package/esm/utils/index.js +1 -0
  310. package/esm/utils/index.js.map +1 -1
  311. package/esm/utils/useNativeValidity.d.ts +11 -0
  312. package/esm/utils/useNativeValidity.d.ts.map +1 -0
  313. package/esm/utils/useNativeValidity.js +29 -0
  314. package/esm/utils/useNativeValidity.js.map +1 -0
  315. package/package.json +2 -1
  316. package/pnpm-workspace.yaml +3 -0
  317. package/src/bugfixes/ToastsFromModal.stories.tsx +59 -0
  318. package/src/components/form/index.ts +1 -0
  319. package/src/components/form/input/Input.stories.tsx +47 -1
  320. package/src/components/form/input/Input.tsx +11 -5
  321. package/src/components/form/timepicker/TimePicker.css.ts +132 -0
  322. package/src/components/form/timepicker/TimePicker.stories.tsx +107 -0
  323. package/src/components/form/timepicker/TimePicker.styled.ts +52 -0
  324. package/src/components/form/timepicker/TimePicker.tsx +229 -0
  325. package/src/components/form/timepicker/TimePickerModal.tsx +131 -0
  326. package/src/components/form/timepicker/Wheel.tsx +201 -0
  327. package/src/components/form/timepicker/utils.ts +66 -0
  328. package/src/components/icons/Clock.tsx +38 -0
  329. package/src/components/icons/Icon.tsx +3 -0
  330. package/src/components/ui/drawer/Drawer.stories.tsx +143 -59
  331. package/src/components/ui/drawer/Drawer.styled.ts +13 -0
  332. package/src/components/ui/drawer/Drawer.tsx +214 -20
  333. package/src/components/ui/modal/Modal.stories.tsx +43 -7
  334. package/src/components/ui/modal/Modal.styled.ts +46 -25
  335. package/src/components/ui/modal/Modal.tsx +135 -52
  336. package/src/components/ui/toaster/Toaster.tsx +12 -2
  337. package/src/components/ui/tooltip/Tooltip.stories.tsx +285 -0
  338. package/src/components/ui/tooltip/Tooltip.styled.ts +36 -0
  339. package/src/components/ui/tooltip/Tooltip.tsx +195 -0
  340. package/src/index.ts +1 -0
  341. package/src/theme.css-global.ts +0 -1
  342. package/src/utils/index.ts +1 -0
  343. package/src/utils/useNativeValidity.ts +57 -0
@@ -0,0 +1,59 @@
1
+ import React, { useCallback, useState } from "react";
2
+
3
+ import type { Meta, StoryObj } from "@storybook/react-vite";
4
+
5
+ import { Button } from "../components/ui/button/Button";
6
+ import { Modal } from "../components/ui/modal/Modal";
7
+ import { ModalButtons } from "../components/ui/modal/ModalButtons";
8
+ import { toast } from "../components/ui/toaster/Toaster";
9
+
10
+ const docs = [
11
+ "Real-world setup: the storybook preview wraps every story in a stacking context",
12
+ "(`transform: translateZ(0)` above `ToasterProvider`), which mirrors what real apps",
13
+ "tend to do unintentionally.",
14
+ "",
15
+ "**Without the fix:** sonner's huge z-index is trapped inside that stacking context.",
16
+ "The modal portals to `document.body` and renders on top — the toast is hidden.",
17
+ "",
18
+ "**With the fix:** `ToasterProvider` portals `<SonnerToaster>` to `document.body`,",
19
+ "escaping the stacking context. The toast renders above the modal.",
20
+ ].join("\n");
21
+
22
+ const meta: Meta = {
23
+ title: "Bugfixes/Toasts from a Modal",
24
+ tags: ["bugfixes"],
25
+ parameters: { docs: { description: { component: docs } } },
26
+ };
27
+
28
+ type Story = StoryObj;
29
+
30
+ const ToastFromModal: Story = {
31
+ render: () => {
32
+ const [open, setOpen] = useState(false);
33
+
34
+ const handleOpen = useCallback(() => { setOpen(true); }, []);
35
+ const handleClose = useCallback(() => { setOpen(false); }, []);
36
+ const handleToast = useCallback(() => {
37
+ toast.success("I should appear above the modal");
38
+ }, []);
39
+
40
+ return (
41
+ <div>
42
+ <Button onClick={handleOpen}>Open modal</Button>
43
+ <Modal onClose={handleClose} isOpen={open} title={"Repro"} position={"bottom"} full={true}>
44
+ <p>Click the button — the toast must appear above this modal.</p>
45
+ <ModalButtons>
46
+ <ModalButtons.Button onClick={handleClose}>Cancel</ModalButtons.Button>
47
+ <ModalButtons.Button variant={"main"} onClick={handleToast}>
48
+ Show toast
49
+ </ModalButtons.Button>
50
+ </ModalButtons>
51
+ </Modal>
52
+ </div>
53
+ );
54
+ },
55
+ };
56
+
57
+ export { ToastFromModal };
58
+
59
+ export default meta;
@@ -1 +1,2 @@
1
1
  export * from "./input/Input";
2
+ export * from "./timepicker/TimePicker";
@@ -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
+ };