tempest-react-sdk 0.38.3 → 0.39.1

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 (519) hide show
  1. package/README.md +1 -1
  2. package/dist/_virtual/_rolldown/runtime.cjs +1 -1
  3. package/dist/access/access-control-context.cjs.map +1 -1
  4. package/dist/access/use-can.cjs.map +1 -1
  5. package/dist/app/AppProviders.cjs.map +1 -1
  6. package/dist/app/AppProviders.js.map +1 -1
  7. package/dist/audio/use-audio-recorder.cjs.map +1 -1
  8. package/dist/audio/use-audio.cjs.map +1 -1
  9. package/dist/audio/use-microphone.cjs.map +1 -1
  10. package/dist/auth/create-auth-store.cjs.map +1 -1
  11. package/dist/auth/lazy-with-retry.cjs.map +1 -1
  12. package/dist/auth/use-passkey.cjs.map +1 -1
  13. package/dist/br/BrazilMap.cjs +1 -1
  14. package/dist/br/BrazilMap.cjs.map +1 -1
  15. package/dist/br/BrazilMap.js +2 -2
  16. package/dist/br/BrazilMap.js.map +1 -1
  17. package/dist/br/BrazilStateCitySelect.cjs.map +1 -1
  18. package/dist/br/BrazilStateCitySelect.js.map +1 -1
  19. package/dist/br/BrazilStateMap.cjs +1 -1
  20. package/dist/br/BrazilStateMap.cjs.map +1 -1
  21. package/dist/br/BrazilStateMap.js +2 -2
  22. package/dist/br/BrazilStateMap.js.map +1 -1
  23. package/dist/br/MapLegend.cjs.map +1 -1
  24. package/dist/br/MapLegend.js.map +1 -1
  25. package/dist/br/MapMarkers.cjs.map +1 -1
  26. package/dist/br/MapMarkers.js.map +1 -1
  27. package/dist/br/MunicipalitySearch.cjs.map +1 -1
  28. package/dist/br/MunicipalitySearch.js.map +1 -1
  29. package/dist/br/PixQRCode.cjs.map +1 -1
  30. package/dist/br/PixQRCode.js.map +1 -1
  31. package/dist/br/use-map-hover.cjs.map +1 -1
  32. package/dist/br/use-map-zoom.cjs.map +1 -1
  33. package/dist/capture/media-recorder.cjs +1 -1
  34. package/dist/capture/media-recorder.js +2 -2
  35. package/dist/capture/use-barcode-scanner.cjs +1 -1
  36. package/dist/capture/use-barcode-scanner.cjs.map +1 -1
  37. package/dist/capture/use-barcode-scanner.js +2 -2
  38. package/dist/capture/use-barcode-scanner.js.map +1 -1
  39. package/dist/capture/use-screen-capture.cjs.map +1 -1
  40. package/dist/capture/use-speech-recognition.cjs.map +1 -1
  41. package/dist/capture/use-torch.cjs.map +1 -1
  42. package/dist/capture/use-video-recorder.cjs.map +1 -1
  43. package/dist/charts/AreaChart.cjs.map +1 -1
  44. package/dist/charts/AreaChart.js.map +1 -1
  45. package/dist/charts/BarChart.cjs.map +1 -1
  46. package/dist/charts/BarChart.js.map +1 -1
  47. package/dist/charts/LineChart.cjs.map +1 -1
  48. package/dist/charts/LineChart.js.map +1 -1
  49. package/dist/charts/PieChart.cjs.map +1 -1
  50. package/dist/charts/PieChart.js.map +1 -1
  51. package/dist/charts/RadarChart.cjs.map +1 -1
  52. package/dist/charts/RadarChart.js.map +1 -1
  53. package/dist/charts/use-chart-colors.cjs.map +1 -1
  54. package/dist/components/AIChat/AIChat.cjs.map +1 -1
  55. package/dist/components/AIChat/AIChat.js.map +1 -1
  56. package/dist/components/AIChat/AIChatComposer.cjs.map +1 -1
  57. package/dist/components/AIChat/AIChatComposer.js.map +1 -1
  58. package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
  59. package/dist/components/AIChat/AIChatTurn.js.map +1 -1
  60. package/dist/components/Accordion/Accordion.cjs.map +1 -1
  61. package/dist/components/Accordion/Accordion.js.map +1 -1
  62. package/dist/components/Alert/Alert.cjs.map +1 -1
  63. package/dist/components/Alert/Alert.js.map +1 -1
  64. package/dist/components/AppBar/AppBar.cjs.map +1 -1
  65. package/dist/components/AppBar/AppBar.js.map +1 -1
  66. package/dist/components/AppShell/AppShell.cjs.map +1 -1
  67. package/dist/components/AppShell/AppShell.js.map +1 -1
  68. package/dist/components/AudioPlayer/AudioPlayer.cjs.map +1 -1
  69. package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -1
  70. package/dist/components/AudioRecorder/AudioRecorder.cjs.map +1 -1
  71. package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -1
  72. package/dist/components/Avatar/Avatar.cjs.map +1 -1
  73. package/dist/components/Avatar/Avatar.js.map +1 -1
  74. package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -1
  75. package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -1
  76. package/dist/components/Badge/Badge.cjs.map +1 -1
  77. package/dist/components/Badge/Badge.js.map +1 -1
  78. package/dist/components/Banner/Banner.cjs.map +1 -1
  79. package/dist/components/Banner/Banner.js.map +1 -1
  80. package/dist/components/BarcodeScanner/BarcodeScanner.cjs.map +1 -1
  81. package/dist/components/BarcodeScanner/BarcodeScanner.js.map +1 -1
  82. package/dist/components/BottomNavigation/BottomNavigation.cjs.map +1 -1
  83. package/dist/components/BottomNavigation/BottomNavigation.js.map +1 -1
  84. package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
  85. package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
  86. package/dist/components/Breadcrumbs/Breadcrumbs.cjs.map +1 -1
  87. package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
  88. package/dist/components/Button/Button.cjs.map +1 -1
  89. package/dist/components/Button/Button.js.map +1 -1
  90. package/dist/components/Calendar/Calendar.cjs +1 -1
  91. package/dist/components/Calendar/Calendar.cjs.map +1 -1
  92. package/dist/components/Calendar/Calendar.js +38 -41
  93. package/dist/components/Calendar/Calendar.js.map +1 -1
  94. package/dist/components/Card/Card.cjs.map +1 -1
  95. package/dist/components/Card/Card.js.map +1 -1
  96. package/dist/components/Carousel/Carousel.cjs.map +1 -1
  97. package/dist/components/Carousel/Carousel.js.map +1 -1
  98. package/dist/components/Chat/Chat.cjs.map +1 -1
  99. package/dist/components/Chat/Chat.js.map +1 -1
  100. package/dist/components/Chat/ChatComposer.cjs.map +1 -1
  101. package/dist/components/Chat/ChatComposer.js.map +1 -1
  102. package/dist/components/Chat/chat-groups.cjs +1 -1
  103. package/dist/components/Chat/chat-groups.cjs.map +1 -1
  104. package/dist/components/Chat/chat-groups.js +2 -2
  105. package/dist/components/Chat/chat-groups.js.map +1 -1
  106. package/dist/components/Checkbox/Checkbox.cjs.map +1 -1
  107. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  108. package/dist/components/ChipInput/ChipInput.cjs.map +1 -1
  109. package/dist/components/ChipInput/ChipInput.js.map +1 -1
  110. package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
  111. package/dist/components/CodeBlock/CodeBlock.cjs.map +1 -1
  112. package/dist/components/CodeBlock/CodeBlock.js.map +1 -1
  113. package/dist/components/Collapsible/Collapsible.cjs.map +1 -1
  114. package/dist/components/Collapsible/Collapsible.js.map +1 -1
  115. package/dist/components/Combobox/Combobox.cjs.map +1 -1
  116. package/dist/components/Combobox/Combobox.js.map +1 -1
  117. package/dist/components/Command/Command.cjs.map +1 -1
  118. package/dist/components/Command/Command.js.map +1 -1
  119. package/dist/components/ConfirmDialog/ConfirmDialog.cjs.map +1 -1
  120. package/dist/components/ConfirmDialog/ConfirmDialog.js.map +1 -1
  121. package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
  122. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  123. package/dist/components/CopyButton/CopyButton.cjs.map +1 -1
  124. package/dist/components/CopyButton/CopyButton.js.map +1 -1
  125. package/dist/components/DataList/DataList.cjs.map +1 -1
  126. package/dist/components/DataList/DataList.js.map +1 -1
  127. package/dist/components/DataTable/DataTable.cjs +1 -1
  128. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  129. package/dist/components/DataTable/DataTable.js +2 -2
  130. package/dist/components/DataTable/DataTable.js.map +1 -1
  131. package/dist/components/DataTable/EditableCell.cjs.map +1 -1
  132. package/dist/components/DataTable/EditableCell.js.map +1 -1
  133. package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
  134. package/dist/components/DateRangePicker/DateRangePicker.cjs.map +1 -1
  135. package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
  136. package/dist/components/DescriptionList/DescriptionList.cjs.map +1 -1
  137. package/dist/components/DescriptionList/DescriptionList.js.map +1 -1
  138. package/dist/components/Divider/Divider.cjs.map +1 -1
  139. package/dist/components/Divider/Divider.js.map +1 -1
  140. package/dist/components/Drawer/Drawer.cjs.map +1 -1
  141. package/dist/components/Drawer/Drawer.js.map +1 -1
  142. package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
  143. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  144. package/dist/components/Dropzone/Dropzone.cjs.map +1 -1
  145. package/dist/components/Dropzone/Dropzone.js.map +1 -1
  146. package/dist/components/EmptyState/EmptyState.cjs.map +1 -1
  147. package/dist/components/EmptyState/EmptyState.js.map +1 -1
  148. package/dist/components/ErrorState/ErrorState.cjs.map +1 -1
  149. package/dist/components/ErrorState/ErrorState.js.map +1 -1
  150. package/dist/components/FileUpload/FileUpload.cjs +1 -1
  151. package/dist/components/FileUpload/FileUpload.cjs.map +1 -1
  152. package/dist/components/FileUpload/FileUpload.js +1 -1
  153. package/dist/components/FileUpload/FileUpload.js.map +1 -1
  154. package/dist/components/FilterBar/FilterBar.cjs.map +1 -1
  155. package/dist/components/FilterBar/FilterBar.js.map +1 -1
  156. package/dist/components/FloatingActionButton/FloatingActionButton.cjs.map +1 -1
  157. package/dist/components/FloatingActionButton/FloatingActionButton.js.map +1 -1
  158. package/dist/components/Form/Form.cjs.map +1 -1
  159. package/dist/components/Form/Form.js.map +1 -1
  160. package/dist/components/HoverCard/HoverCard.cjs.map +1 -1
  161. package/dist/components/HoverCard/HoverCard.js.map +1 -1
  162. package/dist/components/Image/Image.cjs.map +1 -1
  163. package/dist/components/ImageCropper/ImageCropper.cjs +1 -1
  164. package/dist/components/ImageCropper/ImageCropper.cjs.map +1 -1
  165. package/dist/components/ImageCropper/ImageCropper.js +1 -1
  166. package/dist/components/ImageCropper/ImageCropper.js.map +1 -1
  167. package/dist/components/Input/Input.cjs.map +1 -1
  168. package/dist/components/Input/Input.js.map +1 -1
  169. package/dist/components/InstallBanner/InstallBanner.cjs.map +1 -1
  170. package/dist/components/InstallBanner/InstallBanner.js.map +1 -1
  171. package/dist/components/InstallButton/InstallButton.cjs.map +1 -1
  172. package/dist/components/InstallButton/InstallButton.js.map +1 -1
  173. package/dist/components/Kanban/Kanban.cjs.map +1 -1
  174. package/dist/components/Kanban/Kanban.js.map +1 -1
  175. package/dist/components/Label/Label.cjs.map +1 -1
  176. package/dist/components/Label/Label.js.map +1 -1
  177. package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
  178. package/dist/components/Lightbox/Lightbox.js.map +1 -1
  179. package/dist/components/ListTile/ListTile.cjs.map +1 -1
  180. package/dist/components/ListTile/ListTile.js.map +1 -1
  181. package/dist/components/Markdown/Markdown.cjs +1 -1
  182. package/dist/components/Markdown/Markdown.cjs.map +1 -1
  183. package/dist/components/Markdown/Markdown.js +2 -2
  184. package/dist/components/Markdown/Markdown.js.map +1 -1
  185. package/dist/components/Masonry/Masonry.cjs.map +1 -1
  186. package/dist/components/Masonry/Masonry.js.map +1 -1
  187. package/dist/components/Menubar/Menubar.cjs.map +1 -1
  188. package/dist/components/Menubar/Menubar.js.map +1 -1
  189. package/dist/components/Modal/Modal.cjs.map +1 -1
  190. package/dist/components/Modal/Modal.js.map +1 -1
  191. package/dist/components/ModalsManager/ModalsManager.cjs.map +1 -1
  192. package/dist/components/ModalsManager/ModalsManager.js.map +1 -1
  193. package/dist/components/Money/Money.cjs.map +1 -1
  194. package/dist/components/Money/Money.js.map +1 -1
  195. package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
  196. package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
  197. package/dist/components/NProgress/NProgress.cjs.map +1 -1
  198. package/dist/components/Navbar/Navbar.cjs.map +1 -1
  199. package/dist/components/Navbar/Navbar.js.map +1 -1
  200. package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
  201. package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
  202. package/dist/components/NavigationRail/NavigationRail.cjs.map +1 -1
  203. package/dist/components/NavigationRail/NavigationRail.js.map +1 -1
  204. package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -1
  205. package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -1
  206. package/dist/components/NotificationCenter/use-notification-inbox.cjs.map +1 -1
  207. package/dist/components/OfflineIndicator/OfflineIndicator.cjs.map +1 -1
  208. package/dist/components/OfflineIndicator/OfflineIndicator.js.map +1 -1
  209. package/dist/components/Page/Page.cjs.map +1 -1
  210. package/dist/components/Page/Page.js.map +1 -1
  211. package/dist/components/Pagination/Pagination.cjs.map +1 -1
  212. package/dist/components/Pagination/Pagination.js.map +1 -1
  213. package/dist/components/PasswordInput/PasswordInput.cjs.map +1 -1
  214. package/dist/components/PasswordInput/PasswordInput.js.map +1 -1
  215. package/dist/components/PinInput/PinInput.cjs.map +1 -1
  216. package/dist/components/PinInput/PinInput.js.map +1 -1
  217. package/dist/components/Popover/Popover.cjs.map +1 -1
  218. package/dist/components/Popover/Popover.js.map +1 -1
  219. package/dist/components/Portal/Portal.cjs.map +1 -1
  220. package/dist/components/Progress/Progress.cjs.map +1 -1
  221. package/dist/components/Progress/Progress.js.map +1 -1
  222. package/dist/components/QRCode/QRCode.cjs.map +1 -1
  223. package/dist/components/QRCode/QRCode.js.map +1 -1
  224. package/dist/components/Radio/Radio.cjs.map +1 -1
  225. package/dist/components/Radio/Radio.js.map +1 -1
  226. package/dist/components/RangeSlider/RangeSlider.cjs.map +1 -1
  227. package/dist/components/RangeSlider/RangeSlider.js.map +1 -1
  228. package/dist/components/RatingStars/RatingStars.cjs.map +1 -1
  229. package/dist/components/RatingStars/RatingStars.js.map +1 -1
  230. package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
  231. package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
  232. package/dist/components/RelativeTime/RelativeTime.cjs.map +1 -1
  233. package/dist/components/RelativeTime/RelativeTime.js.map +1 -1
  234. package/dist/components/Resizable/Resizable.cjs.map +1 -1
  235. package/dist/components/Resizable/Resizable.js.map +1 -1
  236. package/dist/components/Scheduler/Scheduler.cjs.map +1 -1
  237. package/dist/components/Scheduler/Scheduler.js.map +1 -1
  238. package/dist/components/ScrollArea/ScrollArea.cjs.map +1 -1
  239. package/dist/components/SearchBar/SearchBar.cjs.map +1 -1
  240. package/dist/components/SearchBar/SearchBar.js.map +1 -1
  241. package/dist/components/SegmentedControl/SegmentedControl.cjs.map +1 -1
  242. package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
  243. package/dist/components/Select/Select.cjs.map +1 -1
  244. package/dist/components/Select/Select.js.map +1 -1
  245. package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
  246. package/dist/components/Sidebar/Sidebar.js.map +1 -1
  247. package/dist/components/SignaturePad/SignaturePad.cjs.map +1 -1
  248. package/dist/components/SignaturePad/SignaturePad.js.map +1 -1
  249. package/dist/components/Slider/Slider.cjs.map +1 -1
  250. package/dist/components/Slider/Slider.js.map +1 -1
  251. package/dist/components/Sparkline/Sparkline.cjs.map +1 -1
  252. package/dist/components/Sparkline/Sparkline.js.map +1 -1
  253. package/dist/components/Spinner/Spinner.cjs.map +1 -1
  254. package/dist/components/Spinner/Spinner.js.map +1 -1
  255. package/dist/components/Stat/Stat.cjs.map +1 -1
  256. package/dist/components/Stat/Stat.js.map +1 -1
  257. package/dist/components/Stepper/Stepper.cjs.map +1 -1
  258. package/dist/components/Stepper/Stepper.js.map +1 -1
  259. package/dist/components/StepperInput/StepperInput.cjs.map +1 -1
  260. package/dist/components/StepperInput/StepperInput.js.map +1 -1
  261. package/dist/components/Switch/Switch.cjs.map +1 -1
  262. package/dist/components/Switch/Switch.js.map +1 -1
  263. package/dist/components/SyncStatusBadge/SyncStatusBadge.cjs.map +1 -1
  264. package/dist/components/SyncStatusBadge/SyncStatusBadge.js.map +1 -1
  265. package/dist/components/Table/Table.cjs.map +1 -1
  266. package/dist/components/Table/Table.js.map +1 -1
  267. package/dist/components/Tabs/Tabs.cjs.map +1 -1
  268. package/dist/components/Tabs/Tabs.js.map +1 -1
  269. package/dist/components/Tag/Tag.cjs.map +1 -1
  270. package/dist/components/Tag/Tag.js.map +1 -1
  271. package/dist/components/Textarea/Textarea.cjs.map +1 -1
  272. package/dist/components/Textarea/Textarea.js.map +1 -1
  273. package/dist/components/TimePicker/TimePicker.cjs.map +1 -1
  274. package/dist/components/TimePicker/TimePicker.js.map +1 -1
  275. package/dist/components/Timeline/Timeline.cjs.map +1 -1
  276. package/dist/components/Timeline/Timeline.js.map +1 -1
  277. package/dist/components/Toast/ToastProvider.cjs.map +1 -1
  278. package/dist/components/Toast/ToastProvider.js.map +1 -1
  279. package/dist/components/Toggle/Toggle.cjs.map +1 -1
  280. package/dist/components/ToggleGroup/ToggleGroup.cjs.map +1 -1
  281. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
  282. package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
  283. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  284. package/dist/components/Tour/Tour.cjs.map +1 -1
  285. package/dist/components/Tour/Tour.js.map +1 -1
  286. package/dist/components/Transfer/Transfer.cjs.map +1 -1
  287. package/dist/components/Transfer/Transfer.js.map +1 -1
  288. package/dist/components/TreeView/TreeView.cjs +1 -1
  289. package/dist/components/TreeView/TreeView.cjs.map +1 -1
  290. package/dist/components/TreeView/TreeView.js +1 -4
  291. package/dist/components/TreeView/TreeView.js.map +1 -1
  292. package/dist/components/UpdatePrompt/UpdatePrompt.cjs.map +1 -1
  293. package/dist/components/UpdatePrompt/UpdatePrompt.js.map +1 -1
  294. package/dist/components/VirtualList/VirtualList.cjs.map +1 -1
  295. package/dist/components/VirtualList/VirtualList.js.map +1 -1
  296. package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -1
  297. package/dist/components/VirtualTable/VirtualTable.js.map +1 -1
  298. package/dist/components/VisuallyHidden/VisuallyHidden.cjs.map +1 -1
  299. package/dist/components/Wizard/Wizard.cjs.map +1 -1
  300. package/dist/components/Wizard/Wizard.js.map +1 -1
  301. package/dist/data/data-provider-context.cjs.map +1 -1
  302. package/dist/data/use-resource.cjs.map +1 -1
  303. package/dist/editor/RichTextEditor.cjs.map +1 -1
  304. package/dist/editor/RichTextEditor.js.map +1 -1
  305. package/dist/error-boundary/use-error-handler.cjs.map +1 -1
  306. package/dist/feature-flags/FeatureFlagsProvider.cjs.map +1 -1
  307. package/dist/forms/FormField.cjs.map +1 -1
  308. package/dist/forms/masked-inputs.cjs.map +1 -1
  309. package/dist/forms/use-viacep.cjs.map +1 -1
  310. package/dist/forms/use-zod-form.cjs.map +1 -1
  311. package/dist/geo/TrajectoryMap.cjs.map +1 -1
  312. package/dist/geo/TrajectoryMap.js.map +1 -1
  313. package/dist/geo/leaflet-map.cjs.map +1 -1
  314. package/dist/geo/leaflet-map.js.map +1 -1
  315. package/dist/geo/use-position-tracker.cjs.map +1 -1
  316. package/dist/hooks/use-announce.cjs.map +1 -1
  317. package/dist/hooks/use-async.cjs.map +1 -1
  318. package/dist/hooks/use-before-install-prompt.cjs.map +1 -1
  319. package/dist/hooks/use-breakpoint.cjs.map +1 -1
  320. package/dist/hooks/use-click-outside.cjs.map +1 -1
  321. package/dist/hooks/use-client-filter.cjs.map +1 -1
  322. package/dist/hooks/use-clipboard.cjs.map +1 -1
  323. package/dist/hooks/use-counter.cjs.map +1 -1
  324. package/dist/hooks/use-debounce.cjs.map +1 -1
  325. package/dist/hooks/use-deep-memo.cjs.map +1 -1
  326. package/dist/hooks/use-disclosure.cjs.map +1 -1
  327. package/dist/hooks/use-document-visibility.cjs.map +1 -1
  328. package/dist/hooks/use-event-listener.cjs.map +1 -1
  329. package/dist/hooks/use-geolocation.cjs.map +1 -1
  330. package/dist/hooks/use-hover.cjs.map +1 -1
  331. package/dist/hooks/use-idle.cjs.map +1 -1
  332. package/dist/hooks/use-install-prompt.cjs +1 -1
  333. package/dist/hooks/use-install-prompt.cjs.map +1 -1
  334. package/dist/hooks/use-install-prompt.js +1 -1
  335. package/dist/hooks/use-install-prompt.js.map +1 -1
  336. package/dist/hooks/use-intersection-observer.cjs.map +1 -1
  337. package/dist/hooks/use-interval.cjs.map +1 -1
  338. package/dist/hooks/use-is-first-render.cjs.map +1 -1
  339. package/dist/hooks/use-keyboard-shortcut.cjs +1 -1
  340. package/dist/hooks/use-keyboard-shortcut.cjs.map +1 -1
  341. package/dist/hooks/use-keyboard-shortcut.js +1 -1
  342. package/dist/hooks/use-keyboard-shortcut.js.map +1 -1
  343. package/dist/hooks/use-list-state.cjs.map +1 -1
  344. package/dist/hooks/use-local-storage.cjs.map +1 -1
  345. package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
  346. package/dist/hooks/use-long-press.cjs.map +1 -1
  347. package/dist/hooks/use-map.cjs.map +1 -1
  348. package/dist/hooks/use-media-devices.cjs.map +1 -1
  349. package/dist/hooks/use-media-permission.cjs.map +1 -1
  350. package/dist/hooks/use-media-query.cjs.map +1 -1
  351. package/dist/hooks/use-object-url.cjs.map +1 -1
  352. package/dist/hooks/use-online.cjs.map +1 -1
  353. package/dist/hooks/use-pagination.cjs.map +1 -1
  354. package/dist/hooks/use-previous.cjs.map +1 -1
  355. package/dist/hooks/use-queue.cjs.map +1 -1
  356. package/dist/hooks/use-resize-observer.cjs.map +1 -1
  357. package/dist/hooks/use-scroll-overflow.cjs.map +1 -1
  358. package/dist/hooks/use-service-worker-update.cjs.map +1 -1
  359. package/dist/hooks/use-set.cjs.map +1 -1
  360. package/dist/hooks/use-sortable.cjs +1 -1
  361. package/dist/hooks/use-sortable.cjs.map +1 -1
  362. package/dist/hooks/use-sortable.js +0 -2
  363. package/dist/hooks/use-sortable.js.map +1 -1
  364. package/dist/hooks/use-stable-callback.cjs.map +1 -1
  365. package/dist/hooks/use-storage-estimate.cjs.map +1 -1
  366. package/dist/hooks/use-throttle.cjs.map +1 -1
  367. package/dist/hooks/use-timeout.cjs.map +1 -1
  368. package/dist/hooks/use-toggle.cjs.map +1 -1
  369. package/dist/hooks/use-window-size.cjs.map +1 -1
  370. package/dist/http/api-client.cjs +1 -1
  371. package/dist/http/api-client.cjs.map +1 -1
  372. package/dist/http/api-client.js +7 -5
  373. package/dist/http/api-client.js.map +1 -1
  374. package/dist/http/resumable-upload.cjs +1 -1
  375. package/dist/http/resumable-upload.cjs.map +1 -1
  376. package/dist/http/resumable-upload.js +1 -1
  377. package/dist/http/resumable-upload.js.map +1 -1
  378. package/dist/http/use-poll.cjs.map +1 -1
  379. package/dist/i18n/I18nProvider.cjs.map +1 -1
  380. package/dist/icons/Icon.cjs.map +1 -1
  381. package/dist/icons/IconProvider.cjs.map +1 -1
  382. package/dist/icons/icon-context.cjs.map +1 -1
  383. package/dist/icons/use-icon.cjs.map +1 -1
  384. package/dist/imaging/use-image-processing.cjs.map +1 -1
  385. package/dist/oauth/GoogleSignIn.cjs.map +1 -1
  386. package/dist/oauth/GoogleSignIn.js.map +1 -1
  387. package/dist/oauth/use-oauth-callback.cjs.map +1 -1
  388. package/dist/offline/use-offline-sync.cjs.map +1 -1
  389. package/dist/push/use-push-subscription.cjs.map +1 -1
  390. package/dist/query/QueryProvider.cjs.map +1 -1
  391. package/dist/query/constants.cjs +1 -1
  392. package/dist/query/constants.cjs.map +1 -1
  393. package/dist/query/constants.js +10 -10
  394. package/dist/query/constants.js.map +1 -1
  395. package/dist/query/create-query-keys.cjs +1 -1
  396. package/dist/query/create-query-keys.cjs.map +1 -1
  397. package/dist/query/create-query-keys.js +1 -1
  398. package/dist/query/create-query-keys.js.map +1 -1
  399. package/dist/query/offline-persistence.cjs.map +1 -1
  400. package/dist/query/use-cursor-query.cjs.map +1 -1
  401. package/dist/query/use-offline-mutation.cjs.map +1 -1
  402. package/dist/query/use-paginated-query.cjs.map +1 -1
  403. package/dist/router/AppRouter.cjs +1 -1
  404. package/dist/router/AppRouter.cjs.map +1 -1
  405. package/dist/router/AppRouter.js +7 -2
  406. package/dist/router/AppRouter.js.map +1 -1
  407. package/dist/sse/use-event-stream.cjs.map +1 -1
  408. package/dist/store/create-store.cjs.map +1 -1
  409. package/dist/tabular/use-tabular-predictor.cjs.map +1 -1
  410. package/dist/telemetry/TelemetryProvider.cjs.map +1 -1
  411. package/dist/theme/ThemeProvider.cjs.map +1 -1
  412. package/dist/theme/color.cjs +1 -1
  413. package/dist/theme/color.cjs.map +1 -1
  414. package/dist/theme/color.js +1 -1
  415. package/dist/theme/color.js.map +1 -1
  416. package/dist/utils/cn.cjs +1 -1
  417. package/dist/utils/cn.cjs.map +1 -1
  418. package/dist/utils/cn.js +1 -1
  419. package/dist/utils/cn.js.map +1 -1
  420. package/dist/utils/objects.cjs +1 -1
  421. package/dist/utils/objects.cjs.map +1 -1
  422. package/dist/utils/objects.js +1 -1
  423. package/dist/utils/objects.js.map +1 -1
  424. package/dist/utils/xlsx.cjs +1 -1
  425. package/dist/utils/xlsx.cjs.map +1 -1
  426. package/dist/utils/xlsx.js +3 -3
  427. package/dist/utils/xlsx.js.map +1 -1
  428. package/dist/vision/core/canvas.cjs +1 -1
  429. package/dist/vision/core/canvas.cjs.map +1 -1
  430. package/dist/vision/core/canvas.js +4 -4
  431. package/dist/vision/core/canvas.js.map +1 -1
  432. package/dist/vision/core/exceptions.cjs +1 -1
  433. package/dist/vision/core/exceptions.cjs.map +1 -1
  434. package/dist/vision/core/exceptions.js +2 -2
  435. package/dist/vision/core/exceptions.js.map +1 -1
  436. package/dist/vision/core/metadata.cjs +2 -2
  437. package/dist/vision/core/metadata.cjs.map +1 -1
  438. package/dist/vision/core/metadata.js +11 -8
  439. package/dist/vision/core/metadata.js.map +1 -1
  440. package/dist/vision/core/session.cjs +1 -1
  441. package/dist/vision/core/session.cjs.map +1 -1
  442. package/dist/vision/core/session.js +8 -5
  443. package/dist/vision/core/session.js.map +1 -1
  444. package/dist/vision/fusion.cjs +2 -0
  445. package/dist/vision/fusion.cjs.map +1 -0
  446. package/dist/vision/fusion.js +42 -0
  447. package/dist/vision/fusion.js.map +1 -0
  448. package/dist/vision/index.cjs +1 -1
  449. package/dist/vision/index.cjs.map +1 -1
  450. package/dist/vision/index.js +23 -20
  451. package/dist/vision/index.js.map +1 -1
  452. package/dist/vision/io/image.cjs +1 -1
  453. package/dist/vision/io/image.cjs.map +1 -1
  454. package/dist/vision/io/image.js +4 -2
  455. package/dist/vision/io/image.js.map +1 -1
  456. package/dist/vision/labels.cjs +1 -1
  457. package/dist/vision/labels.cjs.map +1 -1
  458. package/dist/vision/labels.js +7 -4
  459. package/dist/vision/labels.js.map +1 -1
  460. package/dist/vision/postprocess/detection.cjs +1 -1
  461. package/dist/vision/postprocess/detection.cjs.map +1 -1
  462. package/dist/vision/postprocess/detection.js +3 -10
  463. package/dist/vision/postprocess/detection.js.map +1 -1
  464. package/dist/vision/postprocess/segmentation.cjs +1 -1
  465. package/dist/vision/postprocess/segmentation.cjs.map +1 -1
  466. package/dist/vision/postprocess/segmentation.js +11 -15
  467. package/dist/vision/postprocess/segmentation.js.map +1 -1
  468. package/dist/vision/preprocess/image.cjs +1 -1
  469. package/dist/vision/preprocess/image.cjs.map +1 -1
  470. package/dist/vision/preprocess/image.js +4 -2
  471. package/dist/vision/preprocess/image.js.map +1 -1
  472. package/dist/vision/preprocess/pipeline.cjs +2 -0
  473. package/dist/vision/preprocess/pipeline.cjs.map +1 -0
  474. package/dist/vision/preprocess/pipeline.js +61 -0
  475. package/dist/vision/preprocess/pipeline.js.map +1 -0
  476. package/dist/vision/results.cjs +1 -1
  477. package/dist/vision/results.cjs.map +1 -1
  478. package/dist/vision/results.js +23 -2
  479. package/dist/vision/results.js.map +1 -1
  480. package/dist/vision/tasks/base.cjs +1 -1
  481. package/dist/vision/tasks/base.cjs.map +1 -1
  482. package/dist/vision/tasks/base.js +11 -2
  483. package/dist/vision/tasks/base.js.map +1 -1
  484. package/dist/vision/tasks/classifier.cjs +1 -1
  485. package/dist/vision/tasks/classifier.cjs.map +1 -1
  486. package/dist/vision/tasks/classifier.js +2 -2
  487. package/dist/vision/tasks/classifier.js.map +1 -1
  488. package/dist/vision/tasks/detectClassify.cjs +2 -0
  489. package/dist/vision/tasks/detectClassify.cjs.map +1 -0
  490. package/dist/vision/tasks/detectClassify.js +222 -0
  491. package/dist/vision/tasks/detectClassify.js.map +1 -0
  492. package/dist/vision/tasks/detector.cjs +1 -1
  493. package/dist/vision/tasks/detector.cjs.map +1 -1
  494. package/dist/vision/tasks/detector.js +54 -29
  495. package/dist/vision/tasks/detector.js.map +1 -1
  496. package/dist/vision/tasks/segmenter.cjs +1 -1
  497. package/dist/vision/tasks/segmenter.cjs.map +1 -1
  498. package/dist/vision/tasks/segmenter.js +53 -28
  499. package/dist/vision/tasks/segmenter.js.map +1 -1
  500. package/dist/vision/types.cjs.map +1 -1
  501. package/dist/vision/types.js.map +1 -1
  502. package/dist/vision/use-camera-stream.cjs.map +1 -1
  503. package/dist/vision/use-live-luminance.cjs.map +1 -1
  504. package/dist/vision.cjs +1 -1
  505. package/dist/vision.d.ts +1517 -962
  506. package/dist/vision.js +25 -22
  507. package/dist/vite/create-vite-config.cjs +1 -1
  508. package/dist/vite/create-vite-config.cjs.map +1 -1
  509. package/dist/vite/create-vite-config.js +3 -3
  510. package/dist/vite/create-vite-config.js.map +1 -1
  511. package/dist/vite/tempest-icons.cjs.map +1 -1
  512. package/dist/vite/tempest-pwa-dev-sw.cjs.map +1 -1
  513. package/dist/vite/tempest-pwa-icons.cjs.map +1 -1
  514. package/dist/ws/use-web-socket.cjs +1 -1
  515. package/dist/ws/use-web-socket.cjs.map +1 -1
  516. package/dist/ws/use-web-socket.js +5 -3
  517. package/dist/ws/use-web-socket.js.map +1 -1
  518. package/package.json +2 -2
  519. package/template/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"EmptyState.cjs","names":[],"sources":["../../../src/components/EmptyState/EmptyState.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./EmptyState.module.css\";\n\nexport interface EmptyStateProps {\n icon?: ReactNode;\n title: ReactNode;\n description?: ReactNode;\n action?: ReactNode;\n className?: string;\n}\n\n/** Centered \"nothing here yet\" placeholder with optional icon and CTA. */\nexport function EmptyState({ icon, title, description, action, className }: EmptyStateProps) {\n return (\n <div className={cn(styles.wrapper, className)}>\n {icon && <div className={styles.icon}>{icon}</div>}\n <h4 className={styles.title}>{title}</h4>\n {description && <p className={styles.description}>{description}</p>}\n {action && <div className={styles.action}>{action}</div>}\n </div>\n );\n}\n"],"mappings":"8GAaA,SAAgB,EAAW,CAAE,OAAM,QAAO,cAAa,SAAQ,aAA8B,CACzF,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,WAA5C,CACK,IAAQ,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,cAAO,CAAU,CAAA,GACjD,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,eAAQ,CAAU,CAAA,EACvC,IAAe,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAA,QAAO,qBAAc,CAAe,CAAA,EACjE,IAAU,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,gBAAS,CAAY,CAAA,CACtD,GAEb"}
1
+ {"version":3,"file":"EmptyState.cjs","names":[],"sources":["../../../src/components/EmptyState/EmptyState.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./EmptyState.module.css\";\n\nexport interface EmptyStateProps {\n icon?: ReactNode;\n title: ReactNode;\n description?: ReactNode;\n action?: ReactNode;\n className?: string;\n}\n\n/** Centered \"nothing here yet\" placeholder with optional icon and CTA. */\nexport function EmptyState({ icon, title, description, action, className }: EmptyStateProps) {\n return (\n <div className={cn(styles.wrapper, className)}>\n {icon && <div className={styles.icon}>{icon}</div>}\n <h4 className={styles.title}>{title}</h4>\n {description && <p className={styles.description}>{description}</p>}\n {action && <div className={styles.action}>{action}</div>}\n </div>\n );\n}\n"],"mappings":"8GAaA,SAAgB,EAAW,CAAE,OAAM,QAAO,cAAa,SAAQ,aAA8B,CACzF,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EAA5C,SAAA,CACK,IAAQ,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAO,SAAA,CAAU,CAAA,GACjD,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,MAAQ,SAAA,CAAU,CAAA,EACvC,IAAe,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAA,QAAO,YAAc,SAAA,CAAe,CAAA,EACjE,IAAU,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,OAAS,SAAA,CAAY,CAAA,CACtD,GAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"EmptyState.js","names":[],"sources":["../../../src/components/EmptyState/EmptyState.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./EmptyState.module.css\";\n\nexport interface EmptyStateProps {\n icon?: ReactNode;\n title: ReactNode;\n description?: ReactNode;\n action?: ReactNode;\n className?: string;\n}\n\n/** Centered \"nothing here yet\" placeholder with optional icon and CTA. */\nexport function EmptyState({ icon, title, description, action, className }: EmptyStateProps) {\n return (\n <div className={cn(styles.wrapper, className)}>\n {icon && <div className={styles.icon}>{icon}</div>}\n <h4 className={styles.title}>{title}</h4>\n {description && <p className={styles.description}>{description}</p>}\n {action && <div className={styles.action}>{action}</div>}\n </div>\n );\n}\n"],"mappings":";;;;AAaA,SAAgB,EAAW,EAAE,SAAM,UAAO,gBAAa,WAAQ,gBAA8B;CACzF,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAS;YAA5C;GACK,KAAQ,kBAAC,OAAD;IAAK,WAAW,EAAO;cAAO;GAAU,CAAA;GACjD,kBAAC,MAAD;IAAI,WAAW,EAAO;cAAQ;GAAU,CAAA;GACvC,KAAe,kBAAC,KAAD;IAAG,WAAW,EAAO;cAAc;GAAe,CAAA;GACjE,KAAU,kBAAC,OAAD;IAAK,WAAW,EAAO;cAAS;GAAY,CAAA;EACtD;;AAEb"}
1
+ {"version":3,"file":"EmptyState.js","names":[],"sources":["../../../src/components/EmptyState/EmptyState.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./EmptyState.module.css\";\n\nexport interface EmptyStateProps {\n icon?: ReactNode;\n title: ReactNode;\n description?: ReactNode;\n action?: ReactNode;\n className?: string;\n}\n\n/** Centered \"nothing here yet\" placeholder with optional icon and CTA. */\nexport function EmptyState({ icon, title, description, action, className }: EmptyStateProps) {\n return (\n <div className={cn(styles.wrapper, className)}>\n {icon && <div className={styles.icon}>{icon}</div>}\n <h4 className={styles.title}>{title}</h4>\n {description && <p className={styles.description}>{description}</p>}\n {action && <div className={styles.action}>{action}</div>}\n </div>\n );\n}\n"],"mappings":";;;;AAaA,SAAgB,EAAW,EAAE,SAAM,UAAO,gBAAa,WAAQ,gBAA8B;CACzF,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAS;EAA5C,UAAA;GACK,KAAQ,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAO,UAAA;GAAU,CAAA;GACjD,kBAAC,MAAD;IAAI,WAAW,EAAO;IAAQ,UAAA;GAAU,CAAA;GACvC,KAAe,kBAAC,KAAD;IAAG,WAAW,EAAO;IAAc,UAAA;GAAe,CAAA;GACjE,KAAU,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAS,UAAA;GAAY,CAAA;EACtD;;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorState.cjs","names":[],"sources":["../../../src/components/ErrorState/ErrorState.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Button } from \"@/components/Button\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./ErrorState.module.css\";\n\nexport interface ErrorStateProps {\n title?: ReactNode;\n description?: ReactNode;\n onRetry?: () => void;\n retryLabel?: string;\n icon?: ReactNode;\n className?: string;\n}\n\n/** Error placeholder with optional retry CTA. Use when a request fails. */\nexport function ErrorState({\n title = \"Algo deu errado\",\n description = \"Não foi possível carregar essas informações.\",\n onRetry,\n retryLabel = \"Tentar novamente\",\n icon,\n className,\n}: ErrorStateProps) {\n return (\n <div className={cn(styles.wrapper, className)}>\n <div className={styles.icon}>{icon ?? <AlertIcon />}</div>\n <h4 className={styles.title}>{title}</h4>\n {description && <p className={styles.description}>{description}</p>}\n {onRetry && (\n <div className={styles.action}>\n <Button variant=\"secondary\" onClick={onRetry}>\n {retryLabel}\n </Button>\n </div>\n )}\n </div>\n );\n}\n\nfunction AlertIcon() {\n return (\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"gJAeA,SAAgB,EAAW,CACvB,QAAQ,kBACR,cAAc,+CACd,UACA,aAAa,mBACb,OACA,aACgB,CAChB,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,WAA5C,EACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,cAAO,IAAQ,EAAA,EAAA,IAAA,CAAC,EAAD,CAAY,CAAA,CAAO,CAAA,GACzD,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,eAAQ,CAAU,CAAA,EACvC,IAAe,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAA,QAAO,qBAAc,CAAe,CAAA,EACjE,IACG,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,iBACnB,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CAAQ,QAAQ,YAAY,QAAS,WAChC,CACG,CAAA,CACP,CAAA,CAER,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,qGACF,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,OAClB,CAAA,CACA,CAAA,CAEb"}
1
+ {"version":3,"file":"ErrorState.cjs","names":[],"sources":["../../../src/components/ErrorState/ErrorState.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Button } from \"@/components/Button\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./ErrorState.module.css\";\n\nexport interface ErrorStateProps {\n title?: ReactNode;\n description?: ReactNode;\n onRetry?: () => void;\n retryLabel?: string;\n icon?: ReactNode;\n className?: string;\n}\n\n/** Error placeholder with optional retry CTA. Use when a request fails. */\nexport function ErrorState({\n title = \"Algo deu errado\",\n description = \"Não foi possível carregar essas informações.\",\n onRetry,\n retryLabel = \"Tentar novamente\",\n icon,\n className,\n}: ErrorStateProps) {\n return (\n <div className={cn(styles.wrapper, className)}>\n <div className={styles.icon}>{icon ?? <AlertIcon />}</div>\n <h4 className={styles.title}>{title}</h4>\n {description && <p className={styles.description}>{description}</p>}\n {onRetry && (\n <div className={styles.action}>\n <Button variant=\"secondary\" onClick={onRetry}>\n {retryLabel}\n </Button>\n </div>\n )}\n </div>\n );\n}\n\nfunction AlertIcon() {\n return (\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"gJAeA,SAAgB,EAAW,CACvB,QAAQ,kBACR,cAAc,+CACd,UACA,aAAa,mBACb,OACA,aACgB,CAChB,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EAA5C,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAO,SAAA,IAAQ,EAAA,EAAA,IAAA,CAAC,EAAD,CAAY,CAAA,CAAO,CAAA,GACzD,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,MAAQ,SAAA,CAAU,CAAA,EACvC,IAAe,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAA,QAAO,YAAc,SAAA,CAAe,CAAA,EACjE,IACG,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,OACnB,UAAA,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CAAQ,QAAQ,YAAY,QAAS,EAChC,SAAA,CACG,CAAA,CACP,CAAA,CAER,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,qGACF,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,OAClB,CAAA,CACA,CAAA,CAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorState.js","names":[],"sources":["../../../src/components/ErrorState/ErrorState.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Button } from \"@/components/Button\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./ErrorState.module.css\";\n\nexport interface ErrorStateProps {\n title?: ReactNode;\n description?: ReactNode;\n onRetry?: () => void;\n retryLabel?: string;\n icon?: ReactNode;\n className?: string;\n}\n\n/** Error placeholder with optional retry CTA. Use when a request fails. */\nexport function ErrorState({\n title = \"Algo deu errado\",\n description = \"Não foi possível carregar essas informações.\",\n onRetry,\n retryLabel = \"Tentar novamente\",\n icon,\n className,\n}: ErrorStateProps) {\n return (\n <div className={cn(styles.wrapper, className)}>\n <div className={styles.icon}>{icon ?? <AlertIcon />}</div>\n <h4 className={styles.title}>{title}</h4>\n {description && <p className={styles.description}>{description}</p>}\n {onRetry && (\n <div className={styles.action}>\n <Button variant=\"secondary\" onClick={onRetry}>\n {retryLabel}\n </Button>\n </div>\n )}\n </div>\n );\n}\n\nfunction AlertIcon() {\n return (\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":";;;;;AAeA,SAAgB,EAAW,EACvB,WAAQ,mBACR,iBAAc,gDACd,YACA,gBAAa,oBACb,SACA,gBACgB;CAChB,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAS;YAA5C;GACI,kBAAC,OAAD;IAAK,WAAW,EAAO;cAAO,KAAQ,kBAAC,GAAD,CAAY,CAAA;GAAO,CAAA;GACzD,kBAAC,MAAD;IAAI,WAAW,EAAO;cAAQ;GAAU,CAAA;GACvC,KAAe,kBAAC,KAAD;IAAG,WAAW,EAAO;cAAc;GAAe,CAAA;GACjE,KACG,kBAAC,OAAD;IAAK,WAAW,EAAO;cACnB,kBAAC,GAAD;KAAQ,SAAQ;KAAY,SAAS;eAChC;IACG,CAAA;GACP,CAAA;EAER;;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;GACd,gBAAe;EAClB,CAAA;CACA,CAAA;AAEb"}
1
+ {"version":3,"file":"ErrorState.js","names":[],"sources":["../../../src/components/ErrorState/ErrorState.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Button } from \"@/components/Button\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./ErrorState.module.css\";\n\nexport interface ErrorStateProps {\n title?: ReactNode;\n description?: ReactNode;\n onRetry?: () => void;\n retryLabel?: string;\n icon?: ReactNode;\n className?: string;\n}\n\n/** Error placeholder with optional retry CTA. Use when a request fails. */\nexport function ErrorState({\n title = \"Algo deu errado\",\n description = \"Não foi possível carregar essas informações.\",\n onRetry,\n retryLabel = \"Tentar novamente\",\n icon,\n className,\n}: ErrorStateProps) {\n return (\n <div className={cn(styles.wrapper, className)}>\n <div className={styles.icon}>{icon ?? <AlertIcon />}</div>\n <h4 className={styles.title}>{title}</h4>\n {description && <p className={styles.description}>{description}</p>}\n {onRetry && (\n <div className={styles.action}>\n <Button variant=\"secondary\" onClick={onRetry}>\n {retryLabel}\n </Button>\n </div>\n )}\n </div>\n );\n}\n\nfunction AlertIcon() {\n return (\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":";;;;;AAeA,SAAgB,EAAW,EACvB,WAAQ,mBACR,iBAAc,gDACd,YACA,gBAAa,oBACb,SACA,gBACgB;CAChB,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAS;EAA5C,UAAA;GACI,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAO,UAAA,KAAQ,kBAAC,GAAD,CAAY,CAAA;GAAO,CAAA;GACzD,kBAAC,MAAD;IAAI,WAAW,EAAO;IAAQ,UAAA;GAAU,CAAA;GACvC,KAAe,kBAAC,KAAD;IAAG,WAAW,EAAO;IAAc,UAAA;GAAe,CAAA;GACjE,KACG,kBAAC,OAAD;IAAK,WAAW,EAAO;IACnB,UAAA,kBAAC,GAAD;KAAQ,SAAQ;KAAY,SAAS;KAChC,UAAA;IACG,CAAA;GACP,CAAA;EAER;;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;GACd,gBAAe;EAClB,CAAA;CACA,CAAA;AAEb"}
@@ -1,2 +1,2 @@
1
- const e=require("../../utils/cn.cjs"),t=require("./FileUpload.module.cjs");let n=require("react"),r=require("react/jsx-runtime");function i(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(1)} MB`}function a(e,t){if(!t)return!0;let n=t.split(`,`).map(e=>e.trim().toLowerCase()),r=e.name.toLowerCase(),i=e.type.toLowerCase();return n.some(e=>e.startsWith(`.`)?r.endsWith(e):e.endsWith(`/*`)?i.startsWith(e.replace(`/*`,`/`)):i===e)}function o({value:o,onChange:c,label:l,accept:u,multiple:d=!1,maxSize:f,onReject:p,disabled:m,title:h=`Arraste arquivos aqui ou clique para selecionar`,subtitle:g,className:_}){let[v,y]=(0,n.useState)(!1),b=(0,n.useRef)(null);function x(e){let t=[],n=[];for(let r of Array.from(e)){if(!a(r,u)){n.push({file:r,reason:`type`});continue}if(f&&r.size>f){n.push({file:r,reason:`size`});continue}t.push(r)}n.length>0&&p?.(n),t.length!==0&&c(d?[...o,...t]:t.slice(0,1))}function S(e){e.preventDefault(),y(!1),!m&&e.dataTransfer?.files&&x(e.dataTransfer.files)}function C(e){let t=o.slice();t.splice(e,1),c(t)}return(0,r.jsxs)(`div`,{className:e.cn(t.default.wrapper,_),children:[l&&(0,r.jsx)(`label`,{className:t.default.label,children:l}),(0,r.jsxs)(`div`,{className:e.cn(t.default.dropzone,v&&t.default.active,m&&t.default.disabled),role:`button`,tabIndex:m?-1:0,onClick:()=>!m&&b.current?.click(),onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),b.current?.click())},onDragEnter:e=>{e.preventDefault(),m||y(!0)},onDragOver:e=>e.preventDefault(),onDragLeave:()=>y(!1),onDrop:S,children:[(0,r.jsx)(`div`,{className:t.default.icon,"aria-hidden":!0,children:(0,r.jsx)(s,{})}),(0,r.jsx)(`p`,{className:t.default.title,children:h}),g&&(0,r.jsx)(`p`,{className:t.default.subtitle,children:g}),(0,r.jsx)(`input`,{ref:b,type:`file`,accept:u,multiple:d,disabled:m,className:t.default.hidden,onChange:e=>{e.target.files&&x(e.target.files),e.target.value=``}})]}),o.length>0&&(0,r.jsx)(`ul`,{className:t.default.files,children:o.map((e,n)=>(0,r.jsxs)(`li`,{className:t.default.file,children:[(0,r.jsxs)(`div`,{children:[(0,r.jsx)(`div`,{children:e.name}),(0,r.jsx)(`div`,{className:t.default.fileMeta,children:i(e.size)})]}),(0,r.jsx)(`button`,{type:`button`,"aria-label":`Remover ${e.name}`,className:t.default.remove,onClick:()=>C(n),children:`×`})]},`${e.name}-${n}`))})]})}function s(){return(0,r.jsx)(`svg`,{width:`32`,height:`32`,viewBox:`0 0 24 24`,fill:`none`,children:(0,r.jsx)(`path`,{d:`M12 16V4m0 0l-4 4m4-4l4 4M4 20h16`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})})}exports.FileUpload=o;
1
+ const e=require("../../utils/cn.cjs"),t=require("./FileUpload.module.cjs");let n=require("react"),r=require("react/jsx-runtime");function i(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(1)} MB`}function a(e,t){if(!t)return!0;let n=t.split(`,`).map(e=>e.trim().toLowerCase()),r=e.name.toLowerCase(),i=e.type.toLowerCase();return n.some(e=>e.startsWith(`.`)?r.endsWith(e):e.endsWith(`/*`)?i.startsWith(e.replace(`/*`,`/`)):i===e)}function o({value:o,onChange:c,label:l,accept:u,multiple:d=!1,maxSize:f,onReject:p,disabled:m,title:h=`Arraste arquivos aqui ou clique para selecionar`,subtitle:g,className:_}){let[v,y]=(0,n.useState)(!1),b=(0,n.useRef)(null);function x(e){let t=[],n=[];for(let r of Array.from(e)){if(!a(r,u)){n.push({file:r,reason:`type`});continue}if(f&&r.size>f){n.push({file:r,reason:`size`});continue}t.push(r)}n.length>0&&p?.(n),t.length!==0&&c(d?[...o,...t]:t.slice(0,1))}function S(e){e.preventDefault(),y(!1),!m&&e.dataTransfer?.files&&x(e.dataTransfer.files)}function C(e){let t=o.slice();t.splice(e,1),c(t)}return(0,r.jsxs)(`div`,{className:e.cn(t.default.wrapper,_),children:[l&&(0,r.jsx)(`label`,{className:t.default.label,children:l}),(0,r.jsxs)(`div`,{className:e.cn(t.default.dropzone,v&&t.default.active,m&&t.default.disabled),role:`button`,tabIndex:m?-1:0,onClick:()=>!m&&b.current?.click(),onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),b.current?.click())},onDragEnter:e=>{e.preventDefault(),m||y(!0)},onDragOver:e=>e.preventDefault(),onDragLeave:()=>y(!1),onDrop:S,children:[(0,r.jsx)(`div`,{className:t.default.icon,"aria-hidden":!0,children:(0,r.jsx)(s,{})}),(0,r.jsx)(`p`,{className:t.default.title,children:h}),g&&(0,r.jsx)(`p`,{className:t.default.subtitle,children:g}),(0,r.jsx)(`input`,{ref:b,type:`file`,accept:u,multiple:d,disabled:m,className:t.default.hidden,onChange:e=>{e.target.files&&x(e.target.files),e.target.value=``}})]}),o.length>0&&(0,r.jsx)(`ul`,{className:t.default.files,children:o.map((e,n)=>(0,r.jsxs)(`li`,{className:t.default.file,children:[(0,r.jsxs)(`div`,{children:[(0,r.jsx)(`div`,{children:e.name}),(0,r.jsx)(`div`,{className:t.default.fileMeta,children:i(e.size)})]}),(0,r.jsx)(`button`,{type:`button`,"aria-label":`Remover ${e.name}`,className:t.default.remove,onClick:()=>C(n),children:`×`})]},`${e.name}-${n}`))})]})}function s(){return(0,r.jsx)(`svg`,{width:`32`,height:`32`,viewBox:`0 0 24 24`,fill:`none`,children:(0,r.jsx)(`path`,{d:`M12 16V4m0 0l-4 4m4-4l4 4M4 20h16`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})})}exports.FileUpload=o;
2
2
  //# sourceMappingURL=FileUpload.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"FileUpload.cjs","names":[],"sources":["../../../src/components/FileUpload/FileUpload.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the picker (accept,\n * multiple, maxSize, onReject) and the list of chosen files (value, onChange,\n * disabled) are one control, and title/subtitle/label exist because the empty state\n * is the biggest part of the surface.\n */\nimport { useRef, useState } from \"react\";\nimport type { DragEvent } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./FileUpload.module.css\";\n\nexport interface FileUploadProps {\n /** Files currently in the dropzone (controlled). */\n value: File[];\n /** Called with the new list when the user adds or removes a file. */\n onChange: (files: File[]) => void;\n label?: string;\n /** Accept attribute forwarded to `<input>`. */\n accept?: string;\n /** Allow multiple files. Default: false. */\n multiple?: boolean;\n /** Max file size in bytes. Files above are rejected via `onReject`. */\n maxSize?: number;\n /** Called with rejected files when they exceed `maxSize` or fail the `accept` filter. */\n onReject?: (rejected: { file: File; reason: \"size\" | \"type\" }[]) => void;\n disabled?: boolean;\n /** Title shown on the empty dropzone. */\n title?: string;\n /** Helper line below the title. */\n subtitle?: string;\n className?: string;\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / 1024 / 1024).toFixed(1)} MB`;\n}\n\nfunction matchesAccept(file: File, accept?: string): boolean {\n if (!accept) return true;\n const tokens = accept.split(\",\").map((t) => t.trim().toLowerCase());\n const name = file.name.toLowerCase();\n const type = file.type.toLowerCase();\n return tokens.some((token) => {\n if (token.startsWith(\".\")) return name.endsWith(token);\n if (token.endsWith(\"/*\")) return type.startsWith(token.replace(\"/*\", \"/\"));\n return type === token;\n });\n}\n\n/**\n * Drag-and-drop file dropzone. Pair with `uploadWithProgress` from the SDK\n * to wire actual uploads with byte-level progress.\n */\nexport function FileUpload({\n value,\n onChange,\n label,\n accept,\n multiple = false,\n maxSize,\n onReject,\n disabled,\n title = \"Arraste arquivos aqui ou clique para selecionar\",\n subtitle,\n className,\n}: FileUploadProps) {\n const [dragging, setDragging] = useState<boolean>(false);\n const inputRef = useRef<HTMLInputElement>(null);\n\n function addFiles(incoming: FileList | File[]): void {\n const accepted: File[] = [];\n const rejected: { file: File; reason: \"size\" | \"type\" }[] = [];\n\n for (const file of Array.from(incoming)) {\n if (!matchesAccept(file, accept)) {\n rejected.push({ file, reason: \"type\" });\n continue;\n }\n if (maxSize && file.size > maxSize) {\n rejected.push({ file, reason: \"size\" });\n continue;\n }\n accepted.push(file);\n }\n\n if (rejected.length > 0) onReject?.(rejected);\n if (accepted.length === 0) return;\n\n const next = multiple ? [...value, ...accepted] : accepted.slice(0, 1);\n onChange(next);\n }\n\n function handleDrop(event: DragEvent<HTMLDivElement>): void {\n event.preventDefault();\n setDragging(false);\n if (disabled) return;\n if (event.dataTransfer?.files) addFiles(event.dataTransfer.files);\n }\n\n function remove(index: number): void {\n const next = value.slice();\n next.splice(index, 1);\n onChange(next);\n }\n\n return (\n <div className={cn(styles.wrapper, className)}>\n {label && <label className={styles.label}>{label}</label>}\n <div\n className={cn(\n styles.dropzone,\n dragging && styles.active,\n disabled && styles.disabled,\n )}\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n onClick={() => !disabled && inputRef.current?.click()}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n inputRef.current?.click();\n }\n }}\n onDragEnter={(event) => {\n event.preventDefault();\n if (!disabled) setDragging(true);\n }}\n onDragOver={(event) => event.preventDefault()}\n onDragLeave={() => setDragging(false)}\n onDrop={handleDrop}\n >\n <div className={styles.icon} aria-hidden>\n <UploadIcon />\n </div>\n <p className={styles.title}>{title}</p>\n {subtitle && <p className={styles.subtitle}>{subtitle}</p>}\n <input\n ref={inputRef}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n disabled={disabled}\n className={styles.hidden}\n onChange={(event) => {\n if (event.target.files) addFiles(event.target.files);\n event.target.value = \"\";\n }}\n />\n </div>\n\n {value.length > 0 && (\n <ul className={styles.files}>\n {value.map((file, index) => (\n <li key={`${file.name}-${index}`} className={styles.file}>\n <div>\n <div>{file.name}</div>\n <div className={styles.fileMeta}>{formatSize(file.size)}</div>\n </div>\n <button\n type=\"button\"\n aria-label={`Remover ${file.name}`}\n className={styles.remove}\n onClick={() => remove(index)}\n >\n ×\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n\nfunction UploadIcon() {\n return (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M12 16V4m0 0l-4 4m4-4l4 4M4 20h16\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"FileUpload.cjs","names":[],"sources":["../../../src/components/FileUpload/FileUpload.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the picker (accept,\n * multiple, maxSize, onReject) and the list of chosen files (value, onChange,\n * disabled) are one control, and title/subtitle/label exist because the empty state\n * is the biggest part of the surface.\n */\nimport { useRef, useState } from \"react\";\nimport type { DragEvent } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./FileUpload.module.css\";\n\nexport interface FileUploadProps {\n /** Files currently in the dropzone (controlled). */\n value: File[];\n /** Called with the new list when the user adds or removes a file. */\n onChange: (files: File[]) => void;\n label?: string;\n /** Accept attribute forwarded to `<input>`. */\n accept?: string;\n /** Allow multiple files. Default: false. */\n multiple?: boolean;\n /** Max file size in bytes. Files above are rejected via `onReject`. */\n maxSize?: number;\n /** Called with rejected files when they exceed `maxSize` or fail the `accept` filter. */\n onReject?: (rejected: { file: File; reason: \"size\" | \"type\" }[]) => void;\n disabled?: boolean;\n /** Title shown on the empty dropzone. */\n title?: string;\n /** Helper line below the title. */\n subtitle?: string;\n className?: string;\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / 1024 / 1024).toFixed(1)} MB`;\n}\n\nfunction matchesAccept(file: File, accept?: string): boolean {\n if (!accept) return true;\n const tokens = accept.split(\",\").map((t) => t.trim().toLowerCase());\n const name = file.name.toLowerCase();\n const type = file.type.toLowerCase();\n return tokens.some((token) => {\n if (token.startsWith(\".\")) return name.endsWith(token);\n if (token.endsWith(\"/*\")) return type.startsWith(token.replace(\"/*\", \"/\"));\n return type === token;\n });\n}\n\n/**\n * Drag-and-drop file dropzone. Pair with `uploadWithProgress` from the SDK\n * to wire actual uploads with byte-level progress.\n */\nexport function FileUpload({\n value,\n onChange,\n label,\n accept,\n multiple = false,\n maxSize,\n onReject,\n disabled,\n title = \"Arraste arquivos aqui ou clique para selecionar\",\n subtitle,\n className,\n}: FileUploadProps) {\n const [dragging, setDragging] = useState<boolean>(false);\n const inputRef = useRef<HTMLInputElement>(null);\n\n function addFiles(incoming: FileList | File[]): void {\n const accepted: File[] = [];\n const rejected: { file: File; reason: \"size\" | \"type\" }[] = [];\n\n for (const file of Array.from(incoming)) {\n if (!matchesAccept(file, accept)) {\n rejected.push({ file, reason: \"type\" });\n continue;\n }\n if (maxSize && file.size > maxSize) {\n rejected.push({ file, reason: \"size\" });\n continue;\n }\n accepted.push(file);\n }\n\n if (rejected.length > 0) onReject?.(rejected);\n if (accepted.length === 0) return;\n\n const next = multiple ? [...value, ...accepted] : accepted.slice(0, 1);\n onChange(next);\n }\n\n function handleDrop(event: DragEvent<HTMLDivElement>): void {\n event.preventDefault();\n setDragging(false);\n if (disabled) return;\n if (event.dataTransfer?.files) addFiles(event.dataTransfer.files);\n }\n\n function remove(index: number): void {\n const next = value.slice();\n next.splice(index, 1);\n onChange(next);\n }\n\n return (\n <div className={cn(styles.wrapper, className)}>\n {label && <label className={styles.label}>{label}</label>}\n <div\n className={cn(\n styles.dropzone,\n dragging && styles.active,\n disabled && styles.disabled,\n )}\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n onClick={() => !disabled && inputRef.current?.click()}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n inputRef.current?.click();\n }\n }}\n onDragEnter={(event) => {\n event.preventDefault();\n if (!disabled) setDragging(true);\n }}\n onDragOver={(event) => event.preventDefault()}\n onDragLeave={() => setDragging(false)}\n onDrop={handleDrop}\n >\n <div className={styles.icon} aria-hidden>\n <UploadIcon />\n </div>\n <p className={styles.title}>{title}</p>\n {subtitle && <p className={styles.subtitle}>{subtitle}</p>}\n <input\n ref={inputRef}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n disabled={disabled}\n className={styles.hidden}\n onChange={(event) => {\n if (event.target.files) addFiles(event.target.files);\n event.target.value = \"\";\n }}\n />\n </div>\n\n {value.length > 0 && (\n <ul className={styles.files}>\n {value.map((file, index) => (\n <li key={`${file.name}-${index}`} className={styles.file}>\n <div>\n <div>{file.name}</div>\n <div className={styles.fileMeta}>{formatSize(file.size)}</div>\n </div>\n <button\n type=\"button\"\n aria-label={`Remover ${file.name}`}\n className={styles.remove}\n onClick={() => remove(index)}\n >\n ×\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n\nfunction UploadIcon() {\n return (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M12 16V4m0 0l-4 4m4-4l4 4M4 20h16\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"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"}
@@ -4,7 +4,7 @@ import { useRef as n, useState as r } from "react";
4
4
  import { jsx as i, jsxs as a } from "react/jsx-runtime";
5
5
  //#region src/components/FileUpload/FileUpload.tsx
6
6
  function o(e) {
7
- return e < 1024 ? `${e} B` : e < 1024 * 1024 ? `${(e / 1024).toFixed(1)} KB` : `${(e / 1024 / 1024).toFixed(1)} MB`;
7
+ return e < 1024 ? `${e} B` : e < 1048576 ? `${(e / 1024).toFixed(1)} KB` : `${(e / 1024 / 1024).toFixed(1)} MB`;
8
8
  }
9
9
  function s(e, t) {
10
10
  if (!t) return !0;
@@ -1 +1 @@
1
- {"version":3,"file":"FileUpload.js","names":[],"sources":["../../../src/components/FileUpload/FileUpload.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the picker (accept,\n * multiple, maxSize, onReject) and the list of chosen files (value, onChange,\n * disabled) are one control, and title/subtitle/label exist because the empty state\n * is the biggest part of the surface.\n */\nimport { useRef, useState } from \"react\";\nimport type { DragEvent } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./FileUpload.module.css\";\n\nexport interface FileUploadProps {\n /** Files currently in the dropzone (controlled). */\n value: File[];\n /** Called with the new list when the user adds or removes a file. */\n onChange: (files: File[]) => void;\n label?: string;\n /** Accept attribute forwarded to `<input>`. */\n accept?: string;\n /** Allow multiple files. Default: false. */\n multiple?: boolean;\n /** Max file size in bytes. Files above are rejected via `onReject`. */\n maxSize?: number;\n /** Called with rejected files when they exceed `maxSize` or fail the `accept` filter. */\n onReject?: (rejected: { file: File; reason: \"size\" | \"type\" }[]) => void;\n disabled?: boolean;\n /** Title shown on the empty dropzone. */\n title?: string;\n /** Helper line below the title. */\n subtitle?: string;\n className?: string;\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / 1024 / 1024).toFixed(1)} MB`;\n}\n\nfunction matchesAccept(file: File, accept?: string): boolean {\n if (!accept) return true;\n const tokens = accept.split(\",\").map((t) => t.trim().toLowerCase());\n const name = file.name.toLowerCase();\n const type = file.type.toLowerCase();\n return tokens.some((token) => {\n if (token.startsWith(\".\")) return name.endsWith(token);\n if (token.endsWith(\"/*\")) return type.startsWith(token.replace(\"/*\", \"/\"));\n return type === token;\n });\n}\n\n/**\n * Drag-and-drop file dropzone. Pair with `uploadWithProgress` from the SDK\n * to wire actual uploads with byte-level progress.\n */\nexport function FileUpload({\n value,\n onChange,\n label,\n accept,\n multiple = false,\n maxSize,\n onReject,\n disabled,\n title = \"Arraste arquivos aqui ou clique para selecionar\",\n subtitle,\n className,\n}: FileUploadProps) {\n const [dragging, setDragging] = useState<boolean>(false);\n const inputRef = useRef<HTMLInputElement>(null);\n\n function addFiles(incoming: FileList | File[]): void {\n const accepted: File[] = [];\n const rejected: { file: File; reason: \"size\" | \"type\" }[] = [];\n\n for (const file of Array.from(incoming)) {\n if (!matchesAccept(file, accept)) {\n rejected.push({ file, reason: \"type\" });\n continue;\n }\n if (maxSize && file.size > maxSize) {\n rejected.push({ file, reason: \"size\" });\n continue;\n }\n accepted.push(file);\n }\n\n if (rejected.length > 0) onReject?.(rejected);\n if (accepted.length === 0) return;\n\n const next = multiple ? [...value, ...accepted] : accepted.slice(0, 1);\n onChange(next);\n }\n\n function handleDrop(event: DragEvent<HTMLDivElement>): void {\n event.preventDefault();\n setDragging(false);\n if (disabled) return;\n if (event.dataTransfer?.files) addFiles(event.dataTransfer.files);\n }\n\n function remove(index: number): void {\n const next = value.slice();\n next.splice(index, 1);\n onChange(next);\n }\n\n return (\n <div className={cn(styles.wrapper, className)}>\n {label && <label className={styles.label}>{label}</label>}\n <div\n className={cn(\n styles.dropzone,\n dragging && styles.active,\n disabled && styles.disabled,\n )}\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n onClick={() => !disabled && inputRef.current?.click()}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n inputRef.current?.click();\n }\n }}\n onDragEnter={(event) => {\n event.preventDefault();\n if (!disabled) setDragging(true);\n }}\n onDragOver={(event) => event.preventDefault()}\n onDragLeave={() => setDragging(false)}\n onDrop={handleDrop}\n >\n <div className={styles.icon} aria-hidden>\n <UploadIcon />\n </div>\n <p className={styles.title}>{title}</p>\n {subtitle && <p className={styles.subtitle}>{subtitle}</p>}\n <input\n ref={inputRef}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n disabled={disabled}\n className={styles.hidden}\n onChange={(event) => {\n if (event.target.files) addFiles(event.target.files);\n event.target.value = \"\";\n }}\n />\n </div>\n\n {value.length > 0 && (\n <ul className={styles.files}>\n {value.map((file, index) => (\n <li key={`${file.name}-${index}`} className={styles.file}>\n <div>\n <div>{file.name}</div>\n <div className={styles.fileMeta}>{formatSize(file.size)}</div>\n </div>\n <button\n type=\"button\"\n aria-label={`Remover ${file.name}`}\n className={styles.remove}\n onClick={() => remove(index)}\n >\n ×\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n\nfunction UploadIcon() {\n return (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M12 16V4m0 0l-4 4m4-4l4 4M4 20h16\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"FileUpload.js","names":[],"sources":["../../../src/components/FileUpload/FileUpload.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the picker (accept,\n * multiple, maxSize, onReject) and the list of chosen files (value, onChange,\n * disabled) are one control, and title/subtitle/label exist because the empty state\n * is the biggest part of the surface.\n */\nimport { useRef, useState } from \"react\";\nimport type { DragEvent } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./FileUpload.module.css\";\n\nexport interface FileUploadProps {\n /** Files currently in the dropzone (controlled). */\n value: File[];\n /** Called with the new list when the user adds or removes a file. */\n onChange: (files: File[]) => void;\n label?: string;\n /** Accept attribute forwarded to `<input>`. */\n accept?: string;\n /** Allow multiple files. Default: false. */\n multiple?: boolean;\n /** Max file size in bytes. Files above are rejected via `onReject`. */\n maxSize?: number;\n /** Called with rejected files when they exceed `maxSize` or fail the `accept` filter. */\n onReject?: (rejected: { file: File; reason: \"size\" | \"type\" }[]) => void;\n disabled?: boolean;\n /** Title shown on the empty dropzone. */\n title?: string;\n /** Helper line below the title. */\n subtitle?: string;\n className?: string;\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / 1024 / 1024).toFixed(1)} MB`;\n}\n\nfunction matchesAccept(file: File, accept?: string): boolean {\n if (!accept) return true;\n const tokens = accept.split(\",\").map((t) => t.trim().toLowerCase());\n const name = file.name.toLowerCase();\n const type = file.type.toLowerCase();\n return tokens.some((token) => {\n if (token.startsWith(\".\")) return name.endsWith(token);\n if (token.endsWith(\"/*\")) return type.startsWith(token.replace(\"/*\", \"/\"));\n return type === token;\n });\n}\n\n/**\n * Drag-and-drop file dropzone. Pair with `uploadWithProgress` from the SDK\n * to wire actual uploads with byte-level progress.\n */\nexport function FileUpload({\n value,\n onChange,\n label,\n accept,\n multiple = false,\n maxSize,\n onReject,\n disabled,\n title = \"Arraste arquivos aqui ou clique para selecionar\",\n subtitle,\n className,\n}: FileUploadProps) {\n const [dragging, setDragging] = useState<boolean>(false);\n const inputRef = useRef<HTMLInputElement>(null);\n\n function addFiles(incoming: FileList | File[]): void {\n const accepted: File[] = [];\n const rejected: { file: File; reason: \"size\" | \"type\" }[] = [];\n\n for (const file of Array.from(incoming)) {\n if (!matchesAccept(file, accept)) {\n rejected.push({ file, reason: \"type\" });\n continue;\n }\n if (maxSize && file.size > maxSize) {\n rejected.push({ file, reason: \"size\" });\n continue;\n }\n accepted.push(file);\n }\n\n if (rejected.length > 0) onReject?.(rejected);\n if (accepted.length === 0) return;\n\n const next = multiple ? [...value, ...accepted] : accepted.slice(0, 1);\n onChange(next);\n }\n\n function handleDrop(event: DragEvent<HTMLDivElement>): void {\n event.preventDefault();\n setDragging(false);\n if (disabled) return;\n if (event.dataTransfer?.files) addFiles(event.dataTransfer.files);\n }\n\n function remove(index: number): void {\n const next = value.slice();\n next.splice(index, 1);\n onChange(next);\n }\n\n return (\n <div className={cn(styles.wrapper, className)}>\n {label && <label className={styles.label}>{label}</label>}\n <div\n className={cn(\n styles.dropzone,\n dragging && styles.active,\n disabled && styles.disabled,\n )}\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n onClick={() => !disabled && inputRef.current?.click()}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n inputRef.current?.click();\n }\n }}\n onDragEnter={(event) => {\n event.preventDefault();\n if (!disabled) setDragging(true);\n }}\n onDragOver={(event) => event.preventDefault()}\n onDragLeave={() => setDragging(false)}\n onDrop={handleDrop}\n >\n <div className={styles.icon} aria-hidden>\n <UploadIcon />\n </div>\n <p className={styles.title}>{title}</p>\n {subtitle && <p className={styles.subtitle}>{subtitle}</p>}\n <input\n ref={inputRef}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n disabled={disabled}\n className={styles.hidden}\n onChange={(event) => {\n if (event.target.files) addFiles(event.target.files);\n event.target.value = \"\";\n }}\n />\n </div>\n\n {value.length > 0 && (\n <ul className={styles.files}>\n {value.map((file, index) => (\n <li key={`${file.name}-${index}`} className={styles.file}>\n <div>\n <div>{file.name}</div>\n <div className={styles.fileMeta}>{formatSize(file.size)}</div>\n </div>\n <button\n type=\"button\"\n aria-label={`Remover ${file.name}`}\n className={styles.remove}\n onClick={() => remove(index)}\n >\n ×\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n\nfunction UploadIcon() {\n return (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M12 16V4m0 0l-4 4m4-4l4 4M4 20h16\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"FilterBar.cjs","names":[],"sources":["../../../src/components/FilterBar/FilterBar.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, function-lines — a filter bar renders a different\n * editor per filter kind — select, multi-select, range, date range, text — and the\n * body is that dispatch plus the chip summary, both reading the same value map.\n */\nimport { useId, useState, type HTMLAttributes, type ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport {\n defaultOperator,\n describeFilter,\n filterStrings,\n isComplete,\n isMulti,\n isValueless,\n operatorLabel,\n operatorsFor,\n type Filter,\n type FilterField,\n} from \"./filter-model\";\nimport styles from \"./FilterBar.module.css\";\n\n/** DOM attributes this component redefines. */\ntype OverriddenDomProps = \"children\" | \"onChange\";\n\nexport interface FilterBarProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps> {\n /** Fields the user may filter by. */\n fields: readonly FilterField[];\n /** Applied filters. Controlled. */\n value: readonly Filter[];\n /** Next filter set. Combined with AND. */\n onChange: (filters: Filter[]) => void;\n /** Locale for the labels. Default `\"pt-BR\"`. */\n locale?: \"pt-BR\" | \"en\";\n /** Rendered at the end of the bar — a \"save this view\" button, a counter. */\n actions?: ReactNode;\n}\n\n/** The draft filter being built in the editor. */\ninterface Draft {\n field: string;\n operator: Filter[\"operator\"];\n value: string;\n to: string;\n}\n\n/** A fresh draft for a field. */\nfunction draftFor(field: FilterField): Draft {\n return { field: field.name, operator: defaultOperator(field), value: \"\", to: \"\" };\n}\n\n/** Turn a draft into a filter. */\nfunction toFilter(draft: Draft): Filter {\n if (isValueless(draft.operator)) return { field: draft.field, operator: draft.operator };\n if (draft.operator === \"between\") {\n return { field: draft.field, operator: draft.operator, value: [draft.value, draft.to] };\n }\n if (isMulti(draft.operator)) {\n return {\n field: draft.field,\n operator: draft.operator,\n value: draft.value\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean),\n };\n }\n return { field: draft.field, operator: draft.operator, value: draft.value };\n}\n\n/**\n * A row of applied filters, and a small editor to add another.\n *\n * Filters are combined with **AND**, flat — no nested `(a OR b) AND c` groups. That\n * is the shape of nearly every admin list (\"status is paid, created after March,\n * text contains nota\"), and it is what serializes into a URL somebody can send to a\n * colleague. Nested groups need a tree UI with per-node operators and a different\n * serialization; a component trying to be both is clumsy at the common case.\n *\n * Controlled, like the rest of the SDK: it holds the half-typed draft in the editor\n * and nothing else. The applied set is the app's, which is what lets it come from —\n * and go back into — the URL.\n *\n * @example\n * const [filters, setFilters] = useState<Filter[]>(() =>\n * filtersFromSearchParams(new URLSearchParams(location.search), FIELDS),\n * );\n *\n * <FilterBar fields={FIELDS} value={filters} onChange={setFilters} />\n */\nexport function FilterBar({\n fields,\n value,\n onChange,\n locale = \"pt-BR\",\n actions,\n className,\n ...rest\n}: FilterBarProps) {\n const strings = filterStrings(locale);\n const baseId = useId();\n const [draft, setDraft] = useState<Draft | null>(null);\n\n const field = draft ? fields.find((candidate) => candidate.name === draft.field) : undefined;\n const pending = draft ? toFilter(draft) : null;\n const ready = pending !== null && isComplete(pending);\n\n const open = (): void => {\n if (fields.length > 0) setDraft(draftFor(fields[0]));\n };\n\n const apply = (): void => {\n if (!pending || !ready) return;\n onChange([...value, pending]);\n setDraft(null);\n };\n\n const removeAt = (index: number): void => {\n onChange(value.filter((_, position) => position !== index));\n };\n\n return (\n <div className={cn(styles.bar, className)} {...rest}>\n <ul className={styles.chips}>\n {value.length === 0 && !draft && <li className={styles.empty}>{strings.empty}</li>}\n {value.map((filter, index) => {\n const description = describeFilter(filter, fields, locale);\n return (\n <li\n key={`${filter.field}-${filter.operator}-${index}`}\n className={styles.chip}\n >\n <span>{description}</span>\n <button\n type=\"button\"\n className={styles.remove}\n aria-label={strings.remove(description)}\n onClick={() => removeAt(index)}\n >\n ×\n </button>\n </li>\n );\n })}\n </ul>\n\n {draft && field ? (\n <div className={styles.editor} role=\"group\" aria-label={strings.add}>\n <label className={styles.control}>\n <VisuallyHidden>{strings.field}</VisuallyHidden>\n <select\n className={styles.select}\n value={draft.field}\n onChange={(event) => {\n const next = fields.find(\n (candidate) => candidate.name === event.target.value,\n );\n if (next) setDraft(draftFor(next));\n }}\n >\n {fields.map((candidate) => (\n <option key={candidate.name} value={candidate.name}>\n {candidate.label}\n </option>\n ))}\n </select>\n </label>\n\n <label className={styles.control}>\n <VisuallyHidden>{strings.operator}</VisuallyHidden>\n <select\n className={styles.select}\n value={draft.operator}\n onChange={(event) =>\n setDraft({\n ...draft,\n operator: event.target.value as Filter[\"operator\"],\n value: \"\",\n to: \"\",\n })\n }\n >\n {operatorsFor(field).map((operator) => (\n <option key={operator} value={operator}>\n {operatorLabel(operator, locale)}\n </option>\n ))}\n </select>\n </label>\n\n {!isValueless(draft.operator) && (\n <ValueInput\n id={`${baseId}-value`}\n field={field}\n draft={draft}\n strings={strings}\n onChange={setDraft}\n />\n )}\n\n <button\n type=\"button\"\n className={styles.primary}\n disabled={!ready}\n onClick={apply}\n >\n {strings.apply}\n </button>\n <button type=\"button\" className={styles.ghost} onClick={() => setDraft(null)}>\n {strings.cancel}\n </button>\n </div>\n ) : (\n <div className={styles.actions}>\n <button\n type=\"button\"\n className={styles.secondary}\n disabled={fields.length === 0}\n onClick={open}\n >\n + {strings.add}\n </button>\n {value.length > 0 && (\n <button type=\"button\" className={styles.ghost} onClick={() => onChange([])}>\n {strings.clear}\n </button>\n )}\n {actions}\n </div>\n )}\n\n <VisuallyHidden aria-live=\"polite\" role=\"status\">\n {strings.active(value.length)}\n </VisuallyHidden>\n </div>\n );\n}\n\n/**\n * The value input for the draft.\n *\n * The input type follows the **field**, not the operator: a date field gets a date\n * picker even under `between`, where two of them are needed. Typing a date into a\n * text box is the fastest way to produce a filter the backend cannot parse.\n */\nfunction ValueInput({\n id,\n field,\n draft,\n strings,\n onChange,\n}: {\n id: string;\n field: FilterField;\n draft: Draft;\n strings: ReturnType<typeof filterStrings>;\n onChange: (draft: Draft) => void;\n}) {\n const type = field.type === \"number\" ? \"number\" : field.type === \"date\" ? \"date\" : \"text\";\n\n if (field.type === \"select\" && !isMulti(draft.operator)) {\n return (\n <label className={styles.control}>\n <VisuallyHidden>{strings.value}</VisuallyHidden>\n <select\n id={id}\n className={styles.select}\n value={draft.value}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n >\n <option value=\"\">—</option>\n {field.options?.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </label>\n );\n }\n\n if (field.type === \"boolean\") {\n return (\n <label className={styles.control}>\n <VisuallyHidden>{strings.value}</VisuallyHidden>\n <select\n id={id}\n className={styles.select}\n value={draft.value}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n >\n <option value=\"\">—</option>\n <option value=\"true\">{strings.yes}</option>\n <option value=\"false\">{strings.no}</option>\n </select>\n </label>\n );\n }\n\n if (draft.operator === \"between\") {\n return (\n <>\n <label className={styles.control}>\n <VisuallyHidden>{strings.from}</VisuallyHidden>\n <input\n id={id}\n className={styles.input}\n type={type}\n value={draft.value}\n placeholder={strings.from}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n />\n </label>\n <label className={styles.control}>\n <VisuallyHidden>{strings.to}</VisuallyHidden>\n <input\n className={styles.input}\n type={type}\n value={draft.to}\n placeholder={strings.to}\n onChange={(event) => onChange({ ...draft, to: event.target.value })}\n />\n </label>\n </>\n );\n }\n\n return (\n <label className={styles.control}>\n <VisuallyHidden>{strings.value}</VisuallyHidden>\n <input\n id={id}\n className={styles.input}\n type={type}\n value={draft.value}\n placeholder={field.placeholder ?? strings.value}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n />\n </label>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"FilterBar.cjs","names":[],"sources":["../../../src/components/FilterBar/FilterBar.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, function-lines — a filter bar renders a different\n * editor per filter kind — select, multi-select, range, date range, text — and the\n * body is that dispatch plus the chip summary, both reading the same value map.\n */\nimport { useId, useState, type HTMLAttributes, type ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport {\n defaultOperator,\n describeFilter,\n filterStrings,\n isComplete,\n isMulti,\n isValueless,\n operatorLabel,\n operatorsFor,\n type Filter,\n type FilterField,\n} from \"./filter-model\";\nimport styles from \"./FilterBar.module.css\";\n\n/** DOM attributes this component redefines. */\ntype OverriddenDomProps = \"children\" | \"onChange\";\n\nexport interface FilterBarProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps> {\n /** Fields the user may filter by. */\n fields: readonly FilterField[];\n /** Applied filters. Controlled. */\n value: readonly Filter[];\n /** Next filter set. Combined with AND. */\n onChange: (filters: Filter[]) => void;\n /** Locale for the labels. Default `\"pt-BR\"`. */\n locale?: \"pt-BR\" | \"en\";\n /** Rendered at the end of the bar — a \"save this view\" button, a counter. */\n actions?: ReactNode;\n}\n\n/** The draft filter being built in the editor. */\ninterface Draft {\n field: string;\n operator: Filter[\"operator\"];\n value: string;\n to: string;\n}\n\n/** A fresh draft for a field. */\nfunction draftFor(field: FilterField): Draft {\n return { field: field.name, operator: defaultOperator(field), value: \"\", to: \"\" };\n}\n\n/** Turn a draft into a filter. */\nfunction toFilter(draft: Draft): Filter {\n if (isValueless(draft.operator)) return { field: draft.field, operator: draft.operator };\n if (draft.operator === \"between\") {\n return { field: draft.field, operator: draft.operator, value: [draft.value, draft.to] };\n }\n if (isMulti(draft.operator)) {\n return {\n field: draft.field,\n operator: draft.operator,\n value: draft.value\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean),\n };\n }\n return { field: draft.field, operator: draft.operator, value: draft.value };\n}\n\n/**\n * A row of applied filters, and a small editor to add another.\n *\n * Filters are combined with **AND**, flat — no nested `(a OR b) AND c` groups. That\n * is the shape of nearly every admin list (\"status is paid, created after March,\n * text contains nota\"), and it is what serializes into a URL somebody can send to a\n * colleague. Nested groups need a tree UI with per-node operators and a different\n * serialization; a component trying to be both is clumsy at the common case.\n *\n * Controlled, like the rest of the SDK: it holds the half-typed draft in the editor\n * and nothing else. The applied set is the app's, which is what lets it come from —\n * and go back into — the URL.\n *\n * @example\n * const [filters, setFilters] = useState<Filter[]>(() =>\n * filtersFromSearchParams(new URLSearchParams(location.search), FIELDS),\n * );\n *\n * <FilterBar fields={FIELDS} value={filters} onChange={setFilters} />\n */\nexport function FilterBar({\n fields,\n value,\n onChange,\n locale = \"pt-BR\",\n actions,\n className,\n ...rest\n}: FilterBarProps) {\n const strings = filterStrings(locale);\n const baseId = useId();\n const [draft, setDraft] = useState<Draft | null>(null);\n\n const field = draft ? fields.find((candidate) => candidate.name === draft.field) : undefined;\n const pending = draft ? toFilter(draft) : null;\n const ready = pending !== null && isComplete(pending);\n\n const open = (): void => {\n if (fields.length > 0) setDraft(draftFor(fields[0]));\n };\n\n const apply = (): void => {\n if (!pending || !ready) return;\n onChange([...value, pending]);\n setDraft(null);\n };\n\n const removeAt = (index: number): void => {\n onChange(value.filter((_, position) => position !== index));\n };\n\n return (\n <div className={cn(styles.bar, className)} {...rest}>\n <ul className={styles.chips}>\n {value.length === 0 && !draft && <li className={styles.empty}>{strings.empty}</li>}\n {value.map((filter, index) => {\n const description = describeFilter(filter, fields, locale);\n return (\n <li\n key={`${filter.field}-${filter.operator}-${index}`}\n className={styles.chip}\n >\n <span>{description}</span>\n <button\n type=\"button\"\n className={styles.remove}\n aria-label={strings.remove(description)}\n onClick={() => removeAt(index)}\n >\n ×\n </button>\n </li>\n );\n })}\n </ul>\n\n {draft && field ? (\n <div className={styles.editor} role=\"group\" aria-label={strings.add}>\n <label className={styles.control}>\n <VisuallyHidden>{strings.field}</VisuallyHidden>\n <select\n className={styles.select}\n value={draft.field}\n onChange={(event) => {\n const next = fields.find(\n (candidate) => candidate.name === event.target.value,\n );\n if (next) setDraft(draftFor(next));\n }}\n >\n {fields.map((candidate) => (\n <option key={candidate.name} value={candidate.name}>\n {candidate.label}\n </option>\n ))}\n </select>\n </label>\n\n <label className={styles.control}>\n <VisuallyHidden>{strings.operator}</VisuallyHidden>\n <select\n className={styles.select}\n value={draft.operator}\n onChange={(event) =>\n setDraft({\n ...draft,\n operator: event.target.value as Filter[\"operator\"],\n value: \"\",\n to: \"\",\n })\n }\n >\n {operatorsFor(field).map((operator) => (\n <option key={operator} value={operator}>\n {operatorLabel(operator, locale)}\n </option>\n ))}\n </select>\n </label>\n\n {!isValueless(draft.operator) && (\n <ValueInput\n id={`${baseId}-value`}\n field={field}\n draft={draft}\n strings={strings}\n onChange={setDraft}\n />\n )}\n\n <button\n type=\"button\"\n className={styles.primary}\n disabled={!ready}\n onClick={apply}\n >\n {strings.apply}\n </button>\n <button type=\"button\" className={styles.ghost} onClick={() => setDraft(null)}>\n {strings.cancel}\n </button>\n </div>\n ) : (\n <div className={styles.actions}>\n <button\n type=\"button\"\n className={styles.secondary}\n disabled={fields.length === 0}\n onClick={open}\n >\n + {strings.add}\n </button>\n {value.length > 0 && (\n <button type=\"button\" className={styles.ghost} onClick={() => onChange([])}>\n {strings.clear}\n </button>\n )}\n {actions}\n </div>\n )}\n\n <VisuallyHidden aria-live=\"polite\" role=\"status\">\n {strings.active(value.length)}\n </VisuallyHidden>\n </div>\n );\n}\n\n/**\n * The value input for the draft.\n *\n * The input type follows the **field**, not the operator: a date field gets a date\n * picker even under `between`, where two of them are needed. Typing a date into a\n * text box is the fastest way to produce a filter the backend cannot parse.\n */\nfunction ValueInput({\n id,\n field,\n draft,\n strings,\n onChange,\n}: {\n id: string;\n field: FilterField;\n draft: Draft;\n strings: ReturnType<typeof filterStrings>;\n onChange: (draft: Draft) => void;\n}) {\n const type = field.type === \"number\" ? \"number\" : field.type === \"date\" ? \"date\" : \"text\";\n\n if (field.type === \"select\" && !isMulti(draft.operator)) {\n return (\n <label className={styles.control}>\n <VisuallyHidden>{strings.value}</VisuallyHidden>\n <select\n id={id}\n className={styles.select}\n value={draft.value}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n >\n <option value=\"\">—</option>\n {field.options?.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </label>\n );\n }\n\n if (field.type === \"boolean\") {\n return (\n <label className={styles.control}>\n <VisuallyHidden>{strings.value}</VisuallyHidden>\n <select\n id={id}\n className={styles.select}\n value={draft.value}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n >\n <option value=\"\">—</option>\n <option value=\"true\">{strings.yes}</option>\n <option value=\"false\">{strings.no}</option>\n </select>\n </label>\n );\n }\n\n if (draft.operator === \"between\") {\n return (\n <>\n <label className={styles.control}>\n <VisuallyHidden>{strings.from}</VisuallyHidden>\n <input\n id={id}\n className={styles.input}\n type={type}\n value={draft.value}\n placeholder={strings.from}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n />\n </label>\n <label className={styles.control}>\n <VisuallyHidden>{strings.to}</VisuallyHidden>\n <input\n className={styles.input}\n type={type}\n value={draft.to}\n placeholder={strings.to}\n onChange={(event) => onChange({ ...draft, to: event.target.value })}\n />\n </label>\n </>\n );\n }\n\n return (\n <label className={styles.control}>\n <VisuallyHidden>{strings.value}</VisuallyHidden>\n <input\n id={id}\n className={styles.input}\n type={type}\n value={draft.value}\n placeholder={field.placeholder ?? strings.value}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n />\n </label>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"FilterBar.js","names":[],"sources":["../../../src/components/FilterBar/FilterBar.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, function-lines — a filter bar renders a different\n * editor per filter kind — select, multi-select, range, date range, text — and the\n * body is that dispatch plus the chip summary, both reading the same value map.\n */\nimport { useId, useState, type HTMLAttributes, type ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport {\n defaultOperator,\n describeFilter,\n filterStrings,\n isComplete,\n isMulti,\n isValueless,\n operatorLabel,\n operatorsFor,\n type Filter,\n type FilterField,\n} from \"./filter-model\";\nimport styles from \"./FilterBar.module.css\";\n\n/** DOM attributes this component redefines. */\ntype OverriddenDomProps = \"children\" | \"onChange\";\n\nexport interface FilterBarProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps> {\n /** Fields the user may filter by. */\n fields: readonly FilterField[];\n /** Applied filters. Controlled. */\n value: readonly Filter[];\n /** Next filter set. Combined with AND. */\n onChange: (filters: Filter[]) => void;\n /** Locale for the labels. Default `\"pt-BR\"`. */\n locale?: \"pt-BR\" | \"en\";\n /** Rendered at the end of the bar — a \"save this view\" button, a counter. */\n actions?: ReactNode;\n}\n\n/** The draft filter being built in the editor. */\ninterface Draft {\n field: string;\n operator: Filter[\"operator\"];\n value: string;\n to: string;\n}\n\n/** A fresh draft for a field. */\nfunction draftFor(field: FilterField): Draft {\n return { field: field.name, operator: defaultOperator(field), value: \"\", to: \"\" };\n}\n\n/** Turn a draft into a filter. */\nfunction toFilter(draft: Draft): Filter {\n if (isValueless(draft.operator)) return { field: draft.field, operator: draft.operator };\n if (draft.operator === \"between\") {\n return { field: draft.field, operator: draft.operator, value: [draft.value, draft.to] };\n }\n if (isMulti(draft.operator)) {\n return {\n field: draft.field,\n operator: draft.operator,\n value: draft.value\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean),\n };\n }\n return { field: draft.field, operator: draft.operator, value: draft.value };\n}\n\n/**\n * A row of applied filters, and a small editor to add another.\n *\n * Filters are combined with **AND**, flat — no nested `(a OR b) AND c` groups. That\n * is the shape of nearly every admin list (\"status is paid, created after March,\n * text contains nota\"), and it is what serializes into a URL somebody can send to a\n * colleague. Nested groups need a tree UI with per-node operators and a different\n * serialization; a component trying to be both is clumsy at the common case.\n *\n * Controlled, like the rest of the SDK: it holds the half-typed draft in the editor\n * and nothing else. The applied set is the app's, which is what lets it come from —\n * and go back into — the URL.\n *\n * @example\n * const [filters, setFilters] = useState<Filter[]>(() =>\n * filtersFromSearchParams(new URLSearchParams(location.search), FIELDS),\n * );\n *\n * <FilterBar fields={FIELDS} value={filters} onChange={setFilters} />\n */\nexport function FilterBar({\n fields,\n value,\n onChange,\n locale = \"pt-BR\",\n actions,\n className,\n ...rest\n}: FilterBarProps) {\n const strings = filterStrings(locale);\n const baseId = useId();\n const [draft, setDraft] = useState<Draft | null>(null);\n\n const field = draft ? fields.find((candidate) => candidate.name === draft.field) : undefined;\n const pending = draft ? toFilter(draft) : null;\n const ready = pending !== null && isComplete(pending);\n\n const open = (): void => {\n if (fields.length > 0) setDraft(draftFor(fields[0]));\n };\n\n const apply = (): void => {\n if (!pending || !ready) return;\n onChange([...value, pending]);\n setDraft(null);\n };\n\n const removeAt = (index: number): void => {\n onChange(value.filter((_, position) => position !== index));\n };\n\n return (\n <div className={cn(styles.bar, className)} {...rest}>\n <ul className={styles.chips}>\n {value.length === 0 && !draft && <li className={styles.empty}>{strings.empty}</li>}\n {value.map((filter, index) => {\n const description = describeFilter(filter, fields, locale);\n return (\n <li\n key={`${filter.field}-${filter.operator}-${index}`}\n className={styles.chip}\n >\n <span>{description}</span>\n <button\n type=\"button\"\n className={styles.remove}\n aria-label={strings.remove(description)}\n onClick={() => removeAt(index)}\n >\n ×\n </button>\n </li>\n );\n })}\n </ul>\n\n {draft && field ? (\n <div className={styles.editor} role=\"group\" aria-label={strings.add}>\n <label className={styles.control}>\n <VisuallyHidden>{strings.field}</VisuallyHidden>\n <select\n className={styles.select}\n value={draft.field}\n onChange={(event) => {\n const next = fields.find(\n (candidate) => candidate.name === event.target.value,\n );\n if (next) setDraft(draftFor(next));\n }}\n >\n {fields.map((candidate) => (\n <option key={candidate.name} value={candidate.name}>\n {candidate.label}\n </option>\n ))}\n </select>\n </label>\n\n <label className={styles.control}>\n <VisuallyHidden>{strings.operator}</VisuallyHidden>\n <select\n className={styles.select}\n value={draft.operator}\n onChange={(event) =>\n setDraft({\n ...draft,\n operator: event.target.value as Filter[\"operator\"],\n value: \"\",\n to: \"\",\n })\n }\n >\n {operatorsFor(field).map((operator) => (\n <option key={operator} value={operator}>\n {operatorLabel(operator, locale)}\n </option>\n ))}\n </select>\n </label>\n\n {!isValueless(draft.operator) && (\n <ValueInput\n id={`${baseId}-value`}\n field={field}\n draft={draft}\n strings={strings}\n onChange={setDraft}\n />\n )}\n\n <button\n type=\"button\"\n className={styles.primary}\n disabled={!ready}\n onClick={apply}\n >\n {strings.apply}\n </button>\n <button type=\"button\" className={styles.ghost} onClick={() => setDraft(null)}>\n {strings.cancel}\n </button>\n </div>\n ) : (\n <div className={styles.actions}>\n <button\n type=\"button\"\n className={styles.secondary}\n disabled={fields.length === 0}\n onClick={open}\n >\n + {strings.add}\n </button>\n {value.length > 0 && (\n <button type=\"button\" className={styles.ghost} onClick={() => onChange([])}>\n {strings.clear}\n </button>\n )}\n {actions}\n </div>\n )}\n\n <VisuallyHidden aria-live=\"polite\" role=\"status\">\n {strings.active(value.length)}\n </VisuallyHidden>\n </div>\n );\n}\n\n/**\n * The value input for the draft.\n *\n * The input type follows the **field**, not the operator: a date field gets a date\n * picker even under `between`, where two of them are needed. Typing a date into a\n * text box is the fastest way to produce a filter the backend cannot parse.\n */\nfunction ValueInput({\n id,\n field,\n draft,\n strings,\n onChange,\n}: {\n id: string;\n field: FilterField;\n draft: Draft;\n strings: ReturnType<typeof filterStrings>;\n onChange: (draft: Draft) => void;\n}) {\n const type = field.type === \"number\" ? \"number\" : field.type === \"date\" ? \"date\" : \"text\";\n\n if (field.type === \"select\" && !isMulti(draft.operator)) {\n return (\n <label className={styles.control}>\n <VisuallyHidden>{strings.value}</VisuallyHidden>\n <select\n id={id}\n className={styles.select}\n value={draft.value}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n >\n <option value=\"\">—</option>\n {field.options?.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </label>\n );\n }\n\n if (field.type === \"boolean\") {\n return (\n <label className={styles.control}>\n <VisuallyHidden>{strings.value}</VisuallyHidden>\n <select\n id={id}\n className={styles.select}\n value={draft.value}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n >\n <option value=\"\">—</option>\n <option value=\"true\">{strings.yes}</option>\n <option value=\"false\">{strings.no}</option>\n </select>\n </label>\n );\n }\n\n if (draft.operator === \"between\") {\n return (\n <>\n <label className={styles.control}>\n <VisuallyHidden>{strings.from}</VisuallyHidden>\n <input\n id={id}\n className={styles.input}\n type={type}\n value={draft.value}\n placeholder={strings.from}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n />\n </label>\n <label className={styles.control}>\n <VisuallyHidden>{strings.to}</VisuallyHidden>\n <input\n className={styles.input}\n type={type}\n value={draft.to}\n placeholder={strings.to}\n onChange={(event) => onChange({ ...draft, to: event.target.value })}\n />\n </label>\n </>\n );\n }\n\n return (\n <label className={styles.control}>\n <VisuallyHidden>{strings.value}</VisuallyHidden>\n <input\n id={id}\n className={styles.input}\n type={type}\n value={draft.value}\n placeholder={field.placeholder ?? strings.value}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n />\n </label>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"FilterBar.js","names":[],"sources":["../../../src/components/FilterBar/FilterBar.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, function-lines — a filter bar renders a different\n * editor per filter kind — select, multi-select, range, date range, text — and the\n * body is that dispatch plus the chip summary, both reading the same value map.\n */\nimport { useId, useState, type HTMLAttributes, type ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport {\n defaultOperator,\n describeFilter,\n filterStrings,\n isComplete,\n isMulti,\n isValueless,\n operatorLabel,\n operatorsFor,\n type Filter,\n type FilterField,\n} from \"./filter-model\";\nimport styles from \"./FilterBar.module.css\";\n\n/** DOM attributes this component redefines. */\ntype OverriddenDomProps = \"children\" | \"onChange\";\n\nexport interface FilterBarProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps> {\n /** Fields the user may filter by. */\n fields: readonly FilterField[];\n /** Applied filters. Controlled. */\n value: readonly Filter[];\n /** Next filter set. Combined with AND. */\n onChange: (filters: Filter[]) => void;\n /** Locale for the labels. Default `\"pt-BR\"`. */\n locale?: \"pt-BR\" | \"en\";\n /** Rendered at the end of the bar — a \"save this view\" button, a counter. */\n actions?: ReactNode;\n}\n\n/** The draft filter being built in the editor. */\ninterface Draft {\n field: string;\n operator: Filter[\"operator\"];\n value: string;\n to: string;\n}\n\n/** A fresh draft for a field. */\nfunction draftFor(field: FilterField): Draft {\n return { field: field.name, operator: defaultOperator(field), value: \"\", to: \"\" };\n}\n\n/** Turn a draft into a filter. */\nfunction toFilter(draft: Draft): Filter {\n if (isValueless(draft.operator)) return { field: draft.field, operator: draft.operator };\n if (draft.operator === \"between\") {\n return { field: draft.field, operator: draft.operator, value: [draft.value, draft.to] };\n }\n if (isMulti(draft.operator)) {\n return {\n field: draft.field,\n operator: draft.operator,\n value: draft.value\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean),\n };\n }\n return { field: draft.field, operator: draft.operator, value: draft.value };\n}\n\n/**\n * A row of applied filters, and a small editor to add another.\n *\n * Filters are combined with **AND**, flat — no nested `(a OR b) AND c` groups. That\n * is the shape of nearly every admin list (\"status is paid, created after March,\n * text contains nota\"), and it is what serializes into a URL somebody can send to a\n * colleague. Nested groups need a tree UI with per-node operators and a different\n * serialization; a component trying to be both is clumsy at the common case.\n *\n * Controlled, like the rest of the SDK: it holds the half-typed draft in the editor\n * and nothing else. The applied set is the app's, which is what lets it come from —\n * and go back into — the URL.\n *\n * @example\n * const [filters, setFilters] = useState<Filter[]>(() =>\n * filtersFromSearchParams(new URLSearchParams(location.search), FIELDS),\n * );\n *\n * <FilterBar fields={FIELDS} value={filters} onChange={setFilters} />\n */\nexport function FilterBar({\n fields,\n value,\n onChange,\n locale = \"pt-BR\",\n actions,\n className,\n ...rest\n}: FilterBarProps) {\n const strings = filterStrings(locale);\n const baseId = useId();\n const [draft, setDraft] = useState<Draft | null>(null);\n\n const field = draft ? fields.find((candidate) => candidate.name === draft.field) : undefined;\n const pending = draft ? toFilter(draft) : null;\n const ready = pending !== null && isComplete(pending);\n\n const open = (): void => {\n if (fields.length > 0) setDraft(draftFor(fields[0]));\n };\n\n const apply = (): void => {\n if (!pending || !ready) return;\n onChange([...value, pending]);\n setDraft(null);\n };\n\n const removeAt = (index: number): void => {\n onChange(value.filter((_, position) => position !== index));\n };\n\n return (\n <div className={cn(styles.bar, className)} {...rest}>\n <ul className={styles.chips}>\n {value.length === 0 && !draft && <li className={styles.empty}>{strings.empty}</li>}\n {value.map((filter, index) => {\n const description = describeFilter(filter, fields, locale);\n return (\n <li\n key={`${filter.field}-${filter.operator}-${index}`}\n className={styles.chip}\n >\n <span>{description}</span>\n <button\n type=\"button\"\n className={styles.remove}\n aria-label={strings.remove(description)}\n onClick={() => removeAt(index)}\n >\n ×\n </button>\n </li>\n );\n })}\n </ul>\n\n {draft && field ? (\n <div className={styles.editor} role=\"group\" aria-label={strings.add}>\n <label className={styles.control}>\n <VisuallyHidden>{strings.field}</VisuallyHidden>\n <select\n className={styles.select}\n value={draft.field}\n onChange={(event) => {\n const next = fields.find(\n (candidate) => candidate.name === event.target.value,\n );\n if (next) setDraft(draftFor(next));\n }}\n >\n {fields.map((candidate) => (\n <option key={candidate.name} value={candidate.name}>\n {candidate.label}\n </option>\n ))}\n </select>\n </label>\n\n <label className={styles.control}>\n <VisuallyHidden>{strings.operator}</VisuallyHidden>\n <select\n className={styles.select}\n value={draft.operator}\n onChange={(event) =>\n setDraft({\n ...draft,\n operator: event.target.value as Filter[\"operator\"],\n value: \"\",\n to: \"\",\n })\n }\n >\n {operatorsFor(field).map((operator) => (\n <option key={operator} value={operator}>\n {operatorLabel(operator, locale)}\n </option>\n ))}\n </select>\n </label>\n\n {!isValueless(draft.operator) && (\n <ValueInput\n id={`${baseId}-value`}\n field={field}\n draft={draft}\n strings={strings}\n onChange={setDraft}\n />\n )}\n\n <button\n type=\"button\"\n className={styles.primary}\n disabled={!ready}\n onClick={apply}\n >\n {strings.apply}\n </button>\n <button type=\"button\" className={styles.ghost} onClick={() => setDraft(null)}>\n {strings.cancel}\n </button>\n </div>\n ) : (\n <div className={styles.actions}>\n <button\n type=\"button\"\n className={styles.secondary}\n disabled={fields.length === 0}\n onClick={open}\n >\n + {strings.add}\n </button>\n {value.length > 0 && (\n <button type=\"button\" className={styles.ghost} onClick={() => onChange([])}>\n {strings.clear}\n </button>\n )}\n {actions}\n </div>\n )}\n\n <VisuallyHidden aria-live=\"polite\" role=\"status\">\n {strings.active(value.length)}\n </VisuallyHidden>\n </div>\n );\n}\n\n/**\n * The value input for the draft.\n *\n * The input type follows the **field**, not the operator: a date field gets a date\n * picker even under `between`, where two of them are needed. Typing a date into a\n * text box is the fastest way to produce a filter the backend cannot parse.\n */\nfunction ValueInput({\n id,\n field,\n draft,\n strings,\n onChange,\n}: {\n id: string;\n field: FilterField;\n draft: Draft;\n strings: ReturnType<typeof filterStrings>;\n onChange: (draft: Draft) => void;\n}) {\n const type = field.type === \"number\" ? \"number\" : field.type === \"date\" ? \"date\" : \"text\";\n\n if (field.type === \"select\" && !isMulti(draft.operator)) {\n return (\n <label className={styles.control}>\n <VisuallyHidden>{strings.value}</VisuallyHidden>\n <select\n id={id}\n className={styles.select}\n value={draft.value}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n >\n <option value=\"\">—</option>\n {field.options?.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </label>\n );\n }\n\n if (field.type === \"boolean\") {\n return (\n <label className={styles.control}>\n <VisuallyHidden>{strings.value}</VisuallyHidden>\n <select\n id={id}\n className={styles.select}\n value={draft.value}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n >\n <option value=\"\">—</option>\n <option value=\"true\">{strings.yes}</option>\n <option value=\"false\">{strings.no}</option>\n </select>\n </label>\n );\n }\n\n if (draft.operator === \"between\") {\n return (\n <>\n <label className={styles.control}>\n <VisuallyHidden>{strings.from}</VisuallyHidden>\n <input\n id={id}\n className={styles.input}\n type={type}\n value={draft.value}\n placeholder={strings.from}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n />\n </label>\n <label className={styles.control}>\n <VisuallyHidden>{strings.to}</VisuallyHidden>\n <input\n className={styles.input}\n type={type}\n value={draft.to}\n placeholder={strings.to}\n onChange={(event) => onChange({ ...draft, to: event.target.value })}\n />\n </label>\n </>\n );\n }\n\n return (\n <label className={styles.control}>\n <VisuallyHidden>{strings.value}</VisuallyHidden>\n <input\n id={id}\n className={styles.input}\n type={type}\n value={draft.value}\n placeholder={field.placeholder ?? strings.value}\n onChange={(event) => onChange({ ...draft, value: event.target.value })}\n />\n </label>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"FloatingActionButton.cjs","names":[],"sources":["../../../src/components/FloatingActionButton/FloatingActionButton.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./FloatingActionButton.module.css\";\n\nexport type FloatingActionButtonPosition = \"bottom-right\" | \"bottom-left\" | \"none\";\nexport type FloatingActionButtonSize = \"sm\" | \"md\" | \"lg\";\nexport type FloatingActionButtonVariant = \"primary\" | \"surface\";\n\nexport interface FloatingActionButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Icon rendered inside the FAB. Required. */\n icon: ReactNode;\n /** When present, renders an extended (pill) FAB with icon + label. */\n label?: ReactNode;\n /** Corner placement, or `\"none\"` for static/inline. Default `\"bottom-right\"`. */\n position?: FloatingActionButtonPosition;\n /** Size token. Default `\"md\"`. */\n size?: FloatingActionButtonSize;\n /** Visual style. Default `\"primary\"`. */\n variant?: FloatingActionButtonVariant;\n /** Extra class names merged onto the root. */\n className?: string;\n}\n\n/**\n * Material Floating Action Button. Renders a round FAB when only an `icon` is\n * given, or an extended pill FAB when a `label` is also provided. By default it\n * is fixed to the bottom-right corner; set `position=\"none\"` to place it inline.\n *\n * Spreads all native `<button>` props (`onClick`, `disabled`, etc.).\n *\n * @remarks\n * Always pass an `aria-label` when there is no `label`, since an icon-only FAB\n * has no accessible name otherwise.\n *\n * @example\n * <FloatingActionButton icon={<Plus />} aria-label=\"Adicionar\" onClick={create} />\n *\n * @example\n * <FloatingActionButton icon={<Plus />} label=\"Novo\" onClick={create} />\n */\nexport function FloatingActionButton({\n icon,\n label,\n position = \"bottom-right\",\n size = \"md\",\n variant = \"primary\",\n className,\n ...props\n}: FloatingActionButtonProps) {\n const extended = label !== undefined;\n return (\n <button\n type=\"button\"\n className={cn(\n styles.fab,\n styles[size],\n styles[variant],\n extended ? styles.extended : styles.round,\n position !== \"none\" && styles.fixed,\n position === \"bottom-right\" && styles.bottomRight,\n position === \"bottom-left\" && styles.bottomLeft,\n className,\n )}\n {...props}\n >\n <span className={styles.icon}>{icon}</span>\n {extended && <span className={styles.label}>{label}</span>}\n </button>\n );\n}\n"],"mappings":"wHAwCA,SAAgB,EAAqB,CACjC,OACA,QACA,WAAW,eACX,OAAO,KACP,UAAU,UACV,YACA,GAAG,GACuB,CAC1B,IAAM,EAAW,IAAU,IAAA,GAC3B,OACI,EAAA,EAAA,KAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,GACP,EAAA,QAAO,IACP,EAAA,QAAO,GACP,EAAA,QAAO,GACP,EAAW,EAAA,QAAO,SAAW,EAAA,QAAO,MACpC,IAAa,QAAU,EAAA,QAAO,MAC9B,IAAa,gBAAkB,EAAA,QAAO,YACtC,IAAa,eAAiB,EAAA,QAAO,WACrC,CACJ,EACA,GAAI,WAZR,EAcI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,cAAO,CAAW,CAAA,EACzC,IAAY,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,eAAQ,CAAY,CAAA,CACrD,GAEhB"}
1
+ {"version":3,"file":"FloatingActionButton.cjs","names":[],"sources":["../../../src/components/FloatingActionButton/FloatingActionButton.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./FloatingActionButton.module.css\";\n\nexport type FloatingActionButtonPosition = \"bottom-right\" | \"bottom-left\" | \"none\";\nexport type FloatingActionButtonSize = \"sm\" | \"md\" | \"lg\";\nexport type FloatingActionButtonVariant = \"primary\" | \"surface\";\n\nexport interface FloatingActionButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Icon rendered inside the FAB. Required. */\n icon: ReactNode;\n /** When present, renders an extended (pill) FAB with icon + label. */\n label?: ReactNode;\n /** Corner placement, or `\"none\"` for static/inline. Default `\"bottom-right\"`. */\n position?: FloatingActionButtonPosition;\n /** Size token. Default `\"md\"`. */\n size?: FloatingActionButtonSize;\n /** Visual style. Default `\"primary\"`. */\n variant?: FloatingActionButtonVariant;\n /** Extra class names merged onto the root. */\n className?: string;\n}\n\n/**\n * Material Floating Action Button. Renders a round FAB when only an `icon` is\n * given, or an extended pill FAB when a `label` is also provided. By default it\n * is fixed to the bottom-right corner; set `position=\"none\"` to place it inline.\n *\n * Spreads all native `<button>` props (`onClick`, `disabled`, etc.).\n *\n * @remarks\n * Always pass an `aria-label` when there is no `label`, since an icon-only FAB\n * has no accessible name otherwise.\n *\n * @example\n * <FloatingActionButton icon={<Plus />} aria-label=\"Adicionar\" onClick={create} />\n *\n * @example\n * <FloatingActionButton icon={<Plus />} label=\"Novo\" onClick={create} />\n */\nexport function FloatingActionButton({\n icon,\n label,\n position = \"bottom-right\",\n size = \"md\",\n variant = \"primary\",\n className,\n ...props\n}: FloatingActionButtonProps) {\n const extended = label !== undefined;\n return (\n <button\n type=\"button\"\n className={cn(\n styles.fab,\n styles[size],\n styles[variant],\n extended ? styles.extended : styles.round,\n position !== \"none\" && styles.fixed,\n position === \"bottom-right\" && styles.bottomRight,\n position === \"bottom-left\" && styles.bottomLeft,\n className,\n )}\n {...props}\n >\n <span className={styles.icon}>{icon}</span>\n {extended && <span className={styles.label}>{label}</span>}\n </button>\n );\n}\n"],"mappings":"wHAwCA,SAAgB,EAAqB,CACjC,OACA,QACA,WAAW,eACX,OAAO,KACP,UAAU,UACV,YACA,GAAG,GACuB,CAC1B,IAAM,EAAW,IAAU,IAAA,GAC3B,OACI,EAAA,EAAA,KAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,GACP,EAAA,QAAO,IACP,EAAA,QAAO,GACP,EAAA,QAAO,GACP,EAAW,EAAA,QAAO,SAAW,EAAA,QAAO,MACpC,IAAa,QAAU,EAAA,QAAO,MAC9B,IAAa,gBAAkB,EAAA,QAAO,YACtC,IAAa,eAAiB,EAAA,QAAO,WACrC,CACJ,EACA,GAAI,EAZR,SAAA,EAcI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,KAAO,SAAA,CAAW,CAAA,EACzC,IAAY,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,MAAQ,SAAA,CAAY,CAAA,CACrD,GAEhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"FloatingActionButton.js","names":[],"sources":["../../../src/components/FloatingActionButton/FloatingActionButton.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./FloatingActionButton.module.css\";\n\nexport type FloatingActionButtonPosition = \"bottom-right\" | \"bottom-left\" | \"none\";\nexport type FloatingActionButtonSize = \"sm\" | \"md\" | \"lg\";\nexport type FloatingActionButtonVariant = \"primary\" | \"surface\";\n\nexport interface FloatingActionButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Icon rendered inside the FAB. Required. */\n icon: ReactNode;\n /** When present, renders an extended (pill) FAB with icon + label. */\n label?: ReactNode;\n /** Corner placement, or `\"none\"` for static/inline. Default `\"bottom-right\"`. */\n position?: FloatingActionButtonPosition;\n /** Size token. Default `\"md\"`. */\n size?: FloatingActionButtonSize;\n /** Visual style. Default `\"primary\"`. */\n variant?: FloatingActionButtonVariant;\n /** Extra class names merged onto the root. */\n className?: string;\n}\n\n/**\n * Material Floating Action Button. Renders a round FAB when only an `icon` is\n * given, or an extended pill FAB when a `label` is also provided. By default it\n * is fixed to the bottom-right corner; set `position=\"none\"` to place it inline.\n *\n * Spreads all native `<button>` props (`onClick`, `disabled`, etc.).\n *\n * @remarks\n * Always pass an `aria-label` when there is no `label`, since an icon-only FAB\n * has no accessible name otherwise.\n *\n * @example\n * <FloatingActionButton icon={<Plus />} aria-label=\"Adicionar\" onClick={create} />\n *\n * @example\n * <FloatingActionButton icon={<Plus />} label=\"Novo\" onClick={create} />\n */\nexport function FloatingActionButton({\n icon,\n label,\n position = \"bottom-right\",\n size = \"md\",\n variant = \"primary\",\n className,\n ...props\n}: FloatingActionButtonProps) {\n const extended = label !== undefined;\n return (\n <button\n type=\"button\"\n className={cn(\n styles.fab,\n styles[size],\n styles[variant],\n extended ? styles.extended : styles.round,\n position !== \"none\" && styles.fixed,\n position === \"bottom-right\" && styles.bottomRight,\n position === \"bottom-left\" && styles.bottomLeft,\n className,\n )}\n {...props}\n >\n <span className={styles.icon}>{icon}</span>\n {extended && <span className={styles.label}>{label}</span>}\n </button>\n );\n}\n"],"mappings":";;;;AAwCA,SAAgB,EAAqB,EACjC,SACA,UACA,cAAW,gBACX,UAAO,MACP,aAAU,WACV,cACA,GAAG,KACuB;CAC1B,IAAM,IAAW,MAAU,KAAA;CAC3B,OACI,kBAAC,UAAD;EACI,MAAK;EACL,WAAW,EACP,EAAO,KACP,EAAO,IACP,EAAO,IACP,IAAW,EAAO,WAAW,EAAO,OACpC,MAAa,UAAU,EAAO,OAC9B,MAAa,kBAAkB,EAAO,aACtC,MAAa,iBAAiB,EAAO,YACrC,CACJ;EACA,GAAI;YAZR,CAcI,kBAAC,QAAD;GAAM,WAAW,EAAO;aAAO;EAAW,CAAA,GACzC,KAAY,kBAAC,QAAD;GAAM,WAAW,EAAO;aAAQ;EAAY,CAAA,CACrD;;AAEhB"}
1
+ {"version":3,"file":"FloatingActionButton.js","names":[],"sources":["../../../src/components/FloatingActionButton/FloatingActionButton.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./FloatingActionButton.module.css\";\n\nexport type FloatingActionButtonPosition = \"bottom-right\" | \"bottom-left\" | \"none\";\nexport type FloatingActionButtonSize = \"sm\" | \"md\" | \"lg\";\nexport type FloatingActionButtonVariant = \"primary\" | \"surface\";\n\nexport interface FloatingActionButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Icon rendered inside the FAB. Required. */\n icon: ReactNode;\n /** When present, renders an extended (pill) FAB with icon + label. */\n label?: ReactNode;\n /** Corner placement, or `\"none\"` for static/inline. Default `\"bottom-right\"`. */\n position?: FloatingActionButtonPosition;\n /** Size token. Default `\"md\"`. */\n size?: FloatingActionButtonSize;\n /** Visual style. Default `\"primary\"`. */\n variant?: FloatingActionButtonVariant;\n /** Extra class names merged onto the root. */\n className?: string;\n}\n\n/**\n * Material Floating Action Button. Renders a round FAB when only an `icon` is\n * given, or an extended pill FAB when a `label` is also provided. By default it\n * is fixed to the bottom-right corner; set `position=\"none\"` to place it inline.\n *\n * Spreads all native `<button>` props (`onClick`, `disabled`, etc.).\n *\n * @remarks\n * Always pass an `aria-label` when there is no `label`, since an icon-only FAB\n * has no accessible name otherwise.\n *\n * @example\n * <FloatingActionButton icon={<Plus />} aria-label=\"Adicionar\" onClick={create} />\n *\n * @example\n * <FloatingActionButton icon={<Plus />} label=\"Novo\" onClick={create} />\n */\nexport function FloatingActionButton({\n icon,\n label,\n position = \"bottom-right\",\n size = \"md\",\n variant = \"primary\",\n className,\n ...props\n}: FloatingActionButtonProps) {\n const extended = label !== undefined;\n return (\n <button\n type=\"button\"\n className={cn(\n styles.fab,\n styles[size],\n styles[variant],\n extended ? styles.extended : styles.round,\n position !== \"none\" && styles.fixed,\n position === \"bottom-right\" && styles.bottomRight,\n position === \"bottom-left\" && styles.bottomLeft,\n className,\n )}\n {...props}\n >\n <span className={styles.icon}>{icon}</span>\n {extended && <span className={styles.label}>{label}</span>}\n </button>\n );\n}\n"],"mappings":";;;;AAwCA,SAAgB,EAAqB,EACjC,SACA,UACA,cAAW,gBACX,UAAO,MACP,aAAU,WACV,cACA,GAAG,KACuB;CAC1B,IAAM,IAAW,MAAU,KAAA;CAC3B,OACI,kBAAC,UAAD;EACI,MAAK;EACL,WAAW,EACP,EAAO,KACP,EAAO,IACP,EAAO,IACP,IAAW,EAAO,WAAW,EAAO,OACpC,MAAa,UAAU,EAAO,OAC9B,MAAa,kBAAkB,EAAO,aACtC,MAAa,iBAAiB,EAAO,YACrC,CACJ;EACA,GAAI;EAZR,UAAA,CAcI,kBAAC,QAAD;GAAM,WAAW,EAAO;GAAO,UAAA;EAAW,CAAA,GACzC,KAAY,kBAAC,QAAD;GAAM,WAAW,EAAO;GAAQ,UAAA;EAAY,CAAA,CACrD;;AAEhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"Form.cjs","names":[],"sources":["../../../src/components/Form/Form.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { CSSProperties, FormHTMLAttributes, HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Form.module.css\";\n\nexport type FormLayout = \"stack\" | \"inline\" | \"grid\";\nexport type FormActionsAlign = \"start\" | \"center\" | \"end\" | \"between\";\n\ninterface LayoutProps {\n /** Field arrangement. `stack` stacks fields vertically, `inline` lines them up in a wrapping row, `grid` arranges them in `columns` equal-width tracks. Default `stack`. */\n layout?: FormLayout;\n /** Number of columns when `layout=\"grid\"`, or a custom `grid-template-columns` value. Default `2`. */\n columns?: number | string;\n /** Gap between fields. Numbers map to a multiple of the 4px scale (default `4` → 16px). */\n gap?: number | string;\n}\n\nfunction resolveGap(gap: number | string | undefined, fallback: number): string {\n if (gap === undefined) return `${fallback * 4}px`;\n return typeof gap === \"number\" ? `${gap * 4}px` : gap;\n}\n\nfunction resolveColumns(columns: number | string | undefined): string {\n if (columns === undefined) return \"repeat(2, minmax(0, 1fr))\";\n return typeof columns === \"number\" ? `repeat(${columns}, minmax(0, 1fr))` : columns;\n}\n\nexport interface FormProps extends FormHTMLAttributes<HTMLFormElement>, LayoutProps {}\n\n/**\n * Form wrapper with a built-in layout variant. Replaces ad-hoc `<form>` +\n * `<Stack>` / `<Grid>` boilerplate; pair with [[FormRow]], [[FormSection]],\n * and [[FormActions]] for richer layouts.\n *\n * @example\n * <Form layout=\"grid\" columns={2} gap={4} onSubmit={form.handleSubmit(save)}>\n * <Input label=\"Nome\" {...form.register(\"name\")} />\n * <Input label=\"Email\" {...form.register(\"email\")} />\n * <FormActions align=\"end\">\n * <Button type=\"submit\">Salvar</Button>\n * </FormActions>\n * </Form>\n */\nexport const Form = forwardRef<HTMLFormElement, FormProps>(function Form(\n { layout = \"stack\", columns, gap, className, style, children, ...props },\n ref,\n) {\n const finalStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n ...style,\n };\n return (\n <form\n ref={ref}\n className={cn(styles.form, styles[layout], className)}\n style={finalStyle}\n {...props}\n >\n {children}\n </form>\n );\n});\n\nexport interface FormSectionProps extends Omit<HTMLAttributes<HTMLElement>, \"title\">, LayoutProps {\n title?: ReactNode;\n description?: ReactNode;\n}\n\n/**\n * Visually grouped subset of fields with an optional title and description.\n * Has its own `layout`/`columns`/`gap` so subsets can stack while the parent\n * grids (or vice versa).\n *\n * @example\n * <FormSection title=\"Endereço\" description=\"Usado para entrega\" layout=\"grid\" columns={3}>\n * <Input label=\"CEP\" />\n * <Input label=\"Rua\" />\n * <Input label=\"Número\" />\n * </FormSection>\n */\nexport function FormSection({\n title,\n description,\n layout = \"stack\",\n columns,\n gap,\n className,\n style,\n children,\n ...props\n}: FormSectionProps) {\n const bodyStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n };\n return (\n <section className={cn(styles.section, className)} style={style} {...props}>\n {(title || description) && (\n <header className={styles.sectionHeader}>\n {title && <h3 className={styles.sectionTitle}>{title}</h3>}\n {description && <p className={styles.sectionDescription}>{description}</p>}\n </header>\n )}\n <div className={cn(styles.sectionBody, styles[layout])} style={bodyStyle}>\n {children}\n </div>\n </section>\n );\n}\n\nexport interface FormRowProps extends HTMLAttributes<HTMLDivElement> {\n /** Gap between row items. Numbers map to a multiple of the 4px scale (default `3` → 12px). */\n gap?: number | string;\n}\n\n/**\n * Forces a horizontal row regardless of parent layout — useful for grouping\n * two short fields side-by-side inside an otherwise stacked form (e.g. CEP +\n * city, expiry month + year).\n *\n * @example\n * <Form layout=\"stack\">\n * <FormRow>\n * <Input label=\"CEP\" />\n * <Input label=\"Cidade\" />\n * </FormRow>\n * <Input label=\"Endereço completo\" />\n * </Form>\n */\nexport function FormRow({ gap, className, style, children, ...props }: FormRowProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 3), ...style };\n return (\n <div className={cn(styles.row, className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n\nexport interface FormActionsProps extends HTMLAttributes<HTMLDivElement> {\n /** Horizontal alignment of buttons. Default `end`. */\n align?: FormActionsAlign;\n /** Gap between buttons. Numbers map to a multiple of the 4px scale (default `2` → 8px). */\n gap?: number | string;\n}\n\n/**\n * Footer button row for a form. Use inside (or after) [[Form]] / [[FormSection]].\n *\n * @example\n * <FormActions align=\"end\">\n * <Button variant=\"ghost\" onClick={onCancel}>Cancelar</Button>\n * <Button type=\"submit\" loading={form.formState.isSubmitting}>Salvar</Button>\n * </FormActions>\n */\nexport function FormActions({\n align = \"end\",\n gap,\n className,\n style,\n children,\n ...props\n}: FormActionsProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 2), ...style };\n return (\n <div className={cn(styles.actions, styles[align], className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n"],"mappings":"2HAiBA,SAAS,EAAW,EAAkC,EAA0B,CAE5E,OADI,IAAQ,IAAA,GAAkB,GAAG,EAAW,EAAE,IACvC,OAAO,GAAQ,SAAW,GAAG,EAAM,EAAE,IAAM,CACtD,CAEA,SAAS,EAAe,EAA8C,CAElE,OADI,IAAY,IAAA,GAAkB,4BAC3B,OAAO,GAAY,SAAW,UAAU,EAAQ,mBAAqB,CAChF,CAkBA,IAAa,GAAA,EAAA,EAAA,WAAA,CAA8C,SACvD,CAAE,SAAS,QAAS,UAAS,MAAK,YAAW,QAAO,WAAU,GAAG,GACjE,EACF,CACE,IAAM,EAA4B,CAC9B,IAAK,EAAW,EAAK,CAAC,EACtB,GAAI,IAAW,OAAS,CAAE,oBAAqB,EAAe,CAAO,CAAE,EAAI,KAC3E,GAAG,CACP,EACA,OACI,EAAA,EAAA,IAAA,CAAC,OAAD,CACS,MACL,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,EAAA,QAAO,GAAS,CAAS,EACpD,MAAO,EACP,GAAI,EAEH,UACC,CAAA,CAEd,CAAC,EAmBD,SAAgB,EAAY,CACxB,QACA,cACA,SAAS,QACT,UACA,MACA,YACA,QACA,WACA,GAAG,GACc,CACjB,IAAM,EAA2B,CAC7B,IAAK,EAAW,EAAK,CAAC,EACtB,GAAI,IAAW,OAAS,CAAE,oBAAqB,EAAe,CAAO,CAAE,EAAI,IAC/E,EACA,OACI,EAAA,EAAA,KAAA,CAAC,UAAD,CAAS,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EAAU,QAAO,GAAI,WAArE,EACM,GAAS,KACP,EAAA,EAAA,KAAA,CAAC,SAAD,CAAQ,UAAW,EAAA,QAAO,uBAA1B,CACK,IAAS,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,sBAAe,CAAU,CAAA,EACxD,IAAe,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAA,QAAO,4BAAqB,CAAe,CAAA,CACrE,KAEZ,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,YAAa,EAAA,QAAO,EAAO,EAAG,MAAO,EAC1D,UACA,CAAA,CACA,GAEjB,CAqBA,SAAgB,EAAQ,CAAE,MAAK,YAAW,QAAO,WAAU,GAAG,GAAuB,CACjF,IAAM,EAA4B,CAAE,IAAK,EAAW,EAAK,CAAC,EAAG,GAAG,CAAM,EACtE,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,CAAS,EAAG,MAAO,EAAY,GAAI,EAC7D,UACA,CAAA,CAEb,CAkBA,SAAgB,EAAY,CACxB,QAAQ,MACR,MACA,YACA,QACA,WACA,GAAG,GACc,CACjB,IAAM,EAA4B,CAAE,IAAK,EAAW,EAAK,CAAC,EAAG,GAAG,CAAM,EACtE,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,EAAA,QAAO,GAAQ,CAAS,EAAG,MAAO,EAAY,GAAI,EAChF,UACA,CAAA,CAEb"}
1
+ {"version":3,"file":"Form.cjs","names":[],"sources":["../../../src/components/Form/Form.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { CSSProperties, FormHTMLAttributes, HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Form.module.css\";\n\nexport type FormLayout = \"stack\" | \"inline\" | \"grid\";\nexport type FormActionsAlign = \"start\" | \"center\" | \"end\" | \"between\";\n\ninterface LayoutProps {\n /** Field arrangement. `stack` stacks fields vertically, `inline` lines them up in a wrapping row, `grid` arranges them in `columns` equal-width tracks. Default `stack`. */\n layout?: FormLayout;\n /** Number of columns when `layout=\"grid\"`, or a custom `grid-template-columns` value. Default `2`. */\n columns?: number | string;\n /** Gap between fields. Numbers map to a multiple of the 4px scale (default `4` → 16px). */\n gap?: number | string;\n}\n\nfunction resolveGap(gap: number | string | undefined, fallback: number): string {\n if (gap === undefined) return `${fallback * 4}px`;\n return typeof gap === \"number\" ? `${gap * 4}px` : gap;\n}\n\nfunction resolveColumns(columns: number | string | undefined): string {\n if (columns === undefined) return \"repeat(2, minmax(0, 1fr))\";\n return typeof columns === \"number\" ? `repeat(${columns}, minmax(0, 1fr))` : columns;\n}\n\nexport interface FormProps extends FormHTMLAttributes<HTMLFormElement>, LayoutProps {}\n\n/**\n * Form wrapper with a built-in layout variant. Replaces ad-hoc `<form>` +\n * `<Stack>` / `<Grid>` boilerplate; pair with [[FormRow]], [[FormSection]],\n * and [[FormActions]] for richer layouts.\n *\n * @example\n * <Form layout=\"grid\" columns={2} gap={4} onSubmit={form.handleSubmit(save)}>\n * <Input label=\"Nome\" {...form.register(\"name\")} />\n * <Input label=\"Email\" {...form.register(\"email\")} />\n * <FormActions align=\"end\">\n * <Button type=\"submit\">Salvar</Button>\n * </FormActions>\n * </Form>\n */\nexport const Form = forwardRef<HTMLFormElement, FormProps>(function Form(\n { layout = \"stack\", columns, gap, className, style, children, ...props },\n ref,\n) {\n const finalStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n ...style,\n };\n return (\n <form\n ref={ref}\n className={cn(styles.form, styles[layout], className)}\n style={finalStyle}\n {...props}\n >\n {children}\n </form>\n );\n});\n\nexport interface FormSectionProps extends Omit<HTMLAttributes<HTMLElement>, \"title\">, LayoutProps {\n title?: ReactNode;\n description?: ReactNode;\n}\n\n/**\n * Visually grouped subset of fields with an optional title and description.\n * Has its own `layout`/`columns`/`gap` so subsets can stack while the parent\n * grids (or vice versa).\n *\n * @example\n * <FormSection title=\"Endereço\" description=\"Usado para entrega\" layout=\"grid\" columns={3}>\n * <Input label=\"CEP\" />\n * <Input label=\"Rua\" />\n * <Input label=\"Número\" />\n * </FormSection>\n */\nexport function FormSection({\n title,\n description,\n layout = \"stack\",\n columns,\n gap,\n className,\n style,\n children,\n ...props\n}: FormSectionProps) {\n const bodyStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n };\n return (\n <section className={cn(styles.section, className)} style={style} {...props}>\n {(title || description) && (\n <header className={styles.sectionHeader}>\n {title && <h3 className={styles.sectionTitle}>{title}</h3>}\n {description && <p className={styles.sectionDescription}>{description}</p>}\n </header>\n )}\n <div className={cn(styles.sectionBody, styles[layout])} style={bodyStyle}>\n {children}\n </div>\n </section>\n );\n}\n\nexport interface FormRowProps extends HTMLAttributes<HTMLDivElement> {\n /** Gap between row items. Numbers map to a multiple of the 4px scale (default `3` → 12px). */\n gap?: number | string;\n}\n\n/**\n * Forces a horizontal row regardless of parent layout — useful for grouping\n * two short fields side-by-side inside an otherwise stacked form (e.g. CEP +\n * city, expiry month + year).\n *\n * @example\n * <Form layout=\"stack\">\n * <FormRow>\n * <Input label=\"CEP\" />\n * <Input label=\"Cidade\" />\n * </FormRow>\n * <Input label=\"Endereço completo\" />\n * </Form>\n */\nexport function FormRow({ gap, className, style, children, ...props }: FormRowProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 3), ...style };\n return (\n <div className={cn(styles.row, className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n\nexport interface FormActionsProps extends HTMLAttributes<HTMLDivElement> {\n /** Horizontal alignment of buttons. Default `end`. */\n align?: FormActionsAlign;\n /** Gap between buttons. Numbers map to a multiple of the 4px scale (default `2` → 8px). */\n gap?: number | string;\n}\n\n/**\n * Footer button row for a form. Use inside (or after) [[Form]] / [[FormSection]].\n *\n * @example\n * <FormActions align=\"end\">\n * <Button variant=\"ghost\" onClick={onCancel}>Cancelar</Button>\n * <Button type=\"submit\" loading={form.formState.isSubmitting}>Salvar</Button>\n * </FormActions>\n */\nexport function FormActions({\n align = \"end\",\n gap,\n className,\n style,\n children,\n ...props\n}: FormActionsProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 2), ...style };\n return (\n <div className={cn(styles.actions, styles[align], className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n"],"mappings":"2HAiBA,SAAS,EAAW,EAAkC,EAA0B,CAE5E,OADI,IAAQ,IAAA,GAAkB,GAAG,EAAW,EAAE,IACvC,OAAO,GAAQ,SAAW,GAAG,EAAM,EAAE,IAAM,CACtD,CAEA,SAAS,EAAe,EAA8C,CAElE,OADI,IAAY,IAAA,GAAkB,4BAC3B,OAAO,GAAY,SAAW,UAAU,EAAQ,mBAAqB,CAChF,CAkBA,IAAa,GAAA,EAAO,EAAA,WAAA,CAAuC,SACvD,CAAE,SAAS,QAAS,UAAS,MAAK,YAAW,QAAO,WAAU,GAAG,GACjE,EACF,CACE,IAAM,EAA4B,CAC9B,IAAK,EAAW,EAAK,CAAC,EACtB,GAAI,IAAW,OAAS,CAAE,oBAAqB,EAAe,CAAO,CAAE,EAAI,KAC3E,GAAG,CACP,EACA,OACI,EAAA,EAAA,IAAA,CAAC,OAAD,CACS,MACL,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,EAAA,QAAO,GAAS,CAAS,EACpD,MAAO,EACP,GAAI,EAEH,UACC,CAAA,CAEd,CAAC,EAmBD,SAAgB,EAAY,CACxB,QACA,cACA,SAAS,QACT,UACA,MACA,YACA,QACA,WACA,GAAG,GACc,CACjB,IAAM,EAA2B,CAC7B,IAAK,EAAW,EAAK,CAAC,EACtB,GAAI,IAAW,OAAS,CAAE,oBAAqB,EAAe,CAAO,CAAE,EAAI,IAC/E,EACA,OACI,EAAA,EAAA,KAAA,CAAC,UAAD,CAAS,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EAAU,QAAO,GAAI,EAArE,SAAA,EACM,GAAS,KACP,EAAA,EAAA,KAAA,CAAC,SAAD,CAAQ,UAAW,EAAA,QAAO,cAA1B,SAAA,CACK,IAAS,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,aAAe,SAAA,CAAU,CAAA,EACxD,IAAe,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAA,QAAO,mBAAqB,SAAA,CAAe,CAAA,CACrE,CAEZ,CAAA,GAAA,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,YAAa,EAAA,QAAO,EAAO,EAAG,MAAO,EAC1D,UACA,CAAA,CACA,GAEjB,CAqBA,SAAgB,EAAQ,CAAE,MAAK,YAAW,QAAO,WAAU,GAAG,GAAuB,CACjF,IAAM,EAA4B,CAAE,IAAK,EAAW,EAAK,CAAC,EAAG,GAAG,CAAM,EACtE,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,CAAS,EAAG,MAAO,EAAY,GAAI,EAC7D,UACA,CAAA,CAEb,CAkBA,SAAgB,EAAY,CACxB,QAAQ,MACR,MACA,YACA,QACA,WACA,GAAG,GACc,CACjB,IAAM,EAA4B,CAAE,IAAK,EAAW,EAAK,CAAC,EAAG,GAAG,CAAM,EACtE,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,EAAA,QAAO,GAAQ,CAAS,EAAG,MAAO,EAAY,GAAI,EAChF,UACA,CAAA,CAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"Form.js","names":[],"sources":["../../../src/components/Form/Form.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { CSSProperties, FormHTMLAttributes, HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Form.module.css\";\n\nexport type FormLayout = \"stack\" | \"inline\" | \"grid\";\nexport type FormActionsAlign = \"start\" | \"center\" | \"end\" | \"between\";\n\ninterface LayoutProps {\n /** Field arrangement. `stack` stacks fields vertically, `inline` lines them up in a wrapping row, `grid` arranges them in `columns` equal-width tracks. Default `stack`. */\n layout?: FormLayout;\n /** Number of columns when `layout=\"grid\"`, or a custom `grid-template-columns` value. Default `2`. */\n columns?: number | string;\n /** Gap between fields. Numbers map to a multiple of the 4px scale (default `4` → 16px). */\n gap?: number | string;\n}\n\nfunction resolveGap(gap: number | string | undefined, fallback: number): string {\n if (gap === undefined) return `${fallback * 4}px`;\n return typeof gap === \"number\" ? `${gap * 4}px` : gap;\n}\n\nfunction resolveColumns(columns: number | string | undefined): string {\n if (columns === undefined) return \"repeat(2, minmax(0, 1fr))\";\n return typeof columns === \"number\" ? `repeat(${columns}, minmax(0, 1fr))` : columns;\n}\n\nexport interface FormProps extends FormHTMLAttributes<HTMLFormElement>, LayoutProps {}\n\n/**\n * Form wrapper with a built-in layout variant. Replaces ad-hoc `<form>` +\n * `<Stack>` / `<Grid>` boilerplate; pair with [[FormRow]], [[FormSection]],\n * and [[FormActions]] for richer layouts.\n *\n * @example\n * <Form layout=\"grid\" columns={2} gap={4} onSubmit={form.handleSubmit(save)}>\n * <Input label=\"Nome\" {...form.register(\"name\")} />\n * <Input label=\"Email\" {...form.register(\"email\")} />\n * <FormActions align=\"end\">\n * <Button type=\"submit\">Salvar</Button>\n * </FormActions>\n * </Form>\n */\nexport const Form = forwardRef<HTMLFormElement, FormProps>(function Form(\n { layout = \"stack\", columns, gap, className, style, children, ...props },\n ref,\n) {\n const finalStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n ...style,\n };\n return (\n <form\n ref={ref}\n className={cn(styles.form, styles[layout], className)}\n style={finalStyle}\n {...props}\n >\n {children}\n </form>\n );\n});\n\nexport interface FormSectionProps extends Omit<HTMLAttributes<HTMLElement>, \"title\">, LayoutProps {\n title?: ReactNode;\n description?: ReactNode;\n}\n\n/**\n * Visually grouped subset of fields with an optional title and description.\n * Has its own `layout`/`columns`/`gap` so subsets can stack while the parent\n * grids (or vice versa).\n *\n * @example\n * <FormSection title=\"Endereço\" description=\"Usado para entrega\" layout=\"grid\" columns={3}>\n * <Input label=\"CEP\" />\n * <Input label=\"Rua\" />\n * <Input label=\"Número\" />\n * </FormSection>\n */\nexport function FormSection({\n title,\n description,\n layout = \"stack\",\n columns,\n gap,\n className,\n style,\n children,\n ...props\n}: FormSectionProps) {\n const bodyStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n };\n return (\n <section className={cn(styles.section, className)} style={style} {...props}>\n {(title || description) && (\n <header className={styles.sectionHeader}>\n {title && <h3 className={styles.sectionTitle}>{title}</h3>}\n {description && <p className={styles.sectionDescription}>{description}</p>}\n </header>\n )}\n <div className={cn(styles.sectionBody, styles[layout])} style={bodyStyle}>\n {children}\n </div>\n </section>\n );\n}\n\nexport interface FormRowProps extends HTMLAttributes<HTMLDivElement> {\n /** Gap between row items. Numbers map to a multiple of the 4px scale (default `3` → 12px). */\n gap?: number | string;\n}\n\n/**\n * Forces a horizontal row regardless of parent layout — useful for grouping\n * two short fields side-by-side inside an otherwise stacked form (e.g. CEP +\n * city, expiry month + year).\n *\n * @example\n * <Form layout=\"stack\">\n * <FormRow>\n * <Input label=\"CEP\" />\n * <Input label=\"Cidade\" />\n * </FormRow>\n * <Input label=\"Endereço completo\" />\n * </Form>\n */\nexport function FormRow({ gap, className, style, children, ...props }: FormRowProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 3), ...style };\n return (\n <div className={cn(styles.row, className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n\nexport interface FormActionsProps extends HTMLAttributes<HTMLDivElement> {\n /** Horizontal alignment of buttons. Default `end`. */\n align?: FormActionsAlign;\n /** Gap between buttons. Numbers map to a multiple of the 4px scale (default `2` → 8px). */\n gap?: number | string;\n}\n\n/**\n * Footer button row for a form. Use inside (or after) [[Form]] / [[FormSection]].\n *\n * @example\n * <FormActions align=\"end\">\n * <Button variant=\"ghost\" onClick={onCancel}>Cancelar</Button>\n * <Button type=\"submit\" loading={form.formState.isSubmitting}>Salvar</Button>\n * </FormActions>\n */\nexport function FormActions({\n align = \"end\",\n gap,\n className,\n style,\n children,\n ...props\n}: FormActionsProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 2), ...style };\n return (\n <div className={cn(styles.actions, styles[align], className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n"],"mappings":";;;;;AAiBA,SAAS,EAAW,GAAkC,GAA0B;CAE5E,OADI,MAAQ,KAAA,IAAkB,GAAG,IAAW,EAAE,MACvC,OAAO,KAAQ,WAAW,GAAG,IAAM,EAAE,MAAM;AACtD;AAEA,SAAS,EAAe,GAA8C;CAElE,OADI,MAAY,KAAA,IAAkB,8BAC3B,OAAO,KAAY,WAAW,UAAU,EAAQ,qBAAqB;AAChF;AAkBA,IAAa,IAAO,EAAuC,SACvD,EAAE,YAAS,SAAS,YAAS,QAAK,cAAW,UAAO,aAAU,GAAG,KACjE,GACF;CACE,IAAM,IAA4B;EAC9B,KAAK,EAAW,GAAK,CAAC;EACtB,GAAI,MAAW,SAAS,EAAE,qBAAqB,EAAe,CAAO,EAAE,IAAI;EAC3E,GAAG;CACP;CACA,OACI,kBAAC,QAAD;EACS;EACL,WAAW,EAAG,EAAO,MAAM,EAAO,IAAS,CAAS;EACpD,OAAO;EACP,GAAI;EAEH;CACC,CAAA;AAEd,CAAC;AAmBD,SAAgB,EAAY,EACxB,UACA,gBACA,YAAS,SACT,YACA,QACA,cACA,UACA,aACA,GAAG,KACc;CACjB,IAAM,IAA2B;EAC7B,KAAK,EAAW,GAAK,CAAC;EACtB,GAAI,MAAW,SAAS,EAAE,qBAAqB,EAAe,CAAO,EAAE,IAAI;CAC/E;CACA,OACI,kBAAC,WAAD;EAAS,WAAW,EAAG,EAAO,SAAS,CAAS;EAAU;EAAO,GAAI;YAArE,EACM,KAAS,MACP,kBAAC,UAAD;GAAQ,WAAW,EAAO;aAA1B,CACK,KAAS,kBAAC,MAAD;IAAI,WAAW,EAAO;cAAe;GAAU,CAAA,GACxD,KAAe,kBAAC,KAAD;IAAG,WAAW,EAAO;cAAqB;GAAe,CAAA,CACrE;MAEZ,kBAAC,OAAD;GAAK,WAAW,EAAG,EAAO,aAAa,EAAO,EAAO;GAAG,OAAO;GAC1D;EACA,CAAA,CACA;;AAEjB;AAqBA,SAAgB,EAAQ,EAAE,QAAK,cAAW,UAAO,aAAU,GAAG,KAAuB;CACjF,IAAM,IAA4B;EAAE,KAAK,EAAW,GAAK,CAAC;EAAG,GAAG;CAAM;CACtE,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,KAAK,CAAS;EAAG,OAAO;EAAY,GAAI;EAC7D;CACA,CAAA;AAEb;AAkBA,SAAgB,EAAY,EACxB,WAAQ,OACR,QACA,cACA,UACA,aACA,GAAG,KACc;CACjB,IAAM,IAA4B;EAAE,KAAK,EAAW,GAAK,CAAC;EAAG,GAAG;CAAM;CACtE,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,EAAO,IAAQ,CAAS;EAAG,OAAO;EAAY,GAAI;EAChF;CACA,CAAA;AAEb"}
1
+ {"version":3,"file":"Form.js","names":[],"sources":["../../../src/components/Form/Form.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { CSSProperties, FormHTMLAttributes, HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Form.module.css\";\n\nexport type FormLayout = \"stack\" | \"inline\" | \"grid\";\nexport type FormActionsAlign = \"start\" | \"center\" | \"end\" | \"between\";\n\ninterface LayoutProps {\n /** Field arrangement. `stack` stacks fields vertically, `inline` lines them up in a wrapping row, `grid` arranges them in `columns` equal-width tracks. Default `stack`. */\n layout?: FormLayout;\n /** Number of columns when `layout=\"grid\"`, or a custom `grid-template-columns` value. Default `2`. */\n columns?: number | string;\n /** Gap between fields. Numbers map to a multiple of the 4px scale (default `4` → 16px). */\n gap?: number | string;\n}\n\nfunction resolveGap(gap: number | string | undefined, fallback: number): string {\n if (gap === undefined) return `${fallback * 4}px`;\n return typeof gap === \"number\" ? `${gap * 4}px` : gap;\n}\n\nfunction resolveColumns(columns: number | string | undefined): string {\n if (columns === undefined) return \"repeat(2, minmax(0, 1fr))\";\n return typeof columns === \"number\" ? `repeat(${columns}, minmax(0, 1fr))` : columns;\n}\n\nexport interface FormProps extends FormHTMLAttributes<HTMLFormElement>, LayoutProps {}\n\n/**\n * Form wrapper with a built-in layout variant. Replaces ad-hoc `<form>` +\n * `<Stack>` / `<Grid>` boilerplate; pair with [[FormRow]], [[FormSection]],\n * and [[FormActions]] for richer layouts.\n *\n * @example\n * <Form layout=\"grid\" columns={2} gap={4} onSubmit={form.handleSubmit(save)}>\n * <Input label=\"Nome\" {...form.register(\"name\")} />\n * <Input label=\"Email\" {...form.register(\"email\")} />\n * <FormActions align=\"end\">\n * <Button type=\"submit\">Salvar</Button>\n * </FormActions>\n * </Form>\n */\nexport const Form = forwardRef<HTMLFormElement, FormProps>(function Form(\n { layout = \"stack\", columns, gap, className, style, children, ...props },\n ref,\n) {\n const finalStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n ...style,\n };\n return (\n <form\n ref={ref}\n className={cn(styles.form, styles[layout], className)}\n style={finalStyle}\n {...props}\n >\n {children}\n </form>\n );\n});\n\nexport interface FormSectionProps extends Omit<HTMLAttributes<HTMLElement>, \"title\">, LayoutProps {\n title?: ReactNode;\n description?: ReactNode;\n}\n\n/**\n * Visually grouped subset of fields with an optional title and description.\n * Has its own `layout`/`columns`/`gap` so subsets can stack while the parent\n * grids (or vice versa).\n *\n * @example\n * <FormSection title=\"Endereço\" description=\"Usado para entrega\" layout=\"grid\" columns={3}>\n * <Input label=\"CEP\" />\n * <Input label=\"Rua\" />\n * <Input label=\"Número\" />\n * </FormSection>\n */\nexport function FormSection({\n title,\n description,\n layout = \"stack\",\n columns,\n gap,\n className,\n style,\n children,\n ...props\n}: FormSectionProps) {\n const bodyStyle: CSSProperties = {\n gap: resolveGap(gap, 4),\n ...(layout === \"grid\" ? { gridTemplateColumns: resolveColumns(columns) } : null),\n };\n return (\n <section className={cn(styles.section, className)} style={style} {...props}>\n {(title || description) && (\n <header className={styles.sectionHeader}>\n {title && <h3 className={styles.sectionTitle}>{title}</h3>}\n {description && <p className={styles.sectionDescription}>{description}</p>}\n </header>\n )}\n <div className={cn(styles.sectionBody, styles[layout])} style={bodyStyle}>\n {children}\n </div>\n </section>\n );\n}\n\nexport interface FormRowProps extends HTMLAttributes<HTMLDivElement> {\n /** Gap between row items. Numbers map to a multiple of the 4px scale (default `3` → 12px). */\n gap?: number | string;\n}\n\n/**\n * Forces a horizontal row regardless of parent layout — useful for grouping\n * two short fields side-by-side inside an otherwise stacked form (e.g. CEP +\n * city, expiry month + year).\n *\n * @example\n * <Form layout=\"stack\">\n * <FormRow>\n * <Input label=\"CEP\" />\n * <Input label=\"Cidade\" />\n * </FormRow>\n * <Input label=\"Endereço completo\" />\n * </Form>\n */\nexport function FormRow({ gap, className, style, children, ...props }: FormRowProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 3), ...style };\n return (\n <div className={cn(styles.row, className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n\nexport interface FormActionsProps extends HTMLAttributes<HTMLDivElement> {\n /** Horizontal alignment of buttons. Default `end`. */\n align?: FormActionsAlign;\n /** Gap between buttons. Numbers map to a multiple of the 4px scale (default `2` → 8px). */\n gap?: number | string;\n}\n\n/**\n * Footer button row for a form. Use inside (or after) [[Form]] / [[FormSection]].\n *\n * @example\n * <FormActions align=\"end\">\n * <Button variant=\"ghost\" onClick={onCancel}>Cancelar</Button>\n * <Button type=\"submit\" loading={form.formState.isSubmitting}>Salvar</Button>\n * </FormActions>\n */\nexport function FormActions({\n align = \"end\",\n gap,\n className,\n style,\n children,\n ...props\n}: FormActionsProps) {\n const finalStyle: CSSProperties = { gap: resolveGap(gap, 2), ...style };\n return (\n <div className={cn(styles.actions, styles[align], className)} style={finalStyle} {...props}>\n {children}\n </div>\n );\n}\n"],"mappings":";;;;;AAiBA,SAAS,EAAW,GAAkC,GAA0B;CAE5E,OADI,MAAQ,KAAA,IAAkB,GAAG,IAAW,EAAE,MACvC,OAAO,KAAQ,WAAW,GAAG,IAAM,EAAE,MAAM;AACtD;AAEA,SAAS,EAAe,GAA8C;CAElE,OADI,MAAY,KAAA,IAAkB,8BAC3B,OAAO,KAAY,WAAW,UAAU,EAAQ,qBAAqB;AAChF;AAkBA,IAAa,IAAO,EAAuC,SACvD,EAAE,YAAS,SAAS,YAAS,QAAK,cAAW,UAAO,aAAU,GAAG,KACjE,GACF;CACE,IAAM,IAA4B;EAC9B,KAAK,EAAW,GAAK,CAAC;EACtB,GAAI,MAAW,SAAS,EAAE,qBAAqB,EAAe,CAAO,EAAE,IAAI;EAC3E,GAAG;CACP;CACA,OACI,kBAAC,QAAD;EACS;EACL,WAAW,EAAG,EAAO,MAAM,EAAO,IAAS,CAAS;EACpD,OAAO;EACP,GAAI;EAEH;CACC,CAAA;AAEd,CAAC;AAmBD,SAAgB,EAAY,EACxB,UACA,gBACA,YAAS,SACT,YACA,QACA,cACA,UACA,aACA,GAAG,KACc;CACjB,IAAM,IAA2B;EAC7B,KAAK,EAAW,GAAK,CAAC;EACtB,GAAI,MAAW,SAAS,EAAE,qBAAqB,EAAe,CAAO,EAAE,IAAI;CAC/E;CACA,OACI,kBAAC,WAAD;EAAS,WAAW,EAAG,EAAO,SAAS,CAAS;EAAU;EAAO,GAAI;EAArE,UAAA,EACM,KAAS,MACP,kBAAC,UAAD;GAAQ,WAAW,EAAO;GAA1B,UAAA,CACK,KAAS,kBAAC,MAAD;IAAI,WAAW,EAAO;IAAe,UAAA;GAAU,CAAA,GACxD,KAAe,kBAAC,KAAD;IAAG,WAAW,EAAO;IAAqB,UAAA;GAAe,CAAA,CACrE;EAEZ,CAAA,GAAA,kBAAC,OAAD;GAAK,WAAW,EAAG,EAAO,aAAa,EAAO,EAAO;GAAG,OAAO;GAC1D;EACA,CAAA,CACA;;AAEjB;AAqBA,SAAgB,EAAQ,EAAE,QAAK,cAAW,UAAO,aAAU,GAAG,KAAuB;CACjF,IAAM,IAA4B;EAAE,KAAK,EAAW,GAAK,CAAC;EAAG,GAAG;CAAM;CACtE,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,KAAK,CAAS;EAAG,OAAO;EAAY,GAAI;EAC7D;CACA,CAAA;AAEb;AAkBA,SAAgB,EAAY,EACxB,WAAQ,OACR,QACA,cACA,UACA,aACA,GAAG,KACc;CACjB,IAAM,IAA4B;EAAE,KAAK,EAAW,GAAK,CAAC;EAAG,GAAG;CAAM;CACtE,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,EAAO,IAAQ,CAAS;EAAG,OAAO;EAAY,GAAI;EAChF;CACA,CAAA;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"HoverCard.cjs","names":[],"sources":["../../../src/components/HoverCard/HoverCard.tsx"],"sourcesContent":["import { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./HoverCard.module.css\";\n\nexport type HoverCardPlacement = \"top\" | \"bottom\" | \"left\" | \"right\";\n\nexport interface HoverCardProps extends HTMLAttributes<HTMLDivElement> {\n /** Element the user hovers/focuses to reveal the card. */\n trigger: ReactNode;\n /** Card content shown while hovering/focusing the trigger or the card itself. */\n children: ReactNode;\n /** Delay in ms before opening on mouseenter/focus. Default 300. */\n openDelay?: number;\n /** Delay in ms before closing on mouseleave/blur. Default 150. */\n closeDelay?: number;\n /** Where the card is anchored relative to the trigger. Default \"bottom\". */\n placement?: HoverCardPlacement;\n}\n\n/**\n * Content preview shown when the trigger is hovered or focused.\n *\n * - Opens after `openDelay` on `mouseenter`/`focus`.\n * - Closes after `closeDelay` on `mouseleave`/`blur`.\n * - Positioned relative to the trigger via `placement`.\n * - The card is rendered as a labelled `role=\"dialog\"` region; the trigger stays keyboard focusable.\n *\n * @param props - The hover card props.\n * @returns The trigger wrapper and the anchored card when open.\n */\nexport function HoverCard({\n trigger,\n children,\n openDelay = 300,\n closeDelay = 150,\n placement = \"bottom\",\n className,\n ...rest\n}: HoverCardProps) {\n const [open, setOpen] = useState(false);\n const id = useId();\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearTimer = useCallback((): void => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n }, []);\n\n const scheduleOpen = useCallback((): void => {\n clearTimer();\n timerRef.current = setTimeout(() => setOpen(true), openDelay);\n }, [clearTimer, openDelay]);\n\n const scheduleClose = useCallback((): void => {\n clearTimer();\n timerRef.current = setTimeout(() => setOpen(false), closeDelay);\n }, [clearTimer, closeDelay]);\n\n useEffect(() => clearTimer, [clearTimer]);\n\n return (\n <span\n className={styles.root}\n onMouseEnter={scheduleOpen}\n onMouseLeave={scheduleClose}\n onFocus={scheduleOpen}\n onBlur={scheduleClose}\n >\n <span aria-describedby={open ? id : undefined} className={styles.trigger}>\n {trigger}\n </span>\n {open && (\n <div\n id={id}\n role=\"dialog\"\n className={cn(styles.card, styles[placement], className)}\n {...rest}\n >\n {children}\n </div>\n )}\n </span>\n );\n}\n"],"mappings":"gIA+BA,SAAgB,EAAU,CACtB,UACA,WACA,YAAY,IACZ,aAAa,IACb,YAAY,SACZ,YACA,GAAG,GACY,CACf,GAAM,CAAC,EAAM,IAAA,EAAA,EAAA,SAAA,CAAoB,EAAK,EAChC,GAAA,EAAA,EAAA,MAAA,CAAW,EACX,GAAA,EAAA,EAAA,OAAA,CAAwD,IAAI,EAE5D,GAAA,EAAA,EAAA,YAAA,KAAqC,CACnC,EAAS,UAAY,OACrB,aAAa,EAAS,OAAO,EAC7B,EAAS,QAAU,KAE3B,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,KAAuC,CACzC,EAAW,EACX,EAAS,QAAU,eAAiB,EAAQ,EAAI,EAAG,CAAS,CAChE,EAAG,CAAC,EAAY,CAAS,CAAC,EAEpB,GAAA,EAAA,EAAA,YAAA,KAAwC,CAC1C,EAAW,EACX,EAAS,QAAU,eAAiB,EAAQ,EAAK,EAAG,CAAU,CAClE,EAAG,CAAC,EAAY,CAAU,CAAC,EAI3B,OAFA,EAAA,EAAA,UAAA,KAAgB,EAAY,CAAC,CAAU,CAAC,GAGpC,EAAA,EAAA,KAAA,CAAC,OAAD,CACI,UAAW,EAAA,QAAO,KAClB,aAAc,EACd,aAAc,EACd,QAAS,EACT,OAAQ,WALZ,EAOI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,mBAAkB,EAAO,EAAK,IAAA,GAAW,UAAW,EAAA,QAAO,iBAC5D,CACC,CAAA,EACL,IACG,EAAA,EAAA,IAAA,CAAC,MAAD,CACQ,KACJ,KAAK,SACL,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,EAAA,QAAO,GAAY,CAAS,EACvD,GAAI,EAEH,UACA,CAAA,CAEP,GAEd"}
1
+ {"version":3,"file":"HoverCard.cjs","names":[],"sources":["../../../src/components/HoverCard/HoverCard.tsx"],"sourcesContent":["import { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./HoverCard.module.css\";\n\nexport type HoverCardPlacement = \"top\" | \"bottom\" | \"left\" | \"right\";\n\nexport interface HoverCardProps extends HTMLAttributes<HTMLDivElement> {\n /** Element the user hovers/focuses to reveal the card. */\n trigger: ReactNode;\n /** Card content shown while hovering/focusing the trigger or the card itself. */\n children: ReactNode;\n /** Delay in ms before opening on mouseenter/focus. Default 300. */\n openDelay?: number;\n /** Delay in ms before closing on mouseleave/blur. Default 150. */\n closeDelay?: number;\n /** Where the card is anchored relative to the trigger. Default \"bottom\". */\n placement?: HoverCardPlacement;\n}\n\n/**\n * Content preview shown when the trigger is hovered or focused.\n *\n * - Opens after `openDelay` on `mouseenter`/`focus`.\n * - Closes after `closeDelay` on `mouseleave`/`blur`.\n * - Positioned relative to the trigger via `placement`.\n * - The card is rendered as a labelled `role=\"dialog\"` region; the trigger stays keyboard focusable.\n *\n * @param props - The hover card props.\n * @returns The trigger wrapper and the anchored card when open.\n */\nexport function HoverCard({\n trigger,\n children,\n openDelay = 300,\n closeDelay = 150,\n placement = \"bottom\",\n className,\n ...rest\n}: HoverCardProps) {\n const [open, setOpen] = useState(false);\n const id = useId();\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearTimer = useCallback((): void => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n }, []);\n\n const scheduleOpen = useCallback((): void => {\n clearTimer();\n timerRef.current = setTimeout(() => setOpen(true), openDelay);\n }, [clearTimer, openDelay]);\n\n const scheduleClose = useCallback((): void => {\n clearTimer();\n timerRef.current = setTimeout(() => setOpen(false), closeDelay);\n }, [clearTimer, closeDelay]);\n\n useEffect(() => clearTimer, [clearTimer]);\n\n return (\n <span\n className={styles.root}\n onMouseEnter={scheduleOpen}\n onMouseLeave={scheduleClose}\n onFocus={scheduleOpen}\n onBlur={scheduleClose}\n >\n <span aria-describedby={open ? id : undefined} className={styles.trigger}>\n {trigger}\n </span>\n {open && (\n <div\n id={id}\n role=\"dialog\"\n className={cn(styles.card, styles[placement], className)}\n {...rest}\n >\n {children}\n </div>\n )}\n </span>\n );\n}\n"],"mappings":"gIA+BA,SAAgB,EAAU,CACtB,UACA,WACA,YAAY,IACZ,aAAa,IACb,YAAY,SACZ,YACA,GAAG,GACY,CACf,GAAM,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,CAAS,EAAK,EAChC,GAAA,EAAK,EAAA,MAAA,CAAM,EACX,GAAA,EAAW,EAAA,OAAA,CAA6C,IAAI,EAE5D,GAAA,EAAa,EAAA,YAAA,KAAwB,CACnC,EAAS,UAAY,OACrB,aAAa,EAAS,OAAO,EAC7B,EAAS,QAAU,KAE3B,EAAG,CAAC,CAAC,EAEC,GAAA,EAAe,EAAA,YAAA,KAAwB,CACzC,EAAW,EACX,EAAS,QAAU,eAAiB,EAAQ,EAAI,EAAG,CAAS,CAChE,EAAG,CAAC,EAAY,CAAS,CAAC,EAEpB,GAAA,EAAgB,EAAA,YAAA,KAAwB,CAC1C,EAAW,EACX,EAAS,QAAU,eAAiB,EAAQ,EAAK,EAAG,CAAU,CAClE,EAAG,CAAC,EAAY,CAAU,CAAC,EAI3B,OAFA,EAAA,EAAA,UAAA,KAAgB,EAAY,CAAC,CAAU,CAAC,GAGpC,EAAA,EAAA,KAAA,CAAC,OAAD,CACI,UAAW,EAAA,QAAO,KAClB,aAAc,EACd,aAAc,EACd,QAAS,EACT,OAAQ,EALZ,SAAA,EAOI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,mBAAkB,EAAO,EAAK,IAAA,GAAW,UAAW,EAAA,QAAO,QAC5D,SAAA,CACC,CAAA,EACL,IACG,EAAA,EAAA,IAAA,CAAC,MAAD,CACQ,KACJ,KAAK,SACL,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,EAAA,QAAO,GAAY,CAAS,EACvD,GAAI,EAEH,UACA,CAAA,CAEP,GAEd"}
@@ -1 +1 @@
1
- {"version":3,"file":"HoverCard.js","names":[],"sources":["../../../src/components/HoverCard/HoverCard.tsx"],"sourcesContent":["import { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./HoverCard.module.css\";\n\nexport type HoverCardPlacement = \"top\" | \"bottom\" | \"left\" | \"right\";\n\nexport interface HoverCardProps extends HTMLAttributes<HTMLDivElement> {\n /** Element the user hovers/focuses to reveal the card. */\n trigger: ReactNode;\n /** Card content shown while hovering/focusing the trigger or the card itself. */\n children: ReactNode;\n /** Delay in ms before opening on mouseenter/focus. Default 300. */\n openDelay?: number;\n /** Delay in ms before closing on mouseleave/blur. Default 150. */\n closeDelay?: number;\n /** Where the card is anchored relative to the trigger. Default \"bottom\". */\n placement?: HoverCardPlacement;\n}\n\n/**\n * Content preview shown when the trigger is hovered or focused.\n *\n * - Opens after `openDelay` on `mouseenter`/`focus`.\n * - Closes after `closeDelay` on `mouseleave`/`blur`.\n * - Positioned relative to the trigger via `placement`.\n * - The card is rendered as a labelled `role=\"dialog\"` region; the trigger stays keyboard focusable.\n *\n * @param props - The hover card props.\n * @returns The trigger wrapper and the anchored card when open.\n */\nexport function HoverCard({\n trigger,\n children,\n openDelay = 300,\n closeDelay = 150,\n placement = \"bottom\",\n className,\n ...rest\n}: HoverCardProps) {\n const [open, setOpen] = useState(false);\n const id = useId();\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearTimer = useCallback((): void => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n }, []);\n\n const scheduleOpen = useCallback((): void => {\n clearTimer();\n timerRef.current = setTimeout(() => setOpen(true), openDelay);\n }, [clearTimer, openDelay]);\n\n const scheduleClose = useCallback((): void => {\n clearTimer();\n timerRef.current = setTimeout(() => setOpen(false), closeDelay);\n }, [clearTimer, closeDelay]);\n\n useEffect(() => clearTimer, [clearTimer]);\n\n return (\n <span\n className={styles.root}\n onMouseEnter={scheduleOpen}\n onMouseLeave={scheduleClose}\n onFocus={scheduleOpen}\n onBlur={scheduleClose}\n >\n <span aria-describedby={open ? id : undefined} className={styles.trigger}>\n {trigger}\n </span>\n {open && (\n <div\n id={id}\n role=\"dialog\"\n className={cn(styles.card, styles[placement], className)}\n {...rest}\n >\n {children}\n </div>\n )}\n </span>\n );\n}\n"],"mappings":";;;;;AA+BA,SAAgB,EAAU,EACtB,YACA,aACA,eAAY,KACZ,gBAAa,KACb,eAAY,UACZ,cACA,GAAG,KACY;CACf,IAAM,CAAC,GAAM,KAAW,EAAS,EAAK,GAChC,IAAK,EAAM,GACX,IAAW,EAA6C,IAAI,GAE5D,IAAa,QAAwB;EACvC,AAAI,EAAS,YAAY,SACrB,aAAa,EAAS,OAAO,GAC7B,EAAS,UAAU;CAE3B,GAAG,CAAC,CAAC,GAEC,IAAe,QAAwB;EAEzC,AADA,EAAW,GACX,EAAS,UAAU,iBAAiB,EAAQ,EAAI,GAAG,CAAS;CAChE,GAAG,CAAC,GAAY,CAAS,CAAC,GAEpB,IAAgB,QAAwB;EAE1C,AADA,EAAW,GACX,EAAS,UAAU,iBAAiB,EAAQ,EAAK,GAAG,CAAU;CAClE,GAAG,CAAC,GAAY,CAAU,CAAC;CAI3B,OAFA,QAAgB,GAAY,CAAC,CAAU,CAAC,GAGpC,kBAAC,QAAD;EACI,WAAW,EAAO;EAClB,cAAc;EACd,cAAc;EACd,SAAS;EACT,QAAQ;YALZ,CAOI,kBAAC,QAAD;GAAM,oBAAkB,IAAO,IAAK,KAAA;GAAW,WAAW,EAAO;aAC5D;EACC,CAAA,GACL,KACG,kBAAC,OAAD;GACQ;GACJ,MAAK;GACL,WAAW,EAAG,EAAO,MAAM,EAAO,IAAY,CAAS;GACvD,GAAI;GAEH;EACA,CAAA,CAEP;;AAEd"}
1
+ {"version":3,"file":"HoverCard.js","names":[],"sources":["../../../src/components/HoverCard/HoverCard.tsx"],"sourcesContent":["import { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./HoverCard.module.css\";\n\nexport type HoverCardPlacement = \"top\" | \"bottom\" | \"left\" | \"right\";\n\nexport interface HoverCardProps extends HTMLAttributes<HTMLDivElement> {\n /** Element the user hovers/focuses to reveal the card. */\n trigger: ReactNode;\n /** Card content shown while hovering/focusing the trigger or the card itself. */\n children: ReactNode;\n /** Delay in ms before opening on mouseenter/focus. Default 300. */\n openDelay?: number;\n /** Delay in ms before closing on mouseleave/blur. Default 150. */\n closeDelay?: number;\n /** Where the card is anchored relative to the trigger. Default \"bottom\". */\n placement?: HoverCardPlacement;\n}\n\n/**\n * Content preview shown when the trigger is hovered or focused.\n *\n * - Opens after `openDelay` on `mouseenter`/`focus`.\n * - Closes after `closeDelay` on `mouseleave`/`blur`.\n * - Positioned relative to the trigger via `placement`.\n * - The card is rendered as a labelled `role=\"dialog\"` region; the trigger stays keyboard focusable.\n *\n * @param props - The hover card props.\n * @returns The trigger wrapper and the anchored card when open.\n */\nexport function HoverCard({\n trigger,\n children,\n openDelay = 300,\n closeDelay = 150,\n placement = \"bottom\",\n className,\n ...rest\n}: HoverCardProps) {\n const [open, setOpen] = useState(false);\n const id = useId();\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearTimer = useCallback((): void => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n }, []);\n\n const scheduleOpen = useCallback((): void => {\n clearTimer();\n timerRef.current = setTimeout(() => setOpen(true), openDelay);\n }, [clearTimer, openDelay]);\n\n const scheduleClose = useCallback((): void => {\n clearTimer();\n timerRef.current = setTimeout(() => setOpen(false), closeDelay);\n }, [clearTimer, closeDelay]);\n\n useEffect(() => clearTimer, [clearTimer]);\n\n return (\n <span\n className={styles.root}\n onMouseEnter={scheduleOpen}\n onMouseLeave={scheduleClose}\n onFocus={scheduleOpen}\n onBlur={scheduleClose}\n >\n <span aria-describedby={open ? id : undefined} className={styles.trigger}>\n {trigger}\n </span>\n {open && (\n <div\n id={id}\n role=\"dialog\"\n className={cn(styles.card, styles[placement], className)}\n {...rest}\n >\n {children}\n </div>\n )}\n </span>\n );\n}\n"],"mappings":";;;;;AA+BA,SAAgB,EAAU,EACtB,YACA,aACA,eAAY,KACZ,gBAAa,KACb,eAAY,UACZ,cACA,GAAG,KACY;CACf,IAAM,CAAC,GAAM,KAAW,EAAS,EAAK,GAChC,IAAK,EAAM,GACX,IAAW,EAA6C,IAAI,GAE5D,IAAa,QAAwB;EACvC,AAAI,EAAS,YAAY,SACrB,aAAa,EAAS,OAAO,GAC7B,EAAS,UAAU;CAE3B,GAAG,CAAC,CAAC,GAEC,IAAe,QAAwB;EAEzC,AADA,EAAW,GACX,EAAS,UAAU,iBAAiB,EAAQ,EAAI,GAAG,CAAS;CAChE,GAAG,CAAC,GAAY,CAAS,CAAC,GAEpB,IAAgB,QAAwB;EAE1C,AADA,EAAW,GACX,EAAS,UAAU,iBAAiB,EAAQ,EAAK,GAAG,CAAU;CAClE,GAAG,CAAC,GAAY,CAAU,CAAC;CAI3B,OAFA,QAAgB,GAAY,CAAC,CAAU,CAAC,GAGpC,kBAAC,QAAD;EACI,WAAW,EAAO;EAClB,cAAc;EACd,cAAc;EACd,SAAS;EACT,QAAQ;EALZ,UAAA,CAOI,kBAAC,QAAD;GAAM,oBAAkB,IAAO,IAAK,KAAA;GAAW,WAAW,EAAO;GAC5D,UAAA;EACC,CAAA,GACL,KACG,kBAAC,OAAD;GACQ;GACJ,MAAK;GACL,WAAW,EAAG,EAAO,MAAM,EAAO,IAAY,CAAS;GACvD,GAAI;GAEH;EACA,CAAA,CAEP;;AAEd"}
@@ -1 +1 @@
1
- {"version":3,"file":"Image.cjs","names":[],"sources":["../../../src/components/Image/Image.tsx"],"sourcesContent":["import type { ImgHTMLAttributes } from \"react\";\nimport { useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Image.module.css\";\n\nexport interface ImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, \"src\"> {\n /** Primary image source URL. */\n src: string;\n /** Fallback source swapped in once if the primary `src` fails to load. */\n fallback?: string;\n /** Alternative text describing the image (required for accessibility). */\n alt: string;\n /** When true (default) uses native lazy loading; otherwise loads eagerly. */\n lazy?: boolean;\n}\n\n/**\n * Renders an `<img>` with native lazy loading and a one-shot fallback.\n *\n * On the first load error the source is swapped to `fallback` (when provided),\n * guarded so a failing fallback cannot loop the `onError` handler.\n *\n * @param src - The primary image source URL.\n * @param fallback - Optional source used once when `src` fails to load.\n * @param alt - Accessible alternative text for the image.\n * @param lazy - Whether to use `loading=\"lazy\"` (default `true`).\n * @returns The rendered image element.\n */\nexport function Image({\n src,\n fallback,\n alt,\n lazy = true,\n className,\n onError,\n ...props\n}: ImageProps) {\n const [currentSrc, setCurrentSrc] = useState<string>(src);\n const [usedFallback, setUsedFallback] = useState<boolean>(false);\n\n return (\n <img\n src={currentSrc}\n alt={alt}\n loading={lazy ? \"lazy\" : \"eager\"}\n className={cn(styles.image, className)}\n onError={(event) => {\n if (fallback && !usedFallback && currentSrc !== fallback) {\n setUsedFallback(true);\n setCurrentSrc(fallback);\n }\n onError?.(event);\n }}\n {...props}\n />\n );\n}\n"],"mappings":"4HA4BA,SAAgB,EAAM,CAClB,MACA,WACA,MACA,OAAO,GACP,YACA,UACA,GAAG,GACQ,CACX,GAAM,CAAC,EAAY,IAAA,EAAA,EAAA,SAAA,CAAkC,CAAG,EAClD,CAAC,EAAc,IAAA,EAAA,EAAA,SAAA,CAAqC,EAAK,EAE/D,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,IAAK,EACA,MACL,QAAS,EAAO,OAAS,QACzB,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,CAAS,EACrC,QAAU,GAAU,CACZ,GAAY,CAAC,GAAgB,IAAe,IAC5C,EAAgB,EAAI,EACpB,EAAc,CAAQ,GAE1B,IAAU,CAAK,CACnB,EACA,GAAI,CACP,CAAA,CAET"}
1
+ {"version":3,"file":"Image.cjs","names":[],"sources":["../../../src/components/Image/Image.tsx"],"sourcesContent":["import type { ImgHTMLAttributes } from \"react\";\nimport { useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Image.module.css\";\n\nexport interface ImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, \"src\"> {\n /** Primary image source URL. */\n src: string;\n /** Fallback source swapped in once if the primary `src` fails to load. */\n fallback?: string;\n /** Alternative text describing the image (required for accessibility). */\n alt: string;\n /** When true (default) uses native lazy loading; otherwise loads eagerly. */\n lazy?: boolean;\n}\n\n/**\n * Renders an `<img>` with native lazy loading and a one-shot fallback.\n *\n * On the first load error the source is swapped to `fallback` (when provided),\n * guarded so a failing fallback cannot loop the `onError` handler.\n *\n * @param src - The primary image source URL.\n * @param fallback - Optional source used once when `src` fails to load.\n * @param alt - Accessible alternative text for the image.\n * @param lazy - Whether to use `loading=\"lazy\"` (default `true`).\n * @returns The rendered image element.\n */\nexport function Image({\n src,\n fallback,\n alt,\n lazy = true,\n className,\n onError,\n ...props\n}: ImageProps) {\n const [currentSrc, setCurrentSrc] = useState<string>(src);\n const [usedFallback, setUsedFallback] = useState<boolean>(false);\n\n return (\n <img\n src={currentSrc}\n alt={alt}\n loading={lazy ? \"lazy\" : \"eager\"}\n className={cn(styles.image, className)}\n onError={(event) => {\n if (fallback && !usedFallback && currentSrc !== fallback) {\n setUsedFallback(true);\n setCurrentSrc(fallback);\n }\n onError?.(event);\n }}\n {...props}\n />\n );\n}\n"],"mappings":"4HA4BA,SAAgB,EAAM,CAClB,MACA,WACA,MACA,OAAO,GACP,YACA,UACA,GAAG,GACQ,CACX,GAAM,CAAC,EAAY,IAAA,EAAiB,EAAA,SAAA,CAAiB,CAAG,EAClD,CAAC,EAAc,IAAA,EAAmB,EAAA,SAAA,CAAkB,EAAK,EAE/D,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,IAAK,EACA,MACL,QAAS,EAAO,OAAS,QACzB,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,CAAS,EACrC,QAAU,GAAU,CACZ,GAAY,CAAC,GAAgB,IAAe,IAC5C,EAAgB,EAAI,EACpB,EAAc,CAAQ,GAE1B,IAAU,CAAK,CACnB,EACA,GAAI,CACP,CAAA,CAET"}