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":"Modal.js","names":[],"sources":["../../../src/components/Modal/Modal.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count, function-lines — size, fullscreen and\n * fullscreenOnMobile are three distinct decisions (a fixed width, always full, full\n * only on a phone), and the rest is the dialog contract: open, onClose, title,\n * children, footer, closeOnBackdrop, closeOnEsc, hideCloseButton. The body is the\n * focus trap and the scroll lock, which must be installed and torn down together.\n */\nimport { useEffect, useId } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Modal.module.css\";\n\nexport type ModalSize = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\";\n\nexport interface ModalProps {\n open: boolean;\n onClose: () => void;\n title?: ReactNode;\n children?: ReactNode;\n footer?: ReactNode;\n size?: ModalSize;\n closeOnBackdrop?: boolean;\n closeOnEsc?: boolean;\n className?: string;\n hideCloseButton?: boolean;\n /** Force fullscreen at all breakpoints. */\n fullscreen?: boolean;\n /** Auto-fullscreen on mobile viewports (< 640px). Default `false`. */\n fullscreenOnMobile?: boolean;\n /**\n * Accessible name for the dialog. Only needed when there is no `title` —\n * with a `title` the dialog is named by it through `aria-labelledby`.\n */\n \"aria-label\"?: string;\n}\n\n/**\n * Portal-rendered modal dialog with backdrop, Esc handler, and slots for\n * header/body/footer. Locks body scroll while open.\n *\n * The `dialog` role needs an accessible name: a `title` supplies it via\n * `aria-labelledby`, and a titleless dialog should pass `aria-label`. The\n * header heading is only rendered when there is a title, so a close-button-only\n * header does not leave an empty `h3` behind.\n */\nexport function Modal({\n open,\n onClose,\n title,\n children,\n footer,\n size = \"md\",\n closeOnBackdrop = true,\n closeOnEsc = true,\n className,\n hideCloseButton = false,\n fullscreen = false,\n fullscreenOnMobile = false,\n \"aria-label\": ariaLabel,\n}: ModalProps) {\n const titleId = useId();\n useEffect(() => {\n if (!open) return;\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n\n const handleKey = (event: KeyboardEvent): void => {\n if (closeOnEsc && event.key === \"Escape\") onClose();\n };\n window.addEventListener(\"keydown\", handleKey);\n\n return () => {\n document.body.style.overflow = previousOverflow;\n window.removeEventListener(\"keydown\", handleKey);\n };\n }, [open, closeOnEsc, onClose]);\n\n if (!open || typeof document === \"undefined\") return null;\n\n return createPortal(\n <div\n className={styles.overlay}\n role=\"presentation\"\n onClick={() => {\n if (closeOnBackdrop) onClose();\n }}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n aria-label={title ? undefined : ariaLabel}\n className={cn(\n styles.dialog,\n sizeClassName(size),\n fullscreen && styles.fullscreen,\n fullscreenOnMobile && styles.fullscreenOnMobile,\n className,\n )}\n onClick={(event) => event.stopPropagation()}\n >\n {(title || !hideCloseButton) && (\n <header className={styles.header}>\n {title && (\n <h3 id={titleId} className={styles.title}>\n {title}\n </h3>\n )}\n {!hideCloseButton && (\n <button\n type=\"button\"\n className={styles.close}\n aria-label=\"Fechar\"\n onClick={onClose}\n >\n <CloseIcon />\n </button>\n )}\n </header>\n )}\n <div className={styles.body}>{children}</div>\n {footer && <footer className={styles.footer}>{footer}</footer>}\n </div>\n </div>,\n document.body,\n );\n}\n\nfunction sizeClassName(size: ModalSize): string | undefined {\n if (size === \"2xl\") return styles.size2xl;\n if (size === \"3xl\") return styles.size3xl;\n return styles[size];\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 6l12 12M6 18L18 6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":";;;;;;AA8CA,SAAgB,EAAM,EAClB,SACA,YACA,UACA,aACA,WACA,UAAO,MACP,qBAAkB,IAClB,gBAAa,IACb,cACA,qBAAkB,IAClB,gBAAa,IACb,wBAAqB,IACrB,cAAc,KACH;CACX,IAAM,IAAU,EAAM;CAmBtB,OAlBA,QAAgB;EACZ,IAAI,CAAC,GAAM;EACX,IAAM,IAAmB,SAAS,KAAK,MAAM;EAC7C,SAAS,KAAK,MAAM,WAAW;EAE/B,IAAM,KAAa,MAA+B;GAC9C,AAAI,KAAc,EAAM,QAAQ,YAAU,EAAQ;EACtD;EAGA,OAFA,OAAO,iBAAiB,WAAW,CAAS,SAE/B;GAET,AADA,SAAS,KAAK,MAAM,WAAW,GAC/B,OAAO,oBAAoB,WAAW,CAAS;EACnD;CACJ,GAAG;EAAC;EAAM;EAAY;CAAO,CAAC,GAE1B,CAAC,KAAQ,OAAO,WAAa,MAAoB,OAE9C,EACH,kBAAC,OAAD;EACI,WAAW,EAAO;EAClB,MAAK;EACL,eAAe;GACX,AAAI,KAAiB,EAAQ;EACjC;YAEA,kBAAC,OAAD;GACI,MAAK;GACL,cAAW;GACX,mBAAiB,IAAQ,IAAU,KAAA;GACnC,cAAY,IAAQ,KAAA,IAAY;GAChC,WAAW,EACP,EAAO,QACP,EAAc,CAAI,GAClB,KAAc,EAAO,YACrB,KAAsB,EAAO,oBAC7B,CACJ;GACA,UAAU,MAAU,EAAM,gBAAgB;aAZ9C;KAcM,KAAS,CAAC,MACR,kBAAC,UAAD;KAAQ,WAAW,EAAO;eAA1B,CACK,KACG,kBAAC,MAAD;MAAI,IAAI;MAAS,WAAW,EAAO;gBAC9B;KACD,CAAA,GAEP,CAAC,KACE,kBAAC,UAAD;MACI,MAAK;MACL,WAAW,EAAO;MAClB,cAAW;MACX,SAAS;gBAET,kBAAC,GAAD,CAAY,CAAA;KACR,CAAA,CAER;;IAEZ,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAO;IAAc,CAAA;IAC3C,KAAU,kBAAC,UAAD;KAAQ,WAAW,EAAO;eAAS;IAAe,CAAA;GAC5D;;CACJ,CAAA,GACL,SAAS,IACb;AACJ;AAEA,SAAS,EAAc,GAAqC;CAGxD,OAFI,MAAS,QAAc,EAAO,UAC9B,MAAS,QAAc,EAAO,UAC3B,EAAO;AAClB;AAEA,SAAS,IAAY;CACjB,OACI,kBAAC,OAAD;EAAK,OAAM;EAAK,QAAO;EAAK,SAAQ;EAAY,MAAK;YACjD,kBAAC,QAAD;GACI,GAAE;GACF,QAAO;GACP,aAAY;GACZ,eAAc;EACjB,CAAA;CACA,CAAA;AAEb"}
1
+ {"version":3,"file":"Modal.js","names":[],"sources":["../../../src/components/Modal/Modal.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count, function-lines — size, fullscreen and\n * fullscreenOnMobile are three distinct decisions (a fixed width, always full, full\n * only on a phone), and the rest is the dialog contract: open, onClose, title,\n * children, footer, closeOnBackdrop, closeOnEsc, hideCloseButton. The body is the\n * focus trap and the scroll lock, which must be installed and torn down together.\n */\nimport { useEffect, useId } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Modal.module.css\";\n\nexport type ModalSize = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\";\n\nexport interface ModalProps {\n open: boolean;\n onClose: () => void;\n title?: ReactNode;\n children?: ReactNode;\n footer?: ReactNode;\n size?: ModalSize;\n closeOnBackdrop?: boolean;\n closeOnEsc?: boolean;\n className?: string;\n hideCloseButton?: boolean;\n /** Force fullscreen at all breakpoints. */\n fullscreen?: boolean;\n /** Auto-fullscreen on mobile viewports (< 640px). Default `false`. */\n fullscreenOnMobile?: boolean;\n /**\n * Accessible name for the dialog. Only needed when there is no `title` —\n * with a `title` the dialog is named by it through `aria-labelledby`.\n */\n \"aria-label\"?: string;\n}\n\n/**\n * Portal-rendered modal dialog with backdrop, Esc handler, and slots for\n * header/body/footer. Locks body scroll while open.\n *\n * The `dialog` role needs an accessible name: a `title` supplies it via\n * `aria-labelledby`, and a titleless dialog should pass `aria-label`. The\n * header heading is only rendered when there is a title, so a close-button-only\n * header does not leave an empty `h3` behind.\n */\nexport function Modal({\n open,\n onClose,\n title,\n children,\n footer,\n size = \"md\",\n closeOnBackdrop = true,\n closeOnEsc = true,\n className,\n hideCloseButton = false,\n fullscreen = false,\n fullscreenOnMobile = false,\n \"aria-label\": ariaLabel,\n}: ModalProps) {\n const titleId = useId();\n useEffect(() => {\n if (!open) return;\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n\n const handleKey = (event: KeyboardEvent): void => {\n if (closeOnEsc && event.key === \"Escape\") onClose();\n };\n window.addEventListener(\"keydown\", handleKey);\n\n return () => {\n document.body.style.overflow = previousOverflow;\n window.removeEventListener(\"keydown\", handleKey);\n };\n }, [open, closeOnEsc, onClose]);\n\n if (!open || typeof document === \"undefined\") return null;\n\n return createPortal(\n <div\n className={styles.overlay}\n role=\"presentation\"\n onClick={() => {\n if (closeOnBackdrop) onClose();\n }}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n aria-label={title ? undefined : ariaLabel}\n className={cn(\n styles.dialog,\n sizeClassName(size),\n fullscreen && styles.fullscreen,\n fullscreenOnMobile && styles.fullscreenOnMobile,\n className,\n )}\n onClick={(event) => event.stopPropagation()}\n >\n {(title || !hideCloseButton) && (\n <header className={styles.header}>\n {title && (\n <h3 id={titleId} className={styles.title}>\n {title}\n </h3>\n )}\n {!hideCloseButton && (\n <button\n type=\"button\"\n className={styles.close}\n aria-label=\"Fechar\"\n onClick={onClose}\n >\n <CloseIcon />\n </button>\n )}\n </header>\n )}\n <div className={styles.body}>{children}</div>\n {footer && <footer className={styles.footer}>{footer}</footer>}\n </div>\n </div>,\n document.body,\n );\n}\n\nfunction sizeClassName(size: ModalSize): string | undefined {\n if (size === \"2xl\") return styles.size2xl;\n if (size === \"3xl\") return styles.size3xl;\n return styles[size];\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 6l12 12M6 18L18 6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":";;;;;;AA8CA,SAAgB,EAAM,EAClB,SACA,YACA,UACA,aACA,WACA,UAAO,MACP,qBAAkB,IAClB,gBAAa,IACb,cACA,qBAAkB,IAClB,gBAAa,IACb,wBAAqB,IACrB,cAAc,KACH;CACX,IAAM,IAAU,EAAM;CAmBtB,OAlBA,QAAgB;EACZ,IAAI,CAAC,GAAM;EACX,IAAM,IAAmB,SAAS,KAAK,MAAM;EAC7C,SAAS,KAAK,MAAM,WAAW;EAE/B,IAAM,KAAa,MAA+B;GAC9C,AAAI,KAAc,EAAM,QAAQ,YAAU,EAAQ;EACtD;EAGA,OAFA,OAAO,iBAAiB,WAAW,CAAS,SAE/B;GAET,AADA,SAAS,KAAK,MAAM,WAAW,GAC/B,OAAO,oBAAoB,WAAW,CAAS;EACnD;CACJ,GAAG;EAAC;EAAM;EAAY;CAAO,CAAC,GAE1B,CAAC,KAAQ,OAAO,WAAa,MAAoB,OAE9C,EACH,kBAAC,OAAD;EACI,WAAW,EAAO;EAClB,MAAK;EACL,eAAe;GACX,AAAI,KAAiB,EAAQ;EACjC;EAEA,UAAA,kBAAC,OAAD;GACI,MAAK;GACL,cAAW;GACX,mBAAiB,IAAQ,IAAU,KAAA;GACnC,cAAY,IAAQ,KAAA,IAAY;GAChC,WAAW,EACP,EAAO,QACP,EAAc,CAAI,GAClB,KAAc,EAAO,YACrB,KAAsB,EAAO,oBAC7B,CACJ;GACA,UAAU,MAAU,EAAM,gBAAgB;GAZ9C,UAAA;KAcM,KAAS,CAAC,MACR,kBAAC,UAAD;KAAQ,WAAW,EAAO;KAA1B,UAAA,CACK,KACG,kBAAC,MAAD;MAAI,IAAI;MAAS,WAAW,EAAO;MAC9B,UAAA;KACD,CAAA,GAEP,CAAC,KACE,kBAAC,UAAD;MACI,MAAK;MACL,WAAW,EAAO;MAClB,cAAW;MACX,SAAS;MAET,UAAA,kBAAC,GAAD,CAAY,CAAA;KACR,CAAA,CAER;;IAEZ,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAO;IAAc,CAAA;IAC3C,KAAU,kBAAC,UAAD;KAAQ,WAAW,EAAO;KAAS,UAAA;IAAe,CAAA;GAC5D;;CACJ,CAAA,GACL,SAAS,IACb;AACJ;AAEA,SAAS,EAAc,GAAqC;CAGxD,OAFI,MAAS,QAAc,EAAO,UAC9B,MAAS,QAAc,EAAO,UAC3B,EAAO;AAClB;AAEA,SAAS,IAAY;CACjB,OACI,kBAAC,OAAD;EAAK,OAAM;EAAK,QAAO;EAAK,SAAQ;EAAY,MAAK;EACjD,UAAA,kBAAC,QAAD;GACI,GAAE;GACF,QAAO;GACP,aAAY;GACZ,eAAc;EACjB,CAAA;CACA,CAAA;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"ModalsManager.cjs","names":[],"sources":["../../../src/components/ModalsManager/ModalsManager.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines — the imperative API (open, close, confirm, prompt) and\n * the stack that renders it live in one file so the returned promise and the mounted\n * element cannot drift apart.\n */\nimport { createContext, useCallback, useContext, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { ConfirmDialog } from \"@/components/ConfirmDialog\";\nimport { Modal } from \"@/components/Modal\";\nimport type { ModalSize } from \"@/components/Modal\";\nimport styles from \"./ModalsManager.module.css\";\n\n/** Options accepted by {@link ModalsApi.open}. */\nexport interface OpenModalOptions {\n /** Header title. */\n title?: ReactNode;\n /** Modal body content. */\n children: ReactNode;\n /** Dialog size. Default `md`. */\n size?: ModalSize;\n /** Allow closing by clicking the backdrop. Default `true`. */\n closeOnBackdrop?: boolean;\n /** Allow closing with the Esc key. Default `true`. */\n closeOnEsc?: boolean;\n /** Hide the header close button. */\n hideCloseButton?: boolean;\n /** Called after the modal is removed from the stack. */\n onClose?: () => void;\n}\n\n/** Options accepted by {@link ModalsApi.confirm}. */\nexport interface ConfirmModalOptions {\n /** Header title. */\n title?: ReactNode;\n /** Prompt message rendered in the dialog body. */\n message: ReactNode;\n /** Confirm button label. Default `Confirmar`. */\n confirmLabel?: string;\n /** Cancel button label. Default `Cancelar`. */\n cancelLabel?: string;\n /** Render the confirm button in the danger variant. */\n danger?: boolean;\n /** Called when the user confirms. */\n onConfirm?: () => void | Promise<void>;\n /** Called when the user cancels or dismisses. */\n onCancel?: () => void;\n}\n\n/** Imperative API returned by {@link useModals}. */\nexport interface ModalsApi {\n /** Push a content modal. Returns its stack id. */\n open: (options: OpenModalOptions) => string;\n /** Push a confirmation dialog. Returns its stack id. */\n confirm: (options: ConfirmModalOptions) => string;\n /** Remove the modal with the given id. */\n close: (id: string) => void;\n /** Remove every modal from the stack. */\n closeAll: () => void;\n}\n\ninterface ContentEntry {\n kind: \"content\";\n id: string;\n options: OpenModalOptions;\n}\n\ninterface ConfirmEntry {\n kind: \"confirm\";\n id: string;\n options: ConfirmModalOptions;\n}\n\ntype StackEntry = ContentEntry | ConfirmEntry;\n\nconst ModalsContext = createContext<ModalsApi | null>(null);\n\n/** Props for {@link ModalsProvider}. */\nexport interface ModalsProviderProps {\n children: ReactNode;\n}\n\n/**\n * Provides imperative modal control via {@link useModals} and renders the open\n * modal stack. Mount once near the app root.\n *\n * @example\n * <ModalsProvider>\n * <App />\n * </ModalsProvider>\n */\nexport function ModalsProvider({ children }: ModalsProviderProps) {\n const [stack, setStack] = useState<StackEntry[]>([]);\n const counter = useRef(0);\n\n const nextId = useCallback((): string => {\n counter.current += 1;\n return `modal-${counter.current}`;\n }, []);\n\n const close = useCallback((id: string): void => {\n setStack((current) => current.filter((entry) => entry.id !== id));\n }, []);\n\n const closeAll = useCallback((): void => {\n setStack([]);\n }, []);\n\n const open = useCallback(\n (options: OpenModalOptions): string => {\n const id = nextId();\n setStack((current) => [...current, { kind: \"content\", id, options }]);\n return id;\n },\n [nextId],\n );\n\n const confirm = useCallback(\n (options: ConfirmModalOptions): string => {\n const id = nextId();\n setStack((current) => [...current, { kind: \"confirm\", id, options }]);\n return id;\n },\n [nextId],\n );\n\n const api = useMemo<ModalsApi>(\n () => ({ open, confirm, close, closeAll }),\n [open, confirm, close, closeAll],\n );\n\n return (\n <ModalsContext.Provider value={api}>\n {children}\n <div className={styles.stack}>\n {stack.map((entry) =>\n entry.kind === \"content\" ? (\n <ContentModal key={entry.id} entry={entry} close={close} />\n ) : (\n <ConfirmModal key={entry.id} entry={entry} close={close} />\n ),\n )}\n </div>\n </ModalsContext.Provider>\n );\n}\n\ninterface ContentModalProps {\n entry: ContentEntry;\n close: (id: string) => void;\n}\n\nfunction ContentModal({ entry, close }: ContentModalProps) {\n const { options, id } = entry;\n const handleClose = (): void => {\n options.onClose?.();\n close(id);\n };\n return (\n <Modal\n open\n onClose={handleClose}\n title={options.title}\n size={options.size}\n closeOnBackdrop={options.closeOnBackdrop}\n closeOnEsc={options.closeOnEsc}\n hideCloseButton={options.hideCloseButton}\n >\n {options.children}\n </Modal>\n );\n}\n\ninterface ConfirmModalProps {\n entry: ConfirmEntry;\n close: (id: string) => void;\n}\n\nfunction ConfirmModal({ entry, close }: ConfirmModalProps) {\n const { options, id } = entry;\n const [loading, setLoading] = useState(false);\n\n const handleConfirm = async (): Promise<void> => {\n try {\n setLoading(true);\n await options.onConfirm?.();\n } finally {\n setLoading(false);\n close(id);\n }\n };\n\n const handleCancel = (): void => {\n options.onCancel?.();\n close(id);\n };\n\n return (\n <ConfirmDialog\n open\n title={options.title ?? \"\"}\n description={options.message}\n confirmLabel={options.confirmLabel}\n cancelLabel={options.cancelLabel}\n variant={options.danger ? \"danger\" : \"primary\"}\n loading={loading}\n onConfirm={handleConfirm}\n onCancel={handleCancel}\n />\n );\n}\n\n/**\n * Access the imperative modals API. Must be used within a {@link ModalsProvider}.\n *\n * @example\n * const modals = useModals();\n * modals.confirm({ message: \"Excluir item?\", danger: true, onConfirm: del });\n *\n * @throws Error when called outside a {@link ModalsProvider}.\n */\nexport function useModals(): ModalsApi {\n const api = useContext(ModalsContext);\n if (api === null) {\n throw new Error(\"useModals must be used within a <ModalsProvider>\");\n }\n return api;\n}\n"],"mappings":"oLA0EA,IAAM,GAAA,EAAA,EAAA,cAAA,CAAgD,IAAI,EAgB1D,SAAgB,EAAe,CAAE,YAAiC,CAC9D,GAAM,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,CAAmC,CAAC,CAAC,EAC7C,GAAA,EAAA,EAAA,OAAA,CAAiB,CAAC,EAElB,GAAA,EAAA,EAAA,YAAA,MACF,EAAQ,SAAW,EACZ,SAAS,EAAQ,WACzB,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,CAAqB,GAAqB,CAC5C,EAAU,GAAY,EAAQ,OAAQ,GAAU,EAAM,KAAO,CAAE,CAAC,CACpE,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,KAAmC,CACrC,EAAS,CAAC,CAAC,CACf,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,CACD,GAAsC,CACnC,IAAM,EAAK,EAAO,EAElB,OADA,EAAU,GAAY,CAAC,GAAG,EAAS,CAAE,KAAM,UAAW,KAAI,SAAQ,CAAC,CAAC,EAC7D,CACX,EACA,CAAC,CAAM,CACX,EAEM,GAAA,EAAA,EAAA,YAAA,CACD,GAAyC,CACtC,IAAM,EAAK,EAAO,EAElB,OADA,EAAU,GAAY,CAAC,GAAG,EAAS,CAAE,KAAM,UAAW,KAAI,SAAQ,CAAC,CAAC,EAC7D,CACX,EACA,CAAC,CAAM,CACX,EAEM,GAAA,EAAA,EAAA,QAAA,MACK,CAAE,OAAM,UAAS,QAAO,UAAS,GACxC,CAAC,EAAM,EAAS,EAAO,CAAQ,CACnC,EAEA,OACI,EAAA,EAAA,KAAA,CAAC,EAAc,SAAf,CAAwB,MAAO,WAA/B,CACK,GACD,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,eAClB,EAAM,IAAK,GACR,EAAM,OAAS,WACX,EAAA,EAAA,IAAA,CAAC,EAAD,CAAoC,QAAc,OAAQ,EAAvC,EAAM,EAAiC,GAE1D,EAAA,EAAA,IAAA,CAAC,EAAD,CAAoC,QAAc,OAAQ,EAAvC,EAAM,EAAiC,CAElE,CACC,CAAA,CACe,GAEhC,CAOA,SAAS,EAAa,CAAE,QAAO,SAA4B,CACvD,GAAM,CAAE,UAAS,MAAO,EAKxB,OACI,EAAA,EAAA,IAAA,CAAC,EAAA,MAAD,CACI,KAAA,GACA,YAPwB,CAC5B,EAAQ,UAAU,EAClB,EAAM,CAAE,CACZ,EAKQ,MAAO,EAAQ,MACf,KAAM,EAAQ,KACd,gBAAiB,EAAQ,gBACzB,WAAY,EAAQ,WACpB,gBAAiB,EAAQ,yBAExB,EAAQ,QACN,CAAA,CAEf,CAOA,SAAS,EAAa,CAAE,QAAO,SAA4B,CACvD,GAAM,CAAE,UAAS,MAAO,EAClB,CAAC,EAAS,IAAA,EAAA,EAAA,SAAA,CAAuB,EAAK,EAiB5C,OACI,EAAA,EAAA,IAAA,CAAC,EAAA,cAAD,CACI,KAAA,GACA,MAAO,EAAQ,OAAS,GACxB,YAAa,EAAQ,QACrB,aAAc,EAAQ,aACtB,YAAa,EAAQ,YACrB,QAAS,EAAQ,OAAS,SAAW,UAC5B,UACT,UAAW,SAxB8B,CAC7C,GAAI,CACA,EAAW,EAAI,EACf,MAAM,EAAQ,YAAY,CAC9B,QAAU,CACN,EAAW,EAAK,EAChB,EAAM,CAAE,CACZ,CACJ,EAiBQ,aAfyB,CAC7B,EAAQ,WAAW,EACnB,EAAM,CAAE,CACZ,CAaK,CAAA,CAET,CAWA,SAAgB,GAAuB,CACnC,IAAM,GAAA,EAAA,EAAA,WAAA,CAAiB,CAAa,EACpC,GAAI,IAAQ,KACR,MAAU,MAAM,kDAAkD,EAEtE,OAAO,CACX"}
1
+ {"version":3,"file":"ModalsManager.cjs","names":[],"sources":["../../../src/components/ModalsManager/ModalsManager.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines — the imperative API (open, close, confirm, prompt) and\n * the stack that renders it live in one file so the returned promise and the mounted\n * element cannot drift apart.\n */\nimport { createContext, useCallback, useContext, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { ConfirmDialog } from \"@/components/ConfirmDialog\";\nimport { Modal } from \"@/components/Modal\";\nimport type { ModalSize } from \"@/components/Modal\";\nimport styles from \"./ModalsManager.module.css\";\n\n/** Options accepted by {@link ModalsApi.open}. */\nexport interface OpenModalOptions {\n /** Header title. */\n title?: ReactNode;\n /** Modal body content. */\n children: ReactNode;\n /** Dialog size. Default `md`. */\n size?: ModalSize;\n /** Allow closing by clicking the backdrop. Default `true`. */\n closeOnBackdrop?: boolean;\n /** Allow closing with the Esc key. Default `true`. */\n closeOnEsc?: boolean;\n /** Hide the header close button. */\n hideCloseButton?: boolean;\n /** Called after the modal is removed from the stack. */\n onClose?: () => void;\n}\n\n/** Options accepted by {@link ModalsApi.confirm}. */\nexport interface ConfirmModalOptions {\n /** Header title. */\n title?: ReactNode;\n /** Prompt message rendered in the dialog body. */\n message: ReactNode;\n /** Confirm button label. Default `Confirmar`. */\n confirmLabel?: string;\n /** Cancel button label. Default `Cancelar`. */\n cancelLabel?: string;\n /** Render the confirm button in the danger variant. */\n danger?: boolean;\n /** Called when the user confirms. */\n onConfirm?: () => void | Promise<void>;\n /** Called when the user cancels or dismisses. */\n onCancel?: () => void;\n}\n\n/** Imperative API returned by {@link useModals}. */\nexport interface ModalsApi {\n /** Push a content modal. Returns its stack id. */\n open: (options: OpenModalOptions) => string;\n /** Push a confirmation dialog. Returns its stack id. */\n confirm: (options: ConfirmModalOptions) => string;\n /** Remove the modal with the given id. */\n close: (id: string) => void;\n /** Remove every modal from the stack. */\n closeAll: () => void;\n}\n\ninterface ContentEntry {\n kind: \"content\";\n id: string;\n options: OpenModalOptions;\n}\n\ninterface ConfirmEntry {\n kind: \"confirm\";\n id: string;\n options: ConfirmModalOptions;\n}\n\ntype StackEntry = ContentEntry | ConfirmEntry;\n\nconst ModalsContext = createContext<ModalsApi | null>(null);\n\n/** Props for {@link ModalsProvider}. */\nexport interface ModalsProviderProps {\n children: ReactNode;\n}\n\n/**\n * Provides imperative modal control via {@link useModals} and renders the open\n * modal stack. Mount once near the app root.\n *\n * @example\n * <ModalsProvider>\n * <App />\n * </ModalsProvider>\n */\nexport function ModalsProvider({ children }: ModalsProviderProps) {\n const [stack, setStack] = useState<StackEntry[]>([]);\n const counter = useRef(0);\n\n const nextId = useCallback((): string => {\n counter.current += 1;\n return `modal-${counter.current}`;\n }, []);\n\n const close = useCallback((id: string): void => {\n setStack((current) => current.filter((entry) => entry.id !== id));\n }, []);\n\n const closeAll = useCallback((): void => {\n setStack([]);\n }, []);\n\n const open = useCallback(\n (options: OpenModalOptions): string => {\n const id = nextId();\n setStack((current) => [...current, { kind: \"content\", id, options }]);\n return id;\n },\n [nextId],\n );\n\n const confirm = useCallback(\n (options: ConfirmModalOptions): string => {\n const id = nextId();\n setStack((current) => [...current, { kind: \"confirm\", id, options }]);\n return id;\n },\n [nextId],\n );\n\n const api = useMemo<ModalsApi>(\n () => ({ open, confirm, close, closeAll }),\n [open, confirm, close, closeAll],\n );\n\n return (\n <ModalsContext.Provider value={api}>\n {children}\n <div className={styles.stack}>\n {stack.map((entry) =>\n entry.kind === \"content\" ? (\n <ContentModal key={entry.id} entry={entry} close={close} />\n ) : (\n <ConfirmModal key={entry.id} entry={entry} close={close} />\n ),\n )}\n </div>\n </ModalsContext.Provider>\n );\n}\n\ninterface ContentModalProps {\n entry: ContentEntry;\n close: (id: string) => void;\n}\n\nfunction ContentModal({ entry, close }: ContentModalProps) {\n const { options, id } = entry;\n const handleClose = (): void => {\n options.onClose?.();\n close(id);\n };\n return (\n <Modal\n open\n onClose={handleClose}\n title={options.title}\n size={options.size}\n closeOnBackdrop={options.closeOnBackdrop}\n closeOnEsc={options.closeOnEsc}\n hideCloseButton={options.hideCloseButton}\n >\n {options.children}\n </Modal>\n );\n}\n\ninterface ConfirmModalProps {\n entry: ConfirmEntry;\n close: (id: string) => void;\n}\n\nfunction ConfirmModal({ entry, close }: ConfirmModalProps) {\n const { options, id } = entry;\n const [loading, setLoading] = useState(false);\n\n const handleConfirm = async (): Promise<void> => {\n try {\n setLoading(true);\n await options.onConfirm?.();\n } finally {\n setLoading(false);\n close(id);\n }\n };\n\n const handleCancel = (): void => {\n options.onCancel?.();\n close(id);\n };\n\n return (\n <ConfirmDialog\n open\n title={options.title ?? \"\"}\n description={options.message}\n confirmLabel={options.confirmLabel}\n cancelLabel={options.cancelLabel}\n variant={options.danger ? \"danger\" : \"primary\"}\n loading={loading}\n onConfirm={handleConfirm}\n onCancel={handleCancel}\n />\n );\n}\n\n/**\n * Access the imperative modals API. Must be used within a {@link ModalsProvider}.\n *\n * @example\n * const modals = useModals();\n * modals.confirm({ message: \"Excluir item?\", danger: true, onConfirm: del });\n *\n * @throws Error when called outside a {@link ModalsProvider}.\n */\nexport function useModals(): ModalsApi {\n const api = useContext(ModalsContext);\n if (api === null) {\n throw new Error(\"useModals must be used within a <ModalsProvider>\");\n }\n return api;\n}\n"],"mappings":"oLA0EA,IAAM,GAAA,EAAgB,EAAA,cAAA,CAAgC,IAAI,EAgB1D,SAAgB,EAAe,CAAE,YAAiC,CAC9D,GAAM,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAuB,CAAC,CAAC,EAC7C,GAAA,EAAU,EAAA,OAAA,CAAO,CAAC,EAElB,GAAA,EAAS,EAAA,YAAA,MACX,EAAQ,SAAW,EACZ,SAAS,EAAQ,WACzB,CAAC,CAAC,EAEC,GAAA,EAAQ,EAAA,YAAA,CAAa,GAAqB,CAC5C,EAAU,GAAY,EAAQ,OAAQ,GAAU,EAAM,KAAO,CAAE,CAAC,CACpE,EAAG,CAAC,CAAC,EAEC,GAAA,EAAW,EAAA,YAAA,KAAwB,CACrC,EAAS,CAAC,CAAC,CACf,EAAG,CAAC,CAAC,EAEC,GAAA,EAAO,EAAA,YAAA,CACR,GAAsC,CACnC,IAAM,EAAK,EAAO,EAElB,OADA,EAAU,GAAY,CAAC,GAAG,EAAS,CAAE,KAAM,UAAW,KAAI,SAAQ,CAAC,CAAC,EAC7D,CACX,EACA,CAAC,CAAM,CACX,EAEM,GAAA,EAAU,EAAA,YAAA,CACX,GAAyC,CACtC,IAAM,EAAK,EAAO,EAElB,OADA,EAAU,GAAY,CAAC,GAAG,EAAS,CAAE,KAAM,UAAW,KAAI,SAAQ,CAAC,CAAC,EAC7D,CACX,EACA,CAAC,CAAM,CACX,EAEM,GAAA,EAAM,EAAA,QAAA,MACD,CAAE,OAAM,UAAS,QAAO,UAAS,GACxC,CAAC,EAAM,EAAS,EAAO,CAAQ,CACnC,EAEA,OACI,EAAA,EAAA,KAAA,CAAC,EAAc,SAAf,CAAwB,MAAO,EAA/B,SAAA,CACK,GACD,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,MAClB,SAAA,EAAM,IAAK,GACR,EAAM,OAAS,WACX,EAAA,EAAA,IAAA,CAAC,EAAD,CAAoC,QAAc,OAAQ,EAAvC,EAAM,EAAiC,GAE1D,EAAA,EAAA,IAAA,CAAC,EAAD,CAAoC,QAAc,OAAQ,EAAvC,EAAM,EAAiC,CAElE,CACC,CAAA,CACe,GAEhC,CAOA,SAAS,EAAa,CAAE,QAAO,SAA4B,CACvD,GAAM,CAAE,UAAS,MAAO,EAKxB,OACI,EAAA,EAAA,IAAA,CAAC,EAAA,MAAD,CACI,KAAA,GACA,YAPwB,CAC5B,EAAQ,UAAU,EAClB,EAAM,CAAE,CACZ,EAKQ,MAAO,EAAQ,MACf,KAAM,EAAQ,KACd,gBAAiB,EAAQ,gBACzB,WAAY,EAAQ,WACpB,gBAAiB,EAAQ,gBAExB,SAAA,EAAQ,QACN,CAAA,CAEf,CAOA,SAAS,EAAa,CAAE,QAAO,SAA4B,CACvD,GAAM,CAAE,UAAS,MAAO,EAClB,CAAC,EAAS,IAAA,EAAc,EAAA,SAAA,CAAS,EAAK,EAiB5C,OACI,EAAA,EAAA,IAAA,CAAC,EAAA,cAAD,CACI,KAAA,GACA,MAAO,EAAQ,OAAS,GACxB,YAAa,EAAQ,QACrB,aAAc,EAAQ,aACtB,YAAa,EAAQ,YACrB,QAAS,EAAQ,OAAS,SAAW,UAC5B,UACT,UAAW,SAxB8B,CAC7C,GAAI,CACA,EAAW,EAAI,EACf,MAAM,EAAQ,YAAY,CAC9B,QAAU,CACN,EAAW,EAAK,EAChB,EAAM,CAAE,CACZ,CACJ,EAiBQ,aAfyB,CAC7B,EAAQ,WAAW,EACnB,EAAM,CAAE,CACZ,CAaK,CAAA,CAET,CAWA,SAAgB,GAAuB,CACnC,IAAM,GAAA,EAAM,EAAA,WAAA,CAAW,CAAa,EACpC,GAAI,IAAQ,KACR,MAAU,MAAM,kDAAkD,EAEtE,OAAO,CACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"ModalsManager.js","names":[],"sources":["../../../src/components/ModalsManager/ModalsManager.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines — the imperative API (open, close, confirm, prompt) and\n * the stack that renders it live in one file so the returned promise and the mounted\n * element cannot drift apart.\n */\nimport { createContext, useCallback, useContext, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { ConfirmDialog } from \"@/components/ConfirmDialog\";\nimport { Modal } from \"@/components/Modal\";\nimport type { ModalSize } from \"@/components/Modal\";\nimport styles from \"./ModalsManager.module.css\";\n\n/** Options accepted by {@link ModalsApi.open}. */\nexport interface OpenModalOptions {\n /** Header title. */\n title?: ReactNode;\n /** Modal body content. */\n children: ReactNode;\n /** Dialog size. Default `md`. */\n size?: ModalSize;\n /** Allow closing by clicking the backdrop. Default `true`. */\n closeOnBackdrop?: boolean;\n /** Allow closing with the Esc key. Default `true`. */\n closeOnEsc?: boolean;\n /** Hide the header close button. */\n hideCloseButton?: boolean;\n /** Called after the modal is removed from the stack. */\n onClose?: () => void;\n}\n\n/** Options accepted by {@link ModalsApi.confirm}. */\nexport interface ConfirmModalOptions {\n /** Header title. */\n title?: ReactNode;\n /** Prompt message rendered in the dialog body. */\n message: ReactNode;\n /** Confirm button label. Default `Confirmar`. */\n confirmLabel?: string;\n /** Cancel button label. Default `Cancelar`. */\n cancelLabel?: string;\n /** Render the confirm button in the danger variant. */\n danger?: boolean;\n /** Called when the user confirms. */\n onConfirm?: () => void | Promise<void>;\n /** Called when the user cancels or dismisses. */\n onCancel?: () => void;\n}\n\n/** Imperative API returned by {@link useModals}. */\nexport interface ModalsApi {\n /** Push a content modal. Returns its stack id. */\n open: (options: OpenModalOptions) => string;\n /** Push a confirmation dialog. Returns its stack id. */\n confirm: (options: ConfirmModalOptions) => string;\n /** Remove the modal with the given id. */\n close: (id: string) => void;\n /** Remove every modal from the stack. */\n closeAll: () => void;\n}\n\ninterface ContentEntry {\n kind: \"content\";\n id: string;\n options: OpenModalOptions;\n}\n\ninterface ConfirmEntry {\n kind: \"confirm\";\n id: string;\n options: ConfirmModalOptions;\n}\n\ntype StackEntry = ContentEntry | ConfirmEntry;\n\nconst ModalsContext = createContext<ModalsApi | null>(null);\n\n/** Props for {@link ModalsProvider}. */\nexport interface ModalsProviderProps {\n children: ReactNode;\n}\n\n/**\n * Provides imperative modal control via {@link useModals} and renders the open\n * modal stack. Mount once near the app root.\n *\n * @example\n * <ModalsProvider>\n * <App />\n * </ModalsProvider>\n */\nexport function ModalsProvider({ children }: ModalsProviderProps) {\n const [stack, setStack] = useState<StackEntry[]>([]);\n const counter = useRef(0);\n\n const nextId = useCallback((): string => {\n counter.current += 1;\n return `modal-${counter.current}`;\n }, []);\n\n const close = useCallback((id: string): void => {\n setStack((current) => current.filter((entry) => entry.id !== id));\n }, []);\n\n const closeAll = useCallback((): void => {\n setStack([]);\n }, []);\n\n const open = useCallback(\n (options: OpenModalOptions): string => {\n const id = nextId();\n setStack((current) => [...current, { kind: \"content\", id, options }]);\n return id;\n },\n [nextId],\n );\n\n const confirm = useCallback(\n (options: ConfirmModalOptions): string => {\n const id = nextId();\n setStack((current) => [...current, { kind: \"confirm\", id, options }]);\n return id;\n },\n [nextId],\n );\n\n const api = useMemo<ModalsApi>(\n () => ({ open, confirm, close, closeAll }),\n [open, confirm, close, closeAll],\n );\n\n return (\n <ModalsContext.Provider value={api}>\n {children}\n <div className={styles.stack}>\n {stack.map((entry) =>\n entry.kind === \"content\" ? (\n <ContentModal key={entry.id} entry={entry} close={close} />\n ) : (\n <ConfirmModal key={entry.id} entry={entry} close={close} />\n ),\n )}\n </div>\n </ModalsContext.Provider>\n );\n}\n\ninterface ContentModalProps {\n entry: ContentEntry;\n close: (id: string) => void;\n}\n\nfunction ContentModal({ entry, close }: ContentModalProps) {\n const { options, id } = entry;\n const handleClose = (): void => {\n options.onClose?.();\n close(id);\n };\n return (\n <Modal\n open\n onClose={handleClose}\n title={options.title}\n size={options.size}\n closeOnBackdrop={options.closeOnBackdrop}\n closeOnEsc={options.closeOnEsc}\n hideCloseButton={options.hideCloseButton}\n >\n {options.children}\n </Modal>\n );\n}\n\ninterface ConfirmModalProps {\n entry: ConfirmEntry;\n close: (id: string) => void;\n}\n\nfunction ConfirmModal({ entry, close }: ConfirmModalProps) {\n const { options, id } = entry;\n const [loading, setLoading] = useState(false);\n\n const handleConfirm = async (): Promise<void> => {\n try {\n setLoading(true);\n await options.onConfirm?.();\n } finally {\n setLoading(false);\n close(id);\n }\n };\n\n const handleCancel = (): void => {\n options.onCancel?.();\n close(id);\n };\n\n return (\n <ConfirmDialog\n open\n title={options.title ?? \"\"}\n description={options.message}\n confirmLabel={options.confirmLabel}\n cancelLabel={options.cancelLabel}\n variant={options.danger ? \"danger\" : \"primary\"}\n loading={loading}\n onConfirm={handleConfirm}\n onCancel={handleCancel}\n />\n );\n}\n\n/**\n * Access the imperative modals API. Must be used within a {@link ModalsProvider}.\n *\n * @example\n * const modals = useModals();\n * modals.confirm({ message: \"Excluir item?\", danger: true, onConfirm: del });\n *\n * @throws Error when called outside a {@link ModalsProvider}.\n */\nexport function useModals(): ModalsApi {\n const api = useContext(ModalsContext);\n if (api === null) {\n throw new Error(\"useModals must be used within a <ModalsProvider>\");\n }\n return api;\n}\n"],"mappings":";;;;;;AA0EA,IAAM,IAAgB,EAAgC,IAAI;AAgB1D,SAAgB,EAAe,EAAE,eAAiC;CAC9D,IAAM,CAAC,GAAO,KAAY,EAAuB,CAAC,CAAC,GAC7C,IAAU,EAAO,CAAC,GAElB,IAAS,SACX,EAAQ,WAAW,GACZ,SAAS,EAAQ,YACzB,CAAC,CAAC,GAEC,IAAQ,GAAa,MAAqB;EAC5C,GAAU,MAAY,EAAQ,QAAQ,MAAU,EAAM,OAAO,CAAE,CAAC;CACpE,GAAG,CAAC,CAAC,GAEC,IAAW,QAAwB;EACrC,EAAS,CAAC,CAAC;CACf,GAAG,CAAC,CAAC,GAEC,IAAO,GACR,MAAsC;EACnC,IAAM,IAAK,EAAO;EAElB,OADA,GAAU,MAAY,CAAC,GAAG,GAAS;GAAE,MAAM;GAAW;GAAI;EAAQ,CAAC,CAAC,GAC7D;CACX,GACA,CAAC,CAAM,CACX,GAEM,IAAU,GACX,MAAyC;EACtC,IAAM,IAAK,EAAO;EAElB,OADA,GAAU,MAAY,CAAC,GAAG,GAAS;GAAE,MAAM;GAAW;GAAI;EAAQ,CAAC,CAAC,GAC7D;CACX,GACA,CAAC,CAAM,CACX,GAEM,IAAM,SACD;EAAE;EAAM;EAAS;EAAO;CAAS,IACxC;EAAC;EAAM;EAAS;EAAO;CAAQ,CACnC;CAEA,OACI,kBAAC,EAAc,UAAf;EAAwB,OAAO;YAA/B,CACK,GACD,kBAAC,OAAD;GAAK,WAAW,EAAO;aAClB,EAAM,KAAK,MACR,EAAM,SAAS,YACX,kBAAC,GAAD;IAAoC;IAAc;GAAQ,GAAvC,EAAM,EAAiC,IAE1D,kBAAC,GAAD;IAAoC;IAAc;GAAQ,GAAvC,EAAM,EAAiC,CAElE;EACC,CAAA,CACe;;AAEhC;AAOA,SAAS,EAAa,EAAE,UAAO,YAA4B;CACvD,IAAM,EAAE,YAAS,UAAO;CAKxB,OACI,kBAAC,GAAD;EACI,MAAA;EACA,eAPwB;GAE5B,AADA,EAAQ,UAAU,GAClB,EAAM,CAAE;EACZ;EAKQ,OAAO,EAAQ;EACf,MAAM,EAAQ;EACd,iBAAiB,EAAQ;EACzB,YAAY,EAAQ;EACpB,iBAAiB,EAAQ;YAExB,EAAQ;CACN,CAAA;AAEf;AAOA,SAAS,EAAa,EAAE,UAAO,YAA4B;CACvD,IAAM,EAAE,YAAS,UAAO,GAClB,CAAC,GAAS,KAAc,EAAS,EAAK;CAiB5C,OACI,kBAAC,GAAD;EACI,MAAA;EACA,OAAO,EAAQ,SAAS;EACxB,aAAa,EAAQ;EACrB,cAAc,EAAQ;EACtB,aAAa,EAAQ;EACrB,SAAS,EAAQ,SAAS,WAAW;EAC5B;EACT,WAAW,YAxB8B;GAC7C,IAAI;IAEA,AADA,EAAW,EAAI,GACf,MAAM,EAAQ,YAAY;GAC9B,UAAU;IAEN,AADA,EAAW,EAAK,GAChB,EAAM,CAAE;GACZ;EACJ;EAiBQ,gBAfyB;GAE7B,AADA,EAAQ,WAAW,GACnB,EAAM,CAAE;EACZ;CAaK,CAAA;AAET;AAWA,SAAgB,IAAuB;CACnC,IAAM,IAAM,EAAW,CAAa;CACpC,IAAI,MAAQ,MACR,MAAU,MAAM,kDAAkD;CAEtE,OAAO;AACX"}
1
+ {"version":3,"file":"ModalsManager.js","names":[],"sources":["../../../src/components/ModalsManager/ModalsManager.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines — the imperative API (open, close, confirm, prompt) and\n * the stack that renders it live in one file so the returned promise and the mounted\n * element cannot drift apart.\n */\nimport { createContext, useCallback, useContext, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { ConfirmDialog } from \"@/components/ConfirmDialog\";\nimport { Modal } from \"@/components/Modal\";\nimport type { ModalSize } from \"@/components/Modal\";\nimport styles from \"./ModalsManager.module.css\";\n\n/** Options accepted by {@link ModalsApi.open}. */\nexport interface OpenModalOptions {\n /** Header title. */\n title?: ReactNode;\n /** Modal body content. */\n children: ReactNode;\n /** Dialog size. Default `md`. */\n size?: ModalSize;\n /** Allow closing by clicking the backdrop. Default `true`. */\n closeOnBackdrop?: boolean;\n /** Allow closing with the Esc key. Default `true`. */\n closeOnEsc?: boolean;\n /** Hide the header close button. */\n hideCloseButton?: boolean;\n /** Called after the modal is removed from the stack. */\n onClose?: () => void;\n}\n\n/** Options accepted by {@link ModalsApi.confirm}. */\nexport interface ConfirmModalOptions {\n /** Header title. */\n title?: ReactNode;\n /** Prompt message rendered in the dialog body. */\n message: ReactNode;\n /** Confirm button label. Default `Confirmar`. */\n confirmLabel?: string;\n /** Cancel button label. Default `Cancelar`. */\n cancelLabel?: string;\n /** Render the confirm button in the danger variant. */\n danger?: boolean;\n /** Called when the user confirms. */\n onConfirm?: () => void | Promise<void>;\n /** Called when the user cancels or dismisses. */\n onCancel?: () => void;\n}\n\n/** Imperative API returned by {@link useModals}. */\nexport interface ModalsApi {\n /** Push a content modal. Returns its stack id. */\n open: (options: OpenModalOptions) => string;\n /** Push a confirmation dialog. Returns its stack id. */\n confirm: (options: ConfirmModalOptions) => string;\n /** Remove the modal with the given id. */\n close: (id: string) => void;\n /** Remove every modal from the stack. */\n closeAll: () => void;\n}\n\ninterface ContentEntry {\n kind: \"content\";\n id: string;\n options: OpenModalOptions;\n}\n\ninterface ConfirmEntry {\n kind: \"confirm\";\n id: string;\n options: ConfirmModalOptions;\n}\n\ntype StackEntry = ContentEntry | ConfirmEntry;\n\nconst ModalsContext = createContext<ModalsApi | null>(null);\n\n/** Props for {@link ModalsProvider}. */\nexport interface ModalsProviderProps {\n children: ReactNode;\n}\n\n/**\n * Provides imperative modal control via {@link useModals} and renders the open\n * modal stack. Mount once near the app root.\n *\n * @example\n * <ModalsProvider>\n * <App />\n * </ModalsProvider>\n */\nexport function ModalsProvider({ children }: ModalsProviderProps) {\n const [stack, setStack] = useState<StackEntry[]>([]);\n const counter = useRef(0);\n\n const nextId = useCallback((): string => {\n counter.current += 1;\n return `modal-${counter.current}`;\n }, []);\n\n const close = useCallback((id: string): void => {\n setStack((current) => current.filter((entry) => entry.id !== id));\n }, []);\n\n const closeAll = useCallback((): void => {\n setStack([]);\n }, []);\n\n const open = useCallback(\n (options: OpenModalOptions): string => {\n const id = nextId();\n setStack((current) => [...current, { kind: \"content\", id, options }]);\n return id;\n },\n [nextId],\n );\n\n const confirm = useCallback(\n (options: ConfirmModalOptions): string => {\n const id = nextId();\n setStack((current) => [...current, { kind: \"confirm\", id, options }]);\n return id;\n },\n [nextId],\n );\n\n const api = useMemo<ModalsApi>(\n () => ({ open, confirm, close, closeAll }),\n [open, confirm, close, closeAll],\n );\n\n return (\n <ModalsContext.Provider value={api}>\n {children}\n <div className={styles.stack}>\n {stack.map((entry) =>\n entry.kind === \"content\" ? (\n <ContentModal key={entry.id} entry={entry} close={close} />\n ) : (\n <ConfirmModal key={entry.id} entry={entry} close={close} />\n ),\n )}\n </div>\n </ModalsContext.Provider>\n );\n}\n\ninterface ContentModalProps {\n entry: ContentEntry;\n close: (id: string) => void;\n}\n\nfunction ContentModal({ entry, close }: ContentModalProps) {\n const { options, id } = entry;\n const handleClose = (): void => {\n options.onClose?.();\n close(id);\n };\n return (\n <Modal\n open\n onClose={handleClose}\n title={options.title}\n size={options.size}\n closeOnBackdrop={options.closeOnBackdrop}\n closeOnEsc={options.closeOnEsc}\n hideCloseButton={options.hideCloseButton}\n >\n {options.children}\n </Modal>\n );\n}\n\ninterface ConfirmModalProps {\n entry: ConfirmEntry;\n close: (id: string) => void;\n}\n\nfunction ConfirmModal({ entry, close }: ConfirmModalProps) {\n const { options, id } = entry;\n const [loading, setLoading] = useState(false);\n\n const handleConfirm = async (): Promise<void> => {\n try {\n setLoading(true);\n await options.onConfirm?.();\n } finally {\n setLoading(false);\n close(id);\n }\n };\n\n const handleCancel = (): void => {\n options.onCancel?.();\n close(id);\n };\n\n return (\n <ConfirmDialog\n open\n title={options.title ?? \"\"}\n description={options.message}\n confirmLabel={options.confirmLabel}\n cancelLabel={options.cancelLabel}\n variant={options.danger ? \"danger\" : \"primary\"}\n loading={loading}\n onConfirm={handleConfirm}\n onCancel={handleCancel}\n />\n );\n}\n\n/**\n * Access the imperative modals API. Must be used within a {@link ModalsProvider}.\n *\n * @example\n * const modals = useModals();\n * modals.confirm({ message: \"Excluir item?\", danger: true, onConfirm: del });\n *\n * @throws Error when called outside a {@link ModalsProvider}.\n */\nexport function useModals(): ModalsApi {\n const api = useContext(ModalsContext);\n if (api === null) {\n throw new Error(\"useModals must be used within a <ModalsProvider>\");\n }\n return api;\n}\n"],"mappings":";;;;;;AA0EA,IAAM,IAAgB,EAAgC,IAAI;AAgB1D,SAAgB,EAAe,EAAE,eAAiC;CAC9D,IAAM,CAAC,GAAO,KAAY,EAAuB,CAAC,CAAC,GAC7C,IAAU,EAAO,CAAC,GAElB,IAAS,SACX,EAAQ,WAAW,GACZ,SAAS,EAAQ,YACzB,CAAC,CAAC,GAEC,IAAQ,GAAa,MAAqB;EAC5C,GAAU,MAAY,EAAQ,QAAQ,MAAU,EAAM,OAAO,CAAE,CAAC;CACpE,GAAG,CAAC,CAAC,GAEC,IAAW,QAAwB;EACrC,EAAS,CAAC,CAAC;CACf,GAAG,CAAC,CAAC,GAEC,IAAO,GACR,MAAsC;EACnC,IAAM,IAAK,EAAO;EAElB,OADA,GAAU,MAAY,CAAC,GAAG,GAAS;GAAE,MAAM;GAAW;GAAI;EAAQ,CAAC,CAAC,GAC7D;CACX,GACA,CAAC,CAAM,CACX,GAEM,IAAU,GACX,MAAyC;EACtC,IAAM,IAAK,EAAO;EAElB,OADA,GAAU,MAAY,CAAC,GAAG,GAAS;GAAE,MAAM;GAAW;GAAI;EAAQ,CAAC,CAAC,GAC7D;CACX,GACA,CAAC,CAAM,CACX,GAEM,IAAM,SACD;EAAE;EAAM;EAAS;EAAO;CAAS,IACxC;EAAC;EAAM;EAAS;EAAO;CAAQ,CACnC;CAEA,OACI,kBAAC,EAAc,UAAf;EAAwB,OAAO;EAA/B,UAAA,CACK,GACD,kBAAC,OAAD;GAAK,WAAW,EAAO;GAClB,UAAA,EAAM,KAAK,MACR,EAAM,SAAS,YACX,kBAAC,GAAD;IAAoC;IAAc;GAAQ,GAAvC,EAAM,EAAiC,IAE1D,kBAAC,GAAD;IAAoC;IAAc;GAAQ,GAAvC,EAAM,EAAiC,CAElE;EACC,CAAA,CACe;;AAEhC;AAOA,SAAS,EAAa,EAAE,UAAO,YAA4B;CACvD,IAAM,EAAE,YAAS,UAAO;CAKxB,OACI,kBAAC,GAAD;EACI,MAAA;EACA,eAPwB;GAE5B,AADA,EAAQ,UAAU,GAClB,EAAM,CAAE;EACZ;EAKQ,OAAO,EAAQ;EACf,MAAM,EAAQ;EACd,iBAAiB,EAAQ;EACzB,YAAY,EAAQ;EACpB,iBAAiB,EAAQ;EAExB,UAAA,EAAQ;CACN,CAAA;AAEf;AAOA,SAAS,EAAa,EAAE,UAAO,YAA4B;CACvD,IAAM,EAAE,YAAS,UAAO,GAClB,CAAC,GAAS,KAAc,EAAS,EAAK;CAiB5C,OACI,kBAAC,GAAD;EACI,MAAA;EACA,OAAO,EAAQ,SAAS;EACxB,aAAa,EAAQ;EACrB,cAAc,EAAQ;EACtB,aAAa,EAAQ;EACrB,SAAS,EAAQ,SAAS,WAAW;EAC5B;EACT,WAAW,YAxB8B;GAC7C,IAAI;IAEA,AADA,EAAW,EAAI,GACf,MAAM,EAAQ,YAAY;GAC9B,UAAU;IAEN,AADA,EAAW,EAAK,GAChB,EAAM,CAAE;GACZ;EACJ;EAiBQ,gBAfyB;GAE7B,AADA,EAAQ,WAAW,GACnB,EAAM,CAAE;EACZ;CAaK,CAAA;AAET;AAWA,SAAgB,IAAuB;CACnC,IAAM,IAAM,EAAW,CAAa;CACpC,IAAI,MAAQ,MACR,MAAU,MAAM,kDAAkD;CAEtE,OAAO;AACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"Money.cjs","names":[],"sources":["../../../src/components/Money/Money.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\n\nexport interface MoneyProps extends HTMLAttributes<HTMLSpanElement> {\n /** Amount in the smallest currency unit (e.g. cents). */\n cents: number;\n /** ISO 4217 currency code. Defaults to \"BRL\". */\n currency?: string;\n /** BCP 47 locale used for formatting. Defaults to \"pt-BR\". */\n locale?: string;\n}\n\n/**\n * Render a monetary amount given in cents as a localized currency string\n * inside a `<span>`.\n *\n * The integer cents are divided by 100 and formatted with `Intl.NumberFormat`.\n *\n * @example\n * <Money cents={1990} /> // \"R$ 19,90\"\n * <Money cents={500} currency=\"USD\" locale=\"en-US\" /> // \"$5.00\"\n */\nexport function Money({ cents, currency = \"BRL\", locale = \"pt-BR\", ...props }: MoneyProps) {\n const formatted = new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency,\n }).format(cents / 100);\n\n return <span {...props}>{formatted}</span>;\n}\n"],"mappings":"mCAqBA,SAAgB,EAAM,CAAE,QAAO,WAAW,MAAO,SAAS,QAAS,GAAG,GAAqB,CACvF,IAAM,EAAY,IAAI,KAAK,aAAa,EAAQ,CAC5C,MAAO,WACP,UACJ,CAAC,CAAC,CAAC,OAAO,EAAQ,GAAG,EAErB,OAAO,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,GAAI,WAAQ,CAAgB,CAAA,CAC7C"}
1
+ {"version":3,"file":"Money.cjs","names":[],"sources":["../../../src/components/Money/Money.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\n\nexport interface MoneyProps extends HTMLAttributes<HTMLSpanElement> {\n /** Amount in the smallest currency unit (e.g. cents). */\n cents: number;\n /** ISO 4217 currency code. Defaults to \"BRL\". */\n currency?: string;\n /** BCP 47 locale used for formatting. Defaults to \"pt-BR\". */\n locale?: string;\n}\n\n/**\n * Render a monetary amount given in cents as a localized currency string\n * inside a `<span>`.\n *\n * The integer cents are divided by 100 and formatted with `Intl.NumberFormat`.\n *\n * @example\n * <Money cents={1990} /> // \"R$ 19,90\"\n * <Money cents={500} currency=\"USD\" locale=\"en-US\" /> // \"$5.00\"\n */\nexport function Money({ cents, currency = \"BRL\", locale = \"pt-BR\", ...props }: MoneyProps) {\n const formatted = new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency,\n }).format(cents / 100);\n\n return <span {...props}>{formatted}</span>;\n}\n"],"mappings":"mCAqBA,SAAgB,EAAM,CAAE,QAAO,WAAW,MAAO,SAAS,QAAS,GAAG,GAAqB,CACvF,IAAM,EAAY,IAAI,KAAK,aAAa,EAAQ,CAC5C,MAAO,WACP,UACJ,CAAC,CAAC,CAAC,OAAO,EAAQ,GAAG,EAErB,OAAO,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,GAAI,EAAQ,SAAA,CAAgB,CAAA,CAC7C"}
@@ -1 +1 @@
1
- {"version":3,"file":"Money.js","names":[],"sources":["../../../src/components/Money/Money.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\n\nexport interface MoneyProps extends HTMLAttributes<HTMLSpanElement> {\n /** Amount in the smallest currency unit (e.g. cents). */\n cents: number;\n /** ISO 4217 currency code. Defaults to \"BRL\". */\n currency?: string;\n /** BCP 47 locale used for formatting. Defaults to \"pt-BR\". */\n locale?: string;\n}\n\n/**\n * Render a monetary amount given in cents as a localized currency string\n * inside a `<span>`.\n *\n * The integer cents are divided by 100 and formatted with `Intl.NumberFormat`.\n *\n * @example\n * <Money cents={1990} /> // \"R$ 19,90\"\n * <Money cents={500} currency=\"USD\" locale=\"en-US\" /> // \"$5.00\"\n */\nexport function Money({ cents, currency = \"BRL\", locale = \"pt-BR\", ...props }: MoneyProps) {\n const formatted = new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency,\n }).format(cents / 100);\n\n return <span {...props}>{formatted}</span>;\n}\n"],"mappings":";;AAqBA,SAAgB,EAAM,EAAE,UAAO,cAAW,OAAO,YAAS,SAAS,GAAG,KAAqB;CACvF,IAAM,IAAY,IAAI,KAAK,aAAa,GAAQ;EAC5C,OAAO;EACP;CACJ,CAAC,CAAC,CAAC,OAAO,IAAQ,GAAG;CAErB,OAAO,kBAAC,QAAD;EAAM,GAAI;YAAQ;CAAgB,CAAA;AAC7C"}
1
+ {"version":3,"file":"Money.js","names":[],"sources":["../../../src/components/Money/Money.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\n\nexport interface MoneyProps extends HTMLAttributes<HTMLSpanElement> {\n /** Amount in the smallest currency unit (e.g. cents). */\n cents: number;\n /** ISO 4217 currency code. Defaults to \"BRL\". */\n currency?: string;\n /** BCP 47 locale used for formatting. Defaults to \"pt-BR\". */\n locale?: string;\n}\n\n/**\n * Render a monetary amount given in cents as a localized currency string\n * inside a `<span>`.\n *\n * The integer cents are divided by 100 and formatted with `Intl.NumberFormat`.\n *\n * @example\n * <Money cents={1990} /> // \"R$ 19,90\"\n * <Money cents={500} currency=\"USD\" locale=\"en-US\" /> // \"$5.00\"\n */\nexport function Money({ cents, currency = \"BRL\", locale = \"pt-BR\", ...props }: MoneyProps) {\n const formatted = new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency,\n }).format(cents / 100);\n\n return <span {...props}>{formatted}</span>;\n}\n"],"mappings":";;AAqBA,SAAgB,EAAM,EAAE,UAAO,cAAW,OAAO,YAAS,SAAS,GAAG,KAAqB;CACvF,IAAM,IAAY,IAAI,KAAK,aAAa,GAAQ;EAC5C,OAAO;EACP;CACJ,CAAC,CAAC,CAAC,OAAO,IAAQ,GAAG;CAErB,OAAO,kBAAC,QAAD;EAAM,GAAI;EAAQ,UAAA;CAAgB,CAAA;AAC7C"}
@@ -1 +1 @@
1
- {"version":3,"file":"MultiSelect.cjs","names":[],"sources":["../../../src/components/MultiSelect/MultiSelect.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — options/value/onChange\n * plus the shared field contract, and the three knobs that make it multi: maxItems,\n * filter, emptyMessage. The body is the listbox with chip removal, type-ahead and\n * the ARIA active-descendant wiring reading one active index.\n */\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./MultiSelect.module.css\";\n\nexport interface MultiSelectOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface MultiSelectProps {\n options: MultiSelectOption[];\n /** Currently selected values. */\n value: string[];\n onChange: (value: string[]) => void;\n label?: string;\n placeholder?: string;\n helperText?: string;\n error?: string;\n disabled?: boolean;\n /** Cap the number of selectable items. */\n maxItems?: number;\n /** Custom filter — return true to keep the option. Default: case-insensitive substring on label. */\n filter?: (option: MultiSelectOption, query: string) => boolean;\n /** Message shown when no option matches. */\n emptyMessage?: string;\n className?: string;\n}\n\nfunction defaultFilter(option: MultiSelectOption, query: string): boolean {\n if (!query) return true;\n return option.label.toLowerCase().includes(query.toLowerCase());\n}\n\n/**\n * MultiSelect — a filterable dropdown that selects many options, shown as\n * removable chips inside the field. Selecting toggles a value; Backspace on an\n * empty query removes the last chip.\n *\n * Keyboard: ArrowUp/ArrowDown navigate, Enter toggles the active option, Esc\n * closes, Backspace (empty input) pops the last chip.\n */\nexport function MultiSelect({\n options,\n value,\n onChange,\n label,\n placeholder = \"Selecione\",\n helperText,\n error,\n disabled,\n maxItems,\n filter = defaultFilter,\n emptyMessage = \"Nenhuma opção encontrada\",\n className,\n}: MultiSelectProps) {\n const id = useId();\n const rootRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [activeIndex, setActiveIndex] = useState(0);\n\n const selectedSet = useMemo(() => new Set(value), [value]);\n const selectedOptions = useMemo(\n () =>\n value\n .map((v) => options.find((o) => o.value === v))\n .filter((o): o is MultiSelectOption => Boolean(o)),\n [value, options],\n );\n const filtered = useMemo(\n () => options.filter((o) => filter(o, query)),\n [options, filter, query],\n );\n\n const atMax = maxItems !== undefined && value.length >= maxItems;\n\n const toggle = useCallback(\n (option: MultiSelectOption): void => {\n if (option.disabled) return;\n if (selectedSet.has(option.value)) {\n onChange(value.filter((v) => v !== option.value));\n } else {\n if (atMax) return;\n onChange([...value, option.value]);\n }\n setQuery(\"\");\n inputRef.current?.focus();\n },\n [selectedSet, onChange, value, atMax],\n );\n\n const removeAt = useCallback(\n (optionValue: string): void => {\n onChange(value.filter((v) => v !== optionValue));\n },\n [onChange, value],\n );\n\n useEffect(() => {\n if (!open) return;\n const onDown = (event: MouseEvent): void => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n setOpen(false);\n setQuery(\"\");\n }\n };\n window.addEventListener(\"mousedown\", onDown);\n return () => window.removeEventListener(\"mousedown\", onDown);\n }, [open]);\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setOpen(true);\n setActiveIndex((current) => Math.min(filtered.length - 1, current + 1));\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((current) => Math.max(0, current - 1));\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n const option = filtered[activeIndex];\n if (option) toggle(option);\n } else if (event.key === \"Escape\") {\n setOpen(false);\n setQuery(\"\");\n } else if (event.key === \"Backspace\" && query === \"\" && value.length > 0) {\n removeAt(value[value.length - 1]);\n }\n };\n\n return (\n <div ref={rootRef} className={cn(styles.wrapper, error && styles.error, className)}>\n {label && (\n <label htmlFor={id} className={styles.label}>\n {label}\n </label>\n )}\n <div\n className={cn(styles.field, disabled && styles.disabled)}\n onMouseDown={(event) => {\n if (disabled) return;\n // Keep focus on the input when clicking empty field space.\n if (event.target === event.currentTarget) {\n event.preventDefault();\n inputRef.current?.focus();\n setOpen(true);\n }\n }}\n >\n {selectedOptions.map((option) => (\n <span key={option.value} className={styles.chip}>\n {option.label}\n <button\n type=\"button\"\n className={styles.chipRemove}\n aria-label={`Remover ${option.label}`}\n disabled={disabled}\n onMouseDown={(event) => {\n event.preventDefault();\n removeAt(option.value);\n }}\n >\n ×\n </button>\n </span>\n ))}\n <input\n id={id}\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={`${id}-listbox`}\n aria-autocomplete=\"list\"\n className={styles.input}\n placeholder={value.length === 0 ? placeholder : \"\"}\n disabled={disabled}\n value={query}\n onFocus={() => setOpen(true)}\n onChange={(event) => {\n setQuery(event.target.value);\n setOpen(true);\n setActiveIndex(0);\n }}\n onKeyDown={handleKeyDown}\n />\n </div>\n {open && (\n <ul\n id={`${id}-listbox`}\n role=\"listbox\"\n aria-multiselectable\n className={styles.menu}\n >\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n filtered.map((option, index) => {\n const isSelected = selectedSet.has(option.value);\n return (\n <li\n key={option.value}\n role=\"option\"\n aria-selected={isSelected}\n aria-disabled={option.disabled || (!isSelected && atMax)}\n className={cn(\n styles.option,\n index === activeIndex && styles.active,\n isSelected && styles.selected,\n )}\n onMouseEnter={() => setActiveIndex(index)}\n onMouseDown={(event) => {\n event.preventDefault();\n toggle(option);\n }}\n >\n <span className={styles.check} aria-hidden>\n {isSelected ? \"✓\" : \"\"}\n </span>\n {option.label}\n </li>\n );\n })\n )}\n </ul>\n )}\n {error ? (\n <span className={styles.errorText}>{error}</span>\n ) : helperText ? (\n <span className={styles.helper}>{helperText}</span>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MultiSelect.cjs","names":[],"sources":["../../../src/components/MultiSelect/MultiSelect.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — options/value/onChange\n * plus the shared field contract, and the three knobs that make it multi: maxItems,\n * filter, emptyMessage. The body is the listbox with chip removal, type-ahead and\n * the ARIA active-descendant wiring reading one active index.\n */\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./MultiSelect.module.css\";\n\nexport interface MultiSelectOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface MultiSelectProps {\n options: MultiSelectOption[];\n /** Currently selected values. */\n value: string[];\n onChange: (value: string[]) => void;\n label?: string;\n placeholder?: string;\n helperText?: string;\n error?: string;\n disabled?: boolean;\n /** Cap the number of selectable items. */\n maxItems?: number;\n /** Custom filter — return true to keep the option. Default: case-insensitive substring on label. */\n filter?: (option: MultiSelectOption, query: string) => boolean;\n /** Message shown when no option matches. */\n emptyMessage?: string;\n className?: string;\n}\n\nfunction defaultFilter(option: MultiSelectOption, query: string): boolean {\n if (!query) return true;\n return option.label.toLowerCase().includes(query.toLowerCase());\n}\n\n/**\n * MultiSelect — a filterable dropdown that selects many options, shown as\n * removable chips inside the field. Selecting toggles a value; Backspace on an\n * empty query removes the last chip.\n *\n * Keyboard: ArrowUp/ArrowDown navigate, Enter toggles the active option, Esc\n * closes, Backspace (empty input) pops the last chip.\n */\nexport function MultiSelect({\n options,\n value,\n onChange,\n label,\n placeholder = \"Selecione\",\n helperText,\n error,\n disabled,\n maxItems,\n filter = defaultFilter,\n emptyMessage = \"Nenhuma opção encontrada\",\n className,\n}: MultiSelectProps) {\n const id = useId();\n const rootRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [activeIndex, setActiveIndex] = useState(0);\n\n const selectedSet = useMemo(() => new Set(value), [value]);\n const selectedOptions = useMemo(\n () =>\n value\n .map((v) => options.find((o) => o.value === v))\n .filter((o): o is MultiSelectOption => Boolean(o)),\n [value, options],\n );\n const filtered = useMemo(\n () => options.filter((o) => filter(o, query)),\n [options, filter, query],\n );\n\n const atMax = maxItems !== undefined && value.length >= maxItems;\n\n const toggle = useCallback(\n (option: MultiSelectOption): void => {\n if (option.disabled) return;\n if (selectedSet.has(option.value)) {\n onChange(value.filter((v) => v !== option.value));\n } else {\n if (atMax) return;\n onChange([...value, option.value]);\n }\n setQuery(\"\");\n inputRef.current?.focus();\n },\n [selectedSet, onChange, value, atMax],\n );\n\n const removeAt = useCallback(\n (optionValue: string): void => {\n onChange(value.filter((v) => v !== optionValue));\n },\n [onChange, value],\n );\n\n useEffect(() => {\n if (!open) return;\n const onDown = (event: MouseEvent): void => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n setOpen(false);\n setQuery(\"\");\n }\n };\n window.addEventListener(\"mousedown\", onDown);\n return () => window.removeEventListener(\"mousedown\", onDown);\n }, [open]);\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setOpen(true);\n setActiveIndex((current) => Math.min(filtered.length - 1, current + 1));\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((current) => Math.max(0, current - 1));\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n const option = filtered[activeIndex];\n if (option) toggle(option);\n } else if (event.key === \"Escape\") {\n setOpen(false);\n setQuery(\"\");\n } else if (event.key === \"Backspace\" && query === \"\" && value.length > 0) {\n removeAt(value[value.length - 1]);\n }\n };\n\n return (\n <div ref={rootRef} className={cn(styles.wrapper, error && styles.error, className)}>\n {label && (\n <label htmlFor={id} className={styles.label}>\n {label}\n </label>\n )}\n <div\n className={cn(styles.field, disabled && styles.disabled)}\n onMouseDown={(event) => {\n if (disabled) return;\n // Keep focus on the input when clicking empty field space.\n if (event.target === event.currentTarget) {\n event.preventDefault();\n inputRef.current?.focus();\n setOpen(true);\n }\n }}\n >\n {selectedOptions.map((option) => (\n <span key={option.value} className={styles.chip}>\n {option.label}\n <button\n type=\"button\"\n className={styles.chipRemove}\n aria-label={`Remover ${option.label}`}\n disabled={disabled}\n onMouseDown={(event) => {\n event.preventDefault();\n removeAt(option.value);\n }}\n >\n ×\n </button>\n </span>\n ))}\n <input\n id={id}\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={`${id}-listbox`}\n aria-autocomplete=\"list\"\n className={styles.input}\n placeholder={value.length === 0 ? placeholder : \"\"}\n disabled={disabled}\n value={query}\n onFocus={() => setOpen(true)}\n onChange={(event) => {\n setQuery(event.target.value);\n setOpen(true);\n setActiveIndex(0);\n }}\n onKeyDown={handleKeyDown}\n />\n </div>\n {open && (\n <ul\n id={`${id}-listbox`}\n role=\"listbox\"\n aria-multiselectable\n className={styles.menu}\n >\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n filtered.map((option, index) => {\n const isSelected = selectedSet.has(option.value);\n return (\n <li\n key={option.value}\n role=\"option\"\n aria-selected={isSelected}\n aria-disabled={option.disabled || (!isSelected && atMax)}\n className={cn(\n styles.option,\n index === activeIndex && styles.active,\n isSelected && styles.selected,\n )}\n onMouseEnter={() => setActiveIndex(index)}\n onMouseDown={(event) => {\n event.preventDefault();\n toggle(option);\n }}\n >\n <span className={styles.check} aria-hidden>\n {isSelected ? \"✓\" : \"\"}\n </span>\n {option.label}\n </li>\n );\n })\n )}\n </ul>\n )}\n {error ? (\n <span className={styles.errorText}>{error}</span>\n ) : helperText ? (\n <span className={styles.helper}>{helperText}</span>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"MultiSelect.js","names":[],"sources":["../../../src/components/MultiSelect/MultiSelect.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — options/value/onChange\n * plus the shared field contract, and the three knobs that make it multi: maxItems,\n * filter, emptyMessage. The body is the listbox with chip removal, type-ahead and\n * the ARIA active-descendant wiring reading one active index.\n */\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./MultiSelect.module.css\";\n\nexport interface MultiSelectOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface MultiSelectProps {\n options: MultiSelectOption[];\n /** Currently selected values. */\n value: string[];\n onChange: (value: string[]) => void;\n label?: string;\n placeholder?: string;\n helperText?: string;\n error?: string;\n disabled?: boolean;\n /** Cap the number of selectable items. */\n maxItems?: number;\n /** Custom filter — return true to keep the option. Default: case-insensitive substring on label. */\n filter?: (option: MultiSelectOption, query: string) => boolean;\n /** Message shown when no option matches. */\n emptyMessage?: string;\n className?: string;\n}\n\nfunction defaultFilter(option: MultiSelectOption, query: string): boolean {\n if (!query) return true;\n return option.label.toLowerCase().includes(query.toLowerCase());\n}\n\n/**\n * MultiSelect — a filterable dropdown that selects many options, shown as\n * removable chips inside the field. Selecting toggles a value; Backspace on an\n * empty query removes the last chip.\n *\n * Keyboard: ArrowUp/ArrowDown navigate, Enter toggles the active option, Esc\n * closes, Backspace (empty input) pops the last chip.\n */\nexport function MultiSelect({\n options,\n value,\n onChange,\n label,\n placeholder = \"Selecione\",\n helperText,\n error,\n disabled,\n maxItems,\n filter = defaultFilter,\n emptyMessage = \"Nenhuma opção encontrada\",\n className,\n}: MultiSelectProps) {\n const id = useId();\n const rootRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [activeIndex, setActiveIndex] = useState(0);\n\n const selectedSet = useMemo(() => new Set(value), [value]);\n const selectedOptions = useMemo(\n () =>\n value\n .map((v) => options.find((o) => o.value === v))\n .filter((o): o is MultiSelectOption => Boolean(o)),\n [value, options],\n );\n const filtered = useMemo(\n () => options.filter((o) => filter(o, query)),\n [options, filter, query],\n );\n\n const atMax = maxItems !== undefined && value.length >= maxItems;\n\n const toggle = useCallback(\n (option: MultiSelectOption): void => {\n if (option.disabled) return;\n if (selectedSet.has(option.value)) {\n onChange(value.filter((v) => v !== option.value));\n } else {\n if (atMax) return;\n onChange([...value, option.value]);\n }\n setQuery(\"\");\n inputRef.current?.focus();\n },\n [selectedSet, onChange, value, atMax],\n );\n\n const removeAt = useCallback(\n (optionValue: string): void => {\n onChange(value.filter((v) => v !== optionValue));\n },\n [onChange, value],\n );\n\n useEffect(() => {\n if (!open) return;\n const onDown = (event: MouseEvent): void => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n setOpen(false);\n setQuery(\"\");\n }\n };\n window.addEventListener(\"mousedown\", onDown);\n return () => window.removeEventListener(\"mousedown\", onDown);\n }, [open]);\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setOpen(true);\n setActiveIndex((current) => Math.min(filtered.length - 1, current + 1));\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((current) => Math.max(0, current - 1));\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n const option = filtered[activeIndex];\n if (option) toggle(option);\n } else if (event.key === \"Escape\") {\n setOpen(false);\n setQuery(\"\");\n } else if (event.key === \"Backspace\" && query === \"\" && value.length > 0) {\n removeAt(value[value.length - 1]);\n }\n };\n\n return (\n <div ref={rootRef} className={cn(styles.wrapper, error && styles.error, className)}>\n {label && (\n <label htmlFor={id} className={styles.label}>\n {label}\n </label>\n )}\n <div\n className={cn(styles.field, disabled && styles.disabled)}\n onMouseDown={(event) => {\n if (disabled) return;\n // Keep focus on the input when clicking empty field space.\n if (event.target === event.currentTarget) {\n event.preventDefault();\n inputRef.current?.focus();\n setOpen(true);\n }\n }}\n >\n {selectedOptions.map((option) => (\n <span key={option.value} className={styles.chip}>\n {option.label}\n <button\n type=\"button\"\n className={styles.chipRemove}\n aria-label={`Remover ${option.label}`}\n disabled={disabled}\n onMouseDown={(event) => {\n event.preventDefault();\n removeAt(option.value);\n }}\n >\n ×\n </button>\n </span>\n ))}\n <input\n id={id}\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={`${id}-listbox`}\n aria-autocomplete=\"list\"\n className={styles.input}\n placeholder={value.length === 0 ? placeholder : \"\"}\n disabled={disabled}\n value={query}\n onFocus={() => setOpen(true)}\n onChange={(event) => {\n setQuery(event.target.value);\n setOpen(true);\n setActiveIndex(0);\n }}\n onKeyDown={handleKeyDown}\n />\n </div>\n {open && (\n <ul\n id={`${id}-listbox`}\n role=\"listbox\"\n aria-multiselectable\n className={styles.menu}\n >\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n filtered.map((option, index) => {\n const isSelected = selectedSet.has(option.value);\n return (\n <li\n key={option.value}\n role=\"option\"\n aria-selected={isSelected}\n aria-disabled={option.disabled || (!isSelected && atMax)}\n className={cn(\n styles.option,\n index === activeIndex && styles.active,\n isSelected && styles.selected,\n )}\n onMouseEnter={() => setActiveIndex(index)}\n onMouseDown={(event) => {\n event.preventDefault();\n toggle(option);\n }}\n >\n <span className={styles.check} aria-hidden>\n {isSelected ? \"✓\" : \"\"}\n </span>\n {option.label}\n </li>\n );\n })\n )}\n </ul>\n )}\n {error ? (\n <span className={styles.errorText}>{error}</span>\n ) : helperText ? (\n <span className={styles.helper}>{helperText}</span>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MultiSelect.js","names":[],"sources":["../../../src/components/MultiSelect/MultiSelect.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — options/value/onChange\n * plus the shared field contract, and the three knobs that make it multi: maxItems,\n * filter, emptyMessage. The body is the listbox with chip removal, type-ahead and\n * the ARIA active-descendant wiring reading one active index.\n */\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./MultiSelect.module.css\";\n\nexport interface MultiSelectOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface MultiSelectProps {\n options: MultiSelectOption[];\n /** Currently selected values. */\n value: string[];\n onChange: (value: string[]) => void;\n label?: string;\n placeholder?: string;\n helperText?: string;\n error?: string;\n disabled?: boolean;\n /** Cap the number of selectable items. */\n maxItems?: number;\n /** Custom filter — return true to keep the option. Default: case-insensitive substring on label. */\n filter?: (option: MultiSelectOption, query: string) => boolean;\n /** Message shown when no option matches. */\n emptyMessage?: string;\n className?: string;\n}\n\nfunction defaultFilter(option: MultiSelectOption, query: string): boolean {\n if (!query) return true;\n return option.label.toLowerCase().includes(query.toLowerCase());\n}\n\n/**\n * MultiSelect — a filterable dropdown that selects many options, shown as\n * removable chips inside the field. Selecting toggles a value; Backspace on an\n * empty query removes the last chip.\n *\n * Keyboard: ArrowUp/ArrowDown navigate, Enter toggles the active option, Esc\n * closes, Backspace (empty input) pops the last chip.\n */\nexport function MultiSelect({\n options,\n value,\n onChange,\n label,\n placeholder = \"Selecione\",\n helperText,\n error,\n disabled,\n maxItems,\n filter = defaultFilter,\n emptyMessage = \"Nenhuma opção encontrada\",\n className,\n}: MultiSelectProps) {\n const id = useId();\n const rootRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [activeIndex, setActiveIndex] = useState(0);\n\n const selectedSet = useMemo(() => new Set(value), [value]);\n const selectedOptions = useMemo(\n () =>\n value\n .map((v) => options.find((o) => o.value === v))\n .filter((o): o is MultiSelectOption => Boolean(o)),\n [value, options],\n );\n const filtered = useMemo(\n () => options.filter((o) => filter(o, query)),\n [options, filter, query],\n );\n\n const atMax = maxItems !== undefined && value.length >= maxItems;\n\n const toggle = useCallback(\n (option: MultiSelectOption): void => {\n if (option.disabled) return;\n if (selectedSet.has(option.value)) {\n onChange(value.filter((v) => v !== option.value));\n } else {\n if (atMax) return;\n onChange([...value, option.value]);\n }\n setQuery(\"\");\n inputRef.current?.focus();\n },\n [selectedSet, onChange, value, atMax],\n );\n\n const removeAt = useCallback(\n (optionValue: string): void => {\n onChange(value.filter((v) => v !== optionValue));\n },\n [onChange, value],\n );\n\n useEffect(() => {\n if (!open) return;\n const onDown = (event: MouseEvent): void => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n setOpen(false);\n setQuery(\"\");\n }\n };\n window.addEventListener(\"mousedown\", onDown);\n return () => window.removeEventListener(\"mousedown\", onDown);\n }, [open]);\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setOpen(true);\n setActiveIndex((current) => Math.min(filtered.length - 1, current + 1));\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((current) => Math.max(0, current - 1));\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n const option = filtered[activeIndex];\n if (option) toggle(option);\n } else if (event.key === \"Escape\") {\n setOpen(false);\n setQuery(\"\");\n } else if (event.key === \"Backspace\" && query === \"\" && value.length > 0) {\n removeAt(value[value.length - 1]);\n }\n };\n\n return (\n <div ref={rootRef} className={cn(styles.wrapper, error && styles.error, className)}>\n {label && (\n <label htmlFor={id} className={styles.label}>\n {label}\n </label>\n )}\n <div\n className={cn(styles.field, disabled && styles.disabled)}\n onMouseDown={(event) => {\n if (disabled) return;\n // Keep focus on the input when clicking empty field space.\n if (event.target === event.currentTarget) {\n event.preventDefault();\n inputRef.current?.focus();\n setOpen(true);\n }\n }}\n >\n {selectedOptions.map((option) => (\n <span key={option.value} className={styles.chip}>\n {option.label}\n <button\n type=\"button\"\n className={styles.chipRemove}\n aria-label={`Remover ${option.label}`}\n disabled={disabled}\n onMouseDown={(event) => {\n event.preventDefault();\n removeAt(option.value);\n }}\n >\n ×\n </button>\n </span>\n ))}\n <input\n id={id}\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={`${id}-listbox`}\n aria-autocomplete=\"list\"\n className={styles.input}\n placeholder={value.length === 0 ? placeholder : \"\"}\n disabled={disabled}\n value={query}\n onFocus={() => setOpen(true)}\n onChange={(event) => {\n setQuery(event.target.value);\n setOpen(true);\n setActiveIndex(0);\n }}\n onKeyDown={handleKeyDown}\n />\n </div>\n {open && (\n <ul\n id={`${id}-listbox`}\n role=\"listbox\"\n aria-multiselectable\n className={styles.menu}\n >\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n filtered.map((option, index) => {\n const isSelected = selectedSet.has(option.value);\n return (\n <li\n key={option.value}\n role=\"option\"\n aria-selected={isSelected}\n aria-disabled={option.disabled || (!isSelected && atMax)}\n className={cn(\n styles.option,\n index === activeIndex && styles.active,\n isSelected && styles.selected,\n )}\n onMouseEnter={() => setActiveIndex(index)}\n onMouseDown={(event) => {\n event.preventDefault();\n toggle(option);\n }}\n >\n <span className={styles.check} aria-hidden>\n {isSelected ? \"✓\" : \"\"}\n </span>\n {option.label}\n </li>\n );\n })\n )}\n </ul>\n )}\n {error ? (\n <span className={styles.errorText}>{error}</span>\n ) : helperText ? (\n <span className={styles.helper}>{helperText}</span>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;AAmCA,SAAS,EAAc,GAA2B,GAAwB;CAEtE,OADA,CAAK,KACE,EAAO,MAAM,YAAY,CAAC,CAAC,SAAS,EAAM,YAAY,CAAC;AAClE;AAUA,SAAgB,EAAY,EACxB,YACA,UACA,aACA,UACA,iBAAc,aACd,eACA,UACA,aACA,aACA,YAAS,GACT,kBAAe,4BACf,gBACiB;CACjB,IAAM,IAAK,EAAM,GACX,IAAU,EAAuB,IAAI,GACrC,IAAW,EAAyB,IAAI,GACxC,CAAC,GAAM,KAAW,EAAS,EAAK,GAChC,CAAC,GAAO,KAAY,EAAS,EAAE,GAC/B,CAAC,GAAa,KAAkB,EAAS,CAAC,GAE1C,IAAc,QAAc,IAAI,IAAI,CAAK,GAAG,CAAC,CAAK,CAAC,GACnD,IAAkB,QAEhB,EACK,KAAK,MAAM,EAAQ,MAAM,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAC9C,QAAQ,MAA8B,EAAQ,CAAE,GACzD,CAAC,GAAO,CAAO,CACnB,GACM,IAAW,QACP,EAAQ,QAAQ,MAAM,EAAO,GAAG,CAAK,CAAC,GAC5C;EAAC;EAAS;EAAQ;CAAK,CAC3B,GAEM,IAAQ,MAAa,KAAA,KAAa,EAAM,UAAU,GAElD,IAAS,GACV,MAAoC;EAC7B,OAAO,UACX;OAAI,EAAY,IAAI,EAAO,KAAK,GAC5B,EAAS,EAAM,QAAQ,MAAM,MAAM,EAAO,KAAK,CAAC;QAC7C;IACH,IAAI,GAAO;IACX,EAAS,CAAC,GAAG,GAAO,EAAO,KAAK,CAAC;GACrC;GAEA,AADA,EAAS,EAAE,GACX,EAAS,SAAS,MAAM;EAFxB;CAGJ,GACA;EAAC;EAAa;EAAU;EAAO;CAAK,CACxC,GAEM,IAAW,GACZ,MAA8B;EAC3B,EAAS,EAAM,QAAQ,MAAM,MAAM,CAAW,CAAC;CACnD,GACA,CAAC,GAAU,CAAK,CACpB;CAkCA,OAhCA,QAAgB;EACZ,IAAI,CAAC,GAAM;EACX,IAAM,KAAU,MAA4B;GACxC,AAAI,EAAQ,WAAW,CAAC,EAAQ,QAAQ,SAAS,EAAM,MAAc,MACjE,EAAQ,EAAK,GACb,EAAS,EAAE;EAEnB;EAEA,OADA,OAAO,iBAAiB,aAAa,CAAM,SAC9B,OAAO,oBAAoB,aAAa,CAAM;CAC/D,GAAG,CAAC,CAAI,CAAC,GAuBL,kBAAC,OAAD;EAAK,KAAK;EAAS,WAAW,EAAG,EAAO,SAAS,KAAS,EAAO,OAAO,CAAS;EAAjF,UAAA;GACK,KACG,kBAAC,SAAD;IAAO,SAAS;IAAI,WAAW,EAAO;IACjC,UAAA;GACE,CAAA;GAEX,kBAAC,OAAD;IACI,WAAW,EAAG,EAAO,OAAO,KAAY,EAAO,QAAQ;IACvD,cAAc,MAAU;KAChB,KAEA,EAAM,WAAW,EAAM,kBACvB,EAAM,eAAe,GACrB,EAAS,SAAS,MAAM,GACxB,EAAQ,EAAI;IAEpB;IAVJ,UAAA,CAYK,EAAgB,KAAK,MAClB,kBAAC,QAAD;KAAyB,WAAW,EAAO;KAA3C,UAAA,CACK,EAAO,OACR,kBAAC,UAAD;MACI,MAAK;MACL,WAAW,EAAO;MAClB,cAAY,WAAW,EAAO;MACpB;MACV,cAAc,MAAU;OAEpB,AADA,EAAM,eAAe,GACrB,EAAS,EAAO,KAAK;MACzB;MACH,UAAA;KAEO,CAAA,CACN;IAdK,GAAA,EAAO,KAcZ,CACT,GACD,kBAAC,SAAD;KACQ;KACJ,KAAK;KACL,MAAK;KACL,MAAK;KACL,iBAAe;KACf,iBAAe,GAAG,EAAG;KACrB,qBAAkB;KAClB,WAAW,EAAO;KAClB,aAAa,EAAM,WAAW,IAAI,IAAc;KACtC;KACV,OAAO;KACP,eAAe,EAAQ,EAAI;KAC3B,WAAW,MAAU;MAGjB,AAFA,EAAS,EAAM,OAAO,KAAK,GAC3B,EAAQ,EAAI,GACZ,EAAe,CAAC;KACpB;KACA,YA1EO,MAAuD;MAC1E,IAAI,EAAM,QAAQ,aAGd,AAFA,EAAM,eAAe,GACrB,EAAQ,EAAI,GACZ,GAAgB,MAAY,KAAK,IAAI,EAAS,SAAS,GAAG,IAAU,CAAC,CAAC;WACnE,IAAI,EAAM,QAAQ,WAErB,AADA,EAAM,eAAe,GACrB,GAAgB,MAAY,KAAK,IAAI,GAAG,IAAU,CAAC,CAAC;WACjD,IAAI,EAAM,QAAQ,SAAS;OAC9B,EAAM,eAAe;OACrB,IAAM,IAAS,EAAS;OACxB,AAAI,KAAQ,EAAO,CAAM;MAC7B,OAAO,AAAI,EAAM,QAAQ,YACrB,EAAQ,EAAK,GACb,EAAS,EAAE,KACJ,EAAM,QAAQ,eAAe,MAAU,MAAM,EAAM,SAAS,KACnE,EAAS,EAAM,EAAM,SAAS,EAAE;KAExC;IAyDa,CAAA,CACA;;GACJ,KACG,kBAAC,MAAD;IACI,IAAI,GAAG,EAAG;IACV,MAAK;IACL,wBAAA;IACA,WAAW,EAAO;IAEjB,UAAA,EAAS,WAAW,IACjB,kBAAC,MAAD;KAAI,WAAW,EAAO;KAAQ,UAAA;IAAiB,CAAA,IAE/C,EAAS,KAAK,GAAQ,MAAU;KAC5B,IAAM,IAAa,EAAY,IAAI,EAAO,KAAK;KAC/C,OACI,kBAAC,MAAD;MAEI,MAAK;MACL,iBAAe;MACf,iBAAe,EAAO,YAAa,CAAC,KAAc;MAClD,WAAW,EACP,EAAO,QACP,MAAU,KAAe,EAAO,QAChC,KAAc,EAAO,QACzB;MACA,oBAAoB,EAAe,CAAK;MACxC,cAAc,MAAU;OAEpB,AADA,EAAM,eAAe,GACrB,EAAO,CAAM;MACjB;MAdJ,UAAA,CAgBI,kBAAC,QAAD;OAAM,WAAW,EAAO;OAAO,eAAA;OAC1B,UAAA,IAAa,MAAM;MAClB,CAAA,GACL,EAAO,KACR;KAnBK,GAAA,EAAO,KAmBZ;IAEZ,CAAC;GAEL,CAAA;GAEP,IACG,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAY,UAAA;GAAY,CAAA,IAChD,IACA,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAS,UAAA;GAAiB,CAAA,IAClD;EACH;;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"NProgress.cjs","names":[],"sources":["../../../src/components/NProgress/NProgress.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./NProgress.module.css\";\n\n/** Snapshot of the progress controller state delivered to subscribers. */\nexport interface NProgressState {\n /** Current progress, `0` (empty) to `1` (complete). */\n value: number;\n /** Whether the bar should be visible. */\n active: boolean;\n}\n\n/** Listener invoked whenever the progress state changes. */\nexport type NProgressListener = (state: NProgressState) => void;\n\n/** Imperative top-loading-bar controller. */\nexport interface NProgressController {\n /** Show the bar and start trickling toward ~0.9. */\n start: () => void;\n /** Complete to `1`, then hide the bar shortly after. */\n done: () => void;\n /** Set the progress explicitly. Values are clamped to `0..1`. */\n set: (n: number) => void;\n /** Increment progress by `amount` (default a small trickle step). */\n inc: (amount?: number) => void;\n /** Subscribe to state changes. Returns an unsubscribe function. */\n subscribe: (listener: NProgressListener) => () => void;\n}\n\nconst TRICKLE_INTERVAL_MS = 300;\nconst TRICKLE_CEILING = 0.9;\nconst DONE_HIDE_DELAY_MS = 300;\n\nfunction clamp(n: number): number {\n if (n < 0) return 0;\n if (n > 1) return 1;\n return n;\n}\n\nfunction createNProgress(): NProgressController {\n let state: NProgressState = { value: 0, active: false };\n const listeners = new Set<NProgressListener>();\n let trickleTimer: ReturnType<typeof setInterval> | null = null;\n let hideTimer: ReturnType<typeof setTimeout> | null = null;\n\n const emit = (): void => {\n for (const listener of listeners) listener(state);\n };\n\n const update = (next: Partial<NProgressState>): void => {\n state = { ...state, ...next };\n emit();\n };\n\n const stopTrickle = (): void => {\n if (trickleTimer !== null) {\n clearInterval(trickleTimer);\n trickleTimer = null;\n }\n };\n\n const clearHide = (): void => {\n if (hideTimer !== null) {\n clearTimeout(hideTimer);\n hideTimer = null;\n }\n };\n\n const inc = (amount?: number): void => {\n const current = state.value;\n if (current >= TRICKLE_CEILING) return;\n const step = amount ?? (1 - current) * 0.1 + 0.01;\n update({ value: Math.min(clamp(current + step), TRICKLE_CEILING) });\n };\n\n const start = (): void => {\n clearHide();\n if (state.active) return;\n update({ active: true, value: state.value > 0 ? state.value : 0.08 });\n stopTrickle();\n trickleTimer = setInterval(() => inc(), TRICKLE_INTERVAL_MS);\n };\n\n const done = (): void => {\n stopTrickle();\n clearHide();\n update({ value: 1, active: true });\n hideTimer = setTimeout(() => {\n update({ active: false, value: 0 });\n hideTimer = null;\n }, DONE_HIDE_DELAY_MS);\n };\n\n const set = (n: number): void => {\n clearHide();\n const value = clamp(n);\n update({ value, active: value < 1 ? true : state.active });\n };\n\n const subscribe = (listener: NProgressListener): (() => void) => {\n listeners.add(listener);\n listener(state);\n return () => {\n listeners.delete(listener);\n };\n };\n\n return { start, done, set, inc, subscribe };\n}\n\n/**\n * Module-level singleton progress controller. Drive it imperatively from\n * anywhere (router transitions, fetch interceptors) and render the visual bar\n * with {@link NProgressBar}.\n *\n * @example\n * nprogress.start();\n * await loadData();\n * nprogress.done();\n */\nexport const nprogress: NProgressController = createNProgress();\n\n/** Props for {@link NProgressBar}. */\nexport interface NProgressBarProps {\n /** Bar color. Defaults to `var(--tempest-primary)`. */\n color?: string;\n /** Bar height in pixels. Default `3`. */\n height?: number;\n /** Extra class applied to the bar element. */\n className?: string;\n}\n\n/**\n * Fixed top loading bar bound to the {@link nprogress} singleton. Mount once\n * near the app root; it renders nothing while inactive.\n *\n * @example\n * <NProgressBar />\n */\nexport function NProgressBar({ color, height = 3, className }: NProgressBarProps) {\n const [state, setState] = useState<NProgressState>({ value: 0, active: false });\n\n useEffect(() => nprogress.subscribe(setState), []);\n\n if (!state.active) return null;\n\n const style: CSSProperties = {\n width: `${Math.round(state.value * 100)}%`,\n height: `${height}px`,\n background: color ?? \"var(--tempest-primary)\",\n };\n\n return (\n <div\n className={cn(styles.bar, className)}\n style={style}\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(state.value * 100)}\n />\n );\n}\n"],"mappings":"gIA8BA,IAAM,EAAsB,IACtB,EAAkB,GAClB,EAAqB,IAE3B,SAAS,EAAM,EAAmB,CAG9B,OAFI,EAAI,EAAU,EACd,EAAI,EAAU,EACX,CACX,CAEA,SAAS,GAAuC,CAC5C,IAAI,EAAwB,CAAE,MAAO,EAAG,OAAQ,EAAM,EAChD,EAAY,IAAI,IAClB,EAAsD,KACtD,EAAkD,KAEhD,MAAmB,CACrB,IAAK,IAAM,KAAY,EAAW,EAAS,CAAK,CACpD,EAEM,EAAU,GAAwC,CACpD,EAAQ,CAAE,GAAG,EAAO,GAAG,CAAK,EAC5B,EAAK,CACT,EAEM,MAA0B,CACxB,IAAiB,OACjB,cAAc,CAAY,EAC1B,EAAe,KAEvB,EAEM,MAAwB,CACtB,IAAc,OACd,aAAa,CAAS,EACtB,EAAY,KAEpB,EAEM,EAAO,GAA0B,CACnC,IAAM,EAAU,EAAM,MACtB,GAAI,GAAW,EAAiB,OAChC,IAAM,EAAO,IAAW,EAAI,GAAW,GAAM,IAC7C,EAAO,CAAE,MAAO,KAAK,IAAI,EAAM,EAAU,CAAI,EAAG,CAAe,CAAE,CAAC,CACtE,EAkCA,MAAO,CAAE,UAhCiB,CACtB,EAAU,EACN,GAAM,SACV,EAAO,CAAE,OAAQ,GAAM,MAAO,EAAM,MAAQ,EAAI,EAAM,MAAQ,GAAK,CAAC,EACpE,EAAY,EACZ,EAAe,gBAAkB,EAAI,EAAG,CAAmB,EAC/D,EA0BgB,SAxBS,CACrB,EAAY,EACZ,EAAU,EACV,EAAO,CAAE,MAAO,EAAG,OAAQ,EAAK,CAAC,EACjC,EAAY,eAAiB,CACzB,EAAO,CAAE,OAAQ,GAAO,MAAO,CAAE,CAAC,EAClC,EAAY,IAChB,EAAG,CAAkB,CACzB,EAgBsB,IAdT,GAAoB,CAC7B,EAAU,EACV,IAAM,EAAQ,EAAM,CAAC,EACrB,EAAO,CAAE,QAAO,OAAQ,EAAQ,GAAW,EAAM,MAAO,CAAC,CAC7D,EAU2B,MAAK,UARb,IACf,EAAU,IAAI,CAAQ,EACtB,EAAS,CAAK,MACD,CACT,EAAU,OAAO,CAAQ,CAC7B,EAGsC,CAC9C,CAYA,IAAa,EAAiC,EAAgB,EAmB9D,SAAgB,EAAa,CAAE,QAAO,SAAS,EAAG,aAAgC,CAC9E,GAAM,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,CAAqC,CAAE,MAAO,EAAG,OAAQ,EAAM,CAAC,EAI9E,IAFA,EAAA,EAAA,UAAA,KAAgB,EAAU,UAAU,CAAQ,EAAG,CAAC,CAAC,EAE7C,CAAC,EAAM,OAAQ,OAAO,KAE1B,IAAM,EAAuB,CACzB,MAAO,GAAG,KAAK,MAAM,EAAM,MAAQ,GAAG,EAAE,GACxC,OAAQ,GAAG,EAAO,IAClB,WAAY,GAAS,wBACzB,EAEA,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,CAAS,EAC5B,QACP,KAAK,cACL,gBAAe,EACf,gBAAe,IACf,gBAAe,KAAK,MAAM,EAAM,MAAQ,GAAG,CAC9C,CAAA,CAET"}
1
+ {"version":3,"file":"NProgress.cjs","names":[],"sources":["../../../src/components/NProgress/NProgress.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./NProgress.module.css\";\n\n/** Snapshot of the progress controller state delivered to subscribers. */\nexport interface NProgressState {\n /** Current progress, `0` (empty) to `1` (complete). */\n value: number;\n /** Whether the bar should be visible. */\n active: boolean;\n}\n\n/** Listener invoked whenever the progress state changes. */\nexport type NProgressListener = (state: NProgressState) => void;\n\n/** Imperative top-loading-bar controller. */\nexport interface NProgressController {\n /** Show the bar and start trickling toward ~0.9. */\n start: () => void;\n /** Complete to `1`, then hide the bar shortly after. */\n done: () => void;\n /** Set the progress explicitly. Values are clamped to `0..1`. */\n set: (n: number) => void;\n /** Increment progress by `amount` (default a small trickle step). */\n inc: (amount?: number) => void;\n /** Subscribe to state changes. Returns an unsubscribe function. */\n subscribe: (listener: NProgressListener) => () => void;\n}\n\nconst TRICKLE_INTERVAL_MS = 300;\nconst TRICKLE_CEILING = 0.9;\nconst DONE_HIDE_DELAY_MS = 300;\n\nfunction clamp(n: number): number {\n if (n < 0) return 0;\n if (n > 1) return 1;\n return n;\n}\n\nfunction createNProgress(): NProgressController {\n let state: NProgressState = { value: 0, active: false };\n const listeners = new Set<NProgressListener>();\n let trickleTimer: ReturnType<typeof setInterval> | null = null;\n let hideTimer: ReturnType<typeof setTimeout> | null = null;\n\n const emit = (): void => {\n for (const listener of listeners) listener(state);\n };\n\n const update = (next: Partial<NProgressState>): void => {\n state = { ...state, ...next };\n emit();\n };\n\n const stopTrickle = (): void => {\n if (trickleTimer !== null) {\n clearInterval(trickleTimer);\n trickleTimer = null;\n }\n };\n\n const clearHide = (): void => {\n if (hideTimer !== null) {\n clearTimeout(hideTimer);\n hideTimer = null;\n }\n };\n\n const inc = (amount?: number): void => {\n const current = state.value;\n if (current >= TRICKLE_CEILING) return;\n const step = amount ?? (1 - current) * 0.1 + 0.01;\n update({ value: Math.min(clamp(current + step), TRICKLE_CEILING) });\n };\n\n const start = (): void => {\n clearHide();\n if (state.active) return;\n update({ active: true, value: state.value > 0 ? state.value : 0.08 });\n stopTrickle();\n trickleTimer = setInterval(() => inc(), TRICKLE_INTERVAL_MS);\n };\n\n const done = (): void => {\n stopTrickle();\n clearHide();\n update({ value: 1, active: true });\n hideTimer = setTimeout(() => {\n update({ active: false, value: 0 });\n hideTimer = null;\n }, DONE_HIDE_DELAY_MS);\n };\n\n const set = (n: number): void => {\n clearHide();\n const value = clamp(n);\n update({ value, active: value < 1 ? true : state.active });\n };\n\n const subscribe = (listener: NProgressListener): (() => void) => {\n listeners.add(listener);\n listener(state);\n return () => {\n listeners.delete(listener);\n };\n };\n\n return { start, done, set, inc, subscribe };\n}\n\n/**\n * Module-level singleton progress controller. Drive it imperatively from\n * anywhere (router transitions, fetch interceptors) and render the visual bar\n * with {@link NProgressBar}.\n *\n * @example\n * nprogress.start();\n * await loadData();\n * nprogress.done();\n */\nexport const nprogress: NProgressController = createNProgress();\n\n/** Props for {@link NProgressBar}. */\nexport interface NProgressBarProps {\n /** Bar color. Defaults to `var(--tempest-primary)`. */\n color?: string;\n /** Bar height in pixels. Default `3`. */\n height?: number;\n /** Extra class applied to the bar element. */\n className?: string;\n}\n\n/**\n * Fixed top loading bar bound to the {@link nprogress} singleton. Mount once\n * near the app root; it renders nothing while inactive.\n *\n * @example\n * <NProgressBar />\n */\nexport function NProgressBar({ color, height = 3, className }: NProgressBarProps) {\n const [state, setState] = useState<NProgressState>({ value: 0, active: false });\n\n useEffect(() => nprogress.subscribe(setState), []);\n\n if (!state.active) return null;\n\n const style: CSSProperties = {\n width: `${Math.round(state.value * 100)}%`,\n height: `${height}px`,\n background: color ?? \"var(--tempest-primary)\",\n };\n\n return (\n <div\n className={cn(styles.bar, className)}\n style={style}\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(state.value * 100)}\n />\n );\n}\n"],"mappings":"gIA8BA,IAAM,EAAsB,IACtB,EAAkB,GAClB,EAAqB,IAE3B,SAAS,EAAM,EAAmB,CAG9B,OAFI,EAAI,EAAU,EACd,EAAI,EAAU,EACX,CACX,CAEA,SAAS,GAAuC,CAC5C,IAAI,EAAwB,CAAE,MAAO,EAAG,OAAQ,EAAM,EAChD,EAAY,IAAI,IAClB,EAAsD,KACtD,EAAkD,KAEhD,MAAmB,CACrB,IAAK,IAAM,KAAY,EAAW,EAAS,CAAK,CACpD,EAEM,EAAU,GAAwC,CACpD,EAAQ,CAAE,GAAG,EAAO,GAAG,CAAK,EAC5B,EAAK,CACT,EAEM,MAA0B,CACxB,IAAiB,OACjB,cAAc,CAAY,EAC1B,EAAe,KAEvB,EAEM,MAAwB,CACtB,IAAc,OACd,aAAa,CAAS,EACtB,EAAY,KAEpB,EAEM,EAAO,GAA0B,CACnC,IAAM,EAAU,EAAM,MACtB,GAAI,GAAW,EAAiB,OAChC,IAAM,EAAO,IAAW,EAAI,GAAW,GAAM,IAC7C,EAAO,CAAE,MAAO,KAAK,IAAI,EAAM,EAAU,CAAI,EAAG,CAAe,CAAE,CAAC,CACtE,EAkCA,MAAO,CAAE,UAhCiB,CACtB,EAAU,EACN,GAAM,SACV,EAAO,CAAE,OAAQ,GAAM,MAAO,EAAM,MAAQ,EAAI,EAAM,MAAQ,GAAK,CAAC,EACpE,EAAY,EACZ,EAAe,gBAAkB,EAAI,EAAG,CAAmB,EAC/D,EA0BgB,SAxBS,CACrB,EAAY,EACZ,EAAU,EACV,EAAO,CAAE,MAAO,EAAG,OAAQ,EAAK,CAAC,EACjC,EAAY,eAAiB,CACzB,EAAO,CAAE,OAAQ,GAAO,MAAO,CAAE,CAAC,EAClC,EAAY,IAChB,EAAG,CAAkB,CACzB,EAgBsB,IAdT,GAAoB,CAC7B,EAAU,EACV,IAAM,EAAQ,EAAM,CAAC,EACrB,EAAO,CAAE,QAAO,OAAQ,EAAQ,GAAW,EAAM,MAAO,CAAC,CAC7D,EAU2B,MAAK,UARb,IACf,EAAU,IAAI,CAAQ,EACtB,EAAS,CAAK,MACD,CACT,EAAU,OAAO,CAAQ,CAC7B,EAGsC,CAC9C,CAYA,IAAa,EAAiC,EAAgB,EAmB9D,SAAgB,EAAa,CAAE,QAAO,SAAS,EAAG,aAAgC,CAC9E,GAAM,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAyB,CAAE,MAAO,EAAG,OAAQ,EAAM,CAAC,EAI9E,IAFA,EAAA,EAAA,UAAA,KAAgB,EAAU,UAAU,CAAQ,EAAG,CAAC,CAAC,EAE7C,CAAC,EAAM,OAAQ,OAAO,KAE1B,IAAM,EAAuB,CACzB,MAAO,GAAG,KAAK,MAAM,EAAM,MAAQ,GAAG,EAAE,GACxC,OAAQ,GAAG,EAAO,IAClB,WAAY,GAAS,wBACzB,EAEA,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,CAAS,EAC5B,QACP,KAAK,cACL,gBAAe,EACf,gBAAe,IACf,gBAAe,KAAK,MAAM,EAAM,MAAQ,GAAG,CAC9C,CAAA,CAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"Navbar.cjs","names":[],"sources":["../../../src/components/Navbar/Navbar.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Navbar.module.css\";\n\nexport type NavbarTone = \"surface\" | \"primary\" | \"transparent\";\n\nexport interface NavbarProps extends HTMLAttributes<HTMLElement> {\n /** Left slot — typically logo + brand name. */\n logo?: ReactNode;\n /** Center slot — typically nav links. */\n nav?: ReactNode;\n /** Right slot — typically user menu / actions. */\n actions?: ReactNode;\n /** Make the bar sticky at the top of the scroll container. Default `true`. */\n sticky?: boolean;\n /** Visual tone. Default `\"surface\"`. */\n tone?: NavbarTone;\n /** When set, renders a thin bottom border. Default `true`. */\n bordered?: boolean;\n}\n\n/**\n * Top app bar. Three-slot layout (logo / nav / actions) that collapses\n * gracefully on mobile (nav slot wraps below).\n *\n * @example\n * <Navbar\n * logo={<img src=\"/logo.svg\" alt=\"App\" />}\n * nav={<NavLinks />}\n * actions={<UserMenu />}\n * />\n */\nexport function Navbar({\n logo,\n nav,\n actions,\n sticky = true,\n tone = \"surface\",\n bordered = true,\n className,\n ...props\n}: NavbarProps) {\n return (\n <header\n className={cn(\n styles.navbar,\n styles[tone],\n sticky && styles.sticky,\n bordered && styles.bordered,\n className,\n )}\n {...props}\n >\n {logo && <div className={styles.logo}>{logo}</div>}\n {nav && <nav className={styles.nav}>{nav}</nav>}\n {actions && <div className={styles.actions}>{actions}</div>}\n </header>\n );\n}\n"],"mappings":"0GAgCA,SAAgB,EAAO,CACnB,OACA,MACA,UACA,SAAS,GACT,OAAO,UACP,WAAW,GACX,YACA,GAAG,GACS,CACZ,OACI,EAAA,EAAA,KAAA,CAAC,SAAD,CACI,UAAW,EAAA,GACP,EAAA,QAAO,OACP,EAAA,QAAO,GACP,GAAU,EAAA,QAAO,OACjB,GAAY,EAAA,QAAO,SACnB,CACJ,EACA,GAAI,WARR,CAUK,IAAQ,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,cAAO,CAAU,CAAA,EAChD,IAAO,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,aAAM,CAAS,CAAA,EAC7C,IAAW,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,iBAAU,CAAa,CAAA,CACtD,GAEhB"}
1
+ {"version":3,"file":"Navbar.cjs","names":[],"sources":["../../../src/components/Navbar/Navbar.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Navbar.module.css\";\n\nexport type NavbarTone = \"surface\" | \"primary\" | \"transparent\";\n\nexport interface NavbarProps extends HTMLAttributes<HTMLElement> {\n /** Left slot — typically logo + brand name. */\n logo?: ReactNode;\n /** Center slot — typically nav links. */\n nav?: ReactNode;\n /** Right slot — typically user menu / actions. */\n actions?: ReactNode;\n /** Make the bar sticky at the top of the scroll container. Default `true`. */\n sticky?: boolean;\n /** Visual tone. Default `\"surface\"`. */\n tone?: NavbarTone;\n /** When set, renders a thin bottom border. Default `true`. */\n bordered?: boolean;\n}\n\n/**\n * Top app bar. Three-slot layout (logo / nav / actions) that collapses\n * gracefully on mobile (nav slot wraps below).\n *\n * @example\n * <Navbar\n * logo={<img src=\"/logo.svg\" alt=\"App\" />}\n * nav={<NavLinks />}\n * actions={<UserMenu />}\n * />\n */\nexport function Navbar({\n logo,\n nav,\n actions,\n sticky = true,\n tone = \"surface\",\n bordered = true,\n className,\n ...props\n}: NavbarProps) {\n return (\n <header\n className={cn(\n styles.navbar,\n styles[tone],\n sticky && styles.sticky,\n bordered && styles.bordered,\n className,\n )}\n {...props}\n >\n {logo && <div className={styles.logo}>{logo}</div>}\n {nav && <nav className={styles.nav}>{nav}</nav>}\n {actions && <div className={styles.actions}>{actions}</div>}\n </header>\n );\n}\n"],"mappings":"0GAgCA,SAAgB,EAAO,CACnB,OACA,MACA,UACA,SAAS,GACT,OAAO,UACP,WAAW,GACX,YACA,GAAG,GACS,CACZ,OACI,EAAA,EAAA,KAAA,CAAC,SAAD,CACI,UAAW,EAAA,GACP,EAAA,QAAO,OACP,EAAA,QAAO,GACP,GAAU,EAAA,QAAO,OACjB,GAAY,EAAA,QAAO,SACnB,CACJ,EACA,GAAI,EARR,SAAA,CAUK,IAAQ,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAO,SAAA,CAAU,CAAA,EAChD,IAAO,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,IAAM,SAAA,CAAS,CAAA,EAC7C,IAAW,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,QAAU,SAAA,CAAa,CAAA,CACtD,GAEhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"Navbar.js","names":[],"sources":["../../../src/components/Navbar/Navbar.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Navbar.module.css\";\n\nexport type NavbarTone = \"surface\" | \"primary\" | \"transparent\";\n\nexport interface NavbarProps extends HTMLAttributes<HTMLElement> {\n /** Left slot — typically logo + brand name. */\n logo?: ReactNode;\n /** Center slot — typically nav links. */\n nav?: ReactNode;\n /** Right slot — typically user menu / actions. */\n actions?: ReactNode;\n /** Make the bar sticky at the top of the scroll container. Default `true`. */\n sticky?: boolean;\n /** Visual tone. Default `\"surface\"`. */\n tone?: NavbarTone;\n /** When set, renders a thin bottom border. Default `true`. */\n bordered?: boolean;\n}\n\n/**\n * Top app bar. Three-slot layout (logo / nav / actions) that collapses\n * gracefully on mobile (nav slot wraps below).\n *\n * @example\n * <Navbar\n * logo={<img src=\"/logo.svg\" alt=\"App\" />}\n * nav={<NavLinks />}\n * actions={<UserMenu />}\n * />\n */\nexport function Navbar({\n logo,\n nav,\n actions,\n sticky = true,\n tone = \"surface\",\n bordered = true,\n className,\n ...props\n}: NavbarProps) {\n return (\n <header\n className={cn(\n styles.navbar,\n styles[tone],\n sticky && styles.sticky,\n bordered && styles.bordered,\n className,\n )}\n {...props}\n >\n {logo && <div className={styles.logo}>{logo}</div>}\n {nav && <nav className={styles.nav}>{nav}</nav>}\n {actions && <div className={styles.actions}>{actions}</div>}\n </header>\n );\n}\n"],"mappings":";;;;AAgCA,SAAgB,EAAO,EACnB,SACA,QACA,YACA,YAAS,IACT,UAAO,WACP,cAAW,IACX,cACA,GAAG,KACS;CACZ,OACI,kBAAC,UAAD;EACI,WAAW,EACP,EAAO,QACP,EAAO,IACP,KAAU,EAAO,QACjB,KAAY,EAAO,UACnB,CACJ;EACA,GAAI;YARR;GAUK,KAAQ,kBAAC,OAAD;IAAK,WAAW,EAAO;cAAO;GAAU,CAAA;GAChD,KAAO,kBAAC,OAAD;IAAK,WAAW,EAAO;cAAM;GAAS,CAAA;GAC7C,KAAW,kBAAC,OAAD;IAAK,WAAW,EAAO;cAAU;GAAa,CAAA;EACtD;;AAEhB"}
1
+ {"version":3,"file":"Navbar.js","names":[],"sources":["../../../src/components/Navbar/Navbar.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Navbar.module.css\";\n\nexport type NavbarTone = \"surface\" | \"primary\" | \"transparent\";\n\nexport interface NavbarProps extends HTMLAttributes<HTMLElement> {\n /** Left slot — typically logo + brand name. */\n logo?: ReactNode;\n /** Center slot — typically nav links. */\n nav?: ReactNode;\n /** Right slot — typically user menu / actions. */\n actions?: ReactNode;\n /** Make the bar sticky at the top of the scroll container. Default `true`. */\n sticky?: boolean;\n /** Visual tone. Default `\"surface\"`. */\n tone?: NavbarTone;\n /** When set, renders a thin bottom border. Default `true`. */\n bordered?: boolean;\n}\n\n/**\n * Top app bar. Three-slot layout (logo / nav / actions) that collapses\n * gracefully on mobile (nav slot wraps below).\n *\n * @example\n * <Navbar\n * logo={<img src=\"/logo.svg\" alt=\"App\" />}\n * nav={<NavLinks />}\n * actions={<UserMenu />}\n * />\n */\nexport function Navbar({\n logo,\n nav,\n actions,\n sticky = true,\n tone = \"surface\",\n bordered = true,\n className,\n ...props\n}: NavbarProps) {\n return (\n <header\n className={cn(\n styles.navbar,\n styles[tone],\n sticky && styles.sticky,\n bordered && styles.bordered,\n className,\n )}\n {...props}\n >\n {logo && <div className={styles.logo}>{logo}</div>}\n {nav && <nav className={styles.nav}>{nav}</nav>}\n {actions && <div className={styles.actions}>{actions}</div>}\n </header>\n );\n}\n"],"mappings":";;;;AAgCA,SAAgB,EAAO,EACnB,SACA,QACA,YACA,YAAS,IACT,UAAO,WACP,cAAW,IACX,cACA,GAAG,KACS;CACZ,OACI,kBAAC,UAAD;EACI,WAAW,EACP,EAAO,QACP,EAAO,IACP,KAAU,EAAO,QACjB,KAAY,EAAO,UACnB,CACJ;EACA,GAAI;EARR,UAAA;GAUK,KAAQ,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAO,UAAA;GAAU,CAAA;GAChD,KAAO,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAM,UAAA;GAAS,CAAA;GAC7C,KAAW,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAU,UAAA;GAAa,CAAA;EACtD;;AAEhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"NavigationMenu.cjs","names":[],"sources":["../../../src/components/NavigationMenu/NavigationMenu.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body resolves the active item from the\n * current path, owns the open submenu and the hover-intent delay, all of which\n * decide the same highlighted row.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./NavigationMenu.module.css\";\n\nexport interface NavigationMenuItem {\n /** Visible label for the entry. */\n label: ReactNode;\n /** When set, the entry renders as an anchor. */\n href?: string;\n /** Invoked when the entry is activated (click / Enter). */\n onSelect?: () => void;\n /** Nested entries — presence turns the item into a submenu trigger. */\n children?: NavigationMenuItem[];\n}\n\nexport interface NavigationMenuProps extends HTMLAttributes<HTMLElement> {\n /** Top-level navigation entries. */\n items: NavigationMenuItem[];\n}\n\n/**\n * Horizontal navigation menu with hover/click/focus dropdown submenus.\n *\n * - Top-level items render in a `<nav><ul>`.\n * - Items with `children` open a submenu panel (`role=\"menu\"`) on hover, focus,\n * or click. Only one panel is open at a time.\n * - Closes on outside click, Escape, or selecting a leaf entry.\n *\n * @example\n * <NavigationMenu\n * items={[\n * { label: \"Home\", href: \"/\" },\n * {\n * label: \"Products\",\n * children: [\n * { label: \"Analytics\", href: \"/analytics\" },\n * { label: \"Billing\", onSelect: () => openBilling() },\n * ],\n * },\n * ]}\n * />\n */\nexport function NavigationMenu({ items, className, ...props }: NavigationMenuProps) {\n const [clickedIndex, setClickedIndex] = useState<number>(-1);\n const [hovered, setHovered] = useState<number>(-1);\n const baseId = useId();\n const rootRef = useRef<HTMLElement>(null);\n\n const close = useCallback((): void => {\n setClickedIndex(-1);\n setHovered(-1);\n }, []);\n\n const openIndex = clickedIndex !== -1 ? clickedIndex : hovered;\n\n useEffect(() => {\n if (openIndex === -1) return;\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") close();\n };\n const onDown = (event: MouseEvent): void => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) close();\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onDown);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onDown);\n };\n }, [openIndex, close]);\n\n const renderLeaf = (item: NavigationMenuItem, role: \"none\" | \"menuitem\"): ReactNode => {\n const handleClick = (): void => {\n item.onSelect?.();\n close();\n };\n if (item.href) {\n return (\n <a\n href={item.href}\n role={role === \"menuitem\" ? \"menuitem\" : undefined}\n className={styles.link}\n onClick={handleClick}\n >\n {item.label}\n </a>\n );\n }\n return (\n <button\n type=\"button\"\n role={role === \"menuitem\" ? \"menuitem\" : undefined}\n className={styles.link}\n onClick={handleClick}\n >\n {item.label}\n </button>\n );\n };\n\n return (\n <nav ref={rootRef} className={cn(styles.root, className)} {...props}>\n <ul className={styles.list}>\n {items.map((item, index) => {\n const hasChildren = !!item.children && item.children.length > 0;\n if (!hasChildren) {\n return (\n <li key={index} className={styles.item}>\n {renderLeaf(item, \"none\")}\n </li>\n );\n }\n const open = openIndex === index;\n const panelId = `${baseId}-panel-${index}`;\n return (\n <li\n key={index}\n className={styles.item}\n onMouseEnter={() => setHovered(index)}\n onMouseLeave={() => setHovered((prev) => (prev === index ? -1 : prev))}\n >\n <button\n type=\"button\"\n className={styles.trigger}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={panelId}\n onClick={() =>\n setClickedIndex((prev) => (prev === index ? -1 : index))\n }\n onFocus={() => setHovered(index)}\n >\n {item.label}\n </button>\n {open && (\n <ul id={panelId} role=\"menu\" className={styles.panel}>\n {item.children!.map((child, childIndex) => (\n <li key={childIndex} role=\"none\" className={styles.subItem}>\n {renderLeaf(child, \"menuitem\")}\n </li>\n ))}\n </ul>\n )}\n </li>\n );\n })}\n </ul>\n </nav>\n );\n}\n"],"mappings":"qIAgDA,SAAgB,EAAe,CAAE,QAAO,YAAW,GAAG,GAA8B,CAChF,GAAM,CAAC,EAAc,IAAA,EAAA,EAAA,SAAA,CAAoC,EAAE,EACrD,CAAC,EAAS,IAAA,EAAA,EAAA,SAAA,CAA+B,EAAE,EAC3C,GAAA,EAAA,EAAA,MAAA,CAAe,EACf,GAAA,EAAA,EAAA,OAAA,CAA8B,IAAI,EAElC,GAAA,EAAA,EAAA,YAAA,KAAgC,CAClC,EAAgB,EAAE,EAClB,EAAW,EAAE,CACjB,EAAG,CAAC,CAAC,EAEC,EAAY,IAAiB,GAAoB,EAAf,GAExC,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,IAAc,GAAI,OACtB,IAAM,EAAS,GAA+B,CACtC,EAAM,MAAQ,UAAU,EAAM,CACtC,EACM,EAAU,GAA4B,CACpC,EAAQ,SAAW,CAAC,EAAQ,QAAQ,SAAS,EAAM,MAAc,GAAG,EAAM,CAClF,EAGA,OAFA,OAAO,iBAAiB,UAAW,CAAK,EACxC,OAAO,iBAAiB,YAAa,CAAM,MAC9B,CACT,OAAO,oBAAoB,UAAW,CAAK,EAC3C,OAAO,oBAAoB,YAAa,CAAM,CAClD,CACJ,EAAG,CAAC,EAAW,CAAK,CAAC,EAErB,IAAM,GAAc,EAA0B,IAAyC,CACnF,IAAM,MAA0B,CAC5B,EAAK,WAAW,EAChB,EAAM,CACV,EAaA,OAZI,EAAK,MAED,EAAA,EAAA,IAAA,CAAC,IAAD,CACI,KAAM,EAAK,KACX,KAAM,IAAS,WAAa,WAAa,IAAA,GACzC,UAAW,EAAA,QAAO,KAClB,QAAS,WAER,EAAK,KACP,CAAA,GAIP,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,KAAM,IAAS,WAAa,WAAa,IAAA,GACzC,UAAW,EAAA,QAAO,KAClB,QAAS,WAER,EAAK,KACF,CAAA,CAEhB,EAEA,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,IAAK,EAAS,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,CAAS,EAAG,GAAI,YAC1D,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,cACjB,EAAM,KAAK,EAAM,IAAU,CAExB,GAAI,EADkB,EAAK,UAAY,EAAK,SAAS,OAAS,GAE1D,OACI,EAAA,EAAA,IAAA,CAAC,KAAD,CAAgB,UAAW,EAAA,QAAO,cAC7B,EAAW,EAAM,MAAM,CACxB,EAFK,CAEL,EAGZ,IAAM,EAAO,IAAc,EACrB,EAAU,GAAG,EAAO,SAAS,IACnC,OACI,EAAA,EAAA,KAAA,CAAC,KAAD,CAEI,UAAW,EAAA,QAAO,KAClB,iBAAoB,EAAW,CAAK,EACpC,iBAAoB,EAAY,GAAU,IAAS,EAAQ,GAAK,CAAK,WAJzE,EAMI,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,QAClB,gBAAc,OACd,gBAAe,EACf,gBAAe,EACf,YACI,EAAiB,GAAU,IAAS,EAAQ,GAAK,CAAM,EAE3D,YAAe,EAAW,CAAK,WAE9B,EAAK,KACF,CAAA,EACP,IACG,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,GAAI,EAAS,KAAK,OAAO,UAAW,EAAA,QAAO,eAC1C,EAAK,SAAU,KAAK,EAAO,KACxB,EAAA,EAAA,IAAA,CAAC,KAAD,CAAqB,KAAK,OAAO,UAAW,EAAA,QAAO,iBAC9C,EAAW,EAAO,UAAU,CAC7B,EAFK,CAEL,CACP,CACD,CAAA,CAER,GA3BK,CA2BL,CAEZ,CAAC,CACD,CAAA,CACH,CAAA,CAEb"}
1
+ {"version":3,"file":"NavigationMenu.cjs","names":[],"sources":["../../../src/components/NavigationMenu/NavigationMenu.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body resolves the active item from the\n * current path, owns the open submenu and the hover-intent delay, all of which\n * decide the same highlighted row.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./NavigationMenu.module.css\";\n\nexport interface NavigationMenuItem {\n /** Visible label for the entry. */\n label: ReactNode;\n /** When set, the entry renders as an anchor. */\n href?: string;\n /** Invoked when the entry is activated (click / Enter). */\n onSelect?: () => void;\n /** Nested entries — presence turns the item into a submenu trigger. */\n children?: NavigationMenuItem[];\n}\n\nexport interface NavigationMenuProps extends HTMLAttributes<HTMLElement> {\n /** Top-level navigation entries. */\n items: NavigationMenuItem[];\n}\n\n/**\n * Horizontal navigation menu with hover/click/focus dropdown submenus.\n *\n * - Top-level items render in a `<nav><ul>`.\n * - Items with `children` open a submenu panel (`role=\"menu\"`) on hover, focus,\n * or click. Only one panel is open at a time.\n * - Closes on outside click, Escape, or selecting a leaf entry.\n *\n * @example\n * <NavigationMenu\n * items={[\n * { label: \"Home\", href: \"/\" },\n * {\n * label: \"Products\",\n * children: [\n * { label: \"Analytics\", href: \"/analytics\" },\n * { label: \"Billing\", onSelect: () => openBilling() },\n * ],\n * },\n * ]}\n * />\n */\nexport function NavigationMenu({ items, className, ...props }: NavigationMenuProps) {\n const [clickedIndex, setClickedIndex] = useState<number>(-1);\n const [hovered, setHovered] = useState<number>(-1);\n const baseId = useId();\n const rootRef = useRef<HTMLElement>(null);\n\n const close = useCallback((): void => {\n setClickedIndex(-1);\n setHovered(-1);\n }, []);\n\n const openIndex = clickedIndex !== -1 ? clickedIndex : hovered;\n\n useEffect(() => {\n if (openIndex === -1) return;\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") close();\n };\n const onDown = (event: MouseEvent): void => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) close();\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onDown);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onDown);\n };\n }, [openIndex, close]);\n\n const renderLeaf = (item: NavigationMenuItem, role: \"none\" | \"menuitem\"): ReactNode => {\n const handleClick = (): void => {\n item.onSelect?.();\n close();\n };\n if (item.href) {\n return (\n <a\n href={item.href}\n role={role === \"menuitem\" ? \"menuitem\" : undefined}\n className={styles.link}\n onClick={handleClick}\n >\n {item.label}\n </a>\n );\n }\n return (\n <button\n type=\"button\"\n role={role === \"menuitem\" ? \"menuitem\" : undefined}\n className={styles.link}\n onClick={handleClick}\n >\n {item.label}\n </button>\n );\n };\n\n return (\n <nav ref={rootRef} className={cn(styles.root, className)} {...props}>\n <ul className={styles.list}>\n {items.map((item, index) => {\n const hasChildren = !!item.children && item.children.length > 0;\n if (!hasChildren) {\n return (\n <li key={index} className={styles.item}>\n {renderLeaf(item, \"none\")}\n </li>\n );\n }\n const open = openIndex === index;\n const panelId = `${baseId}-panel-${index}`;\n return (\n <li\n key={index}\n className={styles.item}\n onMouseEnter={() => setHovered(index)}\n onMouseLeave={() => setHovered((prev) => (prev === index ? -1 : prev))}\n >\n <button\n type=\"button\"\n className={styles.trigger}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={panelId}\n onClick={() =>\n setClickedIndex((prev) => (prev === index ? -1 : index))\n }\n onFocus={() => setHovered(index)}\n >\n {item.label}\n </button>\n {open && (\n <ul id={panelId} role=\"menu\" className={styles.panel}>\n {item.children!.map((child, childIndex) => (\n <li key={childIndex} role=\"none\" className={styles.subItem}>\n {renderLeaf(child, \"menuitem\")}\n </li>\n ))}\n </ul>\n )}\n </li>\n );\n })}\n </ul>\n </nav>\n );\n}\n"],"mappings":"qIAgDA,SAAgB,EAAe,CAAE,QAAO,YAAW,GAAG,GAA8B,CAChF,GAAM,CAAC,EAAc,IAAA,EAAmB,EAAA,SAAA,CAAiB,EAAE,EACrD,CAAC,EAAS,IAAA,EAAc,EAAA,SAAA,CAAiB,EAAE,EAC3C,GAAA,EAAS,EAAA,MAAA,CAAM,EACf,GAAA,EAAU,EAAA,OAAA,CAAoB,IAAI,EAElC,GAAA,EAAQ,EAAA,YAAA,KAAwB,CAClC,EAAgB,EAAE,EAClB,EAAW,EAAE,CACjB,EAAG,CAAC,CAAC,EAEC,EAAY,IAAiB,GAAoB,EAAf,GAExC,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,IAAc,GAAI,OACtB,IAAM,EAAS,GAA+B,CACtC,EAAM,MAAQ,UAAU,EAAM,CACtC,EACM,EAAU,GAA4B,CACpC,EAAQ,SAAW,CAAC,EAAQ,QAAQ,SAAS,EAAM,MAAc,GAAG,EAAM,CAClF,EAGA,OAFA,OAAO,iBAAiB,UAAW,CAAK,EACxC,OAAO,iBAAiB,YAAa,CAAM,MAC9B,CACT,OAAO,oBAAoB,UAAW,CAAK,EAC3C,OAAO,oBAAoB,YAAa,CAAM,CAClD,CACJ,EAAG,CAAC,EAAW,CAAK,CAAC,EAErB,IAAM,GAAc,EAA0B,IAAyC,CACnF,IAAM,MAA0B,CAC5B,EAAK,WAAW,EAChB,EAAM,CACV,EAaA,OAZI,EAAK,MAED,EAAA,EAAA,IAAA,CAAC,IAAD,CACI,KAAM,EAAK,KACX,KAAM,IAAS,WAAa,WAAa,IAAA,GACzC,UAAW,EAAA,QAAO,KAClB,QAAS,EAER,SAAA,EAAK,KACP,CAAA,GAIP,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,KAAM,IAAS,WAAa,WAAa,IAAA,GACzC,UAAW,EAAA,QAAO,KAClB,QAAS,EAER,SAAA,EAAK,KACF,CAAA,CAEhB,EAEA,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,IAAK,EAAS,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,CAAS,EAAG,GAAI,EAC1D,UAAA,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,KACjB,SAAA,EAAM,KAAK,EAAM,IAAU,CAExB,GAAI,EADkB,EAAK,UAAY,EAAK,SAAS,OAAS,GAE1D,OACI,EAAA,EAAA,IAAA,CAAC,KAAD,CAAgB,UAAW,EAAA,QAAO,KAC7B,SAAA,EAAW,EAAM,MAAM,CACxB,EAFK,CAEL,EAGZ,IAAM,EAAO,IAAc,EACrB,EAAU,GAAG,EAAO,SAAS,IACnC,OACI,EAAA,EAAA,KAAA,CAAC,KAAD,CAEI,UAAW,EAAA,QAAO,KAClB,iBAAoB,EAAW,CAAK,EACpC,iBAAoB,EAAY,GAAU,IAAS,EAAQ,GAAK,CAAK,EAJzE,SAAA,EAMI,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,QAClB,gBAAc,OACd,gBAAe,EACf,gBAAe,EACf,YACI,EAAiB,GAAU,IAAS,EAAQ,GAAK,CAAM,EAE3D,YAAe,EAAW,CAAK,EAE9B,SAAA,EAAK,KACF,CAAA,EACP,IACG,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,GAAI,EAAS,KAAK,OAAO,UAAW,EAAA,QAAO,MAC1C,SAAA,EAAK,SAAU,KAAK,EAAO,KACxB,EAAA,EAAA,IAAA,CAAC,KAAD,CAAqB,KAAK,OAAO,UAAW,EAAA,QAAO,QAC9C,SAAA,EAAW,EAAO,UAAU,CAC7B,EAFK,CAEL,CACP,CACD,CAAA,CAER,CA3BK,EAAA,CA2BL,CAEZ,CAAC,CACD,CAAA,CACH,CAAA,CAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"NavigationMenu.js","names":[],"sources":["../../../src/components/NavigationMenu/NavigationMenu.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body resolves the active item from the\n * current path, owns the open submenu and the hover-intent delay, all of which\n * decide the same highlighted row.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./NavigationMenu.module.css\";\n\nexport interface NavigationMenuItem {\n /** Visible label for the entry. */\n label: ReactNode;\n /** When set, the entry renders as an anchor. */\n href?: string;\n /** Invoked when the entry is activated (click / Enter). */\n onSelect?: () => void;\n /** Nested entries — presence turns the item into a submenu trigger. */\n children?: NavigationMenuItem[];\n}\n\nexport interface NavigationMenuProps extends HTMLAttributes<HTMLElement> {\n /** Top-level navigation entries. */\n items: NavigationMenuItem[];\n}\n\n/**\n * Horizontal navigation menu with hover/click/focus dropdown submenus.\n *\n * - Top-level items render in a `<nav><ul>`.\n * - Items with `children` open a submenu panel (`role=\"menu\"`) on hover, focus,\n * or click. Only one panel is open at a time.\n * - Closes on outside click, Escape, or selecting a leaf entry.\n *\n * @example\n * <NavigationMenu\n * items={[\n * { label: \"Home\", href: \"/\" },\n * {\n * label: \"Products\",\n * children: [\n * { label: \"Analytics\", href: \"/analytics\" },\n * { label: \"Billing\", onSelect: () => openBilling() },\n * ],\n * },\n * ]}\n * />\n */\nexport function NavigationMenu({ items, className, ...props }: NavigationMenuProps) {\n const [clickedIndex, setClickedIndex] = useState<number>(-1);\n const [hovered, setHovered] = useState<number>(-1);\n const baseId = useId();\n const rootRef = useRef<HTMLElement>(null);\n\n const close = useCallback((): void => {\n setClickedIndex(-1);\n setHovered(-1);\n }, []);\n\n const openIndex = clickedIndex !== -1 ? clickedIndex : hovered;\n\n useEffect(() => {\n if (openIndex === -1) return;\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") close();\n };\n const onDown = (event: MouseEvent): void => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) close();\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onDown);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onDown);\n };\n }, [openIndex, close]);\n\n const renderLeaf = (item: NavigationMenuItem, role: \"none\" | \"menuitem\"): ReactNode => {\n const handleClick = (): void => {\n item.onSelect?.();\n close();\n };\n if (item.href) {\n return (\n <a\n href={item.href}\n role={role === \"menuitem\" ? \"menuitem\" : undefined}\n className={styles.link}\n onClick={handleClick}\n >\n {item.label}\n </a>\n );\n }\n return (\n <button\n type=\"button\"\n role={role === \"menuitem\" ? \"menuitem\" : undefined}\n className={styles.link}\n onClick={handleClick}\n >\n {item.label}\n </button>\n );\n };\n\n return (\n <nav ref={rootRef} className={cn(styles.root, className)} {...props}>\n <ul className={styles.list}>\n {items.map((item, index) => {\n const hasChildren = !!item.children && item.children.length > 0;\n if (!hasChildren) {\n return (\n <li key={index} className={styles.item}>\n {renderLeaf(item, \"none\")}\n </li>\n );\n }\n const open = openIndex === index;\n const panelId = `${baseId}-panel-${index}`;\n return (\n <li\n key={index}\n className={styles.item}\n onMouseEnter={() => setHovered(index)}\n onMouseLeave={() => setHovered((prev) => (prev === index ? -1 : prev))}\n >\n <button\n type=\"button\"\n className={styles.trigger}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={panelId}\n onClick={() =>\n setClickedIndex((prev) => (prev === index ? -1 : index))\n }\n onFocus={() => setHovered(index)}\n >\n {item.label}\n </button>\n {open && (\n <ul id={panelId} role=\"menu\" className={styles.panel}>\n {item.children!.map((child, childIndex) => (\n <li key={childIndex} role=\"none\" className={styles.subItem}>\n {renderLeaf(child, \"menuitem\")}\n </li>\n ))}\n </ul>\n )}\n </li>\n );\n })}\n </ul>\n </nav>\n );\n}\n"],"mappings":";;;;;AAgDA,SAAgB,EAAe,EAAE,UAAO,cAAW,GAAG,KAA8B;CAChF,IAAM,CAAC,GAAc,KAAmB,EAAiB,EAAE,GACrD,CAAC,GAAS,KAAc,EAAiB,EAAE,GAC3C,IAAS,EAAM,GACf,IAAU,EAAoB,IAAI,GAElC,IAAQ,QAAwB;EAElC,AADA,EAAgB,EAAE,GAClB,EAAW,EAAE;CACjB,GAAG,CAAC,CAAC,GAEC,IAAY,MAAiB,KAAoB,IAAf;CAExC,QAAgB;EACZ,IAAI,MAAc,IAAI;EACtB,IAAM,KAAS,MAA+B;GAC1C,AAAI,EAAM,QAAQ,YAAU,EAAM;EACtC,GACM,KAAU,MAA4B;GACxC,AAAI,EAAQ,WAAW,CAAC,EAAQ,QAAQ,SAAS,EAAM,MAAc,KAAG,EAAM;EAClF;EAGA,OAFA,OAAO,iBAAiB,WAAW,CAAK,GACxC,OAAO,iBAAiB,aAAa,CAAM,SAC9B;GAET,AADA,OAAO,oBAAoB,WAAW,CAAK,GAC3C,OAAO,oBAAoB,aAAa,CAAM;EAClD;CACJ,GAAG,CAAC,GAAW,CAAK,CAAC;CAErB,IAAM,KAAc,GAA0B,MAAyC;EACnF,IAAM,UAA0B;GAE5B,AADA,EAAK,WAAW,GAChB,EAAM;EACV;EAaA,OAZI,EAAK,OAED,kBAAC,KAAD;GACI,MAAM,EAAK;GACX,MAAM,MAAS,aAAa,aAAa,KAAA;GACzC,WAAW,EAAO;GAClB,SAAS;aAER,EAAK;EACP,CAAA,IAIP,kBAAC,UAAD;GACI,MAAK;GACL,MAAM,MAAS,aAAa,aAAa,KAAA;GACzC,WAAW,EAAO;GAClB,SAAS;aAER,EAAK;EACF,CAAA;CAEhB;CAEA,OACI,kBAAC,OAAD;EAAK,KAAK;EAAS,WAAW,EAAG,EAAO,MAAM,CAAS;EAAG,GAAI;YAC1D,kBAAC,MAAD;GAAI,WAAW,EAAO;aACjB,EAAM,KAAK,GAAM,MAAU;IAExB,IAAI,EADkB,EAAK,YAAY,EAAK,SAAS,SAAS,IAE1D,OACI,kBAAC,MAAD;KAAgB,WAAW,EAAO;eAC7B,EAAW,GAAM,MAAM;IACxB,GAFK,CAEL;IAGZ,IAAM,IAAO,MAAc,GACrB,IAAU,GAAG,EAAO,SAAS;IACnC,OACI,kBAAC,MAAD;KAEI,WAAW,EAAO;KAClB,oBAAoB,EAAW,CAAK;KACpC,oBAAoB,GAAY,MAAU,MAAS,IAAQ,KAAK,CAAK;eAJzE,CAMI,kBAAC,UAAD;MACI,MAAK;MACL,WAAW,EAAO;MAClB,iBAAc;MACd,iBAAe;MACf,iBAAe;MACf,eACI,GAAiB,MAAU,MAAS,IAAQ,KAAK,CAAM;MAE3D,eAAe,EAAW,CAAK;gBAE9B,EAAK;KACF,CAAA,GACP,KACG,kBAAC,MAAD;MAAI,IAAI;MAAS,MAAK;MAAO,WAAW,EAAO;gBAC1C,EAAK,SAAU,KAAK,GAAO,MACxB,kBAAC,MAAD;OAAqB,MAAK;OAAO,WAAW,EAAO;iBAC9C,EAAW,GAAO,UAAU;MAC7B,GAFK,CAEL,CACP;KACD,CAAA,CAER;OA3BK,CA2BL;GAEZ,CAAC;EACD,CAAA;CACH,CAAA;AAEb"}
1
+ {"version":3,"file":"NavigationMenu.js","names":[],"sources":["../../../src/components/NavigationMenu/NavigationMenu.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body resolves the active item from the\n * current path, owns the open submenu and the hover-intent delay, all of which\n * decide the same highlighted row.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./NavigationMenu.module.css\";\n\nexport interface NavigationMenuItem {\n /** Visible label for the entry. */\n label: ReactNode;\n /** When set, the entry renders as an anchor. */\n href?: string;\n /** Invoked when the entry is activated (click / Enter). */\n onSelect?: () => void;\n /** Nested entries — presence turns the item into a submenu trigger. */\n children?: NavigationMenuItem[];\n}\n\nexport interface NavigationMenuProps extends HTMLAttributes<HTMLElement> {\n /** Top-level navigation entries. */\n items: NavigationMenuItem[];\n}\n\n/**\n * Horizontal navigation menu with hover/click/focus dropdown submenus.\n *\n * - Top-level items render in a `<nav><ul>`.\n * - Items with `children` open a submenu panel (`role=\"menu\"`) on hover, focus,\n * or click. Only one panel is open at a time.\n * - Closes on outside click, Escape, or selecting a leaf entry.\n *\n * @example\n * <NavigationMenu\n * items={[\n * { label: \"Home\", href: \"/\" },\n * {\n * label: \"Products\",\n * children: [\n * { label: \"Analytics\", href: \"/analytics\" },\n * { label: \"Billing\", onSelect: () => openBilling() },\n * ],\n * },\n * ]}\n * />\n */\nexport function NavigationMenu({ items, className, ...props }: NavigationMenuProps) {\n const [clickedIndex, setClickedIndex] = useState<number>(-1);\n const [hovered, setHovered] = useState<number>(-1);\n const baseId = useId();\n const rootRef = useRef<HTMLElement>(null);\n\n const close = useCallback((): void => {\n setClickedIndex(-1);\n setHovered(-1);\n }, []);\n\n const openIndex = clickedIndex !== -1 ? clickedIndex : hovered;\n\n useEffect(() => {\n if (openIndex === -1) return;\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") close();\n };\n const onDown = (event: MouseEvent): void => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) close();\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onDown);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onDown);\n };\n }, [openIndex, close]);\n\n const renderLeaf = (item: NavigationMenuItem, role: \"none\" | \"menuitem\"): ReactNode => {\n const handleClick = (): void => {\n item.onSelect?.();\n close();\n };\n if (item.href) {\n return (\n <a\n href={item.href}\n role={role === \"menuitem\" ? \"menuitem\" : undefined}\n className={styles.link}\n onClick={handleClick}\n >\n {item.label}\n </a>\n );\n }\n return (\n <button\n type=\"button\"\n role={role === \"menuitem\" ? \"menuitem\" : undefined}\n className={styles.link}\n onClick={handleClick}\n >\n {item.label}\n </button>\n );\n };\n\n return (\n <nav ref={rootRef} className={cn(styles.root, className)} {...props}>\n <ul className={styles.list}>\n {items.map((item, index) => {\n const hasChildren = !!item.children && item.children.length > 0;\n if (!hasChildren) {\n return (\n <li key={index} className={styles.item}>\n {renderLeaf(item, \"none\")}\n </li>\n );\n }\n const open = openIndex === index;\n const panelId = `${baseId}-panel-${index}`;\n return (\n <li\n key={index}\n className={styles.item}\n onMouseEnter={() => setHovered(index)}\n onMouseLeave={() => setHovered((prev) => (prev === index ? -1 : prev))}\n >\n <button\n type=\"button\"\n className={styles.trigger}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={panelId}\n onClick={() =>\n setClickedIndex((prev) => (prev === index ? -1 : index))\n }\n onFocus={() => setHovered(index)}\n >\n {item.label}\n </button>\n {open && (\n <ul id={panelId} role=\"menu\" className={styles.panel}>\n {item.children!.map((child, childIndex) => (\n <li key={childIndex} role=\"none\" className={styles.subItem}>\n {renderLeaf(child, \"menuitem\")}\n </li>\n ))}\n </ul>\n )}\n </li>\n );\n })}\n </ul>\n </nav>\n );\n}\n"],"mappings":";;;;;AAgDA,SAAgB,EAAe,EAAE,UAAO,cAAW,GAAG,KAA8B;CAChF,IAAM,CAAC,GAAc,KAAmB,EAAiB,EAAE,GACrD,CAAC,GAAS,KAAc,EAAiB,EAAE,GAC3C,IAAS,EAAM,GACf,IAAU,EAAoB,IAAI,GAElC,IAAQ,QAAwB;EAElC,AADA,EAAgB,EAAE,GAClB,EAAW,EAAE;CACjB,GAAG,CAAC,CAAC,GAEC,IAAY,MAAiB,KAAoB,IAAf;CAExC,QAAgB;EACZ,IAAI,MAAc,IAAI;EACtB,IAAM,KAAS,MAA+B;GAC1C,AAAI,EAAM,QAAQ,YAAU,EAAM;EACtC,GACM,KAAU,MAA4B;GACxC,AAAI,EAAQ,WAAW,CAAC,EAAQ,QAAQ,SAAS,EAAM,MAAc,KAAG,EAAM;EAClF;EAGA,OAFA,OAAO,iBAAiB,WAAW,CAAK,GACxC,OAAO,iBAAiB,aAAa,CAAM,SAC9B;GAET,AADA,OAAO,oBAAoB,WAAW,CAAK,GAC3C,OAAO,oBAAoB,aAAa,CAAM;EAClD;CACJ,GAAG,CAAC,GAAW,CAAK,CAAC;CAErB,IAAM,KAAc,GAA0B,MAAyC;EACnF,IAAM,UAA0B;GAE5B,AADA,EAAK,WAAW,GAChB,EAAM;EACV;EAaA,OAZI,EAAK,OAED,kBAAC,KAAD;GACI,MAAM,EAAK;GACX,MAAM,MAAS,aAAa,aAAa,KAAA;GACzC,WAAW,EAAO;GAClB,SAAS;GAER,UAAA,EAAK;EACP,CAAA,IAIP,kBAAC,UAAD;GACI,MAAK;GACL,MAAM,MAAS,aAAa,aAAa,KAAA;GACzC,WAAW,EAAO;GAClB,SAAS;GAER,UAAA,EAAK;EACF,CAAA;CAEhB;CAEA,OACI,kBAAC,OAAD;EAAK,KAAK;EAAS,WAAW,EAAG,EAAO,MAAM,CAAS;EAAG,GAAI;EAC1D,UAAA,kBAAC,MAAD;GAAI,WAAW,EAAO;GACjB,UAAA,EAAM,KAAK,GAAM,MAAU;IAExB,IAAI,EADkB,EAAK,YAAY,EAAK,SAAS,SAAS,IAE1D,OACI,kBAAC,MAAD;KAAgB,WAAW,EAAO;KAC7B,UAAA,EAAW,GAAM,MAAM;IACxB,GAFK,CAEL;IAGZ,IAAM,IAAO,MAAc,GACrB,IAAU,GAAG,EAAO,SAAS;IACnC,OACI,kBAAC,MAAD;KAEI,WAAW,EAAO;KAClB,oBAAoB,EAAW,CAAK;KACpC,oBAAoB,GAAY,MAAU,MAAS,IAAQ,KAAK,CAAK;KAJzE,UAAA,CAMI,kBAAC,UAAD;MACI,MAAK;MACL,WAAW,EAAO;MAClB,iBAAc;MACd,iBAAe;MACf,iBAAe;MACf,eACI,GAAiB,MAAU,MAAS,IAAQ,KAAK,CAAM;MAE3D,eAAe,EAAW,CAAK;MAE9B,UAAA,EAAK;KACF,CAAA,GACP,KACG,kBAAC,MAAD;MAAI,IAAI;MAAS,MAAK;MAAO,WAAW,EAAO;MAC1C,UAAA,EAAK,SAAU,KAAK,GAAO,MACxB,kBAAC,MAAD;OAAqB,MAAK;OAAO,WAAW,EAAO;OAC9C,UAAA,EAAW,GAAO,UAAU;MAC7B,GAFK,CAEL,CACP;KACD,CAAA,CAER;IA3BK,GAAA,CA2BL;GAEZ,CAAC;EACD,CAAA;CACH,CAAA;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"NavigationRail.cjs","names":[],"sources":["../../../src/components/NavigationRail/NavigationRail.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./NavigationRail.module.css\";\n\nexport interface NavigationRailItem {\n /** Unique identifier — used as React key and for value matching. */\n key: string;\n /** Visible label. */\n label: ReactNode;\n /** Icon rendered above the label. */\n icon?: ReactNode;\n /** Optional badge content rendered over the icon. */\n badge?: ReactNode;\n /** When true, the item is not selectable. */\n disabled?: boolean;\n}\n\nexport type NavigationRailLabelVisibility = \"all\" | \"selected\" | \"none\";\n\nexport interface NavigationRailProps extends Omit<HTMLAttributes<HTMLElement>, \"onChange\"> {\n items: NavigationRailItem[];\n /** Selected key. */\n value: string;\n /** Called with the new selected key on click. */\n onChange: (key: string) => void;\n /** Top slot — e.g. a FAB or logo. */\n header?: ReactNode;\n /** Bottom slot — pushed to the bottom of the rail. */\n footer?: ReactNode;\n /** Which item labels to show. Default `\"all\"`. */\n labelVisibility?: NavigationRailLabelVisibility;\n /** Extra class names merged onto the root. */\n className?: string;\n}\n\n/**\n * Vertical, compact navigation column for desktop and tablet layouts. Each item\n * stacks an icon over its label, with the active item flagged via\n * `aria-current=\"page\"`. Use `labelVisibility=\"selected\"` to show only the\n * active item's label, or `\"none\"` for an icon-only rail.\n *\n * @example\n * <NavigationRail\n * header={<FloatingActionButton icon={<Plus />} position=\"none\" />}\n * items={[\n * { key: \"home\", label: \"Início\", icon: <Home /> },\n * { key: \"inbox\", label: \"Caixa\", icon: <Inbox />, badge: 3 },\n * ]}\n * value={tab}\n * onChange={setTab}\n * />\n */\nexport function NavigationRail({\n items,\n value,\n onChange,\n header,\n footer,\n labelVisibility = \"all\",\n className,\n ...props\n}: NavigationRailProps) {\n return (\n <nav className={cn(styles.rail, className)} aria-label=\"Navegação lateral\" {...props}>\n {header !== undefined && <div className={styles.header}>{header}</div>}\n <ul className={styles.list}>\n {items.map((item) => {\n const active = item.key === value;\n const showLabel =\n labelVisibility === \"all\" || (labelVisibility === \"selected\" && active);\n return (\n <li key={item.key}>\n <button\n type=\"button\"\n className={cn(styles.item, active && styles.active)}\n aria-current={active ? \"page\" : undefined}\n disabled={item.disabled}\n onClick={() => onChange(item.key)}\n >\n <span className={styles.iconWrap}>\n {item.icon && <span className={styles.icon}>{item.icon}</span>}\n {item.badge !== undefined && (\n <span className={styles.badge}>{item.badge}</span>\n )}\n </span>\n {showLabel && <span className={styles.label}>{item.label}</span>}\n </button>\n </li>\n );\n })}\n </ul>\n {footer !== undefined && <div className={styles.footer}>{footer}</div>}\n </nav>\n );\n}\n"],"mappings":"kHAoDA,SAAgB,EAAe,CAC3B,QACA,QACA,WACA,SACA,SACA,kBAAkB,MAClB,YACA,GAAG,GACiB,CACpB,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,CAAS,EAAG,aAAW,oBAAoB,GAAI,WAA/E,CACK,IAAW,IAAA,KAAa,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,gBAAS,CAAY,CAAA,GACrE,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,cACjB,EAAM,IAAK,GAAS,CACjB,IAAM,EAAS,EAAK,MAAQ,EACtB,EACF,IAAoB,OAAU,IAAoB,YAAc,EACpE,OACI,EAAA,EAAA,IAAA,CAAC,KAAD,CAAA,UACI,EAAA,EAAA,KAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,GAAU,EAAA,QAAO,MAAM,EAClD,eAAc,EAAS,OAAS,IAAA,GAChC,SAAU,EAAK,SACf,YAAe,EAAS,EAAK,GAAG,WALpC,EAOI,EAAA,EAAA,KAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,kBAAxB,CACK,EAAK,OAAQ,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,cAAO,EAAK,IAAW,CAAA,EAC5D,EAAK,QAAU,IAAA,KACZ,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,eAAQ,EAAK,KAAY,CAAA,CAEnD,IACL,IAAa,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,eAAQ,EAAK,KAAY,CAAA,CAC3D,GACR,EAhBK,EAAK,GAgBV,CAEZ,CAAC,CACD,CAAA,EACH,IAAW,IAAA,KAAa,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,gBAAS,CAAY,CAAA,CACpE,GAEb"}
1
+ {"version":3,"file":"NavigationRail.cjs","names":[],"sources":["../../../src/components/NavigationRail/NavigationRail.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./NavigationRail.module.css\";\n\nexport interface NavigationRailItem {\n /** Unique identifier — used as React key and for value matching. */\n key: string;\n /** Visible label. */\n label: ReactNode;\n /** Icon rendered above the label. */\n icon?: ReactNode;\n /** Optional badge content rendered over the icon. */\n badge?: ReactNode;\n /** When true, the item is not selectable. */\n disabled?: boolean;\n}\n\nexport type NavigationRailLabelVisibility = \"all\" | \"selected\" | \"none\";\n\nexport interface NavigationRailProps extends Omit<HTMLAttributes<HTMLElement>, \"onChange\"> {\n items: NavigationRailItem[];\n /** Selected key. */\n value: string;\n /** Called with the new selected key on click. */\n onChange: (key: string) => void;\n /** Top slot — e.g. a FAB or logo. */\n header?: ReactNode;\n /** Bottom slot — pushed to the bottom of the rail. */\n footer?: ReactNode;\n /** Which item labels to show. Default `\"all\"`. */\n labelVisibility?: NavigationRailLabelVisibility;\n /** Extra class names merged onto the root. */\n className?: string;\n}\n\n/**\n * Vertical, compact navigation column for desktop and tablet layouts. Each item\n * stacks an icon over its label, with the active item flagged via\n * `aria-current=\"page\"`. Use `labelVisibility=\"selected\"` to show only the\n * active item's label, or `\"none\"` for an icon-only rail.\n *\n * @example\n * <NavigationRail\n * header={<FloatingActionButton icon={<Plus />} position=\"none\" />}\n * items={[\n * { key: \"home\", label: \"Início\", icon: <Home /> },\n * { key: \"inbox\", label: \"Caixa\", icon: <Inbox />, badge: 3 },\n * ]}\n * value={tab}\n * onChange={setTab}\n * />\n */\nexport function NavigationRail({\n items,\n value,\n onChange,\n header,\n footer,\n labelVisibility = \"all\",\n className,\n ...props\n}: NavigationRailProps) {\n return (\n <nav className={cn(styles.rail, className)} aria-label=\"Navegação lateral\" {...props}>\n {header !== undefined && <div className={styles.header}>{header}</div>}\n <ul className={styles.list}>\n {items.map((item) => {\n const active = item.key === value;\n const showLabel =\n labelVisibility === \"all\" || (labelVisibility === \"selected\" && active);\n return (\n <li key={item.key}>\n <button\n type=\"button\"\n className={cn(styles.item, active && styles.active)}\n aria-current={active ? \"page\" : undefined}\n disabled={item.disabled}\n onClick={() => onChange(item.key)}\n >\n <span className={styles.iconWrap}>\n {item.icon && <span className={styles.icon}>{item.icon}</span>}\n {item.badge !== undefined && (\n <span className={styles.badge}>{item.badge}</span>\n )}\n </span>\n {showLabel && <span className={styles.label}>{item.label}</span>}\n </button>\n </li>\n );\n })}\n </ul>\n {footer !== undefined && <div className={styles.footer}>{footer}</div>}\n </nav>\n );\n}\n"],"mappings":"kHAoDA,SAAgB,EAAe,CAC3B,QACA,QACA,WACA,SACA,SACA,kBAAkB,MAClB,YACA,GAAG,GACiB,CACpB,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,CAAS,EAAG,aAAW,oBAAoB,GAAI,EAA/E,SAAA,CACK,IAAW,IAAA,KAAa,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,OAAS,SAAA,CAAY,CAAA,GACrE,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,KACjB,SAAA,EAAM,IAAK,GAAS,CACjB,IAAM,EAAS,EAAK,MAAQ,EACtB,EACF,IAAoB,OAAU,IAAoB,YAAc,EACpE,OACI,EAAA,EAAA,IAAA,CAAC,KAAD,CAAA,UACI,EAAA,EAAA,KAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,GAAU,EAAA,QAAO,MAAM,EAClD,eAAc,EAAS,OAAS,IAAA,GAChC,SAAU,EAAK,SACf,YAAe,EAAS,EAAK,GAAG,EALpC,SAAA,EAOI,EAAA,EAAA,KAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,SAAxB,SAAA,CACK,EAAK,OAAQ,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,KAAO,SAAA,EAAK,IAAW,CAAA,EAC5D,EAAK,QAAU,IAAA,KACZ,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,MAAQ,SAAA,EAAK,KAAY,CAAA,CAEnD,CACL,CAAA,EAAA,IAAa,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,MAAQ,SAAA,EAAK,KAAY,CAAA,CAC3D,CACR,CAAA,CAAA,EAhBK,EAAK,GAgBV,CAEZ,CAAC,CACD,CAAA,EACH,IAAW,IAAA,KAAa,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,OAAS,SAAA,CAAY,CAAA,CACpE,GAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"NavigationRail.js","names":[],"sources":["../../../src/components/NavigationRail/NavigationRail.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./NavigationRail.module.css\";\n\nexport interface NavigationRailItem {\n /** Unique identifier — used as React key and for value matching. */\n key: string;\n /** Visible label. */\n label: ReactNode;\n /** Icon rendered above the label. */\n icon?: ReactNode;\n /** Optional badge content rendered over the icon. */\n badge?: ReactNode;\n /** When true, the item is not selectable. */\n disabled?: boolean;\n}\n\nexport type NavigationRailLabelVisibility = \"all\" | \"selected\" | \"none\";\n\nexport interface NavigationRailProps extends Omit<HTMLAttributes<HTMLElement>, \"onChange\"> {\n items: NavigationRailItem[];\n /** Selected key. */\n value: string;\n /** Called with the new selected key on click. */\n onChange: (key: string) => void;\n /** Top slot — e.g. a FAB or logo. */\n header?: ReactNode;\n /** Bottom slot — pushed to the bottom of the rail. */\n footer?: ReactNode;\n /** Which item labels to show. Default `\"all\"`. */\n labelVisibility?: NavigationRailLabelVisibility;\n /** Extra class names merged onto the root. */\n className?: string;\n}\n\n/**\n * Vertical, compact navigation column for desktop and tablet layouts. Each item\n * stacks an icon over its label, with the active item flagged via\n * `aria-current=\"page\"`. Use `labelVisibility=\"selected\"` to show only the\n * active item's label, or `\"none\"` for an icon-only rail.\n *\n * @example\n * <NavigationRail\n * header={<FloatingActionButton icon={<Plus />} position=\"none\" />}\n * items={[\n * { key: \"home\", label: \"Início\", icon: <Home /> },\n * { key: \"inbox\", label: \"Caixa\", icon: <Inbox />, badge: 3 },\n * ]}\n * value={tab}\n * onChange={setTab}\n * />\n */\nexport function NavigationRail({\n items,\n value,\n onChange,\n header,\n footer,\n labelVisibility = \"all\",\n className,\n ...props\n}: NavigationRailProps) {\n return (\n <nav className={cn(styles.rail, className)} aria-label=\"Navegação lateral\" {...props}>\n {header !== undefined && <div className={styles.header}>{header}</div>}\n <ul className={styles.list}>\n {items.map((item) => {\n const active = item.key === value;\n const showLabel =\n labelVisibility === \"all\" || (labelVisibility === \"selected\" && active);\n return (\n <li key={item.key}>\n <button\n type=\"button\"\n className={cn(styles.item, active && styles.active)}\n aria-current={active ? \"page\" : undefined}\n disabled={item.disabled}\n onClick={() => onChange(item.key)}\n >\n <span className={styles.iconWrap}>\n {item.icon && <span className={styles.icon}>{item.icon}</span>}\n {item.badge !== undefined && (\n <span className={styles.badge}>{item.badge}</span>\n )}\n </span>\n {showLabel && <span className={styles.label}>{item.label}</span>}\n </button>\n </li>\n );\n })}\n </ul>\n {footer !== undefined && <div className={styles.footer}>{footer}</div>}\n </nav>\n );\n}\n"],"mappings":";;;;AAoDA,SAAgB,EAAe,EAC3B,UACA,UACA,aACA,WACA,WACA,qBAAkB,OAClB,cACA,GAAG,KACiB;CACpB,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,MAAM,CAAS;EAAG,cAAW;EAAoB,GAAI;YAA/E;GACK,MAAW,KAAA,KAAa,kBAAC,OAAD;IAAK,WAAW,EAAO;cAAS;GAAY,CAAA;GACrE,kBAAC,MAAD;IAAI,WAAW,EAAO;cACjB,EAAM,KAAK,MAAS;KACjB,IAAM,IAAS,EAAK,QAAQ,GACtB,IACF,MAAoB,SAAU,MAAoB,cAAc;KACpE,OACI,kBAAC,MAAD,EAAA,UACI,kBAAC,UAAD;MACI,MAAK;MACL,WAAW,EAAG,EAAO,MAAM,KAAU,EAAO,MAAM;MAClD,gBAAc,IAAS,SAAS,KAAA;MAChC,UAAU,EAAK;MACf,eAAe,EAAS,EAAK,GAAG;gBALpC,CAOI,kBAAC,QAAD;OAAM,WAAW,EAAO;iBAAxB,CACK,EAAK,QAAQ,kBAAC,QAAD;QAAM,WAAW,EAAO;kBAAO,EAAK;OAAW,CAAA,GAC5D,EAAK,UAAU,KAAA,KACZ,kBAAC,QAAD;QAAM,WAAW,EAAO;kBAAQ,EAAK;OAAY,CAAA,CAEnD;UACL,KAAa,kBAAC,QAAD;OAAM,WAAW,EAAO;iBAAQ,EAAK;MAAY,CAAA,CAC3D;QACR,GAhBK,EAAK,GAgBV;IAEZ,CAAC;GACD,CAAA;GACH,MAAW,KAAA,KAAa,kBAAC,OAAD;IAAK,WAAW,EAAO;cAAS;GAAY,CAAA;EACpE;;AAEb"}
1
+ {"version":3,"file":"NavigationRail.js","names":[],"sources":["../../../src/components/NavigationRail/NavigationRail.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./NavigationRail.module.css\";\n\nexport interface NavigationRailItem {\n /** Unique identifier — used as React key and for value matching. */\n key: string;\n /** Visible label. */\n label: ReactNode;\n /** Icon rendered above the label. */\n icon?: ReactNode;\n /** Optional badge content rendered over the icon. */\n badge?: ReactNode;\n /** When true, the item is not selectable. */\n disabled?: boolean;\n}\n\nexport type NavigationRailLabelVisibility = \"all\" | \"selected\" | \"none\";\n\nexport interface NavigationRailProps extends Omit<HTMLAttributes<HTMLElement>, \"onChange\"> {\n items: NavigationRailItem[];\n /** Selected key. */\n value: string;\n /** Called with the new selected key on click. */\n onChange: (key: string) => void;\n /** Top slot — e.g. a FAB or logo. */\n header?: ReactNode;\n /** Bottom slot — pushed to the bottom of the rail. */\n footer?: ReactNode;\n /** Which item labels to show. Default `\"all\"`. */\n labelVisibility?: NavigationRailLabelVisibility;\n /** Extra class names merged onto the root. */\n className?: string;\n}\n\n/**\n * Vertical, compact navigation column for desktop and tablet layouts. Each item\n * stacks an icon over its label, with the active item flagged via\n * `aria-current=\"page\"`. Use `labelVisibility=\"selected\"` to show only the\n * active item's label, or `\"none\"` for an icon-only rail.\n *\n * @example\n * <NavigationRail\n * header={<FloatingActionButton icon={<Plus />} position=\"none\" />}\n * items={[\n * { key: \"home\", label: \"Início\", icon: <Home /> },\n * { key: \"inbox\", label: \"Caixa\", icon: <Inbox />, badge: 3 },\n * ]}\n * value={tab}\n * onChange={setTab}\n * />\n */\nexport function NavigationRail({\n items,\n value,\n onChange,\n header,\n footer,\n labelVisibility = \"all\",\n className,\n ...props\n}: NavigationRailProps) {\n return (\n <nav className={cn(styles.rail, className)} aria-label=\"Navegação lateral\" {...props}>\n {header !== undefined && <div className={styles.header}>{header}</div>}\n <ul className={styles.list}>\n {items.map((item) => {\n const active = item.key === value;\n const showLabel =\n labelVisibility === \"all\" || (labelVisibility === \"selected\" && active);\n return (\n <li key={item.key}>\n <button\n type=\"button\"\n className={cn(styles.item, active && styles.active)}\n aria-current={active ? \"page\" : undefined}\n disabled={item.disabled}\n onClick={() => onChange(item.key)}\n >\n <span className={styles.iconWrap}>\n {item.icon && <span className={styles.icon}>{item.icon}</span>}\n {item.badge !== undefined && (\n <span className={styles.badge}>{item.badge}</span>\n )}\n </span>\n {showLabel && <span className={styles.label}>{item.label}</span>}\n </button>\n </li>\n );\n })}\n </ul>\n {footer !== undefined && <div className={styles.footer}>{footer}</div>}\n </nav>\n );\n}\n"],"mappings":";;;;AAoDA,SAAgB,EAAe,EAC3B,UACA,UACA,aACA,WACA,WACA,qBAAkB,OAClB,cACA,GAAG,KACiB;CACpB,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,MAAM,CAAS;EAAG,cAAW;EAAoB,GAAI;EAA/E,UAAA;GACK,MAAW,KAAA,KAAa,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAS,UAAA;GAAY,CAAA;GACrE,kBAAC,MAAD;IAAI,WAAW,EAAO;IACjB,UAAA,EAAM,KAAK,MAAS;KACjB,IAAM,IAAS,EAAK,QAAQ,GACtB,IACF,MAAoB,SAAU,MAAoB,cAAc;KACpE,OACI,kBAAC,MAAD,EAAA,UACI,kBAAC,UAAD;MACI,MAAK;MACL,WAAW,EAAG,EAAO,MAAM,KAAU,EAAO,MAAM;MAClD,gBAAc,IAAS,SAAS,KAAA;MAChC,UAAU,EAAK;MACf,eAAe,EAAS,EAAK,GAAG;MALpC,UAAA,CAOI,kBAAC,QAAD;OAAM,WAAW,EAAO;OAAxB,UAAA,CACK,EAAK,QAAQ,kBAAC,QAAD;QAAM,WAAW,EAAO;QAAO,UAAA,EAAK;OAAW,CAAA,GAC5D,EAAK,UAAU,KAAA,KACZ,kBAAC,QAAD;QAAM,WAAW,EAAO;QAAQ,UAAA,EAAK;OAAY,CAAA,CAEnD;MACL,CAAA,GAAA,KAAa,kBAAC,QAAD;OAAM,WAAW,EAAO;OAAQ,UAAA,EAAK;MAAY,CAAA,CAC3D;KACR,CAAA,EAAA,GAhBK,EAAK,GAgBV;IAEZ,CAAC;GACD,CAAA;GACH,MAAW,KAAA,KAAa,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAS,UAAA;GAAY,CAAA;EACpE;;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"NotificationCenter.cjs","names":[],"sources":["../../../src/components/NotificationCenter/NotificationCenter.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count, function-lines — an inbox has four actions the app\n * must implement (onSelect, onMarkRead, onMarkAllRead, onDismiss) over one list,\n * plus the presentation it needs to render a readable feed: renderIcon, locale, now\n * for relative timestamps, emptyState and title.\n */\nimport type { HTMLAttributes, ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\nimport { relativeTime, type RelativeTimeLocale } from \"@/utils/relative-time\";\n\nimport { Badge } from \"../Badge\";\nimport { EmptyState } from \"../EmptyState\";\nimport type { NotificationItem } from \"./use-notification-inbox\";\nimport styles from \"./NotificationCenter.module.css\";\n\n/**\n * DOM attributes this component redefines.\n *\n * `title` becomes a rendered heading node instead of a tooltip string, and\n * `onSelect` becomes \"an entry was activated\" instead of the DOM text-selection\n * event. Both would be type errors if merged, and silently confusing if allowed\n * through.\n */\ntype OverriddenDomProps = \"children\" | \"title\" | \"onSelect\";\n\nexport interface NotificationCenterProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n OverriddenDomProps\n> {\n /** Entries to show. Rendered in the order given — `useNotificationInbox` sorts newest first. */\n items: readonly NotificationItem[];\n /**\n * Panel heading. Pass `null` to render the list with no header.\n *\n * Widened from the DOM `title` attribute (a `string`) on purpose: this is a\n * rendered heading, not a tooltip, so it takes a node.\n */\n title?: ReactNode;\n /** Activate an entry: click, `Enter` or `Space`. Also marks it read when `onMarkRead` is set. */\n onSelect?: (item: NotificationItem) => void;\n /** Mark one entry as read. Enables the per-item read control. */\n onMarkRead?: (id: string) => void;\n /** Mark every entry as read. Enables the header action. */\n onMarkAllRead?: () => void;\n /** Remove one entry. Enables the per-item dismiss control. */\n onDismiss?: (id: string) => void;\n /** Icon rendered at the leading edge of each row — an `<Icon name={…} />`, say. */\n renderIcon?: (item: NotificationItem) => ReactNode;\n /** Locale for the relative timestamps. Default `\"pt-BR\"`. */\n locale?: RelativeTimeLocale;\n /** Shown when `items` is empty. */\n emptyState?: ReactNode;\n /** Reference point for the relative timestamps. Default: now, at render time. */\n now?: number;\n}\n\n/**\n * Inbox panel for notifications the app has received.\n *\n * Deliberately presentational and controlled: it takes a list and emits intent.\n * Where the list comes from — an API, a service-worker push, `localStorage` — and\n * where read state is written are app decisions, and a component that assumed any\n * of them would be wrong for most apps. `useNotificationInbox` is the companion\n * that holds the state, including the service-worker bridge.\n *\n * It is also just the panel, not a popover: apps mount it inside their own\n * `Popover`, `Drawer` or route. That keeps one component from owning both the\n * inbox and a positioning strategy.\n *\n * @example\n * const inbox = useNotificationInbox();\n *\n * <Popover trigger={<Button>Notificações ({inbox.unreadCount})</Button>}>\n * <NotificationCenter\n * items={inbox.items}\n * onMarkRead={inbox.markRead}\n * onMarkAllRead={inbox.markAllRead}\n * onDismiss={inbox.remove}\n * onSelect={(item) => item.url && navigate(item.url)}\n * />\n * </Popover>\n */\nexport function NotificationCenter({\n items,\n title = \"Notificações\",\n onSelect,\n onMarkRead,\n onMarkAllRead,\n onDismiss,\n renderIcon,\n locale = \"pt-BR\",\n emptyState,\n now,\n className,\n ...rest\n}: NotificationCenterProps) {\n const unreadCount = items.filter((item) => !item.read).length;\n const reference = now ?? new Date().getTime();\n\n /**\n * Activate an entry.\n *\n * Reading a notification is implied by opening it, so activation marks it read\n * as well — otherwise every app would have to remember to call both, and the\n * unread badge would keep counting something the user already saw.\n */\n const activate = (item: NotificationItem): void => {\n if (!item.read) onMarkRead?.(item.id);\n onSelect?.(item);\n };\n\n const interactive = Boolean(onSelect || onMarkRead);\n\n return (\n <div className={cn(styles.panel, className)} {...rest}>\n {(title || (onMarkAllRead && unreadCount > 0)) && (\n <header className={styles.header}>\n {title ? (\n <h2 className={styles.title}>\n {title}\n {unreadCount > 0 && (\n <Badge variant=\"primary\" aria-label={`${unreadCount} não lidas`}>\n {unreadCount}\n </Badge>\n )}\n </h2>\n ) : (\n <span />\n )}\n {onMarkAllRead && unreadCount > 0 && (\n <button\n type=\"button\"\n className={styles.headerAction}\n onClick={onMarkAllRead}\n >\n Marcar todas como lidas\n </button>\n )}\n </header>\n )}\n\n {items.length === 0 ? (\n (emptyState ?? <EmptyState title=\"Nenhuma notificação\" />)\n ) : (\n <ul className={styles.list}>\n {items.map((item) => (\n <li\n key={item.id}\n className={cn(styles.item, !item.read && styles.unread)}\n aria-current={!item.read ? \"true\" : undefined}\n >\n {renderIcon && <span className={styles.icon}>{renderIcon(item)}</span>}\n\n <div className={styles.body}>\n {interactive ? (\n <button\n type=\"button\"\n className={styles.trigger}\n onClick={() => activate(item)}\n >\n <span className={styles.itemTitle}>{item.title}</span>\n {item.body && (\n <span className={styles.itemBody}>{item.body}</span>\n )}\n </button>\n ) : (\n <>\n <span className={styles.itemTitle}>{item.title}</span>\n {item.body && (\n <span className={styles.itemBody}>{item.body}</span>\n )}\n </>\n )}\n <time\n className={styles.time}\n dateTime={new Date(item.receivedAt).toISOString()}\n >\n {relativeTime(item.receivedAt, { locale, now: reference })}\n </time>\n </div>\n\n {onDismiss && (\n <button\n type=\"button\"\n className={styles.dismiss}\n onClick={() => onDismiss(item.id)}\n aria-label={`Descartar: ${item.title}`}\n >\n ×\n </button>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":"2OAmFA,SAAgB,EAAmB,CAC/B,QACA,QAAQ,eACR,WACA,aACA,gBACA,YACA,aACA,SAAS,QACT,aACA,MACA,YACA,GAAG,GACqB,CACxB,IAAM,EAAc,EAAM,OAAQ,GAAS,CAAC,EAAK,IAAI,CAAC,CAAC,OACjD,EAAY,GAAO,IAAI,KAAK,CAAA,CAAE,QAAQ,EAStC,EAAY,GAAiC,CAC1C,EAAK,MAAM,IAAa,EAAK,EAAE,EACpC,IAAW,CAAI,CACnB,EAEM,EAAc,GAAQ,GAAY,GAExC,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,CAAS,EAAG,GAAI,WAAjD,EACM,GAAU,GAAiB,EAAc,KACvC,EAAA,EAAA,KAAA,CAAC,SAAD,CAAQ,UAAW,EAAA,QAAO,gBAA1B,CACK,GACG,EAAA,EAAA,KAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,eAAtB,CACK,EACA,EAAc,IACX,EAAA,EAAA,IAAA,CAAC,EAAA,MAAD,CAAO,QAAQ,UAAU,aAAY,GAAG,EAAY,qBAC/C,CACE,CAAA,CAEX,KAEJ,EAAA,EAAA,IAAA,CAAC,OAAD,CAAO,CAAA,EAEV,GAAiB,EAAc,IAC5B,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,aAClB,QAAS,WACZ,yBAEO,CAAA,CAER,IAGX,EAAM,SAAW,EACb,IAAc,EAAA,EAAA,IAAA,CAAC,EAAA,WAAD,CAAY,MAAM,qBAAuB,CAAA,GAExD,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,cACjB,EAAM,IAAK,IACR,EAAA,EAAA,KAAA,CAAC,KAAD,CAEI,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,CAAC,EAAK,MAAQ,EAAA,QAAO,MAAM,EACtD,eAAe,EAAK,KAAgB,IAAA,GAAT,gBAH/B,CAKK,IAAc,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,cAAO,EAAW,CAAI,CAAQ,CAAA,GAErE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,cAAvB,CACK,GACG,EAAA,EAAA,KAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,QAClB,YAAe,EAAS,CAAI,WAHhC,EAKI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,mBAAY,EAAK,KAAY,CAAA,EACpD,EAAK,OACF,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,kBAAW,EAAK,IAAW,CAAA,CAEnD,KAER,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,mBAAY,EAAK,KAAY,CAAA,EACpD,EAAK,OACF,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,kBAAW,EAAK,IAAW,CAAA,CAEzD,CAAA,CAAA,GAEN,EAAA,EAAA,IAAA,CAAC,OAAD,CACI,UAAW,EAAA,QAAO,KAClB,SAAU,IAAI,KAAK,EAAK,UAAU,CAAC,CAAC,YAAY,WAE/C,EAAA,aAAa,EAAK,WAAY,CAAE,SAAQ,IAAK,CAAU,CAAC,CACvD,CAAA,CACL,IAEJ,IACG,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,QAClB,YAAe,EAAU,EAAK,EAAE,EAChC,aAAY,cAAc,EAAK,iBAClC,GAEO,CAAA,CAEZ,GA5CK,EAAK,EA4CV,CACP,CACD,CAAA,CAEP,GAEb"}
1
+ {"version":3,"file":"NotificationCenter.cjs","names":[],"sources":["../../../src/components/NotificationCenter/NotificationCenter.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count, function-lines — an inbox has four actions the app\n * must implement (onSelect, onMarkRead, onMarkAllRead, onDismiss) over one list,\n * plus the presentation it needs to render a readable feed: renderIcon, locale, now\n * for relative timestamps, emptyState and title.\n */\nimport type { HTMLAttributes, ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\nimport { relativeTime, type RelativeTimeLocale } from \"@/utils/relative-time\";\n\nimport { Badge } from \"../Badge\";\nimport { EmptyState } from \"../EmptyState\";\nimport type { NotificationItem } from \"./use-notification-inbox\";\nimport styles from \"./NotificationCenter.module.css\";\n\n/**\n * DOM attributes this component redefines.\n *\n * `title` becomes a rendered heading node instead of a tooltip string, and\n * `onSelect` becomes \"an entry was activated\" instead of the DOM text-selection\n * event. Both would be type errors if merged, and silently confusing if allowed\n * through.\n */\ntype OverriddenDomProps = \"children\" | \"title\" | \"onSelect\";\n\nexport interface NotificationCenterProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n OverriddenDomProps\n> {\n /** Entries to show. Rendered in the order given — `useNotificationInbox` sorts newest first. */\n items: readonly NotificationItem[];\n /**\n * Panel heading. Pass `null` to render the list with no header.\n *\n * Widened from the DOM `title` attribute (a `string`) on purpose: this is a\n * rendered heading, not a tooltip, so it takes a node.\n */\n title?: ReactNode;\n /** Activate an entry: click, `Enter` or `Space`. Also marks it read when `onMarkRead` is set. */\n onSelect?: (item: NotificationItem) => void;\n /** Mark one entry as read. Enables the per-item read control. */\n onMarkRead?: (id: string) => void;\n /** Mark every entry as read. Enables the header action. */\n onMarkAllRead?: () => void;\n /** Remove one entry. Enables the per-item dismiss control. */\n onDismiss?: (id: string) => void;\n /** Icon rendered at the leading edge of each row — an `<Icon name={…} />`, say. */\n renderIcon?: (item: NotificationItem) => ReactNode;\n /** Locale for the relative timestamps. Default `\"pt-BR\"`. */\n locale?: RelativeTimeLocale;\n /** Shown when `items` is empty. */\n emptyState?: ReactNode;\n /** Reference point for the relative timestamps. Default: now, at render time. */\n now?: number;\n}\n\n/**\n * Inbox panel for notifications the app has received.\n *\n * Deliberately presentational and controlled: it takes a list and emits intent.\n * Where the list comes from — an API, a service-worker push, `localStorage` — and\n * where read state is written are app decisions, and a component that assumed any\n * of them would be wrong for most apps. `useNotificationInbox` is the companion\n * that holds the state, including the service-worker bridge.\n *\n * It is also just the panel, not a popover: apps mount it inside their own\n * `Popover`, `Drawer` or route. That keeps one component from owning both the\n * inbox and a positioning strategy.\n *\n * @example\n * const inbox = useNotificationInbox();\n *\n * <Popover trigger={<Button>Notificações ({inbox.unreadCount})</Button>}>\n * <NotificationCenter\n * items={inbox.items}\n * onMarkRead={inbox.markRead}\n * onMarkAllRead={inbox.markAllRead}\n * onDismiss={inbox.remove}\n * onSelect={(item) => item.url && navigate(item.url)}\n * />\n * </Popover>\n */\nexport function NotificationCenter({\n items,\n title = \"Notificações\",\n onSelect,\n onMarkRead,\n onMarkAllRead,\n onDismiss,\n renderIcon,\n locale = \"pt-BR\",\n emptyState,\n now,\n className,\n ...rest\n}: NotificationCenterProps) {\n const unreadCount = items.filter((item) => !item.read).length;\n const reference = now ?? new Date().getTime();\n\n /**\n * Activate an entry.\n *\n * Reading a notification is implied by opening it, so activation marks it read\n * as well — otherwise every app would have to remember to call both, and the\n * unread badge would keep counting something the user already saw.\n */\n const activate = (item: NotificationItem): void => {\n if (!item.read) onMarkRead?.(item.id);\n onSelect?.(item);\n };\n\n const interactive = Boolean(onSelect || onMarkRead);\n\n return (\n <div className={cn(styles.panel, className)} {...rest}>\n {(title || (onMarkAllRead && unreadCount > 0)) && (\n <header className={styles.header}>\n {title ? (\n <h2 className={styles.title}>\n {title}\n {unreadCount > 0 && (\n <Badge variant=\"primary\" aria-label={`${unreadCount} não lidas`}>\n {unreadCount}\n </Badge>\n )}\n </h2>\n ) : (\n <span />\n )}\n {onMarkAllRead && unreadCount > 0 && (\n <button\n type=\"button\"\n className={styles.headerAction}\n onClick={onMarkAllRead}\n >\n Marcar todas como lidas\n </button>\n )}\n </header>\n )}\n\n {items.length === 0 ? (\n (emptyState ?? <EmptyState title=\"Nenhuma notificação\" />)\n ) : (\n <ul className={styles.list}>\n {items.map((item) => (\n <li\n key={item.id}\n className={cn(styles.item, !item.read && styles.unread)}\n aria-current={!item.read ? \"true\" : undefined}\n >\n {renderIcon && <span className={styles.icon}>{renderIcon(item)}</span>}\n\n <div className={styles.body}>\n {interactive ? (\n <button\n type=\"button\"\n className={styles.trigger}\n onClick={() => activate(item)}\n >\n <span className={styles.itemTitle}>{item.title}</span>\n {item.body && (\n <span className={styles.itemBody}>{item.body}</span>\n )}\n </button>\n ) : (\n <>\n <span className={styles.itemTitle}>{item.title}</span>\n {item.body && (\n <span className={styles.itemBody}>{item.body}</span>\n )}\n </>\n )}\n <time\n className={styles.time}\n dateTime={new Date(item.receivedAt).toISOString()}\n >\n {relativeTime(item.receivedAt, { locale, now: reference })}\n </time>\n </div>\n\n {onDismiss && (\n <button\n type=\"button\"\n className={styles.dismiss}\n onClick={() => onDismiss(item.id)}\n aria-label={`Descartar: ${item.title}`}\n >\n ×\n </button>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":"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"}