tempest-react-sdk 0.39.0 → 0.40.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 (475) hide show
  1. package/dist/_virtual/_rolldown/runtime.cjs +1 -1
  2. package/dist/access/access-control-context.cjs.map +1 -1
  3. package/dist/access/use-can.cjs.map +1 -1
  4. package/dist/app/AppProviders.cjs.map +1 -1
  5. package/dist/app/AppProviders.js.map +1 -1
  6. package/dist/audio/use-audio-recorder.cjs.map +1 -1
  7. package/dist/audio/use-audio.cjs.map +1 -1
  8. package/dist/audio/use-microphone.cjs.map +1 -1
  9. package/dist/auth/create-auth-store.cjs.map +1 -1
  10. package/dist/auth/lazy-with-retry.cjs.map +1 -1
  11. package/dist/auth/passkey.cjs.map +1 -1
  12. package/dist/auth/passkey.js.map +1 -1
  13. package/dist/auth/use-passkey.cjs.map +1 -1
  14. package/dist/br/BrazilMap.cjs +1 -1
  15. package/dist/br/BrazilMap.cjs.map +1 -1
  16. package/dist/br/BrazilMap.js +2 -2
  17. package/dist/br/BrazilMap.js.map +1 -1
  18. package/dist/br/BrazilStateCitySelect.cjs.map +1 -1
  19. package/dist/br/BrazilStateCitySelect.js.map +1 -1
  20. package/dist/br/BrazilStateMap.cjs +1 -1
  21. package/dist/br/BrazilStateMap.cjs.map +1 -1
  22. package/dist/br/BrazilStateMap.js +2 -2
  23. package/dist/br/BrazilStateMap.js.map +1 -1
  24. package/dist/br/MapLegend.cjs.map +1 -1
  25. package/dist/br/MapLegend.js.map +1 -1
  26. package/dist/br/MapMarkers.cjs.map +1 -1
  27. package/dist/br/MapMarkers.js.map +1 -1
  28. package/dist/br/MunicipalitySearch.cjs.map +1 -1
  29. package/dist/br/MunicipalitySearch.js.map +1 -1
  30. package/dist/br/PixQRCode.cjs.map +1 -1
  31. package/dist/br/PixQRCode.js.map +1 -1
  32. package/dist/br/use-map-hover.cjs.map +1 -1
  33. package/dist/br/use-map-zoom.cjs.map +1 -1
  34. package/dist/capture/media-recorder.cjs +1 -1
  35. package/dist/capture/media-recorder.js +2 -2
  36. package/dist/capture/use-barcode-scanner.cjs +1 -1
  37. package/dist/capture/use-barcode-scanner.cjs.map +1 -1
  38. package/dist/capture/use-barcode-scanner.js +2 -2
  39. package/dist/capture/use-barcode-scanner.js.map +1 -1
  40. package/dist/capture/use-screen-capture.cjs.map +1 -1
  41. package/dist/capture/use-speech-recognition.cjs.map +1 -1
  42. package/dist/capture/use-torch.cjs.map +1 -1
  43. package/dist/capture/use-video-recorder.cjs.map +1 -1
  44. package/dist/charts/AreaChart.cjs.map +1 -1
  45. package/dist/charts/AreaChart.js.map +1 -1
  46. package/dist/charts/BarChart.cjs.map +1 -1
  47. package/dist/charts/BarChart.js.map +1 -1
  48. package/dist/charts/LineChart.cjs.map +1 -1
  49. package/dist/charts/LineChart.js.map +1 -1
  50. package/dist/charts/PieChart.cjs.map +1 -1
  51. package/dist/charts/PieChart.js.map +1 -1
  52. package/dist/charts/RadarChart.cjs.map +1 -1
  53. package/dist/charts/RadarChart.js.map +1 -1
  54. package/dist/charts/use-chart-colors.cjs.map +1 -1
  55. package/dist/components/AIChat/AIChat.cjs.map +1 -1
  56. package/dist/components/AIChat/AIChat.js.map +1 -1
  57. package/dist/components/AIChat/AIChatComposer.cjs.map +1 -1
  58. package/dist/components/AIChat/AIChatComposer.js.map +1 -1
  59. package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
  60. package/dist/components/AIChat/AIChatTurn.js.map +1 -1
  61. package/dist/components/Accordion/Accordion.cjs.map +1 -1
  62. package/dist/components/Accordion/Accordion.js.map +1 -1
  63. package/dist/components/Alert/Alert.cjs.map +1 -1
  64. package/dist/components/Alert/Alert.js.map +1 -1
  65. package/dist/components/AppBar/AppBar.cjs.map +1 -1
  66. package/dist/components/AppBar/AppBar.js.map +1 -1
  67. package/dist/components/AppShell/AppShell.cjs.map +1 -1
  68. package/dist/components/AppShell/AppShell.js.map +1 -1
  69. package/dist/components/AudioPlayer/AudioPlayer.cjs.map +1 -1
  70. package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -1
  71. package/dist/components/AudioRecorder/AudioRecorder.cjs.map +1 -1
  72. package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -1
  73. package/dist/components/Avatar/Avatar.cjs.map +1 -1
  74. package/dist/components/Avatar/Avatar.js.map +1 -1
  75. package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -1
  76. package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -1
  77. package/dist/components/Badge/Badge.cjs.map +1 -1
  78. package/dist/components/Badge/Badge.js.map +1 -1
  79. package/dist/components/Banner/Banner.cjs.map +1 -1
  80. package/dist/components/Banner/Banner.js.map +1 -1
  81. package/dist/components/BarcodeScanner/BarcodeScanner.cjs.map +1 -1
  82. package/dist/components/BarcodeScanner/BarcodeScanner.js.map +1 -1
  83. package/dist/components/BottomNavigation/BottomNavigation.cjs.map +1 -1
  84. package/dist/components/BottomNavigation/BottomNavigation.js.map +1 -1
  85. package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
  86. package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
  87. package/dist/components/Breadcrumbs/Breadcrumbs.cjs.map +1 -1
  88. package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
  89. package/dist/components/Button/Button.cjs.map +1 -1
  90. package/dist/components/Button/Button.js.map +1 -1
  91. package/dist/components/Calendar/Calendar.cjs +1 -1
  92. package/dist/components/Calendar/Calendar.cjs.map +1 -1
  93. package/dist/components/Calendar/Calendar.js +38 -41
  94. package/dist/components/Calendar/Calendar.js.map +1 -1
  95. package/dist/components/Card/Card.cjs.map +1 -1
  96. package/dist/components/Card/Card.js.map +1 -1
  97. package/dist/components/Carousel/Carousel.cjs.map +1 -1
  98. package/dist/components/Carousel/Carousel.js.map +1 -1
  99. package/dist/components/Chat/Chat.cjs.map +1 -1
  100. package/dist/components/Chat/Chat.js.map +1 -1
  101. package/dist/components/Chat/ChatComposer.cjs.map +1 -1
  102. package/dist/components/Chat/ChatComposer.js.map +1 -1
  103. package/dist/components/Chat/chat-groups.cjs +1 -1
  104. package/dist/components/Chat/chat-groups.cjs.map +1 -1
  105. package/dist/components/Chat/chat-groups.js +2 -2
  106. package/dist/components/Chat/chat-groups.js.map +1 -1
  107. package/dist/components/Checkbox/Checkbox.cjs.map +1 -1
  108. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  109. package/dist/components/ChipInput/ChipInput.cjs.map +1 -1
  110. package/dist/components/ChipInput/ChipInput.js.map +1 -1
  111. package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
  112. package/dist/components/CodeBlock/CodeBlock.cjs.map +1 -1
  113. package/dist/components/CodeBlock/CodeBlock.js.map +1 -1
  114. package/dist/components/Collapsible/Collapsible.cjs.map +1 -1
  115. package/dist/components/Collapsible/Collapsible.js.map +1 -1
  116. package/dist/components/Combobox/Combobox.cjs.map +1 -1
  117. package/dist/components/Combobox/Combobox.js.map +1 -1
  118. package/dist/components/Command/Command.cjs.map +1 -1
  119. package/dist/components/Command/Command.js.map +1 -1
  120. package/dist/components/ConfirmDialog/ConfirmDialog.cjs.map +1 -1
  121. package/dist/components/ConfirmDialog/ConfirmDialog.js.map +1 -1
  122. package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
  123. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  124. package/dist/components/CopyButton/CopyButton.cjs.map +1 -1
  125. package/dist/components/CopyButton/CopyButton.js.map +1 -1
  126. package/dist/components/DataList/DataList.cjs.map +1 -1
  127. package/dist/components/DataList/DataList.js.map +1 -1
  128. package/dist/components/DataTable/DataTable.cjs +1 -1
  129. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  130. package/dist/components/DataTable/DataTable.js +2 -2
  131. package/dist/components/DataTable/DataTable.js.map +1 -1
  132. package/dist/components/DataTable/EditableCell.cjs.map +1 -1
  133. package/dist/components/DataTable/EditableCell.js.map +1 -1
  134. package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
  135. package/dist/components/DateRangePicker/DateRangePicker.cjs.map +1 -1
  136. package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
  137. package/dist/components/DescriptionList/DescriptionList.cjs.map +1 -1
  138. package/dist/components/DescriptionList/DescriptionList.js.map +1 -1
  139. package/dist/components/Divider/Divider.cjs.map +1 -1
  140. package/dist/components/Divider/Divider.js.map +1 -1
  141. package/dist/components/Drawer/Drawer.cjs.map +1 -1
  142. package/dist/components/Drawer/Drawer.js.map +1 -1
  143. package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
  144. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  145. package/dist/components/Dropzone/Dropzone.cjs.map +1 -1
  146. package/dist/components/Dropzone/Dropzone.js.map +1 -1
  147. package/dist/components/EmptyState/EmptyState.cjs.map +1 -1
  148. package/dist/components/EmptyState/EmptyState.js.map +1 -1
  149. package/dist/components/ErrorState/ErrorState.cjs.map +1 -1
  150. package/dist/components/ErrorState/ErrorState.js.map +1 -1
  151. package/dist/components/FileUpload/FileUpload.cjs +1 -1
  152. package/dist/components/FileUpload/FileUpload.cjs.map +1 -1
  153. package/dist/components/FileUpload/FileUpload.js +1 -1
  154. package/dist/components/FileUpload/FileUpload.js.map +1 -1
  155. package/dist/components/FilterBar/FilterBar.cjs.map +1 -1
  156. package/dist/components/FilterBar/FilterBar.js.map +1 -1
  157. package/dist/components/FloatingActionButton/FloatingActionButton.cjs.map +1 -1
  158. package/dist/components/FloatingActionButton/FloatingActionButton.js.map +1 -1
  159. package/dist/components/Form/Form.cjs.map +1 -1
  160. package/dist/components/Form/Form.js.map +1 -1
  161. package/dist/components/HoverCard/HoverCard.cjs.map +1 -1
  162. package/dist/components/HoverCard/HoverCard.js.map +1 -1
  163. package/dist/components/Image/Image.cjs.map +1 -1
  164. package/dist/components/ImageCropper/ImageCropper.cjs +1 -1
  165. package/dist/components/ImageCropper/ImageCropper.cjs.map +1 -1
  166. package/dist/components/ImageCropper/ImageCropper.js +1 -1
  167. package/dist/components/ImageCropper/ImageCropper.js.map +1 -1
  168. package/dist/components/Input/Input.cjs.map +1 -1
  169. package/dist/components/Input/Input.js.map +1 -1
  170. package/dist/components/InstallBanner/InstallBanner.cjs.map +1 -1
  171. package/dist/components/InstallBanner/InstallBanner.js.map +1 -1
  172. package/dist/components/InstallButton/InstallButton.cjs.map +1 -1
  173. package/dist/components/InstallButton/InstallButton.js.map +1 -1
  174. package/dist/components/Kanban/Kanban.cjs.map +1 -1
  175. package/dist/components/Kanban/Kanban.js.map +1 -1
  176. package/dist/components/Label/Label.cjs.map +1 -1
  177. package/dist/components/Label/Label.js.map +1 -1
  178. package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
  179. package/dist/components/Lightbox/Lightbox.js.map +1 -1
  180. package/dist/components/ListTile/ListTile.cjs.map +1 -1
  181. package/dist/components/ListTile/ListTile.js.map +1 -1
  182. package/dist/components/Markdown/Markdown.cjs +1 -1
  183. package/dist/components/Markdown/Markdown.cjs.map +1 -1
  184. package/dist/components/Markdown/Markdown.js +2 -2
  185. package/dist/components/Markdown/Markdown.js.map +1 -1
  186. package/dist/components/Masonry/Masonry.cjs.map +1 -1
  187. package/dist/components/Masonry/Masonry.js.map +1 -1
  188. package/dist/components/Menubar/Menubar.cjs.map +1 -1
  189. package/dist/components/Menubar/Menubar.js.map +1 -1
  190. package/dist/components/Modal/Modal.cjs.map +1 -1
  191. package/dist/components/Modal/Modal.js.map +1 -1
  192. package/dist/components/ModalsManager/ModalsManager.cjs.map +1 -1
  193. package/dist/components/ModalsManager/ModalsManager.js.map +1 -1
  194. package/dist/components/Money/Money.cjs.map +1 -1
  195. package/dist/components/Money/Money.js.map +1 -1
  196. package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
  197. package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
  198. package/dist/components/NProgress/NProgress.cjs.map +1 -1
  199. package/dist/components/Navbar/Navbar.cjs.map +1 -1
  200. package/dist/components/Navbar/Navbar.js.map +1 -1
  201. package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
  202. package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
  203. package/dist/components/NavigationRail/NavigationRail.cjs.map +1 -1
  204. package/dist/components/NavigationRail/NavigationRail.js.map +1 -1
  205. package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -1
  206. package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -1
  207. package/dist/components/NotificationCenter/use-notification-inbox.cjs.map +1 -1
  208. package/dist/components/OfflineIndicator/OfflineIndicator.cjs.map +1 -1
  209. package/dist/components/OfflineIndicator/OfflineIndicator.js.map +1 -1
  210. package/dist/components/Page/Page.cjs.map +1 -1
  211. package/dist/components/Page/Page.js.map +1 -1
  212. package/dist/components/Pagination/Pagination.cjs.map +1 -1
  213. package/dist/components/Pagination/Pagination.js.map +1 -1
  214. package/dist/components/PasswordInput/PasswordInput.cjs.map +1 -1
  215. package/dist/components/PasswordInput/PasswordInput.js.map +1 -1
  216. package/dist/components/PinInput/PinInput.cjs.map +1 -1
  217. package/dist/components/PinInput/PinInput.js.map +1 -1
  218. package/dist/components/Popover/Popover.cjs.map +1 -1
  219. package/dist/components/Popover/Popover.js.map +1 -1
  220. package/dist/components/Portal/Portal.cjs.map +1 -1
  221. package/dist/components/Progress/Progress.cjs.map +1 -1
  222. package/dist/components/Progress/Progress.js.map +1 -1
  223. package/dist/components/QRCode/QRCode.cjs.map +1 -1
  224. package/dist/components/QRCode/QRCode.js.map +1 -1
  225. package/dist/components/Radio/Radio.cjs.map +1 -1
  226. package/dist/components/Radio/Radio.js.map +1 -1
  227. package/dist/components/RangeSlider/RangeSlider.cjs.map +1 -1
  228. package/dist/components/RangeSlider/RangeSlider.js.map +1 -1
  229. package/dist/components/RatingStars/RatingStars.cjs.map +1 -1
  230. package/dist/components/RatingStars/RatingStars.js.map +1 -1
  231. package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
  232. package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
  233. package/dist/components/RelativeTime/RelativeTime.cjs.map +1 -1
  234. package/dist/components/RelativeTime/RelativeTime.js.map +1 -1
  235. package/dist/components/Resizable/Resizable.cjs.map +1 -1
  236. package/dist/components/Resizable/Resizable.js.map +1 -1
  237. package/dist/components/Scheduler/Scheduler.cjs.map +1 -1
  238. package/dist/components/Scheduler/Scheduler.js.map +1 -1
  239. package/dist/components/ScrollArea/ScrollArea.cjs.map +1 -1
  240. package/dist/components/SearchBar/SearchBar.cjs.map +1 -1
  241. package/dist/components/SearchBar/SearchBar.js.map +1 -1
  242. package/dist/components/SegmentedControl/SegmentedControl.cjs.map +1 -1
  243. package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
  244. package/dist/components/Select/Select.cjs.map +1 -1
  245. package/dist/components/Select/Select.js.map +1 -1
  246. package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
  247. package/dist/components/Sidebar/Sidebar.js.map +1 -1
  248. package/dist/components/SignaturePad/SignaturePad.cjs.map +1 -1
  249. package/dist/components/SignaturePad/SignaturePad.js.map +1 -1
  250. package/dist/components/Slider/Slider.cjs.map +1 -1
  251. package/dist/components/Slider/Slider.js.map +1 -1
  252. package/dist/components/Sparkline/Sparkline.cjs.map +1 -1
  253. package/dist/components/Sparkline/Sparkline.js.map +1 -1
  254. package/dist/components/Spinner/Spinner.cjs.map +1 -1
  255. package/dist/components/Spinner/Spinner.js.map +1 -1
  256. package/dist/components/Stat/Stat.cjs.map +1 -1
  257. package/dist/components/Stat/Stat.js.map +1 -1
  258. package/dist/components/Stepper/Stepper.cjs.map +1 -1
  259. package/dist/components/Stepper/Stepper.js.map +1 -1
  260. package/dist/components/StepperInput/StepperInput.cjs.map +1 -1
  261. package/dist/components/StepperInput/StepperInput.js.map +1 -1
  262. package/dist/components/Switch/Switch.cjs.map +1 -1
  263. package/dist/components/Switch/Switch.js.map +1 -1
  264. package/dist/components/SyncStatusBadge/SyncStatusBadge.cjs.map +1 -1
  265. package/dist/components/SyncStatusBadge/SyncStatusBadge.js.map +1 -1
  266. package/dist/components/Table/Table.cjs.map +1 -1
  267. package/dist/components/Table/Table.js.map +1 -1
  268. package/dist/components/Tabs/Tabs.cjs.map +1 -1
  269. package/dist/components/Tabs/Tabs.js.map +1 -1
  270. package/dist/components/Tag/Tag.cjs.map +1 -1
  271. package/dist/components/Tag/Tag.js.map +1 -1
  272. package/dist/components/Textarea/Textarea.cjs.map +1 -1
  273. package/dist/components/Textarea/Textarea.js.map +1 -1
  274. package/dist/components/TimePicker/TimePicker.cjs.map +1 -1
  275. package/dist/components/TimePicker/TimePicker.js.map +1 -1
  276. package/dist/components/Timeline/Timeline.cjs.map +1 -1
  277. package/dist/components/Timeline/Timeline.js.map +1 -1
  278. package/dist/components/Toast/ToastProvider.cjs.map +1 -1
  279. package/dist/components/Toast/ToastProvider.js.map +1 -1
  280. package/dist/components/Toggle/Toggle.cjs.map +1 -1
  281. package/dist/components/ToggleGroup/ToggleGroup.cjs.map +1 -1
  282. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
  283. package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
  284. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  285. package/dist/components/Tour/Tour.cjs.map +1 -1
  286. package/dist/components/Tour/Tour.js.map +1 -1
  287. package/dist/components/Transfer/Transfer.cjs.map +1 -1
  288. package/dist/components/Transfer/Transfer.js.map +1 -1
  289. package/dist/components/TreeView/TreeView.cjs +1 -1
  290. package/dist/components/TreeView/TreeView.cjs.map +1 -1
  291. package/dist/components/TreeView/TreeView.js +1 -4
  292. package/dist/components/TreeView/TreeView.js.map +1 -1
  293. package/dist/components/UpdatePrompt/UpdatePrompt.cjs.map +1 -1
  294. package/dist/components/UpdatePrompt/UpdatePrompt.js.map +1 -1
  295. package/dist/components/VirtualList/VirtualList.cjs.map +1 -1
  296. package/dist/components/VirtualList/VirtualList.js.map +1 -1
  297. package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -1
  298. package/dist/components/VirtualTable/VirtualTable.js.map +1 -1
  299. package/dist/components/VisuallyHidden/VisuallyHidden.cjs.map +1 -1
  300. package/dist/components/Wizard/Wizard.cjs.map +1 -1
  301. package/dist/components/Wizard/Wizard.js.map +1 -1
  302. package/dist/data/data-provider-context.cjs.map +1 -1
  303. package/dist/data/use-resource.cjs.map +1 -1
  304. package/dist/editor/RichTextEditor.cjs.map +1 -1
  305. package/dist/editor/RichTextEditor.js.map +1 -1
  306. package/dist/error-boundary/use-error-handler.cjs.map +1 -1
  307. package/dist/feature-flags/FeatureFlagsProvider.cjs.map +1 -1
  308. package/dist/forms/FormField.cjs.map +1 -1
  309. package/dist/forms/masked-inputs.cjs +1 -1
  310. package/dist/forms/masked-inputs.cjs.map +1 -1
  311. package/dist/forms/masked-inputs.js +1 -1
  312. package/dist/forms/masked-inputs.js.map +1 -1
  313. package/dist/forms/use-viacep.cjs.map +1 -1
  314. package/dist/forms/use-zod-form.cjs.map +1 -1
  315. package/dist/forms/zod-resolver.cjs.map +1 -1
  316. package/dist/forms/zod-resolver.js.map +1 -1
  317. package/dist/geo/TrajectoryMap.cjs.map +1 -1
  318. package/dist/geo/TrajectoryMap.js.map +1 -1
  319. package/dist/geo/leaflet-map.cjs.map +1 -1
  320. package/dist/geo/leaflet-map.js.map +1 -1
  321. package/dist/geo/use-position-tracker.cjs.map +1 -1
  322. package/dist/hooks/use-announce.cjs.map +1 -1
  323. package/dist/hooks/use-async.cjs.map +1 -1
  324. package/dist/hooks/use-before-install-prompt.cjs.map +1 -1
  325. package/dist/hooks/use-breakpoint.cjs.map +1 -1
  326. package/dist/hooks/use-click-outside.cjs.map +1 -1
  327. package/dist/hooks/use-client-filter.cjs.map +1 -1
  328. package/dist/hooks/use-clipboard.cjs.map +1 -1
  329. package/dist/hooks/use-counter.cjs.map +1 -1
  330. package/dist/hooks/use-debounce.cjs.map +1 -1
  331. package/dist/hooks/use-deep-memo.cjs.map +1 -1
  332. package/dist/hooks/use-disclosure.cjs.map +1 -1
  333. package/dist/hooks/use-document-visibility.cjs.map +1 -1
  334. package/dist/hooks/use-event-listener.cjs.map +1 -1
  335. package/dist/hooks/use-geolocation.cjs.map +1 -1
  336. package/dist/hooks/use-hover.cjs.map +1 -1
  337. package/dist/hooks/use-idle.cjs.map +1 -1
  338. package/dist/hooks/use-install-prompt.cjs +1 -1
  339. package/dist/hooks/use-install-prompt.cjs.map +1 -1
  340. package/dist/hooks/use-install-prompt.js +1 -1
  341. package/dist/hooks/use-install-prompt.js.map +1 -1
  342. package/dist/hooks/use-intersection-observer.cjs.map +1 -1
  343. package/dist/hooks/use-interval.cjs.map +1 -1
  344. package/dist/hooks/use-is-first-render.cjs.map +1 -1
  345. package/dist/hooks/use-keyboard-shortcut.cjs +1 -1
  346. package/dist/hooks/use-keyboard-shortcut.cjs.map +1 -1
  347. package/dist/hooks/use-keyboard-shortcut.js +1 -1
  348. package/dist/hooks/use-keyboard-shortcut.js.map +1 -1
  349. package/dist/hooks/use-list-state.cjs.map +1 -1
  350. package/dist/hooks/use-local-storage.cjs.map +1 -1
  351. package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
  352. package/dist/hooks/use-long-press.cjs.map +1 -1
  353. package/dist/hooks/use-map.cjs.map +1 -1
  354. package/dist/hooks/use-media-devices.cjs.map +1 -1
  355. package/dist/hooks/use-media-permission.cjs.map +1 -1
  356. package/dist/hooks/use-media-query.cjs.map +1 -1
  357. package/dist/hooks/use-object-url.cjs.map +1 -1
  358. package/dist/hooks/use-online.cjs.map +1 -1
  359. package/dist/hooks/use-pagination.cjs.map +1 -1
  360. package/dist/hooks/use-previous.cjs.map +1 -1
  361. package/dist/hooks/use-queue.cjs.map +1 -1
  362. package/dist/hooks/use-resize-observer.cjs.map +1 -1
  363. package/dist/hooks/use-scroll-overflow.cjs.map +1 -1
  364. package/dist/hooks/use-service-worker-update.cjs.map +1 -1
  365. package/dist/hooks/use-set.cjs.map +1 -1
  366. package/dist/hooks/use-sortable.cjs +1 -1
  367. package/dist/hooks/use-sortable.cjs.map +1 -1
  368. package/dist/hooks/use-sortable.js +0 -2
  369. package/dist/hooks/use-sortable.js.map +1 -1
  370. package/dist/hooks/use-stable-callback.cjs.map +1 -1
  371. package/dist/hooks/use-storage-estimate.cjs.map +1 -1
  372. package/dist/hooks/use-throttle.cjs.map +1 -1
  373. package/dist/hooks/use-timeout.cjs.map +1 -1
  374. package/dist/hooks/use-toggle.cjs.map +1 -1
  375. package/dist/hooks/use-window-size.cjs.map +1 -1
  376. package/dist/http/api-client.cjs +1 -1
  377. package/dist/http/api-client.cjs.map +1 -1
  378. package/dist/http/api-client.js +7 -5
  379. package/dist/http/api-client.js.map +1 -1
  380. package/dist/http/resumable-upload.cjs +1 -1
  381. package/dist/http/resumable-upload.cjs.map +1 -1
  382. package/dist/http/resumable-upload.js +1 -1
  383. package/dist/http/resumable-upload.js.map +1 -1
  384. package/dist/http/use-poll.cjs.map +1 -1
  385. package/dist/i18n/I18nProvider.cjs.map +1 -1
  386. package/dist/icons/Icon.cjs.map +1 -1
  387. package/dist/icons/IconProvider.cjs.map +1 -1
  388. package/dist/icons/icon-context.cjs.map +1 -1
  389. package/dist/icons/use-icon.cjs.map +1 -1
  390. package/dist/imaging/use-image-processing.cjs.map +1 -1
  391. package/dist/oauth/GoogleSignIn.cjs.map +1 -1
  392. package/dist/oauth/GoogleSignIn.js.map +1 -1
  393. package/dist/oauth/use-oauth-callback.cjs.map +1 -1
  394. package/dist/offline/use-offline-sync.cjs.map +1 -1
  395. package/dist/push/use-push-subscription.cjs.map +1 -1
  396. package/dist/query/QueryProvider.cjs.map +1 -1
  397. package/dist/query/constants.cjs +1 -1
  398. package/dist/query/constants.cjs.map +1 -1
  399. package/dist/query/constants.js +10 -10
  400. package/dist/query/constants.js.map +1 -1
  401. package/dist/query/create-query-keys.cjs +1 -1
  402. package/dist/query/create-query-keys.cjs.map +1 -1
  403. package/dist/query/create-query-keys.js +1 -1
  404. package/dist/query/create-query-keys.js.map +1 -1
  405. package/dist/query/offline-persistence.cjs.map +1 -1
  406. package/dist/query/use-cursor-query.cjs.map +1 -1
  407. package/dist/query/use-offline-mutation.cjs.map +1 -1
  408. package/dist/query/use-paginated-query.cjs.map +1 -1
  409. package/dist/router/AppRouter.cjs +1 -1
  410. package/dist/router/AppRouter.cjs.map +1 -1
  411. package/dist/router/AppRouter.js +7 -2
  412. package/dist/router/AppRouter.js.map +1 -1
  413. package/dist/sse/use-event-stream.cjs.map +1 -1
  414. package/dist/store/create-store.cjs.map +1 -1
  415. package/dist/tabular/use-tabular-predictor.cjs.map +1 -1
  416. package/dist/telemetry/TelemetryProvider.cjs.map +1 -1
  417. package/dist/tempest-react-sdk.d.ts +25 -26
  418. package/dist/theme/ThemeProvider.cjs.map +1 -1
  419. package/dist/theme/color.cjs +1 -1
  420. package/dist/theme/color.cjs.map +1 -1
  421. package/dist/theme/color.js +1 -1
  422. package/dist/theme/color.js.map +1 -1
  423. package/dist/utils/cn.cjs +1 -1
  424. package/dist/utils/cn.cjs.map +1 -1
  425. package/dist/utils/cn.js +1 -1
  426. package/dist/utils/cn.js.map +1 -1
  427. package/dist/utils/objects.cjs +1 -1
  428. package/dist/utils/objects.cjs.map +1 -1
  429. package/dist/utils/objects.js +1 -1
  430. package/dist/utils/objects.js.map +1 -1
  431. package/dist/utils/xlsx.cjs +1 -1
  432. package/dist/utils/xlsx.cjs.map +1 -1
  433. package/dist/utils/xlsx.js +3 -3
  434. package/dist/utils/xlsx.js.map +1 -1
  435. package/dist/vision/core/exceptions.cjs.map +1 -1
  436. package/dist/vision/core/exceptions.js.map +1 -1
  437. package/dist/vision/core/metadata.cjs +1 -1
  438. package/dist/vision/core/metadata.cjs.map +1 -1
  439. package/dist/vision/core/metadata.js +1 -1
  440. package/dist/vision/core/metadata.js.map +1 -1
  441. package/dist/vision/io/image.cjs +1 -1
  442. package/dist/vision/io/image.cjs.map +1 -1
  443. package/dist/vision/io/image.js +4 -2
  444. package/dist/vision/io/image.js.map +1 -1
  445. package/dist/vision/preprocess/image.cjs +1 -1
  446. package/dist/vision/preprocess/image.cjs.map +1 -1
  447. package/dist/vision/preprocess/image.js +4 -2
  448. package/dist/vision/preprocess/image.js.map +1 -1
  449. package/dist/vision/tasks/base.cjs +1 -1
  450. package/dist/vision/tasks/base.cjs.map +1 -1
  451. package/dist/vision/tasks/base.js +3 -1
  452. package/dist/vision/tasks/base.js.map +1 -1
  453. package/dist/vision/tasks/classifier.cjs +1 -1
  454. package/dist/vision/tasks/classifier.cjs.map +1 -1
  455. package/dist/vision/tasks/classifier.js +2 -2
  456. package/dist/vision/tasks/classifier.js.map +1 -1
  457. package/dist/vision/tasks/detectClassify.cjs +1 -1
  458. package/dist/vision/tasks/detectClassify.cjs.map +1 -1
  459. package/dist/vision/tasks/detectClassify.js +16 -15
  460. package/dist/vision/tasks/detectClassify.js.map +1 -1
  461. package/dist/vision/use-camera-stream.cjs.map +1 -1
  462. package/dist/vision/use-live-luminance.cjs.map +1 -1
  463. package/dist/vite/create-vite-config.cjs +1 -1
  464. package/dist/vite/create-vite-config.cjs.map +1 -1
  465. package/dist/vite/create-vite-config.js +3 -3
  466. package/dist/vite/create-vite-config.js.map +1 -1
  467. package/dist/vite/tempest-icons.cjs.map +1 -1
  468. package/dist/vite/tempest-pwa-dev-sw.cjs.map +1 -1
  469. package/dist/vite/tempest-pwa-icons.cjs.map +1 -1
  470. package/dist/ws/use-web-socket.cjs +1 -1
  471. package/dist/ws/use-web-socket.cjs.map +1 -1
  472. package/dist/ws/use-web-socket.js +5 -3
  473. package/dist/ws/use-web-socket.js.map +1 -1
  474. package/package.json +2 -2
  475. package/template/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"RangeSlider.js","names":[],"sources":["../../../src/components/RangeSlider/RangeSlider.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — min, max and step define the scale, value/onChange\n * the two thumbs, formatValue the readout, and label/helperText/disabled/className\n * the field around it. Same surface as Slider, one thumb more.\n */\nimport { useCallback, useMemo } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./RangeSlider.module.css\";\n\nexport type RangeValue = [number, number];\n\nexport interface RangeSliderProps {\n value: RangeValue;\n onChange: (value: RangeValue) => void;\n min?: number;\n max?: number;\n step?: number;\n label?: string;\n helperText?: string;\n disabled?: boolean;\n /** Formatter for the value badge next to the label. Defaults to `min – max`. */\n formatValue?: (value: RangeValue) => string;\n className?: string;\n}\n\n/**\n * Dual-thumb range slider. Built on two native `<input type=\"range\">` so it\n * stays accessible and works with keyboards/screen readers without\n * heavyweight positioning libs. The active fill is positioned via percentages.\n */\nexport function RangeSlider({\n value,\n onChange,\n min = 0,\n max = 100,\n step = 1,\n label,\n helperText,\n disabled = false,\n formatValue,\n className,\n}: RangeSliderProps) {\n const [low, high] = value;\n const range = max - min;\n\n const fillLeft = useMemo(() => ((low - min) / range) * 100, [low, min, range]);\n const fillRight = useMemo(() => ((high - min) / range) * 100, [high, min, range]);\n\n const valueText = formatValue?.(value) ?? `${low} – ${high}`;\n\n const handleLow = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>): void => {\n const next = Math.min(Number(event.target.value), high);\n onChange([next, high]);\n },\n [high, onChange],\n );\n\n const handleHigh = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>): void => {\n const next = Math.max(Number(event.target.value), low);\n onChange([low, next]);\n },\n [low, onChange],\n );\n\n return (\n <div className={cn(styles.wrapper, className)}>\n {label && (\n <div className={styles.label}>\n <span>{label}</span>\n <span className={styles.value}>{valueText}</span>\n </div>\n )}\n <div className={styles.field}>\n <div className={styles.track} />\n <div\n className={styles.fill}\n style={{ left: `${fillLeft}%`, right: `${100 - fillRight}%` }}\n />\n <input\n type=\"range\"\n className={styles.input}\n min={min}\n max={max}\n step={step}\n value={low}\n onChange={handleLow}\n disabled={disabled}\n aria-label={label ? `${label} (mínimo)` : \"Mínimo\"}\n />\n <input\n type=\"range\"\n className={styles.input}\n min={min}\n max={max}\n step={step}\n value={high}\n onChange={handleHigh}\n disabled={disabled}\n aria-label={label ? `${label} (máximo)` : \"Máximo\"}\n />\n </div>\n {helperText && <span className={styles.helper}>{helperText}</span>}\n </div>\n );\n}\n"],"mappings":";;;;;AA8BA,SAAgB,EAAY,EACxB,UACA,aACA,SAAM,GACN,SAAM,KACN,UAAO,GACP,UACA,eACA,cAAW,IACX,gBACA,gBACiB;CACjB,IAAM,CAAC,GAAK,KAAQ,GACd,IAAQ,IAAM,GAEd,IAAW,SAAgB,IAAM,KAAO,IAAS,KAAK;EAAC;EAAK;EAAK;CAAK,CAAC,GACvE,IAAY,SAAgB,IAAO,KAAO,IAAS,KAAK;EAAC;EAAM;EAAK;CAAK,CAAC,GAE1E,IAAY,IAAc,CAAK,KAAK,GAAG,EAAI,KAAK,KAEhD,IAAY,GACb,MAAqD;EAElD,EAAS,CADI,KAAK,IAAI,OAAO,EAAM,OAAO,KAAK,GAAG,CACxC,GAAM,CAAI,CAAC;CACzB,GACA,CAAC,GAAM,CAAQ,CACnB,GAEM,IAAa,GACd,MAAqD;EAClD,IAAM,IAAO,KAAK,IAAI,OAAO,EAAM,OAAO,KAAK,GAAG,CAAG;EACrD,EAAS,CAAC,GAAK,CAAI,CAAC;CACxB,GACA,CAAC,GAAK,CAAQ,CAClB;CAEA,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAS;YAA5C;GACK,KACG,kBAAC,OAAD;IAAK,WAAW,EAAO;cAAvB,CACI,kBAAC,QAAD,EAAA,UAAO,EAAY,CAAA,GACnB,kBAAC,QAAD;KAAM,WAAW,EAAO;eAAQ;IAAgB,CAAA,CAC/C;;GAET,kBAAC,OAAD;IAAK,WAAW,EAAO;cAAvB;KACI,kBAAC,OAAD,EAAK,WAAW,EAAO,MAAQ,CAAA;KAC/B,kBAAC,OAAD;MACI,WAAW,EAAO;MAClB,OAAO;OAAE,MAAM,GAAG,EAAS;OAAI,OAAO,GAAG,MAAM,EAAU;MAAG;KAC/D,CAAA;KACD,kBAAC,SAAD;MACI,MAAK;MACL,WAAW,EAAO;MACb;MACA;MACC;MACN,OAAO;MACP,UAAU;MACA;MACV,cAAY,IAAQ,GAAG,EAAM,aAAa;KAC7C,CAAA;KACD,kBAAC,SAAD;MACI,MAAK;MACL,WAAW,EAAO;MACb;MACA;MACC;MACN,OAAO;MACP,UAAU;MACA;MACV,cAAY,IAAQ,GAAG,EAAM,aAAa;KAC7C,CAAA;IACA;;GACJ,KAAc,kBAAC,QAAD;IAAM,WAAW,EAAO;cAAS;GAAiB,CAAA;EAChE;;AAEb"}
1
+ {"version":3,"file":"RangeSlider.js","names":[],"sources":["../../../src/components/RangeSlider/RangeSlider.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — min, max and step define the scale, value/onChange\n * the two thumbs, formatValue the readout, and label/helperText/disabled/className\n * the field around it. Same surface as Slider, one thumb more.\n */\nimport { useCallback, useMemo } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./RangeSlider.module.css\";\n\nexport type RangeValue = [number, number];\n\nexport interface RangeSliderProps {\n value: RangeValue;\n onChange: (value: RangeValue) => void;\n min?: number;\n max?: number;\n step?: number;\n label?: string;\n helperText?: string;\n disabled?: boolean;\n /** Formatter for the value badge next to the label. Defaults to `min – max`. */\n formatValue?: (value: RangeValue) => string;\n className?: string;\n}\n\n/**\n * Dual-thumb range slider. Built on two native `<input type=\"range\">` so it\n * stays accessible and works with keyboards/screen readers without\n * heavyweight positioning libs. The active fill is positioned via percentages.\n */\nexport function RangeSlider({\n value,\n onChange,\n min = 0,\n max = 100,\n step = 1,\n label,\n helperText,\n disabled = false,\n formatValue,\n className,\n}: RangeSliderProps) {\n const [low, high] = value;\n const range = max - min;\n\n const fillLeft = useMemo(() => ((low - min) / range) * 100, [low, min, range]);\n const fillRight = useMemo(() => ((high - min) / range) * 100, [high, min, range]);\n\n const valueText = formatValue?.(value) ?? `${low} – ${high}`;\n\n const handleLow = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>): void => {\n const next = Math.min(Number(event.target.value), high);\n onChange([next, high]);\n },\n [high, onChange],\n );\n\n const handleHigh = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>): void => {\n const next = Math.max(Number(event.target.value), low);\n onChange([low, next]);\n },\n [low, onChange],\n );\n\n return (\n <div className={cn(styles.wrapper, className)}>\n {label && (\n <div className={styles.label}>\n <span>{label}</span>\n <span className={styles.value}>{valueText}</span>\n </div>\n )}\n <div className={styles.field}>\n <div className={styles.track} />\n <div\n className={styles.fill}\n style={{ left: `${fillLeft}%`, right: `${100 - fillRight}%` }}\n />\n <input\n type=\"range\"\n className={styles.input}\n min={min}\n max={max}\n step={step}\n value={low}\n onChange={handleLow}\n disabled={disabled}\n aria-label={label ? `${label} (mínimo)` : \"Mínimo\"}\n />\n <input\n type=\"range\"\n className={styles.input}\n min={min}\n max={max}\n step={step}\n value={high}\n onChange={handleHigh}\n disabled={disabled}\n aria-label={label ? `${label} (máximo)` : \"Máximo\"}\n />\n </div>\n {helperText && <span className={styles.helper}>{helperText}</span>}\n </div>\n );\n}\n"],"mappings":";;;;;AA8BA,SAAgB,EAAY,EACxB,UACA,aACA,SAAM,GACN,SAAM,KACN,UAAO,GACP,UACA,eACA,cAAW,IACX,gBACA,gBACiB;CACjB,IAAM,CAAC,GAAK,KAAQ,GACd,IAAQ,IAAM,GAEd,IAAW,SAAgB,IAAM,KAAO,IAAS,KAAK;EAAC;EAAK;EAAK;CAAK,CAAC,GACvE,IAAY,SAAgB,IAAO,KAAO,IAAS,KAAK;EAAC;EAAM;EAAK;CAAK,CAAC,GAE1E,IAAY,IAAc,CAAK,KAAK,GAAG,EAAI,KAAK,KAEhD,IAAY,GACb,MAAqD;EAElD,EAAS,CADI,KAAK,IAAI,OAAO,EAAM,OAAO,KAAK,GAAG,CACxC,GAAM,CAAI,CAAC;CACzB,GACA,CAAC,GAAM,CAAQ,CACnB,GAEM,IAAa,GACd,MAAqD;EAClD,IAAM,IAAO,KAAK,IAAI,OAAO,EAAM,OAAO,KAAK,GAAG,CAAG;EACrD,EAAS,CAAC,GAAK,CAAI,CAAC;CACxB,GACA,CAAC,GAAK,CAAQ,CAClB;CAEA,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAS;EAA5C,UAAA;GACK,KACG,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAvB,UAAA,CACI,kBAAC,QAAD,EAAA,UAAO,EAAY,CAAA,GACnB,kBAAC,QAAD;KAAM,WAAW,EAAO;KAAQ,UAAA;IAAgB,CAAA,CAC/C;;GAET,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAvB,UAAA;KACI,kBAAC,OAAD,EAAK,WAAW,EAAO,MAAQ,CAAA;KAC/B,kBAAC,OAAD;MACI,WAAW,EAAO;MAClB,OAAO;OAAE,MAAM,GAAG,EAAS;OAAI,OAAO,GAAG,MAAM,EAAU;MAAG;KAC/D,CAAA;KACD,kBAAC,SAAD;MACI,MAAK;MACL,WAAW,EAAO;MACb;MACA;MACC;MACN,OAAO;MACP,UAAU;MACA;MACV,cAAY,IAAQ,GAAG,EAAM,aAAa;KAC7C,CAAA;KACD,kBAAC,SAAD;MACI,MAAK;MACL,WAAW,EAAO;MACb;MACA;MACC;MACN,OAAO;MACP,UAAU;MACA;MACV,cAAY,IAAQ,GAAG,EAAM,aAAa;KAC7C,CAAA;IACA;;GACJ,KAAc,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAS,UAAA;GAAiB,CAAA;EAChE;;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"RatingStars.cjs","names":[],"sources":["../../../src/components/RatingStars/RatingStars.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — value, max, onChange, size, readonly, disabled,\n * label, className — a rating is a radio group drawn as stars, and readonly and\n * disabled are genuinely different (a shown rating versus a control you cannot use).\n */\nimport { useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./RatingStars.module.css\";\n\nexport type RatingSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface RatingStarsProps {\n /** Current selected value (1..max). 0 means none. */\n value: number;\n /** Total number of stars. Default 5. */\n max?: number;\n onChange?: (value: number) => void;\n size?: RatingSize;\n readonly?: boolean;\n disabled?: boolean;\n /** Accessible label for the rating group. */\n label?: string;\n className?: string;\n}\n\n/**\n * Star rating control. Renders `max` stars, fills the first `value`. Click a\n * star to set rating (when not readonly). Hovering previews the value.\n */\nexport function RatingStars({\n value,\n max = 5,\n onChange,\n size = \"md\",\n readonly = false,\n disabled = false,\n label = \"Avaliação\",\n className,\n}: RatingStarsProps) {\n const [hover, setHover] = useState<number>(0);\n const displayed = hover > 0 ? hover : value;\n\n const handleClick = (next: number): void => {\n if (readonly || disabled) return;\n onChange?.(next);\n };\n\n return (\n <span\n role=\"radiogroup\"\n aria-label={label}\n className={cn(\n styles.wrapper,\n styles[size],\n disabled && styles.disabled,\n readonly && styles.readonly,\n className,\n )}\n onMouseLeave={() => setHover(0)}\n >\n {Array.from({ length: max }, (_, i) => {\n const starIndex = i + 1;\n const filled = starIndex <= displayed;\n return (\n <button\n key={starIndex}\n type=\"button\"\n role=\"radio\"\n aria-checked={value === starIndex}\n aria-label={`${starIndex} ${starIndex === 1 ? \"estrela\" : \"estrelas\"}`}\n className={cn(styles.star, filled && styles.filled)}\n disabled={disabled}\n onMouseEnter={() => !readonly && !disabled && setHover(starIndex)}\n onClick={() => handleClick(starIndex)}\n >\n <StarIcon filled={filled} />\n </button>\n );\n })}\n </span>\n );\n}\n\nfunction StarIcon({ filled }: { filled: boolean }) {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill={filled ? \"currentColor\" : \"none\"}\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n <path d=\"M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.56 5.82 22 7 14.14 2 9.27l6.91-1.01L12 2z\" />\n </svg>\n );\n}\n"],"mappings":"kIA6BA,SAAgB,EAAY,CACxB,QACA,MAAM,EACN,WACA,OAAO,KACP,WAAW,GACX,WAAW,GACX,QAAQ,YACR,aACiB,CACjB,GAAM,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,CAA6B,CAAC,EACtC,EAAY,EAAQ,EAAI,EAAQ,EAEhC,EAAe,GAAuB,CACpC,GAAY,GAChB,IAAW,CAAI,CACnB,EAEA,OACI,EAAA,EAAA,IAAA,CAAC,OAAD,CACI,KAAK,aACL,aAAY,EACZ,UAAW,EAAA,GACP,EAAA,QAAO,QACP,EAAA,QAAO,GACP,GAAY,EAAA,QAAO,SACnB,GAAY,EAAA,QAAO,SACnB,CACJ,EACA,iBAAoB,EAAS,CAAC,WAE7B,MAAM,KAAK,CAAE,OAAQ,CAAI,GAAI,EAAG,IAAM,CACnC,IAAM,EAAY,EAAI,EAChB,EAAS,GAAa,EAC5B,OACI,EAAA,EAAA,IAAA,CAAC,SAAD,CAEI,KAAK,SACL,KAAK,QACL,eAAc,IAAU,EACxB,aAAY,GAAG,EAAU,GAAG,IAAc,EAAI,UAAY,aAC1D,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,GAAU,EAAA,QAAO,MAAM,EACxC,WACV,iBAAoB,CAAC,GAAY,CAAC,GAAY,EAAS,CAAS,EAChE,YAAe,EAAY,CAAS,YAEpC,EAAA,EAAA,IAAA,CAAC,EAAD,CAAkB,QAAS,CAAA,CACvB,EAXC,CAWD,CAEhB,CAAC,CACC,CAAA,CAEd,CAEA,SAAS,EAAS,CAAE,UAA+B,CAC/C,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAM,EAAS,eAAiB,OAChC,OAAO,eACP,YAAY,MACZ,eAAe,QACf,cAAA,aAEA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,0FAA4F,CAAA,CACnG,CAAA,CAEb"}
1
+ {"version":3,"file":"RatingStars.cjs","names":[],"sources":["../../../src/components/RatingStars/RatingStars.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — value, max, onChange, size, readonly, disabled,\n * label, className — a rating is a radio group drawn as stars, and readonly and\n * disabled are genuinely different (a shown rating versus a control you cannot use).\n */\nimport { useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./RatingStars.module.css\";\n\nexport type RatingSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface RatingStarsProps {\n /** Current selected value (1..max). 0 means none. */\n value: number;\n /** Total number of stars. Default 5. */\n max?: number;\n onChange?: (value: number) => void;\n size?: RatingSize;\n readonly?: boolean;\n disabled?: boolean;\n /** Accessible label for the rating group. */\n label?: string;\n className?: string;\n}\n\n/**\n * Star rating control. Renders `max` stars, fills the first `value`. Click a\n * star to set rating (when not readonly). Hovering previews the value.\n */\nexport function RatingStars({\n value,\n max = 5,\n onChange,\n size = \"md\",\n readonly = false,\n disabled = false,\n label = \"Avaliação\",\n className,\n}: RatingStarsProps) {\n const [hover, setHover] = useState<number>(0);\n const displayed = hover > 0 ? hover : value;\n\n const handleClick = (next: number): void => {\n if (readonly || disabled) return;\n onChange?.(next);\n };\n\n return (\n <span\n role=\"radiogroup\"\n aria-label={label}\n className={cn(\n styles.wrapper,\n styles[size],\n disabled && styles.disabled,\n readonly && styles.readonly,\n className,\n )}\n onMouseLeave={() => setHover(0)}\n >\n {Array.from({ length: max }, (_, i) => {\n const starIndex = i + 1;\n const filled = starIndex <= displayed;\n return (\n <button\n key={starIndex}\n type=\"button\"\n role=\"radio\"\n aria-checked={value === starIndex}\n aria-label={`${starIndex} ${starIndex === 1 ? \"estrela\" : \"estrelas\"}`}\n className={cn(styles.star, filled && styles.filled)}\n disabled={disabled}\n onMouseEnter={() => !readonly && !disabled && setHover(starIndex)}\n onClick={() => handleClick(starIndex)}\n >\n <StarIcon filled={filled} />\n </button>\n );\n })}\n </span>\n );\n}\n\nfunction StarIcon({ filled }: { filled: boolean }) {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill={filled ? \"currentColor\" : \"none\"}\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n <path d=\"M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.56 5.82 22 7 14.14 2 9.27l6.91-1.01L12 2z\" />\n </svg>\n );\n}\n"],"mappings":"kIA6BA,SAAgB,EAAY,CACxB,QACA,MAAM,EACN,WACA,OAAO,KACP,WAAW,GACX,WAAW,GACX,QAAQ,YACR,aACiB,CACjB,GAAM,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAiB,CAAC,EACtC,EAAY,EAAQ,EAAI,EAAQ,EAEhC,EAAe,GAAuB,CACpC,GAAY,GAChB,IAAW,CAAI,CACnB,EAEA,OACI,EAAA,EAAA,IAAA,CAAC,OAAD,CACI,KAAK,aACL,aAAY,EACZ,UAAW,EAAA,GACP,EAAA,QAAO,QACP,EAAA,QAAO,GACP,GAAY,EAAA,QAAO,SACnB,GAAY,EAAA,QAAO,SACnB,CACJ,EACA,iBAAoB,EAAS,CAAC,EAE7B,SAAA,MAAM,KAAK,CAAE,OAAQ,CAAI,GAAI,EAAG,IAAM,CACnC,IAAM,EAAY,EAAI,EAChB,EAAS,GAAa,EAC5B,OACI,EAAA,EAAA,IAAA,CAAC,SAAD,CAEI,KAAK,SACL,KAAK,QACL,eAAc,IAAU,EACxB,aAAY,GAAG,EAAU,GAAG,IAAc,EAAI,UAAY,aAC1D,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,GAAU,EAAA,QAAO,MAAM,EACxC,WACV,iBAAoB,CAAC,GAAY,CAAC,GAAY,EAAS,CAAS,EAChE,YAAe,EAAY,CAAS,EAEpC,UAAA,EAAA,EAAA,IAAA,CAAC,EAAD,CAAkB,QAAS,CAAA,CACvB,EAXC,CAWD,CAEhB,CAAC,CACC,CAAA,CAEd,CAEA,SAAS,EAAS,CAAE,UAA+B,CAC/C,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAM,EAAS,eAAiB,OAChC,OAAO,eACP,YAAY,MACZ,eAAe,QACf,cAAA,GAEA,UAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,0FAA4F,CAAA,CACnG,CAAA,CAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"RatingStars.js","names":[],"sources":["../../../src/components/RatingStars/RatingStars.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — value, max, onChange, size, readonly, disabled,\n * label, className — a rating is a radio group drawn as stars, and readonly and\n * disabled are genuinely different (a shown rating versus a control you cannot use).\n */\nimport { useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./RatingStars.module.css\";\n\nexport type RatingSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface RatingStarsProps {\n /** Current selected value (1..max). 0 means none. */\n value: number;\n /** Total number of stars. Default 5. */\n max?: number;\n onChange?: (value: number) => void;\n size?: RatingSize;\n readonly?: boolean;\n disabled?: boolean;\n /** Accessible label for the rating group. */\n label?: string;\n className?: string;\n}\n\n/**\n * Star rating control. Renders `max` stars, fills the first `value`. Click a\n * star to set rating (when not readonly). Hovering previews the value.\n */\nexport function RatingStars({\n value,\n max = 5,\n onChange,\n size = \"md\",\n readonly = false,\n disabled = false,\n label = \"Avaliação\",\n className,\n}: RatingStarsProps) {\n const [hover, setHover] = useState<number>(0);\n const displayed = hover > 0 ? hover : value;\n\n const handleClick = (next: number): void => {\n if (readonly || disabled) return;\n onChange?.(next);\n };\n\n return (\n <span\n role=\"radiogroup\"\n aria-label={label}\n className={cn(\n styles.wrapper,\n styles[size],\n disabled && styles.disabled,\n readonly && styles.readonly,\n className,\n )}\n onMouseLeave={() => setHover(0)}\n >\n {Array.from({ length: max }, (_, i) => {\n const starIndex = i + 1;\n const filled = starIndex <= displayed;\n return (\n <button\n key={starIndex}\n type=\"button\"\n role=\"radio\"\n aria-checked={value === starIndex}\n aria-label={`${starIndex} ${starIndex === 1 ? \"estrela\" : \"estrelas\"}`}\n className={cn(styles.star, filled && styles.filled)}\n disabled={disabled}\n onMouseEnter={() => !readonly && !disabled && setHover(starIndex)}\n onClick={() => handleClick(starIndex)}\n >\n <StarIcon filled={filled} />\n </button>\n );\n })}\n </span>\n );\n}\n\nfunction StarIcon({ filled }: { filled: boolean }) {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill={filled ? \"currentColor\" : \"none\"}\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n <path d=\"M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.56 5.82 22 7 14.14 2 9.27l6.91-1.01L12 2z\" />\n </svg>\n );\n}\n"],"mappings":";;;;;AA6BA,SAAgB,EAAY,EACxB,UACA,SAAM,GACN,aACA,UAAO,MACP,cAAW,IACX,cAAW,IACX,WAAQ,aACR,gBACiB;CACjB,IAAM,CAAC,GAAO,KAAY,EAAiB,CAAC,GACtC,IAAY,IAAQ,IAAI,IAAQ,GAEhC,KAAe,MAAuB;EACpC,KAAY,KAChB,IAAW,CAAI;CACnB;CAEA,OACI,kBAAC,QAAD;EACI,MAAK;EACL,cAAY;EACZ,WAAW,EACP,EAAO,SACP,EAAO,IACP,KAAY,EAAO,UACnB,KAAY,EAAO,UACnB,CACJ;EACA,oBAAoB,EAAS,CAAC;YAE7B,MAAM,KAAK,EAAE,QAAQ,EAAI,IAAI,GAAG,MAAM;GACnC,IAAM,IAAY,IAAI,GAChB,IAAS,KAAa;GAC5B,OACI,kBAAC,UAAD;IAEI,MAAK;IACL,MAAK;IACL,gBAAc,MAAU;IACxB,cAAY,GAAG,EAAU,GAAG,MAAc,IAAI,YAAY;IAC1D,WAAW,EAAG,EAAO,MAAM,KAAU,EAAO,MAAM;IACxC;IACV,oBAAoB,CAAC,KAAY,CAAC,KAAY,EAAS,CAAS;IAChE,eAAe,EAAY,CAAS;cAEpC,kBAAC,GAAD,EAAkB,UAAS,CAAA;GACvB,GAXC,CAWD;EAEhB,CAAC;CACC,CAAA;AAEd;AAEA,SAAS,EAAS,EAAE,aAA+B;CAC/C,OACI,kBAAC,OAAD;EACI,OAAM;EACN,QAAO;EACP,SAAQ;EACR,MAAM,IAAS,iBAAiB;EAChC,QAAO;EACP,aAAY;EACZ,gBAAe;EACf,eAAA;YAEA,kBAAC,QAAD,EAAM,GAAE,2FAA4F,CAAA;CACnG,CAAA;AAEb"}
1
+ {"version":3,"file":"RatingStars.js","names":[],"sources":["../../../src/components/RatingStars/RatingStars.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — value, max, onChange, size, readonly, disabled,\n * label, className — a rating is a radio group drawn as stars, and readonly and\n * disabled are genuinely different (a shown rating versus a control you cannot use).\n */\nimport { useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./RatingStars.module.css\";\n\nexport type RatingSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface RatingStarsProps {\n /** Current selected value (1..max). 0 means none. */\n value: number;\n /** Total number of stars. Default 5. */\n max?: number;\n onChange?: (value: number) => void;\n size?: RatingSize;\n readonly?: boolean;\n disabled?: boolean;\n /** Accessible label for the rating group. */\n label?: string;\n className?: string;\n}\n\n/**\n * Star rating control. Renders `max` stars, fills the first `value`. Click a\n * star to set rating (when not readonly). Hovering previews the value.\n */\nexport function RatingStars({\n value,\n max = 5,\n onChange,\n size = \"md\",\n readonly = false,\n disabled = false,\n label = \"Avaliação\",\n className,\n}: RatingStarsProps) {\n const [hover, setHover] = useState<number>(0);\n const displayed = hover > 0 ? hover : value;\n\n const handleClick = (next: number): void => {\n if (readonly || disabled) return;\n onChange?.(next);\n };\n\n return (\n <span\n role=\"radiogroup\"\n aria-label={label}\n className={cn(\n styles.wrapper,\n styles[size],\n disabled && styles.disabled,\n readonly && styles.readonly,\n className,\n )}\n onMouseLeave={() => setHover(0)}\n >\n {Array.from({ length: max }, (_, i) => {\n const starIndex = i + 1;\n const filled = starIndex <= displayed;\n return (\n <button\n key={starIndex}\n type=\"button\"\n role=\"radio\"\n aria-checked={value === starIndex}\n aria-label={`${starIndex} ${starIndex === 1 ? \"estrela\" : \"estrelas\"}`}\n className={cn(styles.star, filled && styles.filled)}\n disabled={disabled}\n onMouseEnter={() => !readonly && !disabled && setHover(starIndex)}\n onClick={() => handleClick(starIndex)}\n >\n <StarIcon filled={filled} />\n </button>\n );\n })}\n </span>\n );\n}\n\nfunction StarIcon({ filled }: { filled: boolean }) {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill={filled ? \"currentColor\" : \"none\"}\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n <path d=\"M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.56 5.82 22 7 14.14 2 9.27l6.91-1.01L12 2z\" />\n </svg>\n );\n}\n"],"mappings":";;;;;AA6BA,SAAgB,EAAY,EACxB,UACA,SAAM,GACN,aACA,UAAO,MACP,cAAW,IACX,cAAW,IACX,WAAQ,aACR,gBACiB;CACjB,IAAM,CAAC,GAAO,KAAY,EAAiB,CAAC,GACtC,IAAY,IAAQ,IAAI,IAAQ,GAEhC,KAAe,MAAuB;EACpC,KAAY,KAChB,IAAW,CAAI;CACnB;CAEA,OACI,kBAAC,QAAD;EACI,MAAK;EACL,cAAY;EACZ,WAAW,EACP,EAAO,SACP,EAAO,IACP,KAAY,EAAO,UACnB,KAAY,EAAO,UACnB,CACJ;EACA,oBAAoB,EAAS,CAAC;EAE7B,UAAA,MAAM,KAAK,EAAE,QAAQ,EAAI,IAAI,GAAG,MAAM;GACnC,IAAM,IAAY,IAAI,GAChB,IAAS,KAAa;GAC5B,OACI,kBAAC,UAAD;IAEI,MAAK;IACL,MAAK;IACL,gBAAc,MAAU;IACxB,cAAY,GAAG,EAAU,GAAG,MAAc,IAAI,YAAY;IAC1D,WAAW,EAAG,EAAO,MAAM,KAAU,EAAO,MAAM;IACxC;IACV,oBAAoB,CAAC,KAAY,CAAC,KAAY,EAAS,CAAS;IAChE,eAAe,EAAY,CAAS;IAEpC,UAAA,kBAAC,GAAD,EAAkB,UAAS,CAAA;GACvB,GAXC,CAWD;EAEhB,CAAC;CACC,CAAA;AAEd;AAEA,SAAS,EAAS,EAAE,aAA+B;CAC/C,OACI,kBAAC,OAAD;EACI,OAAM;EACN,QAAO;EACP,SAAQ;EACR,MAAM,IAAS,iBAAiB;EAChC,QAAO;EACP,aAAY;EACZ,gBAAe;EACf,eAAA;EAEA,UAAA,kBAAC,QAAD,EAAM,GAAE,2FAA4F,CAAA;CACnG,CAAA;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"RefreshIndicator.cjs","names":[],"sources":["../../../src/components/RefreshIndicator/RefreshIndicator.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — pull-to-refresh is a gesture with a threshold, a\n * rubber-band offset and a release animation, and the body is those three reading\n * one pointer delta.\n */\nimport { useRef, useState, type ReactNode, type TouchEvent } from \"react\";\nimport { Spinner } from \"@/components/Spinner\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./RefreshIndicator.module.css\";\n\nexport interface RefreshIndicatorProps {\n /** Invoked when the user pulls past `threshold` and releases. May be async. */\n onRefresh: () => void | Promise<void>;\n /** Scrollable content to wrap. */\n children: ReactNode;\n /** Pixels the user must pull past to trigger a refresh. Defaults to `80`. */\n threshold?: number;\n /** When true, pull-to-refresh is inert. */\n disabled?: boolean;\n className?: string;\n}\n\n/** Apply resistance so the content lags behind the finger and the pull never runs away. */\nfunction applyResistance(distance: number, threshold: number): number {\n const cap = threshold * 1.5;\n return Math.min(distance / 2, cap);\n}\n\n/**\n * RefreshIndicator — pull-to-refresh wrapper for touch devices.\n *\n * Wraps scrollable `children` and listens for a downward drag that starts while the\n * container is scrolled to the top. Pulling past `threshold` and releasing triggers\n * `onRefresh`; the SDK {@link Spinner} is shown while pulling and during the refresh.\n */\nexport function RefreshIndicator({\n onRefresh,\n children,\n threshold = 80,\n disabled,\n className,\n}: RefreshIndicatorProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const startYRef = useRef<number | null>(null);\n const [pull, setPull] = useState(0);\n const [refreshing, setRefreshing] = useState(false);\n /**\n * Whether a drag is in progress. Kept in state, not derived from\n * `startYRef.current`: a ref is not reactive, so reading it during render ties\n * the rendered class to a value React never re-renders for — it only looked\n * correct here because the touch handlers happen to call `setPull` too.\n */\n const [engaged, setEngaged] = useState(false);\n\n const handleTouchStart = (event: TouchEvent<HTMLDivElement>): void => {\n if (disabled || refreshing) return;\n const container = containerRef.current;\n if (!container || container.scrollTop > 0) return;\n const touch = event.touches[0];\n if (!touch) return;\n startYRef.current = touch.clientY;\n setEngaged(true);\n };\n\n const handleTouchMove = (event: TouchEvent<HTMLDivElement>): void => {\n if (disabled || refreshing) return;\n const startY = startYRef.current;\n if (startY === null) return;\n const touch = event.touches[0];\n if (!touch) return;\n const delta = touch.clientY - startY;\n if (delta <= 0) {\n setPull(0);\n return;\n }\n setPull(applyResistance(delta, threshold));\n };\n\n const reset = (): void => {\n startYRef.current = null;\n setEngaged(false);\n setPull(0);\n };\n\n const handleTouchEnd = async (): Promise<void> => {\n if (disabled || refreshing) {\n reset();\n return;\n }\n const startY = startYRef.current;\n const triggered = startY !== null && pull >= threshold;\n if (!triggered) {\n reset();\n return;\n }\n startYRef.current = null;\n setEngaged(false);\n setRefreshing(true);\n setPull(threshold);\n try {\n await onRefresh();\n } finally {\n setRefreshing(false);\n setPull(0);\n }\n };\n\n const showIndicator = refreshing || pull > 0;\n const progress = Math.min(1, pull / threshold);\n\n return (\n <div\n ref={containerRef}\n className={cn(styles.wrapper, className)}\n data-refreshing={refreshing}\n onTouchStart={handleTouchStart}\n onTouchMove={handleTouchMove}\n onTouchEnd={handleTouchEnd}\n >\n <div\n className={styles.indicator}\n aria-hidden={!showIndicator}\n style={{\n opacity: refreshing ? 1 : progress,\n transform: `translateX(-50%) translateY(${showIndicator ? pull : 0}px) rotate(${progress * 360}deg)`,\n }}\n >\n <Spinner size=\"sm\" label=\"Atualizando\" />\n </div>\n <div\n className={cn(styles.content, (engaged || refreshing) && styles.dragging)}\n style={{ transform: `translateY(${showIndicator ? pull : 0}px)` }}\n >\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":"2KAuBA,SAAS,EAAgB,EAAkB,EAA2B,CAClE,IAAM,EAAM,EAAY,IACxB,OAAO,KAAK,IAAI,EAAW,EAAG,CAAG,CACrC,CASA,SAAgB,EAAiB,CAC7B,YACA,WACA,YAAY,GACZ,WACA,aACsB,CACtB,IAAM,GAAA,EAAA,EAAA,OAAA,CAAsC,IAAI,EAC1C,GAAA,EAAA,EAAA,OAAA,CAAkC,IAAI,EACtC,CAAC,EAAM,IAAA,EAAA,EAAA,SAAA,CAAoB,CAAC,EAC5B,CAAC,EAAY,IAAA,EAAA,EAAA,SAAA,CAA0B,EAAK,EAO5C,CAAC,EAAS,IAAA,EAAA,EAAA,SAAA,CAAuB,EAAK,EAEtC,EAAoB,GAA4C,CAClE,GAAI,GAAY,EAAY,OAC5B,IAAM,EAAY,EAAa,QAC/B,GAAI,CAAC,GAAa,EAAU,UAAY,EAAG,OAC3C,IAAM,EAAQ,EAAM,QAAQ,GACvB,IACL,EAAU,QAAU,EAAM,QAC1B,EAAW,EAAI,EACnB,EAEM,EAAmB,GAA4C,CACjE,GAAI,GAAY,EAAY,OAC5B,IAAM,EAAS,EAAU,QACzB,GAAI,IAAW,KAAM,OACrB,IAAM,EAAQ,EAAM,QAAQ,GAC5B,GAAI,CAAC,EAAO,OACZ,IAAM,EAAQ,EAAM,QAAU,EAC9B,GAAI,GAAS,EAAG,CACZ,EAAQ,CAAC,EACT,MACJ,CACA,EAAQ,EAAgB,EAAO,CAAS,CAAC,CAC7C,EAEM,MAAoB,CACtB,EAAU,QAAU,KACpB,EAAW,EAAK,EAChB,EAAQ,CAAC,CACb,EAEM,EAAiB,SAA2B,CAC9C,GAAI,GAAY,EAAY,CACxB,EAAM,EACN,MACJ,CAGA,GAAI,EAFW,EAAU,UACI,MAAQ,GAAQ,GAC7B,CACZ,EAAM,EACN,MACJ,CACA,EAAU,QAAU,KACpB,EAAW,EAAK,EAChB,EAAc,EAAI,EAClB,EAAQ,CAAS,EACjB,GAAI,CACA,MAAM,EAAU,CACpB,QAAU,CACN,EAAc,EAAK,EACnB,EAAQ,CAAC,CACb,CACJ,EAEM,EAAgB,GAAc,EAAO,EACrC,EAAW,KAAK,IAAI,EAAG,EAAO,CAAS,EAE7C,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CACI,IAAK,EACL,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EACvC,kBAAiB,EACjB,aAAc,EACd,YAAa,EACb,WAAY,WANhB,EAQI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,QAAO,UAClB,cAAa,CAAC,EACd,MAAO,CACH,QAAS,EAAa,EAAI,EAC1B,UAAW,+BAA+B,EAAgB,EAAO,EAAE,aAAa,EAAW,IAAI,KACnG,YAEA,EAAA,EAAA,IAAA,CAAC,EAAA,QAAD,CAAS,KAAK,KAAK,MAAM,aAAe,CAAA,CACvC,CAAA,GACL,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,SAAU,GAAW,IAAe,EAAA,QAAO,QAAQ,EACxE,MAAO,CAAE,UAAW,cAAc,EAAgB,EAAO,EAAE,IAAK,EAE/D,UACA,CAAA,CACJ,GAEb"}
1
+ {"version":3,"file":"RefreshIndicator.cjs","names":[],"sources":["../../../src/components/RefreshIndicator/RefreshIndicator.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — pull-to-refresh is a gesture with a threshold, a\n * rubber-band offset and a release animation, and the body is those three reading\n * one pointer delta.\n */\nimport { useRef, useState, type ReactNode, type TouchEvent } from \"react\";\nimport { Spinner } from \"@/components/Spinner\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./RefreshIndicator.module.css\";\n\nexport interface RefreshIndicatorProps {\n /** Invoked when the user pulls past `threshold` and releases. May be async. */\n onRefresh: () => void | Promise<void>;\n /** Scrollable content to wrap. */\n children: ReactNode;\n /** Pixels the user must pull past to trigger a refresh. Defaults to `80`. */\n threshold?: number;\n /** When true, pull-to-refresh is inert. */\n disabled?: boolean;\n className?: string;\n}\n\n/** Apply resistance so the content lags behind the finger and the pull never runs away. */\nfunction applyResistance(distance: number, threshold: number): number {\n const cap = threshold * 1.5;\n return Math.min(distance / 2, cap);\n}\n\n/**\n * RefreshIndicator — pull-to-refresh wrapper for touch devices.\n *\n * Wraps scrollable `children` and listens for a downward drag that starts while the\n * container is scrolled to the top. Pulling past `threshold` and releasing triggers\n * `onRefresh`; the SDK {@link Spinner} is shown while pulling and during the refresh.\n */\nexport function RefreshIndicator({\n onRefresh,\n children,\n threshold = 80,\n disabled,\n className,\n}: RefreshIndicatorProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const startYRef = useRef<number | null>(null);\n const [pull, setPull] = useState(0);\n const [refreshing, setRefreshing] = useState(false);\n /**\n * Whether a drag is in progress. Kept in state, not derived from\n * `startYRef.current`: a ref is not reactive, so reading it during render ties\n * the rendered class to a value React never re-renders for — it only looked\n * correct here because the touch handlers happen to call `setPull` too.\n */\n const [engaged, setEngaged] = useState(false);\n\n const handleTouchStart = (event: TouchEvent<HTMLDivElement>): void => {\n if (disabled || refreshing) return;\n const container = containerRef.current;\n if (!container || container.scrollTop > 0) return;\n const touch = event.touches[0];\n if (!touch) return;\n startYRef.current = touch.clientY;\n setEngaged(true);\n };\n\n const handleTouchMove = (event: TouchEvent<HTMLDivElement>): void => {\n if (disabled || refreshing) return;\n const startY = startYRef.current;\n if (startY === null) return;\n const touch = event.touches[0];\n if (!touch) return;\n const delta = touch.clientY - startY;\n if (delta <= 0) {\n setPull(0);\n return;\n }\n setPull(applyResistance(delta, threshold));\n };\n\n const reset = (): void => {\n startYRef.current = null;\n setEngaged(false);\n setPull(0);\n };\n\n const handleTouchEnd = async (): Promise<void> => {\n if (disabled || refreshing) {\n reset();\n return;\n }\n const startY = startYRef.current;\n const triggered = startY !== null && pull >= threshold;\n if (!triggered) {\n reset();\n return;\n }\n startYRef.current = null;\n setEngaged(false);\n setRefreshing(true);\n setPull(threshold);\n try {\n await onRefresh();\n } finally {\n setRefreshing(false);\n setPull(0);\n }\n };\n\n const showIndicator = refreshing || pull > 0;\n const progress = Math.min(1, pull / threshold);\n\n return (\n <div\n ref={containerRef}\n className={cn(styles.wrapper, className)}\n data-refreshing={refreshing}\n onTouchStart={handleTouchStart}\n onTouchMove={handleTouchMove}\n onTouchEnd={handleTouchEnd}\n >\n <div\n className={styles.indicator}\n aria-hidden={!showIndicator}\n style={{\n opacity: refreshing ? 1 : progress,\n transform: `translateX(-50%) translateY(${showIndicator ? pull : 0}px) rotate(${progress * 360}deg)`,\n }}\n >\n <Spinner size=\"sm\" label=\"Atualizando\" />\n </div>\n <div\n className={cn(styles.content, (engaged || refreshing) && styles.dragging)}\n style={{ transform: `translateY(${showIndicator ? pull : 0}px)` }}\n >\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":"2KAuBA,SAAS,EAAgB,EAAkB,EAA2B,CAClE,IAAM,EAAM,EAAY,IACxB,OAAO,KAAK,IAAI,EAAW,EAAG,CAAG,CACrC,CASA,SAAgB,EAAiB,CAC7B,YACA,WACA,YAAY,GACZ,WACA,aACsB,CACtB,IAAM,GAAA,EAAe,EAAA,OAAA,CAAuB,IAAI,EAC1C,GAAA,EAAY,EAAA,OAAA,CAAsB,IAAI,EACtC,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,CAAS,CAAC,EAC5B,CAAC,EAAY,IAAA,EAAiB,EAAA,SAAA,CAAS,EAAK,EAO5C,CAAC,EAAS,IAAA,EAAc,EAAA,SAAA,CAAS,EAAK,EAEtC,EAAoB,GAA4C,CAClE,GAAI,GAAY,EAAY,OAC5B,IAAM,EAAY,EAAa,QAC/B,GAAI,CAAC,GAAa,EAAU,UAAY,EAAG,OAC3C,IAAM,EAAQ,EAAM,QAAQ,GACvB,IACL,EAAU,QAAU,EAAM,QAC1B,EAAW,EAAI,EACnB,EAEM,EAAmB,GAA4C,CACjE,GAAI,GAAY,EAAY,OAC5B,IAAM,EAAS,EAAU,QACzB,GAAI,IAAW,KAAM,OACrB,IAAM,EAAQ,EAAM,QAAQ,GAC5B,GAAI,CAAC,EAAO,OACZ,IAAM,EAAQ,EAAM,QAAU,EAC9B,GAAI,GAAS,EAAG,CACZ,EAAQ,CAAC,EACT,MACJ,CACA,EAAQ,EAAgB,EAAO,CAAS,CAAC,CAC7C,EAEM,MAAoB,CACtB,EAAU,QAAU,KACpB,EAAW,EAAK,EAChB,EAAQ,CAAC,CACb,EAEM,EAAiB,SAA2B,CAC9C,GAAI,GAAY,EAAY,CACxB,EAAM,EACN,MACJ,CAGA,GAAI,EAFW,EAAU,UACI,MAAQ,GAAQ,GAC7B,CACZ,EAAM,EACN,MACJ,CACA,EAAU,QAAU,KACpB,EAAW,EAAK,EAChB,EAAc,EAAI,EAClB,EAAQ,CAAS,EACjB,GAAI,CACA,MAAM,EAAU,CACpB,QAAU,CACN,EAAc,EAAK,EACnB,EAAQ,CAAC,CACb,CACJ,EAEM,EAAgB,GAAc,EAAO,EACrC,EAAW,KAAK,IAAI,EAAG,EAAO,CAAS,EAE7C,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CACI,IAAK,EACL,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EACvC,kBAAiB,EACjB,aAAc,EACd,YAAa,EACb,WAAY,EANhB,SAAA,EAQI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,QAAO,UAClB,cAAa,CAAC,EACd,MAAO,CACH,QAAS,EAAa,EAAI,EAC1B,UAAW,+BAA+B,EAAgB,EAAO,EAAE,aAAa,EAAW,IAAI,KACnG,EAEA,UAAA,EAAA,EAAA,IAAA,CAAC,EAAA,QAAD,CAAS,KAAK,KAAK,MAAM,aAAe,CAAA,CACvC,CAAA,GACL,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,SAAU,GAAW,IAAe,EAAA,QAAO,QAAQ,EACxE,MAAO,CAAE,UAAW,cAAc,EAAgB,EAAO,EAAE,IAAK,EAE/D,UACA,CAAA,CACJ,GAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"RefreshIndicator.js","names":[],"sources":["../../../src/components/RefreshIndicator/RefreshIndicator.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — pull-to-refresh is a gesture with a threshold, a\n * rubber-band offset and a release animation, and the body is those three reading\n * one pointer delta.\n */\nimport { useRef, useState, type ReactNode, type TouchEvent } from \"react\";\nimport { Spinner } from \"@/components/Spinner\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./RefreshIndicator.module.css\";\n\nexport interface RefreshIndicatorProps {\n /** Invoked when the user pulls past `threshold` and releases. May be async. */\n onRefresh: () => void | Promise<void>;\n /** Scrollable content to wrap. */\n children: ReactNode;\n /** Pixels the user must pull past to trigger a refresh. Defaults to `80`. */\n threshold?: number;\n /** When true, pull-to-refresh is inert. */\n disabled?: boolean;\n className?: string;\n}\n\n/** Apply resistance so the content lags behind the finger and the pull never runs away. */\nfunction applyResistance(distance: number, threshold: number): number {\n const cap = threshold * 1.5;\n return Math.min(distance / 2, cap);\n}\n\n/**\n * RefreshIndicator — pull-to-refresh wrapper for touch devices.\n *\n * Wraps scrollable `children` and listens for a downward drag that starts while the\n * container is scrolled to the top. Pulling past `threshold` and releasing triggers\n * `onRefresh`; the SDK {@link Spinner} is shown while pulling and during the refresh.\n */\nexport function RefreshIndicator({\n onRefresh,\n children,\n threshold = 80,\n disabled,\n className,\n}: RefreshIndicatorProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const startYRef = useRef<number | null>(null);\n const [pull, setPull] = useState(0);\n const [refreshing, setRefreshing] = useState(false);\n /**\n * Whether a drag is in progress. Kept in state, not derived from\n * `startYRef.current`: a ref is not reactive, so reading it during render ties\n * the rendered class to a value React never re-renders for — it only looked\n * correct here because the touch handlers happen to call `setPull` too.\n */\n const [engaged, setEngaged] = useState(false);\n\n const handleTouchStart = (event: TouchEvent<HTMLDivElement>): void => {\n if (disabled || refreshing) return;\n const container = containerRef.current;\n if (!container || container.scrollTop > 0) return;\n const touch = event.touches[0];\n if (!touch) return;\n startYRef.current = touch.clientY;\n setEngaged(true);\n };\n\n const handleTouchMove = (event: TouchEvent<HTMLDivElement>): void => {\n if (disabled || refreshing) return;\n const startY = startYRef.current;\n if (startY === null) return;\n const touch = event.touches[0];\n if (!touch) return;\n const delta = touch.clientY - startY;\n if (delta <= 0) {\n setPull(0);\n return;\n }\n setPull(applyResistance(delta, threshold));\n };\n\n const reset = (): void => {\n startYRef.current = null;\n setEngaged(false);\n setPull(0);\n };\n\n const handleTouchEnd = async (): Promise<void> => {\n if (disabled || refreshing) {\n reset();\n return;\n }\n const startY = startYRef.current;\n const triggered = startY !== null && pull >= threshold;\n if (!triggered) {\n reset();\n return;\n }\n startYRef.current = null;\n setEngaged(false);\n setRefreshing(true);\n setPull(threshold);\n try {\n await onRefresh();\n } finally {\n setRefreshing(false);\n setPull(0);\n }\n };\n\n const showIndicator = refreshing || pull > 0;\n const progress = Math.min(1, pull / threshold);\n\n return (\n <div\n ref={containerRef}\n className={cn(styles.wrapper, className)}\n data-refreshing={refreshing}\n onTouchStart={handleTouchStart}\n onTouchMove={handleTouchMove}\n onTouchEnd={handleTouchEnd}\n >\n <div\n className={styles.indicator}\n aria-hidden={!showIndicator}\n style={{\n opacity: refreshing ? 1 : progress,\n transform: `translateX(-50%) translateY(${showIndicator ? pull : 0}px) rotate(${progress * 360}deg)`,\n }}\n >\n <Spinner size=\"sm\" label=\"Atualizando\" />\n </div>\n <div\n className={cn(styles.content, (engaged || refreshing) && styles.dragging)}\n style={{ transform: `translateY(${showIndicator ? pull : 0}px)` }}\n >\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;AAuBA,SAAS,EAAgB,GAAkB,GAA2B;CAClE,IAAM,IAAM,IAAY;CACxB,OAAO,KAAK,IAAI,IAAW,GAAG,CAAG;AACrC;AASA,SAAgB,EAAiB,EAC7B,cACA,aACA,eAAY,IACZ,aACA,gBACsB;CACtB,IAAM,IAAe,EAAuB,IAAI,GAC1C,IAAY,EAAsB,IAAI,GACtC,CAAC,GAAM,KAAW,EAAS,CAAC,GAC5B,CAAC,GAAY,KAAiB,EAAS,EAAK,GAO5C,CAAC,GAAS,KAAc,EAAS,EAAK,GAEtC,KAAoB,MAA4C;EAClE,IAAI,KAAY,GAAY;EAC5B,IAAM,IAAY,EAAa;EAC/B,IAAI,CAAC,KAAa,EAAU,YAAY,GAAG;EAC3C,IAAM,IAAQ,EAAM,QAAQ;EACvB,MACL,EAAU,UAAU,EAAM,SAC1B,EAAW,EAAI;CACnB,GAEM,KAAmB,MAA4C;EACjE,IAAI,KAAY,GAAY;EAC5B,IAAM,IAAS,EAAU;EACzB,IAAI,MAAW,MAAM;EACrB,IAAM,IAAQ,EAAM,QAAQ;EAC5B,IAAI,CAAC,GAAO;EACZ,IAAM,IAAQ,EAAM,UAAU;EAC9B,IAAI,KAAS,GAAG;GACZ,EAAQ,CAAC;GACT;EACJ;EACA,EAAQ,EAAgB,GAAO,CAAS,CAAC;CAC7C,GAEM,UAAoB;EAGtB,AAFA,EAAU,UAAU,MACpB,EAAW,EAAK,GAChB,EAAQ,CAAC;CACb,GAEM,IAAiB,YAA2B;EAC9C,IAAI,KAAY,GAAY;GACxB,EAAM;GACN;EACJ;EAGA,IAAI,EAFW,EAAU,YACI,QAAQ,KAAQ,IAC7B;GACZ,EAAM;GACN;EACJ;EAIA,AAHA,EAAU,UAAU,MACpB,EAAW,EAAK,GAChB,EAAc,EAAI,GAClB,EAAQ,CAAS;EACjB,IAAI;GACA,MAAM,EAAU;EACpB,UAAU;GAEN,AADA,EAAc,EAAK,GACnB,EAAQ,CAAC;EACb;CACJ,GAEM,IAAgB,KAAc,IAAO,GACrC,IAAW,KAAK,IAAI,GAAG,IAAO,CAAS;CAE7C,OACI,kBAAC,OAAD;EACI,KAAK;EACL,WAAW,EAAG,EAAO,SAAS,CAAS;EACvC,mBAAiB;EACjB,cAAc;EACd,aAAa;EACb,YAAY;YANhB,CAQI,kBAAC,OAAD;GACI,WAAW,EAAO;GAClB,eAAa,CAAC;GACd,OAAO;IACH,SAAS,IAAa,IAAI;IAC1B,WAAW,+BAA+B,IAAgB,IAAO,EAAE,aAAa,IAAW,IAAI;GACnG;aAEA,kBAAC,GAAD;IAAS,MAAK;IAAK,OAAM;GAAe,CAAA;EACvC,CAAA,GACL,kBAAC,OAAD;GACI,WAAW,EAAG,EAAO,UAAU,KAAW,MAAe,EAAO,QAAQ;GACxE,OAAO,EAAE,WAAW,cAAc,IAAgB,IAAO,EAAE,KAAK;GAE/D;EACA,CAAA,CACJ;;AAEb"}
1
+ {"version":3,"file":"RefreshIndicator.js","names":[],"sources":["../../../src/components/RefreshIndicator/RefreshIndicator.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — pull-to-refresh is a gesture with a threshold, a\n * rubber-band offset and a release animation, and the body is those three reading\n * one pointer delta.\n */\nimport { useRef, useState, type ReactNode, type TouchEvent } from \"react\";\nimport { Spinner } from \"@/components/Spinner\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./RefreshIndicator.module.css\";\n\nexport interface RefreshIndicatorProps {\n /** Invoked when the user pulls past `threshold` and releases. May be async. */\n onRefresh: () => void | Promise<void>;\n /** Scrollable content to wrap. */\n children: ReactNode;\n /** Pixels the user must pull past to trigger a refresh. Defaults to `80`. */\n threshold?: number;\n /** When true, pull-to-refresh is inert. */\n disabled?: boolean;\n className?: string;\n}\n\n/** Apply resistance so the content lags behind the finger and the pull never runs away. */\nfunction applyResistance(distance: number, threshold: number): number {\n const cap = threshold * 1.5;\n return Math.min(distance / 2, cap);\n}\n\n/**\n * RefreshIndicator — pull-to-refresh wrapper for touch devices.\n *\n * Wraps scrollable `children` and listens for a downward drag that starts while the\n * container is scrolled to the top. Pulling past `threshold` and releasing triggers\n * `onRefresh`; the SDK {@link Spinner} is shown while pulling and during the refresh.\n */\nexport function RefreshIndicator({\n onRefresh,\n children,\n threshold = 80,\n disabled,\n className,\n}: RefreshIndicatorProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const startYRef = useRef<number | null>(null);\n const [pull, setPull] = useState(0);\n const [refreshing, setRefreshing] = useState(false);\n /**\n * Whether a drag is in progress. Kept in state, not derived from\n * `startYRef.current`: a ref is not reactive, so reading it during render ties\n * the rendered class to a value React never re-renders for — it only looked\n * correct here because the touch handlers happen to call `setPull` too.\n */\n const [engaged, setEngaged] = useState(false);\n\n const handleTouchStart = (event: TouchEvent<HTMLDivElement>): void => {\n if (disabled || refreshing) return;\n const container = containerRef.current;\n if (!container || container.scrollTop > 0) return;\n const touch = event.touches[0];\n if (!touch) return;\n startYRef.current = touch.clientY;\n setEngaged(true);\n };\n\n const handleTouchMove = (event: TouchEvent<HTMLDivElement>): void => {\n if (disabled || refreshing) return;\n const startY = startYRef.current;\n if (startY === null) return;\n const touch = event.touches[0];\n if (!touch) return;\n const delta = touch.clientY - startY;\n if (delta <= 0) {\n setPull(0);\n return;\n }\n setPull(applyResistance(delta, threshold));\n };\n\n const reset = (): void => {\n startYRef.current = null;\n setEngaged(false);\n setPull(0);\n };\n\n const handleTouchEnd = async (): Promise<void> => {\n if (disabled || refreshing) {\n reset();\n return;\n }\n const startY = startYRef.current;\n const triggered = startY !== null && pull >= threshold;\n if (!triggered) {\n reset();\n return;\n }\n startYRef.current = null;\n setEngaged(false);\n setRefreshing(true);\n setPull(threshold);\n try {\n await onRefresh();\n } finally {\n setRefreshing(false);\n setPull(0);\n }\n };\n\n const showIndicator = refreshing || pull > 0;\n const progress = Math.min(1, pull / threshold);\n\n return (\n <div\n ref={containerRef}\n className={cn(styles.wrapper, className)}\n data-refreshing={refreshing}\n onTouchStart={handleTouchStart}\n onTouchMove={handleTouchMove}\n onTouchEnd={handleTouchEnd}\n >\n <div\n className={styles.indicator}\n aria-hidden={!showIndicator}\n style={{\n opacity: refreshing ? 1 : progress,\n transform: `translateX(-50%) translateY(${showIndicator ? pull : 0}px) rotate(${progress * 360}deg)`,\n }}\n >\n <Spinner size=\"sm\" label=\"Atualizando\" />\n </div>\n <div\n className={cn(styles.content, (engaged || refreshing) && styles.dragging)}\n style={{ transform: `translateY(${showIndicator ? pull : 0}px)` }}\n >\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;AAuBA,SAAS,EAAgB,GAAkB,GAA2B;CAClE,IAAM,IAAM,IAAY;CACxB,OAAO,KAAK,IAAI,IAAW,GAAG,CAAG;AACrC;AASA,SAAgB,EAAiB,EAC7B,cACA,aACA,eAAY,IACZ,aACA,gBACsB;CACtB,IAAM,IAAe,EAAuB,IAAI,GAC1C,IAAY,EAAsB,IAAI,GACtC,CAAC,GAAM,KAAW,EAAS,CAAC,GAC5B,CAAC,GAAY,KAAiB,EAAS,EAAK,GAO5C,CAAC,GAAS,KAAc,EAAS,EAAK,GAEtC,KAAoB,MAA4C;EAClE,IAAI,KAAY,GAAY;EAC5B,IAAM,IAAY,EAAa;EAC/B,IAAI,CAAC,KAAa,EAAU,YAAY,GAAG;EAC3C,IAAM,IAAQ,EAAM,QAAQ;EACvB,MACL,EAAU,UAAU,EAAM,SAC1B,EAAW,EAAI;CACnB,GAEM,KAAmB,MAA4C;EACjE,IAAI,KAAY,GAAY;EAC5B,IAAM,IAAS,EAAU;EACzB,IAAI,MAAW,MAAM;EACrB,IAAM,IAAQ,EAAM,QAAQ;EAC5B,IAAI,CAAC,GAAO;EACZ,IAAM,IAAQ,EAAM,UAAU;EAC9B,IAAI,KAAS,GAAG;GACZ,EAAQ,CAAC;GACT;EACJ;EACA,EAAQ,EAAgB,GAAO,CAAS,CAAC;CAC7C,GAEM,UAAoB;EAGtB,AAFA,EAAU,UAAU,MACpB,EAAW,EAAK,GAChB,EAAQ,CAAC;CACb,GAEM,IAAiB,YAA2B;EAC9C,IAAI,KAAY,GAAY;GACxB,EAAM;GACN;EACJ;EAGA,IAAI,EAFW,EAAU,YACI,QAAQ,KAAQ,IAC7B;GACZ,EAAM;GACN;EACJ;EAIA,AAHA,EAAU,UAAU,MACpB,EAAW,EAAK,GAChB,EAAc,EAAI,GAClB,EAAQ,CAAS;EACjB,IAAI;GACA,MAAM,EAAU;EACpB,UAAU;GAEN,AADA,EAAc,EAAK,GACnB,EAAQ,CAAC;EACb;CACJ,GAEM,IAAgB,KAAc,IAAO,GACrC,IAAW,KAAK,IAAI,GAAG,IAAO,CAAS;CAE7C,OACI,kBAAC,OAAD;EACI,KAAK;EACL,WAAW,EAAG,EAAO,SAAS,CAAS;EACvC,mBAAiB;EACjB,cAAc;EACd,aAAa;EACb,YAAY;EANhB,UAAA,CAQI,kBAAC,OAAD;GACI,WAAW,EAAO;GAClB,eAAa,CAAC;GACd,OAAO;IACH,SAAS,IAAa,IAAI;IAC1B,WAAW,+BAA+B,IAAgB,IAAO,EAAE,aAAa,IAAW,IAAI;GACnG;GAEA,UAAA,kBAAC,GAAD;IAAS,MAAK;IAAK,OAAM;GAAe,CAAA;EACvC,CAAA,GACL,kBAAC,OAAD;GACI,WAAW,EAAG,EAAO,UAAU,KAAW,MAAe,EAAO,QAAQ;GACxE,OAAO,EAAE,WAAW,cAAc,IAAgB,IAAO,EAAE,KAAK;GAE/D;EACA,CAAA,CACJ;;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"RelativeTime.cjs","names":[],"sources":["../../../src/components/RelativeTime/RelativeTime.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\nimport { relativeTime } from \"@/utils/relative-time\";\n\nexport interface RelativeTimeProps extends HTMLAttributes<HTMLTimeElement> {\n /** The instant to render relative to now. */\n date: Date | string | number;\n /** Output language. Defaults to \"pt\". */\n locale?: \"pt\" | \"en\";\n}\n\n/**\n * Render a date as a human-friendly relative-time string (e.g. \"5 min atrás\")\n * inside a semantic `<time>` element with a machine-readable `dateTime`.\n *\n * Delegates the wording to the `relativeTime` util; \"pt\" maps to its \"pt-BR\"\n * locale.\n *\n * @example\n * <RelativeTime date={post.createdAt} locale=\"en\" />\n */\nexport function RelativeTime({ date, locale = \"pt\", ...props }: RelativeTimeProps) {\n const target = date instanceof Date ? date : new Date(date);\n const iso = Number.isNaN(target.getTime()) ? undefined : target.toISOString();\n const label = relativeTime(date, { locale: locale === \"pt\" ? \"pt-BR\" : \"en\" });\n\n return (\n <time dateTime={iso} {...props}>\n {label}\n </time>\n );\n}\n"],"mappings":"oFAoBA,SAAgB,EAAa,CAAE,OAAM,SAAS,KAAM,GAAG,GAA4B,CAC/E,IAAM,EAAS,aAAgB,KAAO,EAAO,IAAI,KAAK,CAAI,EACpD,EAAM,OAAO,MAAM,EAAO,QAAQ,CAAC,EAAI,IAAA,GAAY,EAAO,YAAY,EACtE,EAAQ,EAAA,aAAa,EAAM,CAAE,OAAQ,IAAW,KAAO,QAAU,IAAK,CAAC,EAE7E,OACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,SAAU,EAAK,GAAI,WACpB,CACC,CAAA,CAEd"}
1
+ {"version":3,"file":"RelativeTime.cjs","names":[],"sources":["../../../src/components/RelativeTime/RelativeTime.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\nimport { relativeTime } from \"@/utils/relative-time\";\n\nexport interface RelativeTimeProps extends HTMLAttributes<HTMLTimeElement> {\n /** The instant to render relative to now. */\n date: Date | string | number;\n /** Output language. Defaults to \"pt\". */\n locale?: \"pt\" | \"en\";\n}\n\n/**\n * Render a date as a human-friendly relative-time string (e.g. \"5 min atrás\")\n * inside a semantic `<time>` element with a machine-readable `dateTime`.\n *\n * Delegates the wording to the `relativeTime` util; \"pt\" maps to its \"pt-BR\"\n * locale.\n *\n * @example\n * <RelativeTime date={post.createdAt} locale=\"en\" />\n */\nexport function RelativeTime({ date, locale = \"pt\", ...props }: RelativeTimeProps) {\n const target = date instanceof Date ? date : new Date(date);\n const iso = Number.isNaN(target.getTime()) ? undefined : target.toISOString();\n const label = relativeTime(date, { locale: locale === \"pt\" ? \"pt-BR\" : \"en\" });\n\n return (\n <time dateTime={iso} {...props}>\n {label}\n </time>\n );\n}\n"],"mappings":"oFAoBA,SAAgB,EAAa,CAAE,OAAM,SAAS,KAAM,GAAG,GAA4B,CAC/E,IAAM,EAAS,aAAgB,KAAO,EAAO,IAAI,KAAK,CAAI,EACpD,EAAM,OAAO,MAAM,EAAO,QAAQ,CAAC,EAAI,IAAA,GAAY,EAAO,YAAY,EACtE,EAAQ,EAAA,aAAa,EAAM,CAAE,OAAQ,IAAW,KAAO,QAAU,IAAK,CAAC,EAE7E,OACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,SAAU,EAAK,GAAI,EACpB,SAAA,CACC,CAAA,CAEd"}
@@ -1 +1 @@
1
- {"version":3,"file":"RelativeTime.js","names":[],"sources":["../../../src/components/RelativeTime/RelativeTime.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\nimport { relativeTime } from \"@/utils/relative-time\";\n\nexport interface RelativeTimeProps extends HTMLAttributes<HTMLTimeElement> {\n /** The instant to render relative to now. */\n date: Date | string | number;\n /** Output language. Defaults to \"pt\". */\n locale?: \"pt\" | \"en\";\n}\n\n/**\n * Render a date as a human-friendly relative-time string (e.g. \"5 min atrás\")\n * inside a semantic `<time>` element with a machine-readable `dateTime`.\n *\n * Delegates the wording to the `relativeTime` util; \"pt\" maps to its \"pt-BR\"\n * locale.\n *\n * @example\n * <RelativeTime date={post.createdAt} locale=\"en\" />\n */\nexport function RelativeTime({ date, locale = \"pt\", ...props }: RelativeTimeProps) {\n const target = date instanceof Date ? date : new Date(date);\n const iso = Number.isNaN(target.getTime()) ? undefined : target.toISOString();\n const label = relativeTime(date, { locale: locale === \"pt\" ? \"pt-BR\" : \"en\" });\n\n return (\n <time dateTime={iso} {...props}>\n {label}\n </time>\n );\n}\n"],"mappings":";;;AAoBA,SAAgB,EAAa,EAAE,SAAM,YAAS,MAAM,GAAG,KAA4B;CAC/E,IAAM,IAAS,aAAgB,OAAO,IAAO,IAAI,KAAK,CAAI,GACpD,IAAM,OAAO,MAAM,EAAO,QAAQ,CAAC,IAAI,KAAA,IAAY,EAAO,YAAY,GACtE,IAAQ,EAAa,GAAM,EAAE,QAAQ,MAAW,OAAO,UAAU,KAAK,CAAC;CAE7E,OACI,kBAAC,QAAD;EAAM,UAAU;EAAK,GAAI;YACpB;CACC,CAAA;AAEd"}
1
+ {"version":3,"file":"RelativeTime.js","names":[],"sources":["../../../src/components/RelativeTime/RelativeTime.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\nimport { relativeTime } from \"@/utils/relative-time\";\n\nexport interface RelativeTimeProps extends HTMLAttributes<HTMLTimeElement> {\n /** The instant to render relative to now. */\n date: Date | string | number;\n /** Output language. Defaults to \"pt\". */\n locale?: \"pt\" | \"en\";\n}\n\n/**\n * Render a date as a human-friendly relative-time string (e.g. \"5 min atrás\")\n * inside a semantic `<time>` element with a machine-readable `dateTime`.\n *\n * Delegates the wording to the `relativeTime` util; \"pt\" maps to its \"pt-BR\"\n * locale.\n *\n * @example\n * <RelativeTime date={post.createdAt} locale=\"en\" />\n */\nexport function RelativeTime({ date, locale = \"pt\", ...props }: RelativeTimeProps) {\n const target = date instanceof Date ? date : new Date(date);\n const iso = Number.isNaN(target.getTime()) ? undefined : target.toISOString();\n const label = relativeTime(date, { locale: locale === \"pt\" ? \"pt-BR\" : \"en\" });\n\n return (\n <time dateTime={iso} {...props}>\n {label}\n </time>\n );\n}\n"],"mappings":";;;AAoBA,SAAgB,EAAa,EAAE,SAAM,YAAS,MAAM,GAAG,KAA4B;CAC/E,IAAM,IAAS,aAAgB,OAAO,IAAO,IAAI,KAAK,CAAI,GACpD,IAAM,OAAO,MAAM,EAAO,QAAQ,CAAC,IAAI,KAAA,IAAY,EAAO,YAAY,GACtE,IAAQ,EAAa,GAAM,EAAE,QAAQ,MAAW,OAAO,UAAU,KAAK,CAAC;CAE7E,OACI,kBAAC,QAAD;EAAM,UAAU;EAAK,GAAI;EACpB,UAAA;CACC,CAAA;AAEd"}
@@ -1 +1 @@
1
- {"version":3,"file":"Resizable.cjs","names":[],"sources":["../../../src/components/Resizable/Resizable.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body owns the pointer capture, the min/max\n * clamp and the keyboard resize step; all three write the same size and must agree\n * on the bounds.\n */\nimport { useCallback, useRef, useState } from \"react\";\nimport type { HTMLAttributes, KeyboardEvent, PointerEvent, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Resizable.module.css\";\n\nexport type ResizableDirection = \"horizontal\" | \"vertical\";\n\nexport interface ResizableProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** Split orientation. `horizontal` (default) places panes side by side. */\n direction?: ResizableDirection;\n /** Initial size of the first pane, as a percentage. Defaults to `50`. */\n defaultSize?: number;\n /** Lower clamp for the first pane size, in percent. Defaults to `10`. */\n min?: number;\n /** Upper clamp for the first pane size, in percent. Defaults to `90`. */\n max?: number;\n /** Exactly two panes — `[paneA, paneB]`. */\n children: [ReactNode, ReactNode];\n}\n\nconst KEY_STEP = 2;\n\n/**\n * Clamp a number into the inclusive `[min, max]` range.\n *\n * @param value - The value to clamp.\n * @param min - Lower bound.\n * @param max - Upper bound.\n * @returns The clamped value.\n */\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/**\n * A two-pane split layout with a draggable divider. The first pane is sized via\n * `flex-basis` as a percentage; the second pane fills the rest. Drag the divider\n * with a pointer, or focus it and use the arrow keys to adjust by 2% steps.\n *\n * The size is clamped to `[min, max]` at all times.\n */\nexport function Resizable({\n direction = \"horizontal\",\n defaultSize = 50,\n min = 10,\n max = 90,\n children,\n className,\n ...props\n}: ResizableProps) {\n const [size, setSize] = useState<number>(() => clamp(defaultSize, min, max));\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [paneA, paneB] = children;\n const isHorizontal = direction === \"horizontal\";\n\n const updateFromPointer = useCallback(\n (clientX: number, clientY: number): void => {\n const container = containerRef.current;\n if (!container) return;\n const rect = container.getBoundingClientRect();\n const total = isHorizontal ? rect.width : rect.height;\n if (total <= 0) return;\n const offset = isHorizontal ? clientX - rect.left : clientY - rect.top;\n const percent = (offset / total) * 100;\n setSize(clamp(percent, min, max));\n },\n [isHorizontal, min, max],\n );\n\n const handlePointerDown = useCallback(\n (event: PointerEvent<HTMLDivElement>): void => {\n event.preventDefault();\n const divider = event.currentTarget;\n divider.setPointerCapture(event.pointerId);\n\n const handleMove = (moveEvent: globalThis.PointerEvent): void => {\n updateFromPointer(moveEvent.clientX, moveEvent.clientY);\n };\n const handleUp = (): void => {\n window.removeEventListener(\"pointermove\", handleMove);\n window.removeEventListener(\"pointerup\", handleUp);\n };\n\n window.addEventListener(\"pointermove\", handleMove);\n window.addEventListener(\"pointerup\", handleUp);\n },\n [updateFromPointer],\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>): void => {\n let delta = 0;\n if (isHorizontal) {\n if (event.key === \"ArrowRight\") delta = KEY_STEP;\n else if (event.key === \"ArrowLeft\") delta = -KEY_STEP;\n } else {\n if (event.key === \"ArrowDown\") delta = KEY_STEP;\n else if (event.key === \"ArrowUp\") delta = -KEY_STEP;\n }\n if (event.key === \"Home\") {\n event.preventDefault();\n setSize(min);\n return;\n }\n if (event.key === \"End\") {\n event.preventDefault();\n setSize(max);\n return;\n }\n if (delta === 0) return;\n event.preventDefault();\n setSize((current) => clamp(current + delta, min, max));\n },\n [isHorizontal, min, max],\n );\n\n return (\n <div\n ref={containerRef}\n className={cn(\n styles.root,\n isHorizontal ? styles.horizontal : styles.vertical,\n className,\n )}\n {...props}\n >\n <div className={styles.pane} style={{ flexBasis: `${size}%` }}>\n {paneA}\n </div>\n <div\n role=\"separator\"\n aria-orientation={isHorizontal ? \"vertical\" : \"horizontal\"}\n aria-valuenow={Math.round(size)}\n aria-valuemin={min}\n aria-valuemax={max}\n tabIndex={0}\n className={styles.divider}\n onPointerDown={handlePointerDown}\n onKeyDown={handleKeyDown}\n >\n <span className={styles.handle} aria-hidden=\"true\" />\n </div>\n <div className={styles.pane} style={{ flexBasis: `${100 - size}%` }}>\n {paneB}\n </div>\n </div>\n );\n}\n"],"mappings":"gIAyBA,IAAM,EAAW,EAUjB,SAAS,EAAM,EAAe,EAAa,EAAqB,CAC5D,OAAO,KAAK,IAAI,EAAK,KAAK,IAAI,EAAK,CAAK,CAAC,CAC7C,CASA,SAAgB,EAAU,CACtB,YAAY,aACZ,cAAc,GACd,MAAM,GACN,MAAM,GACN,WACA,YACA,GAAG,GACY,CACf,GAAM,CAAC,EAAM,IAAA,EAAA,EAAA,SAAA,KAAkC,EAAM,EAAa,EAAK,CAAG,CAAC,EACrE,GAAA,EAAA,EAAA,OAAA,CAA6C,IAAI,EACjD,CAAC,EAAO,GAAS,EACjB,EAAe,IAAc,aAE7B,GAAA,EAAA,EAAA,YAAA,EACD,EAAiB,IAA0B,CACxC,IAAM,EAAY,EAAa,QAC/B,GAAI,CAAC,EAAW,OAChB,IAAM,EAAO,EAAU,sBAAsB,EACvC,EAAQ,EAAe,EAAK,MAAQ,EAAK,OAC/C,GAAI,GAAS,EAAG,OAEhB,IAAM,GADS,EAAe,EAAU,EAAK,KAAO,EAAU,EAAK,KACzC,EAAS,IACnC,EAAQ,EAAM,EAAS,EAAK,CAAG,CAAC,CACpC,EACA,CAAC,EAAc,EAAK,CAAG,CAC3B,EAEM,GAAA,EAAA,EAAA,YAAA,CACD,GAA8C,CAC3C,EAAM,eAAe,EAErB,EADsB,cACd,kBAAkB,EAAM,SAAS,EAEzC,IAAM,EAAc,GAA6C,CAC7D,EAAkB,EAAU,QAAS,EAAU,OAAO,CAC1D,EACM,MAAuB,CACzB,OAAO,oBAAoB,cAAe,CAAU,EACpD,OAAO,oBAAoB,YAAa,CAAQ,CACpD,EAEA,OAAO,iBAAiB,cAAe,CAAU,EACjD,OAAO,iBAAiB,YAAa,CAAQ,CACjD,EACA,CAAC,CAAiB,CACtB,EAEM,GAAA,EAAA,EAAA,YAAA,CACD,GAA+C,CAC5C,IAAI,EAAQ,EAQZ,GAPI,EACI,EAAM,MAAQ,aAAc,EAAQ,EAC/B,EAAM,MAAQ,cAAa,EAAQ,IAExC,EAAM,MAAQ,YAAa,EAAQ,EAC9B,EAAM,MAAQ,YAAW,EAAQ,IAE1C,EAAM,MAAQ,OAAQ,CACtB,EAAM,eAAe,EACrB,EAAQ,CAAG,EACX,MACJ,CACA,GAAI,EAAM,MAAQ,MAAO,CACrB,EAAM,eAAe,EACrB,EAAQ,CAAG,EACX,MACJ,CACI,IAAU,IACd,EAAM,eAAe,EACrB,EAAS,GAAY,EAAM,EAAU,EAAO,EAAK,CAAG,CAAC,EACzD,EACA,CAAC,EAAc,EAAK,CAAG,CAC3B,EAEA,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CACI,IAAK,EACL,UAAW,EAAA,GACP,EAAA,QAAO,KACP,EAAe,EAAA,QAAO,WAAa,EAAA,QAAO,SAC1C,CACJ,EACA,GAAI,WAPR,EASI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAM,MAAO,CAAE,UAAW,GAAG,EAAK,EAAG,WACvD,CACA,CAAA,GACL,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,KAAK,YACL,mBAAkB,EAAe,WAAa,aAC9C,gBAAe,KAAK,MAAM,CAAI,EAC9B,gBAAe,EACf,gBAAe,EACf,SAAU,EACV,UAAW,EAAA,QAAO,QAClB,cAAe,EACf,UAAW,YAEX,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,OAAQ,cAAY,MAAQ,CAAA,CACnD,CAAA,GACL,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAM,MAAO,CAAE,UAAW,GAAG,IAAM,EAAK,EAAG,WAC7D,CACA,CAAA,CACJ,GAEb"}
1
+ {"version":3,"file":"Resizable.cjs","names":[],"sources":["../../../src/components/Resizable/Resizable.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body owns the pointer capture, the min/max\n * clamp and the keyboard resize step; all three write the same size and must agree\n * on the bounds.\n */\nimport { useCallback, useRef, useState } from \"react\";\nimport type { HTMLAttributes, KeyboardEvent, PointerEvent, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Resizable.module.css\";\n\nexport type ResizableDirection = \"horizontal\" | \"vertical\";\n\nexport interface ResizableProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** Split orientation. `horizontal` (default) places panes side by side. */\n direction?: ResizableDirection;\n /** Initial size of the first pane, as a percentage. Defaults to `50`. */\n defaultSize?: number;\n /** Lower clamp for the first pane size, in percent. Defaults to `10`. */\n min?: number;\n /** Upper clamp for the first pane size, in percent. Defaults to `90`. */\n max?: number;\n /** Exactly two panes — `[paneA, paneB]`. */\n children: [ReactNode, ReactNode];\n}\n\nconst KEY_STEP = 2;\n\n/**\n * Clamp a number into the inclusive `[min, max]` range.\n *\n * @param value - The value to clamp.\n * @param min - Lower bound.\n * @param max - Upper bound.\n * @returns The clamped value.\n */\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/**\n * A two-pane split layout with a draggable divider. The first pane is sized via\n * `flex-basis` as a percentage; the second pane fills the rest. Drag the divider\n * with a pointer, or focus it and use the arrow keys to adjust by 2% steps.\n *\n * The size is clamped to `[min, max]` at all times.\n */\nexport function Resizable({\n direction = \"horizontal\",\n defaultSize = 50,\n min = 10,\n max = 90,\n children,\n className,\n ...props\n}: ResizableProps) {\n const [size, setSize] = useState<number>(() => clamp(defaultSize, min, max));\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [paneA, paneB] = children;\n const isHorizontal = direction === \"horizontal\";\n\n const updateFromPointer = useCallback(\n (clientX: number, clientY: number): void => {\n const container = containerRef.current;\n if (!container) return;\n const rect = container.getBoundingClientRect();\n const total = isHorizontal ? rect.width : rect.height;\n if (total <= 0) return;\n const offset = isHorizontal ? clientX - rect.left : clientY - rect.top;\n const percent = (offset / total) * 100;\n setSize(clamp(percent, min, max));\n },\n [isHorizontal, min, max],\n );\n\n const handlePointerDown = useCallback(\n (event: PointerEvent<HTMLDivElement>): void => {\n event.preventDefault();\n const divider = event.currentTarget;\n divider.setPointerCapture(event.pointerId);\n\n const handleMove = (moveEvent: globalThis.PointerEvent): void => {\n updateFromPointer(moveEvent.clientX, moveEvent.clientY);\n };\n const handleUp = (): void => {\n window.removeEventListener(\"pointermove\", handleMove);\n window.removeEventListener(\"pointerup\", handleUp);\n };\n\n window.addEventListener(\"pointermove\", handleMove);\n window.addEventListener(\"pointerup\", handleUp);\n },\n [updateFromPointer],\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>): void => {\n let delta = 0;\n if (isHorizontal) {\n if (event.key === \"ArrowRight\") delta = KEY_STEP;\n else if (event.key === \"ArrowLeft\") delta = -KEY_STEP;\n } else {\n if (event.key === \"ArrowDown\") delta = KEY_STEP;\n else if (event.key === \"ArrowUp\") delta = -KEY_STEP;\n }\n if (event.key === \"Home\") {\n event.preventDefault();\n setSize(min);\n return;\n }\n if (event.key === \"End\") {\n event.preventDefault();\n setSize(max);\n return;\n }\n if (delta === 0) return;\n event.preventDefault();\n setSize((current) => clamp(current + delta, min, max));\n },\n [isHorizontal, min, max],\n );\n\n return (\n <div\n ref={containerRef}\n className={cn(\n styles.root,\n isHorizontal ? styles.horizontal : styles.vertical,\n className,\n )}\n {...props}\n >\n <div className={styles.pane} style={{ flexBasis: `${size}%` }}>\n {paneA}\n </div>\n <div\n role=\"separator\"\n aria-orientation={isHorizontal ? \"vertical\" : \"horizontal\"}\n aria-valuenow={Math.round(size)}\n aria-valuemin={min}\n aria-valuemax={max}\n tabIndex={0}\n className={styles.divider}\n onPointerDown={handlePointerDown}\n onKeyDown={handleKeyDown}\n >\n <span className={styles.handle} aria-hidden=\"true\" />\n </div>\n <div className={styles.pane} style={{ flexBasis: `${100 - size}%` }}>\n {paneB}\n </div>\n </div>\n );\n}\n"],"mappings":"gIAyBA,IAAM,EAAW,EAUjB,SAAS,EAAM,EAAe,EAAa,EAAqB,CAC5D,OAAO,KAAK,IAAI,EAAK,KAAK,IAAI,EAAK,CAAK,CAAC,CAC7C,CASA,SAAgB,EAAU,CACtB,YAAY,aACZ,cAAc,GACd,MAAM,GACN,MAAM,GACN,WACA,YACA,GAAG,GACY,CACf,GAAM,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,KAAuB,EAAM,EAAa,EAAK,CAAG,CAAC,EACrE,GAAA,EAAe,EAAA,OAAA,CAA8B,IAAI,EACjD,CAAC,EAAO,GAAS,EACjB,EAAe,IAAc,aAE7B,GAAA,EAAoB,EAAA,YAAA,EACrB,EAAiB,IAA0B,CACxC,IAAM,EAAY,EAAa,QAC/B,GAAI,CAAC,EAAW,OAChB,IAAM,EAAO,EAAU,sBAAsB,EACvC,EAAQ,EAAe,EAAK,MAAQ,EAAK,OAC/C,GAAI,GAAS,EAAG,OAEhB,IAAM,GADS,EAAe,EAAU,EAAK,KAAO,EAAU,EAAK,KACzC,EAAS,IACnC,EAAQ,EAAM,EAAS,EAAK,CAAG,CAAC,CACpC,EACA,CAAC,EAAc,EAAK,CAAG,CAC3B,EAEM,GAAA,EAAoB,EAAA,YAAA,CACrB,GAA8C,CAC3C,EAAM,eAAe,EAErB,EADsB,cACd,kBAAkB,EAAM,SAAS,EAEzC,IAAM,EAAc,GAA6C,CAC7D,EAAkB,EAAU,QAAS,EAAU,OAAO,CAC1D,EACM,MAAuB,CACzB,OAAO,oBAAoB,cAAe,CAAU,EACpD,OAAO,oBAAoB,YAAa,CAAQ,CACpD,EAEA,OAAO,iBAAiB,cAAe,CAAU,EACjD,OAAO,iBAAiB,YAAa,CAAQ,CACjD,EACA,CAAC,CAAiB,CACtB,EAEM,GAAA,EAAgB,EAAA,YAAA,CACjB,GAA+C,CAC5C,IAAI,EAAQ,EAQZ,GAPI,EACI,EAAM,MAAQ,aAAc,EAAQ,EAC/B,EAAM,MAAQ,cAAa,EAAQ,IAExC,EAAM,MAAQ,YAAa,EAAQ,EAC9B,EAAM,MAAQ,YAAW,EAAQ,IAE1C,EAAM,MAAQ,OAAQ,CACtB,EAAM,eAAe,EACrB,EAAQ,CAAG,EACX,MACJ,CACA,GAAI,EAAM,MAAQ,MAAO,CACrB,EAAM,eAAe,EACrB,EAAQ,CAAG,EACX,MACJ,CACI,IAAU,IACd,EAAM,eAAe,EACrB,EAAS,GAAY,EAAM,EAAU,EAAO,EAAK,CAAG,CAAC,EACzD,EACA,CAAC,EAAc,EAAK,CAAG,CAC3B,EAEA,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CACI,IAAK,EACL,UAAW,EAAA,GACP,EAAA,QAAO,KACP,EAAe,EAAA,QAAO,WAAa,EAAA,QAAO,SAC1C,CACJ,EACA,GAAI,EAPR,SAAA,EASI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAM,MAAO,CAAE,UAAW,GAAG,EAAK,EAAG,EACvD,SAAA,CACA,CAAA,GACL,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,KAAK,YACL,mBAAkB,EAAe,WAAa,aAC9C,gBAAe,KAAK,MAAM,CAAI,EAC9B,gBAAe,EACf,gBAAe,EACf,SAAU,EACV,UAAW,EAAA,QAAO,QAClB,cAAe,EACf,UAAW,EAEX,UAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,OAAQ,cAAY,MAAQ,CAAA,CACnD,CAAA,GACL,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAM,MAAO,CAAE,UAAW,GAAG,IAAM,EAAK,EAAG,EAC7D,SAAA,CACA,CAAA,CACJ,GAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"Resizable.js","names":[],"sources":["../../../src/components/Resizable/Resizable.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body owns the pointer capture, the min/max\n * clamp and the keyboard resize step; all three write the same size and must agree\n * on the bounds.\n */\nimport { useCallback, useRef, useState } from \"react\";\nimport type { HTMLAttributes, KeyboardEvent, PointerEvent, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Resizable.module.css\";\n\nexport type ResizableDirection = \"horizontal\" | \"vertical\";\n\nexport interface ResizableProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** Split orientation. `horizontal` (default) places panes side by side. */\n direction?: ResizableDirection;\n /** Initial size of the first pane, as a percentage. Defaults to `50`. */\n defaultSize?: number;\n /** Lower clamp for the first pane size, in percent. Defaults to `10`. */\n min?: number;\n /** Upper clamp for the first pane size, in percent. Defaults to `90`. */\n max?: number;\n /** Exactly two panes — `[paneA, paneB]`. */\n children: [ReactNode, ReactNode];\n}\n\nconst KEY_STEP = 2;\n\n/**\n * Clamp a number into the inclusive `[min, max]` range.\n *\n * @param value - The value to clamp.\n * @param min - Lower bound.\n * @param max - Upper bound.\n * @returns The clamped value.\n */\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/**\n * A two-pane split layout with a draggable divider. The first pane is sized via\n * `flex-basis` as a percentage; the second pane fills the rest. Drag the divider\n * with a pointer, or focus it and use the arrow keys to adjust by 2% steps.\n *\n * The size is clamped to `[min, max]` at all times.\n */\nexport function Resizable({\n direction = \"horizontal\",\n defaultSize = 50,\n min = 10,\n max = 90,\n children,\n className,\n ...props\n}: ResizableProps) {\n const [size, setSize] = useState<number>(() => clamp(defaultSize, min, max));\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [paneA, paneB] = children;\n const isHorizontal = direction === \"horizontal\";\n\n const updateFromPointer = useCallback(\n (clientX: number, clientY: number): void => {\n const container = containerRef.current;\n if (!container) return;\n const rect = container.getBoundingClientRect();\n const total = isHorizontal ? rect.width : rect.height;\n if (total <= 0) return;\n const offset = isHorizontal ? clientX - rect.left : clientY - rect.top;\n const percent = (offset / total) * 100;\n setSize(clamp(percent, min, max));\n },\n [isHorizontal, min, max],\n );\n\n const handlePointerDown = useCallback(\n (event: PointerEvent<HTMLDivElement>): void => {\n event.preventDefault();\n const divider = event.currentTarget;\n divider.setPointerCapture(event.pointerId);\n\n const handleMove = (moveEvent: globalThis.PointerEvent): void => {\n updateFromPointer(moveEvent.clientX, moveEvent.clientY);\n };\n const handleUp = (): void => {\n window.removeEventListener(\"pointermove\", handleMove);\n window.removeEventListener(\"pointerup\", handleUp);\n };\n\n window.addEventListener(\"pointermove\", handleMove);\n window.addEventListener(\"pointerup\", handleUp);\n },\n [updateFromPointer],\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>): void => {\n let delta = 0;\n if (isHorizontal) {\n if (event.key === \"ArrowRight\") delta = KEY_STEP;\n else if (event.key === \"ArrowLeft\") delta = -KEY_STEP;\n } else {\n if (event.key === \"ArrowDown\") delta = KEY_STEP;\n else if (event.key === \"ArrowUp\") delta = -KEY_STEP;\n }\n if (event.key === \"Home\") {\n event.preventDefault();\n setSize(min);\n return;\n }\n if (event.key === \"End\") {\n event.preventDefault();\n setSize(max);\n return;\n }\n if (delta === 0) return;\n event.preventDefault();\n setSize((current) => clamp(current + delta, min, max));\n },\n [isHorizontal, min, max],\n );\n\n return (\n <div\n ref={containerRef}\n className={cn(\n styles.root,\n isHorizontal ? styles.horizontal : styles.vertical,\n className,\n )}\n {...props}\n >\n <div className={styles.pane} style={{ flexBasis: `${size}%` }}>\n {paneA}\n </div>\n <div\n role=\"separator\"\n aria-orientation={isHorizontal ? \"vertical\" : \"horizontal\"}\n aria-valuenow={Math.round(size)}\n aria-valuemin={min}\n aria-valuemax={max}\n tabIndex={0}\n className={styles.divider}\n onPointerDown={handlePointerDown}\n onKeyDown={handleKeyDown}\n >\n <span className={styles.handle} aria-hidden=\"true\" />\n </div>\n <div className={styles.pane} style={{ flexBasis: `${100 - size}%` }}>\n {paneB}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAyBA,IAAM,IAAW;AAUjB,SAAS,EAAM,GAAe,GAAa,GAAqB;CAC5D,OAAO,KAAK,IAAI,GAAK,KAAK,IAAI,GAAK,CAAK,CAAC;AAC7C;AASA,SAAgB,EAAU,EACtB,eAAY,cACZ,iBAAc,IACd,SAAM,IACN,SAAM,IACN,aACA,cACA,GAAG,KACY;CACf,IAAM,CAAC,GAAM,KAAW,QAAuB,EAAM,GAAa,GAAK,CAAG,CAAC,GACrE,IAAe,EAA8B,IAAI,GACjD,CAAC,GAAO,KAAS,GACjB,IAAe,MAAc,cAE7B,IAAoB,GACrB,GAAiB,MAA0B;EACxC,IAAM,IAAY,EAAa;EAC/B,IAAI,CAAC,GAAW;EAChB,IAAM,IAAO,EAAU,sBAAsB,GACvC,IAAQ,IAAe,EAAK,QAAQ,EAAK;EAC/C,IAAI,KAAS,GAAG;EAEhB,IAAM,KADS,IAAe,IAAU,EAAK,OAAO,IAAU,EAAK,OACzC,IAAS;EACnC,EAAQ,EAAM,GAAS,GAAK,CAAG,CAAC;CACpC,GACA;EAAC;EAAc;EAAK;CAAG,CAC3B,GAEM,IAAoB,GACrB,MAA8C;EAG3C,AAFA,EAAM,eAAe,GAErB,EADsB,cACd,kBAAkB,EAAM,SAAS;EAEzC,IAAM,KAAc,MAA6C;GAC7D,EAAkB,EAAU,SAAS,EAAU,OAAO;EAC1D,GACM,UAAuB;GAEzB,AADA,OAAO,oBAAoB,eAAe,CAAU,GACpD,OAAO,oBAAoB,aAAa,CAAQ;EACpD;EAGA,AADA,OAAO,iBAAiB,eAAe,CAAU,GACjD,OAAO,iBAAiB,aAAa,CAAQ;CACjD,GACA,CAAC,CAAiB,CACtB,GAEM,IAAgB,GACjB,MAA+C;EAC5C,IAAI,IAAQ;EAQZ,IAPI,IACI,EAAM,QAAQ,eAAc,IAAQ,IAC/B,EAAM,QAAQ,gBAAa,IAAQ,MAExC,EAAM,QAAQ,cAAa,IAAQ,IAC9B,EAAM,QAAQ,cAAW,IAAQ,KAE1C,EAAM,QAAQ,QAAQ;GAEtB,AADA,EAAM,eAAe,GACrB,EAAQ,CAAG;GACX;EACJ;EACA,IAAI,EAAM,QAAQ,OAAO;GAErB,AADA,EAAM,eAAe,GACrB,EAAQ,CAAG;GACX;EACJ;EACI,MAAU,MACd,EAAM,eAAe,GACrB,GAAS,MAAY,EAAM,IAAU,GAAO,GAAK,CAAG,CAAC;CACzD,GACA;EAAC;EAAc;EAAK;CAAG,CAC3B;CAEA,OACI,kBAAC,OAAD;EACI,KAAK;EACL,WAAW,EACP,EAAO,MACP,IAAe,EAAO,aAAa,EAAO,UAC1C,CACJ;EACA,GAAI;YAPR;GASI,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAM,OAAO,EAAE,WAAW,GAAG,EAAK,GAAG;cACvD;GACA,CAAA;GACL,kBAAC,OAAD;IACI,MAAK;IACL,oBAAkB,IAAe,aAAa;IAC9C,iBAAe,KAAK,MAAM,CAAI;IAC9B,iBAAe;IACf,iBAAe;IACf,UAAU;IACV,WAAW,EAAO;IAClB,eAAe;IACf,WAAW;cAEX,kBAAC,QAAD;KAAM,WAAW,EAAO;KAAQ,eAAY;IAAQ,CAAA;GACnD,CAAA;GACL,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAM,OAAO,EAAE,WAAW,GAAG,MAAM,EAAK,GAAG;cAC7D;GACA,CAAA;EACJ;;AAEb"}
1
+ {"version":3,"file":"Resizable.js","names":[],"sources":["../../../src/components/Resizable/Resizable.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body owns the pointer capture, the min/max\n * clamp and the keyboard resize step; all three write the same size and must agree\n * on the bounds.\n */\nimport { useCallback, useRef, useState } from \"react\";\nimport type { HTMLAttributes, KeyboardEvent, PointerEvent, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Resizable.module.css\";\n\nexport type ResizableDirection = \"horizontal\" | \"vertical\";\n\nexport interface ResizableProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** Split orientation. `horizontal` (default) places panes side by side. */\n direction?: ResizableDirection;\n /** Initial size of the first pane, as a percentage. Defaults to `50`. */\n defaultSize?: number;\n /** Lower clamp for the first pane size, in percent. Defaults to `10`. */\n min?: number;\n /** Upper clamp for the first pane size, in percent. Defaults to `90`. */\n max?: number;\n /** Exactly two panes — `[paneA, paneB]`. */\n children: [ReactNode, ReactNode];\n}\n\nconst KEY_STEP = 2;\n\n/**\n * Clamp a number into the inclusive `[min, max]` range.\n *\n * @param value - The value to clamp.\n * @param min - Lower bound.\n * @param max - Upper bound.\n * @returns The clamped value.\n */\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/**\n * A two-pane split layout with a draggable divider. The first pane is sized via\n * `flex-basis` as a percentage; the second pane fills the rest. Drag the divider\n * with a pointer, or focus it and use the arrow keys to adjust by 2% steps.\n *\n * The size is clamped to `[min, max]` at all times.\n */\nexport function Resizable({\n direction = \"horizontal\",\n defaultSize = 50,\n min = 10,\n max = 90,\n children,\n className,\n ...props\n}: ResizableProps) {\n const [size, setSize] = useState<number>(() => clamp(defaultSize, min, max));\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [paneA, paneB] = children;\n const isHorizontal = direction === \"horizontal\";\n\n const updateFromPointer = useCallback(\n (clientX: number, clientY: number): void => {\n const container = containerRef.current;\n if (!container) return;\n const rect = container.getBoundingClientRect();\n const total = isHorizontal ? rect.width : rect.height;\n if (total <= 0) return;\n const offset = isHorizontal ? clientX - rect.left : clientY - rect.top;\n const percent = (offset / total) * 100;\n setSize(clamp(percent, min, max));\n },\n [isHorizontal, min, max],\n );\n\n const handlePointerDown = useCallback(\n (event: PointerEvent<HTMLDivElement>): void => {\n event.preventDefault();\n const divider = event.currentTarget;\n divider.setPointerCapture(event.pointerId);\n\n const handleMove = (moveEvent: globalThis.PointerEvent): void => {\n updateFromPointer(moveEvent.clientX, moveEvent.clientY);\n };\n const handleUp = (): void => {\n window.removeEventListener(\"pointermove\", handleMove);\n window.removeEventListener(\"pointerup\", handleUp);\n };\n\n window.addEventListener(\"pointermove\", handleMove);\n window.addEventListener(\"pointerup\", handleUp);\n },\n [updateFromPointer],\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>): void => {\n let delta = 0;\n if (isHorizontal) {\n if (event.key === \"ArrowRight\") delta = KEY_STEP;\n else if (event.key === \"ArrowLeft\") delta = -KEY_STEP;\n } else {\n if (event.key === \"ArrowDown\") delta = KEY_STEP;\n else if (event.key === \"ArrowUp\") delta = -KEY_STEP;\n }\n if (event.key === \"Home\") {\n event.preventDefault();\n setSize(min);\n return;\n }\n if (event.key === \"End\") {\n event.preventDefault();\n setSize(max);\n return;\n }\n if (delta === 0) return;\n event.preventDefault();\n setSize((current) => clamp(current + delta, min, max));\n },\n [isHorizontal, min, max],\n );\n\n return (\n <div\n ref={containerRef}\n className={cn(\n styles.root,\n isHorizontal ? styles.horizontal : styles.vertical,\n className,\n )}\n {...props}\n >\n <div className={styles.pane} style={{ flexBasis: `${size}%` }}>\n {paneA}\n </div>\n <div\n role=\"separator\"\n aria-orientation={isHorizontal ? \"vertical\" : \"horizontal\"}\n aria-valuenow={Math.round(size)}\n aria-valuemin={min}\n aria-valuemax={max}\n tabIndex={0}\n className={styles.divider}\n onPointerDown={handlePointerDown}\n onKeyDown={handleKeyDown}\n >\n <span className={styles.handle} aria-hidden=\"true\" />\n </div>\n <div className={styles.pane} style={{ flexBasis: `${100 - size}%` }}>\n {paneB}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAyBA,IAAM,IAAW;AAUjB,SAAS,EAAM,GAAe,GAAa,GAAqB;CAC5D,OAAO,KAAK,IAAI,GAAK,KAAK,IAAI,GAAK,CAAK,CAAC;AAC7C;AASA,SAAgB,EAAU,EACtB,eAAY,cACZ,iBAAc,IACd,SAAM,IACN,SAAM,IACN,aACA,cACA,GAAG,KACY;CACf,IAAM,CAAC,GAAM,KAAW,QAAuB,EAAM,GAAa,GAAK,CAAG,CAAC,GACrE,IAAe,EAA8B,IAAI,GACjD,CAAC,GAAO,KAAS,GACjB,IAAe,MAAc,cAE7B,IAAoB,GACrB,GAAiB,MAA0B;EACxC,IAAM,IAAY,EAAa;EAC/B,IAAI,CAAC,GAAW;EAChB,IAAM,IAAO,EAAU,sBAAsB,GACvC,IAAQ,IAAe,EAAK,QAAQ,EAAK;EAC/C,IAAI,KAAS,GAAG;EAEhB,IAAM,KADS,IAAe,IAAU,EAAK,OAAO,IAAU,EAAK,OACzC,IAAS;EACnC,EAAQ,EAAM,GAAS,GAAK,CAAG,CAAC;CACpC,GACA;EAAC;EAAc;EAAK;CAAG,CAC3B,GAEM,IAAoB,GACrB,MAA8C;EAG3C,AAFA,EAAM,eAAe,GAErB,EADsB,cACd,kBAAkB,EAAM,SAAS;EAEzC,IAAM,KAAc,MAA6C;GAC7D,EAAkB,EAAU,SAAS,EAAU,OAAO;EAC1D,GACM,UAAuB;GAEzB,AADA,OAAO,oBAAoB,eAAe,CAAU,GACpD,OAAO,oBAAoB,aAAa,CAAQ;EACpD;EAGA,AADA,OAAO,iBAAiB,eAAe,CAAU,GACjD,OAAO,iBAAiB,aAAa,CAAQ;CACjD,GACA,CAAC,CAAiB,CACtB,GAEM,IAAgB,GACjB,MAA+C;EAC5C,IAAI,IAAQ;EAQZ,IAPI,IACI,EAAM,QAAQ,eAAc,IAAQ,IAC/B,EAAM,QAAQ,gBAAa,IAAQ,MAExC,EAAM,QAAQ,cAAa,IAAQ,IAC9B,EAAM,QAAQ,cAAW,IAAQ,KAE1C,EAAM,QAAQ,QAAQ;GAEtB,AADA,EAAM,eAAe,GACrB,EAAQ,CAAG;GACX;EACJ;EACA,IAAI,EAAM,QAAQ,OAAO;GAErB,AADA,EAAM,eAAe,GACrB,EAAQ,CAAG;GACX;EACJ;EACI,MAAU,MACd,EAAM,eAAe,GACrB,GAAS,MAAY,EAAM,IAAU,GAAO,GAAK,CAAG,CAAC;CACzD,GACA;EAAC;EAAc;EAAK;CAAG,CAC3B;CAEA,OACI,kBAAC,OAAD;EACI,KAAK;EACL,WAAW,EACP,EAAO,MACP,IAAe,EAAO,aAAa,EAAO,UAC1C,CACJ;EACA,GAAI;EAPR,UAAA;GASI,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAM,OAAO,EAAE,WAAW,GAAG,EAAK,GAAG;IACvD,UAAA;GACA,CAAA;GACL,kBAAC,OAAD;IACI,MAAK;IACL,oBAAkB,IAAe,aAAa;IAC9C,iBAAe,KAAK,MAAM,CAAI;IAC9B,iBAAe;IACf,iBAAe;IACf,UAAU;IACV,WAAW,EAAO;IAClB,eAAe;IACf,WAAW;IAEX,UAAA,kBAAC,QAAD;KAAM,WAAW,EAAO;KAAQ,eAAY;IAAQ,CAAA;GACnD,CAAA;GACL,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAM,OAAO,EAAE,WAAW,GAAG,MAAM,EAAK,GAAG;IAC7D,UAAA;GACA,CAAA;EACJ;;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"Scheduler.cjs","names":[],"sources":["../../../src/components/Scheduler/Scheduler.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the grid is defined by\n * anchor, days, startHour, endHour and snapMinutes; the content by events,\n * renderEvent, onEventClick and onSlotClick; the reading by locale, showCurrentTime\n * and now. The body lays out overlapping events into columns, which needs the whole\n * day's events at once.\n */\nimport { type HTMLAttributes, type ReactNode, useEffect, useMemo, useState } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport {\n dayRange,\n type DayWindow,\n fractionOfWindow,\n hourMarks,\n isSameDay,\n layoutAllDay,\n layoutEvents,\n type SchedulerEvent,\n} from \"./scheduler-layout\";\nimport styles from \"./Scheduler.module.css\";\n\nexport interface SchedulerProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** Events to place. Instants are read in the browser's local time. */\n events: readonly SchedulerEvent[];\n /** Any day within the range to show. Default: today. */\n anchor?: Date;\n /** How many consecutive days to render. `1` is a day view, `7` a week. Default `7`. */\n days?: number;\n /** First visible hour, `0`–`23`. Default `8`. */\n startHour?: number;\n /** Last visible hour, `1`–`24`. Default `20`. */\n endHour?: number;\n /** Minutes a click on empty space snaps to. Default `30`. */\n snapMinutes?: number;\n /** Called when an event is activated by click, `Enter` or `Space`. */\n onEventClick?: (event: SchedulerEvent) => void;\n /** Called with the snapped instant when empty space is clicked. */\n onSlotClick?: (start: Date) => void;\n /** Render an event's contents. Defaults to its title and start time. */\n renderEvent?: (event: SchedulerEvent) => ReactNode;\n /** Locale for the day and hour labels. Default `\"pt-BR\"`. */\n locale?: string;\n /** Draw the current-time line. Default `true`. */\n showCurrentTime?: boolean;\n /** Fixed \"now\" for the indicator. Default: the real clock, ticking each minute. */\n now?: Date;\n}\n\n/** Minutes between ticks of the current-time indicator. */\nconst TICK_MS = 60_000;\n\n/**\n * An agenda: events placed on a time grid across consecutive days.\n *\n * `Calendar` is a date *picker* — it answers \"which day?\". This answers \"what is on\n * those days, and when\", which needs a different structure entirely: a vertical time\n * axis, events sized by duration, and overlapping events sitting side by side.\n *\n * That last part is the one worth naming. Overlapping events are grouped into\n * clusters of mutual overlap and every event in a cluster shares one column count,\n * so widths line up; a column is reused the moment it frees, so `9–10`, `9–10`,\n * `10–11` takes two columns and not three. The layout is pure and lives in\n * `scheduler-layout.ts`.\n *\n * Times are local. An event crossing midnight is split into both day columns, and\n * the day range is built by incrementing the calendar day, so a DST boundary does\n * not duplicate or skip a date.\n *\n * @example\n * <Scheduler\n * events={bookings}\n * days={7}\n * startHour={7}\n * endHour={21}\n * onEventClick={(e) => open(e.id)}\n * onSlotClick={(start) => createAt(start)}\n * />\n */\nexport function Scheduler({\n events,\n anchor,\n days: dayCount = 7,\n startHour = 8,\n endHour = 20,\n snapMinutes = 30,\n onEventClick,\n onSlotClick,\n renderEvent,\n locale = \"pt-BR\",\n showCurrentTime = true,\n now,\n className,\n ...rest\n}: SchedulerProps) {\n const [clock, setClock] = useState<Date>(() => now ?? new Date());\n\n /**\n * Keep the current-time line moving.\n *\n * Skipped entirely when `now` is supplied: that is the hook tests and demos use\n * to be deterministic, and a timer would fight it.\n */\n useEffect(() => {\n if (now || !showCurrentTime) return;\n const id = setInterval(() => setClock(new Date()), TICK_MS);\n return () => clearInterval(id);\n }, [now, showCurrentTime]);\n\n const reference = now ?? clock;\n\n const window = useMemo<DayWindow>(\n () => ({ startMinute: startHour * 60, endMinute: endHour * 60 }),\n [startHour, endHour],\n );\n\n /**\n * The calendar day the range starts from, as a stable string.\n *\n * `reference` ticks every minute when the current-time line is live. Depending on\n * the Date itself would re-slice the day range — and therefore relayout every\n * event — once a minute; depending on the day only recomputes at midnight.\n */\n const anchorDay = (anchor ?? reference).toDateString();\n const dayList = useMemo(() => dayRange(new Date(anchorDay), dayCount), [anchorDay, dayCount]);\n\n const placed = useMemo(\n () => layoutEvents({ events, days: dayList, window }),\n [events, dayList, window],\n );\n const allDay = useMemo(() => layoutAllDay({ events, days: dayList }), [events, dayList]);\n const marks = useMemo(() => hourMarks(window), [window]);\n\n const dayLabel = new Intl.DateTimeFormat(locale, { weekday: \"short\", day: \"numeric\" });\n const timeLabel = new Intl.DateTimeFormat(locale, { hour: \"2-digit\", minute: \"2-digit\" });\n\n /** Turn a click's vertical position within a day column into a snapped instant. */\n const slotFromClick = (day: Date, event: React.MouseEvent<HTMLDivElement>): Date => {\n const rect = event.currentTarget.getBoundingClientRect();\n const fraction = rect.height > 0 ? (event.clientY - rect.top) / rect.height : 0;\n const raw = window.startMinute + fraction * (window.endMinute - window.startMinute);\n const snapped = Math.round(raw / snapMinutes) * snapMinutes;\n const clamped = Math.max(window.startMinute, Math.min(window.endMinute, snapped));\n const result = new Date(day);\n result.setHours(0, clamped, 0, 0);\n return result;\n };\n\n const currentFraction = showCurrentTime ? fractionOfWindow(reference, window) : null;\n const todayIndex = dayList.findIndex((day) => isSameDay(day, reference));\n\n return (\n <div className={cn(styles.wrapper, className)} {...rest}>\n <div\n className={styles.head}\n style={{ [\"--tempest-scheduler-days\" as string]: dayCount }}\n >\n <span className={styles.gutterHead} />\n {dayList.map((day, index) => (\n <span\n key={day.toISOString()}\n className={cn(styles.dayHead, index === todayIndex && styles.today)}\n >\n {dayLabel.format(day)}\n </span>\n ))}\n </div>\n\n {allDay.length > 0 && (\n <div\n className={styles.allDayLane}\n style={{ [\"--tempest-scheduler-days\" as string]: dayCount }}\n >\n <span className={styles.gutterHead}>Dia inteiro</span>\n <div className={styles.allDayTrack}>\n {allDay.map(({ event, dayIndex, span }) => (\n <button\n key={event.id}\n type=\"button\"\n className={styles.allDayEvent}\n style={{ gridColumn: `${dayIndex + 1} / span ${span}` }}\n onClick={() => onEventClick?.(event)}\n disabled={!onEventClick}\n >\n {event.title}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {/*\n * Focusable because it scrolls vertically: a scroll region that cannot be\n * focused is unreachable by keyboard, which is what `axe`'s\n * `scrollable-region-focusable` rule is about. It needs a name too, or the\n * new tab stop would announce nothing — but `group`, not `region`: a named\n * `region` is a landmark, and two schedulers on one page would then be two\n * identically-named landmarks (`landmark-unique`).\n */}\n <div\n className={styles.body}\n style={{ [\"--tempest-scheduler-days\" as string]: dayCount }}\n tabIndex={0}\n role=\"group\"\n aria-label=\"Grade de horários\"\n >\n <div className={styles.gutter}>\n {marks.map((minute) => (\n <span\n key={minute}\n className={styles.hourLabel}\n style={{\n top: `${((minute - window.startMinute) / (window.endMinute - window.startMinute)) * 100}%`,\n }}\n >\n {timeLabel.format(\n new Date(2026, 0, 1, Math.floor(minute / 60), minute % 60),\n )}\n </span>\n ))}\n </div>\n\n {/*\n * Not `role=\"grid\"`: that requires `row` children, and the events are\n * siblings of the day columns inside one CSS grid — a `row` wrapper\n * would stop the columns being grid items and collapse the layout.\n * A labelled group per day is the honest structure anyway: a screen\n * reader tabs the event buttons and the group name supplies the day.\n */}\n <div className={styles.grid} aria-label=\"Agenda\">\n {dayList.map((day, index) => (\n <div\n key={day.toISOString()}\n className={cn(\n styles.dayColumn,\n index === todayIndex && styles.todayColumn,\n )}\n role=\"group\"\n aria-label={dayLabel.format(day)}\n onClick={\n onSlotClick\n ? (event) => {\n // Only empty space creates: a click that\n // landed on an event is that event's.\n if (event.target !== event.currentTarget) return;\n onSlotClick(slotFromClick(day, event));\n }\n : undefined\n }\n >\n {marks.map((minute) => (\n <span\n key={minute}\n className={styles.hourLine}\n style={{\n top: `${((minute - window.startMinute) / (window.endMinute - window.startMinute)) * 100}%`,\n }}\n />\n ))}\n </div>\n ))}\n\n {placed.map((item) => (\n <button\n key={`${item.event.id}-${item.dayIndex}`}\n type=\"button\"\n className={styles.event}\n style={{\n gridColumn: item.dayIndex + 1,\n top: `${item.top * 100}%`,\n height: `${item.height * 100}%`,\n left: `${(item.column / item.columns) * 100}%`,\n width: `${(1 / item.columns) * 100}%`,\n }}\n onClick={() => onEventClick?.(item.event)}\n disabled={!onEventClick}\n title={`${item.event.title} — ${timeLabel.format(item.event.start)}`}\n >\n {renderEvent ? (\n renderEvent(item.event)\n ) : (\n <>\n <span className={styles.eventTime}>\n {timeLabel.format(item.event.start)}\n </span>\n <span className={styles.eventTitle}>{item.event.title}</span>\n </>\n )}\n </button>\n ))}\n\n {currentFraction !== null && todayIndex >= 0 && (\n <span\n className={styles.nowLine}\n style={{ top: `${currentFraction * 100}%` }}\n aria-hidden\n data-testid=\"scheduler-now\"\n />\n )}\n </div>\n </div>\n </div>\n );\n}\n\nexport type { SchedulerEvent };\n"],"mappings":"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"}
1
+ {"version":3,"file":"Scheduler.cjs","names":[],"sources":["../../../src/components/Scheduler/Scheduler.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the grid is defined by\n * anchor, days, startHour, endHour and snapMinutes; the content by events,\n * renderEvent, onEventClick and onSlotClick; the reading by locale, showCurrentTime\n * and now. The body lays out overlapping events into columns, which needs the whole\n * day's events at once.\n */\nimport { type HTMLAttributes, type ReactNode, useEffect, useMemo, useState } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport {\n dayRange,\n type DayWindow,\n fractionOfWindow,\n hourMarks,\n isSameDay,\n layoutAllDay,\n layoutEvents,\n type SchedulerEvent,\n} from \"./scheduler-layout\";\nimport styles from \"./Scheduler.module.css\";\n\nexport interface SchedulerProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** Events to place. Instants are read in the browser's local time. */\n events: readonly SchedulerEvent[];\n /** Any day within the range to show. Default: today. */\n anchor?: Date;\n /** How many consecutive days to render. `1` is a day view, `7` a week. Default `7`. */\n days?: number;\n /** First visible hour, `0`–`23`. Default `8`. */\n startHour?: number;\n /** Last visible hour, `1`–`24`. Default `20`. */\n endHour?: number;\n /** Minutes a click on empty space snaps to. Default `30`. */\n snapMinutes?: number;\n /** Called when an event is activated by click, `Enter` or `Space`. */\n onEventClick?: (event: SchedulerEvent) => void;\n /** Called with the snapped instant when empty space is clicked. */\n onSlotClick?: (start: Date) => void;\n /** Render an event's contents. Defaults to its title and start time. */\n renderEvent?: (event: SchedulerEvent) => ReactNode;\n /** Locale for the day and hour labels. Default `\"pt-BR\"`. */\n locale?: string;\n /** Draw the current-time line. Default `true`. */\n showCurrentTime?: boolean;\n /** Fixed \"now\" for the indicator. Default: the real clock, ticking each minute. */\n now?: Date;\n}\n\n/** Minutes between ticks of the current-time indicator. */\nconst TICK_MS = 60_000;\n\n/**\n * An agenda: events placed on a time grid across consecutive days.\n *\n * `Calendar` is a date *picker* — it answers \"which day?\". This answers \"what is on\n * those days, and when\", which needs a different structure entirely: a vertical time\n * axis, events sized by duration, and overlapping events sitting side by side.\n *\n * That last part is the one worth naming. Overlapping events are grouped into\n * clusters of mutual overlap and every event in a cluster shares one column count,\n * so widths line up; a column is reused the moment it frees, so `9–10`, `9–10`,\n * `10–11` takes two columns and not three. The layout is pure and lives in\n * `scheduler-layout.ts`.\n *\n * Times are local. An event crossing midnight is split into both day columns, and\n * the day range is built by incrementing the calendar day, so a DST boundary does\n * not duplicate or skip a date.\n *\n * @example\n * <Scheduler\n * events={bookings}\n * days={7}\n * startHour={7}\n * endHour={21}\n * onEventClick={(e) => open(e.id)}\n * onSlotClick={(start) => createAt(start)}\n * />\n */\nexport function Scheduler({\n events,\n anchor,\n days: dayCount = 7,\n startHour = 8,\n endHour = 20,\n snapMinutes = 30,\n onEventClick,\n onSlotClick,\n renderEvent,\n locale = \"pt-BR\",\n showCurrentTime = true,\n now,\n className,\n ...rest\n}: SchedulerProps) {\n const [clock, setClock] = useState<Date>(() => now ?? new Date());\n\n /**\n * Keep the current-time line moving.\n *\n * Skipped entirely when `now` is supplied: that is the hook tests and demos use\n * to be deterministic, and a timer would fight it.\n */\n useEffect(() => {\n if (now || !showCurrentTime) return;\n const id = setInterval(() => setClock(new Date()), TICK_MS);\n return () => clearInterval(id);\n }, [now, showCurrentTime]);\n\n const reference = now ?? clock;\n\n const window = useMemo<DayWindow>(\n () => ({ startMinute: startHour * 60, endMinute: endHour * 60 }),\n [startHour, endHour],\n );\n\n /**\n * The calendar day the range starts from, as a stable string.\n *\n * `reference` ticks every minute when the current-time line is live. Depending on\n * the Date itself would re-slice the day range — and therefore relayout every\n * event — once a minute; depending on the day only recomputes at midnight.\n */\n const anchorDay = (anchor ?? reference).toDateString();\n const dayList = useMemo(() => dayRange(new Date(anchorDay), dayCount), [anchorDay, dayCount]);\n\n const placed = useMemo(\n () => layoutEvents({ events, days: dayList, window }),\n [events, dayList, window],\n );\n const allDay = useMemo(() => layoutAllDay({ events, days: dayList }), [events, dayList]);\n const marks = useMemo(() => hourMarks(window), [window]);\n\n const dayLabel = new Intl.DateTimeFormat(locale, { weekday: \"short\", day: \"numeric\" });\n const timeLabel = new Intl.DateTimeFormat(locale, { hour: \"2-digit\", minute: \"2-digit\" });\n\n /** Turn a click's vertical position within a day column into a snapped instant. */\n const slotFromClick = (day: Date, event: React.MouseEvent<HTMLDivElement>): Date => {\n const rect = event.currentTarget.getBoundingClientRect();\n const fraction = rect.height > 0 ? (event.clientY - rect.top) / rect.height : 0;\n const raw = window.startMinute + fraction * (window.endMinute - window.startMinute);\n const snapped = Math.round(raw / snapMinutes) * snapMinutes;\n const clamped = Math.max(window.startMinute, Math.min(window.endMinute, snapped));\n const result = new Date(day);\n result.setHours(0, clamped, 0, 0);\n return result;\n };\n\n const currentFraction = showCurrentTime ? fractionOfWindow(reference, window) : null;\n const todayIndex = dayList.findIndex((day) => isSameDay(day, reference));\n\n return (\n <div className={cn(styles.wrapper, className)} {...rest}>\n <div\n className={styles.head}\n style={{ [\"--tempest-scheduler-days\" as string]: dayCount }}\n >\n <span className={styles.gutterHead} />\n {dayList.map((day, index) => (\n <span\n key={day.toISOString()}\n className={cn(styles.dayHead, index === todayIndex && styles.today)}\n >\n {dayLabel.format(day)}\n </span>\n ))}\n </div>\n\n {allDay.length > 0 && (\n <div\n className={styles.allDayLane}\n style={{ [\"--tempest-scheduler-days\" as string]: dayCount }}\n >\n <span className={styles.gutterHead}>Dia inteiro</span>\n <div className={styles.allDayTrack}>\n {allDay.map(({ event, dayIndex, span }) => (\n <button\n key={event.id}\n type=\"button\"\n className={styles.allDayEvent}\n style={{ gridColumn: `${dayIndex + 1} / span ${span}` }}\n onClick={() => onEventClick?.(event)}\n disabled={!onEventClick}\n >\n {event.title}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {/*\n * Focusable because it scrolls vertically: a scroll region that cannot be\n * focused is unreachable by keyboard, which is what `axe`'s\n * `scrollable-region-focusable` rule is about. It needs a name too, or the\n * new tab stop would announce nothing — but `group`, not `region`: a named\n * `region` is a landmark, and two schedulers on one page would then be two\n * identically-named landmarks (`landmark-unique`).\n */}\n <div\n className={styles.body}\n style={{ [\"--tempest-scheduler-days\" as string]: dayCount }}\n tabIndex={0}\n role=\"group\"\n aria-label=\"Grade de horários\"\n >\n <div className={styles.gutter}>\n {marks.map((minute) => (\n <span\n key={minute}\n className={styles.hourLabel}\n style={{\n top: `${((minute - window.startMinute) / (window.endMinute - window.startMinute)) * 100}%`,\n }}\n >\n {timeLabel.format(\n new Date(2026, 0, 1, Math.floor(minute / 60), minute % 60),\n )}\n </span>\n ))}\n </div>\n\n {/*\n * Not `role=\"grid\"`: that requires `row` children, and the events are\n * siblings of the day columns inside one CSS grid — a `row` wrapper\n * would stop the columns being grid items and collapse the layout.\n * A labelled group per day is the honest structure anyway: a screen\n * reader tabs the event buttons and the group name supplies the day.\n */}\n <div className={styles.grid} aria-label=\"Agenda\">\n {dayList.map((day, index) => (\n <div\n key={day.toISOString()}\n className={cn(\n styles.dayColumn,\n index === todayIndex && styles.todayColumn,\n )}\n role=\"group\"\n aria-label={dayLabel.format(day)}\n onClick={\n onSlotClick\n ? (event) => {\n // Only empty space creates: a click that\n // landed on an event is that event's.\n if (event.target !== event.currentTarget) return;\n onSlotClick(slotFromClick(day, event));\n }\n : undefined\n }\n >\n {marks.map((minute) => (\n <span\n key={minute}\n className={styles.hourLine}\n style={{\n top: `${((minute - window.startMinute) / (window.endMinute - window.startMinute)) * 100}%`,\n }}\n />\n ))}\n </div>\n ))}\n\n {placed.map((item) => (\n <button\n key={`${item.event.id}-${item.dayIndex}`}\n type=\"button\"\n className={styles.event}\n style={{\n gridColumn: item.dayIndex + 1,\n top: `${item.top * 100}%`,\n height: `${item.height * 100}%`,\n left: `${(item.column / item.columns) * 100}%`,\n width: `${(1 / item.columns) * 100}%`,\n }}\n onClick={() => onEventClick?.(item.event)}\n disabled={!onEventClick}\n title={`${item.event.title} — ${timeLabel.format(item.event.start)}`}\n >\n {renderEvent ? (\n renderEvent(item.event)\n ) : (\n <>\n <span className={styles.eventTime}>\n {timeLabel.format(item.event.start)}\n </span>\n <span className={styles.eventTitle}>{item.event.title}</span>\n </>\n )}\n </button>\n ))}\n\n {currentFraction !== null && todayIndex >= 0 && (\n <span\n className={styles.nowLine}\n style={{ top: `${currentFraction * 100}%` }}\n aria-hidden\n data-testid=\"scheduler-now\"\n />\n )}\n </div>\n </div>\n </div>\n );\n}\n\nexport type { SchedulerEvent };\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Scheduler.js","names":[],"sources":["../../../src/components/Scheduler/Scheduler.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the grid is defined by\n * anchor, days, startHour, endHour and snapMinutes; the content by events,\n * renderEvent, onEventClick and onSlotClick; the reading by locale, showCurrentTime\n * and now. The body lays out overlapping events into columns, which needs the whole\n * day's events at once.\n */\nimport { type HTMLAttributes, type ReactNode, useEffect, useMemo, useState } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport {\n dayRange,\n type DayWindow,\n fractionOfWindow,\n hourMarks,\n isSameDay,\n layoutAllDay,\n layoutEvents,\n type SchedulerEvent,\n} from \"./scheduler-layout\";\nimport styles from \"./Scheduler.module.css\";\n\nexport interface SchedulerProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** Events to place. Instants are read in the browser's local time. */\n events: readonly SchedulerEvent[];\n /** Any day within the range to show. Default: today. */\n anchor?: Date;\n /** How many consecutive days to render. `1` is a day view, `7` a week. Default `7`. */\n days?: number;\n /** First visible hour, `0`–`23`. Default `8`. */\n startHour?: number;\n /** Last visible hour, `1`–`24`. Default `20`. */\n endHour?: number;\n /** Minutes a click on empty space snaps to. Default `30`. */\n snapMinutes?: number;\n /** Called when an event is activated by click, `Enter` or `Space`. */\n onEventClick?: (event: SchedulerEvent) => void;\n /** Called with the snapped instant when empty space is clicked. */\n onSlotClick?: (start: Date) => void;\n /** Render an event's contents. Defaults to its title and start time. */\n renderEvent?: (event: SchedulerEvent) => ReactNode;\n /** Locale for the day and hour labels. Default `\"pt-BR\"`. */\n locale?: string;\n /** Draw the current-time line. Default `true`. */\n showCurrentTime?: boolean;\n /** Fixed \"now\" for the indicator. Default: the real clock, ticking each minute. */\n now?: Date;\n}\n\n/** Minutes between ticks of the current-time indicator. */\nconst TICK_MS = 60_000;\n\n/**\n * An agenda: events placed on a time grid across consecutive days.\n *\n * `Calendar` is a date *picker* — it answers \"which day?\". This answers \"what is on\n * those days, and when\", which needs a different structure entirely: a vertical time\n * axis, events sized by duration, and overlapping events sitting side by side.\n *\n * That last part is the one worth naming. Overlapping events are grouped into\n * clusters of mutual overlap and every event in a cluster shares one column count,\n * so widths line up; a column is reused the moment it frees, so `9–10`, `9–10`,\n * `10–11` takes two columns and not three. The layout is pure and lives in\n * `scheduler-layout.ts`.\n *\n * Times are local. An event crossing midnight is split into both day columns, and\n * the day range is built by incrementing the calendar day, so a DST boundary does\n * not duplicate or skip a date.\n *\n * @example\n * <Scheduler\n * events={bookings}\n * days={7}\n * startHour={7}\n * endHour={21}\n * onEventClick={(e) => open(e.id)}\n * onSlotClick={(start) => createAt(start)}\n * />\n */\nexport function Scheduler({\n events,\n anchor,\n days: dayCount = 7,\n startHour = 8,\n endHour = 20,\n snapMinutes = 30,\n onEventClick,\n onSlotClick,\n renderEvent,\n locale = \"pt-BR\",\n showCurrentTime = true,\n now,\n className,\n ...rest\n}: SchedulerProps) {\n const [clock, setClock] = useState<Date>(() => now ?? new Date());\n\n /**\n * Keep the current-time line moving.\n *\n * Skipped entirely when `now` is supplied: that is the hook tests and demos use\n * to be deterministic, and a timer would fight it.\n */\n useEffect(() => {\n if (now || !showCurrentTime) return;\n const id = setInterval(() => setClock(new Date()), TICK_MS);\n return () => clearInterval(id);\n }, [now, showCurrentTime]);\n\n const reference = now ?? clock;\n\n const window = useMemo<DayWindow>(\n () => ({ startMinute: startHour * 60, endMinute: endHour * 60 }),\n [startHour, endHour],\n );\n\n /**\n * The calendar day the range starts from, as a stable string.\n *\n * `reference` ticks every minute when the current-time line is live. Depending on\n * the Date itself would re-slice the day range — and therefore relayout every\n * event — once a minute; depending on the day only recomputes at midnight.\n */\n const anchorDay = (anchor ?? reference).toDateString();\n const dayList = useMemo(() => dayRange(new Date(anchorDay), dayCount), [anchorDay, dayCount]);\n\n const placed = useMemo(\n () => layoutEvents({ events, days: dayList, window }),\n [events, dayList, window],\n );\n const allDay = useMemo(() => layoutAllDay({ events, days: dayList }), [events, dayList]);\n const marks = useMemo(() => hourMarks(window), [window]);\n\n const dayLabel = new Intl.DateTimeFormat(locale, { weekday: \"short\", day: \"numeric\" });\n const timeLabel = new Intl.DateTimeFormat(locale, { hour: \"2-digit\", minute: \"2-digit\" });\n\n /** Turn a click's vertical position within a day column into a snapped instant. */\n const slotFromClick = (day: Date, event: React.MouseEvent<HTMLDivElement>): Date => {\n const rect = event.currentTarget.getBoundingClientRect();\n const fraction = rect.height > 0 ? (event.clientY - rect.top) / rect.height : 0;\n const raw = window.startMinute + fraction * (window.endMinute - window.startMinute);\n const snapped = Math.round(raw / snapMinutes) * snapMinutes;\n const clamped = Math.max(window.startMinute, Math.min(window.endMinute, snapped));\n const result = new Date(day);\n result.setHours(0, clamped, 0, 0);\n return result;\n };\n\n const currentFraction = showCurrentTime ? fractionOfWindow(reference, window) : null;\n const todayIndex = dayList.findIndex((day) => isSameDay(day, reference));\n\n return (\n <div className={cn(styles.wrapper, className)} {...rest}>\n <div\n className={styles.head}\n style={{ [\"--tempest-scheduler-days\" as string]: dayCount }}\n >\n <span className={styles.gutterHead} />\n {dayList.map((day, index) => (\n <span\n key={day.toISOString()}\n className={cn(styles.dayHead, index === todayIndex && styles.today)}\n >\n {dayLabel.format(day)}\n </span>\n ))}\n </div>\n\n {allDay.length > 0 && (\n <div\n className={styles.allDayLane}\n style={{ [\"--tempest-scheduler-days\" as string]: dayCount }}\n >\n <span className={styles.gutterHead}>Dia inteiro</span>\n <div className={styles.allDayTrack}>\n {allDay.map(({ event, dayIndex, span }) => (\n <button\n key={event.id}\n type=\"button\"\n className={styles.allDayEvent}\n style={{ gridColumn: `${dayIndex + 1} / span ${span}` }}\n onClick={() => onEventClick?.(event)}\n disabled={!onEventClick}\n >\n {event.title}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {/*\n * Focusable because it scrolls vertically: a scroll region that cannot be\n * focused is unreachable by keyboard, which is what `axe`'s\n * `scrollable-region-focusable` rule is about. It needs a name too, or the\n * new tab stop would announce nothing — but `group`, not `region`: a named\n * `region` is a landmark, and two schedulers on one page would then be two\n * identically-named landmarks (`landmark-unique`).\n */}\n <div\n className={styles.body}\n style={{ [\"--tempest-scheduler-days\" as string]: dayCount }}\n tabIndex={0}\n role=\"group\"\n aria-label=\"Grade de horários\"\n >\n <div className={styles.gutter}>\n {marks.map((minute) => (\n <span\n key={minute}\n className={styles.hourLabel}\n style={{\n top: `${((minute - window.startMinute) / (window.endMinute - window.startMinute)) * 100}%`,\n }}\n >\n {timeLabel.format(\n new Date(2026, 0, 1, Math.floor(minute / 60), minute % 60),\n )}\n </span>\n ))}\n </div>\n\n {/*\n * Not `role=\"grid\"`: that requires `row` children, and the events are\n * siblings of the day columns inside one CSS grid — a `row` wrapper\n * would stop the columns being grid items and collapse the layout.\n * A labelled group per day is the honest structure anyway: a screen\n * reader tabs the event buttons and the group name supplies the day.\n */}\n <div className={styles.grid} aria-label=\"Agenda\">\n {dayList.map((day, index) => (\n <div\n key={day.toISOString()}\n className={cn(\n styles.dayColumn,\n index === todayIndex && styles.todayColumn,\n )}\n role=\"group\"\n aria-label={dayLabel.format(day)}\n onClick={\n onSlotClick\n ? (event) => {\n // Only empty space creates: a click that\n // landed on an event is that event's.\n if (event.target !== event.currentTarget) return;\n onSlotClick(slotFromClick(day, event));\n }\n : undefined\n }\n >\n {marks.map((minute) => (\n <span\n key={minute}\n className={styles.hourLine}\n style={{\n top: `${((minute - window.startMinute) / (window.endMinute - window.startMinute)) * 100}%`,\n }}\n />\n ))}\n </div>\n ))}\n\n {placed.map((item) => (\n <button\n key={`${item.event.id}-${item.dayIndex}`}\n type=\"button\"\n className={styles.event}\n style={{\n gridColumn: item.dayIndex + 1,\n top: `${item.top * 100}%`,\n height: `${item.height * 100}%`,\n left: `${(item.column / item.columns) * 100}%`,\n width: `${(1 / item.columns) * 100}%`,\n }}\n onClick={() => onEventClick?.(item.event)}\n disabled={!onEventClick}\n title={`${item.event.title} — ${timeLabel.format(item.event.start)}`}\n >\n {renderEvent ? (\n renderEvent(item.event)\n ) : (\n <>\n <span className={styles.eventTime}>\n {timeLabel.format(item.event.start)}\n </span>\n <span className={styles.eventTitle}>{item.event.title}</span>\n </>\n )}\n </button>\n ))}\n\n {currentFraction !== null && todayIndex >= 0 && (\n <span\n className={styles.nowLine}\n style={{ top: `${currentFraction * 100}%` }}\n aria-hidden\n data-testid=\"scheduler-now\"\n />\n )}\n </div>\n </div>\n </div>\n );\n}\n\nexport type { SchedulerEvent };\n"],"mappings":"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"}
1
+ {"version":3,"file":"Scheduler.js","names":[],"sources":["../../../src/components/Scheduler/Scheduler.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the grid is defined by\n * anchor, days, startHour, endHour and snapMinutes; the content by events,\n * renderEvent, onEventClick and onSlotClick; the reading by locale, showCurrentTime\n * and now. The body lays out overlapping events into columns, which needs the whole\n * day's events at once.\n */\nimport { type HTMLAttributes, type ReactNode, useEffect, useMemo, useState } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport {\n dayRange,\n type DayWindow,\n fractionOfWindow,\n hourMarks,\n isSameDay,\n layoutAllDay,\n layoutEvents,\n type SchedulerEvent,\n} from \"./scheduler-layout\";\nimport styles from \"./Scheduler.module.css\";\n\nexport interface SchedulerProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** Events to place. Instants are read in the browser's local time. */\n events: readonly SchedulerEvent[];\n /** Any day within the range to show. Default: today. */\n anchor?: Date;\n /** How many consecutive days to render. `1` is a day view, `7` a week. Default `7`. */\n days?: number;\n /** First visible hour, `0`–`23`. Default `8`. */\n startHour?: number;\n /** Last visible hour, `1`–`24`. Default `20`. */\n endHour?: number;\n /** Minutes a click on empty space snaps to. Default `30`. */\n snapMinutes?: number;\n /** Called when an event is activated by click, `Enter` or `Space`. */\n onEventClick?: (event: SchedulerEvent) => void;\n /** Called with the snapped instant when empty space is clicked. */\n onSlotClick?: (start: Date) => void;\n /** Render an event's contents. Defaults to its title and start time. */\n renderEvent?: (event: SchedulerEvent) => ReactNode;\n /** Locale for the day and hour labels. Default `\"pt-BR\"`. */\n locale?: string;\n /** Draw the current-time line. Default `true`. */\n showCurrentTime?: boolean;\n /** Fixed \"now\" for the indicator. Default: the real clock, ticking each minute. */\n now?: Date;\n}\n\n/** Minutes between ticks of the current-time indicator. */\nconst TICK_MS = 60_000;\n\n/**\n * An agenda: events placed on a time grid across consecutive days.\n *\n * `Calendar` is a date *picker* — it answers \"which day?\". This answers \"what is on\n * those days, and when\", which needs a different structure entirely: a vertical time\n * axis, events sized by duration, and overlapping events sitting side by side.\n *\n * That last part is the one worth naming. Overlapping events are grouped into\n * clusters of mutual overlap and every event in a cluster shares one column count,\n * so widths line up; a column is reused the moment it frees, so `9–10`, `9–10`,\n * `10–11` takes two columns and not three. The layout is pure and lives in\n * `scheduler-layout.ts`.\n *\n * Times are local. An event crossing midnight is split into both day columns, and\n * the day range is built by incrementing the calendar day, so a DST boundary does\n * not duplicate or skip a date.\n *\n * @example\n * <Scheduler\n * events={bookings}\n * days={7}\n * startHour={7}\n * endHour={21}\n * onEventClick={(e) => open(e.id)}\n * onSlotClick={(start) => createAt(start)}\n * />\n */\nexport function Scheduler({\n events,\n anchor,\n days: dayCount = 7,\n startHour = 8,\n endHour = 20,\n snapMinutes = 30,\n onEventClick,\n onSlotClick,\n renderEvent,\n locale = \"pt-BR\",\n showCurrentTime = true,\n now,\n className,\n ...rest\n}: SchedulerProps) {\n const [clock, setClock] = useState<Date>(() => now ?? new Date());\n\n /**\n * Keep the current-time line moving.\n *\n * Skipped entirely when `now` is supplied: that is the hook tests and demos use\n * to be deterministic, and a timer would fight it.\n */\n useEffect(() => {\n if (now || !showCurrentTime) return;\n const id = setInterval(() => setClock(new Date()), TICK_MS);\n return () => clearInterval(id);\n }, [now, showCurrentTime]);\n\n const reference = now ?? clock;\n\n const window = useMemo<DayWindow>(\n () => ({ startMinute: startHour * 60, endMinute: endHour * 60 }),\n [startHour, endHour],\n );\n\n /**\n * The calendar day the range starts from, as a stable string.\n *\n * `reference` ticks every minute when the current-time line is live. Depending on\n * the Date itself would re-slice the day range — and therefore relayout every\n * event — once a minute; depending on the day only recomputes at midnight.\n */\n const anchorDay = (anchor ?? reference).toDateString();\n const dayList = useMemo(() => dayRange(new Date(anchorDay), dayCount), [anchorDay, dayCount]);\n\n const placed = useMemo(\n () => layoutEvents({ events, days: dayList, window }),\n [events, dayList, window],\n );\n const allDay = useMemo(() => layoutAllDay({ events, days: dayList }), [events, dayList]);\n const marks = useMemo(() => hourMarks(window), [window]);\n\n const dayLabel = new Intl.DateTimeFormat(locale, { weekday: \"short\", day: \"numeric\" });\n const timeLabel = new Intl.DateTimeFormat(locale, { hour: \"2-digit\", minute: \"2-digit\" });\n\n /** Turn a click's vertical position within a day column into a snapped instant. */\n const slotFromClick = (day: Date, event: React.MouseEvent<HTMLDivElement>): Date => {\n const rect = event.currentTarget.getBoundingClientRect();\n const fraction = rect.height > 0 ? (event.clientY - rect.top) / rect.height : 0;\n const raw = window.startMinute + fraction * (window.endMinute - window.startMinute);\n const snapped = Math.round(raw / snapMinutes) * snapMinutes;\n const clamped = Math.max(window.startMinute, Math.min(window.endMinute, snapped));\n const result = new Date(day);\n result.setHours(0, clamped, 0, 0);\n return result;\n };\n\n const currentFraction = showCurrentTime ? fractionOfWindow(reference, window) : null;\n const todayIndex = dayList.findIndex((day) => isSameDay(day, reference));\n\n return (\n <div className={cn(styles.wrapper, className)} {...rest}>\n <div\n className={styles.head}\n style={{ [\"--tempest-scheduler-days\" as string]: dayCount }}\n >\n <span className={styles.gutterHead} />\n {dayList.map((day, index) => (\n <span\n key={day.toISOString()}\n className={cn(styles.dayHead, index === todayIndex && styles.today)}\n >\n {dayLabel.format(day)}\n </span>\n ))}\n </div>\n\n {allDay.length > 0 && (\n <div\n className={styles.allDayLane}\n style={{ [\"--tempest-scheduler-days\" as string]: dayCount }}\n >\n <span className={styles.gutterHead}>Dia inteiro</span>\n <div className={styles.allDayTrack}>\n {allDay.map(({ event, dayIndex, span }) => (\n <button\n key={event.id}\n type=\"button\"\n className={styles.allDayEvent}\n style={{ gridColumn: `${dayIndex + 1} / span ${span}` }}\n onClick={() => onEventClick?.(event)}\n disabled={!onEventClick}\n >\n {event.title}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {/*\n * Focusable because it scrolls vertically: a scroll region that cannot be\n * focused is unreachable by keyboard, which is what `axe`'s\n * `scrollable-region-focusable` rule is about. It needs a name too, or the\n * new tab stop would announce nothing — but `group`, not `region`: a named\n * `region` is a landmark, and two schedulers on one page would then be two\n * identically-named landmarks (`landmark-unique`).\n */}\n <div\n className={styles.body}\n style={{ [\"--tempest-scheduler-days\" as string]: dayCount }}\n tabIndex={0}\n role=\"group\"\n aria-label=\"Grade de horários\"\n >\n <div className={styles.gutter}>\n {marks.map((minute) => (\n <span\n key={minute}\n className={styles.hourLabel}\n style={{\n top: `${((minute - window.startMinute) / (window.endMinute - window.startMinute)) * 100}%`,\n }}\n >\n {timeLabel.format(\n new Date(2026, 0, 1, Math.floor(minute / 60), minute % 60),\n )}\n </span>\n ))}\n </div>\n\n {/*\n * Not `role=\"grid\"`: that requires `row` children, and the events are\n * siblings of the day columns inside one CSS grid — a `row` wrapper\n * would stop the columns being grid items and collapse the layout.\n * A labelled group per day is the honest structure anyway: a screen\n * reader tabs the event buttons and the group name supplies the day.\n */}\n <div className={styles.grid} aria-label=\"Agenda\">\n {dayList.map((day, index) => (\n <div\n key={day.toISOString()}\n className={cn(\n styles.dayColumn,\n index === todayIndex && styles.todayColumn,\n )}\n role=\"group\"\n aria-label={dayLabel.format(day)}\n onClick={\n onSlotClick\n ? (event) => {\n // Only empty space creates: a click that\n // landed on an event is that event's.\n if (event.target !== event.currentTarget) return;\n onSlotClick(slotFromClick(day, event));\n }\n : undefined\n }\n >\n {marks.map((minute) => (\n <span\n key={minute}\n className={styles.hourLine}\n style={{\n top: `${((minute - window.startMinute) / (window.endMinute - window.startMinute)) * 100}%`,\n }}\n />\n ))}\n </div>\n ))}\n\n {placed.map((item) => (\n <button\n key={`${item.event.id}-${item.dayIndex}`}\n type=\"button\"\n className={styles.event}\n style={{\n gridColumn: item.dayIndex + 1,\n top: `${item.top * 100}%`,\n height: `${item.height * 100}%`,\n left: `${(item.column / item.columns) * 100}%`,\n width: `${(1 / item.columns) * 100}%`,\n }}\n onClick={() => onEventClick?.(item.event)}\n disabled={!onEventClick}\n title={`${item.event.title} — ${timeLabel.format(item.event.start)}`}\n >\n {renderEvent ? (\n renderEvent(item.event)\n ) : (\n <>\n <span className={styles.eventTime}>\n {timeLabel.format(item.event.start)}\n </span>\n <span className={styles.eventTitle}>{item.event.title}</span>\n </>\n )}\n </button>\n ))}\n\n {currentFraction !== null && todayIndex >= 0 && (\n <span\n className={styles.nowLine}\n style={{ top: `${currentFraction * 100}%` }}\n aria-hidden\n data-testid=\"scheduler-now\"\n />\n )}\n </div>\n </div>\n </div>\n );\n}\n\nexport type { SchedulerEvent };\n"],"mappings":";;;;;;AAmDA,IAAM,IAAU;AA6BhB,SAAgB,EAAU,EACtB,WACA,WACA,MAAM,IAAW,GACjB,eAAY,GACZ,aAAU,IACV,iBAAc,IACd,iBACA,gBACA,gBACA,YAAS,SACT,qBAAkB,IAClB,QACA,cACA,GAAG,KACY;CACf,IAAM,CAAC,GAAO,KAAY,QAAqB,qBAAO,IAAI,KAAK,CAAC;CAQhE,QAAgB;EACZ,IAAI,KAAO,CAAC,GAAiB;EAC7B,IAAM,IAAK,kBAAkB,kBAAS,IAAI,KAAK,CAAC,GAAG,CAAO;EAC1D,aAAa,cAAc,CAAE;CACjC,GAAG,CAAC,GAAK,CAAe,CAAC;CAEzB,IAAM,IAAY,KAAO,GAEnB,IAAS,SACJ;EAAE,aAAa,IAAY;EAAI,WAAW,IAAU;CAAG,IAC9D,CAAC,GAAW,CAAO,CACvB,GASM,KAAa,KAAU,EAAA,CAAW,aAAa,GAC/C,IAAU,QAAc,EAAS,IAAI,KAAK,CAAS,GAAG,CAAQ,GAAG,CAAC,GAAW,CAAQ,CAAC,GAEtF,IAAS,QACL,EAAa;EAAE;EAAQ,MAAM;EAAS;CAAO,CAAC,GACpD;EAAC;EAAQ;EAAS;CAAM,CAC5B,GACM,IAAS,QAAc,EAAa;EAAE;EAAQ,MAAM;CAAQ,CAAC,GAAG,CAAC,GAAQ,CAAO,CAAC,GACjF,IAAQ,QAAc,EAAU,CAAM,GAAG,CAAC,CAAM,CAAC,GAEjD,IAAW,IAAI,KAAK,eAAe,GAAQ;EAAE,SAAS;EAAS,KAAK;CAAU,CAAC,GAC/E,IAAY,IAAI,KAAK,eAAe,GAAQ;EAAE,MAAM;EAAW,QAAQ;CAAU,CAAC,GAGlF,KAAiB,GAAW,MAAkD;EAChF,IAAM,IAAO,EAAM,cAAc,sBAAsB,GACjD,IAAW,EAAK,SAAS,KAAK,EAAM,UAAU,EAAK,OAAO,EAAK,SAAS,GACxE,IAAM,EAAO,cAAc,KAAY,EAAO,YAAY,EAAO,cACjE,IAAU,KAAK,MAAM,IAAM,CAAW,IAAI,GAC1C,IAAU,KAAK,IAAI,EAAO,aAAa,KAAK,IAAI,EAAO,WAAW,CAAO,CAAC,GAC1E,IAAS,IAAI,KAAK,CAAG;EAE3B,OADA,EAAO,SAAS,GAAG,GAAS,GAAG,CAAC,GACzB;CACX,GAEM,IAAkB,IAAkB,EAAiB,GAAW,CAAM,IAAI,MAC1E,IAAa,EAAQ,WAAW,MAAQ,EAAU,GAAK,CAAS,CAAC;CAEvE,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAS;EAAG,GAAI;EAAnD,UAAA;GACI,kBAAC,OAAD;IACI,WAAW,EAAO;IAClB,OAAO,EAAG,4BAAuC,EAAS;IAF9D,UAAA,CAII,kBAAC,QAAD,EAAM,WAAW,EAAO,WAAa,CAAA,GACpC,EAAQ,KAAK,GAAK,MACf,kBAAC,QAAD;KAEI,WAAW,EAAG,EAAO,SAAS,MAAU,KAAc,EAAO,KAAK;KAEjE,UAAA,EAAS,OAAO,CAAG;IAClB,GAJG,EAAI,YAAY,CAInB,CACT,CACA;;GAEJ,EAAO,SAAS,KACb,kBAAC,OAAD;IACI,WAAW,EAAO;IAClB,OAAO,EAAG,4BAAuC,EAAS;IAF9D,UAAA,CAII,kBAAC,QAAD;KAAM,WAAW,EAAO;KAAY,UAAA;IAAiB,CAAA,GACrD,kBAAC,OAAD;KAAK,WAAW,EAAO;KAClB,UAAA,EAAO,KAAK,EAAE,UAAO,aAAU,cAC5B,kBAAC,UAAD;MAEI,MAAK;MACL,WAAW,EAAO;MAClB,OAAO,EAAE,YAAY,GAAG,IAAW,EAAE,UAAU,IAAO;MACtD,eAAe,IAAe,CAAK;MACnC,UAAU,CAAC;MAEV,UAAA,EAAM;KACH,GARC,EAAM,EAQP,CACX;IACA,CAAA,CACJ;;GAWT,kBAAC,OAAD;IACI,WAAW,EAAO;IAClB,OAAO,EAAG,4BAAuC,EAAS;IAC1D,UAAU;IACV,MAAK;IACL,cAAW;IALf,UAAA,CAOI,kBAAC,OAAD;KAAK,WAAW,EAAO;KAClB,UAAA,EAAM,KAAK,MACR,kBAAC,QAAD;MAEI,WAAW,EAAO;MAClB,OAAO,EACH,KAAK,IAAK,IAAS,EAAO,gBAAgB,EAAO,YAAY,EAAO,eAAgB,IAAI,GAC5F;MAEC,UAAA,EAAU,OACP,IAAI,KAAK,MAAM,GAAG,GAAG,KAAK,MAAM,IAAS,EAAE,GAAG,IAAS,EAAE,CAC7D;KACE,GATG,CASH,CACT;IACA,CAAA,GASL,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAM,cAAW;KAAxC,UAAA;MACK,EAAQ,KAAK,GAAK,MACf,kBAAC,OAAD;OAEI,WAAW,EACP,EAAO,WACP,MAAU,KAAc,EAAO,WACnC;OACA,MAAK;OACL,cAAY,EAAS,OAAO,CAAG;OAC/B,SACI,KACO,MAAU;QAGH,EAAM,WAAW,EAAM,iBAC3B,EAAY,EAAc,GAAK,CAAK,CAAC;OACzC,IACA,KAAA;OAGT,UAAA,EAAM,KAAK,MACR,kBAAC,QAAD;QAEI,WAAW,EAAO;QAClB,OAAO,EACH,KAAK,IAAK,IAAS,EAAO,gBAAgB,EAAO,YAAY,EAAO,eAAgB,IAAI,GAC5F;OACH,GALQ,CAKR,CACJ;MACA,GA3BI,EAAI,YAAY,CA2BpB,CACR;MAEA,EAAO,KAAK,MACT,kBAAC,UAAD;OAEI,MAAK;OACL,WAAW,EAAO;OAClB,OAAO;QACH,YAAY,EAAK,WAAW;QAC5B,KAAK,GAAG,EAAK,MAAM,IAAI;QACvB,QAAQ,GAAG,EAAK,SAAS,IAAI;QAC7B,MAAM,GAAI,EAAK,SAAS,EAAK,UAAW,IAAI;QAC5C,OAAO,GAAI,IAAI,EAAK,UAAW,IAAI;OACvC;OACA,eAAe,IAAe,EAAK,KAAK;OACxC,UAAU,CAAC;OACX,OAAO,GAAG,EAAK,MAAM,MAAM,KAAK,EAAU,OAAO,EAAK,MAAM,KAAK;OAEhE,UAAA,IACG,EAAY,EAAK,KAAK,IAEtB,kBAAA,GAAA,EAAA,UAAA,CACI,kBAAC,QAAD;QAAM,WAAW,EAAO;QACnB,UAAA,EAAU,OAAO,EAAK,MAAM,KAAK;OAChC,CAAA,GACN,kBAAC,QAAD;QAAM,WAAW,EAAO;QAAa,UAAA,EAAK,MAAM;OAAY,CAAA,CAC9D,EAAA,CAAA;MAEF,GAxBC,GAAG,EAAK,MAAM,GAAG,GAAG,EAAK,UAwB1B,CACX;MAEA,MAAoB,QAAQ,KAAc,KACvC,kBAAC,QAAD;OACI,WAAW,EAAO;OAClB,OAAO,EAAE,KAAK,GAAG,IAAkB,IAAI,GAAG;OAC1C,eAAA;OACA,eAAY;MACf,CAAA;KAEJ;IACJ,CAAA,CAAA;;EACJ;;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"ScrollArea.cjs","names":[],"sources":["../../../src/components/ScrollArea/ScrollArea.tsx"],"sourcesContent":["import { forwardRef, useCallback, useRef } from \"react\";\nimport type { CSSProperties, HTMLAttributes } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { useScrollOverflow } from \"@/hooks/use-scroll-overflow\";\nimport styles from \"./ScrollArea.module.css\";\n\nexport type ScrollAreaOrientation = \"vertical\" | \"horizontal\" | \"both\";\n\nexport interface ScrollAreaProps extends HTMLAttributes<HTMLDivElement> {\n /** Caps the container height; numbers are treated as pixels. */\n maxHeight?: number | string;\n /** Which axis scrolls. Default `\"vertical\"`. */\n orientation?: ScrollAreaOrientation;\n /**\n * Accessible name used while the content actually overflows, when the area\n * takes a tab stop of its own. Defaults to a generic one; name it when the\n * page holds several scroll areas.\n */\n scrollLabel?: string;\n}\n\n/**\n * A styled scroll container that overflows on the chosen axis and renders a\n * thin custom scrollbar (WebKit) while staying fully functional in browsers\n * without scrollbar styling. Forwards `className`, `style` and the ref to the\n * underlying `<div>`.\n *\n * While the content overflows, the container becomes a named, focusable group.\n * A scroll area whose children are plain text holds nothing focusable, so\n * without that a keyboard user can see the scrollbar and has no way to move it.\n * The tab stop disappears again once the content fits, so an area that does not\n * scroll never adds one. Callers may still override `tabIndex` or `role`.\n */\nexport const ScrollArea = forwardRef<HTMLDivElement, ScrollAreaProps>(function ScrollArea(\n {\n maxHeight,\n orientation = \"vertical\",\n scrollLabel = \"Área rolável\",\n className,\n style,\n children,\n ...props\n },\n ref,\n) {\n const innerRef = useRef<HTMLDivElement>(null);\n const scrollable = useScrollOverflow(innerRef, orientation);\n\n /**\n * Keep the forwarded ref working while measuring internally: the caller's\n * ref is the public contract, the inner one is what the observer needs.\n */\n const setRefs = useCallback(\n (node: HTMLDivElement | null) => {\n innerRef.current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) ref.current = node;\n },\n [ref],\n );\n\n const mergedStyle: CSSProperties = {\n overflowX: orientation === \"vertical\" ? \"hidden\" : \"auto\",\n overflowY: orientation === \"horizontal\" ? \"hidden\" : \"auto\",\n ...(maxHeight !== undefined ? { maxHeight } : {}),\n ...style,\n };\n\n return (\n <div\n ref={setRefs}\n className={cn(styles.root, className)}\n style={mergedStyle}\n tabIndex={scrollable ? 0 : undefined}\n role={scrollable ? \"group\" : undefined}\n aria-label={scrollable ? scrollLabel : undefined}\n {...props}\n >\n {children}\n </div>\n );\n});\n"],"mappings":"kLAiCA,IAAa,GAAA,EAAA,EAAA,WAAA,CAAyD,SAClE,CACI,YACA,cAAc,WACd,cAAc,eACd,YACA,QACA,WACA,GAAG,GAEP,EACF,CACE,IAAM,GAAA,EAAA,EAAA,OAAA,CAAkC,IAAI,EACtC,EAAa,EAAA,kBAAkB,EAAU,CAAW,EAMpD,GAAA,EAAA,EAAA,YAAA,CACD,GAAgC,CAC7B,EAAS,QAAU,EACf,OAAO,GAAQ,WAAY,EAAI,CAAI,EAC9B,IAAK,EAAI,QAAU,EAChC,EACA,CAAC,CAAG,CACR,EAEM,EAA6B,CAC/B,UAAW,IAAgB,WAAa,SAAW,OACnD,UAAW,IAAgB,aAAe,SAAW,OACrD,GAAI,IAAc,IAAA,GAA4B,CAAC,EAAjB,CAAE,WAAU,EAC1C,GAAG,CACP,EAEA,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,IAAK,EACL,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,CAAS,EACpC,MAAO,EACP,SAAU,EAAa,EAAI,IAAA,GAC3B,KAAM,EAAa,QAAU,IAAA,GAC7B,aAAY,EAAa,EAAc,IAAA,GACvC,GAAI,EAEH,UACA,CAAA,CAEb,CAAC"}
1
+ {"version":3,"file":"ScrollArea.cjs","names":[],"sources":["../../../src/components/ScrollArea/ScrollArea.tsx"],"sourcesContent":["import { forwardRef, useCallback, useRef } from \"react\";\nimport type { CSSProperties, HTMLAttributes } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { useScrollOverflow } from \"@/hooks/use-scroll-overflow\";\nimport styles from \"./ScrollArea.module.css\";\n\nexport type ScrollAreaOrientation = \"vertical\" | \"horizontal\" | \"both\";\n\nexport interface ScrollAreaProps extends HTMLAttributes<HTMLDivElement> {\n /** Caps the container height; numbers are treated as pixels. */\n maxHeight?: number | string;\n /** Which axis scrolls. Default `\"vertical\"`. */\n orientation?: ScrollAreaOrientation;\n /**\n * Accessible name used while the content actually overflows, when the area\n * takes a tab stop of its own. Defaults to a generic one; name it when the\n * page holds several scroll areas.\n */\n scrollLabel?: string;\n}\n\n/**\n * A styled scroll container that overflows on the chosen axis and renders a\n * thin custom scrollbar (WebKit) while staying fully functional in browsers\n * without scrollbar styling. Forwards `className`, `style` and the ref to the\n * underlying `<div>`.\n *\n * While the content overflows, the container becomes a named, focusable group.\n * A scroll area whose children are plain text holds nothing focusable, so\n * without that a keyboard user can see the scrollbar and has no way to move it.\n * The tab stop disappears again once the content fits, so an area that does not\n * scroll never adds one. Callers may still override `tabIndex` or `role`.\n */\nexport const ScrollArea = forwardRef<HTMLDivElement, ScrollAreaProps>(function ScrollArea(\n {\n maxHeight,\n orientation = \"vertical\",\n scrollLabel = \"Área rolável\",\n className,\n style,\n children,\n ...props\n },\n ref,\n) {\n const innerRef = useRef<HTMLDivElement>(null);\n const scrollable = useScrollOverflow(innerRef, orientation);\n\n /**\n * Keep the forwarded ref working while measuring internally: the caller's\n * ref is the public contract, the inner one is what the observer needs.\n */\n const setRefs = useCallback(\n (node: HTMLDivElement | null) => {\n innerRef.current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) ref.current = node;\n },\n [ref],\n );\n\n const mergedStyle: CSSProperties = {\n overflowX: orientation === \"vertical\" ? \"hidden\" : \"auto\",\n overflowY: orientation === \"horizontal\" ? \"hidden\" : \"auto\",\n ...(maxHeight !== undefined ? { maxHeight } : {}),\n ...style,\n };\n\n return (\n <div\n ref={setRefs}\n className={cn(styles.root, className)}\n style={mergedStyle}\n tabIndex={scrollable ? 0 : undefined}\n role={scrollable ? \"group\" : undefined}\n aria-label={scrollable ? scrollLabel : undefined}\n {...props}\n >\n {children}\n </div>\n );\n});\n"],"mappings":"kLAiCA,IAAa,GAAA,EAAa,EAAA,WAAA,CAA4C,SAClE,CACI,YACA,cAAc,WACd,cAAc,eACd,YACA,QACA,WACA,GAAG,GAEP,EACF,CACE,IAAM,GAAA,EAAW,EAAA,OAAA,CAAuB,IAAI,EACtC,EAAa,EAAA,kBAAkB,EAAU,CAAW,EAMpD,GAAA,EAAU,EAAA,YAAA,CACX,GAAgC,CAC7B,EAAS,QAAU,EACf,OAAO,GAAQ,WAAY,EAAI,CAAI,EAC9B,IAAK,EAAI,QAAU,EAChC,EACA,CAAC,CAAG,CACR,EAEM,EAA6B,CAC/B,UAAW,IAAgB,WAAa,SAAW,OACnD,UAAW,IAAgB,aAAe,SAAW,OACrD,GAAI,IAAc,IAAA,GAA4B,CAAC,EAAjB,CAAE,WAAU,EAC1C,GAAG,CACP,EAEA,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,IAAK,EACL,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,CAAS,EACpC,MAAO,EACP,SAAU,EAAa,EAAI,IAAA,GAC3B,KAAM,EAAa,QAAU,IAAA,GAC7B,aAAY,EAAa,EAAc,IAAA,GACvC,GAAI,EAEH,UACA,CAAA,CAEb,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"SearchBar.cjs","names":[],"sources":["../../../src/components/SearchBar/SearchBar.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { InputHTMLAttributes } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./SearchBar.module.css\";\n\nexport interface SearchBarProps extends Omit<InputHTMLAttributes<HTMLInputElement>, \"onChange\"> {\n value: string;\n onChange: (value: string) => void;\n onClear?: () => void;\n wrapperClassName?: string;\n}\n\n/**\n * Search input with magnifier icon and a clear button. Controlled component:\n * pass `value` and `onChange`.\n */\nexport const SearchBar = forwardRef<HTMLInputElement, SearchBarProps>(function SearchBar(\n { value, onChange, onClear, wrapperClassName, placeholder = \"Buscar...\", className, ...props },\n ref,\n) {\n function handleClear(): void {\n onChange(\"\");\n onClear?.();\n }\n\n return (\n <div className={cn(styles.wrapper, wrapperClassName)}>\n <span className={styles.iconLeft} aria-hidden>\n <SearchIcon />\n </span>\n <input\n ref={ref}\n type=\"search\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n placeholder={placeholder}\n className={cn(styles.input, className)}\n {...props}\n />\n {value && (\n <button\n type=\"button\"\n className={styles.clear}\n aria-label=\"Limpar busca\"\n onClick={handleClear}\n >\n <ClearIcon />\n </button>\n )}\n </div>\n );\n});\n\nfunction SearchIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M20 20l-3.5-3.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nfunction ClearIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 6l12 12M6 18L18 6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"gIAgBA,IAAa,GAAA,EAAA,EAAA,WAAA,CAAyD,SAClE,CAAE,QAAO,WAAU,UAAS,mBAAkB,cAAc,YAAa,YAAW,GAAG,GACvF,EACF,CACE,SAAS,GAAoB,CACzB,EAAS,EAAE,EACX,IAAU,CACd,CAEA,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAgB,WAAnD,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,SAAU,cAAA,aAC9B,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,CAAA,CACX,CAAA,GACN,EAAA,EAAA,IAAA,CAAC,QAAD,CACS,MACL,KAAK,SACE,QACP,SAAW,GAAU,EAAS,EAAM,OAAO,KAAK,EACnC,cACb,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,CAAS,EACrC,GAAI,CACP,CAAA,EACA,IACG,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,MAClB,aAAW,eACX,QAAS,YAET,EAAA,EAAA,IAAA,CAAC,EAAD,CAAY,CAAA,CACR,CAAA,CAEX,GAEb,CAAC,EAED,SAAS,GAAa,CAClB,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,gBAArD,EACI,EAAA,EAAA,IAAA,CAAC,SAAD,CAAQ,GAAG,KAAK,GAAG,KAAK,EAAE,IAAI,OAAO,eAAe,YAAY,GAAK,CAAA,GACrE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,kBAAkB,OAAO,eAAe,YAAY,IAAI,cAAc,OAAS,CAAA,CACtF,GAEb,CAEA,SAAS,GAAY,CACjB,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,iBACjD,EAAA,EAAA,IAAA,CAAC,OAAD,CACI,EAAE,uBACF,OAAO,eACP,YAAY,IACZ,cAAc,OACjB,CAAA,CACA,CAAA,CAEb"}
1
+ {"version":3,"file":"SearchBar.cjs","names":[],"sources":["../../../src/components/SearchBar/SearchBar.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { InputHTMLAttributes } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./SearchBar.module.css\";\n\nexport interface SearchBarProps extends Omit<InputHTMLAttributes<HTMLInputElement>, \"onChange\"> {\n value: string;\n onChange: (value: string) => void;\n onClear?: () => void;\n wrapperClassName?: string;\n}\n\n/**\n * Search input with magnifier icon and a clear button. Controlled component:\n * pass `value` and `onChange`.\n */\nexport const SearchBar = forwardRef<HTMLInputElement, SearchBarProps>(function SearchBar(\n { value, onChange, onClear, wrapperClassName, placeholder = \"Buscar...\", className, ...props },\n ref,\n) {\n function handleClear(): void {\n onChange(\"\");\n onClear?.();\n }\n\n return (\n <div className={cn(styles.wrapper, wrapperClassName)}>\n <span className={styles.iconLeft} aria-hidden>\n <SearchIcon />\n </span>\n <input\n ref={ref}\n type=\"search\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n placeholder={placeholder}\n className={cn(styles.input, className)}\n {...props}\n />\n {value && (\n <button\n type=\"button\"\n className={styles.clear}\n aria-label=\"Limpar busca\"\n onClick={handleClear}\n >\n <ClearIcon />\n </button>\n )}\n </div>\n );\n});\n\nfunction SearchIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M20 20l-3.5-3.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nfunction ClearIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 6l12 12M6 18L18 6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"gIAgBA,IAAa,GAAA,EAAY,EAAA,WAAA,CAA6C,SAClE,CAAE,QAAO,WAAU,UAAS,mBAAkB,cAAc,YAAa,YAAW,GAAG,GACvF,EACF,CACE,SAAS,GAAoB,CACzB,EAAS,EAAE,EACX,IAAU,CACd,CAEA,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAgB,EAAnD,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,SAAU,cAAA,GAC9B,UAAA,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,CAAA,CACX,CAAA,GACN,EAAA,EAAA,IAAA,CAAC,QAAD,CACS,MACL,KAAK,SACE,QACP,SAAW,GAAU,EAAS,EAAM,OAAO,KAAK,EACnC,cACb,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,CAAS,EACrC,GAAI,CACP,CAAA,EACA,IACG,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,MAClB,aAAW,eACX,QAAS,EAET,UAAA,EAAA,EAAA,IAAA,CAAC,EAAD,CAAY,CAAA,CACR,CAAA,CAEX,GAEb,CAAC,EAED,SAAS,GAAa,CAClB,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OAArD,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,SAAD,CAAQ,GAAG,KAAK,GAAG,KAAK,EAAE,IAAI,OAAO,eAAe,YAAY,GAAK,CAAA,GACrE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,kBAAkB,OAAO,eAAe,YAAY,IAAI,cAAc,OAAS,CAAA,CACtF,GAEb,CAEA,SAAS,GAAY,CACjB,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OACjD,UAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CACI,EAAE,uBACF,OAAO,eACP,YAAY,IACZ,cAAc,OACjB,CAAA,CACA,CAAA,CAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"SearchBar.js","names":[],"sources":["../../../src/components/SearchBar/SearchBar.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { InputHTMLAttributes } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./SearchBar.module.css\";\n\nexport interface SearchBarProps extends Omit<InputHTMLAttributes<HTMLInputElement>, \"onChange\"> {\n value: string;\n onChange: (value: string) => void;\n onClear?: () => void;\n wrapperClassName?: string;\n}\n\n/**\n * Search input with magnifier icon and a clear button. Controlled component:\n * pass `value` and `onChange`.\n */\nexport const SearchBar = forwardRef<HTMLInputElement, SearchBarProps>(function SearchBar(\n { value, onChange, onClear, wrapperClassName, placeholder = \"Buscar...\", className, ...props },\n ref,\n) {\n function handleClear(): void {\n onChange(\"\");\n onClear?.();\n }\n\n return (\n <div className={cn(styles.wrapper, wrapperClassName)}>\n <span className={styles.iconLeft} aria-hidden>\n <SearchIcon />\n </span>\n <input\n ref={ref}\n type=\"search\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n placeholder={placeholder}\n className={cn(styles.input, className)}\n {...props}\n />\n {value && (\n <button\n type=\"button\"\n className={styles.clear}\n aria-label=\"Limpar busca\"\n onClick={handleClear}\n >\n <ClearIcon />\n </button>\n )}\n </div>\n );\n});\n\nfunction SearchIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M20 20l-3.5-3.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nfunction ClearIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 6l12 12M6 18L18 6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":";;;;;AAgBA,IAAa,IAAY,EAA6C,SAClE,EAAE,UAAO,aAAU,YAAS,qBAAkB,iBAAc,aAAa,cAAW,GAAG,KACvF,GACF;CACE,SAAS,IAAoB;EAEzB,AADA,EAAS,EAAE,GACX,IAAU;CACd;CAEA,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAgB;YAAnD;GACI,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAU,eAAA;cAC9B,kBAAC,GAAD,CAAa,CAAA;GACX,CAAA;GACN,kBAAC,SAAD;IACS;IACL,MAAK;IACE;IACP,WAAW,MAAU,EAAS,EAAM,OAAO,KAAK;IACnC;IACb,WAAW,EAAG,EAAO,OAAO,CAAS;IACrC,GAAI;GACP,CAAA;GACA,KACG,kBAAC,UAAD;IACI,MAAK;IACL,WAAW,EAAO;IAClB,cAAW;IACX,SAAS;cAET,kBAAC,GAAD,CAAY,CAAA;GACR,CAAA;EAEX;;AAEb,CAAC;AAED,SAAS,IAAa;CAClB,OACI,kBAAC,OAAD;EAAK,OAAM;EAAK,QAAO;EAAK,SAAQ;EAAY,MAAK;YAArD,CACI,kBAAC,UAAD;GAAQ,IAAG;GAAK,IAAG;GAAK,GAAE;GAAI,QAAO;GAAe,aAAY;EAAK,CAAA,GACrE,kBAAC,QAAD;GAAM,GAAE;GAAkB,QAAO;GAAe,aAAY;GAAI,eAAc;EAAS,CAAA,CACtF;;AAEb;AAEA,SAAS,IAAY;CACjB,OACI,kBAAC,OAAD;EAAK,OAAM;EAAK,QAAO;EAAK,SAAQ;EAAY,MAAK;YACjD,kBAAC,QAAD;GACI,GAAE;GACF,QAAO;GACP,aAAY;GACZ,eAAc;EACjB,CAAA;CACA,CAAA;AAEb"}
1
+ {"version":3,"file":"SearchBar.js","names":[],"sources":["../../../src/components/SearchBar/SearchBar.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { InputHTMLAttributes } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./SearchBar.module.css\";\n\nexport interface SearchBarProps extends Omit<InputHTMLAttributes<HTMLInputElement>, \"onChange\"> {\n value: string;\n onChange: (value: string) => void;\n onClear?: () => void;\n wrapperClassName?: string;\n}\n\n/**\n * Search input with magnifier icon and a clear button. Controlled component:\n * pass `value` and `onChange`.\n */\nexport const SearchBar = forwardRef<HTMLInputElement, SearchBarProps>(function SearchBar(\n { value, onChange, onClear, wrapperClassName, placeholder = \"Buscar...\", className, ...props },\n ref,\n) {\n function handleClear(): void {\n onChange(\"\");\n onClear?.();\n }\n\n return (\n <div className={cn(styles.wrapper, wrapperClassName)}>\n <span className={styles.iconLeft} aria-hidden>\n <SearchIcon />\n </span>\n <input\n ref={ref}\n type=\"search\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n placeholder={placeholder}\n className={cn(styles.input, className)}\n {...props}\n />\n {value && (\n <button\n type=\"button\"\n className={styles.clear}\n aria-label=\"Limpar busca\"\n onClick={handleClear}\n >\n <ClearIcon />\n </button>\n )}\n </div>\n );\n});\n\nfunction SearchIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M20 20l-3.5-3.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nfunction ClearIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 6l12 12M6 18L18 6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":";;;;;AAgBA,IAAa,IAAY,EAA6C,SAClE,EAAE,UAAO,aAAU,YAAS,qBAAkB,iBAAc,aAAa,cAAW,GAAG,KACvF,GACF;CACE,SAAS,IAAoB;EAEzB,AADA,EAAS,EAAE,GACX,IAAU;CACd;CAEA,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAgB;EAAnD,UAAA;GACI,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAU,eAAA;IAC9B,UAAA,kBAAC,GAAD,CAAa,CAAA;GACX,CAAA;GACN,kBAAC,SAAD;IACS;IACL,MAAK;IACE;IACP,WAAW,MAAU,EAAS,EAAM,OAAO,KAAK;IACnC;IACb,WAAW,EAAG,EAAO,OAAO,CAAS;IACrC,GAAI;GACP,CAAA;GACA,KACG,kBAAC,UAAD;IACI,MAAK;IACL,WAAW,EAAO;IAClB,cAAW;IACX,SAAS;IAET,UAAA,kBAAC,GAAD,CAAY,CAAA;GACR,CAAA;EAEX;;AAEb,CAAC;AAED,SAAS,IAAa;CAClB,OACI,kBAAC,OAAD;EAAK,OAAM;EAAK,QAAO;EAAK,SAAQ;EAAY,MAAK;EAArD,UAAA,CACI,kBAAC,UAAD;GAAQ,IAAG;GAAK,IAAG;GAAK,GAAE;GAAI,QAAO;GAAe,aAAY;EAAK,CAAA,GACrE,kBAAC,QAAD;GAAM,GAAE;GAAkB,QAAO;GAAe,aAAY;GAAI,eAAc;EAAS,CAAA,CACtF;;AAEb;AAEA,SAAS,IAAY;CACjB,OACI,kBAAC,OAAD;EAAK,OAAM;EAAK,QAAO;EAAK,SAAQ;EAAY,MAAK;EACjD,UAAA,kBAAC,QAAD;GACI,GAAE;GACF,QAAO;GACP,aAAY;GACZ,eAAc;EACjB,CAAA;CACA,CAAA;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentedControl.cjs","names":[],"sources":["../../../src/components/SegmentedControl/SegmentedControl.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./SegmentedControl.module.css\";\n\nexport interface SegmentedControlOption<TValue extends string = string> {\n value: TValue;\n label: ReactNode;\n icon?: ReactNode;\n disabled?: boolean;\n}\n\nexport interface SegmentedControlProps<TValue extends string = string> extends Omit<\n HTMLAttributes<HTMLDivElement>,\n \"onChange\"\n> {\n /** Available segments. */\n options: SegmentedControlOption<TValue>[];\n /** Selected value. */\n value: TValue;\n /** Fires with the new value when a segment is selected. */\n onChange: (value: TValue) => void;\n /** Visual size. Default `\"md\"`. */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Stretch to full width of container. Default `false`. */\n fullWidth?: boolean;\n /** Group label for screen readers. */\n \"aria-label\"?: string;\n}\n\n/**\n * iOS-style segmented control. Two-to-five mutually-exclusive options\n * rendered as a single connected pill bar.\n *\n * @example\n * <SegmentedControl\n * value={view}\n * onChange={setView}\n * options={[\n * { value: \"list\", label: \"Lista\" },\n * { value: \"grid\", label: \"Grade\" },\n * ]}\n * />\n */\nexport function SegmentedControl<TValue extends string = string>({\n options,\n value,\n onChange,\n size = \"md\",\n fullWidth = false,\n className,\n \"aria-label\": ariaLabel,\n ...props\n}: SegmentedControlProps<TValue>) {\n return (\n <div\n role=\"radiogroup\"\n aria-label={ariaLabel}\n className={cn(styles.group, styles[size], fullWidth && styles.fullWidth, className)}\n {...props}\n >\n {options.map((option) => {\n const selected = option.value === value;\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n disabled={option.disabled}\n className={cn(styles.segment, selected && styles.active)}\n onClick={() => onChange(option.value)}\n >\n {option.icon && <span className={styles.icon}>{option.icon}</span>}\n <span className={styles.label}>{option.label}</span>\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":"oHA2CA,SAAgB,EAAiD,CAC7D,UACA,QACA,WACA,OAAO,KACP,YAAY,GACZ,YACA,aAAc,EACd,GAAG,GAC2B,CAC9B,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,KAAK,aACL,aAAY,EACZ,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,EAAA,QAAO,GAAO,GAAa,EAAA,QAAO,UAAW,CAAS,EAClF,GAAI,WAEH,EAAQ,IAAK,GAAW,CACrB,IAAM,EAAW,EAAO,QAAU,EAClC,OACI,EAAA,EAAA,KAAA,CAAC,SAAD,CAEI,KAAK,SACL,KAAK,QACL,eAAc,EACd,SAAU,EAAO,SACjB,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,GAAY,EAAA,QAAO,MAAM,EACvD,YAAe,EAAS,EAAO,KAAK,WAPxC,CASK,EAAO,OAAQ,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,cAAO,EAAO,IAAW,CAAA,GACjE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,eAAQ,EAAO,KAAY,CAAA,CAC/C,GAVC,EAAO,KAUR,CAEhB,CAAC,CACA,CAAA,CAEb"}
1
+ {"version":3,"file":"SegmentedControl.cjs","names":[],"sources":["../../../src/components/SegmentedControl/SegmentedControl.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./SegmentedControl.module.css\";\n\nexport interface SegmentedControlOption<TValue extends string = string> {\n value: TValue;\n label: ReactNode;\n icon?: ReactNode;\n disabled?: boolean;\n}\n\nexport interface SegmentedControlProps<TValue extends string = string> extends Omit<\n HTMLAttributes<HTMLDivElement>,\n \"onChange\"\n> {\n /** Available segments. */\n options: SegmentedControlOption<TValue>[];\n /** Selected value. */\n value: TValue;\n /** Fires with the new value when a segment is selected. */\n onChange: (value: TValue) => void;\n /** Visual size. Default `\"md\"`. */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Stretch to full width of container. Default `false`. */\n fullWidth?: boolean;\n /** Group label for screen readers. */\n \"aria-label\"?: string;\n}\n\n/**\n * iOS-style segmented control. Two-to-five mutually-exclusive options\n * rendered as a single connected pill bar.\n *\n * @example\n * <SegmentedControl\n * value={view}\n * onChange={setView}\n * options={[\n * { value: \"list\", label: \"Lista\" },\n * { value: \"grid\", label: \"Grade\" },\n * ]}\n * />\n */\nexport function SegmentedControl<TValue extends string = string>({\n options,\n value,\n onChange,\n size = \"md\",\n fullWidth = false,\n className,\n \"aria-label\": ariaLabel,\n ...props\n}: SegmentedControlProps<TValue>) {\n return (\n <div\n role=\"radiogroup\"\n aria-label={ariaLabel}\n className={cn(styles.group, styles[size], fullWidth && styles.fullWidth, className)}\n {...props}\n >\n {options.map((option) => {\n const selected = option.value === value;\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n disabled={option.disabled}\n className={cn(styles.segment, selected && styles.active)}\n onClick={() => onChange(option.value)}\n >\n {option.icon && <span className={styles.icon}>{option.icon}</span>}\n <span className={styles.label}>{option.label}</span>\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":"oHA2CA,SAAgB,EAAiD,CAC7D,UACA,QACA,WACA,OAAO,KACP,YAAY,GACZ,YACA,aAAc,EACd,GAAG,GAC2B,CAC9B,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,KAAK,aACL,aAAY,EACZ,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,EAAA,QAAO,GAAO,GAAa,EAAA,QAAO,UAAW,CAAS,EAClF,GAAI,EAEH,SAAA,EAAQ,IAAK,GAAW,CACrB,IAAM,EAAW,EAAO,QAAU,EAClC,OACI,EAAA,EAAA,KAAA,CAAC,SAAD,CAEI,KAAK,SACL,KAAK,QACL,eAAc,EACd,SAAU,EAAO,SACjB,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,GAAY,EAAA,QAAO,MAAM,EACvD,YAAe,EAAS,EAAO,KAAK,EAPxC,SAAA,CASK,EAAO,OAAQ,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,KAAO,SAAA,EAAO,IAAW,CAAA,GACjE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,MAAQ,SAAA,EAAO,KAAY,CAAA,CAC/C,CAVC,EAAA,EAAO,KAUR,CAEhB,CAAC,CACA,CAAA,CAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentedControl.js","names":[],"sources":["../../../src/components/SegmentedControl/SegmentedControl.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./SegmentedControl.module.css\";\n\nexport interface SegmentedControlOption<TValue extends string = string> {\n value: TValue;\n label: ReactNode;\n icon?: ReactNode;\n disabled?: boolean;\n}\n\nexport interface SegmentedControlProps<TValue extends string = string> extends Omit<\n HTMLAttributes<HTMLDivElement>,\n \"onChange\"\n> {\n /** Available segments. */\n options: SegmentedControlOption<TValue>[];\n /** Selected value. */\n value: TValue;\n /** Fires with the new value when a segment is selected. */\n onChange: (value: TValue) => void;\n /** Visual size. Default `\"md\"`. */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Stretch to full width of container. Default `false`. */\n fullWidth?: boolean;\n /** Group label for screen readers. */\n \"aria-label\"?: string;\n}\n\n/**\n * iOS-style segmented control. Two-to-five mutually-exclusive options\n * rendered as a single connected pill bar.\n *\n * @example\n * <SegmentedControl\n * value={view}\n * onChange={setView}\n * options={[\n * { value: \"list\", label: \"Lista\" },\n * { value: \"grid\", label: \"Grade\" },\n * ]}\n * />\n */\nexport function SegmentedControl<TValue extends string = string>({\n options,\n value,\n onChange,\n size = \"md\",\n fullWidth = false,\n className,\n \"aria-label\": ariaLabel,\n ...props\n}: SegmentedControlProps<TValue>) {\n return (\n <div\n role=\"radiogroup\"\n aria-label={ariaLabel}\n className={cn(styles.group, styles[size], fullWidth && styles.fullWidth, className)}\n {...props}\n >\n {options.map((option) => {\n const selected = option.value === value;\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n disabled={option.disabled}\n className={cn(styles.segment, selected && styles.active)}\n onClick={() => onChange(option.value)}\n >\n {option.icon && <span className={styles.icon}>{option.icon}</span>}\n <span className={styles.label}>{option.label}</span>\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;AA2CA,SAAgB,EAAiD,EAC7D,YACA,UACA,aACA,UAAO,MACP,eAAY,IACZ,cACA,cAAc,GACd,GAAG,KAC2B;CAC9B,OACI,kBAAC,OAAD;EACI,MAAK;EACL,cAAY;EACZ,WAAW,EAAG,EAAO,OAAO,EAAO,IAAO,KAAa,EAAO,WAAW,CAAS;EAClF,GAAI;YAEH,EAAQ,KAAK,MAAW;GACrB,IAAM,IAAW,EAAO,UAAU;GAClC,OACI,kBAAC,UAAD;IAEI,MAAK;IACL,MAAK;IACL,gBAAc;IACd,UAAU,EAAO;IACjB,WAAW,EAAG,EAAO,SAAS,KAAY,EAAO,MAAM;IACvD,eAAe,EAAS,EAAO,KAAK;cAPxC,CASK,EAAO,QAAQ,kBAAC,QAAD;KAAM,WAAW,EAAO;eAAO,EAAO;IAAW,CAAA,GACjE,kBAAC,QAAD;KAAM,WAAW,EAAO;eAAQ,EAAO;IAAY,CAAA,CAC/C;MAVC,EAAO,KAUR;EAEhB,CAAC;CACA,CAAA;AAEb"}
1
+ {"version":3,"file":"SegmentedControl.js","names":[],"sources":["../../../src/components/SegmentedControl/SegmentedControl.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./SegmentedControl.module.css\";\n\nexport interface SegmentedControlOption<TValue extends string = string> {\n value: TValue;\n label: ReactNode;\n icon?: ReactNode;\n disabled?: boolean;\n}\n\nexport interface SegmentedControlProps<TValue extends string = string> extends Omit<\n HTMLAttributes<HTMLDivElement>,\n \"onChange\"\n> {\n /** Available segments. */\n options: SegmentedControlOption<TValue>[];\n /** Selected value. */\n value: TValue;\n /** Fires with the new value when a segment is selected. */\n onChange: (value: TValue) => void;\n /** Visual size. Default `\"md\"`. */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Stretch to full width of container. Default `false`. */\n fullWidth?: boolean;\n /** Group label for screen readers. */\n \"aria-label\"?: string;\n}\n\n/**\n * iOS-style segmented control. Two-to-five mutually-exclusive options\n * rendered as a single connected pill bar.\n *\n * @example\n * <SegmentedControl\n * value={view}\n * onChange={setView}\n * options={[\n * { value: \"list\", label: \"Lista\" },\n * { value: \"grid\", label: \"Grade\" },\n * ]}\n * />\n */\nexport function SegmentedControl<TValue extends string = string>({\n options,\n value,\n onChange,\n size = \"md\",\n fullWidth = false,\n className,\n \"aria-label\": ariaLabel,\n ...props\n}: SegmentedControlProps<TValue>) {\n return (\n <div\n role=\"radiogroup\"\n aria-label={ariaLabel}\n className={cn(styles.group, styles[size], fullWidth && styles.fullWidth, className)}\n {...props}\n >\n {options.map((option) => {\n const selected = option.value === value;\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n disabled={option.disabled}\n className={cn(styles.segment, selected && styles.active)}\n onClick={() => onChange(option.value)}\n >\n {option.icon && <span className={styles.icon}>{option.icon}</span>}\n <span className={styles.label}>{option.label}</span>\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;AA2CA,SAAgB,EAAiD,EAC7D,YACA,UACA,aACA,UAAO,MACP,eAAY,IACZ,cACA,cAAc,GACd,GAAG,KAC2B;CAC9B,OACI,kBAAC,OAAD;EACI,MAAK;EACL,cAAY;EACZ,WAAW,EAAG,EAAO,OAAO,EAAO,IAAO,KAAa,EAAO,WAAW,CAAS;EAClF,GAAI;EAEH,UAAA,EAAQ,KAAK,MAAW;GACrB,IAAM,IAAW,EAAO,UAAU;GAClC,OACI,kBAAC,UAAD;IAEI,MAAK;IACL,MAAK;IACL,gBAAc;IACd,UAAU,EAAO;IACjB,WAAW,EAAG,EAAO,SAAS,KAAY,EAAO,MAAM;IACvD,eAAe,EAAS,EAAO,KAAK;IAPxC,UAAA,CASK,EAAO,QAAQ,kBAAC,QAAD;KAAM,WAAW,EAAO;KAAO,UAAA,EAAO;IAAW,CAAA,GACjE,kBAAC,QAAD;KAAM,WAAW,EAAO;KAAQ,UAAA,EAAO;IAAY,CAAA,CAC/C;GAVC,GAAA,EAAO,KAUR;EAEhB,CAAC;CACA,CAAA;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"Select.cjs","names":[],"sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["import { forwardRef, useId } from \"react\";\nimport type { SelectHTMLAttributes } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Select.module.css\";\n\nexport interface SelectOption {\n value: string | number;\n label: string;\n disabled?: boolean;\n}\n\nexport interface SelectProps extends SelectHTMLAttributes<HTMLSelectElement> {\n label?: string;\n helperText?: string;\n error?: string;\n options?: SelectOption[];\n placeholder?: string;\n wrapperClassName?: string;\n}\n\n/**\n * Native `<select>` wrapper with label/helper/error slots. Either provide\n * `options` for a quick render, or pass `<option>` children directly.\n */\nexport const Select = forwardRef<HTMLSelectElement, SelectProps>(function Select(\n {\n label,\n helperText,\n error,\n options,\n placeholder,\n wrapperClassName,\n className,\n children,\n id,\n required,\n ...props\n },\n ref,\n) {\n const generatedId = useId();\n const selectId = id ?? generatedId;\n\n return (\n <div className={cn(styles.wrapper, error && styles.error, wrapperClassName)}>\n {label && (\n <label htmlFor={selectId} className={styles.label}>\n {label}\n {required && <span className={styles.required}>*</span>}\n </label>\n )}\n <div className={styles.field}>\n <select\n ref={ref}\n id={selectId}\n aria-invalid={!!error}\n required={required}\n className={cn(styles.select, className)}\n {...props}\n >\n {placeholder && (\n <option value=\"\" disabled hidden>\n {placeholder}\n </option>\n )}\n {options?.map((opt) => (\n <option key={opt.value} value={opt.value} disabled={opt.disabled}>\n {opt.label}\n </option>\n ))}\n {children}\n </select>\n <span className={styles.caret} aria-hidden>\n <CaretIcon />\n </span>\n </div>\n {error ? (\n <span className={styles.errorText}>{error}</span>\n ) : helperText ? (\n <span className={styles.helper}>{helperText}</span>\n ) : null}\n </div>\n );\n});\n\nfunction CaretIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 9l6 6 6-6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"6HAwBA,IAAa,GAAA,EAAA,EAAA,WAAA,CAAoD,SAC7D,CACI,QACA,aACA,QACA,UACA,cACA,mBACA,YACA,WACA,KACA,WACA,GAAG,GAEP,EACF,CACE,IAAM,GAAA,EAAA,EAAA,MAAA,CAAoB,EACpB,EAAW,GAAM,EAEvB,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,GAAS,EAAA,QAAO,MAAO,CAAgB,WAA1E,CACK,IACG,EAAA,EAAA,KAAA,CAAC,QAAD,CAAO,QAAS,EAAU,UAAW,EAAA,QAAO,eAA5C,CACK,EACA,IAAY,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,kBAAU,GAAO,CAAA,CACnD,KAEX,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,eAAvB,EACI,EAAA,EAAA,KAAA,CAAC,SAAD,CACS,MACL,GAAI,EACJ,eAAc,CAAC,CAAC,EACN,WACV,UAAW,EAAA,GAAG,EAAA,QAAO,OAAQ,CAAS,EACtC,GAAI,WANR,CAQK,IACG,EAAA,EAAA,IAAA,CAAC,SAAD,CAAQ,MAAM,GAAG,SAAA,GAAS,OAAA,YACrB,CACG,CAAA,EAEX,GAAS,IAAK,IACX,EAAA,EAAA,IAAA,CAAC,SAAD,CAAwB,MAAO,EAAI,MAAO,SAAU,EAAI,kBACnD,EAAI,KACD,EAFK,EAAI,KAET,CACX,EACA,CACG,KACR,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,MAAO,cAAA,aAC3B,EAAA,EAAA,IAAA,CAAC,EAAD,CAAY,CAAA,CACV,CAAA,CACL,IACJ,GACG,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,mBAAY,CAAY,CAAA,EAChD,GACA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,gBAAS,CAAiB,CAAA,EAClD,IACH,GAEb,CAAC,EAED,SAAS,GAAY,CACjB,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,iBACjD,EAAA,EAAA,IAAA,CAAC,OAAD,CACI,EAAE,eACF,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,OAClB,CAAA,CACA,CAAA,CAEb"}
1
+ {"version":3,"file":"Select.cjs","names":[],"sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["import { forwardRef, useId } from \"react\";\nimport type { SelectHTMLAttributes } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Select.module.css\";\n\nexport interface SelectOption {\n value: string | number;\n label: string;\n disabled?: boolean;\n}\n\nexport interface SelectProps extends SelectHTMLAttributes<HTMLSelectElement> {\n label?: string;\n helperText?: string;\n error?: string;\n options?: SelectOption[];\n placeholder?: string;\n wrapperClassName?: string;\n}\n\n/**\n * Native `<select>` wrapper with label/helper/error slots. Either provide\n * `options` for a quick render, or pass `<option>` children directly.\n */\nexport const Select = forwardRef<HTMLSelectElement, SelectProps>(function Select(\n {\n label,\n helperText,\n error,\n options,\n placeholder,\n wrapperClassName,\n className,\n children,\n id,\n required,\n ...props\n },\n ref,\n) {\n const generatedId = useId();\n const selectId = id ?? generatedId;\n\n return (\n <div className={cn(styles.wrapper, error && styles.error, wrapperClassName)}>\n {label && (\n <label htmlFor={selectId} className={styles.label}>\n {label}\n {required && <span className={styles.required}>*</span>}\n </label>\n )}\n <div className={styles.field}>\n <select\n ref={ref}\n id={selectId}\n aria-invalid={!!error}\n required={required}\n className={cn(styles.select, className)}\n {...props}\n >\n {placeholder && (\n <option value=\"\" disabled hidden>\n {placeholder}\n </option>\n )}\n {options?.map((opt) => (\n <option key={opt.value} value={opt.value} disabled={opt.disabled}>\n {opt.label}\n </option>\n ))}\n {children}\n </select>\n <span className={styles.caret} aria-hidden>\n <CaretIcon />\n </span>\n </div>\n {error ? (\n <span className={styles.errorText}>{error}</span>\n ) : helperText ? (\n <span className={styles.helper}>{helperText}</span>\n ) : null}\n </div>\n );\n});\n\nfunction CaretIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 9l6 6 6-6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"6HAwBA,IAAa,GAAA,EAAS,EAAA,WAAA,CAA2C,SAC7D,CACI,QACA,aACA,QACA,UACA,cACA,mBACA,YACA,WACA,KACA,WACA,GAAG,GAEP,EACF,CACE,IAAM,GAAA,EAAc,EAAA,MAAA,CAAM,EACpB,EAAW,GAAM,EAEvB,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,GAAS,EAAA,QAAO,MAAO,CAAgB,EAA1E,SAAA,CACK,IACG,EAAA,EAAA,KAAA,CAAC,QAAD,CAAO,QAAS,EAAU,UAAW,EAAA,QAAO,MAA5C,SAAA,CACK,EACA,IAAY,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,SAAU,SAAA,GAAO,CAAA,CACnD,KAEX,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,MAAvB,SAAA,EACI,EAAA,EAAA,KAAA,CAAC,SAAD,CACS,MACL,GAAI,EACJ,eAAc,CAAC,CAAC,EACN,WACV,UAAW,EAAA,GAAG,EAAA,QAAO,OAAQ,CAAS,EACtC,GAAI,EANR,SAAA,CAQK,IACG,EAAA,EAAA,IAAA,CAAC,SAAD,CAAQ,MAAM,GAAG,SAAA,GAAS,OAAA,GACrB,SAAA,CACG,CAAA,EAEX,GAAS,IAAK,IACX,EAAA,EAAA,IAAA,CAAC,SAAD,CAAwB,MAAO,EAAI,MAAO,SAAU,EAAI,SACnD,SAAA,EAAI,KACD,EAFK,EAAI,KAET,CACX,EACA,CACG,CACR,CAAA,GAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,MAAO,cAAA,GAC3B,UAAA,EAAA,EAAA,IAAA,CAAC,EAAD,CAAY,CAAA,CACV,CAAA,CACL,IACJ,GACG,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,UAAY,SAAA,CAAY,CAAA,EAChD,GACA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,OAAS,SAAA,CAAiB,CAAA,EAClD,IACH,GAEb,CAAC,EAED,SAAS,GAAY,CACjB,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OACjD,UAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CACI,EAAE,eACF,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,OAClB,CAAA,CACA,CAAA,CAEb"}