tempest-react-sdk 0.39.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (475) hide show
  1. package/dist/_virtual/_rolldown/runtime.cjs +1 -1
  2. package/dist/access/access-control-context.cjs.map +1 -1
  3. package/dist/access/use-can.cjs.map +1 -1
  4. package/dist/app/AppProviders.cjs.map +1 -1
  5. package/dist/app/AppProviders.js.map +1 -1
  6. package/dist/audio/use-audio-recorder.cjs.map +1 -1
  7. package/dist/audio/use-audio.cjs.map +1 -1
  8. package/dist/audio/use-microphone.cjs.map +1 -1
  9. package/dist/auth/create-auth-store.cjs.map +1 -1
  10. package/dist/auth/lazy-with-retry.cjs.map +1 -1
  11. package/dist/auth/passkey.cjs.map +1 -1
  12. package/dist/auth/passkey.js.map +1 -1
  13. package/dist/auth/use-passkey.cjs.map +1 -1
  14. package/dist/br/BrazilMap.cjs +1 -1
  15. package/dist/br/BrazilMap.cjs.map +1 -1
  16. package/dist/br/BrazilMap.js +2 -2
  17. package/dist/br/BrazilMap.js.map +1 -1
  18. package/dist/br/BrazilStateCitySelect.cjs.map +1 -1
  19. package/dist/br/BrazilStateCitySelect.js.map +1 -1
  20. package/dist/br/BrazilStateMap.cjs +1 -1
  21. package/dist/br/BrazilStateMap.cjs.map +1 -1
  22. package/dist/br/BrazilStateMap.js +2 -2
  23. package/dist/br/BrazilStateMap.js.map +1 -1
  24. package/dist/br/MapLegend.cjs.map +1 -1
  25. package/dist/br/MapLegend.js.map +1 -1
  26. package/dist/br/MapMarkers.cjs.map +1 -1
  27. package/dist/br/MapMarkers.js.map +1 -1
  28. package/dist/br/MunicipalitySearch.cjs.map +1 -1
  29. package/dist/br/MunicipalitySearch.js.map +1 -1
  30. package/dist/br/PixQRCode.cjs.map +1 -1
  31. package/dist/br/PixQRCode.js.map +1 -1
  32. package/dist/br/use-map-hover.cjs.map +1 -1
  33. package/dist/br/use-map-zoom.cjs.map +1 -1
  34. package/dist/capture/media-recorder.cjs +1 -1
  35. package/dist/capture/media-recorder.js +2 -2
  36. package/dist/capture/use-barcode-scanner.cjs +1 -1
  37. package/dist/capture/use-barcode-scanner.cjs.map +1 -1
  38. package/dist/capture/use-barcode-scanner.js +2 -2
  39. package/dist/capture/use-barcode-scanner.js.map +1 -1
  40. package/dist/capture/use-screen-capture.cjs.map +1 -1
  41. package/dist/capture/use-speech-recognition.cjs.map +1 -1
  42. package/dist/capture/use-torch.cjs.map +1 -1
  43. package/dist/capture/use-video-recorder.cjs.map +1 -1
  44. package/dist/charts/AreaChart.cjs.map +1 -1
  45. package/dist/charts/AreaChart.js.map +1 -1
  46. package/dist/charts/BarChart.cjs.map +1 -1
  47. package/dist/charts/BarChart.js.map +1 -1
  48. package/dist/charts/LineChart.cjs.map +1 -1
  49. package/dist/charts/LineChart.js.map +1 -1
  50. package/dist/charts/PieChart.cjs.map +1 -1
  51. package/dist/charts/PieChart.js.map +1 -1
  52. package/dist/charts/RadarChart.cjs.map +1 -1
  53. package/dist/charts/RadarChart.js.map +1 -1
  54. package/dist/charts/use-chart-colors.cjs.map +1 -1
  55. package/dist/components/AIChat/AIChat.cjs.map +1 -1
  56. package/dist/components/AIChat/AIChat.js.map +1 -1
  57. package/dist/components/AIChat/AIChatComposer.cjs.map +1 -1
  58. package/dist/components/AIChat/AIChatComposer.js.map +1 -1
  59. package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
  60. package/dist/components/AIChat/AIChatTurn.js.map +1 -1
  61. package/dist/components/Accordion/Accordion.cjs.map +1 -1
  62. package/dist/components/Accordion/Accordion.js.map +1 -1
  63. package/dist/components/Alert/Alert.cjs.map +1 -1
  64. package/dist/components/Alert/Alert.js.map +1 -1
  65. package/dist/components/AppBar/AppBar.cjs.map +1 -1
  66. package/dist/components/AppBar/AppBar.js.map +1 -1
  67. package/dist/components/AppShell/AppShell.cjs.map +1 -1
  68. package/dist/components/AppShell/AppShell.js.map +1 -1
  69. package/dist/components/AudioPlayer/AudioPlayer.cjs.map +1 -1
  70. package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -1
  71. package/dist/components/AudioRecorder/AudioRecorder.cjs.map +1 -1
  72. package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -1
  73. package/dist/components/Avatar/Avatar.cjs.map +1 -1
  74. package/dist/components/Avatar/Avatar.js.map +1 -1
  75. package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -1
  76. package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -1
  77. package/dist/components/Badge/Badge.cjs.map +1 -1
  78. package/dist/components/Badge/Badge.js.map +1 -1
  79. package/dist/components/Banner/Banner.cjs.map +1 -1
  80. package/dist/components/Banner/Banner.js.map +1 -1
  81. package/dist/components/BarcodeScanner/BarcodeScanner.cjs.map +1 -1
  82. package/dist/components/BarcodeScanner/BarcodeScanner.js.map +1 -1
  83. package/dist/components/BottomNavigation/BottomNavigation.cjs.map +1 -1
  84. package/dist/components/BottomNavigation/BottomNavigation.js.map +1 -1
  85. package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
  86. package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
  87. package/dist/components/Breadcrumbs/Breadcrumbs.cjs.map +1 -1
  88. package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
  89. package/dist/components/Button/Button.cjs.map +1 -1
  90. package/dist/components/Button/Button.js.map +1 -1
  91. package/dist/components/Calendar/Calendar.cjs +1 -1
  92. package/dist/components/Calendar/Calendar.cjs.map +1 -1
  93. package/dist/components/Calendar/Calendar.js +38 -41
  94. package/dist/components/Calendar/Calendar.js.map +1 -1
  95. package/dist/components/Card/Card.cjs.map +1 -1
  96. package/dist/components/Card/Card.js.map +1 -1
  97. package/dist/components/Carousel/Carousel.cjs.map +1 -1
  98. package/dist/components/Carousel/Carousel.js.map +1 -1
  99. package/dist/components/Chat/Chat.cjs.map +1 -1
  100. package/dist/components/Chat/Chat.js.map +1 -1
  101. package/dist/components/Chat/ChatComposer.cjs.map +1 -1
  102. package/dist/components/Chat/ChatComposer.js.map +1 -1
  103. package/dist/components/Chat/chat-groups.cjs +1 -1
  104. package/dist/components/Chat/chat-groups.cjs.map +1 -1
  105. package/dist/components/Chat/chat-groups.js +2 -2
  106. package/dist/components/Chat/chat-groups.js.map +1 -1
  107. package/dist/components/Checkbox/Checkbox.cjs.map +1 -1
  108. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  109. package/dist/components/ChipInput/ChipInput.cjs.map +1 -1
  110. package/dist/components/ChipInput/ChipInput.js.map +1 -1
  111. package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
  112. package/dist/components/CodeBlock/CodeBlock.cjs.map +1 -1
  113. package/dist/components/CodeBlock/CodeBlock.js.map +1 -1
  114. package/dist/components/Collapsible/Collapsible.cjs.map +1 -1
  115. package/dist/components/Collapsible/Collapsible.js.map +1 -1
  116. package/dist/components/Combobox/Combobox.cjs.map +1 -1
  117. package/dist/components/Combobox/Combobox.js.map +1 -1
  118. package/dist/components/Command/Command.cjs.map +1 -1
  119. package/dist/components/Command/Command.js.map +1 -1
  120. package/dist/components/ConfirmDialog/ConfirmDialog.cjs.map +1 -1
  121. package/dist/components/ConfirmDialog/ConfirmDialog.js.map +1 -1
  122. package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
  123. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  124. package/dist/components/CopyButton/CopyButton.cjs.map +1 -1
  125. package/dist/components/CopyButton/CopyButton.js.map +1 -1
  126. package/dist/components/DataList/DataList.cjs.map +1 -1
  127. package/dist/components/DataList/DataList.js.map +1 -1
  128. package/dist/components/DataTable/DataTable.cjs +1 -1
  129. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  130. package/dist/components/DataTable/DataTable.js +2 -2
  131. package/dist/components/DataTable/DataTable.js.map +1 -1
  132. package/dist/components/DataTable/EditableCell.cjs.map +1 -1
  133. package/dist/components/DataTable/EditableCell.js.map +1 -1
  134. package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
  135. package/dist/components/DateRangePicker/DateRangePicker.cjs.map +1 -1
  136. package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
  137. package/dist/components/DescriptionList/DescriptionList.cjs.map +1 -1
  138. package/dist/components/DescriptionList/DescriptionList.js.map +1 -1
  139. package/dist/components/Divider/Divider.cjs.map +1 -1
  140. package/dist/components/Divider/Divider.js.map +1 -1
  141. package/dist/components/Drawer/Drawer.cjs.map +1 -1
  142. package/dist/components/Drawer/Drawer.js.map +1 -1
  143. package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
  144. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  145. package/dist/components/Dropzone/Dropzone.cjs.map +1 -1
  146. package/dist/components/Dropzone/Dropzone.js.map +1 -1
  147. package/dist/components/EmptyState/EmptyState.cjs.map +1 -1
  148. package/dist/components/EmptyState/EmptyState.js.map +1 -1
  149. package/dist/components/ErrorState/ErrorState.cjs.map +1 -1
  150. package/dist/components/ErrorState/ErrorState.js.map +1 -1
  151. package/dist/components/FileUpload/FileUpload.cjs +1 -1
  152. package/dist/components/FileUpload/FileUpload.cjs.map +1 -1
  153. package/dist/components/FileUpload/FileUpload.js +1 -1
  154. package/dist/components/FileUpload/FileUpload.js.map +1 -1
  155. package/dist/components/FilterBar/FilterBar.cjs.map +1 -1
  156. package/dist/components/FilterBar/FilterBar.js.map +1 -1
  157. package/dist/components/FloatingActionButton/FloatingActionButton.cjs.map +1 -1
  158. package/dist/components/FloatingActionButton/FloatingActionButton.js.map +1 -1
  159. package/dist/components/Form/Form.cjs.map +1 -1
  160. package/dist/components/Form/Form.js.map +1 -1
  161. package/dist/components/HoverCard/HoverCard.cjs.map +1 -1
  162. package/dist/components/HoverCard/HoverCard.js.map +1 -1
  163. package/dist/components/Image/Image.cjs.map +1 -1
  164. package/dist/components/ImageCropper/ImageCropper.cjs +1 -1
  165. package/dist/components/ImageCropper/ImageCropper.cjs.map +1 -1
  166. package/dist/components/ImageCropper/ImageCropper.js +1 -1
  167. package/dist/components/ImageCropper/ImageCropper.js.map +1 -1
  168. package/dist/components/Input/Input.cjs.map +1 -1
  169. package/dist/components/Input/Input.js.map +1 -1
  170. package/dist/components/InstallBanner/InstallBanner.cjs.map +1 -1
  171. package/dist/components/InstallBanner/InstallBanner.js.map +1 -1
  172. package/dist/components/InstallButton/InstallButton.cjs.map +1 -1
  173. package/dist/components/InstallButton/InstallButton.js.map +1 -1
  174. package/dist/components/Kanban/Kanban.cjs.map +1 -1
  175. package/dist/components/Kanban/Kanban.js.map +1 -1
  176. package/dist/components/Label/Label.cjs.map +1 -1
  177. package/dist/components/Label/Label.js.map +1 -1
  178. package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
  179. package/dist/components/Lightbox/Lightbox.js.map +1 -1
  180. package/dist/components/ListTile/ListTile.cjs.map +1 -1
  181. package/dist/components/ListTile/ListTile.js.map +1 -1
  182. package/dist/components/Markdown/Markdown.cjs +1 -1
  183. package/dist/components/Markdown/Markdown.cjs.map +1 -1
  184. package/dist/components/Markdown/Markdown.js +2 -2
  185. package/dist/components/Markdown/Markdown.js.map +1 -1
  186. package/dist/components/Masonry/Masonry.cjs.map +1 -1
  187. package/dist/components/Masonry/Masonry.js.map +1 -1
  188. package/dist/components/Menubar/Menubar.cjs.map +1 -1
  189. package/dist/components/Menubar/Menubar.js.map +1 -1
  190. package/dist/components/Modal/Modal.cjs.map +1 -1
  191. package/dist/components/Modal/Modal.js.map +1 -1
  192. package/dist/components/ModalsManager/ModalsManager.cjs.map +1 -1
  193. package/dist/components/ModalsManager/ModalsManager.js.map +1 -1
  194. package/dist/components/Money/Money.cjs.map +1 -1
  195. package/dist/components/Money/Money.js.map +1 -1
  196. package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
  197. package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
  198. package/dist/components/NProgress/NProgress.cjs.map +1 -1
  199. package/dist/components/Navbar/Navbar.cjs.map +1 -1
  200. package/dist/components/Navbar/Navbar.js.map +1 -1
  201. package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
  202. package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
  203. package/dist/components/NavigationRail/NavigationRail.cjs.map +1 -1
  204. package/dist/components/NavigationRail/NavigationRail.js.map +1 -1
  205. package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -1
  206. package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -1
  207. package/dist/components/NotificationCenter/use-notification-inbox.cjs.map +1 -1
  208. package/dist/components/OfflineIndicator/OfflineIndicator.cjs.map +1 -1
  209. package/dist/components/OfflineIndicator/OfflineIndicator.js.map +1 -1
  210. package/dist/components/Page/Page.cjs.map +1 -1
  211. package/dist/components/Page/Page.js.map +1 -1
  212. package/dist/components/Pagination/Pagination.cjs.map +1 -1
  213. package/dist/components/Pagination/Pagination.js.map +1 -1
  214. package/dist/components/PasswordInput/PasswordInput.cjs.map +1 -1
  215. package/dist/components/PasswordInput/PasswordInput.js.map +1 -1
  216. package/dist/components/PinInput/PinInput.cjs.map +1 -1
  217. package/dist/components/PinInput/PinInput.js.map +1 -1
  218. package/dist/components/Popover/Popover.cjs.map +1 -1
  219. package/dist/components/Popover/Popover.js.map +1 -1
  220. package/dist/components/Portal/Portal.cjs.map +1 -1
  221. package/dist/components/Progress/Progress.cjs.map +1 -1
  222. package/dist/components/Progress/Progress.js.map +1 -1
  223. package/dist/components/QRCode/QRCode.cjs.map +1 -1
  224. package/dist/components/QRCode/QRCode.js.map +1 -1
  225. package/dist/components/Radio/Radio.cjs.map +1 -1
  226. package/dist/components/Radio/Radio.js.map +1 -1
  227. package/dist/components/RangeSlider/RangeSlider.cjs.map +1 -1
  228. package/dist/components/RangeSlider/RangeSlider.js.map +1 -1
  229. package/dist/components/RatingStars/RatingStars.cjs.map +1 -1
  230. package/dist/components/RatingStars/RatingStars.js.map +1 -1
  231. package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
  232. package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
  233. package/dist/components/RelativeTime/RelativeTime.cjs.map +1 -1
  234. package/dist/components/RelativeTime/RelativeTime.js.map +1 -1
  235. package/dist/components/Resizable/Resizable.cjs.map +1 -1
  236. package/dist/components/Resizable/Resizable.js.map +1 -1
  237. package/dist/components/Scheduler/Scheduler.cjs.map +1 -1
  238. package/dist/components/Scheduler/Scheduler.js.map +1 -1
  239. package/dist/components/ScrollArea/ScrollArea.cjs.map +1 -1
  240. package/dist/components/SearchBar/SearchBar.cjs.map +1 -1
  241. package/dist/components/SearchBar/SearchBar.js.map +1 -1
  242. package/dist/components/SegmentedControl/SegmentedControl.cjs.map +1 -1
  243. package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
  244. package/dist/components/Select/Select.cjs.map +1 -1
  245. package/dist/components/Select/Select.js.map +1 -1
  246. package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
  247. package/dist/components/Sidebar/Sidebar.js.map +1 -1
  248. package/dist/components/SignaturePad/SignaturePad.cjs.map +1 -1
  249. package/dist/components/SignaturePad/SignaturePad.js.map +1 -1
  250. package/dist/components/Slider/Slider.cjs.map +1 -1
  251. package/dist/components/Slider/Slider.js.map +1 -1
  252. package/dist/components/Sparkline/Sparkline.cjs.map +1 -1
  253. package/dist/components/Sparkline/Sparkline.js.map +1 -1
  254. package/dist/components/Spinner/Spinner.cjs.map +1 -1
  255. package/dist/components/Spinner/Spinner.js.map +1 -1
  256. package/dist/components/Stat/Stat.cjs.map +1 -1
  257. package/dist/components/Stat/Stat.js.map +1 -1
  258. package/dist/components/Stepper/Stepper.cjs.map +1 -1
  259. package/dist/components/Stepper/Stepper.js.map +1 -1
  260. package/dist/components/StepperInput/StepperInput.cjs.map +1 -1
  261. package/dist/components/StepperInput/StepperInput.js.map +1 -1
  262. package/dist/components/Switch/Switch.cjs.map +1 -1
  263. package/dist/components/Switch/Switch.js.map +1 -1
  264. package/dist/components/SyncStatusBadge/SyncStatusBadge.cjs.map +1 -1
  265. package/dist/components/SyncStatusBadge/SyncStatusBadge.js.map +1 -1
  266. package/dist/components/Table/Table.cjs.map +1 -1
  267. package/dist/components/Table/Table.js.map +1 -1
  268. package/dist/components/Tabs/Tabs.cjs.map +1 -1
  269. package/dist/components/Tabs/Tabs.js.map +1 -1
  270. package/dist/components/Tag/Tag.cjs.map +1 -1
  271. package/dist/components/Tag/Tag.js.map +1 -1
  272. package/dist/components/Textarea/Textarea.cjs.map +1 -1
  273. package/dist/components/Textarea/Textarea.js.map +1 -1
  274. package/dist/components/TimePicker/TimePicker.cjs.map +1 -1
  275. package/dist/components/TimePicker/TimePicker.js.map +1 -1
  276. package/dist/components/Timeline/Timeline.cjs.map +1 -1
  277. package/dist/components/Timeline/Timeline.js.map +1 -1
  278. package/dist/components/Toast/ToastProvider.cjs.map +1 -1
  279. package/dist/components/Toast/ToastProvider.js.map +1 -1
  280. package/dist/components/Toggle/Toggle.cjs.map +1 -1
  281. package/dist/components/ToggleGroup/ToggleGroup.cjs.map +1 -1
  282. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
  283. package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
  284. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  285. package/dist/components/Tour/Tour.cjs.map +1 -1
  286. package/dist/components/Tour/Tour.js.map +1 -1
  287. package/dist/components/Transfer/Transfer.cjs.map +1 -1
  288. package/dist/components/Transfer/Transfer.js.map +1 -1
  289. package/dist/components/TreeView/TreeView.cjs +1 -1
  290. package/dist/components/TreeView/TreeView.cjs.map +1 -1
  291. package/dist/components/TreeView/TreeView.js +1 -4
  292. package/dist/components/TreeView/TreeView.js.map +1 -1
  293. package/dist/components/UpdatePrompt/UpdatePrompt.cjs.map +1 -1
  294. package/dist/components/UpdatePrompt/UpdatePrompt.js.map +1 -1
  295. package/dist/components/VirtualList/VirtualList.cjs.map +1 -1
  296. package/dist/components/VirtualList/VirtualList.js.map +1 -1
  297. package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -1
  298. package/dist/components/VirtualTable/VirtualTable.js.map +1 -1
  299. package/dist/components/VisuallyHidden/VisuallyHidden.cjs.map +1 -1
  300. package/dist/components/Wizard/Wizard.cjs.map +1 -1
  301. package/dist/components/Wizard/Wizard.js.map +1 -1
  302. package/dist/data/data-provider-context.cjs.map +1 -1
  303. package/dist/data/use-resource.cjs.map +1 -1
  304. package/dist/editor/RichTextEditor.cjs.map +1 -1
  305. package/dist/editor/RichTextEditor.js.map +1 -1
  306. package/dist/error-boundary/use-error-handler.cjs.map +1 -1
  307. package/dist/feature-flags/FeatureFlagsProvider.cjs.map +1 -1
  308. package/dist/forms/FormField.cjs.map +1 -1
  309. package/dist/forms/masked-inputs.cjs +1 -1
  310. package/dist/forms/masked-inputs.cjs.map +1 -1
  311. package/dist/forms/masked-inputs.js +1 -1
  312. package/dist/forms/masked-inputs.js.map +1 -1
  313. package/dist/forms/use-viacep.cjs.map +1 -1
  314. package/dist/forms/use-zod-form.cjs.map +1 -1
  315. package/dist/forms/zod-resolver.cjs.map +1 -1
  316. package/dist/forms/zod-resolver.js.map +1 -1
  317. package/dist/geo/TrajectoryMap.cjs.map +1 -1
  318. package/dist/geo/TrajectoryMap.js.map +1 -1
  319. package/dist/geo/leaflet-map.cjs.map +1 -1
  320. package/dist/geo/leaflet-map.js.map +1 -1
  321. package/dist/geo/use-position-tracker.cjs.map +1 -1
  322. package/dist/hooks/use-announce.cjs.map +1 -1
  323. package/dist/hooks/use-async.cjs.map +1 -1
  324. package/dist/hooks/use-before-install-prompt.cjs.map +1 -1
  325. package/dist/hooks/use-breakpoint.cjs.map +1 -1
  326. package/dist/hooks/use-click-outside.cjs.map +1 -1
  327. package/dist/hooks/use-client-filter.cjs.map +1 -1
  328. package/dist/hooks/use-clipboard.cjs.map +1 -1
  329. package/dist/hooks/use-counter.cjs.map +1 -1
  330. package/dist/hooks/use-debounce.cjs.map +1 -1
  331. package/dist/hooks/use-deep-memo.cjs.map +1 -1
  332. package/dist/hooks/use-disclosure.cjs.map +1 -1
  333. package/dist/hooks/use-document-visibility.cjs.map +1 -1
  334. package/dist/hooks/use-event-listener.cjs.map +1 -1
  335. package/dist/hooks/use-geolocation.cjs.map +1 -1
  336. package/dist/hooks/use-hover.cjs.map +1 -1
  337. package/dist/hooks/use-idle.cjs.map +1 -1
  338. package/dist/hooks/use-install-prompt.cjs +1 -1
  339. package/dist/hooks/use-install-prompt.cjs.map +1 -1
  340. package/dist/hooks/use-install-prompt.js +1 -1
  341. package/dist/hooks/use-install-prompt.js.map +1 -1
  342. package/dist/hooks/use-intersection-observer.cjs.map +1 -1
  343. package/dist/hooks/use-interval.cjs.map +1 -1
  344. package/dist/hooks/use-is-first-render.cjs.map +1 -1
  345. package/dist/hooks/use-keyboard-shortcut.cjs +1 -1
  346. package/dist/hooks/use-keyboard-shortcut.cjs.map +1 -1
  347. package/dist/hooks/use-keyboard-shortcut.js +1 -1
  348. package/dist/hooks/use-keyboard-shortcut.js.map +1 -1
  349. package/dist/hooks/use-list-state.cjs.map +1 -1
  350. package/dist/hooks/use-local-storage.cjs.map +1 -1
  351. package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
  352. package/dist/hooks/use-long-press.cjs.map +1 -1
  353. package/dist/hooks/use-map.cjs.map +1 -1
  354. package/dist/hooks/use-media-devices.cjs.map +1 -1
  355. package/dist/hooks/use-media-permission.cjs.map +1 -1
  356. package/dist/hooks/use-media-query.cjs.map +1 -1
  357. package/dist/hooks/use-object-url.cjs.map +1 -1
  358. package/dist/hooks/use-online.cjs.map +1 -1
  359. package/dist/hooks/use-pagination.cjs.map +1 -1
  360. package/dist/hooks/use-previous.cjs.map +1 -1
  361. package/dist/hooks/use-queue.cjs.map +1 -1
  362. package/dist/hooks/use-resize-observer.cjs.map +1 -1
  363. package/dist/hooks/use-scroll-overflow.cjs.map +1 -1
  364. package/dist/hooks/use-service-worker-update.cjs.map +1 -1
  365. package/dist/hooks/use-set.cjs.map +1 -1
  366. package/dist/hooks/use-sortable.cjs +1 -1
  367. package/dist/hooks/use-sortable.cjs.map +1 -1
  368. package/dist/hooks/use-sortable.js +0 -2
  369. package/dist/hooks/use-sortable.js.map +1 -1
  370. package/dist/hooks/use-stable-callback.cjs.map +1 -1
  371. package/dist/hooks/use-storage-estimate.cjs.map +1 -1
  372. package/dist/hooks/use-throttle.cjs.map +1 -1
  373. package/dist/hooks/use-timeout.cjs.map +1 -1
  374. package/dist/hooks/use-toggle.cjs.map +1 -1
  375. package/dist/hooks/use-window-size.cjs.map +1 -1
  376. package/dist/http/api-client.cjs +1 -1
  377. package/dist/http/api-client.cjs.map +1 -1
  378. package/dist/http/api-client.js +7 -5
  379. package/dist/http/api-client.js.map +1 -1
  380. package/dist/http/resumable-upload.cjs +1 -1
  381. package/dist/http/resumable-upload.cjs.map +1 -1
  382. package/dist/http/resumable-upload.js +1 -1
  383. package/dist/http/resumable-upload.js.map +1 -1
  384. package/dist/http/use-poll.cjs.map +1 -1
  385. package/dist/i18n/I18nProvider.cjs.map +1 -1
  386. package/dist/icons/Icon.cjs.map +1 -1
  387. package/dist/icons/IconProvider.cjs.map +1 -1
  388. package/dist/icons/icon-context.cjs.map +1 -1
  389. package/dist/icons/use-icon.cjs.map +1 -1
  390. package/dist/imaging/use-image-processing.cjs.map +1 -1
  391. package/dist/oauth/GoogleSignIn.cjs.map +1 -1
  392. package/dist/oauth/GoogleSignIn.js.map +1 -1
  393. package/dist/oauth/use-oauth-callback.cjs.map +1 -1
  394. package/dist/offline/use-offline-sync.cjs.map +1 -1
  395. package/dist/push/use-push-subscription.cjs.map +1 -1
  396. package/dist/query/QueryProvider.cjs.map +1 -1
  397. package/dist/query/constants.cjs +1 -1
  398. package/dist/query/constants.cjs.map +1 -1
  399. package/dist/query/constants.js +10 -10
  400. package/dist/query/constants.js.map +1 -1
  401. package/dist/query/create-query-keys.cjs +1 -1
  402. package/dist/query/create-query-keys.cjs.map +1 -1
  403. package/dist/query/create-query-keys.js +1 -1
  404. package/dist/query/create-query-keys.js.map +1 -1
  405. package/dist/query/offline-persistence.cjs.map +1 -1
  406. package/dist/query/use-cursor-query.cjs.map +1 -1
  407. package/dist/query/use-offline-mutation.cjs.map +1 -1
  408. package/dist/query/use-paginated-query.cjs.map +1 -1
  409. package/dist/router/AppRouter.cjs +1 -1
  410. package/dist/router/AppRouter.cjs.map +1 -1
  411. package/dist/router/AppRouter.js +7 -2
  412. package/dist/router/AppRouter.js.map +1 -1
  413. package/dist/sse/use-event-stream.cjs.map +1 -1
  414. package/dist/store/create-store.cjs.map +1 -1
  415. package/dist/tabular/use-tabular-predictor.cjs.map +1 -1
  416. package/dist/telemetry/TelemetryProvider.cjs.map +1 -1
  417. package/dist/tempest-react-sdk.d.ts +25 -26
  418. package/dist/theme/ThemeProvider.cjs.map +1 -1
  419. package/dist/theme/color.cjs +1 -1
  420. package/dist/theme/color.cjs.map +1 -1
  421. package/dist/theme/color.js +1 -1
  422. package/dist/theme/color.js.map +1 -1
  423. package/dist/utils/cn.cjs +1 -1
  424. package/dist/utils/cn.cjs.map +1 -1
  425. package/dist/utils/cn.js +1 -1
  426. package/dist/utils/cn.js.map +1 -1
  427. package/dist/utils/objects.cjs +1 -1
  428. package/dist/utils/objects.cjs.map +1 -1
  429. package/dist/utils/objects.js +1 -1
  430. package/dist/utils/objects.js.map +1 -1
  431. package/dist/utils/xlsx.cjs +1 -1
  432. package/dist/utils/xlsx.cjs.map +1 -1
  433. package/dist/utils/xlsx.js +3 -3
  434. package/dist/utils/xlsx.js.map +1 -1
  435. package/dist/vision/core/exceptions.cjs.map +1 -1
  436. package/dist/vision/core/exceptions.js.map +1 -1
  437. package/dist/vision/core/metadata.cjs +1 -1
  438. package/dist/vision/core/metadata.cjs.map +1 -1
  439. package/dist/vision/core/metadata.js +1 -1
  440. package/dist/vision/core/metadata.js.map +1 -1
  441. package/dist/vision/io/image.cjs +1 -1
  442. package/dist/vision/io/image.cjs.map +1 -1
  443. package/dist/vision/io/image.js +4 -2
  444. package/dist/vision/io/image.js.map +1 -1
  445. package/dist/vision/preprocess/image.cjs +1 -1
  446. package/dist/vision/preprocess/image.cjs.map +1 -1
  447. package/dist/vision/preprocess/image.js +4 -2
  448. package/dist/vision/preprocess/image.js.map +1 -1
  449. package/dist/vision/tasks/base.cjs +1 -1
  450. package/dist/vision/tasks/base.cjs.map +1 -1
  451. package/dist/vision/tasks/base.js +3 -1
  452. package/dist/vision/tasks/base.js.map +1 -1
  453. package/dist/vision/tasks/classifier.cjs +1 -1
  454. package/dist/vision/tasks/classifier.cjs.map +1 -1
  455. package/dist/vision/tasks/classifier.js +2 -2
  456. package/dist/vision/tasks/classifier.js.map +1 -1
  457. package/dist/vision/tasks/detectClassify.cjs +1 -1
  458. package/dist/vision/tasks/detectClassify.cjs.map +1 -1
  459. package/dist/vision/tasks/detectClassify.js +16 -15
  460. package/dist/vision/tasks/detectClassify.js.map +1 -1
  461. package/dist/vision/use-camera-stream.cjs.map +1 -1
  462. package/dist/vision/use-live-luminance.cjs.map +1 -1
  463. package/dist/vite/create-vite-config.cjs +1 -1
  464. package/dist/vite/create-vite-config.cjs.map +1 -1
  465. package/dist/vite/create-vite-config.js +3 -3
  466. package/dist/vite/create-vite-config.js.map +1 -1
  467. package/dist/vite/tempest-icons.cjs.map +1 -1
  468. package/dist/vite/tempest-pwa-dev-sw.cjs.map +1 -1
  469. package/dist/vite/tempest-pwa-icons.cjs.map +1 -1
  470. package/dist/ws/use-web-socket.cjs +1 -1
  471. package/dist/ws/use-web-socket.cjs.map +1 -1
  472. package/dist/ws/use-web-socket.js +5 -3
  473. package/dist/ws/use-web-socket.js.map +1 -1
  474. package/package.json +2 -2
  475. package/template/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlock.cjs","names":[],"sources":["../../../src/components/CodeBlock/CodeBlock.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — code and language drive the scanner; filename,\n * showLineNumbers, highlightLines, maxHeight and wrap are the presentation a docs\n * page picks per block, and copyable plus label are the affordance and its\n * accessible name. All independent, all used in the SDK's own docs gallery.\n */\nimport { Fragment, useMemo } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport { CopyButton } from \"../CopyButton\";\nimport { resolveLanguage, tokenizeLines } from \"./tokenize\";\nimport styles from \"./CodeBlock.module.css\";\n\nexport interface CodeBlockProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** The source to display. Leading and trailing blank lines are trimmed. */\n code: string;\n /** Grammar name or alias (`ts`, `bash`, `json`…). Unknown values render plain. */\n language?: string;\n /** Shown in the header, usually a file path. */\n filename?: ReactNode;\n /** Number the lines. Default `false`. */\n showLineNumbers?: boolean;\n /** 1-based line numbers to mark as the point of the snippet. */\n highlightLines?: readonly number[];\n /** Offer a copy button. Default `true`. */\n copyable?: boolean;\n /** Cap the height in px or any CSS length; the body scrolls past it. */\n maxHeight?: number | string;\n /** Wrap long lines instead of scrolling sideways. Default `false`. */\n wrap?: boolean;\n /**\n * Accessible name for the code region. Defaults to naming the language, and\n * to the filename when there is one.\n */\n label?: string;\n}\n\n/**\n * A read-only code sample: syntax colours, optional line numbers, copy button.\n *\n * The `<pre>` is always focusable. A code block is scrollable and holds nothing\n * focusable inside, so without a tab stop a keyboard user can see there is more\n * code past the edge and has no way to reach it. It is the one scroll container\n * where the stop is unconditional rather than measured — a code sample is\n * expected to be reachable, read and selected on its own.\n *\n * Colours come from an approximate scanner, not a parser — see {@link tokenize}.\n *\n * @example\n * <CodeBlock code={snippet} language=\"ts\" filename=\"src/main.ts\" showLineNumbers />\n * <CodeBlock code={log} language=\"bash\" maxHeight={280} />\n */\nexport function CodeBlock({\n code,\n language,\n filename,\n showLineNumbers = false,\n highlightLines,\n copyable = true,\n maxHeight,\n wrap = false,\n label,\n className,\n ...rest\n}: CodeBlockProps) {\n const trimmed = useMemo(() => code.replace(/^\\n+/, \"\").replace(/\\s+$/, \"\"), [code]);\n const lines = useMemo(() => tokenizeLines(trimmed, language), [trimmed, language]);\n const resolved = resolveLanguage(language);\n const marked = useMemo(() => new Set(highlightLines ?? []), [highlightLines]);\n\n const name =\n label ??\n (filename && typeof filename === \"string\"\n ? `Código: ${filename}`\n : `Bloco de código${resolved === \"plain\" ? \"\" : ` em ${resolved}`}`);\n\n const hasHeader = Boolean(filename) || copyable;\n\n return (\n <div className={cn(styles.wrapper, className)} {...rest}>\n {hasHeader && (\n <div className={styles.header}>\n <span className={styles.filename}>\n {filename ?? (resolved === \"plain\" ? \"\" : resolved)}\n </span>\n {copyable && <CopyButton value={trimmed} className={styles.copy} />}\n </div>\n )}\n\n <pre\n className={cn(styles.pre, wrap && styles.wrap)}\n style={{ maxHeight }}\n tabIndex={0}\n role=\"group\"\n aria-label={name}\n >\n <code className={styles.code} data-language={resolved}>\n {lines.map((tokens, index) => (\n <Fragment key={index}>\n <span\n className={cn(styles.line, marked.has(index + 1) && styles.marked)}\n >\n {showLineNumbers && (\n /*\n * The number is decoration: it must not land in the\n * clipboard when the reader selects the snippet, and a\n * screen reader announcing \"one const two import\" adds\n * nothing. `user-select: none` in CSS plus this.\n */\n <span className={styles.lineNumber} aria-hidden=\"true\">\n {index + 1}\n </span>\n )}\n <span className={styles.lineContent}>\n {tokens.map((token, tokenIndex) => (\n <span\n key={tokenIndex}\n className={styles[token.kind]}\n data-token={token.kind}\n >\n {token.value}\n </span>\n ))}\n </span>\n </span>\n {/*\n * A real newline character, and outside the line box.\n * It has to be real so that selecting the snippet by\n * hand and copying yields the source instead of one\n * run-together line. It has to be outside because the\n * line is an inline-block: a newline within one is\n * consumed inside that box, and every line ends up\n * side by side on a single row. The last one is\n * dropped so the block does not end in blank space.\n */}\n {index < lines.length - 1 ? \"\\n\" : null}\n </Fragment>\n ))}\n </code>\n </pre>\n </div>\n );\n}\n"],"mappings":"sMAsDA,SAAgB,EAAU,CACtB,OACA,WACA,WACA,kBAAkB,GAClB,iBACA,WAAW,GACX,YACA,OAAO,GACP,QACA,YACA,GAAG,GACY,CACf,IAAM,GAAA,EAAA,EAAA,QAAA,KAAwB,EAAK,QAAQ,OAAQ,EAAE,CAAC,CAAC,QAAQ,OAAQ,EAAE,EAAG,CAAC,CAAI,CAAC,EAC5E,GAAA,EAAA,EAAA,QAAA,KAAsB,EAAA,cAAc,EAAS,CAAQ,EAAG,CAAC,EAAS,CAAQ,CAAC,EAC3E,EAAW,EAAA,gBAAgB,CAAQ,EACnC,GAAA,EAAA,EAAA,QAAA,KAAuB,IAAI,IAAI,GAAkB,CAAC,CAAC,EAAG,CAAC,CAAc,CAAC,EAEtE,EACF,IACC,GAAY,OAAO,GAAa,SAC3B,WAAW,IACX,kBAAkB,IAAa,QAAU,GAAK,OAAO,OAEzD,EAAY,EAAQ,GAAa,EAEvC,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EAAG,GAAI,WAAnD,CACK,IACG,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,gBAAvB,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,kBACnB,IAAa,IAAa,QAAU,GAAK,EACxC,CAAA,EACL,IAAY,EAAA,EAAA,IAAA,CAAC,EAAA,WAAD,CAAY,MAAO,EAAS,UAAW,EAAA,QAAO,IAAO,CAAA,CACjE,KAGT,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,GAAQ,EAAA,QAAO,IAAI,EAC7C,MAAO,CAAE,WAAU,EACnB,SAAU,EACV,KAAK,QACL,aAAY,YAEZ,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,KAAM,gBAAe,WACxC,EAAM,KAAK,EAAQ,KAChB,EAAA,EAAA,KAAA,CAAC,EAAA,SAAD,CAAA,SAAA,EACI,EAAA,EAAA,KAAA,CAAC,OAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,EAAO,IAAI,EAAQ,CAAC,GAAK,EAAA,QAAO,MAAM,WADrE,CAGK,IAOG,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,WAAY,cAAY,gBAC3C,EAAQ,CACP,CAAA,GAEV,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,qBACnB,EAAO,KAAK,EAAO,KAChB,EAAA,EAAA,IAAA,CAAC,OAAD,CAEI,UAAW,EAAA,QAAO,EAAM,MACxB,aAAY,EAAM,cAEjB,EAAM,KACL,EALG,CAKH,CACT,CACC,CAAA,CACJ,IAWL,EAAQ,EAAM,OAAS,EAAI;EAAO,IAC7B,CAAA,EAtCK,CAsCL,CACb,CACC,CAAA,CACL,CAAA,CACJ,GAEb"}
1
+ {"version":3,"file":"CodeBlock.cjs","names":[],"sources":["../../../src/components/CodeBlock/CodeBlock.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — code and language drive the scanner; filename,\n * showLineNumbers, highlightLines, maxHeight and wrap are the presentation a docs\n * page picks per block, and copyable plus label are the affordance and its\n * accessible name. All independent, all used in the SDK's own docs gallery.\n */\nimport { Fragment, useMemo } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport { CopyButton } from \"../CopyButton\";\nimport { resolveLanguage, tokenizeLines } from \"./tokenize\";\nimport styles from \"./CodeBlock.module.css\";\n\nexport interface CodeBlockProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** The source to display. Leading and trailing blank lines are trimmed. */\n code: string;\n /** Grammar name or alias (`ts`, `bash`, `json`…). Unknown values render plain. */\n language?: string;\n /** Shown in the header, usually a file path. */\n filename?: ReactNode;\n /** Number the lines. Default `false`. */\n showLineNumbers?: boolean;\n /** 1-based line numbers to mark as the point of the snippet. */\n highlightLines?: readonly number[];\n /** Offer a copy button. Default `true`. */\n copyable?: boolean;\n /** Cap the height in px or any CSS length; the body scrolls past it. */\n maxHeight?: number | string;\n /** Wrap long lines instead of scrolling sideways. Default `false`. */\n wrap?: boolean;\n /**\n * Accessible name for the code region. Defaults to naming the language, and\n * to the filename when there is one.\n */\n label?: string;\n}\n\n/**\n * A read-only code sample: syntax colours, optional line numbers, copy button.\n *\n * The `<pre>` is always focusable. A code block is scrollable and holds nothing\n * focusable inside, so without a tab stop a keyboard user can see there is more\n * code past the edge and has no way to reach it. It is the one scroll container\n * where the stop is unconditional rather than measured — a code sample is\n * expected to be reachable, read and selected on its own.\n *\n * Colours come from an approximate scanner, not a parser — see {@link tokenize}.\n *\n * @example\n * <CodeBlock code={snippet} language=\"ts\" filename=\"src/main.ts\" showLineNumbers />\n * <CodeBlock code={log} language=\"bash\" maxHeight={280} />\n */\nexport function CodeBlock({\n code,\n language,\n filename,\n showLineNumbers = false,\n highlightLines,\n copyable = true,\n maxHeight,\n wrap = false,\n label,\n className,\n ...rest\n}: CodeBlockProps) {\n const trimmed = useMemo(() => code.replace(/^\\n+/, \"\").replace(/\\s+$/, \"\"), [code]);\n const lines = useMemo(() => tokenizeLines(trimmed, language), [trimmed, language]);\n const resolved = resolveLanguage(language);\n const marked = useMemo(() => new Set(highlightLines ?? []), [highlightLines]);\n\n const name =\n label ??\n (filename && typeof filename === \"string\"\n ? `Código: ${filename}`\n : `Bloco de código${resolved === \"plain\" ? \"\" : ` em ${resolved}`}`);\n\n const hasHeader = Boolean(filename) || copyable;\n\n return (\n <div className={cn(styles.wrapper, className)} {...rest}>\n {hasHeader && (\n <div className={styles.header}>\n <span className={styles.filename}>\n {filename ?? (resolved === \"plain\" ? \"\" : resolved)}\n </span>\n {copyable && <CopyButton value={trimmed} className={styles.copy} />}\n </div>\n )}\n\n <pre\n className={cn(styles.pre, wrap && styles.wrap)}\n style={{ maxHeight }}\n tabIndex={0}\n role=\"group\"\n aria-label={name}\n >\n <code className={styles.code} data-language={resolved}>\n {lines.map((tokens, index) => (\n <Fragment key={index}>\n <span\n className={cn(styles.line, marked.has(index + 1) && styles.marked)}\n >\n {showLineNumbers && (\n /*\n * The number is decoration: it must not land in the\n * clipboard when the reader selects the snippet, and a\n * screen reader announcing \"one const two import\" adds\n * nothing. `user-select: none` in CSS plus this.\n */\n <span className={styles.lineNumber} aria-hidden=\"true\">\n {index + 1}\n </span>\n )}\n <span className={styles.lineContent}>\n {tokens.map((token, tokenIndex) => (\n <span\n key={tokenIndex}\n className={styles[token.kind]}\n data-token={token.kind}\n >\n {token.value}\n </span>\n ))}\n </span>\n </span>\n {/*\n * A real newline character, and outside the line box.\n * It has to be real so that selecting the snippet by\n * hand and copying yields the source instead of one\n * run-together line. It has to be outside because the\n * line is an inline-block: a newline within one is\n * consumed inside that box, and every line ends up\n * side by side on a single row. The last one is\n * dropped so the block does not end in blank space.\n */}\n {index < lines.length - 1 ? \"\\n\" : null}\n </Fragment>\n ))}\n </code>\n </pre>\n </div>\n );\n}\n"],"mappings":"sMAsDA,SAAgB,EAAU,CACtB,OACA,WACA,WACA,kBAAkB,GAClB,iBACA,WAAW,GACX,YACA,OAAO,GACP,QACA,YACA,GAAG,GACY,CACf,IAAM,GAAA,EAAU,EAAA,QAAA,KAAc,EAAK,QAAQ,OAAQ,EAAE,CAAC,CAAC,QAAQ,OAAQ,EAAE,EAAG,CAAC,CAAI,CAAC,EAC5E,GAAA,EAAQ,EAAA,QAAA,KAAc,EAAA,cAAc,EAAS,CAAQ,EAAG,CAAC,EAAS,CAAQ,CAAC,EAC3E,EAAW,EAAA,gBAAgB,CAAQ,EACnC,GAAA,EAAS,EAAA,QAAA,KAAc,IAAI,IAAI,GAAkB,CAAC,CAAC,EAAG,CAAC,CAAc,CAAC,EAEtE,EACF,IACC,GAAY,OAAO,GAAa,SAC3B,WAAW,IACX,kBAAkB,IAAa,QAAU,GAAK,OAAO,OAEzD,EAAY,EAAQ,GAAa,EAEvC,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EAAG,GAAI,EAAnD,SAAA,CACK,IACG,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,OAAvB,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,SACnB,SAAA,IAAa,IAAa,QAAU,GAAK,EACxC,CAAA,EACL,IAAY,EAAA,EAAA,IAAA,CAAC,EAAA,WAAD,CAAY,MAAO,EAAS,UAAW,EAAA,QAAO,IAAO,CAAA,CACjE,CAGT,CAAA,GAAA,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,GAAQ,EAAA,QAAO,IAAI,EAC7C,MAAO,CAAE,WAAU,EACnB,SAAU,EACV,KAAK,QACL,aAAY,EAEZ,UAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,KAAM,gBAAe,EACxC,SAAA,EAAM,KAAK,EAAQ,KAChB,EAAA,EAAA,KAAA,CAAC,EAAA,SAAD,CAAA,SAAA,EACI,EAAA,EAAA,KAAA,CAAC,OAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,EAAO,IAAI,EAAQ,CAAC,GAAK,EAAA,QAAO,MAAM,EADrE,SAAA,CAGK,IAOG,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,WAAY,cAAY,OAC3C,SAAA,EAAQ,CACP,CAAA,GAEV,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,YACnB,SAAA,EAAO,KAAK,EAAO,KAChB,EAAA,EAAA,IAAA,CAAC,OAAD,CAEI,UAAW,EAAA,QAAO,EAAM,MACxB,aAAY,EAAM,KAEjB,SAAA,EAAM,KACL,EALG,CAKH,CACT,CACC,CAAA,CACJ,CAWL,CAAA,EAAA,EAAQ,EAAM,OAAS,EAAI;EAAO,IAC7B,CAAA,EAtCK,CAsCL,CACb,CACC,CAAA,CACL,CAAA,CACJ,GAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlock.js","names":[],"sources":["../../../src/components/CodeBlock/CodeBlock.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — code and language drive the scanner; filename,\n * showLineNumbers, highlightLines, maxHeight and wrap are the presentation a docs\n * page picks per block, and copyable plus label are the affordance and its\n * accessible name. All independent, all used in the SDK's own docs gallery.\n */\nimport { Fragment, useMemo } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport { CopyButton } from \"../CopyButton\";\nimport { resolveLanguage, tokenizeLines } from \"./tokenize\";\nimport styles from \"./CodeBlock.module.css\";\n\nexport interface CodeBlockProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** The source to display. Leading and trailing blank lines are trimmed. */\n code: string;\n /** Grammar name or alias (`ts`, `bash`, `json`…). Unknown values render plain. */\n language?: string;\n /** Shown in the header, usually a file path. */\n filename?: ReactNode;\n /** Number the lines. Default `false`. */\n showLineNumbers?: boolean;\n /** 1-based line numbers to mark as the point of the snippet. */\n highlightLines?: readonly number[];\n /** Offer a copy button. Default `true`. */\n copyable?: boolean;\n /** Cap the height in px or any CSS length; the body scrolls past it. */\n maxHeight?: number | string;\n /** Wrap long lines instead of scrolling sideways. Default `false`. */\n wrap?: boolean;\n /**\n * Accessible name for the code region. Defaults to naming the language, and\n * to the filename when there is one.\n */\n label?: string;\n}\n\n/**\n * A read-only code sample: syntax colours, optional line numbers, copy button.\n *\n * The `<pre>` is always focusable. A code block is scrollable and holds nothing\n * focusable inside, so without a tab stop a keyboard user can see there is more\n * code past the edge and has no way to reach it. It is the one scroll container\n * where the stop is unconditional rather than measured — a code sample is\n * expected to be reachable, read and selected on its own.\n *\n * Colours come from an approximate scanner, not a parser — see {@link tokenize}.\n *\n * @example\n * <CodeBlock code={snippet} language=\"ts\" filename=\"src/main.ts\" showLineNumbers />\n * <CodeBlock code={log} language=\"bash\" maxHeight={280} />\n */\nexport function CodeBlock({\n code,\n language,\n filename,\n showLineNumbers = false,\n highlightLines,\n copyable = true,\n maxHeight,\n wrap = false,\n label,\n className,\n ...rest\n}: CodeBlockProps) {\n const trimmed = useMemo(() => code.replace(/^\\n+/, \"\").replace(/\\s+$/, \"\"), [code]);\n const lines = useMemo(() => tokenizeLines(trimmed, language), [trimmed, language]);\n const resolved = resolveLanguage(language);\n const marked = useMemo(() => new Set(highlightLines ?? []), [highlightLines]);\n\n const name =\n label ??\n (filename && typeof filename === \"string\"\n ? `Código: ${filename}`\n : `Bloco de código${resolved === \"plain\" ? \"\" : ` em ${resolved}`}`);\n\n const hasHeader = Boolean(filename) || copyable;\n\n return (\n <div className={cn(styles.wrapper, className)} {...rest}>\n {hasHeader && (\n <div className={styles.header}>\n <span className={styles.filename}>\n {filename ?? (resolved === \"plain\" ? \"\" : resolved)}\n </span>\n {copyable && <CopyButton value={trimmed} className={styles.copy} />}\n </div>\n )}\n\n <pre\n className={cn(styles.pre, wrap && styles.wrap)}\n style={{ maxHeight }}\n tabIndex={0}\n role=\"group\"\n aria-label={name}\n >\n <code className={styles.code} data-language={resolved}>\n {lines.map((tokens, index) => (\n <Fragment key={index}>\n <span\n className={cn(styles.line, marked.has(index + 1) && styles.marked)}\n >\n {showLineNumbers && (\n /*\n * The number is decoration: it must not land in the\n * clipboard when the reader selects the snippet, and a\n * screen reader announcing \"one const two import\" adds\n * nothing. `user-select: none` in CSS plus this.\n */\n <span className={styles.lineNumber} aria-hidden=\"true\">\n {index + 1}\n </span>\n )}\n <span className={styles.lineContent}>\n {tokens.map((token, tokenIndex) => (\n <span\n key={tokenIndex}\n className={styles[token.kind]}\n data-token={token.kind}\n >\n {token.value}\n </span>\n ))}\n </span>\n </span>\n {/*\n * A real newline character, and outside the line box.\n * It has to be real so that selecting the snippet by\n * hand and copying yields the source instead of one\n * run-together line. It has to be outside because the\n * line is an inline-block: a newline within one is\n * consumed inside that box, and every line ends up\n * side by side on a single row. The last one is\n * dropped so the block does not end in blank space.\n */}\n {index < lines.length - 1 ? \"\\n\" : null}\n </Fragment>\n ))}\n </code>\n </pre>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAsDA,SAAgB,EAAU,EACtB,SACA,aACA,aACA,qBAAkB,IAClB,mBACA,cAAW,IACX,cACA,UAAO,IACP,UACA,cACA,GAAG,KACY;CACf,IAAM,IAAU,QAAc,EAAK,QAAQ,QAAQ,EAAE,CAAC,CAAC,QAAQ,QAAQ,EAAE,GAAG,CAAC,CAAI,CAAC,GAC5E,IAAQ,QAAc,EAAc,GAAS,CAAQ,GAAG,CAAC,GAAS,CAAQ,CAAC,GAC3E,IAAW,EAAgB,CAAQ,GACnC,IAAS,QAAc,IAAI,IAAI,KAAkB,CAAC,CAAC,GAAG,CAAC,CAAc,CAAC,GAEtE,IACF,MACC,KAAY,OAAO,KAAa,WAC3B,WAAW,MACX,kBAAkB,MAAa,UAAU,KAAK,OAAO,QAEzD,IAAY,EAAQ,KAAa;CAEvC,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAS;EAAG,GAAI;YAAnD,CACK,KACG,kBAAC,OAAD;GAAK,WAAW,EAAO;aAAvB,CACI,kBAAC,QAAD;IAAM,WAAW,EAAO;cACnB,MAAa,MAAa,UAAU,KAAK;GACxC,CAAA,GACL,KAAY,kBAAC,GAAD;IAAY,OAAO;IAAS,WAAW,EAAO;GAAO,CAAA,CACjE;MAGT,kBAAC,OAAD;GACI,WAAW,EAAG,EAAO,KAAK,KAAQ,EAAO,IAAI;GAC7C,OAAO,EAAE,aAAU;GACnB,UAAU;GACV,MAAK;GACL,cAAY;aAEZ,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAM,iBAAe;cACxC,EAAM,KAAK,GAAQ,MAChB,kBAAC,GAAD,EAAA,UAAA,CACI,kBAAC,QAAD;KACI,WAAW,EAAG,EAAO,MAAM,EAAO,IAAI,IAAQ,CAAC,KAAK,EAAO,MAAM;eADrE,CAGK,KAOG,kBAAC,QAAD;MAAM,WAAW,EAAO;MAAY,eAAY;gBAC3C,IAAQ;KACP,CAAA,GAEV,kBAAC,QAAD;MAAM,WAAW,EAAO;gBACnB,EAAO,KAAK,GAAO,MAChB,kBAAC,QAAD;OAEI,WAAW,EAAO,EAAM;OACxB,cAAY,EAAM;iBAEjB,EAAM;MACL,GALG,CAKH,CACT;KACC,CAAA,CACJ;QAWL,IAAQ,EAAM,SAAS,IAAI,OAAO,IAC7B,EAAA,GAtCK,CAsCL,CACb;GACC,CAAA;EACL,CAAA,CACJ;;AAEb"}
1
+ {"version":3,"file":"CodeBlock.js","names":[],"sources":["../../../src/components/CodeBlock/CodeBlock.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — code and language drive the scanner; filename,\n * showLineNumbers, highlightLines, maxHeight and wrap are the presentation a docs\n * page picks per block, and copyable plus label are the affordance and its\n * accessible name. All independent, all used in the SDK's own docs gallery.\n */\nimport { Fragment, useMemo } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport { CopyButton } from \"../CopyButton\";\nimport { resolveLanguage, tokenizeLines } from \"./tokenize\";\nimport styles from \"./CodeBlock.module.css\";\n\nexport interface CodeBlockProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** The source to display. Leading and trailing blank lines are trimmed. */\n code: string;\n /** Grammar name or alias (`ts`, `bash`, `json`…). Unknown values render plain. */\n language?: string;\n /** Shown in the header, usually a file path. */\n filename?: ReactNode;\n /** Number the lines. Default `false`. */\n showLineNumbers?: boolean;\n /** 1-based line numbers to mark as the point of the snippet. */\n highlightLines?: readonly number[];\n /** Offer a copy button. Default `true`. */\n copyable?: boolean;\n /** Cap the height in px or any CSS length; the body scrolls past it. */\n maxHeight?: number | string;\n /** Wrap long lines instead of scrolling sideways. Default `false`. */\n wrap?: boolean;\n /**\n * Accessible name for the code region. Defaults to naming the language, and\n * to the filename when there is one.\n */\n label?: string;\n}\n\n/**\n * A read-only code sample: syntax colours, optional line numbers, copy button.\n *\n * The `<pre>` is always focusable. A code block is scrollable and holds nothing\n * focusable inside, so without a tab stop a keyboard user can see there is more\n * code past the edge and has no way to reach it. It is the one scroll container\n * where the stop is unconditional rather than measured — a code sample is\n * expected to be reachable, read and selected on its own.\n *\n * Colours come from an approximate scanner, not a parser — see {@link tokenize}.\n *\n * @example\n * <CodeBlock code={snippet} language=\"ts\" filename=\"src/main.ts\" showLineNumbers />\n * <CodeBlock code={log} language=\"bash\" maxHeight={280} />\n */\nexport function CodeBlock({\n code,\n language,\n filename,\n showLineNumbers = false,\n highlightLines,\n copyable = true,\n maxHeight,\n wrap = false,\n label,\n className,\n ...rest\n}: CodeBlockProps) {\n const trimmed = useMemo(() => code.replace(/^\\n+/, \"\").replace(/\\s+$/, \"\"), [code]);\n const lines = useMemo(() => tokenizeLines(trimmed, language), [trimmed, language]);\n const resolved = resolveLanguage(language);\n const marked = useMemo(() => new Set(highlightLines ?? []), [highlightLines]);\n\n const name =\n label ??\n (filename && typeof filename === \"string\"\n ? `Código: ${filename}`\n : `Bloco de código${resolved === \"plain\" ? \"\" : ` em ${resolved}`}`);\n\n const hasHeader = Boolean(filename) || copyable;\n\n return (\n <div className={cn(styles.wrapper, className)} {...rest}>\n {hasHeader && (\n <div className={styles.header}>\n <span className={styles.filename}>\n {filename ?? (resolved === \"plain\" ? \"\" : resolved)}\n </span>\n {copyable && <CopyButton value={trimmed} className={styles.copy} />}\n </div>\n )}\n\n <pre\n className={cn(styles.pre, wrap && styles.wrap)}\n style={{ maxHeight }}\n tabIndex={0}\n role=\"group\"\n aria-label={name}\n >\n <code className={styles.code} data-language={resolved}>\n {lines.map((tokens, index) => (\n <Fragment key={index}>\n <span\n className={cn(styles.line, marked.has(index + 1) && styles.marked)}\n >\n {showLineNumbers && (\n /*\n * The number is decoration: it must not land in the\n * clipboard when the reader selects the snippet, and a\n * screen reader announcing \"one const two import\" adds\n * nothing. `user-select: none` in CSS plus this.\n */\n <span className={styles.lineNumber} aria-hidden=\"true\">\n {index + 1}\n </span>\n )}\n <span className={styles.lineContent}>\n {tokens.map((token, tokenIndex) => (\n <span\n key={tokenIndex}\n className={styles[token.kind]}\n data-token={token.kind}\n >\n {token.value}\n </span>\n ))}\n </span>\n </span>\n {/*\n * A real newline character, and outside the line box.\n * It has to be real so that selecting the snippet by\n * hand and copying yields the source instead of one\n * run-together line. It has to be outside because the\n * line is an inline-block: a newline within one is\n * consumed inside that box, and every line ends up\n * side by side on a single row. The last one is\n * dropped so the block does not end in blank space.\n */}\n {index < lines.length - 1 ? \"\\n\" : null}\n </Fragment>\n ))}\n </code>\n </pre>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAsDA,SAAgB,EAAU,EACtB,SACA,aACA,aACA,qBAAkB,IAClB,mBACA,cAAW,IACX,cACA,UAAO,IACP,UACA,cACA,GAAG,KACY;CACf,IAAM,IAAU,QAAc,EAAK,QAAQ,QAAQ,EAAE,CAAC,CAAC,QAAQ,QAAQ,EAAE,GAAG,CAAC,CAAI,CAAC,GAC5E,IAAQ,QAAc,EAAc,GAAS,CAAQ,GAAG,CAAC,GAAS,CAAQ,CAAC,GAC3E,IAAW,EAAgB,CAAQ,GACnC,IAAS,QAAc,IAAI,IAAI,KAAkB,CAAC,CAAC,GAAG,CAAC,CAAc,CAAC,GAEtE,IACF,MACC,KAAY,OAAO,KAAa,WAC3B,WAAW,MACX,kBAAkB,MAAa,UAAU,KAAK,OAAO,QAEzD,IAAY,EAAQ,KAAa;CAEvC,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAS;EAAG,GAAI;EAAnD,UAAA,CACK,KACG,kBAAC,OAAD;GAAK,WAAW,EAAO;GAAvB,UAAA,CACI,kBAAC,QAAD;IAAM,WAAW,EAAO;IACnB,UAAA,MAAa,MAAa,UAAU,KAAK;GACxC,CAAA,GACL,KAAY,kBAAC,GAAD;IAAY,OAAO;IAAS,WAAW,EAAO;GAAO,CAAA,CACjE;EAGT,CAAA,GAAA,kBAAC,OAAD;GACI,WAAW,EAAG,EAAO,KAAK,KAAQ,EAAO,IAAI;GAC7C,OAAO,EAAE,aAAU;GACnB,UAAU;GACV,MAAK;GACL,cAAY;GAEZ,UAAA,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAM,iBAAe;IACxC,UAAA,EAAM,KAAK,GAAQ,MAChB,kBAAC,GAAD,EAAA,UAAA,CACI,kBAAC,QAAD;KACI,WAAW,EAAG,EAAO,MAAM,EAAO,IAAI,IAAQ,CAAC,KAAK,EAAO,MAAM;KADrE,UAAA,CAGK,KAOG,kBAAC,QAAD;MAAM,WAAW,EAAO;MAAY,eAAY;MAC3C,UAAA,IAAQ;KACP,CAAA,GAEV,kBAAC,QAAD;MAAM,WAAW,EAAO;MACnB,UAAA,EAAO,KAAK,GAAO,MAChB,kBAAC,QAAD;OAEI,WAAW,EAAO,EAAM;OACxB,cAAY,EAAM;OAEjB,UAAA,EAAM;MACL,GALG,CAKH,CACT;KACC,CAAA,CACJ;IAWL,CAAA,GAAA,IAAQ,EAAM,SAAS,IAAI,OAAO,IAC7B,EAAA,GAtCK,CAsCL,CACb;GACC,CAAA;EACL,CAAA,CACJ;;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"Collapsible.cjs","names":[],"sources":["../../../src/components/Collapsible/Collapsible.tsx"],"sourcesContent":["import { useCallback, useId, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Collapsible.module.css\";\n\nexport interface CollapsibleProps extends HTMLAttributes<HTMLDivElement> {\n /** Controlled open state. When provided the component is controlled. */\n open?: boolean;\n /** Initial open state for the uncontrolled variant. Default `false`. */\n defaultOpen?: boolean;\n /** Fired with the next open state whenever the trigger is activated. */\n onOpenChange?: (open: boolean) => void;\n /** Content rendered inside the trigger button. */\n trigger: ReactNode;\n /** Collapsible content, hidden while closed. */\n children: ReactNode;\n}\n\n/**\n * A single expand/collapse region — a lighter alternative to `Accordion` for\n * one toggleable block. The trigger is a `<button aria-expanded aria-controls>`\n * wired to a content region sharing the same id; the region is `hidden` while\n * closed. Works controlled (`open` + `onOpenChange`) or uncontrolled\n * (`defaultOpen`).\n *\n * @param props - {@link CollapsibleProps}.\n * @returns The collapsible container.\n */\nexport function Collapsible({\n open,\n defaultOpen = false,\n onOpenChange,\n trigger,\n className,\n children,\n ...props\n}: CollapsibleProps) {\n const reactId = useId();\n const contentId = `${reactId}-content`;\n const triggerId = `${reactId}-trigger`;\n\n const isControlled = open !== undefined;\n const [internalOpen, setInternalOpen] = useState<boolean>(defaultOpen);\n const isOpen = isControlled ? open : internalOpen;\n\n const handleToggle = useCallback((): void => {\n const next = !isOpen;\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n }, [isOpen, isControlled, onOpenChange]);\n\n return (\n <div className={cn(styles.collapsible, isOpen && styles.open, className)} {...props}>\n <button\n type=\"button\"\n id={triggerId}\n className={styles.trigger}\n aria-expanded={isOpen}\n aria-controls={contentId}\n onClick={handleToggle}\n >\n {trigger}\n </button>\n <div\n id={contentId}\n role=\"region\"\n aria-labelledby={triggerId}\n hidden={!isOpen}\n className={styles.content}\n >\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":"kIA4BA,SAAgB,EAAY,CACxB,OACA,cAAc,GACd,eACA,UACA,YACA,WACA,GAAG,GACc,CACjB,IAAM,GAAA,EAAA,EAAA,MAAA,CAAgB,EAChB,EAAY,GAAG,EAAQ,UACvB,EAAY,GAAG,EAAQ,UAEvB,EAAe,IAAS,IAAA,GACxB,CAAC,EAAc,IAAA,EAAA,EAAA,SAAA,CAAqC,CAAW,EAC/D,EAAS,EAAe,EAAO,EAE/B,GAAA,EAAA,EAAA,YAAA,KAAuC,CACzC,IAAM,EAAO,CAAC,EACT,GAAc,EAAgB,CAAI,EACvC,IAAe,CAAI,CACvB,EAAG,CAAC,EAAQ,EAAc,CAAY,CAAC,EAEvC,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,YAAa,GAAU,EAAA,QAAO,KAAM,CAAS,EAAG,GAAI,WAA9E,EACI,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,GAAI,EACJ,UAAW,EAAA,QAAO,QAClB,gBAAe,EACf,gBAAe,EACf,QAAS,WAER,CACG,CAAA,GACR,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,GAAI,EACJ,KAAK,SACL,kBAAiB,EACjB,OAAQ,CAAC,EACT,UAAW,EAAA,QAAO,QAEjB,UACA,CAAA,CACJ,GAEb"}
1
+ {"version":3,"file":"Collapsible.cjs","names":[],"sources":["../../../src/components/Collapsible/Collapsible.tsx"],"sourcesContent":["import { useCallback, useId, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Collapsible.module.css\";\n\nexport interface CollapsibleProps extends HTMLAttributes<HTMLDivElement> {\n /** Controlled open state. When provided the component is controlled. */\n open?: boolean;\n /** Initial open state for the uncontrolled variant. Default `false`. */\n defaultOpen?: boolean;\n /** Fired with the next open state whenever the trigger is activated. */\n onOpenChange?: (open: boolean) => void;\n /** Content rendered inside the trigger button. */\n trigger: ReactNode;\n /** Collapsible content, hidden while closed. */\n children: ReactNode;\n}\n\n/**\n * A single expand/collapse region — a lighter alternative to `Accordion` for\n * one toggleable block. The trigger is a `<button aria-expanded aria-controls>`\n * wired to a content region sharing the same id; the region is `hidden` while\n * closed. Works controlled (`open` + `onOpenChange`) or uncontrolled\n * (`defaultOpen`).\n *\n * @param props - {@link CollapsibleProps}.\n * @returns The collapsible container.\n */\nexport function Collapsible({\n open,\n defaultOpen = false,\n onOpenChange,\n trigger,\n className,\n children,\n ...props\n}: CollapsibleProps) {\n const reactId = useId();\n const contentId = `${reactId}-content`;\n const triggerId = `${reactId}-trigger`;\n\n const isControlled = open !== undefined;\n const [internalOpen, setInternalOpen] = useState<boolean>(defaultOpen);\n const isOpen = isControlled ? open : internalOpen;\n\n const handleToggle = useCallback((): void => {\n const next = !isOpen;\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n }, [isOpen, isControlled, onOpenChange]);\n\n return (\n <div className={cn(styles.collapsible, isOpen && styles.open, className)} {...props}>\n <button\n type=\"button\"\n id={triggerId}\n className={styles.trigger}\n aria-expanded={isOpen}\n aria-controls={contentId}\n onClick={handleToggle}\n >\n {trigger}\n </button>\n <div\n id={contentId}\n role=\"region\"\n aria-labelledby={triggerId}\n hidden={!isOpen}\n className={styles.content}\n >\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":"kIA4BA,SAAgB,EAAY,CACxB,OACA,cAAc,GACd,eACA,UACA,YACA,WACA,GAAG,GACc,CACjB,IAAM,GAAA,EAAU,EAAA,MAAA,CAAM,EAChB,EAAY,GAAG,EAAQ,UACvB,EAAY,GAAG,EAAQ,UAEvB,EAAe,IAAS,IAAA,GACxB,CAAC,EAAc,IAAA,EAAmB,EAAA,SAAA,CAAkB,CAAW,EAC/D,EAAS,EAAe,EAAO,EAE/B,GAAA,EAAe,EAAA,YAAA,KAAwB,CACzC,IAAM,EAAO,CAAC,EACT,GAAc,EAAgB,CAAI,EACvC,IAAe,CAAI,CACvB,EAAG,CAAC,EAAQ,EAAc,CAAY,CAAC,EAEvC,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,YAAa,GAAU,EAAA,QAAO,KAAM,CAAS,EAAG,GAAI,EAA9E,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,GAAI,EACJ,UAAW,EAAA,QAAO,QAClB,gBAAe,EACf,gBAAe,EACf,QAAS,EAER,SAAA,CACG,CAAA,GACR,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,GAAI,EACJ,KAAK,SACL,kBAAiB,EACjB,OAAQ,CAAC,EACT,UAAW,EAAA,QAAO,QAEjB,UACA,CAAA,CACJ,GAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"Collapsible.js","names":[],"sources":["../../../src/components/Collapsible/Collapsible.tsx"],"sourcesContent":["import { useCallback, useId, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Collapsible.module.css\";\n\nexport interface CollapsibleProps extends HTMLAttributes<HTMLDivElement> {\n /** Controlled open state. When provided the component is controlled. */\n open?: boolean;\n /** Initial open state for the uncontrolled variant. Default `false`. */\n defaultOpen?: boolean;\n /** Fired with the next open state whenever the trigger is activated. */\n onOpenChange?: (open: boolean) => void;\n /** Content rendered inside the trigger button. */\n trigger: ReactNode;\n /** Collapsible content, hidden while closed. */\n children: ReactNode;\n}\n\n/**\n * A single expand/collapse region — a lighter alternative to `Accordion` for\n * one toggleable block. The trigger is a `<button aria-expanded aria-controls>`\n * wired to a content region sharing the same id; the region is `hidden` while\n * closed. Works controlled (`open` + `onOpenChange`) or uncontrolled\n * (`defaultOpen`).\n *\n * @param props - {@link CollapsibleProps}.\n * @returns The collapsible container.\n */\nexport function Collapsible({\n open,\n defaultOpen = false,\n onOpenChange,\n trigger,\n className,\n children,\n ...props\n}: CollapsibleProps) {\n const reactId = useId();\n const contentId = `${reactId}-content`;\n const triggerId = `${reactId}-trigger`;\n\n const isControlled = open !== undefined;\n const [internalOpen, setInternalOpen] = useState<boolean>(defaultOpen);\n const isOpen = isControlled ? open : internalOpen;\n\n const handleToggle = useCallback((): void => {\n const next = !isOpen;\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n }, [isOpen, isControlled, onOpenChange]);\n\n return (\n <div className={cn(styles.collapsible, isOpen && styles.open, className)} {...props}>\n <button\n type=\"button\"\n id={triggerId}\n className={styles.trigger}\n aria-expanded={isOpen}\n aria-controls={contentId}\n onClick={handleToggle}\n >\n {trigger}\n </button>\n <div\n id={contentId}\n role=\"region\"\n aria-labelledby={triggerId}\n hidden={!isOpen}\n className={styles.content}\n >\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AA4BA,SAAgB,EAAY,EACxB,SACA,iBAAc,IACd,iBACA,YACA,cACA,aACA,GAAG,KACc;CACjB,IAAM,IAAU,EAAM,GAChB,IAAY,GAAG,EAAQ,WACvB,IAAY,GAAG,EAAQ,WAEvB,IAAe,MAAS,KAAA,GACxB,CAAC,GAAc,KAAmB,EAAkB,CAAW,GAC/D,IAAS,IAAe,IAAO,GAE/B,IAAe,QAAwB;EACzC,IAAM,IAAO,CAAC;EAEd,AADK,KAAc,EAAgB,CAAI,GACvC,IAAe,CAAI;CACvB,GAAG;EAAC;EAAQ;EAAc;CAAY,CAAC;CAEvC,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,aAAa,KAAU,EAAO,MAAM,CAAS;EAAG,GAAI;YAA9E,CACI,kBAAC,UAAD;GACI,MAAK;GACL,IAAI;GACJ,WAAW,EAAO;GAClB,iBAAe;GACf,iBAAe;GACf,SAAS;aAER;EACG,CAAA,GACR,kBAAC,OAAD;GACI,IAAI;GACJ,MAAK;GACL,mBAAiB;GACjB,QAAQ,CAAC;GACT,WAAW,EAAO;GAEjB;EACA,CAAA,CACJ;;AAEb"}
1
+ {"version":3,"file":"Collapsible.js","names":[],"sources":["../../../src/components/Collapsible/Collapsible.tsx"],"sourcesContent":["import { useCallback, useId, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Collapsible.module.css\";\n\nexport interface CollapsibleProps extends HTMLAttributes<HTMLDivElement> {\n /** Controlled open state. When provided the component is controlled. */\n open?: boolean;\n /** Initial open state for the uncontrolled variant. Default `false`. */\n defaultOpen?: boolean;\n /** Fired with the next open state whenever the trigger is activated. */\n onOpenChange?: (open: boolean) => void;\n /** Content rendered inside the trigger button. */\n trigger: ReactNode;\n /** Collapsible content, hidden while closed. */\n children: ReactNode;\n}\n\n/**\n * A single expand/collapse region — a lighter alternative to `Accordion` for\n * one toggleable block. The trigger is a `<button aria-expanded aria-controls>`\n * wired to a content region sharing the same id; the region is `hidden` while\n * closed. Works controlled (`open` + `onOpenChange`) or uncontrolled\n * (`defaultOpen`).\n *\n * @param props - {@link CollapsibleProps}.\n * @returns The collapsible container.\n */\nexport function Collapsible({\n open,\n defaultOpen = false,\n onOpenChange,\n trigger,\n className,\n children,\n ...props\n}: CollapsibleProps) {\n const reactId = useId();\n const contentId = `${reactId}-content`;\n const triggerId = `${reactId}-trigger`;\n\n const isControlled = open !== undefined;\n const [internalOpen, setInternalOpen] = useState<boolean>(defaultOpen);\n const isOpen = isControlled ? open : internalOpen;\n\n const handleToggle = useCallback((): void => {\n const next = !isOpen;\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n }, [isOpen, isControlled, onOpenChange]);\n\n return (\n <div className={cn(styles.collapsible, isOpen && styles.open, className)} {...props}>\n <button\n type=\"button\"\n id={triggerId}\n className={styles.trigger}\n aria-expanded={isOpen}\n aria-controls={contentId}\n onClick={handleToggle}\n >\n {trigger}\n </button>\n <div\n id={contentId}\n role=\"region\"\n aria-labelledby={triggerId}\n hidden={!isOpen}\n className={styles.content}\n >\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AA4BA,SAAgB,EAAY,EACxB,SACA,iBAAc,IACd,iBACA,YACA,cACA,aACA,GAAG,KACc;CACjB,IAAM,IAAU,EAAM,GAChB,IAAY,GAAG,EAAQ,WACvB,IAAY,GAAG,EAAQ,WAEvB,IAAe,MAAS,KAAA,GACxB,CAAC,GAAc,KAAmB,EAAkB,CAAW,GAC/D,IAAS,IAAe,IAAO,GAE/B,IAAe,QAAwB;EACzC,IAAM,IAAO,CAAC;EAEd,AADK,KAAc,EAAgB,CAAI,GACvC,IAAe,CAAI;CACvB,GAAG;EAAC;EAAQ;EAAc;CAAY,CAAC;CAEvC,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,aAAa,KAAU,EAAO,MAAM,CAAS;EAAG,GAAI;EAA9E,UAAA,CACI,kBAAC,UAAD;GACI,MAAK;GACL,IAAI;GACJ,WAAW,EAAO;GAClB,iBAAe;GACf,iBAAe;GACf,SAAS;GAER,UAAA;EACG,CAAA,GACR,kBAAC,OAAD;GACI,IAAI;GACJ,MAAK;GACL,mBAAiB;GACjB,QAAQ,CAAC;GACT,WAAW,EAAO;GAEjB;EACA,CAAA,CACJ;;AAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"Combobox.cjs","names":[],"sources":["../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — options/value/onChange\n * plus the shared field contract (label, placeholder, helperText, error, disabled,\n * className) and the three combobox-specific knobs: filter, emptyMessage. The body\n * is the listbox — open state, active descendant, type-ahead and the ARIA wiring —\n * and those cannot be separated without passing the same active index back and\n * forth.\n */\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Combobox.module.css\";\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface ComboboxProps {\n options: ComboboxOption[];\n value: string;\n onChange: (value: string) => void;\n label?: string;\n placeholder?: string;\n helperText?: string;\n error?: string;\n disabled?: boolean;\n /** Custom filter — return true to keep the option. Default is case-insensitive substring match on label. */\n filter?: (option: ComboboxOption, query: string) => boolean;\n /** Message shown when no option matches. */\n emptyMessage?: string;\n className?: string;\n}\n\nfunction defaultFilter(option: ComboboxOption, query: string): boolean {\n if (!query) return true;\n return option.label.toLowerCase().includes(query.toLowerCase());\n}\n\n/**\n * Combobox — text input with a filterable dropdown of options.\n *\n * Selecting an option fires `onChange(value)`. Typing filters the list.\n * Keyboard: ArrowUp/ArrowDown to navigate, Enter to select, Esc to close.\n */\nexport function Combobox({\n options,\n value,\n onChange,\n label,\n placeholder = \"Selecione\",\n helperText,\n error,\n disabled,\n filter = defaultFilter,\n emptyMessage = \"Nenhuma opção encontrada\",\n className,\n}: ComboboxProps) {\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 selectedLabel = useMemo(\n () => options.find((o) => o.value === value)?.label ?? \"\",\n [options, value],\n );\n\n const filtered = useMemo(\n () => options.filter((o) => filter(o, query)),\n [options, filter, query],\n );\n\n const closeAndReset = useCallback((): void => {\n setOpen(false);\n setQuery(\"\");\n setActiveIndex(0);\n }, []);\n\n const handleSelect = useCallback(\n (option: ComboboxOption): void => {\n if (option.disabled) return;\n onChange(option.value);\n closeAndReset();\n },\n [onChange, closeAndReset],\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 closeAndReset();\n }\n };\n window.addEventListener(\"mousedown\", onDown);\n return () => window.removeEventListener(\"mousedown\", onDown);\n }, [open, closeAndReset]);\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) handleSelect(option);\n } else if (event.key === \"Escape\") {\n closeAndReset();\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 className={styles.field}>\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={placeholder}\n disabled={disabled}\n value={open ? query : selectedLabel}\n onFocus={() => setOpen(true)}\n onChange={(event) => {\n setQuery(event.target.value);\n setOpen(true);\n setActiveIndex(0);\n }}\n onKeyDown={handleKeyDown}\n />\n <span className={styles.caret} aria-hidden>\n ▾\n </span>\n </div>\n {open && (\n <ul id={`${id}-listbox`} role=\"listbox\" className={styles.menu}>\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n filtered.map((option, index) => (\n <li\n key={option.value}\n role=\"option\"\n aria-selected={option.value === value}\n className={cn(\n styles.option,\n index === activeIndex && styles.active,\n option.value === value && styles.selected,\n )}\n onMouseEnter={() => setActiveIndex(index)}\n onMouseDown={(event) => {\n event.preventDefault();\n handleSelect(option);\n }}\n >\n {option.label}\n </li>\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":"Combobox.cjs","names":[],"sources":["../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — options/value/onChange\n * plus the shared field contract (label, placeholder, helperText, error, disabled,\n * className) and the three combobox-specific knobs: filter, emptyMessage. The body\n * is the listbox — open state, active descendant, type-ahead and the ARIA wiring —\n * and those cannot be separated without passing the same active index back and\n * forth.\n */\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Combobox.module.css\";\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface ComboboxProps {\n options: ComboboxOption[];\n value: string;\n onChange: (value: string) => void;\n label?: string;\n placeholder?: string;\n helperText?: string;\n error?: string;\n disabled?: boolean;\n /** Custom filter — return true to keep the option. Default is case-insensitive substring match on label. */\n filter?: (option: ComboboxOption, query: string) => boolean;\n /** Message shown when no option matches. */\n emptyMessage?: string;\n className?: string;\n}\n\nfunction defaultFilter(option: ComboboxOption, query: string): boolean {\n if (!query) return true;\n return option.label.toLowerCase().includes(query.toLowerCase());\n}\n\n/**\n * Combobox — text input with a filterable dropdown of options.\n *\n * Selecting an option fires `onChange(value)`. Typing filters the list.\n * Keyboard: ArrowUp/ArrowDown to navigate, Enter to select, Esc to close.\n */\nexport function Combobox({\n options,\n value,\n onChange,\n label,\n placeholder = \"Selecione\",\n helperText,\n error,\n disabled,\n filter = defaultFilter,\n emptyMessage = \"Nenhuma opção encontrada\",\n className,\n}: ComboboxProps) {\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 selectedLabel = useMemo(\n () => options.find((o) => o.value === value)?.label ?? \"\",\n [options, value],\n );\n\n const filtered = useMemo(\n () => options.filter((o) => filter(o, query)),\n [options, filter, query],\n );\n\n const closeAndReset = useCallback((): void => {\n setOpen(false);\n setQuery(\"\");\n setActiveIndex(0);\n }, []);\n\n const handleSelect = useCallback(\n (option: ComboboxOption): void => {\n if (option.disabled) return;\n onChange(option.value);\n closeAndReset();\n },\n [onChange, closeAndReset],\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 closeAndReset();\n }\n };\n window.addEventListener(\"mousedown\", onDown);\n return () => window.removeEventListener(\"mousedown\", onDown);\n }, [open, closeAndReset]);\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) handleSelect(option);\n } else if (event.key === \"Escape\") {\n closeAndReset();\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 className={styles.field}>\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={placeholder}\n disabled={disabled}\n value={open ? query : selectedLabel}\n onFocus={() => setOpen(true)}\n onChange={(event) => {\n setQuery(event.target.value);\n setOpen(true);\n setActiveIndex(0);\n }}\n onKeyDown={handleKeyDown}\n />\n <span className={styles.caret} aria-hidden>\n ▾\n </span>\n </div>\n {open && (\n <ul id={`${id}-listbox`} role=\"listbox\" className={styles.menu}>\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n filtered.map((option, index) => (\n <li\n key={option.value}\n role=\"option\"\n aria-selected={option.value === value}\n className={cn(\n styles.option,\n index === activeIndex && styles.active,\n option.value === value && styles.selected,\n )}\n onMouseEnter={() => setActiveIndex(index)}\n onMouseDown={(event) => {\n event.preventDefault();\n handleSelect(option);\n }}\n >\n {option.label}\n </li>\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":"Combobox.js","names":[],"sources":["../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — options/value/onChange\n * plus the shared field contract (label, placeholder, helperText, error, disabled,\n * className) and the three combobox-specific knobs: filter, emptyMessage. The body\n * is the listbox — open state, active descendant, type-ahead and the ARIA wiring —\n * and those cannot be separated without passing the same active index back and\n * forth.\n */\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Combobox.module.css\";\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface ComboboxProps {\n options: ComboboxOption[];\n value: string;\n onChange: (value: string) => void;\n label?: string;\n placeholder?: string;\n helperText?: string;\n error?: string;\n disabled?: boolean;\n /** Custom filter — return true to keep the option. Default is case-insensitive substring match on label. */\n filter?: (option: ComboboxOption, query: string) => boolean;\n /** Message shown when no option matches. */\n emptyMessage?: string;\n className?: string;\n}\n\nfunction defaultFilter(option: ComboboxOption, query: string): boolean {\n if (!query) return true;\n return option.label.toLowerCase().includes(query.toLowerCase());\n}\n\n/**\n * Combobox — text input with a filterable dropdown of options.\n *\n * Selecting an option fires `onChange(value)`. Typing filters the list.\n * Keyboard: ArrowUp/ArrowDown to navigate, Enter to select, Esc to close.\n */\nexport function Combobox({\n options,\n value,\n onChange,\n label,\n placeholder = \"Selecione\",\n helperText,\n error,\n disabled,\n filter = defaultFilter,\n emptyMessage = \"Nenhuma opção encontrada\",\n className,\n}: ComboboxProps) {\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 selectedLabel = useMemo(\n () => options.find((o) => o.value === value)?.label ?? \"\",\n [options, value],\n );\n\n const filtered = useMemo(\n () => options.filter((o) => filter(o, query)),\n [options, filter, query],\n );\n\n const closeAndReset = useCallback((): void => {\n setOpen(false);\n setQuery(\"\");\n setActiveIndex(0);\n }, []);\n\n const handleSelect = useCallback(\n (option: ComboboxOption): void => {\n if (option.disabled) return;\n onChange(option.value);\n closeAndReset();\n },\n [onChange, closeAndReset],\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 closeAndReset();\n }\n };\n window.addEventListener(\"mousedown\", onDown);\n return () => window.removeEventListener(\"mousedown\", onDown);\n }, [open, closeAndReset]);\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) handleSelect(option);\n } else if (event.key === \"Escape\") {\n closeAndReset();\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 className={styles.field}>\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={placeholder}\n disabled={disabled}\n value={open ? query : selectedLabel}\n onFocus={() => setOpen(true)}\n onChange={(event) => {\n setQuery(event.target.value);\n setOpen(true);\n setActiveIndex(0);\n }}\n onKeyDown={handleKeyDown}\n />\n <span className={styles.caret} aria-hidden>\n ▾\n </span>\n </div>\n {open && (\n <ul id={`${id}-listbox`} role=\"listbox\" className={styles.menu}>\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n filtered.map((option, index) => (\n <li\n key={option.value}\n role=\"option\"\n aria-selected={option.value === value}\n className={cn(\n styles.option,\n index === activeIndex && styles.active,\n option.value === value && styles.selected,\n )}\n onMouseEnter={() => setActiveIndex(index)}\n onMouseDown={(event) => {\n event.preventDefault();\n handleSelect(option);\n }}\n >\n {option.label}\n </li>\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":"Combobox.js","names":[],"sources":["../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — options/value/onChange\n * plus the shared field contract (label, placeholder, helperText, error, disabled,\n * className) and the three combobox-specific knobs: filter, emptyMessage. The body\n * is the listbox — open state, active descendant, type-ahead and the ARIA wiring —\n * and those cannot be separated without passing the same active index back and\n * forth.\n */\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Combobox.module.css\";\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface ComboboxProps {\n options: ComboboxOption[];\n value: string;\n onChange: (value: string) => void;\n label?: string;\n placeholder?: string;\n helperText?: string;\n error?: string;\n disabled?: boolean;\n /** Custom filter — return true to keep the option. Default is case-insensitive substring match on label. */\n filter?: (option: ComboboxOption, query: string) => boolean;\n /** Message shown when no option matches. */\n emptyMessage?: string;\n className?: string;\n}\n\nfunction defaultFilter(option: ComboboxOption, query: string): boolean {\n if (!query) return true;\n return option.label.toLowerCase().includes(query.toLowerCase());\n}\n\n/**\n * Combobox — text input with a filterable dropdown of options.\n *\n * Selecting an option fires `onChange(value)`. Typing filters the list.\n * Keyboard: ArrowUp/ArrowDown to navigate, Enter to select, Esc to close.\n */\nexport function Combobox({\n options,\n value,\n onChange,\n label,\n placeholder = \"Selecione\",\n helperText,\n error,\n disabled,\n filter = defaultFilter,\n emptyMessage = \"Nenhuma opção encontrada\",\n className,\n}: ComboboxProps) {\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 selectedLabel = useMemo(\n () => options.find((o) => o.value === value)?.label ?? \"\",\n [options, value],\n );\n\n const filtered = useMemo(\n () => options.filter((o) => filter(o, query)),\n [options, filter, query],\n );\n\n const closeAndReset = useCallback((): void => {\n setOpen(false);\n setQuery(\"\");\n setActiveIndex(0);\n }, []);\n\n const handleSelect = useCallback(\n (option: ComboboxOption): void => {\n if (option.disabled) return;\n onChange(option.value);\n closeAndReset();\n },\n [onChange, closeAndReset],\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 closeAndReset();\n }\n };\n window.addEventListener(\"mousedown\", onDown);\n return () => window.removeEventListener(\"mousedown\", onDown);\n }, [open, closeAndReset]);\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) handleSelect(option);\n } else if (event.key === \"Escape\") {\n closeAndReset();\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 className={styles.field}>\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={placeholder}\n disabled={disabled}\n value={open ? query : selectedLabel}\n onFocus={() => setOpen(true)}\n onChange={(event) => {\n setQuery(event.target.value);\n setOpen(true);\n setActiveIndex(0);\n }}\n onKeyDown={handleKeyDown}\n />\n <span className={styles.caret} aria-hidden>\n ▾\n </span>\n </div>\n {open && (\n <ul id={`${id}-listbox`} role=\"listbox\" className={styles.menu}>\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n filtered.map((option, index) => (\n <li\n key={option.value}\n role=\"option\"\n aria-selected={option.value === value}\n className={cn(\n styles.option,\n index === activeIndex && styles.active,\n option.value === value && styles.selected,\n )}\n onMouseEnter={() => setActiveIndex(index)}\n onMouseDown={(event) => {\n event.preventDefault();\n handleSelect(option);\n }}\n >\n {option.label}\n </li>\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":"Command.cjs","names":[],"sources":["../../../src/components/Command/Command.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, function-lines — a command palette is a filtered\n * listbox with its own keyboard contract: the body holds the query, the flattened\n * result list, the active index and the Escape/Enter handling, all of which read\n * each other on every keystroke.\n */\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/utils/cn\";\nimport { useFocusTrap } from \"@/hooks/use-focus-trap\";\nimport styles from \"./Command.module.css\";\n\nexport interface CommandItem {\n /** Stable unique identifier for the item. */\n id: string;\n /** Human-readable label shown in the list and matched against the query. */\n label: string;\n /** Optional group heading; items sharing a group are rendered together. */\n group?: string;\n /** Extra terms matched against the query in addition to `label`. */\n keywords?: string[];\n /** Invoked when the item is chosen (click or Enter on the active row). */\n onSelect: () => void;\n /** Optional leading icon. */\n icon?: ReactNode;\n}\n\nexport interface CommandProps {\n /** Whether the palette is visible. */\n open: boolean;\n /** Called with the next open state (Escape, selection, backdrop click). */\n onOpenChange: (open: boolean) => void;\n /** Candidate items to filter and display. */\n items: CommandItem[];\n /** Placeholder for the search input. */\n placeholder?: string;\n /** Rendered when no item matches the current query. */\n emptyMessage?: ReactNode;\n /** Forwarded to the dialog element. */\n className?: string;\n}\n\ninterface CommandGroup {\n name: string | undefined;\n items: CommandItem[];\n}\n\n/**\n * Case-insensitively test whether `item` matches `query` by substring against\n * its label and any keywords. An empty query matches everything.\n *\n * @param item - The candidate command item.\n * @param query - The lowercased search query.\n * @returns `true` when the item should be shown.\n */\nfunction matchesQuery(item: CommandItem, query: string): boolean {\n if (query === \"\") return true;\n if (item.label.toLowerCase().includes(query)) return true;\n return (item.keywords ?? []).some((keyword) => keyword.toLowerCase().includes(query));\n}\n\n/**\n * Partition a flat item list into ordered groups, preserving first-seen order\n * for both groups and the items within them.\n *\n * @param items - The (already filtered) items to group.\n * @returns An ordered list of groups.\n */\nfunction groupItems(items: CommandItem[]): CommandGroup[] {\n const groups: CommandGroup[] = [];\n const indexByName = new Map<string | undefined, number>();\n for (const item of items) {\n const existing = indexByName.get(item.group);\n if (existing === undefined) {\n indexByName.set(item.group, groups.length);\n groups.push({ name: item.group, items: [item] });\n } else {\n groups[existing]!.items.push(item);\n }\n }\n return groups;\n}\n\n/**\n * A ⌘K-style command palette: an overlay dialog with a search input that\n * substring-filters items by label and keywords, groups results, and supports\n * full keyboard navigation (Arrow up/down, Enter, Escape). Traps focus while\n * open.\n */\nexport function Command({\n open,\n onOpenChange,\n items,\n placeholder = \"Type a command…\",\n emptyMessage = \"No results\",\n className,\n}: CommandProps) {\n const dialogRef = useRef<HTMLDivElement>(null);\n const [query, setQuery] = useState<string>(\"\");\n const [activeIndex, setActiveIndex] = useState<number>(0);\n const listId = \"tempest-command-list\";\n\n useFocusTrap(dialogRef, open);\n\n const filtered = useMemo<CommandItem[]>(() => {\n const normalized = query.trim().toLowerCase();\n const visible = items.filter((item) => matchesQuery(item, normalized));\n return groupItems(visible).flatMap((group) => group.items);\n }, [items, query]);\n\n const groups = useMemo<CommandGroup[]>(() => groupItems(filtered), [filtered]);\n\n // Reset transient state whenever the palette opens.\n useEffect(() => {\n if (open) {\n setQuery(\"\");\n setActiveIndex(0);\n }\n }, [open]);\n\n // Keep the active index within bounds as the filtered list shrinks/grows.\n useEffect(() => {\n setActiveIndex((index) => {\n if (filtered.length === 0) return 0;\n return Math.min(index, filtered.length - 1);\n });\n }, [filtered.length]);\n\n if (!open || typeof document === \"undefined\") return null;\n\n function selectItem(item: CommandItem): void {\n item.onSelect();\n onOpenChange(false);\n }\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {\n if (event.key === \"Escape\") {\n event.preventDefault();\n onOpenChange(false);\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n if (filtered.length === 0) return;\n setActiveIndex((index) => (index + 1) % filtered.length);\n return;\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n if (filtered.length === 0) return;\n setActiveIndex((index) => (index - 1 + filtered.length) % filtered.length);\n return;\n }\n if (event.key === \"Enter\") {\n event.preventDefault();\n const item = filtered[activeIndex];\n if (item) selectItem(item);\n }\n }\n\n let renderIndex = -1;\n\n return createPortal(\n <div className={styles.overlay} role=\"presentation\" onClick={() => onOpenChange(false)}>\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Command palette\"\n className={cn(styles.dialog, className)}\n onClick={(event) => event.stopPropagation()}\n >\n <div className={styles.inputRow}>\n <SearchIcon />\n <input\n type=\"text\"\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n autoFocus\n className={styles.input}\n placeholder={placeholder}\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onKeyDown={handleKeyDown}\n />\n </div>\n <ul id={listId} role=\"listbox\" className={styles.list}>\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n groups.map((group) => (\n <li key={group.name ?? \"__ungrouped__\"} className={styles.group}>\n {group.name && (\n <div className={styles.groupHeading}>{group.name}</div>\n )}\n <ul role=\"presentation\" className={styles.groupList}>\n {group.items.map((item) => {\n renderIndex += 1;\n const isActive = renderIndex === activeIndex;\n const index = renderIndex;\n return (\n <li\n key={item.id}\n role=\"option\"\n aria-selected={isActive}\n className={cn(\n styles.option,\n isActive && styles.active,\n )}\n onMouseMove={() => setActiveIndex(index)}\n onClick={() => selectItem(item)}\n >\n {item.icon && (\n <span className={styles.icon}>{item.icon}</span>\n )}\n <span className={styles.label}>{item.label}</span>\n </li>\n );\n })}\n </ul>\n </li>\n ))\n )}\n </ul>\n </div>\n </div>,\n document.body,\n );\n}\n\nfunction SearchIcon() {\n return (\n <svg\n className={styles.searchIcon}\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M20 20l-3.5-3.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Command.cjs","names":[],"sources":["../../../src/components/Command/Command.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, function-lines — a command palette is a filtered\n * listbox with its own keyboard contract: the body holds the query, the flattened\n * result list, the active index and the Escape/Enter handling, all of which read\n * each other on every keystroke.\n */\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/utils/cn\";\nimport { useFocusTrap } from \"@/hooks/use-focus-trap\";\nimport styles from \"./Command.module.css\";\n\nexport interface CommandItem {\n /** Stable unique identifier for the item. */\n id: string;\n /** Human-readable label shown in the list and matched against the query. */\n label: string;\n /** Optional group heading; items sharing a group are rendered together. */\n group?: string;\n /** Extra terms matched against the query in addition to `label`. */\n keywords?: string[];\n /** Invoked when the item is chosen (click or Enter on the active row). */\n onSelect: () => void;\n /** Optional leading icon. */\n icon?: ReactNode;\n}\n\nexport interface CommandProps {\n /** Whether the palette is visible. */\n open: boolean;\n /** Called with the next open state (Escape, selection, backdrop click). */\n onOpenChange: (open: boolean) => void;\n /** Candidate items to filter and display. */\n items: CommandItem[];\n /** Placeholder for the search input. */\n placeholder?: string;\n /** Rendered when no item matches the current query. */\n emptyMessage?: ReactNode;\n /** Forwarded to the dialog element. */\n className?: string;\n}\n\ninterface CommandGroup {\n name: string | undefined;\n items: CommandItem[];\n}\n\n/**\n * Case-insensitively test whether `item` matches `query` by substring against\n * its label and any keywords. An empty query matches everything.\n *\n * @param item - The candidate command item.\n * @param query - The lowercased search query.\n * @returns `true` when the item should be shown.\n */\nfunction matchesQuery(item: CommandItem, query: string): boolean {\n if (query === \"\") return true;\n if (item.label.toLowerCase().includes(query)) return true;\n return (item.keywords ?? []).some((keyword) => keyword.toLowerCase().includes(query));\n}\n\n/**\n * Partition a flat item list into ordered groups, preserving first-seen order\n * for both groups and the items within them.\n *\n * @param items - The (already filtered) items to group.\n * @returns An ordered list of groups.\n */\nfunction groupItems(items: CommandItem[]): CommandGroup[] {\n const groups: CommandGroup[] = [];\n const indexByName = new Map<string | undefined, number>();\n for (const item of items) {\n const existing = indexByName.get(item.group);\n if (existing === undefined) {\n indexByName.set(item.group, groups.length);\n groups.push({ name: item.group, items: [item] });\n } else {\n groups[existing]!.items.push(item);\n }\n }\n return groups;\n}\n\n/**\n * A ⌘K-style command palette: an overlay dialog with a search input that\n * substring-filters items by label and keywords, groups results, and supports\n * full keyboard navigation (Arrow up/down, Enter, Escape). Traps focus while\n * open.\n */\nexport function Command({\n open,\n onOpenChange,\n items,\n placeholder = \"Type a command…\",\n emptyMessage = \"No results\",\n className,\n}: CommandProps) {\n const dialogRef = useRef<HTMLDivElement>(null);\n const [query, setQuery] = useState<string>(\"\");\n const [activeIndex, setActiveIndex] = useState<number>(0);\n const listId = \"tempest-command-list\";\n\n useFocusTrap(dialogRef, open);\n\n const filtered = useMemo<CommandItem[]>(() => {\n const normalized = query.trim().toLowerCase();\n const visible = items.filter((item) => matchesQuery(item, normalized));\n return groupItems(visible).flatMap((group) => group.items);\n }, [items, query]);\n\n const groups = useMemo<CommandGroup[]>(() => groupItems(filtered), [filtered]);\n\n // Reset transient state whenever the palette opens.\n useEffect(() => {\n if (open) {\n setQuery(\"\");\n setActiveIndex(0);\n }\n }, [open]);\n\n // Keep the active index within bounds as the filtered list shrinks/grows.\n useEffect(() => {\n setActiveIndex((index) => {\n if (filtered.length === 0) return 0;\n return Math.min(index, filtered.length - 1);\n });\n }, [filtered.length]);\n\n if (!open || typeof document === \"undefined\") return null;\n\n function selectItem(item: CommandItem): void {\n item.onSelect();\n onOpenChange(false);\n }\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {\n if (event.key === \"Escape\") {\n event.preventDefault();\n onOpenChange(false);\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n if (filtered.length === 0) return;\n setActiveIndex((index) => (index + 1) % filtered.length);\n return;\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n if (filtered.length === 0) return;\n setActiveIndex((index) => (index - 1 + filtered.length) % filtered.length);\n return;\n }\n if (event.key === \"Enter\") {\n event.preventDefault();\n const item = filtered[activeIndex];\n if (item) selectItem(item);\n }\n }\n\n let renderIndex = -1;\n\n return createPortal(\n <div className={styles.overlay} role=\"presentation\" onClick={() => onOpenChange(false)}>\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Command palette\"\n className={cn(styles.dialog, className)}\n onClick={(event) => event.stopPropagation()}\n >\n <div className={styles.inputRow}>\n <SearchIcon />\n <input\n type=\"text\"\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n autoFocus\n className={styles.input}\n placeholder={placeholder}\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onKeyDown={handleKeyDown}\n />\n </div>\n <ul id={listId} role=\"listbox\" className={styles.list}>\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n groups.map((group) => (\n <li key={group.name ?? \"__ungrouped__\"} className={styles.group}>\n {group.name && (\n <div className={styles.groupHeading}>{group.name}</div>\n )}\n <ul role=\"presentation\" className={styles.groupList}>\n {group.items.map((item) => {\n renderIndex += 1;\n const isActive = renderIndex === activeIndex;\n const index = renderIndex;\n return (\n <li\n key={item.id}\n role=\"option\"\n aria-selected={isActive}\n className={cn(\n styles.option,\n isActive && styles.active,\n )}\n onMouseMove={() => setActiveIndex(index)}\n onClick={() => selectItem(item)}\n >\n {item.icon && (\n <span className={styles.icon}>{item.icon}</span>\n )}\n <span className={styles.label}>{item.label}</span>\n </li>\n );\n })}\n </ul>\n </li>\n ))\n )}\n </ul>\n </div>\n </div>,\n document.body,\n );\n}\n\nfunction SearchIcon() {\n return (\n <svg\n className={styles.searchIcon}\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M20 20l-3.5-3.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Command.js","names":[],"sources":["../../../src/components/Command/Command.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, function-lines — a command palette is a filtered\n * listbox with its own keyboard contract: the body holds the query, the flattened\n * result list, the active index and the Escape/Enter handling, all of which read\n * each other on every keystroke.\n */\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/utils/cn\";\nimport { useFocusTrap } from \"@/hooks/use-focus-trap\";\nimport styles from \"./Command.module.css\";\n\nexport interface CommandItem {\n /** Stable unique identifier for the item. */\n id: string;\n /** Human-readable label shown in the list and matched against the query. */\n label: string;\n /** Optional group heading; items sharing a group are rendered together. */\n group?: string;\n /** Extra terms matched against the query in addition to `label`. */\n keywords?: string[];\n /** Invoked when the item is chosen (click or Enter on the active row). */\n onSelect: () => void;\n /** Optional leading icon. */\n icon?: ReactNode;\n}\n\nexport interface CommandProps {\n /** Whether the palette is visible. */\n open: boolean;\n /** Called with the next open state (Escape, selection, backdrop click). */\n onOpenChange: (open: boolean) => void;\n /** Candidate items to filter and display. */\n items: CommandItem[];\n /** Placeholder for the search input. */\n placeholder?: string;\n /** Rendered when no item matches the current query. */\n emptyMessage?: ReactNode;\n /** Forwarded to the dialog element. */\n className?: string;\n}\n\ninterface CommandGroup {\n name: string | undefined;\n items: CommandItem[];\n}\n\n/**\n * Case-insensitively test whether `item` matches `query` by substring against\n * its label and any keywords. An empty query matches everything.\n *\n * @param item - The candidate command item.\n * @param query - The lowercased search query.\n * @returns `true` when the item should be shown.\n */\nfunction matchesQuery(item: CommandItem, query: string): boolean {\n if (query === \"\") return true;\n if (item.label.toLowerCase().includes(query)) return true;\n return (item.keywords ?? []).some((keyword) => keyword.toLowerCase().includes(query));\n}\n\n/**\n * Partition a flat item list into ordered groups, preserving first-seen order\n * for both groups and the items within them.\n *\n * @param items - The (already filtered) items to group.\n * @returns An ordered list of groups.\n */\nfunction groupItems(items: CommandItem[]): CommandGroup[] {\n const groups: CommandGroup[] = [];\n const indexByName = new Map<string | undefined, number>();\n for (const item of items) {\n const existing = indexByName.get(item.group);\n if (existing === undefined) {\n indexByName.set(item.group, groups.length);\n groups.push({ name: item.group, items: [item] });\n } else {\n groups[existing]!.items.push(item);\n }\n }\n return groups;\n}\n\n/**\n * A ⌘K-style command palette: an overlay dialog with a search input that\n * substring-filters items by label and keywords, groups results, and supports\n * full keyboard navigation (Arrow up/down, Enter, Escape). Traps focus while\n * open.\n */\nexport function Command({\n open,\n onOpenChange,\n items,\n placeholder = \"Type a command…\",\n emptyMessage = \"No results\",\n className,\n}: CommandProps) {\n const dialogRef = useRef<HTMLDivElement>(null);\n const [query, setQuery] = useState<string>(\"\");\n const [activeIndex, setActiveIndex] = useState<number>(0);\n const listId = \"tempest-command-list\";\n\n useFocusTrap(dialogRef, open);\n\n const filtered = useMemo<CommandItem[]>(() => {\n const normalized = query.trim().toLowerCase();\n const visible = items.filter((item) => matchesQuery(item, normalized));\n return groupItems(visible).flatMap((group) => group.items);\n }, [items, query]);\n\n const groups = useMemo<CommandGroup[]>(() => groupItems(filtered), [filtered]);\n\n // Reset transient state whenever the palette opens.\n useEffect(() => {\n if (open) {\n setQuery(\"\");\n setActiveIndex(0);\n }\n }, [open]);\n\n // Keep the active index within bounds as the filtered list shrinks/grows.\n useEffect(() => {\n setActiveIndex((index) => {\n if (filtered.length === 0) return 0;\n return Math.min(index, filtered.length - 1);\n });\n }, [filtered.length]);\n\n if (!open || typeof document === \"undefined\") return null;\n\n function selectItem(item: CommandItem): void {\n item.onSelect();\n onOpenChange(false);\n }\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {\n if (event.key === \"Escape\") {\n event.preventDefault();\n onOpenChange(false);\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n if (filtered.length === 0) return;\n setActiveIndex((index) => (index + 1) % filtered.length);\n return;\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n if (filtered.length === 0) return;\n setActiveIndex((index) => (index - 1 + filtered.length) % filtered.length);\n return;\n }\n if (event.key === \"Enter\") {\n event.preventDefault();\n const item = filtered[activeIndex];\n if (item) selectItem(item);\n }\n }\n\n let renderIndex = -1;\n\n return createPortal(\n <div className={styles.overlay} role=\"presentation\" onClick={() => onOpenChange(false)}>\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Command palette\"\n className={cn(styles.dialog, className)}\n onClick={(event) => event.stopPropagation()}\n >\n <div className={styles.inputRow}>\n <SearchIcon />\n <input\n type=\"text\"\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n autoFocus\n className={styles.input}\n placeholder={placeholder}\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onKeyDown={handleKeyDown}\n />\n </div>\n <ul id={listId} role=\"listbox\" className={styles.list}>\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n groups.map((group) => (\n <li key={group.name ?? \"__ungrouped__\"} className={styles.group}>\n {group.name && (\n <div className={styles.groupHeading}>{group.name}</div>\n )}\n <ul role=\"presentation\" className={styles.groupList}>\n {group.items.map((item) => {\n renderIndex += 1;\n const isActive = renderIndex === activeIndex;\n const index = renderIndex;\n return (\n <li\n key={item.id}\n role=\"option\"\n aria-selected={isActive}\n className={cn(\n styles.option,\n isActive && styles.active,\n )}\n onMouseMove={() => setActiveIndex(index)}\n onClick={() => selectItem(item)}\n >\n {item.icon && (\n <span className={styles.icon}>{item.icon}</span>\n )}\n <span className={styles.label}>{item.label}</span>\n </li>\n );\n })}\n </ul>\n </li>\n ))\n )}\n </ul>\n </div>\n </div>,\n document.body,\n );\n}\n\nfunction SearchIcon() {\n return (\n <svg\n className={styles.searchIcon}\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M20 20l-3.5-3.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Command.js","names":[],"sources":["../../../src/components/Command/Command.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, function-lines — a command palette is a filtered\n * listbox with its own keyboard contract: the body holds the query, the flattened\n * result list, the active index and the Escape/Enter handling, all of which read\n * each other on every keystroke.\n */\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/utils/cn\";\nimport { useFocusTrap } from \"@/hooks/use-focus-trap\";\nimport styles from \"./Command.module.css\";\n\nexport interface CommandItem {\n /** Stable unique identifier for the item. */\n id: string;\n /** Human-readable label shown in the list and matched against the query. */\n label: string;\n /** Optional group heading; items sharing a group are rendered together. */\n group?: string;\n /** Extra terms matched against the query in addition to `label`. */\n keywords?: string[];\n /** Invoked when the item is chosen (click or Enter on the active row). */\n onSelect: () => void;\n /** Optional leading icon. */\n icon?: ReactNode;\n}\n\nexport interface CommandProps {\n /** Whether the palette is visible. */\n open: boolean;\n /** Called with the next open state (Escape, selection, backdrop click). */\n onOpenChange: (open: boolean) => void;\n /** Candidate items to filter and display. */\n items: CommandItem[];\n /** Placeholder for the search input. */\n placeholder?: string;\n /** Rendered when no item matches the current query. */\n emptyMessage?: ReactNode;\n /** Forwarded to the dialog element. */\n className?: string;\n}\n\ninterface CommandGroup {\n name: string | undefined;\n items: CommandItem[];\n}\n\n/**\n * Case-insensitively test whether `item` matches `query` by substring against\n * its label and any keywords. An empty query matches everything.\n *\n * @param item - The candidate command item.\n * @param query - The lowercased search query.\n * @returns `true` when the item should be shown.\n */\nfunction matchesQuery(item: CommandItem, query: string): boolean {\n if (query === \"\") return true;\n if (item.label.toLowerCase().includes(query)) return true;\n return (item.keywords ?? []).some((keyword) => keyword.toLowerCase().includes(query));\n}\n\n/**\n * Partition a flat item list into ordered groups, preserving first-seen order\n * for both groups and the items within them.\n *\n * @param items - The (already filtered) items to group.\n * @returns An ordered list of groups.\n */\nfunction groupItems(items: CommandItem[]): CommandGroup[] {\n const groups: CommandGroup[] = [];\n const indexByName = new Map<string | undefined, number>();\n for (const item of items) {\n const existing = indexByName.get(item.group);\n if (existing === undefined) {\n indexByName.set(item.group, groups.length);\n groups.push({ name: item.group, items: [item] });\n } else {\n groups[existing]!.items.push(item);\n }\n }\n return groups;\n}\n\n/**\n * A ⌘K-style command palette: an overlay dialog with a search input that\n * substring-filters items by label and keywords, groups results, and supports\n * full keyboard navigation (Arrow up/down, Enter, Escape). Traps focus while\n * open.\n */\nexport function Command({\n open,\n onOpenChange,\n items,\n placeholder = \"Type a command…\",\n emptyMessage = \"No results\",\n className,\n}: CommandProps) {\n const dialogRef = useRef<HTMLDivElement>(null);\n const [query, setQuery] = useState<string>(\"\");\n const [activeIndex, setActiveIndex] = useState<number>(0);\n const listId = \"tempest-command-list\";\n\n useFocusTrap(dialogRef, open);\n\n const filtered = useMemo<CommandItem[]>(() => {\n const normalized = query.trim().toLowerCase();\n const visible = items.filter((item) => matchesQuery(item, normalized));\n return groupItems(visible).flatMap((group) => group.items);\n }, [items, query]);\n\n const groups = useMemo<CommandGroup[]>(() => groupItems(filtered), [filtered]);\n\n // Reset transient state whenever the palette opens.\n useEffect(() => {\n if (open) {\n setQuery(\"\");\n setActiveIndex(0);\n }\n }, [open]);\n\n // Keep the active index within bounds as the filtered list shrinks/grows.\n useEffect(() => {\n setActiveIndex((index) => {\n if (filtered.length === 0) return 0;\n return Math.min(index, filtered.length - 1);\n });\n }, [filtered.length]);\n\n if (!open || typeof document === \"undefined\") return null;\n\n function selectItem(item: CommandItem): void {\n item.onSelect();\n onOpenChange(false);\n }\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {\n if (event.key === \"Escape\") {\n event.preventDefault();\n onOpenChange(false);\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n if (filtered.length === 0) return;\n setActiveIndex((index) => (index + 1) % filtered.length);\n return;\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n if (filtered.length === 0) return;\n setActiveIndex((index) => (index - 1 + filtered.length) % filtered.length);\n return;\n }\n if (event.key === \"Enter\") {\n event.preventDefault();\n const item = filtered[activeIndex];\n if (item) selectItem(item);\n }\n }\n\n let renderIndex = -1;\n\n return createPortal(\n <div className={styles.overlay} role=\"presentation\" onClick={() => onOpenChange(false)}>\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Command palette\"\n className={cn(styles.dialog, className)}\n onClick={(event) => event.stopPropagation()}\n >\n <div className={styles.inputRow}>\n <SearchIcon />\n <input\n type=\"text\"\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n autoFocus\n className={styles.input}\n placeholder={placeholder}\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onKeyDown={handleKeyDown}\n />\n </div>\n <ul id={listId} role=\"listbox\" className={styles.list}>\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n groups.map((group) => (\n <li key={group.name ?? \"__ungrouped__\"} className={styles.group}>\n {group.name && (\n <div className={styles.groupHeading}>{group.name}</div>\n )}\n <ul role=\"presentation\" className={styles.groupList}>\n {group.items.map((item) => {\n renderIndex += 1;\n const isActive = renderIndex === activeIndex;\n const index = renderIndex;\n return (\n <li\n key={item.id}\n role=\"option\"\n aria-selected={isActive}\n className={cn(\n styles.option,\n isActive && styles.active,\n )}\n onMouseMove={() => setActiveIndex(index)}\n onClick={() => selectItem(item)}\n >\n {item.icon && (\n <span className={styles.icon}>{item.icon}</span>\n )}\n <span className={styles.label}>{item.label}</span>\n </li>\n );\n })}\n </ul>\n </li>\n ))\n )}\n </ul>\n </div>\n </div>,\n document.body,\n );\n}\n\nfunction SearchIcon() {\n return (\n <svg\n className={styles.searchIcon}\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M20 20l-3.5-3.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmDialog.cjs","names":[],"sources":["../../../src/components/ConfirmDialog/ConfirmDialog.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a confirmation is a question (title, description),\n * two buttons whose copy the app must own (confirmLabel, cancelLabel), a\n * destructive-or-not tone (variant), and the async state of the answer (loading,\n * onConfirm, onCancel, open). Fewer props means the app writes the dialog again\n * around a Modal.\n */\nimport type { ReactNode } from \"react\";\nimport { Button } from \"@/components/Button\";\nimport { Modal } from \"@/components/Modal\";\n\nexport interface ConfirmDialogProps {\n open: boolean;\n title: ReactNode;\n description?: ReactNode;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: \"primary\" | \"danger\";\n loading?: boolean;\n onConfirm: () => void | Promise<void>;\n onCancel: () => void;\n}\n\n/**\n * Quick confirmation prompt built on top of {@link Modal}. Use for destructive\n * actions with `variant=\"danger\"`.\n */\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = \"Confirmar\",\n cancelLabel = \"Cancelar\",\n variant = \"primary\",\n loading = false,\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n return (\n <Modal\n open={open}\n onClose={onCancel}\n title={title}\n size=\"sm\"\n footer={\n <>\n <Button variant=\"secondary\" onClick={onCancel} disabled={loading}>\n {cancelLabel}\n </Button>\n <Button variant={variant} loading={loading} onClick={() => void onConfirm()}>\n {confirmLabel}\n </Button>\n </>\n }\n >\n {description}\n </Modal>\n );\n}\n"],"mappings":"2GA2BA,SAAgB,EAAc,CAC1B,OACA,QACA,cACA,eAAe,YACf,cAAc,WACd,UAAU,UACV,UAAU,GACV,YACA,YACmB,CACnB,OACI,EAAA,EAAA,IAAA,CAAC,EAAA,MAAD,CACU,OACN,QAAS,EACF,QACP,KAAK,KACL,QACI,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CAAQ,QAAQ,YAAY,QAAS,EAAU,SAAU,WACpD,CACG,CAAA,GACR,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CAAiB,UAAkB,UAAS,YAAe,KAAK,EAAU,WACrE,CACG,CAAA,CACV,CAAA,CAAA,WAGL,CACE,CAAA,CAEf"}
1
+ {"version":3,"file":"ConfirmDialog.cjs","names":[],"sources":["../../../src/components/ConfirmDialog/ConfirmDialog.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a confirmation is a question (title, description),\n * two buttons whose copy the app must own (confirmLabel, cancelLabel), a\n * destructive-or-not tone (variant), and the async state of the answer (loading,\n * onConfirm, onCancel, open). Fewer props means the app writes the dialog again\n * around a Modal.\n */\nimport type { ReactNode } from \"react\";\nimport { Button } from \"@/components/Button\";\nimport { Modal } from \"@/components/Modal\";\n\nexport interface ConfirmDialogProps {\n open: boolean;\n title: ReactNode;\n description?: ReactNode;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: \"primary\" | \"danger\";\n loading?: boolean;\n onConfirm: () => void | Promise<void>;\n onCancel: () => void;\n}\n\n/**\n * Quick confirmation prompt built on top of {@link Modal}. Use for destructive\n * actions with `variant=\"danger\"`.\n */\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = \"Confirmar\",\n cancelLabel = \"Cancelar\",\n variant = \"primary\",\n loading = false,\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n return (\n <Modal\n open={open}\n onClose={onCancel}\n title={title}\n size=\"sm\"\n footer={\n <>\n <Button variant=\"secondary\" onClick={onCancel} disabled={loading}>\n {cancelLabel}\n </Button>\n <Button variant={variant} loading={loading} onClick={() => void onConfirm()}>\n {confirmLabel}\n </Button>\n </>\n }\n >\n {description}\n </Modal>\n );\n}\n"],"mappings":"2GA2BA,SAAgB,EAAc,CAC1B,OACA,QACA,cACA,eAAe,YACf,cAAc,WACd,UAAU,UACV,UAAU,GACV,YACA,YACmB,CACnB,OACI,EAAA,EAAA,IAAA,CAAC,EAAA,MAAD,CACU,OACN,QAAS,EACF,QACP,KAAK,KACL,QACI,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CAAQ,QAAQ,YAAY,QAAS,EAAU,SAAU,EACpD,SAAA,CACG,CAAA,GACR,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CAAiB,UAAkB,UAAS,YAAe,KAAK,EAAU,EACrE,SAAA,CACG,CAAA,CACV,CAAA,CAAA,EAGL,SAAA,CACE,CAAA,CAEf"}
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmDialog.js","names":[],"sources":["../../../src/components/ConfirmDialog/ConfirmDialog.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a confirmation is a question (title, description),\n * two buttons whose copy the app must own (confirmLabel, cancelLabel), a\n * destructive-or-not tone (variant), and the async state of the answer (loading,\n * onConfirm, onCancel, open). Fewer props means the app writes the dialog again\n * around a Modal.\n */\nimport type { ReactNode } from \"react\";\nimport { Button } from \"@/components/Button\";\nimport { Modal } from \"@/components/Modal\";\n\nexport interface ConfirmDialogProps {\n open: boolean;\n title: ReactNode;\n description?: ReactNode;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: \"primary\" | \"danger\";\n loading?: boolean;\n onConfirm: () => void | Promise<void>;\n onCancel: () => void;\n}\n\n/**\n * Quick confirmation prompt built on top of {@link Modal}. Use for destructive\n * actions with `variant=\"danger\"`.\n */\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = \"Confirmar\",\n cancelLabel = \"Cancelar\",\n variant = \"primary\",\n loading = false,\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n return (\n <Modal\n open={open}\n onClose={onCancel}\n title={title}\n size=\"sm\"\n footer={\n <>\n <Button variant=\"secondary\" onClick={onCancel} disabled={loading}>\n {cancelLabel}\n </Button>\n <Button variant={variant} loading={loading} onClick={() => void onConfirm()}>\n {confirmLabel}\n </Button>\n </>\n }\n >\n {description}\n </Modal>\n );\n}\n"],"mappings":";;;;AA2BA,SAAgB,EAAc,EAC1B,SACA,UACA,gBACA,kBAAe,aACf,iBAAc,YACd,aAAU,WACV,aAAU,IACV,cACA,eACmB;CACnB,OACI,kBAAC,GAAD;EACU;EACN,SAAS;EACF;EACP,MAAK;EACL,QACI,kBAAA,GAAA,EAAA,UAAA,CACI,kBAAC,GAAD;GAAQ,SAAQ;GAAY,SAAS;GAAU,UAAU;aACpD;EACG,CAAA,GACR,kBAAC,GAAD;GAAiB;GAAkB;GAAS,eAAe,KAAK,EAAU;aACrE;EACG,CAAA,CACV,EAAA,CAAA;YAGL;CACE,CAAA;AAEf"}
1
+ {"version":3,"file":"ConfirmDialog.js","names":[],"sources":["../../../src/components/ConfirmDialog/ConfirmDialog.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a confirmation is a question (title, description),\n * two buttons whose copy the app must own (confirmLabel, cancelLabel), a\n * destructive-or-not tone (variant), and the async state of the answer (loading,\n * onConfirm, onCancel, open). Fewer props means the app writes the dialog again\n * around a Modal.\n */\nimport type { ReactNode } from \"react\";\nimport { Button } from \"@/components/Button\";\nimport { Modal } from \"@/components/Modal\";\n\nexport interface ConfirmDialogProps {\n open: boolean;\n title: ReactNode;\n description?: ReactNode;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: \"primary\" | \"danger\";\n loading?: boolean;\n onConfirm: () => void | Promise<void>;\n onCancel: () => void;\n}\n\n/**\n * Quick confirmation prompt built on top of {@link Modal}. Use for destructive\n * actions with `variant=\"danger\"`.\n */\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = \"Confirmar\",\n cancelLabel = \"Cancelar\",\n variant = \"primary\",\n loading = false,\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n return (\n <Modal\n open={open}\n onClose={onCancel}\n title={title}\n size=\"sm\"\n footer={\n <>\n <Button variant=\"secondary\" onClick={onCancel} disabled={loading}>\n {cancelLabel}\n </Button>\n <Button variant={variant} loading={loading} onClick={() => void onConfirm()}>\n {confirmLabel}\n </Button>\n </>\n }\n >\n {description}\n </Modal>\n );\n}\n"],"mappings":";;;;AA2BA,SAAgB,EAAc,EAC1B,SACA,UACA,gBACA,kBAAe,aACf,iBAAc,YACd,aAAU,WACV,aAAU,IACV,cACA,eACmB;CACnB,OACI,kBAAC,GAAD;EACU;EACN,SAAS;EACF;EACP,MAAK;EACL,QACI,kBAAA,GAAA,EAAA,UAAA,CACI,kBAAC,GAAD;GAAQ,SAAQ;GAAY,SAAS;GAAU,UAAU;GACpD,UAAA;EACG,CAAA,GACR,kBAAC,GAAD;GAAiB;GAAkB;GAAS,eAAe,KAAK,EAAU;GACrE,UAAA;EACG,CAAA,CACV,EAAA,CAAA;EAGL,UAAA;CACE,CAAA;AAEf"}
@@ -1 +1 @@
1
- {"version":3,"file":"ContextMenu.cjs","names":[],"sources":["../../../src/components/ContextMenu/ContextMenu.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body positions the menu against the pointer,\n * flips it inside the viewport, and owns roving focus for the keyboard path — one\n * geometry computed from one anchor point.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { Portal } from \"@/components/Portal\";\nimport styles from \"./ContextMenu.module.css\";\n\nexport type ContextMenuItem =\n | {\n label: ReactNode;\n onSelect?: () => void;\n disabled?: boolean;\n danger?: boolean;\n }\n | { separator: true };\n\nexport interface ContextMenuProps {\n /** Menu entries — selectable items and separators. */\n items: ContextMenuItem[];\n /** Trigger area. Right-clicking anywhere within opens the menu at the cursor. */\n children: ReactNode;\n /** Extra class names forwarded to the menu element. */\n className?: string;\n}\n\ninterface Position {\n x: number;\n y: number;\n}\n\nfunction isSeparator(item: ContextMenuItem): item is { separator: true } {\n return \"separator\" in item && item.separator === true;\n}\n\n/**\n * Right-click context menu.\n *\n * - Opens at the cursor position on `onContextMenu` (default browser menu suppressed).\n * - Rendered through a {@link Portal} so it escapes parent overflow/stacking contexts.\n * - Closes on outside click, Escape, or item selection.\n * - Arrow Up/Down move focus across selectable items; Enter activates the focused item.\n *\n * @param props - The context menu props.\n * @returns The trigger wrapper plus the portalled menu when open.\n */\nexport function ContextMenu({ items, children, className }: ContextMenuProps) {\n const [open, setOpen] = useState(false);\n const [position, setPosition] = useState<Position>({ x: 0, y: 0 });\n const [activeIndex, setActiveIndex] = useState<number>(-1);\n const id = useId();\n const menuRef = useRef<HTMLUListElement>(null);\n const itemRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n const selectableIndexes = items\n .map((item, index) => (!isSeparator(item) && !item.disabled ? index : -1))\n .filter((i) => i !== -1);\n\n const close = useCallback((): void => {\n setOpen(false);\n setActiveIndex(-1);\n }, []);\n\n const handleContextMenu = (event: React.MouseEvent): void => {\n event.preventDefault();\n setPosition({ x: event.clientX, y: event.clientY });\n setActiveIndex(-1);\n setOpen(true);\n };\n\n useEffect(() => {\n if (!open) return;\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") {\n close();\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const next = selectableIndexes[(current + 1) % selectableIndexes.length] ?? -1;\n setActiveIndex(next);\n itemRefs.current[next]?.focus();\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const prev =\n selectableIndexes[\n (current - 1 + selectableIndexes.length) % selectableIndexes.length\n ] ?? -1;\n setActiveIndex(prev);\n itemRefs.current[prev]?.focus();\n }\n };\n const onDown = (event: MouseEvent): void => {\n if (menuRef.current && !menuRef.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 }, [open, activeIndex, selectableIndexes, close]);\n\n const handleSelect = (item: Extract<ContextMenuItem, { label: ReactNode }>): void => {\n item.onSelect?.();\n close();\n };\n\n return (\n <>\n <span className={styles.root} onContextMenu={handleContextMenu}>\n {children}\n </span>\n {open && (\n <Portal>\n <ul\n ref={menuRef}\n id={id}\n role=\"menu\"\n className={cn(styles.menu, className)}\n style={{ top: position.y, left: position.x }}\n >\n {items.map((item, index) => {\n if (isSeparator(item)) {\n return (\n <li\n key={`separator-${index}`}\n role=\"separator\"\n className={styles.separator}\n aria-hidden\n />\n );\n }\n return (\n <li key={`item-${index}`} role=\"none\">\n <button\n ref={(el) => {\n itemRefs.current[index] = el;\n }}\n type=\"button\"\n role=\"menuitem\"\n className={cn(\n styles.item,\n item.danger && styles.danger,\n activeIndex === index && styles.active,\n )}\n disabled={item.disabled}\n onClick={() => handleSelect(item)}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {item.label}\n </button>\n </li>\n );\n })}\n </ul>\n </Portal>\n )}\n </>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ContextMenu.cjs","names":[],"sources":["../../../src/components/ContextMenu/ContextMenu.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body positions the menu against the pointer,\n * flips it inside the viewport, and owns roving focus for the keyboard path — one\n * geometry computed from one anchor point.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { Portal } from \"@/components/Portal\";\nimport styles from \"./ContextMenu.module.css\";\n\nexport type ContextMenuItem =\n | {\n label: ReactNode;\n onSelect?: () => void;\n disabled?: boolean;\n danger?: boolean;\n }\n | { separator: true };\n\nexport interface ContextMenuProps {\n /** Menu entries — selectable items and separators. */\n items: ContextMenuItem[];\n /** Trigger area. Right-clicking anywhere within opens the menu at the cursor. */\n children: ReactNode;\n /** Extra class names forwarded to the menu element. */\n className?: string;\n}\n\ninterface Position {\n x: number;\n y: number;\n}\n\nfunction isSeparator(item: ContextMenuItem): item is { separator: true } {\n return \"separator\" in item && item.separator === true;\n}\n\n/**\n * Right-click context menu.\n *\n * - Opens at the cursor position on `onContextMenu` (default browser menu suppressed).\n * - Rendered through a {@link Portal} so it escapes parent overflow/stacking contexts.\n * - Closes on outside click, Escape, or item selection.\n * - Arrow Up/Down move focus across selectable items; Enter activates the focused item.\n *\n * @param props - The context menu props.\n * @returns The trigger wrapper plus the portalled menu when open.\n */\nexport function ContextMenu({ items, children, className }: ContextMenuProps) {\n const [open, setOpen] = useState(false);\n const [position, setPosition] = useState<Position>({ x: 0, y: 0 });\n const [activeIndex, setActiveIndex] = useState<number>(-1);\n const id = useId();\n const menuRef = useRef<HTMLUListElement>(null);\n const itemRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n const selectableIndexes = items\n .map((item, index) => (!isSeparator(item) && !item.disabled ? index : -1))\n .filter((i) => i !== -1);\n\n const close = useCallback((): void => {\n setOpen(false);\n setActiveIndex(-1);\n }, []);\n\n const handleContextMenu = (event: React.MouseEvent): void => {\n event.preventDefault();\n setPosition({ x: event.clientX, y: event.clientY });\n setActiveIndex(-1);\n setOpen(true);\n };\n\n useEffect(() => {\n if (!open) return;\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") {\n close();\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const next = selectableIndexes[(current + 1) % selectableIndexes.length] ?? -1;\n setActiveIndex(next);\n itemRefs.current[next]?.focus();\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const prev =\n selectableIndexes[\n (current - 1 + selectableIndexes.length) % selectableIndexes.length\n ] ?? -1;\n setActiveIndex(prev);\n itemRefs.current[prev]?.focus();\n }\n };\n const onDown = (event: MouseEvent): void => {\n if (menuRef.current && !menuRef.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 }, [open, activeIndex, selectableIndexes, close]);\n\n const handleSelect = (item: Extract<ContextMenuItem, { label: ReactNode }>): void => {\n item.onSelect?.();\n close();\n };\n\n return (\n <>\n <span className={styles.root} onContextMenu={handleContextMenu}>\n {children}\n </span>\n {open && (\n <Portal>\n <ul\n ref={menuRef}\n id={id}\n role=\"menu\"\n className={cn(styles.menu, className)}\n style={{ top: position.y, left: position.x }}\n >\n {items.map((item, index) => {\n if (isSeparator(item)) {\n return (\n <li\n key={`separator-${index}`}\n role=\"separator\"\n className={styles.separator}\n aria-hidden\n />\n );\n }\n return (\n <li key={`item-${index}`} role=\"none\">\n <button\n ref={(el) => {\n itemRefs.current[index] = el;\n }}\n type=\"button\"\n role=\"menuitem\"\n className={cn(\n styles.item,\n item.danger && styles.danger,\n activeIndex === index && styles.active,\n )}\n disabled={item.disabled}\n onClick={() => handleSelect(item)}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {item.label}\n </button>\n </li>\n );\n })}\n </ul>\n </Portal>\n )}\n </>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ContextMenu.js","names":[],"sources":["../../../src/components/ContextMenu/ContextMenu.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body positions the menu against the pointer,\n * flips it inside the viewport, and owns roving focus for the keyboard path — one\n * geometry computed from one anchor point.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { Portal } from \"@/components/Portal\";\nimport styles from \"./ContextMenu.module.css\";\n\nexport type ContextMenuItem =\n | {\n label: ReactNode;\n onSelect?: () => void;\n disabled?: boolean;\n danger?: boolean;\n }\n | { separator: true };\n\nexport interface ContextMenuProps {\n /** Menu entries — selectable items and separators. */\n items: ContextMenuItem[];\n /** Trigger area. Right-clicking anywhere within opens the menu at the cursor. */\n children: ReactNode;\n /** Extra class names forwarded to the menu element. */\n className?: string;\n}\n\ninterface Position {\n x: number;\n y: number;\n}\n\nfunction isSeparator(item: ContextMenuItem): item is { separator: true } {\n return \"separator\" in item && item.separator === true;\n}\n\n/**\n * Right-click context menu.\n *\n * - Opens at the cursor position on `onContextMenu` (default browser menu suppressed).\n * - Rendered through a {@link Portal} so it escapes parent overflow/stacking contexts.\n * - Closes on outside click, Escape, or item selection.\n * - Arrow Up/Down move focus across selectable items; Enter activates the focused item.\n *\n * @param props - The context menu props.\n * @returns The trigger wrapper plus the portalled menu when open.\n */\nexport function ContextMenu({ items, children, className }: ContextMenuProps) {\n const [open, setOpen] = useState(false);\n const [position, setPosition] = useState<Position>({ x: 0, y: 0 });\n const [activeIndex, setActiveIndex] = useState<number>(-1);\n const id = useId();\n const menuRef = useRef<HTMLUListElement>(null);\n const itemRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n const selectableIndexes = items\n .map((item, index) => (!isSeparator(item) && !item.disabled ? index : -1))\n .filter((i) => i !== -1);\n\n const close = useCallback((): void => {\n setOpen(false);\n setActiveIndex(-1);\n }, []);\n\n const handleContextMenu = (event: React.MouseEvent): void => {\n event.preventDefault();\n setPosition({ x: event.clientX, y: event.clientY });\n setActiveIndex(-1);\n setOpen(true);\n };\n\n useEffect(() => {\n if (!open) return;\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") {\n close();\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const next = selectableIndexes[(current + 1) % selectableIndexes.length] ?? -1;\n setActiveIndex(next);\n itemRefs.current[next]?.focus();\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const prev =\n selectableIndexes[\n (current - 1 + selectableIndexes.length) % selectableIndexes.length\n ] ?? -1;\n setActiveIndex(prev);\n itemRefs.current[prev]?.focus();\n }\n };\n const onDown = (event: MouseEvent): void => {\n if (menuRef.current && !menuRef.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 }, [open, activeIndex, selectableIndexes, close]);\n\n const handleSelect = (item: Extract<ContextMenuItem, { label: ReactNode }>): void => {\n item.onSelect?.();\n close();\n };\n\n return (\n <>\n <span className={styles.root} onContextMenu={handleContextMenu}>\n {children}\n </span>\n {open && (\n <Portal>\n <ul\n ref={menuRef}\n id={id}\n role=\"menu\"\n className={cn(styles.menu, className)}\n style={{ top: position.y, left: position.x }}\n >\n {items.map((item, index) => {\n if (isSeparator(item)) {\n return (\n <li\n key={`separator-${index}`}\n role=\"separator\"\n className={styles.separator}\n aria-hidden\n />\n );\n }\n return (\n <li key={`item-${index}`} role=\"none\">\n <button\n ref={(el) => {\n itemRefs.current[index] = el;\n }}\n type=\"button\"\n role=\"menuitem\"\n className={cn(\n styles.item,\n item.danger && styles.danger,\n activeIndex === index && styles.active,\n )}\n disabled={item.disabled}\n onClick={() => handleSelect(item)}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {item.label}\n </button>\n </li>\n );\n })}\n </ul>\n </Portal>\n )}\n </>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ContextMenu.js","names":[],"sources":["../../../src/components/ContextMenu/ContextMenu.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body positions the menu against the pointer,\n * flips it inside the viewport, and owns roving focus for the keyboard path — one\n * geometry computed from one anchor point.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { Portal } from \"@/components/Portal\";\nimport styles from \"./ContextMenu.module.css\";\n\nexport type ContextMenuItem =\n | {\n label: ReactNode;\n onSelect?: () => void;\n disabled?: boolean;\n danger?: boolean;\n }\n | { separator: true };\n\nexport interface ContextMenuProps {\n /** Menu entries — selectable items and separators. */\n items: ContextMenuItem[];\n /** Trigger area. Right-clicking anywhere within opens the menu at the cursor. */\n children: ReactNode;\n /** Extra class names forwarded to the menu element. */\n className?: string;\n}\n\ninterface Position {\n x: number;\n y: number;\n}\n\nfunction isSeparator(item: ContextMenuItem): item is { separator: true } {\n return \"separator\" in item && item.separator === true;\n}\n\n/**\n * Right-click context menu.\n *\n * - Opens at the cursor position on `onContextMenu` (default browser menu suppressed).\n * - Rendered through a {@link Portal} so it escapes parent overflow/stacking contexts.\n * - Closes on outside click, Escape, or item selection.\n * - Arrow Up/Down move focus across selectable items; Enter activates the focused item.\n *\n * @param props - The context menu props.\n * @returns The trigger wrapper plus the portalled menu when open.\n */\nexport function ContextMenu({ items, children, className }: ContextMenuProps) {\n const [open, setOpen] = useState(false);\n const [position, setPosition] = useState<Position>({ x: 0, y: 0 });\n const [activeIndex, setActiveIndex] = useState<number>(-1);\n const id = useId();\n const menuRef = useRef<HTMLUListElement>(null);\n const itemRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n const selectableIndexes = items\n .map((item, index) => (!isSeparator(item) && !item.disabled ? index : -1))\n .filter((i) => i !== -1);\n\n const close = useCallback((): void => {\n setOpen(false);\n setActiveIndex(-1);\n }, []);\n\n const handleContextMenu = (event: React.MouseEvent): void => {\n event.preventDefault();\n setPosition({ x: event.clientX, y: event.clientY });\n setActiveIndex(-1);\n setOpen(true);\n };\n\n useEffect(() => {\n if (!open) return;\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") {\n close();\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const next = selectableIndexes[(current + 1) % selectableIndexes.length] ?? -1;\n setActiveIndex(next);\n itemRefs.current[next]?.focus();\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const prev =\n selectableIndexes[\n (current - 1 + selectableIndexes.length) % selectableIndexes.length\n ] ?? -1;\n setActiveIndex(prev);\n itemRefs.current[prev]?.focus();\n }\n };\n const onDown = (event: MouseEvent): void => {\n if (menuRef.current && !menuRef.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 }, [open, activeIndex, selectableIndexes, close]);\n\n const handleSelect = (item: Extract<ContextMenuItem, { label: ReactNode }>): void => {\n item.onSelect?.();\n close();\n };\n\n return (\n <>\n <span className={styles.root} onContextMenu={handleContextMenu}>\n {children}\n </span>\n {open && (\n <Portal>\n <ul\n ref={menuRef}\n id={id}\n role=\"menu\"\n className={cn(styles.menu, className)}\n style={{ top: position.y, left: position.x }}\n >\n {items.map((item, index) => {\n if (isSeparator(item)) {\n return (\n <li\n key={`separator-${index}`}\n role=\"separator\"\n className={styles.separator}\n aria-hidden\n />\n );\n }\n return (\n <li key={`item-${index}`} role=\"none\">\n <button\n ref={(el) => {\n itemRefs.current[index] = el;\n }}\n type=\"button\"\n role=\"menuitem\"\n className={cn(\n styles.item,\n item.danger && styles.danger,\n activeIndex === index && styles.active,\n )}\n disabled={item.disabled}\n onClick={() => handleSelect(item)}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {item.label}\n </button>\n </li>\n );\n })}\n </ul>\n </Portal>\n )}\n </>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CopyButton.cjs","names":[],"sources":["../../../src/components/CopyButton/CopyButton.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./CopyButton.module.css\";\n\nexport interface CopyButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Text written to the clipboard when the button is clicked. */\n value: string;\n /** How long (ms) the \"copied\" state stays active before resetting. Defaults to 2000. */\n timeout?: number;\n /** Optional label. Falls back to \"Copy\" / \"Copied\" based on state. */\n children?: ReactNode;\n /** Called after a successful clipboard write. */\n onCopied?: () => void;\n}\n\n/**\n * Button that copies a string to the clipboard and shows a transient \"copied\"\n * state for `timeout` milliseconds.\n *\n * When `children` are provided they are rendered in both states; otherwise the\n * label toggles between \"Copy\" and \"Copied\". The reset timer is cleared on\n * unmount to avoid setting state on an unmounted component.\n *\n * @tempest-limits empty-catch — `navigator.clipboard.writeText` rejects when the\n * page is not a secure context, when the document is not focused, or when the user\n * denied the permission. None of those are recoverable here and none deserve an\n * error surface: the button simply never enters the \"copied\" state, which is the\n * feedback the user needs.\n *\n * @example\n * <CopyButton value=\"npm i tempest-react-sdk\" />\n */\nexport function CopyButton({\n value,\n timeout = 2000,\n children,\n onCopied,\n className,\n onClick,\n ...props\n}: CopyButtonProps) {\n const [copied, setCopied] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n };\n }, []);\n\n const handleClick = useCallback(\n async (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n try {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n onCopied?.();\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setCopied(false), timeout);\n } catch {\n /* empty */\n }\n },\n [value, timeout, onCopied, onClick],\n );\n\n return (\n <button\n type=\"button\"\n className={cn(styles.button, copied && styles.copied, className)}\n data-copied={copied || undefined}\n onClick={handleClick}\n {...props}\n >\n {children ?? (copied ? \"Copied\" : \"Copy\")}\n </button>\n );\n}\n"],"mappings":"iIAiCA,SAAgB,EAAW,CACvB,QACA,UAAU,IACV,WACA,WACA,YACA,UACA,GAAG,GACa,CAChB,GAAM,CAAC,EAAQ,IAAA,EAAA,EAAA,SAAA,CAAsB,EAAK,EACpC,GAAA,EAAA,EAAA,OAAA,CAAwD,IAAI,GAElE,EAAA,EAAA,UAAA,SACiB,CACL,EAAS,UAAY,MAAM,aAAa,EAAS,OAAO,CAChE,EACD,CAAC,CAAC,EAEL,IAAM,GAAA,EAAA,EAAA,YAAA,CACF,KAAO,IAA+C,CAClD,IAAU,CAAK,EACf,GAAI,CACA,MAAM,UAAU,UAAU,UAAU,CAAK,EACzC,EAAU,EAAI,EACd,IAAW,EACP,EAAS,UAAY,MAAM,aAAa,EAAS,OAAO,EAC5D,EAAS,QAAU,eAAiB,EAAU,EAAK,EAAG,CAAO,CACjE,MAAQ,CAER,CACJ,EACA,CAAC,EAAO,EAAS,EAAU,CAAO,CACtC,EAEA,OACI,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,GAAG,EAAA,QAAO,OAAQ,GAAU,EAAA,QAAO,OAAQ,CAAS,EAC/D,cAAa,GAAU,IAAA,GACvB,QAAS,EACT,GAAI,WAEH,IAAa,EAAS,SAAW,OAC9B,CAAA,CAEhB"}
1
+ {"version":3,"file":"CopyButton.cjs","names":[],"sources":["../../../src/components/CopyButton/CopyButton.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./CopyButton.module.css\";\n\nexport interface CopyButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Text written to the clipboard when the button is clicked. */\n value: string;\n /** How long (ms) the \"copied\" state stays active before resetting. Defaults to 2000. */\n timeout?: number;\n /** Optional label. Falls back to \"Copy\" / \"Copied\" based on state. */\n children?: ReactNode;\n /** Called after a successful clipboard write. */\n onCopied?: () => void;\n}\n\n/**\n * Button that copies a string to the clipboard and shows a transient \"copied\"\n * state for `timeout` milliseconds.\n *\n * When `children` are provided they are rendered in both states; otherwise the\n * label toggles between \"Copy\" and \"Copied\". The reset timer is cleared on\n * unmount to avoid setting state on an unmounted component.\n *\n * @tempest-limits empty-catch — `navigator.clipboard.writeText` rejects when the\n * page is not a secure context, when the document is not focused, or when the user\n * denied the permission. None of those are recoverable here and none deserve an\n * error surface: the button simply never enters the \"copied\" state, which is the\n * feedback the user needs.\n *\n * @example\n * <CopyButton value=\"npm i tempest-react-sdk\" />\n */\nexport function CopyButton({\n value,\n timeout = 2000,\n children,\n onCopied,\n className,\n onClick,\n ...props\n}: CopyButtonProps) {\n const [copied, setCopied] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n };\n }, []);\n\n const handleClick = useCallback(\n async (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n try {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n onCopied?.();\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setCopied(false), timeout);\n } catch {\n /* empty */\n }\n },\n [value, timeout, onCopied, onClick],\n );\n\n return (\n <button\n type=\"button\"\n className={cn(styles.button, copied && styles.copied, className)}\n data-copied={copied || undefined}\n onClick={handleClick}\n {...props}\n >\n {children ?? (copied ? \"Copied\" : \"Copy\")}\n </button>\n );\n}\n"],"mappings":"iIAiCA,SAAgB,EAAW,CACvB,QACA,UAAU,IACV,WACA,WACA,YACA,UACA,GAAG,GACa,CAChB,GAAM,CAAC,EAAQ,IAAA,EAAa,EAAA,SAAA,CAAS,EAAK,EACpC,GAAA,EAAW,EAAA,OAAA,CAA6C,IAAI,GAElE,EAAA,EAAA,UAAA,SACiB,CACL,EAAS,UAAY,MAAM,aAAa,EAAS,OAAO,CAChE,EACD,CAAC,CAAC,EAEL,IAAM,GAAA,EAAc,EAAA,YAAA,CAChB,KAAO,IAA+C,CAClD,IAAU,CAAK,EACf,GAAI,CACA,MAAM,UAAU,UAAU,UAAU,CAAK,EACzC,EAAU,EAAI,EACd,IAAW,EACP,EAAS,UAAY,MAAM,aAAa,EAAS,OAAO,EAC5D,EAAS,QAAU,eAAiB,EAAU,EAAK,EAAG,CAAO,CACjE,MAAQ,CAER,CACJ,EACA,CAAC,EAAO,EAAS,EAAU,CAAO,CACtC,EAEA,OACI,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,GAAG,EAAA,QAAO,OAAQ,GAAU,EAAA,QAAO,OAAQ,CAAS,EAC/D,cAAa,GAAU,IAAA,GACvB,QAAS,EACT,GAAI,EAEH,SAAA,IAAa,EAAS,SAAW,OAC9B,CAAA,CAEhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"CopyButton.js","names":[],"sources":["../../../src/components/CopyButton/CopyButton.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./CopyButton.module.css\";\n\nexport interface CopyButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Text written to the clipboard when the button is clicked. */\n value: string;\n /** How long (ms) the \"copied\" state stays active before resetting. Defaults to 2000. */\n timeout?: number;\n /** Optional label. Falls back to \"Copy\" / \"Copied\" based on state. */\n children?: ReactNode;\n /** Called after a successful clipboard write. */\n onCopied?: () => void;\n}\n\n/**\n * Button that copies a string to the clipboard and shows a transient \"copied\"\n * state for `timeout` milliseconds.\n *\n * When `children` are provided they are rendered in both states; otherwise the\n * label toggles between \"Copy\" and \"Copied\". The reset timer is cleared on\n * unmount to avoid setting state on an unmounted component.\n *\n * @tempest-limits empty-catch — `navigator.clipboard.writeText` rejects when the\n * page is not a secure context, when the document is not focused, or when the user\n * denied the permission. None of those are recoverable here and none deserve an\n * error surface: the button simply never enters the \"copied\" state, which is the\n * feedback the user needs.\n *\n * @example\n * <CopyButton value=\"npm i tempest-react-sdk\" />\n */\nexport function CopyButton({\n value,\n timeout = 2000,\n children,\n onCopied,\n className,\n onClick,\n ...props\n}: CopyButtonProps) {\n const [copied, setCopied] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n };\n }, []);\n\n const handleClick = useCallback(\n async (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n try {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n onCopied?.();\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setCopied(false), timeout);\n } catch {\n /* empty */\n }\n },\n [value, timeout, onCopied, onClick],\n );\n\n return (\n <button\n type=\"button\"\n className={cn(styles.button, copied && styles.copied, className)}\n data-copied={copied || undefined}\n onClick={handleClick}\n {...props}\n >\n {children ?? (copied ? \"Copied\" : \"Copy\")}\n </button>\n );\n}\n"],"mappings":";;;;;AAiCA,SAAgB,EAAW,EACvB,UACA,aAAU,KACV,aACA,aACA,cACA,YACA,GAAG,KACa;CAChB,IAAM,CAAC,GAAQ,KAAa,EAAS,EAAK,GACpC,IAAW,EAA6C,IAAI;CAElE,cACiB;EACT,AAAI,EAAS,YAAY,QAAM,aAAa,EAAS,OAAO;CAChE,GACD,CAAC,CAAC;CAEL,IAAM,IAAc,EAChB,OAAO,MAA+C;EAClD,IAAU,CAAK;EACf,IAAI;GAKA,AAJA,MAAM,UAAU,UAAU,UAAU,CAAK,GACzC,EAAU,EAAI,GACd,IAAW,GACP,EAAS,YAAY,QAAM,aAAa,EAAS,OAAO,GAC5D,EAAS,UAAU,iBAAiB,EAAU,EAAK,GAAG,CAAO;EACjE,QAAQ,CAER;CACJ,GACA;EAAC;EAAO;EAAS;EAAU;CAAO,CACtC;CAEA,OACI,kBAAC,UAAD;EACI,MAAK;EACL,WAAW,EAAG,EAAO,QAAQ,KAAU,EAAO,QAAQ,CAAS;EAC/D,eAAa,KAAU,KAAA;EACvB,SAAS;EACT,GAAI;YAEH,MAAa,IAAS,WAAW;CAC9B,CAAA;AAEhB"}
1
+ {"version":3,"file":"CopyButton.js","names":[],"sources":["../../../src/components/CopyButton/CopyButton.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./CopyButton.module.css\";\n\nexport interface CopyButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Text written to the clipboard when the button is clicked. */\n value: string;\n /** How long (ms) the \"copied\" state stays active before resetting. Defaults to 2000. */\n timeout?: number;\n /** Optional label. Falls back to \"Copy\" / \"Copied\" based on state. */\n children?: ReactNode;\n /** Called after a successful clipboard write. */\n onCopied?: () => void;\n}\n\n/**\n * Button that copies a string to the clipboard and shows a transient \"copied\"\n * state for `timeout` milliseconds.\n *\n * When `children` are provided they are rendered in both states; otherwise the\n * label toggles between \"Copy\" and \"Copied\". The reset timer is cleared on\n * unmount to avoid setting state on an unmounted component.\n *\n * @tempest-limits empty-catch — `navigator.clipboard.writeText` rejects when the\n * page is not a secure context, when the document is not focused, or when the user\n * denied the permission. None of those are recoverable here and none deserve an\n * error surface: the button simply never enters the \"copied\" state, which is the\n * feedback the user needs.\n *\n * @example\n * <CopyButton value=\"npm i tempest-react-sdk\" />\n */\nexport function CopyButton({\n value,\n timeout = 2000,\n children,\n onCopied,\n className,\n onClick,\n ...props\n}: CopyButtonProps) {\n const [copied, setCopied] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n };\n }, []);\n\n const handleClick = useCallback(\n async (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n try {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n onCopied?.();\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setCopied(false), timeout);\n } catch {\n /* empty */\n }\n },\n [value, timeout, onCopied, onClick],\n );\n\n return (\n <button\n type=\"button\"\n className={cn(styles.button, copied && styles.copied, className)}\n data-copied={copied || undefined}\n onClick={handleClick}\n {...props}\n >\n {children ?? (copied ? \"Copied\" : \"Copy\")}\n </button>\n );\n}\n"],"mappings":";;;;;AAiCA,SAAgB,EAAW,EACvB,UACA,aAAU,KACV,aACA,aACA,cACA,YACA,GAAG,KACa;CAChB,IAAM,CAAC,GAAQ,KAAa,EAAS,EAAK,GACpC,IAAW,EAA6C,IAAI;CAElE,cACiB;EACT,AAAI,EAAS,YAAY,QAAM,aAAa,EAAS,OAAO;CAChE,GACD,CAAC,CAAC;CAEL,IAAM,IAAc,EAChB,OAAO,MAA+C;EAClD,IAAU,CAAK;EACf,IAAI;GAKA,AAJA,MAAM,UAAU,UAAU,UAAU,CAAK,GACzC,EAAU,EAAI,GACd,IAAW,GACP,EAAS,YAAY,QAAM,aAAa,EAAS,OAAO,GAC5D,EAAS,UAAU,iBAAiB,EAAU,EAAK,GAAG,CAAO;EACjE,QAAQ,CAER;CACJ,GACA;EAAC;EAAO;EAAS;EAAU;CAAO,CACtC;CAEA,OACI,kBAAC,UAAD;EACI,MAAK;EACL,WAAW,EAAG,EAAO,QAAQ,KAAU,EAAO,QAAQ,CAAS;EAC/D,eAAa,KAAU,KAAA;EACvB,SAAS;EACT,GAAI;EAEH,UAAA,MAAa,IAAS,WAAW;CAC9B,CAAA;AAEhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"DataList.cjs","names":[],"sources":["../../../src/components/DataList/DataList.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./DataList.module.css\";\n\nexport interface DataListProps<T> extends HTMLAttributes<HTMLUListElement> {\n /** The collection to render, one `<li>` per item. */\n items: readonly T[];\n /** Renders the contents of each list item. */\n renderItem: (item: T, index: number) => ReactNode;\n /** Derives a stable React key for each item (defaults to the index). */\n keyExtractor?: (item: T, index: number) => string | number;\n /** Node rendered in place of the list when `items` is empty. */\n empty?: ReactNode;\n}\n\n/**\n * Generic, typed list that renders a `<ul>` with one `<li>` per item.\n *\n * The component is generic over the item type so `renderItem` and\n * `keyExtractor` infer their argument types from `items`. When `items` is\n * empty it renders `empty` (or nothing) instead of an empty list.\n *\n * @param items - The collection to render.\n * @param renderItem - Renders the contents of each list item.\n * @param keyExtractor - Optional stable key derivation (defaults to index).\n * @param empty - Optional node shown when there are no items.\n * @returns The rendered list, or the `empty` node when there are no items.\n */\nexport function DataList<T>({\n items,\n renderItem,\n keyExtractor,\n empty,\n className,\n ...props\n}: DataListProps<T>) {\n if (items.length === 0) {\n return <>{empty ?? null}</>;\n }\n\n return (\n <ul className={cn(styles.list, className)} {...props}>\n {items.map((item, index) => (\n <li key={keyExtractor ? keyExtractor(item, index) : index} className={styles.item}>\n {renderItem(item, index)}\n </li>\n ))}\n </ul>\n );\n}\n"],"mappings":"4GA4BA,SAAgB,EAAY,CACxB,QACA,aACA,eACA,QACA,YACA,GAAG,GACc,CAKjB,OAJI,EAAM,SAAW,GACV,EAAA,EAAA,IAAA,CAAA,EAAA,SAAA,CAAA,SAAG,GAAS,IAAO,CAAA,GAI1B,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,CAAS,EAAG,GAAI,WAC1C,EAAM,KAAK,EAAM,KACd,EAAA,EAAA,IAAA,CAAC,KAAD,CAA2D,UAAW,EAAA,QAAO,cACxE,EAAW,EAAM,CAAK,CACvB,EAFK,EAAe,EAAa,EAAM,CAAK,EAAI,CAEhD,CACP,CACD,CAAA,CAEZ"}
1
+ {"version":3,"file":"DataList.cjs","names":[],"sources":["../../../src/components/DataList/DataList.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./DataList.module.css\";\n\nexport interface DataListProps<T> extends HTMLAttributes<HTMLUListElement> {\n /** The collection to render, one `<li>` per item. */\n items: readonly T[];\n /** Renders the contents of each list item. */\n renderItem: (item: T, index: number) => ReactNode;\n /** Derives a stable React key for each item (defaults to the index). */\n keyExtractor?: (item: T, index: number) => string | number;\n /** Node rendered in place of the list when `items` is empty. */\n empty?: ReactNode;\n}\n\n/**\n * Generic, typed list that renders a `<ul>` with one `<li>` per item.\n *\n * The component is generic over the item type so `renderItem` and\n * `keyExtractor` infer their argument types from `items`. When `items` is\n * empty it renders `empty` (or nothing) instead of an empty list.\n *\n * @param items - The collection to render.\n * @param renderItem - Renders the contents of each list item.\n * @param keyExtractor - Optional stable key derivation (defaults to index).\n * @param empty - Optional node shown when there are no items.\n * @returns The rendered list, or the `empty` node when there are no items.\n */\nexport function DataList<T>({\n items,\n renderItem,\n keyExtractor,\n empty,\n className,\n ...props\n}: DataListProps<T>) {\n if (items.length === 0) {\n return <>{empty ?? null}</>;\n }\n\n return (\n <ul className={cn(styles.list, className)} {...props}>\n {items.map((item, index) => (\n <li key={keyExtractor ? keyExtractor(item, index) : index} className={styles.item}>\n {renderItem(item, index)}\n </li>\n ))}\n </ul>\n );\n}\n"],"mappings":"4GA4BA,SAAgB,EAAY,CACxB,QACA,aACA,eACA,QACA,YACA,GAAG,GACc,CAKjB,OAJI,EAAM,SAAW,GACV,EAAA,EAAA,IAAA,CAAA,EAAA,SAAA,CAAA,SAAG,GAAS,IAAO,CAAA,GAI1B,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,CAAS,EAAG,GAAI,EAC1C,SAAA,EAAM,KAAK,EAAM,KACd,EAAA,EAAA,IAAA,CAAC,KAAD,CAA2D,UAAW,EAAA,QAAO,KACxE,SAAA,EAAW,EAAM,CAAK,CACvB,EAFK,EAAe,EAAa,EAAM,CAAK,EAAI,CAEhD,CACP,CACD,CAAA,CAEZ"}
@@ -1 +1 @@
1
- {"version":3,"file":"DataList.js","names":[],"sources":["../../../src/components/DataList/DataList.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./DataList.module.css\";\n\nexport interface DataListProps<T> extends HTMLAttributes<HTMLUListElement> {\n /** The collection to render, one `<li>` per item. */\n items: readonly T[];\n /** Renders the contents of each list item. */\n renderItem: (item: T, index: number) => ReactNode;\n /** Derives a stable React key for each item (defaults to the index). */\n keyExtractor?: (item: T, index: number) => string | number;\n /** Node rendered in place of the list when `items` is empty. */\n empty?: ReactNode;\n}\n\n/**\n * Generic, typed list that renders a `<ul>` with one `<li>` per item.\n *\n * The component is generic over the item type so `renderItem` and\n * `keyExtractor` infer their argument types from `items`. When `items` is\n * empty it renders `empty` (or nothing) instead of an empty list.\n *\n * @param items - The collection to render.\n * @param renderItem - Renders the contents of each list item.\n * @param keyExtractor - Optional stable key derivation (defaults to index).\n * @param empty - Optional node shown when there are no items.\n * @returns The rendered list, or the `empty` node when there are no items.\n */\nexport function DataList<T>({\n items,\n renderItem,\n keyExtractor,\n empty,\n className,\n ...props\n}: DataListProps<T>) {\n if (items.length === 0) {\n return <>{empty ?? null}</>;\n }\n\n return (\n <ul className={cn(styles.list, className)} {...props}>\n {items.map((item, index) => (\n <li key={keyExtractor ? keyExtractor(item, index) : index} className={styles.item}>\n {renderItem(item, index)}\n </li>\n ))}\n </ul>\n );\n}\n"],"mappings":";;;;AA4BA,SAAgB,EAAY,EACxB,UACA,eACA,iBACA,UACA,cACA,GAAG,KACc;CAKjB,OAJI,EAAM,WAAW,IACV,kBAAA,GAAA,EAAA,UAAG,KAAS,KAAO,CAAA,IAI1B,kBAAC,MAAD;EAAI,WAAW,EAAG,EAAO,MAAM,CAAS;EAAG,GAAI;YAC1C,EAAM,KAAK,GAAM,MACd,kBAAC,MAAD;GAA2D,WAAW,EAAO;aACxE,EAAW,GAAM,CAAK;EACvB,GAFK,IAAe,EAAa,GAAM,CAAK,IAAI,CAEhD,CACP;CACD,CAAA;AAEZ"}
1
+ {"version":3,"file":"DataList.js","names":[],"sources":["../../../src/components/DataList/DataList.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./DataList.module.css\";\n\nexport interface DataListProps<T> extends HTMLAttributes<HTMLUListElement> {\n /** The collection to render, one `<li>` per item. */\n items: readonly T[];\n /** Renders the contents of each list item. */\n renderItem: (item: T, index: number) => ReactNode;\n /** Derives a stable React key for each item (defaults to the index). */\n keyExtractor?: (item: T, index: number) => string | number;\n /** Node rendered in place of the list when `items` is empty. */\n empty?: ReactNode;\n}\n\n/**\n * Generic, typed list that renders a `<ul>` with one `<li>` per item.\n *\n * The component is generic over the item type so `renderItem` and\n * `keyExtractor` infer their argument types from `items`. When `items` is\n * empty it renders `empty` (or nothing) instead of an empty list.\n *\n * @param items - The collection to render.\n * @param renderItem - Renders the contents of each list item.\n * @param keyExtractor - Optional stable key derivation (defaults to index).\n * @param empty - Optional node shown when there are no items.\n * @returns The rendered list, or the `empty` node when there are no items.\n */\nexport function DataList<T>({\n items,\n renderItem,\n keyExtractor,\n empty,\n className,\n ...props\n}: DataListProps<T>) {\n if (items.length === 0) {\n return <>{empty ?? null}</>;\n }\n\n return (\n <ul className={cn(styles.list, className)} {...props}>\n {items.map((item, index) => (\n <li key={keyExtractor ? keyExtractor(item, index) : index} className={styles.item}>\n {renderItem(item, index)}\n </li>\n ))}\n </ul>\n );\n}\n"],"mappings":";;;;AA4BA,SAAgB,EAAY,EACxB,UACA,eACA,iBACA,UACA,cACA,GAAG,KACc;CAKjB,OAJI,EAAM,WAAW,IACV,kBAAA,GAAA,EAAA,UAAG,KAAS,KAAO,CAAA,IAI1B,kBAAC,MAAD;EAAI,WAAW,EAAG,EAAO,MAAM,CAAS;EAAG,GAAI;EAC1C,UAAA,EAAM,KAAK,GAAM,MACd,kBAAC,MAAD;GAA2D,WAAW,EAAO;GACxE,UAAA,EAAW,GAAM,CAAK;EACvB,GAFK,IAAe,EAAa,GAAM,CAAK,IAAI,CAEhD,CACP;CACD,CAAA;AAEZ"}