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.
- package/dist/_virtual/_rolldown/runtime.cjs +1 -1
- package/dist/access/access-control-context.cjs.map +1 -1
- package/dist/access/use-can.cjs.map +1 -1
- package/dist/app/AppProviders.cjs.map +1 -1
- package/dist/app/AppProviders.js.map +1 -1
- package/dist/audio/use-audio-recorder.cjs.map +1 -1
- package/dist/audio/use-audio.cjs.map +1 -1
- package/dist/audio/use-microphone.cjs.map +1 -1
- package/dist/auth/create-auth-store.cjs.map +1 -1
- package/dist/auth/lazy-with-retry.cjs.map +1 -1
- package/dist/auth/passkey.cjs.map +1 -1
- package/dist/auth/passkey.js.map +1 -1
- package/dist/auth/use-passkey.cjs.map +1 -1
- package/dist/br/BrazilMap.cjs +1 -1
- package/dist/br/BrazilMap.cjs.map +1 -1
- package/dist/br/BrazilMap.js +2 -2
- package/dist/br/BrazilMap.js.map +1 -1
- package/dist/br/BrazilStateCitySelect.cjs.map +1 -1
- package/dist/br/BrazilStateCitySelect.js.map +1 -1
- package/dist/br/BrazilStateMap.cjs +1 -1
- package/dist/br/BrazilStateMap.cjs.map +1 -1
- package/dist/br/BrazilStateMap.js +2 -2
- package/dist/br/BrazilStateMap.js.map +1 -1
- package/dist/br/MapLegend.cjs.map +1 -1
- package/dist/br/MapLegend.js.map +1 -1
- package/dist/br/MapMarkers.cjs.map +1 -1
- package/dist/br/MapMarkers.js.map +1 -1
- package/dist/br/MunicipalitySearch.cjs.map +1 -1
- package/dist/br/MunicipalitySearch.js.map +1 -1
- package/dist/br/PixQRCode.cjs.map +1 -1
- package/dist/br/PixQRCode.js.map +1 -1
- package/dist/br/use-map-hover.cjs.map +1 -1
- package/dist/br/use-map-zoom.cjs.map +1 -1
- package/dist/capture/media-recorder.cjs +1 -1
- package/dist/capture/media-recorder.js +2 -2
- package/dist/capture/use-barcode-scanner.cjs +1 -1
- package/dist/capture/use-barcode-scanner.cjs.map +1 -1
- package/dist/capture/use-barcode-scanner.js +2 -2
- package/dist/capture/use-barcode-scanner.js.map +1 -1
- package/dist/capture/use-screen-capture.cjs.map +1 -1
- package/dist/capture/use-speech-recognition.cjs.map +1 -1
- package/dist/capture/use-torch.cjs.map +1 -1
- package/dist/capture/use-video-recorder.cjs.map +1 -1
- package/dist/charts/AreaChart.cjs.map +1 -1
- package/dist/charts/AreaChart.js.map +1 -1
- package/dist/charts/BarChart.cjs.map +1 -1
- package/dist/charts/BarChart.js.map +1 -1
- package/dist/charts/LineChart.cjs.map +1 -1
- package/dist/charts/LineChart.js.map +1 -1
- package/dist/charts/PieChart.cjs.map +1 -1
- package/dist/charts/PieChart.js.map +1 -1
- package/dist/charts/RadarChart.cjs.map +1 -1
- package/dist/charts/RadarChart.js.map +1 -1
- package/dist/charts/use-chart-colors.cjs.map +1 -1
- package/dist/components/AIChat/AIChat.cjs.map +1 -1
- package/dist/components/AIChat/AIChat.js.map +1 -1
- package/dist/components/AIChat/AIChatComposer.cjs.map +1 -1
- package/dist/components/AIChat/AIChatComposer.js.map +1 -1
- package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
- package/dist/components/AIChat/AIChatTurn.js.map +1 -1
- package/dist/components/Accordion/Accordion.cjs.map +1 -1
- package/dist/components/Accordion/Accordion.js.map +1 -1
- package/dist/components/Alert/Alert.cjs.map +1 -1
- package/dist/components/Alert/Alert.js.map +1 -1
- package/dist/components/AppBar/AppBar.cjs.map +1 -1
- package/dist/components/AppBar/AppBar.js.map +1 -1
- package/dist/components/AppShell/AppShell.cjs.map +1 -1
- package/dist/components/AppShell/AppShell.js.map +1 -1
- package/dist/components/AudioPlayer/AudioPlayer.cjs.map +1 -1
- package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -1
- package/dist/components/AudioRecorder/AudioRecorder.cjs.map +1 -1
- package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -1
- package/dist/components/Avatar/Avatar.cjs.map +1 -1
- package/dist/components/Avatar/Avatar.js.map +1 -1
- package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -1
- package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -1
- package/dist/components/Badge/Badge.cjs.map +1 -1
- package/dist/components/Badge/Badge.js.map +1 -1
- package/dist/components/Banner/Banner.cjs.map +1 -1
- package/dist/components/Banner/Banner.js.map +1 -1
- package/dist/components/BarcodeScanner/BarcodeScanner.cjs.map +1 -1
- package/dist/components/BarcodeScanner/BarcodeScanner.js.map +1 -1
- package/dist/components/BottomNavigation/BottomNavigation.cjs.map +1 -1
- package/dist/components/BottomNavigation/BottomNavigation.js.map +1 -1
- package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
- package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
- package/dist/components/Breadcrumbs/Breadcrumbs.cjs.map +1 -1
- package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
- package/dist/components/Button/Button.cjs.map +1 -1
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Calendar/Calendar.cjs +1 -1
- package/dist/components/Calendar/Calendar.cjs.map +1 -1
- package/dist/components/Calendar/Calendar.js +38 -41
- package/dist/components/Calendar/Calendar.js.map +1 -1
- package/dist/components/Card/Card.cjs.map +1 -1
- package/dist/components/Card/Card.js.map +1 -1
- package/dist/components/Carousel/Carousel.cjs.map +1 -1
- package/dist/components/Carousel/Carousel.js.map +1 -1
- package/dist/components/Chat/Chat.cjs.map +1 -1
- package/dist/components/Chat/Chat.js.map +1 -1
- package/dist/components/Chat/ChatComposer.cjs.map +1 -1
- package/dist/components/Chat/ChatComposer.js.map +1 -1
- package/dist/components/Chat/chat-groups.cjs +1 -1
- package/dist/components/Chat/chat-groups.cjs.map +1 -1
- package/dist/components/Chat/chat-groups.js +2 -2
- package/dist/components/Chat/chat-groups.js.map +1 -1
- package/dist/components/Checkbox/Checkbox.cjs.map +1 -1
- package/dist/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/components/ChipInput/ChipInput.cjs.map +1 -1
- package/dist/components/ChipInput/ChipInput.js.map +1 -1
- package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
- package/dist/components/CodeBlock/CodeBlock.cjs.map +1 -1
- package/dist/components/CodeBlock/CodeBlock.js.map +1 -1
- package/dist/components/Collapsible/Collapsible.cjs.map +1 -1
- package/dist/components/Collapsible/Collapsible.js.map +1 -1
- package/dist/components/Combobox/Combobox.cjs.map +1 -1
- package/dist/components/Combobox/Combobox.js.map +1 -1
- package/dist/components/Command/Command.cjs.map +1 -1
- package/dist/components/Command/Command.js.map +1 -1
- package/dist/components/ConfirmDialog/ConfirmDialog.cjs.map +1 -1
- package/dist/components/ConfirmDialog/ConfirmDialog.js.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
- package/dist/components/CopyButton/CopyButton.cjs.map +1 -1
- package/dist/components/CopyButton/CopyButton.js.map +1 -1
- package/dist/components/DataList/DataList.cjs.map +1 -1
- package/dist/components/DataList/DataList.js.map +1 -1
- package/dist/components/DataTable/DataTable.cjs +1 -1
- package/dist/components/DataTable/DataTable.cjs.map +1 -1
- package/dist/components/DataTable/DataTable.js +2 -2
- package/dist/components/DataTable/DataTable.js.map +1 -1
- package/dist/components/DataTable/EditableCell.cjs.map +1 -1
- package/dist/components/DataTable/EditableCell.js.map +1 -1
- package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
- package/dist/components/DateRangePicker/DateRangePicker.cjs.map +1 -1
- package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
- package/dist/components/DescriptionList/DescriptionList.cjs.map +1 -1
- package/dist/components/DescriptionList/DescriptionList.js.map +1 -1
- package/dist/components/Divider/Divider.cjs.map +1 -1
- package/dist/components/Divider/Divider.js.map +1 -1
- package/dist/components/Drawer/Drawer.cjs.map +1 -1
- package/dist/components/Drawer/Drawer.js.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/components/Dropzone/Dropzone.cjs.map +1 -1
- package/dist/components/Dropzone/Dropzone.js.map +1 -1
- package/dist/components/EmptyState/EmptyState.cjs.map +1 -1
- package/dist/components/EmptyState/EmptyState.js.map +1 -1
- package/dist/components/ErrorState/ErrorState.cjs.map +1 -1
- package/dist/components/ErrorState/ErrorState.js.map +1 -1
- package/dist/components/FileUpload/FileUpload.cjs +1 -1
- package/dist/components/FileUpload/FileUpload.cjs.map +1 -1
- package/dist/components/FileUpload/FileUpload.js +1 -1
- package/dist/components/FileUpload/FileUpload.js.map +1 -1
- package/dist/components/FilterBar/FilterBar.cjs.map +1 -1
- package/dist/components/FilterBar/FilterBar.js.map +1 -1
- package/dist/components/FloatingActionButton/FloatingActionButton.cjs.map +1 -1
- package/dist/components/FloatingActionButton/FloatingActionButton.js.map +1 -1
- package/dist/components/Form/Form.cjs.map +1 -1
- package/dist/components/Form/Form.js.map +1 -1
- package/dist/components/HoverCard/HoverCard.cjs.map +1 -1
- package/dist/components/HoverCard/HoverCard.js.map +1 -1
- package/dist/components/Image/Image.cjs.map +1 -1
- package/dist/components/ImageCropper/ImageCropper.cjs +1 -1
- package/dist/components/ImageCropper/ImageCropper.cjs.map +1 -1
- package/dist/components/ImageCropper/ImageCropper.js +1 -1
- package/dist/components/ImageCropper/ImageCropper.js.map +1 -1
- package/dist/components/Input/Input.cjs.map +1 -1
- package/dist/components/Input/Input.js.map +1 -1
- package/dist/components/InstallBanner/InstallBanner.cjs.map +1 -1
- package/dist/components/InstallBanner/InstallBanner.js.map +1 -1
- package/dist/components/InstallButton/InstallButton.cjs.map +1 -1
- package/dist/components/InstallButton/InstallButton.js.map +1 -1
- package/dist/components/Kanban/Kanban.cjs.map +1 -1
- package/dist/components/Kanban/Kanban.js.map +1 -1
- package/dist/components/Label/Label.cjs.map +1 -1
- package/dist/components/Label/Label.js.map +1 -1
- package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
- package/dist/components/Lightbox/Lightbox.js.map +1 -1
- package/dist/components/ListTile/ListTile.cjs.map +1 -1
- package/dist/components/ListTile/ListTile.js.map +1 -1
- package/dist/components/Markdown/Markdown.cjs +1 -1
- package/dist/components/Markdown/Markdown.cjs.map +1 -1
- package/dist/components/Markdown/Markdown.js +2 -2
- package/dist/components/Markdown/Markdown.js.map +1 -1
- package/dist/components/Masonry/Masonry.cjs.map +1 -1
- package/dist/components/Masonry/Masonry.js.map +1 -1
- package/dist/components/Menubar/Menubar.cjs.map +1 -1
- package/dist/components/Menubar/Menubar.js.map +1 -1
- package/dist/components/Modal/Modal.cjs.map +1 -1
- package/dist/components/Modal/Modal.js.map +1 -1
- package/dist/components/ModalsManager/ModalsManager.cjs.map +1 -1
- package/dist/components/ModalsManager/ModalsManager.js.map +1 -1
- package/dist/components/Money/Money.cjs.map +1 -1
- package/dist/components/Money/Money.js.map +1 -1
- package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
- package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/components/NProgress/NProgress.cjs.map +1 -1
- package/dist/components/Navbar/Navbar.cjs.map +1 -1
- package/dist/components/Navbar/Navbar.js.map +1 -1
- package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
- package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
- package/dist/components/NavigationRail/NavigationRail.cjs.map +1 -1
- package/dist/components/NavigationRail/NavigationRail.js.map +1 -1
- package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -1
- package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -1
- package/dist/components/NotificationCenter/use-notification-inbox.cjs.map +1 -1
- package/dist/components/OfflineIndicator/OfflineIndicator.cjs.map +1 -1
- package/dist/components/OfflineIndicator/OfflineIndicator.js.map +1 -1
- package/dist/components/Page/Page.cjs.map +1 -1
- package/dist/components/Page/Page.js.map +1 -1
- package/dist/components/Pagination/Pagination.cjs.map +1 -1
- package/dist/components/Pagination/Pagination.js.map +1 -1
- package/dist/components/PasswordInput/PasswordInput.cjs.map +1 -1
- package/dist/components/PasswordInput/PasswordInput.js.map +1 -1
- package/dist/components/PinInput/PinInput.cjs.map +1 -1
- package/dist/components/PinInput/PinInput.js.map +1 -1
- package/dist/components/Popover/Popover.cjs.map +1 -1
- package/dist/components/Popover/Popover.js.map +1 -1
- package/dist/components/Portal/Portal.cjs.map +1 -1
- package/dist/components/Progress/Progress.cjs.map +1 -1
- package/dist/components/Progress/Progress.js.map +1 -1
- package/dist/components/QRCode/QRCode.cjs.map +1 -1
- package/dist/components/QRCode/QRCode.js.map +1 -1
- package/dist/components/Radio/Radio.cjs.map +1 -1
- package/dist/components/Radio/Radio.js.map +1 -1
- package/dist/components/RangeSlider/RangeSlider.cjs.map +1 -1
- package/dist/components/RangeSlider/RangeSlider.js.map +1 -1
- package/dist/components/RatingStars/RatingStars.cjs.map +1 -1
- package/dist/components/RatingStars/RatingStars.js.map +1 -1
- package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
- package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
- package/dist/components/RelativeTime/RelativeTime.cjs.map +1 -1
- package/dist/components/RelativeTime/RelativeTime.js.map +1 -1
- package/dist/components/Resizable/Resizable.cjs.map +1 -1
- package/dist/components/Resizable/Resizable.js.map +1 -1
- package/dist/components/Scheduler/Scheduler.cjs.map +1 -1
- package/dist/components/Scheduler/Scheduler.js.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.cjs.map +1 -1
- package/dist/components/SearchBar/SearchBar.cjs.map +1 -1
- package/dist/components/SearchBar/SearchBar.js.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.cjs.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
- package/dist/components/Select/Select.cjs.map +1 -1
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
- package/dist/components/Sidebar/Sidebar.js.map +1 -1
- package/dist/components/SignaturePad/SignaturePad.cjs.map +1 -1
- package/dist/components/SignaturePad/SignaturePad.js.map +1 -1
- package/dist/components/Slider/Slider.cjs.map +1 -1
- package/dist/components/Slider/Slider.js.map +1 -1
- package/dist/components/Sparkline/Sparkline.cjs.map +1 -1
- package/dist/components/Sparkline/Sparkline.js.map +1 -1
- package/dist/components/Spinner/Spinner.cjs.map +1 -1
- package/dist/components/Spinner/Spinner.js.map +1 -1
- package/dist/components/Stat/Stat.cjs.map +1 -1
- package/dist/components/Stat/Stat.js.map +1 -1
- package/dist/components/Stepper/Stepper.cjs.map +1 -1
- package/dist/components/Stepper/Stepper.js.map +1 -1
- package/dist/components/StepperInput/StepperInput.cjs.map +1 -1
- package/dist/components/StepperInput/StepperInput.js.map +1 -1
- package/dist/components/Switch/Switch.cjs.map +1 -1
- package/dist/components/Switch/Switch.js.map +1 -1
- package/dist/components/SyncStatusBadge/SyncStatusBadge.cjs.map +1 -1
- package/dist/components/SyncStatusBadge/SyncStatusBadge.js.map +1 -1
- package/dist/components/Table/Table.cjs.map +1 -1
- package/dist/components/Table/Table.js.map +1 -1
- package/dist/components/Tabs/Tabs.cjs.map +1 -1
- package/dist/components/Tabs/Tabs.js.map +1 -1
- package/dist/components/Tag/Tag.cjs.map +1 -1
- package/dist/components/Tag/Tag.js.map +1 -1
- package/dist/components/Textarea/Textarea.cjs.map +1 -1
- package/dist/components/Textarea/Textarea.js.map +1 -1
- package/dist/components/TimePicker/TimePicker.cjs.map +1 -1
- package/dist/components/TimePicker/TimePicker.js.map +1 -1
- package/dist/components/Timeline/Timeline.cjs.map +1 -1
- package/dist/components/Timeline/Timeline.js.map +1 -1
- package/dist/components/Toast/ToastProvider.cjs.map +1 -1
- package/dist/components/Toast/ToastProvider.js.map +1 -1
- package/dist/components/Toggle/Toggle.cjs.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroup.cjs.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
- package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
- package/dist/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/components/Tour/Tour.cjs.map +1 -1
- package/dist/components/Tour/Tour.js.map +1 -1
- package/dist/components/Transfer/Transfer.cjs.map +1 -1
- package/dist/components/Transfer/Transfer.js.map +1 -1
- package/dist/components/TreeView/TreeView.cjs +1 -1
- package/dist/components/TreeView/TreeView.cjs.map +1 -1
- package/dist/components/TreeView/TreeView.js +1 -4
- package/dist/components/TreeView/TreeView.js.map +1 -1
- package/dist/components/UpdatePrompt/UpdatePrompt.cjs.map +1 -1
- package/dist/components/UpdatePrompt/UpdatePrompt.js.map +1 -1
- package/dist/components/VirtualList/VirtualList.cjs.map +1 -1
- package/dist/components/VirtualList/VirtualList.js.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.js.map +1 -1
- package/dist/components/VisuallyHidden/VisuallyHidden.cjs.map +1 -1
- package/dist/components/Wizard/Wizard.cjs.map +1 -1
- package/dist/components/Wizard/Wizard.js.map +1 -1
- package/dist/data/data-provider-context.cjs.map +1 -1
- package/dist/data/use-resource.cjs.map +1 -1
- package/dist/editor/RichTextEditor.cjs.map +1 -1
- package/dist/editor/RichTextEditor.js.map +1 -1
- package/dist/error-boundary/use-error-handler.cjs.map +1 -1
- package/dist/feature-flags/FeatureFlagsProvider.cjs.map +1 -1
- package/dist/forms/FormField.cjs.map +1 -1
- package/dist/forms/masked-inputs.cjs +1 -1
- package/dist/forms/masked-inputs.cjs.map +1 -1
- package/dist/forms/masked-inputs.js +1 -1
- package/dist/forms/masked-inputs.js.map +1 -1
- package/dist/forms/use-viacep.cjs.map +1 -1
- package/dist/forms/use-zod-form.cjs.map +1 -1
- package/dist/forms/zod-resolver.cjs.map +1 -1
- package/dist/forms/zod-resolver.js.map +1 -1
- package/dist/geo/TrajectoryMap.cjs.map +1 -1
- package/dist/geo/TrajectoryMap.js.map +1 -1
- package/dist/geo/leaflet-map.cjs.map +1 -1
- package/dist/geo/leaflet-map.js.map +1 -1
- package/dist/geo/use-position-tracker.cjs.map +1 -1
- package/dist/hooks/use-announce.cjs.map +1 -1
- package/dist/hooks/use-async.cjs.map +1 -1
- package/dist/hooks/use-before-install-prompt.cjs.map +1 -1
- package/dist/hooks/use-breakpoint.cjs.map +1 -1
- package/dist/hooks/use-click-outside.cjs.map +1 -1
- package/dist/hooks/use-client-filter.cjs.map +1 -1
- package/dist/hooks/use-clipboard.cjs.map +1 -1
- package/dist/hooks/use-counter.cjs.map +1 -1
- package/dist/hooks/use-debounce.cjs.map +1 -1
- package/dist/hooks/use-deep-memo.cjs.map +1 -1
- package/dist/hooks/use-disclosure.cjs.map +1 -1
- package/dist/hooks/use-document-visibility.cjs.map +1 -1
- package/dist/hooks/use-event-listener.cjs.map +1 -1
- package/dist/hooks/use-geolocation.cjs.map +1 -1
- package/dist/hooks/use-hover.cjs.map +1 -1
- package/dist/hooks/use-idle.cjs.map +1 -1
- package/dist/hooks/use-install-prompt.cjs +1 -1
- package/dist/hooks/use-install-prompt.cjs.map +1 -1
- package/dist/hooks/use-install-prompt.js +1 -1
- package/dist/hooks/use-install-prompt.js.map +1 -1
- package/dist/hooks/use-intersection-observer.cjs.map +1 -1
- package/dist/hooks/use-interval.cjs.map +1 -1
- package/dist/hooks/use-is-first-render.cjs.map +1 -1
- package/dist/hooks/use-keyboard-shortcut.cjs +1 -1
- package/dist/hooks/use-keyboard-shortcut.cjs.map +1 -1
- package/dist/hooks/use-keyboard-shortcut.js +1 -1
- package/dist/hooks/use-keyboard-shortcut.js.map +1 -1
- package/dist/hooks/use-list-state.cjs.map +1 -1
- package/dist/hooks/use-local-storage.cjs.map +1 -1
- package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
- package/dist/hooks/use-long-press.cjs.map +1 -1
- package/dist/hooks/use-map.cjs.map +1 -1
- package/dist/hooks/use-media-devices.cjs.map +1 -1
- package/dist/hooks/use-media-permission.cjs.map +1 -1
- package/dist/hooks/use-media-query.cjs.map +1 -1
- package/dist/hooks/use-object-url.cjs.map +1 -1
- package/dist/hooks/use-online.cjs.map +1 -1
- package/dist/hooks/use-pagination.cjs.map +1 -1
- package/dist/hooks/use-previous.cjs.map +1 -1
- package/dist/hooks/use-queue.cjs.map +1 -1
- package/dist/hooks/use-resize-observer.cjs.map +1 -1
- package/dist/hooks/use-scroll-overflow.cjs.map +1 -1
- package/dist/hooks/use-service-worker-update.cjs.map +1 -1
- package/dist/hooks/use-set.cjs.map +1 -1
- package/dist/hooks/use-sortable.cjs +1 -1
- package/dist/hooks/use-sortable.cjs.map +1 -1
- package/dist/hooks/use-sortable.js +0 -2
- package/dist/hooks/use-sortable.js.map +1 -1
- package/dist/hooks/use-stable-callback.cjs.map +1 -1
- package/dist/hooks/use-storage-estimate.cjs.map +1 -1
- package/dist/hooks/use-throttle.cjs.map +1 -1
- package/dist/hooks/use-timeout.cjs.map +1 -1
- package/dist/hooks/use-toggle.cjs.map +1 -1
- package/dist/hooks/use-window-size.cjs.map +1 -1
- package/dist/http/api-client.cjs +1 -1
- package/dist/http/api-client.cjs.map +1 -1
- package/dist/http/api-client.js +7 -5
- package/dist/http/api-client.js.map +1 -1
- package/dist/http/resumable-upload.cjs +1 -1
- package/dist/http/resumable-upload.cjs.map +1 -1
- package/dist/http/resumable-upload.js +1 -1
- package/dist/http/resumable-upload.js.map +1 -1
- package/dist/http/use-poll.cjs.map +1 -1
- package/dist/i18n/I18nProvider.cjs.map +1 -1
- package/dist/icons/Icon.cjs.map +1 -1
- package/dist/icons/IconProvider.cjs.map +1 -1
- package/dist/icons/icon-context.cjs.map +1 -1
- package/dist/icons/use-icon.cjs.map +1 -1
- package/dist/imaging/use-image-processing.cjs.map +1 -1
- package/dist/oauth/GoogleSignIn.cjs.map +1 -1
- package/dist/oauth/GoogleSignIn.js.map +1 -1
- package/dist/oauth/use-oauth-callback.cjs.map +1 -1
- package/dist/offline/use-offline-sync.cjs.map +1 -1
- package/dist/push/use-push-subscription.cjs.map +1 -1
- package/dist/query/QueryProvider.cjs.map +1 -1
- package/dist/query/constants.cjs +1 -1
- package/dist/query/constants.cjs.map +1 -1
- package/dist/query/constants.js +10 -10
- package/dist/query/constants.js.map +1 -1
- package/dist/query/create-query-keys.cjs +1 -1
- package/dist/query/create-query-keys.cjs.map +1 -1
- package/dist/query/create-query-keys.js +1 -1
- package/dist/query/create-query-keys.js.map +1 -1
- package/dist/query/offline-persistence.cjs.map +1 -1
- package/dist/query/use-cursor-query.cjs.map +1 -1
- package/dist/query/use-offline-mutation.cjs.map +1 -1
- package/dist/query/use-paginated-query.cjs.map +1 -1
- package/dist/router/AppRouter.cjs +1 -1
- package/dist/router/AppRouter.cjs.map +1 -1
- package/dist/router/AppRouter.js +7 -2
- package/dist/router/AppRouter.js.map +1 -1
- package/dist/sse/use-event-stream.cjs.map +1 -1
- package/dist/store/create-store.cjs.map +1 -1
- package/dist/tabular/use-tabular-predictor.cjs.map +1 -1
- package/dist/telemetry/TelemetryProvider.cjs.map +1 -1
- package/dist/tempest-react-sdk.d.ts +25 -26
- package/dist/theme/ThemeProvider.cjs.map +1 -1
- package/dist/theme/color.cjs +1 -1
- package/dist/theme/color.cjs.map +1 -1
- package/dist/theme/color.js +1 -1
- package/dist/theme/color.js.map +1 -1
- package/dist/utils/cn.cjs +1 -1
- package/dist/utils/cn.cjs.map +1 -1
- package/dist/utils/cn.js +1 -1
- package/dist/utils/cn.js.map +1 -1
- package/dist/utils/objects.cjs +1 -1
- package/dist/utils/objects.cjs.map +1 -1
- package/dist/utils/objects.js +1 -1
- package/dist/utils/objects.js.map +1 -1
- package/dist/utils/xlsx.cjs +1 -1
- package/dist/utils/xlsx.cjs.map +1 -1
- package/dist/utils/xlsx.js +3 -3
- package/dist/utils/xlsx.js.map +1 -1
- package/dist/vision/core/exceptions.cjs.map +1 -1
- package/dist/vision/core/exceptions.js.map +1 -1
- package/dist/vision/core/metadata.cjs +1 -1
- package/dist/vision/core/metadata.cjs.map +1 -1
- package/dist/vision/core/metadata.js +1 -1
- package/dist/vision/core/metadata.js.map +1 -1
- package/dist/vision/io/image.cjs +1 -1
- package/dist/vision/io/image.cjs.map +1 -1
- package/dist/vision/io/image.js +4 -2
- package/dist/vision/io/image.js.map +1 -1
- package/dist/vision/preprocess/image.cjs +1 -1
- package/dist/vision/preprocess/image.cjs.map +1 -1
- package/dist/vision/preprocess/image.js +4 -2
- package/dist/vision/preprocess/image.js.map +1 -1
- package/dist/vision/tasks/base.cjs +1 -1
- package/dist/vision/tasks/base.cjs.map +1 -1
- package/dist/vision/tasks/base.js +3 -1
- package/dist/vision/tasks/base.js.map +1 -1
- package/dist/vision/tasks/classifier.cjs +1 -1
- package/dist/vision/tasks/classifier.cjs.map +1 -1
- package/dist/vision/tasks/classifier.js +2 -2
- package/dist/vision/tasks/classifier.js.map +1 -1
- package/dist/vision/tasks/detectClassify.cjs +1 -1
- package/dist/vision/tasks/detectClassify.cjs.map +1 -1
- package/dist/vision/tasks/detectClassify.js +16 -15
- package/dist/vision/tasks/detectClassify.js.map +1 -1
- package/dist/vision/use-camera-stream.cjs.map +1 -1
- package/dist/vision/use-live-luminance.cjs.map +1 -1
- package/dist/vite/create-vite-config.cjs +1 -1
- package/dist/vite/create-vite-config.cjs.map +1 -1
- package/dist/vite/create-vite-config.js +3 -3
- package/dist/vite/create-vite-config.js.map +1 -1
- package/dist/vite/tempest-icons.cjs.map +1 -1
- package/dist/vite/tempest-pwa-dev-sw.cjs.map +1 -1
- package/dist/vite/tempest-pwa-icons.cjs.map +1 -1
- package/dist/ws/use-web-socket.cjs +1 -1
- package/dist/ws/use-web-socket.cjs.map +1 -1
- package/dist/ws/use-web-socket.js +5 -3
- package/dist/ws/use-web-socket.js.map +1 -1
- package/package.json +2 -2
- package/template/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SyncStatusBadge.cjs","names":[],"sources":["../../../src/components/SyncStatusBadge/SyncStatusBadge.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\nimport { AlertTriangle, Check, CloudOff, RefreshCw, UploadCloud } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport type { OfflineSync, SyncTone } from \"@/offline\";\nimport { useSyncStatus } from \"@/offline/use-offline-sync\";\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport styles from \"./SyncStatusBadge.module.css\";\n\nconst DEFAULT_LABELS: Record<SyncTone, string> = {\n idle: \"Sincronizado\",\n syncing: \"Sincronizando…\",\n pending: \"Pendente\",\n offline: \"Offline\",\n error: \"Erro\",\n};\n\nconst ICONS: Record<SyncTone, typeof Check> = {\n idle: Check,\n syncing: RefreshCw,\n pending: UploadCloud,\n offline: CloudOff,\n error: AlertTriangle,\n};\n\nexport interface SyncStatusBadgeProps extends Omit<HTMLAttributes<HTMLSpanElement>, \"children\"> {\n /**\n * The dominant tone. Required when `sync` is not passed. Ignored when `sync`\n * is passed (the tone is derived from the engine).\n */\n tone?: SyncTone;\n /**\n * An `OfflineSync` engine to observe directly. When set, the badge wires\n * `useSyncStatus` internally, so `tone` and `pending` come from the engine.\n */\n sync?: OfflineSync<unknown>;\n /** Number of queued mutations, appended to the label when `> 0`. */\n pending?: number;\n /** Override the per-tone label text. */\n labels?: Partial<Record<SyncTone, string>>;\n /** Show the pending count next to the label. Default `true`. */\n showPending?: boolean;\n /** Render only the icon (no text). Default `false`. */\n iconOnly?: boolean;\n}\n\ntype PresentationalProps = Omit<SyncStatusBadgeProps, \"sync\">;\n\n/**\n * The badge itself: a persistent `role=\"status\"` region.\n *\n * Left as its own live region rather than routed through `useAnnounce`, on purpose.\n * The badge is not a transient message — it is a piece of state that stays on\n * screen, which is exactly what `role=\"status\"` describes, and a reader can go back\n * and re-read it. Announcing it *again* from the shared announcer would read every\n * tone change twice.\n *\n * `iconOnly` used to break that, though: dropping the label left a live region whose\n * content never changed, so a switch to `offline` or `error` was announced as\n * nothing at all. The label is now always rendered — visually hidden when\n * `iconOnly`, since `title` is not content and is not announced on a change.\n */\nfunction PresentationalBadge({\n tone = \"idle\",\n pending = 0,\n labels,\n showPending = true,\n iconOnly = false,\n className,\n ...props\n}: PresentationalProps) {\n const Icon = ICONS[tone];\n const label = labels?.[tone] ?? DEFAULT_LABELS[tone];\n const showCount = showPending && pending > 0 && (tone === \"pending\" || tone === \"error\");\n return (\n <span\n className={cn(styles.badge, styles[tone], className)}\n role=\"status\"\n aria-live=\"polite\"\n title={label}\n {...props}\n >\n <Icon\n className={cn(styles.icon, tone === \"syncing\" && styles.spin)}\n size={14}\n aria-hidden=\"true\"\n />\n {iconOnly ? (\n <VisuallyHidden>{label}</VisuallyHidden>\n ) : (\n <span className={styles.label}>{label}</span>\n )}\n {showCount && <span className={styles.count}>{pending}</span>}\n </span>\n );\n}\n\nfunction ConnectedBadge({ sync, ...rest }: PresentationalProps & { sync: OfflineSync<unknown> }) {\n const { tone, pending } = useSyncStatus(sync);\n return <PresentationalBadge {...rest} tone={tone} pending={pending} />;\n}\n\n/**\n * Compact pill showing offline-sync status: a tone-colored icon plus a label\n * and optional pending count.\n *\n * Two modes: pass `sync` to have the badge observe an engine via\n * `useSyncStatus` (zero wiring), or pass an explicit `tone` (+ `pending`) to\n * keep it presentational and testable without IndexedDB.\n *\n * @example\n * // Connected — auto-wires the engine:\n * <SyncStatusBadge sync={notesSync} />\n *\n * // Presentational — you own the state:\n * const { tone, pending } = useSyncStatus(notesSync);\n * <SyncStatusBadge tone={tone} pending={pending} />\n */\nexport function SyncStatusBadge({ sync, ...rest }: SyncStatusBadgeProps) {\n if (sync) return <ConnectedBadge sync={sync} {...rest} />;\n return <PresentationalBadge {...rest} />;\n}\n"],"mappings":"+OAQA,IAAM,EAA2C,CAC7C,KAAM,eACN,QAAS,iBACT,QAAS,WACT,QAAS,UACT,MAAO,MACX,EAEM,EAAwC,CAC1C,KAAM,EAAA,MACN,QAAS,EAAA,UACT,QAAS,EAAA,YACT,QAAS,EAAA,SACT,MAAO,EAAA,aACX,EAuCA,SAAS,EAAoB,CACzB,OAAO,OACP,UAAU,EACV,SACA,cAAc,GACd,WAAW,GACX,YACA,GAAG,GACiB,CACpB,IAAM,EAAO,EAAM,GACb,EAAQ,IAAS,IAAS,EAAe,GACzC,EAAY,GAAe,EAAU,IAAM,IAAS,WAAa,IAAS,SAChF,OACI,EAAA,EAAA,KAAA,CAAC,OAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,EAAA,QAAO,GAAO,CAAS,EACnD,KAAK,SACL,YAAU,SACV,MAAO,EACP,GAAI,
|
|
1
|
+
{"version":3,"file":"SyncStatusBadge.cjs","names":[],"sources":["../../../src/components/SyncStatusBadge/SyncStatusBadge.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\nimport { AlertTriangle, Check, CloudOff, RefreshCw, UploadCloud } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport type { OfflineSync, SyncTone } from \"@/offline\";\nimport { useSyncStatus } from \"@/offline/use-offline-sync\";\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport styles from \"./SyncStatusBadge.module.css\";\n\nconst DEFAULT_LABELS: Record<SyncTone, string> = {\n idle: \"Sincronizado\",\n syncing: \"Sincronizando…\",\n pending: \"Pendente\",\n offline: \"Offline\",\n error: \"Erro\",\n};\n\nconst ICONS: Record<SyncTone, typeof Check> = {\n idle: Check,\n syncing: RefreshCw,\n pending: UploadCloud,\n offline: CloudOff,\n error: AlertTriangle,\n};\n\nexport interface SyncStatusBadgeProps extends Omit<HTMLAttributes<HTMLSpanElement>, \"children\"> {\n /**\n * The dominant tone. Required when `sync` is not passed. Ignored when `sync`\n * is passed (the tone is derived from the engine).\n */\n tone?: SyncTone;\n /**\n * An `OfflineSync` engine to observe directly. When set, the badge wires\n * `useSyncStatus` internally, so `tone` and `pending` come from the engine.\n */\n sync?: OfflineSync<unknown>;\n /** Number of queued mutations, appended to the label when `> 0`. */\n pending?: number;\n /** Override the per-tone label text. */\n labels?: Partial<Record<SyncTone, string>>;\n /** Show the pending count next to the label. Default `true`. */\n showPending?: boolean;\n /** Render only the icon (no text). Default `false`. */\n iconOnly?: boolean;\n}\n\ntype PresentationalProps = Omit<SyncStatusBadgeProps, \"sync\">;\n\n/**\n * The badge itself: a persistent `role=\"status\"` region.\n *\n * Left as its own live region rather than routed through `useAnnounce`, on purpose.\n * The badge is not a transient message — it is a piece of state that stays on\n * screen, which is exactly what `role=\"status\"` describes, and a reader can go back\n * and re-read it. Announcing it *again* from the shared announcer would read every\n * tone change twice.\n *\n * `iconOnly` used to break that, though: dropping the label left a live region whose\n * content never changed, so a switch to `offline` or `error` was announced as\n * nothing at all. The label is now always rendered — visually hidden when\n * `iconOnly`, since `title` is not content and is not announced on a change.\n */\nfunction PresentationalBadge({\n tone = \"idle\",\n pending = 0,\n labels,\n showPending = true,\n iconOnly = false,\n className,\n ...props\n}: PresentationalProps) {\n const Icon = ICONS[tone];\n const label = labels?.[tone] ?? DEFAULT_LABELS[tone];\n const showCount = showPending && pending > 0 && (tone === \"pending\" || tone === \"error\");\n return (\n <span\n className={cn(styles.badge, styles[tone], className)}\n role=\"status\"\n aria-live=\"polite\"\n title={label}\n {...props}\n >\n <Icon\n className={cn(styles.icon, tone === \"syncing\" && styles.spin)}\n size={14}\n aria-hidden=\"true\"\n />\n {iconOnly ? (\n <VisuallyHidden>{label}</VisuallyHidden>\n ) : (\n <span className={styles.label}>{label}</span>\n )}\n {showCount && <span className={styles.count}>{pending}</span>}\n </span>\n );\n}\n\nfunction ConnectedBadge({ sync, ...rest }: PresentationalProps & { sync: OfflineSync<unknown> }) {\n const { tone, pending } = useSyncStatus(sync);\n return <PresentationalBadge {...rest} tone={tone} pending={pending} />;\n}\n\n/**\n * Compact pill showing offline-sync status: a tone-colored icon plus a label\n * and optional pending count.\n *\n * Two modes: pass `sync` to have the badge observe an engine via\n * `useSyncStatus` (zero wiring), or pass an explicit `tone` (+ `pending`) to\n * keep it presentational and testable without IndexedDB.\n *\n * @example\n * // Connected — auto-wires the engine:\n * <SyncStatusBadge sync={notesSync} />\n *\n * // Presentational — you own the state:\n * const { tone, pending } = useSyncStatus(notesSync);\n * <SyncStatusBadge tone={tone} pending={pending} />\n */\nexport function SyncStatusBadge({ sync, ...rest }: SyncStatusBadgeProps) {\n if (sync) return <ConnectedBadge sync={sync} {...rest} />;\n return <PresentationalBadge {...rest} />;\n}\n"],"mappings":"+OAQA,IAAM,EAA2C,CAC7C,KAAM,eACN,QAAS,iBACT,QAAS,WACT,QAAS,UACT,MAAO,MACX,EAEM,EAAwC,CAC1C,KAAM,EAAA,MACN,QAAS,EAAA,UACT,QAAS,EAAA,YACT,QAAS,EAAA,SACT,MAAO,EAAA,aACX,EAuCA,SAAS,EAAoB,CACzB,OAAO,OACP,UAAU,EACV,SACA,cAAc,GACd,WAAW,GACX,YACA,GAAG,GACiB,CACpB,IAAM,EAAO,EAAM,GACb,EAAQ,IAAS,IAAS,EAAe,GACzC,EAAY,GAAe,EAAU,IAAM,IAAS,WAAa,IAAS,SAChF,OACI,EAAA,EAAA,KAAA,CAAC,OAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,EAAA,QAAO,GAAO,CAAS,EACnD,KAAK,SACL,YAAU,SACV,MAAO,EACP,GAAI,EALR,SAAA,EAOI,EAAA,EAAA,IAAA,CAAC,EAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,IAAS,WAAa,EAAA,QAAO,IAAI,EAC5D,KAAM,GACN,cAAY,MACf,CAAA,EACA,GACG,EAAA,EAAA,IAAA,CAAC,EAAA,eAAD,CAAA,SAAiB,CAAsB,CAAA,GAEvC,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,MAAQ,SAAA,CAAY,CAAA,EAE/C,IAAa,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,MAAQ,SAAA,CAAc,CAAA,CAC1D,GAEd,CAEA,SAAS,EAAe,CAAE,OAAM,GAAG,GAA8D,CAC7F,GAAM,CAAE,OAAM,WAAY,EAAA,cAAc,CAAI,EAC5C,OAAO,EAAA,EAAA,IAAA,CAAC,EAAD,CAAqB,GAAI,EAAY,OAAe,SAAU,CAAA,CACzE,CAkBA,SAAgB,EAAgB,CAAE,OAAM,GAAG,GAA8B,CAErE,OADI,GAAa,EAAA,EAAA,IAAA,CAAC,EAAD,CAAsB,OAAM,GAAI,CAAO,CAAA,GACjD,EAAA,EAAA,IAAA,CAAC,EAAD,CAAqB,GAAI,CAAO,CAAA,CAC3C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SyncStatusBadge.js","names":[],"sources":["../../../src/components/SyncStatusBadge/SyncStatusBadge.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\nimport { AlertTriangle, Check, CloudOff, RefreshCw, UploadCloud } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport type { OfflineSync, SyncTone } from \"@/offline\";\nimport { useSyncStatus } from \"@/offline/use-offline-sync\";\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport styles from \"./SyncStatusBadge.module.css\";\n\nconst DEFAULT_LABELS: Record<SyncTone, string> = {\n idle: \"Sincronizado\",\n syncing: \"Sincronizando…\",\n pending: \"Pendente\",\n offline: \"Offline\",\n error: \"Erro\",\n};\n\nconst ICONS: Record<SyncTone, typeof Check> = {\n idle: Check,\n syncing: RefreshCw,\n pending: UploadCloud,\n offline: CloudOff,\n error: AlertTriangle,\n};\n\nexport interface SyncStatusBadgeProps extends Omit<HTMLAttributes<HTMLSpanElement>, \"children\"> {\n /**\n * The dominant tone. Required when `sync` is not passed. Ignored when `sync`\n * is passed (the tone is derived from the engine).\n */\n tone?: SyncTone;\n /**\n * An `OfflineSync` engine to observe directly. When set, the badge wires\n * `useSyncStatus` internally, so `tone` and `pending` come from the engine.\n */\n sync?: OfflineSync<unknown>;\n /** Number of queued mutations, appended to the label when `> 0`. */\n pending?: number;\n /** Override the per-tone label text. */\n labels?: Partial<Record<SyncTone, string>>;\n /** Show the pending count next to the label. Default `true`. */\n showPending?: boolean;\n /** Render only the icon (no text). Default `false`. */\n iconOnly?: boolean;\n}\n\ntype PresentationalProps = Omit<SyncStatusBadgeProps, \"sync\">;\n\n/**\n * The badge itself: a persistent `role=\"status\"` region.\n *\n * Left as its own live region rather than routed through `useAnnounce`, on purpose.\n * The badge is not a transient message — it is a piece of state that stays on\n * screen, which is exactly what `role=\"status\"` describes, and a reader can go back\n * and re-read it. Announcing it *again* from the shared announcer would read every\n * tone change twice.\n *\n * `iconOnly` used to break that, though: dropping the label left a live region whose\n * content never changed, so a switch to `offline` or `error` was announced as\n * nothing at all. The label is now always rendered — visually hidden when\n * `iconOnly`, since `title` is not content and is not announced on a change.\n */\nfunction PresentationalBadge({\n tone = \"idle\",\n pending = 0,\n labels,\n showPending = true,\n iconOnly = false,\n className,\n ...props\n}: PresentationalProps) {\n const Icon = ICONS[tone];\n const label = labels?.[tone] ?? DEFAULT_LABELS[tone];\n const showCount = showPending && pending > 0 && (tone === \"pending\" || tone === \"error\");\n return (\n <span\n className={cn(styles.badge, styles[tone], className)}\n role=\"status\"\n aria-live=\"polite\"\n title={label}\n {...props}\n >\n <Icon\n className={cn(styles.icon, tone === \"syncing\" && styles.spin)}\n size={14}\n aria-hidden=\"true\"\n />\n {iconOnly ? (\n <VisuallyHidden>{label}</VisuallyHidden>\n ) : (\n <span className={styles.label}>{label}</span>\n )}\n {showCount && <span className={styles.count}>{pending}</span>}\n </span>\n );\n}\n\nfunction ConnectedBadge({ sync, ...rest }: PresentationalProps & { sync: OfflineSync<unknown> }) {\n const { tone, pending } = useSyncStatus(sync);\n return <PresentationalBadge {...rest} tone={tone} pending={pending} />;\n}\n\n/**\n * Compact pill showing offline-sync status: a tone-colored icon plus a label\n * and optional pending count.\n *\n * Two modes: pass `sync` to have the badge observe an engine via\n * `useSyncStatus` (zero wiring), or pass an explicit `tone` (+ `pending`) to\n * keep it presentational and testable without IndexedDB.\n *\n * @example\n * // Connected — auto-wires the engine:\n * <SyncStatusBadge sync={notesSync} />\n *\n * // Presentational — you own the state:\n * const { tone, pending } = useSyncStatus(notesSync);\n * <SyncStatusBadge tone={tone} pending={pending} />\n */\nexport function SyncStatusBadge({ sync, ...rest }: SyncStatusBadgeProps) {\n if (sync) return <ConnectedBadge sync={sync} {...rest} />;\n return <PresentationalBadge {...rest} />;\n}\n"],"mappings":";;;;;;;AAQA,IAAM,IAA2C;CAC7C,MAAM;CACN,SAAS;CACT,SAAS;CACT,SAAS;CACT,OAAO;AACX,GAEM,IAAwC;CAC1C,MAAM;CACN,SAAS;CACT,SAAS;CACT,SAAS;CACT,OAAO;AACX;AAuCA,SAAS,EAAoB,EACzB,UAAO,QACP,aAAU,GACV,WACA,iBAAc,IACd,cAAW,IACX,cACA,GAAG,KACiB;CACpB,IAAM,IAAO,EAAM,IACb,IAAQ,IAAS,MAAS,EAAe,IACzC,IAAY,KAAe,IAAU,MAAM,MAAS,aAAa,MAAS;CAChF,OACI,kBAAC,QAAD;EACI,WAAW,EAAG,EAAO,OAAO,EAAO,IAAO,CAAS;EACnD,MAAK;EACL,aAAU;EACV,OAAO;EACP,GAAI;
|
|
1
|
+
{"version":3,"file":"SyncStatusBadge.js","names":[],"sources":["../../../src/components/SyncStatusBadge/SyncStatusBadge.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\nimport { AlertTriangle, Check, CloudOff, RefreshCw, UploadCloud } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport type { OfflineSync, SyncTone } from \"@/offline\";\nimport { useSyncStatus } from \"@/offline/use-offline-sync\";\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport styles from \"./SyncStatusBadge.module.css\";\n\nconst DEFAULT_LABELS: Record<SyncTone, string> = {\n idle: \"Sincronizado\",\n syncing: \"Sincronizando…\",\n pending: \"Pendente\",\n offline: \"Offline\",\n error: \"Erro\",\n};\n\nconst ICONS: Record<SyncTone, typeof Check> = {\n idle: Check,\n syncing: RefreshCw,\n pending: UploadCloud,\n offline: CloudOff,\n error: AlertTriangle,\n};\n\nexport interface SyncStatusBadgeProps extends Omit<HTMLAttributes<HTMLSpanElement>, \"children\"> {\n /**\n * The dominant tone. Required when `sync` is not passed. Ignored when `sync`\n * is passed (the tone is derived from the engine).\n */\n tone?: SyncTone;\n /**\n * An `OfflineSync` engine to observe directly. When set, the badge wires\n * `useSyncStatus` internally, so `tone` and `pending` come from the engine.\n */\n sync?: OfflineSync<unknown>;\n /** Number of queued mutations, appended to the label when `> 0`. */\n pending?: number;\n /** Override the per-tone label text. */\n labels?: Partial<Record<SyncTone, string>>;\n /** Show the pending count next to the label. Default `true`. */\n showPending?: boolean;\n /** Render only the icon (no text). Default `false`. */\n iconOnly?: boolean;\n}\n\ntype PresentationalProps = Omit<SyncStatusBadgeProps, \"sync\">;\n\n/**\n * The badge itself: a persistent `role=\"status\"` region.\n *\n * Left as its own live region rather than routed through `useAnnounce`, on purpose.\n * The badge is not a transient message — it is a piece of state that stays on\n * screen, which is exactly what `role=\"status\"` describes, and a reader can go back\n * and re-read it. Announcing it *again* from the shared announcer would read every\n * tone change twice.\n *\n * `iconOnly` used to break that, though: dropping the label left a live region whose\n * content never changed, so a switch to `offline` or `error` was announced as\n * nothing at all. The label is now always rendered — visually hidden when\n * `iconOnly`, since `title` is not content and is not announced on a change.\n */\nfunction PresentationalBadge({\n tone = \"idle\",\n pending = 0,\n labels,\n showPending = true,\n iconOnly = false,\n className,\n ...props\n}: PresentationalProps) {\n const Icon = ICONS[tone];\n const label = labels?.[tone] ?? DEFAULT_LABELS[tone];\n const showCount = showPending && pending > 0 && (tone === \"pending\" || tone === \"error\");\n return (\n <span\n className={cn(styles.badge, styles[tone], className)}\n role=\"status\"\n aria-live=\"polite\"\n title={label}\n {...props}\n >\n <Icon\n className={cn(styles.icon, tone === \"syncing\" && styles.spin)}\n size={14}\n aria-hidden=\"true\"\n />\n {iconOnly ? (\n <VisuallyHidden>{label}</VisuallyHidden>\n ) : (\n <span className={styles.label}>{label}</span>\n )}\n {showCount && <span className={styles.count}>{pending}</span>}\n </span>\n );\n}\n\nfunction ConnectedBadge({ sync, ...rest }: PresentationalProps & { sync: OfflineSync<unknown> }) {\n const { tone, pending } = useSyncStatus(sync);\n return <PresentationalBadge {...rest} tone={tone} pending={pending} />;\n}\n\n/**\n * Compact pill showing offline-sync status: a tone-colored icon plus a label\n * and optional pending count.\n *\n * Two modes: pass `sync` to have the badge observe an engine via\n * `useSyncStatus` (zero wiring), or pass an explicit `tone` (+ `pending`) to\n * keep it presentational and testable without IndexedDB.\n *\n * @example\n * // Connected — auto-wires the engine:\n * <SyncStatusBadge sync={notesSync} />\n *\n * // Presentational — you own the state:\n * const { tone, pending } = useSyncStatus(notesSync);\n * <SyncStatusBadge tone={tone} pending={pending} />\n */\nexport function SyncStatusBadge({ sync, ...rest }: SyncStatusBadgeProps) {\n if (sync) return <ConnectedBadge sync={sync} {...rest} />;\n return <PresentationalBadge {...rest} />;\n}\n"],"mappings":";;;;;;;AAQA,IAAM,IAA2C;CAC7C,MAAM;CACN,SAAS;CACT,SAAS;CACT,SAAS;CACT,OAAO;AACX,GAEM,IAAwC;CAC1C,MAAM;CACN,SAAS;CACT,SAAS;CACT,SAAS;CACT,OAAO;AACX;AAuCA,SAAS,EAAoB,EACzB,UAAO,QACP,aAAU,GACV,WACA,iBAAc,IACd,cAAW,IACX,cACA,GAAG,KACiB;CACpB,IAAM,IAAO,EAAM,IACb,IAAQ,IAAS,MAAS,EAAe,IACzC,IAAY,KAAe,IAAU,MAAM,MAAS,aAAa,MAAS;CAChF,OACI,kBAAC,QAAD;EACI,WAAW,EAAG,EAAO,OAAO,EAAO,IAAO,CAAS;EACnD,MAAK;EACL,aAAU;EACV,OAAO;EACP,GAAI;EALR,UAAA;GAOI,kBAAC,GAAD;IACI,WAAW,EAAG,EAAO,MAAM,MAAS,aAAa,EAAO,IAAI;IAC5D,MAAM;IACN,eAAY;GACf,CAAA;GACA,IACG,kBAAC,GAAD,EAAA,UAAiB,EAAsB,CAAA,IAEvC,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAQ,UAAA;GAAY,CAAA;GAE/C,KAAa,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAQ,UAAA;GAAc,CAAA;EAC1D;;AAEd;AAEA,SAAS,EAAe,EAAE,SAAM,GAAG,KAA8D;CAC7F,IAAM,EAAE,SAAM,eAAY,EAAc,CAAI;CAC5C,OAAO,kBAAC,GAAD;EAAqB,GAAI;EAAY;EAAe;CAAU,CAAA;AACzE;AAkBA,SAAgB,EAAgB,EAAE,SAAM,GAAG,KAA8B;CAErE,OADI,IAAa,kBAAC,GAAD;EAAsB;EAAM,GAAI;CAAO,CAAA,IACjD,kBAAC,GAAD,EAAqB,GAAI,EAAO,CAAA;AAC3C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.cjs","names":[],"sources":["../../../src/components/Table/Table.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — columns, data and rowKey are the model; onRowClick\n * and emptyMessage the interaction and the empty state; stackOnMobile and\n * scrollLabel are the two ways a table survives a phone, and the label is required\n * because a scroll region needs an accessible name.\n */\nimport { useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { useScrollOverflow } from \"@/hooks/use-scroll-overflow\";\nimport styles from \"./Table.module.css\";\n\nexport type TableAlign = \"left\" | \"right\" | \"center\";\nexport type TablePriority = \"always\" | \"tablet\" | \"desktop\";\n\nexport interface TableColumn<T> {\n key: string;\n header: ReactNode;\n /** Render the cell content. Defaults to `row[key]` if not provided. */\n render?: (row: T, index: number) => ReactNode;\n align?: TableAlign;\n width?: string | number;\n className?: string;\n /**\n * Visibility priority: `always` (default) shows on every viewport,\n * `tablet` hides below md (< 768px), `desktop` hides below lg (< 1024px).\n */\n priority?: TablePriority;\n}\n\nexport interface TableProps<T> {\n columns: TableColumn<T>[];\n data: T[];\n rowKey: (row: T, index: number) => string | number;\n onRowClick?: (row: T) => void;\n emptyMessage?: ReactNode;\n className?: string;\n /**\n * Stack mode — render rows as label/value cards on mobile (< md).\n * Better than horizontal scroll when each row has 3+ columns of dense data.\n */\n stackOnMobile?: boolean;\n /**\n * Accessible name for the scrollable region, used only while the table is\n * actually wider than its box. A focus stop that announces nothing is worse\n * than no focus stop, so name the table when the page holds several.\n */\n scrollLabel?: string;\n}\n\nfunction priorityClass(priority: TablePriority | undefined): string | undefined {\n if (priority === \"tablet\") return styles.priorityTablet;\n if (priority === \"desktop\") return styles.priorityDesktop;\n return undefined;\n}\n\n/**\n * Lightweight table with declarative columns + mobile niceties.\n *\n * - `priority` per column lets less-important data hide on narrow viewports.\n * - `stackOnMobile` re-renders each row as a label/value card on mobile,\n * avoiding horizontal scroll for dense data.\n */\nexport function Table<T>({\n columns,\n data,\n rowKey,\n onRowClick,\n emptyMessage = \"Nenhum registro encontrado.\",\n className,\n stackOnMobile = false,\n scrollLabel = \"Tabela rolável horizontalmente\",\n}: TableProps<T>) {\n const scrollRef = useRef<HTMLDivElement>(null);\n const scrollable = useScrollOverflow(scrollRef, \"horizontal\");\n\n return (\n <div\n ref={scrollRef}\n className={cn(styles.scroll, stackOnMobile && styles.stackable, className)}\n tabIndex={scrollable ? 0 : undefined}\n role={scrollable ? \"group\" : undefined}\n aria-label={scrollable ? scrollLabel : undefined}\n >\n <table className={styles.table}>\n <thead className={cn(stackOnMobile && styles.stackableHead)}>\n <tr>\n {columns.map((column) => (\n <th\n key={column.key}\n className={cn(\n styles.th,\n column.align === \"right\" && styles.alignRight,\n column.align === \"center\" && styles.alignCenter,\n priorityClass(column.priority),\n )}\n style={{ width: column.width }}\n >\n {column.header}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.length === 0 ? (\n <tr>\n <td className={styles.emptyRow} colSpan={columns.length}>\n {emptyMessage}\n </td>\n </tr>\n ) : (\n data.map((row, index) => (\n <tr\n key={rowKey(row, index)}\n className={cn(\n styles.tr,\n onRowClick && styles.clickable,\n stackOnMobile && styles.stackableRow,\n )}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n >\n {columns.map((column) => {\n const content = column.render\n ? column.render(row, index)\n : (row as Record<string, ReactNode>)[column.key];\n return (\n <td\n key={column.key}\n className={cn(\n styles.td,\n column.align === \"right\" && styles.alignRight,\n column.align === \"center\" && styles.alignCenter,\n priorityClass(column.priority),\n column.className,\n )}\n data-label={\n typeof column.header === \"string\"\n ? column.header\n : undefined\n }\n >\n {content}\n </td>\n );\n })}\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n );\n}\n"],"mappings":"6KAkDA,SAAS,EAAc,EAAyD,CAC5E,GAAI,IAAa,SAAU,OAAO,EAAA,QAAO,eACzC,GAAI,IAAa,UAAW,OAAO,EAAA,QAAO,eAE9C,CASA,SAAgB,EAAS,CACrB,UACA,OACA,SACA,aACA,eAAe,8BACf,YACA,gBAAgB,GAChB,cAAc,kCACA,CACd,IAAM,GAAA,
|
|
1
|
+
{"version":3,"file":"Table.cjs","names":[],"sources":["../../../src/components/Table/Table.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — columns, data and rowKey are the model; onRowClick\n * and emptyMessage the interaction and the empty state; stackOnMobile and\n * scrollLabel are the two ways a table survives a phone, and the label is required\n * because a scroll region needs an accessible name.\n */\nimport { useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { useScrollOverflow } from \"@/hooks/use-scroll-overflow\";\nimport styles from \"./Table.module.css\";\n\nexport type TableAlign = \"left\" | \"right\" | \"center\";\nexport type TablePriority = \"always\" | \"tablet\" | \"desktop\";\n\nexport interface TableColumn<T> {\n key: string;\n header: ReactNode;\n /** Render the cell content. Defaults to `row[key]` if not provided. */\n render?: (row: T, index: number) => ReactNode;\n align?: TableAlign;\n width?: string | number;\n className?: string;\n /**\n * Visibility priority: `always` (default) shows on every viewport,\n * `tablet` hides below md (< 768px), `desktop` hides below lg (< 1024px).\n */\n priority?: TablePriority;\n}\n\nexport interface TableProps<T> {\n columns: TableColumn<T>[];\n data: T[];\n rowKey: (row: T, index: number) => string | number;\n onRowClick?: (row: T) => void;\n emptyMessage?: ReactNode;\n className?: string;\n /**\n * Stack mode — render rows as label/value cards on mobile (< md).\n * Better than horizontal scroll when each row has 3+ columns of dense data.\n */\n stackOnMobile?: boolean;\n /**\n * Accessible name for the scrollable region, used only while the table is\n * actually wider than its box. A focus stop that announces nothing is worse\n * than no focus stop, so name the table when the page holds several.\n */\n scrollLabel?: string;\n}\n\nfunction priorityClass(priority: TablePriority | undefined): string | undefined {\n if (priority === \"tablet\") return styles.priorityTablet;\n if (priority === \"desktop\") return styles.priorityDesktop;\n return undefined;\n}\n\n/**\n * Lightweight table with declarative columns + mobile niceties.\n *\n * - `priority` per column lets less-important data hide on narrow viewports.\n * - `stackOnMobile` re-renders each row as a label/value card on mobile,\n * avoiding horizontal scroll for dense data.\n */\nexport function Table<T>({\n columns,\n data,\n rowKey,\n onRowClick,\n emptyMessage = \"Nenhum registro encontrado.\",\n className,\n stackOnMobile = false,\n scrollLabel = \"Tabela rolável horizontalmente\",\n}: TableProps<T>) {\n const scrollRef = useRef<HTMLDivElement>(null);\n const scrollable = useScrollOverflow(scrollRef, \"horizontal\");\n\n return (\n <div\n ref={scrollRef}\n className={cn(styles.scroll, stackOnMobile && styles.stackable, className)}\n tabIndex={scrollable ? 0 : undefined}\n role={scrollable ? \"group\" : undefined}\n aria-label={scrollable ? scrollLabel : undefined}\n >\n <table className={styles.table}>\n <thead className={cn(stackOnMobile && styles.stackableHead)}>\n <tr>\n {columns.map((column) => (\n <th\n key={column.key}\n className={cn(\n styles.th,\n column.align === \"right\" && styles.alignRight,\n column.align === \"center\" && styles.alignCenter,\n priorityClass(column.priority),\n )}\n style={{ width: column.width }}\n >\n {column.header}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.length === 0 ? (\n <tr>\n <td className={styles.emptyRow} colSpan={columns.length}>\n {emptyMessage}\n </td>\n </tr>\n ) : (\n data.map((row, index) => (\n <tr\n key={rowKey(row, index)}\n className={cn(\n styles.tr,\n onRowClick && styles.clickable,\n stackOnMobile && styles.stackableRow,\n )}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n >\n {columns.map((column) => {\n const content = column.render\n ? column.render(row, index)\n : (row as Record<string, ReactNode>)[column.key];\n return (\n <td\n key={column.key}\n className={cn(\n styles.td,\n column.align === \"right\" && styles.alignRight,\n column.align === \"center\" && styles.alignCenter,\n priorityClass(column.priority),\n column.className,\n )}\n data-label={\n typeof column.header === \"string\"\n ? column.header\n : undefined\n }\n >\n {content}\n </td>\n );\n })}\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n );\n}\n"],"mappings":"6KAkDA,SAAS,EAAc,EAAyD,CAC5E,GAAI,IAAa,SAAU,OAAO,EAAA,QAAO,eACzC,GAAI,IAAa,UAAW,OAAO,EAAA,QAAO,eAE9C,CASA,SAAgB,EAAS,CACrB,UACA,OACA,SACA,aACA,eAAe,8BACf,YACA,gBAAgB,GAChB,cAAc,kCACA,CACd,IAAM,GAAA,EAAY,EAAA,OAAA,CAAuB,IAAI,EACvC,EAAa,EAAA,kBAAkB,EAAW,YAAY,EAE5D,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,IAAK,EACL,UAAW,EAAA,GAAG,EAAA,QAAO,OAAQ,GAAiB,EAAA,QAAO,UAAW,CAAS,EACzE,SAAU,EAAa,EAAI,IAAA,GAC3B,KAAM,EAAa,QAAU,IAAA,GAC7B,aAAY,EAAa,EAAc,IAAA,GAEvC,UAAA,EAAA,EAAA,KAAA,CAAC,QAAD,CAAO,UAAW,EAAA,QAAO,MAAzB,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,QAAD,CAAO,UAAW,EAAA,GAAG,GAAiB,EAAA,QAAO,aAAa,EACtD,UAAA,EAAA,EAAA,IAAA,CAAC,KAAD,CAAA,SACK,EAAQ,IAAK,IACV,EAAA,EAAA,IAAA,CAAC,KAAD,CAEI,UAAW,EAAA,GACP,EAAA,QAAO,GACP,EAAO,QAAU,SAAW,EAAA,QAAO,WACnC,EAAO,QAAU,UAAY,EAAA,QAAO,YACpC,EAAc,EAAO,QAAQ,CACjC,EACA,MAAO,CAAE,MAAO,EAAO,KAAM,EAE5B,SAAA,EAAO,MACR,EAVK,EAAO,GAUZ,CACP,CACD,CAAA,CACD,CAAA,GACP,EAAA,EAAA,IAAA,CAAC,QAAD,CAAA,SACK,EAAK,SAAW,GACb,EAAA,EAAA,IAAA,CAAC,KAAD,CAAA,UACI,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,SAAU,QAAS,EAAQ,OAC5C,SAAA,CACD,CAAA,CACJ,CAAA,EAEJ,EAAK,KAAK,EAAK,KACX,EAAA,EAAA,IAAA,CAAC,KAAD,CAEI,UAAW,EAAA,GACP,EAAA,QAAO,GACP,GAAc,EAAA,QAAO,UACrB,GAAiB,EAAA,QAAO,YAC5B,EACA,QAAS,MAAmB,EAAW,CAAG,EAAI,IAAA,GAE7C,SAAA,EAAQ,IAAK,GAAW,CACrB,IAAM,EAAU,EAAO,OACjB,EAAO,OAAO,EAAK,CAAK,EACvB,EAAkC,EAAO,KAChD,OACI,EAAA,EAAA,IAAA,CAAC,KAAD,CAEI,UAAW,EAAA,GACP,EAAA,QAAO,GACP,EAAO,QAAU,SAAW,EAAA,QAAO,WACnC,EAAO,QAAU,UAAY,EAAA,QAAO,YACpC,EAAc,EAAO,QAAQ,EAC7B,EAAO,SACX,EACA,aACI,OAAO,EAAO,QAAW,SACnB,EAAO,OACP,IAAA,GAGT,SAAA,CACD,EAfK,EAAO,GAeZ,CAEZ,CAAC,CACD,EAhCK,EAAO,EAAK,CAAK,CAgCtB,CACP,CAEF,CAAA,CACJ,GACN,CAAA,CAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.js","names":[],"sources":["../../../src/components/Table/Table.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — columns, data and rowKey are the model; onRowClick\n * and emptyMessage the interaction and the empty state; stackOnMobile and\n * scrollLabel are the two ways a table survives a phone, and the label is required\n * because a scroll region needs an accessible name.\n */\nimport { useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { useScrollOverflow } from \"@/hooks/use-scroll-overflow\";\nimport styles from \"./Table.module.css\";\n\nexport type TableAlign = \"left\" | \"right\" | \"center\";\nexport type TablePriority = \"always\" | \"tablet\" | \"desktop\";\n\nexport interface TableColumn<T> {\n key: string;\n header: ReactNode;\n /** Render the cell content. Defaults to `row[key]` if not provided. */\n render?: (row: T, index: number) => ReactNode;\n align?: TableAlign;\n width?: string | number;\n className?: string;\n /**\n * Visibility priority: `always` (default) shows on every viewport,\n * `tablet` hides below md (< 768px), `desktop` hides below lg (< 1024px).\n */\n priority?: TablePriority;\n}\n\nexport interface TableProps<T> {\n columns: TableColumn<T>[];\n data: T[];\n rowKey: (row: T, index: number) => string | number;\n onRowClick?: (row: T) => void;\n emptyMessage?: ReactNode;\n className?: string;\n /**\n * Stack mode — render rows as label/value cards on mobile (< md).\n * Better than horizontal scroll when each row has 3+ columns of dense data.\n */\n stackOnMobile?: boolean;\n /**\n * Accessible name for the scrollable region, used only while the table is\n * actually wider than its box. A focus stop that announces nothing is worse\n * than no focus stop, so name the table when the page holds several.\n */\n scrollLabel?: string;\n}\n\nfunction priorityClass(priority: TablePriority | undefined): string | undefined {\n if (priority === \"tablet\") return styles.priorityTablet;\n if (priority === \"desktop\") return styles.priorityDesktop;\n return undefined;\n}\n\n/**\n * Lightweight table with declarative columns + mobile niceties.\n *\n * - `priority` per column lets less-important data hide on narrow viewports.\n * - `stackOnMobile` re-renders each row as a label/value card on mobile,\n * avoiding horizontal scroll for dense data.\n */\nexport function Table<T>({\n columns,\n data,\n rowKey,\n onRowClick,\n emptyMessage = \"Nenhum registro encontrado.\",\n className,\n stackOnMobile = false,\n scrollLabel = \"Tabela rolável horizontalmente\",\n}: TableProps<T>) {\n const scrollRef = useRef<HTMLDivElement>(null);\n const scrollable = useScrollOverflow(scrollRef, \"horizontal\");\n\n return (\n <div\n ref={scrollRef}\n className={cn(styles.scroll, stackOnMobile && styles.stackable, className)}\n tabIndex={scrollable ? 0 : undefined}\n role={scrollable ? \"group\" : undefined}\n aria-label={scrollable ? scrollLabel : undefined}\n >\n <table className={styles.table}>\n <thead className={cn(stackOnMobile && styles.stackableHead)}>\n <tr>\n {columns.map((column) => (\n <th\n key={column.key}\n className={cn(\n styles.th,\n column.align === \"right\" && styles.alignRight,\n column.align === \"center\" && styles.alignCenter,\n priorityClass(column.priority),\n )}\n style={{ width: column.width }}\n >\n {column.header}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.length === 0 ? (\n <tr>\n <td className={styles.emptyRow} colSpan={columns.length}>\n {emptyMessage}\n </td>\n </tr>\n ) : (\n data.map((row, index) => (\n <tr\n key={rowKey(row, index)}\n className={cn(\n styles.tr,\n onRowClick && styles.clickable,\n stackOnMobile && styles.stackableRow,\n )}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n >\n {columns.map((column) => {\n const content = column.render\n ? column.render(row, index)\n : (row as Record<string, ReactNode>)[column.key];\n return (\n <td\n key={column.key}\n className={cn(\n styles.td,\n column.align === \"right\" && styles.alignRight,\n column.align === \"center\" && styles.alignCenter,\n priorityClass(column.priority),\n column.className,\n )}\n data-label={\n typeof column.header === \"string\"\n ? column.header\n : undefined\n }\n >\n {content}\n </td>\n );\n })}\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n );\n}\n"],"mappings":";;;;;;AAkDA,SAAS,EAAc,GAAyD;CAC5E,IAAI,MAAa,UAAU,OAAO,EAAO;CACzC,IAAI,MAAa,WAAW,OAAO,EAAO;AAE9C;AASA,SAAgB,EAAS,EACrB,YACA,SACA,WACA,eACA,kBAAe,+BACf,cACA,mBAAgB,IAChB,iBAAc,oCACA;CACd,IAAM,IAAY,EAAuB,IAAI,GACvC,IAAa,EAAkB,GAAW,YAAY;CAE5D,OACI,kBAAC,OAAD;EACI,KAAK;EACL,WAAW,EAAG,EAAO,QAAQ,KAAiB,EAAO,WAAW,CAAS;EACzE,UAAU,IAAa,IAAI,KAAA;EAC3B,MAAM,IAAa,UAAU,KAAA;EAC7B,cAAY,IAAa,IAAc,KAAA;
|
|
1
|
+
{"version":3,"file":"Table.js","names":[],"sources":["../../../src/components/Table/Table.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — columns, data and rowKey are the model; onRowClick\n * and emptyMessage the interaction and the empty state; stackOnMobile and\n * scrollLabel are the two ways a table survives a phone, and the label is required\n * because a scroll region needs an accessible name.\n */\nimport { useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { useScrollOverflow } from \"@/hooks/use-scroll-overflow\";\nimport styles from \"./Table.module.css\";\n\nexport type TableAlign = \"left\" | \"right\" | \"center\";\nexport type TablePriority = \"always\" | \"tablet\" | \"desktop\";\n\nexport interface TableColumn<T> {\n key: string;\n header: ReactNode;\n /** Render the cell content. Defaults to `row[key]` if not provided. */\n render?: (row: T, index: number) => ReactNode;\n align?: TableAlign;\n width?: string | number;\n className?: string;\n /**\n * Visibility priority: `always` (default) shows on every viewport,\n * `tablet` hides below md (< 768px), `desktop` hides below lg (< 1024px).\n */\n priority?: TablePriority;\n}\n\nexport interface TableProps<T> {\n columns: TableColumn<T>[];\n data: T[];\n rowKey: (row: T, index: number) => string | number;\n onRowClick?: (row: T) => void;\n emptyMessage?: ReactNode;\n className?: string;\n /**\n * Stack mode — render rows as label/value cards on mobile (< md).\n * Better than horizontal scroll when each row has 3+ columns of dense data.\n */\n stackOnMobile?: boolean;\n /**\n * Accessible name for the scrollable region, used only while the table is\n * actually wider than its box. A focus stop that announces nothing is worse\n * than no focus stop, so name the table when the page holds several.\n */\n scrollLabel?: string;\n}\n\nfunction priorityClass(priority: TablePriority | undefined): string | undefined {\n if (priority === \"tablet\") return styles.priorityTablet;\n if (priority === \"desktop\") return styles.priorityDesktop;\n return undefined;\n}\n\n/**\n * Lightweight table with declarative columns + mobile niceties.\n *\n * - `priority` per column lets less-important data hide on narrow viewports.\n * - `stackOnMobile` re-renders each row as a label/value card on mobile,\n * avoiding horizontal scroll for dense data.\n */\nexport function Table<T>({\n columns,\n data,\n rowKey,\n onRowClick,\n emptyMessage = \"Nenhum registro encontrado.\",\n className,\n stackOnMobile = false,\n scrollLabel = \"Tabela rolável horizontalmente\",\n}: TableProps<T>) {\n const scrollRef = useRef<HTMLDivElement>(null);\n const scrollable = useScrollOverflow(scrollRef, \"horizontal\");\n\n return (\n <div\n ref={scrollRef}\n className={cn(styles.scroll, stackOnMobile && styles.stackable, className)}\n tabIndex={scrollable ? 0 : undefined}\n role={scrollable ? \"group\" : undefined}\n aria-label={scrollable ? scrollLabel : undefined}\n >\n <table className={styles.table}>\n <thead className={cn(stackOnMobile && styles.stackableHead)}>\n <tr>\n {columns.map((column) => (\n <th\n key={column.key}\n className={cn(\n styles.th,\n column.align === \"right\" && styles.alignRight,\n column.align === \"center\" && styles.alignCenter,\n priorityClass(column.priority),\n )}\n style={{ width: column.width }}\n >\n {column.header}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.length === 0 ? (\n <tr>\n <td className={styles.emptyRow} colSpan={columns.length}>\n {emptyMessage}\n </td>\n </tr>\n ) : (\n data.map((row, index) => (\n <tr\n key={rowKey(row, index)}\n className={cn(\n styles.tr,\n onRowClick && styles.clickable,\n stackOnMobile && styles.stackableRow,\n )}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n >\n {columns.map((column) => {\n const content = column.render\n ? column.render(row, index)\n : (row as Record<string, ReactNode>)[column.key];\n return (\n <td\n key={column.key}\n className={cn(\n styles.td,\n column.align === \"right\" && styles.alignRight,\n column.align === \"center\" && styles.alignCenter,\n priorityClass(column.priority),\n column.className,\n )}\n data-label={\n typeof column.header === \"string\"\n ? column.header\n : undefined\n }\n >\n {content}\n </td>\n );\n })}\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n );\n}\n"],"mappings":";;;;;;AAkDA,SAAS,EAAc,GAAyD;CAC5E,IAAI,MAAa,UAAU,OAAO,EAAO;CACzC,IAAI,MAAa,WAAW,OAAO,EAAO;AAE9C;AASA,SAAgB,EAAS,EACrB,YACA,SACA,WACA,eACA,kBAAe,+BACf,cACA,mBAAgB,IAChB,iBAAc,oCACA;CACd,IAAM,IAAY,EAAuB,IAAI,GACvC,IAAa,EAAkB,GAAW,YAAY;CAE5D,OACI,kBAAC,OAAD;EACI,KAAK;EACL,WAAW,EAAG,EAAO,QAAQ,KAAiB,EAAO,WAAW,CAAS;EACzE,UAAU,IAAa,IAAI,KAAA;EAC3B,MAAM,IAAa,UAAU,KAAA;EAC7B,cAAY,IAAa,IAAc,KAAA;EAEvC,UAAA,kBAAC,SAAD;GAAO,WAAW,EAAO;GAAzB,UAAA,CACI,kBAAC,SAAD;IAAO,WAAW,EAAG,KAAiB,EAAO,aAAa;IACtD,UAAA,kBAAC,MAAD,EAAA,UACK,EAAQ,KAAK,MACV,kBAAC,MAAD;KAEI,WAAW,EACP,EAAO,IACP,EAAO,UAAU,WAAW,EAAO,YACnC,EAAO,UAAU,YAAY,EAAO,aACpC,EAAc,EAAO,QAAQ,CACjC;KACA,OAAO,EAAE,OAAO,EAAO,MAAM;KAE5B,UAAA,EAAO;IACR,GAVK,EAAO,GAUZ,CACP,EACD,CAAA;GACD,CAAA,GACP,kBAAC,SAAD,EAAA,UACK,EAAK,WAAW,IACb,kBAAC,MAAD,EAAA,UACI,kBAAC,MAAD;IAAI,WAAW,EAAO;IAAU,SAAS,EAAQ;IAC5C,UAAA;GACD,CAAA,EACJ,CAAA,IAEJ,EAAK,KAAK,GAAK,MACX,kBAAC,MAAD;IAEI,WAAW,EACP,EAAO,IACP,KAAc,EAAO,WACrB,KAAiB,EAAO,YAC5B;IACA,SAAS,UAAmB,EAAW,CAAG,IAAI,KAAA;IAE7C,UAAA,EAAQ,KAAK,MAAW;KACrB,IAAM,IAAU,EAAO,SACjB,EAAO,OAAO,GAAK,CAAK,IACvB,EAAkC,EAAO;KAChD,OACI,kBAAC,MAAD;MAEI,WAAW,EACP,EAAO,IACP,EAAO,UAAU,WAAW,EAAO,YACnC,EAAO,UAAU,YAAY,EAAO,aACpC,EAAc,EAAO,QAAQ,GAC7B,EAAO,SACX;MACA,cACI,OAAO,EAAO,UAAW,WACnB,EAAO,SACP,KAAA;MAGT,UAAA;KACD,GAfK,EAAO,GAeZ;IAEZ,CAAC;GACD,GAhCK,EAAO,GAAK,CAAK,CAgCtB,CACP,EAEF,CAAA,CACJ;;CACN,CAAA;AAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs.cjs","names":[],"sources":["../../../src/components/Tabs/Tabs.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Tabs.module.css\";\n\nexport interface TabItem {\n id: string;\n label: ReactNode;\n content: ReactNode;\n disabled?: boolean;\n}\n\nexport interface TabsProps {\n items: TabItem[];\n /** Initial active tab id. Defaults to the first non-disabled item. */\n defaultId?: string;\n /** Controlled active id. When provided, ignore internal state. */\n activeId?: string;\n onChange?: (id: string) => void;\n variant?: \"underline\" | \"pill\";\n className?: string;\n}\n\n/**\n * Accessible tabs with an underline (default) or pill variant. Controlled via\n * `activeId` + `onChange` or uncontrolled via `defaultId`.\n */\nexport function Tabs({\n items,\n defaultId,\n activeId,\n onChange,\n variant = \"underline\",\n className,\n}: TabsProps) {\n const firstEnabled = items.find((item) => !item.disabled);\n const [internal, setInternal] = useState<string | undefined>(defaultId ?? firstEnabled?.id);\n\n const isControlled = activeId !== undefined;\n const current = isControlled ? activeId : internal;\n const active = items.find((item) => item.id === current) ?? firstEnabled;\n\n function activate(id: string): void {\n if (!isControlled) setInternal(id);\n onChange?.(id);\n }\n\n return (\n <div className={className}>\n <div role=\"tablist\" className={cn(styles.tablist, variant === \"pill\" && styles.pill)}>\n {items.map((item) => {\n const isActive = item.id === active?.id;\n return (\n <button\n key={item.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n aria-controls={`panel-${item.id}`}\n id={`tab-${item.id}`}\n disabled={item.disabled}\n className={cn(styles.tab, isActive && styles.active)}\n onClick={() => activate(item.id)}\n >\n {item.label}\n </button>\n );\n })}\n </div>\n {active && (\n <div\n role=\"tabpanel\"\n id={`panel-${active.id}`}\n aria-labelledby={`tab-${active.id}`}\n className={styles.panel}\n >\n {active.content}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"2HA2BA,SAAgB,EAAK,CACjB,QACA,YACA,WACA,WACA,UAAU,YACV,aACU,CACV,IAAM,EAAe,EAAM,KAAM,GAAS,CAAC,EAAK,QAAQ,EAClD,CAAC,EAAU,IAAA,
|
|
1
|
+
{"version":3,"file":"Tabs.cjs","names":[],"sources":["../../../src/components/Tabs/Tabs.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Tabs.module.css\";\n\nexport interface TabItem {\n id: string;\n label: ReactNode;\n content: ReactNode;\n disabled?: boolean;\n}\n\nexport interface TabsProps {\n items: TabItem[];\n /** Initial active tab id. Defaults to the first non-disabled item. */\n defaultId?: string;\n /** Controlled active id. When provided, ignore internal state. */\n activeId?: string;\n onChange?: (id: string) => void;\n variant?: \"underline\" | \"pill\";\n className?: string;\n}\n\n/**\n * Accessible tabs with an underline (default) or pill variant. Controlled via\n * `activeId` + `onChange` or uncontrolled via `defaultId`.\n */\nexport function Tabs({\n items,\n defaultId,\n activeId,\n onChange,\n variant = \"underline\",\n className,\n}: TabsProps) {\n const firstEnabled = items.find((item) => !item.disabled);\n const [internal, setInternal] = useState<string | undefined>(defaultId ?? firstEnabled?.id);\n\n const isControlled = activeId !== undefined;\n const current = isControlled ? activeId : internal;\n const active = items.find((item) => item.id === current) ?? firstEnabled;\n\n function activate(id: string): void {\n if (!isControlled) setInternal(id);\n onChange?.(id);\n }\n\n return (\n <div className={className}>\n <div role=\"tablist\" className={cn(styles.tablist, variant === \"pill\" && styles.pill)}>\n {items.map((item) => {\n const isActive = item.id === active?.id;\n return (\n <button\n key={item.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n aria-controls={`panel-${item.id}`}\n id={`tab-${item.id}`}\n disabled={item.disabled}\n className={cn(styles.tab, isActive && styles.active)}\n onClick={() => activate(item.id)}\n >\n {item.label}\n </button>\n );\n })}\n </div>\n {active && (\n <div\n role=\"tabpanel\"\n id={`panel-${active.id}`}\n aria-labelledby={`tab-${active.id}`}\n className={styles.panel}\n >\n {active.content}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"2HA2BA,SAAgB,EAAK,CACjB,QACA,YACA,WACA,WACA,UAAU,YACV,aACU,CACV,IAAM,EAAe,EAAM,KAAM,GAAS,CAAC,EAAK,QAAQ,EAClD,CAAC,EAAU,IAAA,EAAe,EAAA,SAAA,CAA6B,GAAa,GAAc,EAAE,EAEpF,EAAe,IAAa,IAAA,GAC5B,EAAU,EAAe,EAAW,EACpC,EAAS,EAAM,KAAM,GAAS,EAAK,KAAO,CAAO,GAAK,EAE5D,SAAS,EAAS,EAAkB,CAC3B,GAAc,EAAY,CAAE,EACjC,IAAW,CAAE,CACjB,CAEA,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAgB,YAAhB,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,KAAK,UAAU,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,IAAY,QAAU,EAAA,QAAO,IAAI,EAC9E,SAAA,EAAM,IAAK,GAAS,CACjB,IAAM,EAAW,EAAK,KAAO,GAAQ,GACrC,OACI,EAAA,EAAA,IAAA,CAAC,SAAD,CAEI,KAAK,SACL,KAAK,MACL,gBAAe,EACf,gBAAe,SAAS,EAAK,KAC7B,GAAI,OAAO,EAAK,KAChB,SAAU,EAAK,SACf,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,GAAY,EAAA,QAAO,MAAM,EACnD,YAAe,EAAS,EAAK,EAAE,EAE9B,SAAA,EAAK,KACF,EAXC,EAAK,EAWN,CAEhB,CAAC,CACA,CAAA,EACJ,IACG,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,KAAK,WACL,GAAI,SAAS,EAAO,KACpB,kBAAiB,OAAO,EAAO,KAC/B,UAAW,EAAA,QAAO,MAEjB,SAAA,EAAO,OACP,CAAA,CAER,GAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs.js","names":[],"sources":["../../../src/components/Tabs/Tabs.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Tabs.module.css\";\n\nexport interface TabItem {\n id: string;\n label: ReactNode;\n content: ReactNode;\n disabled?: boolean;\n}\n\nexport interface TabsProps {\n items: TabItem[];\n /** Initial active tab id. Defaults to the first non-disabled item. */\n defaultId?: string;\n /** Controlled active id. When provided, ignore internal state. */\n activeId?: string;\n onChange?: (id: string) => void;\n variant?: \"underline\" | \"pill\";\n className?: string;\n}\n\n/**\n * Accessible tabs with an underline (default) or pill variant. Controlled via\n * `activeId` + `onChange` or uncontrolled via `defaultId`.\n */\nexport function Tabs({\n items,\n defaultId,\n activeId,\n onChange,\n variant = \"underline\",\n className,\n}: TabsProps) {\n const firstEnabled = items.find((item) => !item.disabled);\n const [internal, setInternal] = useState<string | undefined>(defaultId ?? firstEnabled?.id);\n\n const isControlled = activeId !== undefined;\n const current = isControlled ? activeId : internal;\n const active = items.find((item) => item.id === current) ?? firstEnabled;\n\n function activate(id: string): void {\n if (!isControlled) setInternal(id);\n onChange?.(id);\n }\n\n return (\n <div className={className}>\n <div role=\"tablist\" className={cn(styles.tablist, variant === \"pill\" && styles.pill)}>\n {items.map((item) => {\n const isActive = item.id === active?.id;\n return (\n <button\n key={item.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n aria-controls={`panel-${item.id}`}\n id={`tab-${item.id}`}\n disabled={item.disabled}\n className={cn(styles.tab, isActive && styles.active)}\n onClick={() => activate(item.id)}\n >\n {item.label}\n </button>\n );\n })}\n </div>\n {active && (\n <div\n role=\"tabpanel\"\n id={`panel-${active.id}`}\n aria-labelledby={`tab-${active.id}`}\n className={styles.panel}\n >\n {active.content}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AA2BA,SAAgB,EAAK,EACjB,UACA,cACA,aACA,aACA,aAAU,aACV,gBACU;CACV,IAAM,IAAe,EAAM,MAAM,MAAS,CAAC,EAAK,QAAQ,GAClD,CAAC,GAAU,KAAe,EAA6B,KAAa,GAAc,EAAE,GAEpF,IAAe,MAAa,KAAA,GAC5B,IAAU,IAAe,IAAW,GACpC,IAAS,EAAM,MAAM,MAAS,EAAK,OAAO,CAAO,KAAK;CAE5D,SAAS,EAAS,GAAkB;EAEhC,AADK,KAAc,EAAY,CAAE,GACjC,IAAW,CAAE;CACjB;CAEA,OACI,kBAAC,OAAD;EAAgB;
|
|
1
|
+
{"version":3,"file":"Tabs.js","names":[],"sources":["../../../src/components/Tabs/Tabs.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Tabs.module.css\";\n\nexport interface TabItem {\n id: string;\n label: ReactNode;\n content: ReactNode;\n disabled?: boolean;\n}\n\nexport interface TabsProps {\n items: TabItem[];\n /** Initial active tab id. Defaults to the first non-disabled item. */\n defaultId?: string;\n /** Controlled active id. When provided, ignore internal state. */\n activeId?: string;\n onChange?: (id: string) => void;\n variant?: \"underline\" | \"pill\";\n className?: string;\n}\n\n/**\n * Accessible tabs with an underline (default) or pill variant. Controlled via\n * `activeId` + `onChange` or uncontrolled via `defaultId`.\n */\nexport function Tabs({\n items,\n defaultId,\n activeId,\n onChange,\n variant = \"underline\",\n className,\n}: TabsProps) {\n const firstEnabled = items.find((item) => !item.disabled);\n const [internal, setInternal] = useState<string | undefined>(defaultId ?? firstEnabled?.id);\n\n const isControlled = activeId !== undefined;\n const current = isControlled ? activeId : internal;\n const active = items.find((item) => item.id === current) ?? firstEnabled;\n\n function activate(id: string): void {\n if (!isControlled) setInternal(id);\n onChange?.(id);\n }\n\n return (\n <div className={className}>\n <div role=\"tablist\" className={cn(styles.tablist, variant === \"pill\" && styles.pill)}>\n {items.map((item) => {\n const isActive = item.id === active?.id;\n return (\n <button\n key={item.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n aria-controls={`panel-${item.id}`}\n id={`tab-${item.id}`}\n disabled={item.disabled}\n className={cn(styles.tab, isActive && styles.active)}\n onClick={() => activate(item.id)}\n >\n {item.label}\n </button>\n );\n })}\n </div>\n {active && (\n <div\n role=\"tabpanel\"\n id={`panel-${active.id}`}\n aria-labelledby={`tab-${active.id}`}\n className={styles.panel}\n >\n {active.content}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AA2BA,SAAgB,EAAK,EACjB,UACA,cACA,aACA,aACA,aAAU,aACV,gBACU;CACV,IAAM,IAAe,EAAM,MAAM,MAAS,CAAC,EAAK,QAAQ,GAClD,CAAC,GAAU,KAAe,EAA6B,KAAa,GAAc,EAAE,GAEpF,IAAe,MAAa,KAAA,GAC5B,IAAU,IAAe,IAAW,GACpC,IAAS,EAAM,MAAM,MAAS,EAAK,OAAO,CAAO,KAAK;CAE5D,SAAS,EAAS,GAAkB;EAEhC,AADK,KAAc,EAAY,CAAE,GACjC,IAAW,CAAE;CACjB;CAEA,OACI,kBAAC,OAAD;EAAgB;EAAhB,UAAA,CACI,kBAAC,OAAD;GAAK,MAAK;GAAU,WAAW,EAAG,EAAO,SAAS,MAAY,UAAU,EAAO,IAAI;GAC9E,UAAA,EAAM,KAAK,MAAS;IACjB,IAAM,IAAW,EAAK,OAAO,GAAQ;IACrC,OACI,kBAAC,UAAD;KAEI,MAAK;KACL,MAAK;KACL,iBAAe;KACf,iBAAe,SAAS,EAAK;KAC7B,IAAI,OAAO,EAAK;KAChB,UAAU,EAAK;KACf,WAAW,EAAG,EAAO,KAAK,KAAY,EAAO,MAAM;KACnD,eAAe,EAAS,EAAK,EAAE;KAE9B,UAAA,EAAK;IACF,GAXC,EAAK,EAWN;GAEhB,CAAC;EACA,CAAA,GACJ,KACG,kBAAC,OAAD;GACI,MAAK;GACL,IAAI,SAAS,EAAO;GACpB,mBAAiB,OAAO,EAAO;GAC/B,WAAW,EAAO;GAEjB,UAAA,EAAO;EACP,CAAA,CAER;;AAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tag.cjs","names":[],"sources":["../../../src/components/Tag/Tag.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Tag.module.css\";\n\nexport type TagVariant = \"neutral\" | \"primary\" | \"success\" | \"warning\" | \"danger\" | \"info\";\nexport type TagSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface TagProps extends Omit<HTMLAttributes<HTMLSpanElement>, \"onRemove\"> {\n /** Visual variant. Default `\"neutral\"`. */\n variant?: TagVariant;\n /** Visual size. Default `\"md\"`. */\n size?: TagSize;\n /** When set, renders a close button that fires this callback. */\n onRemove?: () => void;\n /** Custom remove label for screen readers. Default `\"Remover\"`. */\n removeLabel?: string;\n children?: ReactNode;\n}\n\n/**\n * Removable chip — used for filter tokens, applied search filters,\n * selected entities. Different from `Badge` (status-only, not removable).\n *\n * @example\n * <Tag variant=\"primary\" onRemove={() => removeFilter(\"sao-paulo\")}>\n * São Paulo\n * </Tag>\n */\nexport function Tag({\n variant = \"neutral\",\n size = \"md\",\n onRemove,\n removeLabel = \"Remover\",\n className,\n children,\n ...props\n}: TagProps) {\n return (\n <span className={cn(styles.tag, styles[variant], styles[size], className)} {...props}>\n <span className={styles.label}>{children}</span>\n {onRemove && (\n <button\n type=\"button\"\n className={styles.remove}\n aria-label={removeLabel}\n onClick={onRemove}\n >\n ×\n </button>\n )}\n </span>\n );\n}\n"],"mappings":"uGA4BA,SAAgB,EAAI,CAChB,UAAU,UACV,OAAO,KACP,WACA,cAAc,UACd,YACA,WACA,GAAG,GACM,CACT,OACI,EAAA,EAAA,KAAA,CAAC,OAAD,CAAM,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,EAAA,QAAO,GAAU,EAAA,QAAO,GAAO,CAAS,EAAG,GAAI,
|
|
1
|
+
{"version":3,"file":"Tag.cjs","names":[],"sources":["../../../src/components/Tag/Tag.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Tag.module.css\";\n\nexport type TagVariant = \"neutral\" | \"primary\" | \"success\" | \"warning\" | \"danger\" | \"info\";\nexport type TagSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface TagProps extends Omit<HTMLAttributes<HTMLSpanElement>, \"onRemove\"> {\n /** Visual variant. Default `\"neutral\"`. */\n variant?: TagVariant;\n /** Visual size. Default `\"md\"`. */\n size?: TagSize;\n /** When set, renders a close button that fires this callback. */\n onRemove?: () => void;\n /** Custom remove label for screen readers. Default `\"Remover\"`. */\n removeLabel?: string;\n children?: ReactNode;\n}\n\n/**\n * Removable chip — used for filter tokens, applied search filters,\n * selected entities. Different from `Badge` (status-only, not removable).\n *\n * @example\n * <Tag variant=\"primary\" onRemove={() => removeFilter(\"sao-paulo\")}>\n * São Paulo\n * </Tag>\n */\nexport function Tag({\n variant = \"neutral\",\n size = \"md\",\n onRemove,\n removeLabel = \"Remover\",\n className,\n children,\n ...props\n}: TagProps) {\n return (\n <span className={cn(styles.tag, styles[variant], styles[size], className)} {...props}>\n <span className={styles.label}>{children}</span>\n {onRemove && (\n <button\n type=\"button\"\n className={styles.remove}\n aria-label={removeLabel}\n onClick={onRemove}\n >\n ×\n </button>\n )}\n </span>\n );\n}\n"],"mappings":"uGA4BA,SAAgB,EAAI,CAChB,UAAU,UACV,OAAO,KACP,WACA,cAAc,UACd,YACA,WACA,GAAG,GACM,CACT,OACI,EAAA,EAAA,KAAA,CAAC,OAAD,CAAM,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,EAAA,QAAO,GAAU,EAAA,QAAO,GAAO,CAAS,EAAG,GAAI,EAA/E,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,MAAQ,UAAe,CAAA,EAC9C,IACG,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,OAClB,aAAY,EACZ,QAAS,EACZ,SAAA,GAEO,CAAA,CAEV,GAEd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tag.js","names":[],"sources":["../../../src/components/Tag/Tag.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Tag.module.css\";\n\nexport type TagVariant = \"neutral\" | \"primary\" | \"success\" | \"warning\" | \"danger\" | \"info\";\nexport type TagSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface TagProps extends Omit<HTMLAttributes<HTMLSpanElement>, \"onRemove\"> {\n /** Visual variant. Default `\"neutral\"`. */\n variant?: TagVariant;\n /** Visual size. Default `\"md\"`. */\n size?: TagSize;\n /** When set, renders a close button that fires this callback. */\n onRemove?: () => void;\n /** Custom remove label for screen readers. Default `\"Remover\"`. */\n removeLabel?: string;\n children?: ReactNode;\n}\n\n/**\n * Removable chip — used for filter tokens, applied search filters,\n * selected entities. Different from `Badge` (status-only, not removable).\n *\n * @example\n * <Tag variant=\"primary\" onRemove={() => removeFilter(\"sao-paulo\")}>\n * São Paulo\n * </Tag>\n */\nexport function Tag({\n variant = \"neutral\",\n size = \"md\",\n onRemove,\n removeLabel = \"Remover\",\n className,\n children,\n ...props\n}: TagProps) {\n return (\n <span className={cn(styles.tag, styles[variant], styles[size], className)} {...props}>\n <span className={styles.label}>{children}</span>\n {onRemove && (\n <button\n type=\"button\"\n className={styles.remove}\n aria-label={removeLabel}\n onClick={onRemove}\n >\n ×\n </button>\n )}\n </span>\n );\n}\n"],"mappings":";;;;AA4BA,SAAgB,EAAI,EAChB,aAAU,WACV,UAAO,MACP,aACA,iBAAc,WACd,cACA,aACA,GAAG,KACM;CACT,OACI,kBAAC,QAAD;EAAM,WAAW,EAAG,EAAO,KAAK,EAAO,IAAU,EAAO,IAAO,CAAS;EAAG,GAAI;
|
|
1
|
+
{"version":3,"file":"Tag.js","names":[],"sources":["../../../src/components/Tag/Tag.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Tag.module.css\";\n\nexport type TagVariant = \"neutral\" | \"primary\" | \"success\" | \"warning\" | \"danger\" | \"info\";\nexport type TagSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface TagProps extends Omit<HTMLAttributes<HTMLSpanElement>, \"onRemove\"> {\n /** Visual variant. Default `\"neutral\"`. */\n variant?: TagVariant;\n /** Visual size. Default `\"md\"`. */\n size?: TagSize;\n /** When set, renders a close button that fires this callback. */\n onRemove?: () => void;\n /** Custom remove label for screen readers. Default `\"Remover\"`. */\n removeLabel?: string;\n children?: ReactNode;\n}\n\n/**\n * Removable chip — used for filter tokens, applied search filters,\n * selected entities. Different from `Badge` (status-only, not removable).\n *\n * @example\n * <Tag variant=\"primary\" onRemove={() => removeFilter(\"sao-paulo\")}>\n * São Paulo\n * </Tag>\n */\nexport function Tag({\n variant = \"neutral\",\n size = \"md\",\n onRemove,\n removeLabel = \"Remover\",\n className,\n children,\n ...props\n}: TagProps) {\n return (\n <span className={cn(styles.tag, styles[variant], styles[size], className)} {...props}>\n <span className={styles.label}>{children}</span>\n {onRemove && (\n <button\n type=\"button\"\n className={styles.remove}\n aria-label={removeLabel}\n onClick={onRemove}\n >\n ×\n </button>\n )}\n </span>\n );\n}\n"],"mappings":";;;;AA4BA,SAAgB,EAAI,EAChB,aAAU,WACV,UAAO,MACP,aACA,iBAAc,WACd,cACA,aACA,GAAG,KACM;CACT,OACI,kBAAC,QAAD;EAAM,WAAW,EAAG,EAAO,KAAK,EAAO,IAAU,EAAO,IAAO,CAAS;EAAG,GAAI;EAA/E,UAAA,CACI,kBAAC,QAAD;GAAM,WAAW,EAAO;GAAQ;EAAe,CAAA,GAC9C,KACG,kBAAC,UAAD;GACI,MAAK;GACL,WAAW,EAAO;GAClB,cAAY;GACZ,SAAS;GACZ,UAAA;EAEO,CAAA,CAEV;;AAEd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Textarea.cjs","names":[],"sources":["../../../src/components/Textarea/Textarea.tsx"],"sourcesContent":["import { forwardRef, useId } from \"react\";\nimport type { TextareaHTMLAttributes } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Textarea.module.css\";\n\nexport interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {\n label?: string;\n helperText?: string;\n error?: string;\n wrapperClassName?: string;\n}\n\n/**\n * Multi-line text input. Mirrors the {@link Input} API for label/helper/error.\n */\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(function Textarea(\n { label, helperText, error, wrapperClassName, className, id, required, ...props },\n ref,\n) {\n const generatedId = useId();\n const textareaId = id ?? generatedId;\n\n return (\n <div className={cn(styles.wrapper, error && styles.error, wrapperClassName)}>\n {label && (\n <label htmlFor={textareaId} className={styles.label}>\n {label}\n {required && <span className={styles.required}>*</span>}\n </label>\n )}\n <textarea\n ref={ref}\n id={textareaId}\n aria-invalid={!!error}\n required={required}\n className={cn(styles.textarea, className)}\n {...props}\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":"+HAeA,IAAa,GAAA,
|
|
1
|
+
{"version":3,"file":"Textarea.cjs","names":[],"sources":["../../../src/components/Textarea/Textarea.tsx"],"sourcesContent":["import { forwardRef, useId } from \"react\";\nimport type { TextareaHTMLAttributes } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Textarea.module.css\";\n\nexport interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {\n label?: string;\n helperText?: string;\n error?: string;\n wrapperClassName?: string;\n}\n\n/**\n * Multi-line text input. Mirrors the {@link Input} API for label/helper/error.\n */\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(function Textarea(\n { label, helperText, error, wrapperClassName, className, id, required, ...props },\n ref,\n) {\n const generatedId = useId();\n const textareaId = id ?? generatedId;\n\n return (\n <div className={cn(styles.wrapper, error && styles.error, wrapperClassName)}>\n {label && (\n <label htmlFor={textareaId} className={styles.label}>\n {label}\n {required && <span className={styles.required}>*</span>}\n </label>\n )}\n <textarea\n ref={ref}\n id={textareaId}\n aria-invalid={!!error}\n required={required}\n className={cn(styles.textarea, className)}\n {...props}\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":"+HAeA,IAAa,GAAA,EAAW,EAAA,WAAA,CAA+C,SACnE,CAAE,QAAO,aAAY,QAAO,mBAAkB,YAAW,KAAI,WAAU,GAAG,GAC1E,EACF,CACE,IAAM,GAAA,EAAc,EAAA,MAAA,CAAM,EACpB,EAAa,GAAM,EAEzB,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,GAAS,EAAA,QAAO,MAAO,CAAgB,EAA1E,SAAA,CACK,IACG,EAAA,EAAA,KAAA,CAAC,QAAD,CAAO,QAAS,EAAY,UAAW,EAAA,QAAO,MAA9C,SAAA,CACK,EACA,IAAY,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,SAAU,SAAA,GAAO,CAAA,CACnD,KAEX,EAAA,EAAA,IAAA,CAAC,WAAD,CACS,MACL,GAAI,EACJ,eAAc,CAAC,CAAC,EACN,WACV,UAAW,EAAA,GAAG,EAAA,QAAO,SAAU,CAAS,EACxC,GAAI,CACP,CAAA,EACA,GACG,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,UAAY,SAAA,CAAY,CAAA,EAChD,GACA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,OAAS,SAAA,CAAiB,CAAA,EAClD,IACH,GAEb,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Textarea.js","names":[],"sources":["../../../src/components/Textarea/Textarea.tsx"],"sourcesContent":["import { forwardRef, useId } from \"react\";\nimport type { TextareaHTMLAttributes } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Textarea.module.css\";\n\nexport interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {\n label?: string;\n helperText?: string;\n error?: string;\n wrapperClassName?: string;\n}\n\n/**\n * Multi-line text input. Mirrors the {@link Input} API for label/helper/error.\n */\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(function Textarea(\n { label, helperText, error, wrapperClassName, className, id, required, ...props },\n ref,\n) {\n const generatedId = useId();\n const textareaId = id ?? generatedId;\n\n return (\n <div className={cn(styles.wrapper, error && styles.error, wrapperClassName)}>\n {label && (\n <label htmlFor={textareaId} className={styles.label}>\n {label}\n {required && <span className={styles.required}>*</span>}\n </label>\n )}\n <textarea\n ref={ref}\n id={textareaId}\n aria-invalid={!!error}\n required={required}\n className={cn(styles.textarea, className)}\n {...props}\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":";;;;;AAeA,IAAa,IAAW,EAA+C,SACnE,EAAE,UAAO,eAAY,UAAO,qBAAkB,cAAW,OAAI,aAAU,GAAG,KAC1E,GACF;CACE,IAAM,IAAc,EAAM,GACpB,IAAa,KAAM;CAEzB,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,KAAS,EAAO,OAAO,CAAgB;
|
|
1
|
+
{"version":3,"file":"Textarea.js","names":[],"sources":["../../../src/components/Textarea/Textarea.tsx"],"sourcesContent":["import { forwardRef, useId } from \"react\";\nimport type { TextareaHTMLAttributes } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Textarea.module.css\";\n\nexport interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {\n label?: string;\n helperText?: string;\n error?: string;\n wrapperClassName?: string;\n}\n\n/**\n * Multi-line text input. Mirrors the {@link Input} API for label/helper/error.\n */\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(function Textarea(\n { label, helperText, error, wrapperClassName, className, id, required, ...props },\n ref,\n) {\n const generatedId = useId();\n const textareaId = id ?? generatedId;\n\n return (\n <div className={cn(styles.wrapper, error && styles.error, wrapperClassName)}>\n {label && (\n <label htmlFor={textareaId} className={styles.label}>\n {label}\n {required && <span className={styles.required}>*</span>}\n </label>\n )}\n <textarea\n ref={ref}\n id={textareaId}\n aria-invalid={!!error}\n required={required}\n className={cn(styles.textarea, className)}\n {...props}\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":";;;;;AAeA,IAAa,IAAW,EAA+C,SACnE,EAAE,UAAO,eAAY,UAAO,qBAAkB,cAAW,OAAI,aAAU,GAAG,KAC1E,GACF;CACE,IAAM,IAAc,EAAM,GACpB,IAAa,KAAM;CAEzB,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,KAAS,EAAO,OAAO,CAAgB;EAA1E,UAAA;GACK,KACG,kBAAC,SAAD;IAAO,SAAS;IAAY,WAAW,EAAO;IAA9C,UAAA,CACK,GACA,KAAY,kBAAC,QAAD;KAAM,WAAW,EAAO;KAAU,UAAA;IAAO,CAAA,CACnD;;GAEX,kBAAC,YAAD;IACS;IACL,IAAI;IACJ,gBAAc,CAAC,CAAC;IACN;IACV,WAAW,EAAG,EAAO,UAAU,CAAS;IACxC,GAAI;GACP,CAAA;GACA,IACG,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAY,UAAA;GAAY,CAAA,IAChD,IACA,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAS,UAAA;GAAiB,CAAA,IAClD;EACH;;AAEb,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimePicker.cjs","names":[],"sources":["../../../src/components/TimePicker/TimePicker.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — minuteStep and\n * use12Hours change both the list of options and how a typed value parses, so the\n * body holds parsing, formatting and the option list together; the remaining props\n * are the shared field contract.\n */\nimport { useId, useMemo } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./TimePicker.module.css\";\n\nexport interface TimePickerProps {\n /** Selected time as a 24h `\"HH:MM\"` string (e.g. `\"14:30\"`). May be `\"\"` for none. */\n value: string;\n /** Fired with the new 24h `\"HH:MM\"` string whenever a cell is picked. */\n onChange: (value: string) => void;\n /** Granularity of the minute column. Defaults to `5`. */\n minuteStep?: number;\n /** When true, show a 1–12 hour column plus an AM/PM column (still emits 24h). */\n use12Hours?: boolean;\n label?: string;\n helperText?: string;\n disabled?: boolean;\n className?: string;\n}\n\ntype Period = \"AM\" | \"PM\";\n\ninterface ParsedTime {\n hour24: number | null;\n minute: number | null;\n}\n\nfunction pad2(value: number): string {\n return value.toString().padStart(2, \"0\");\n}\n\n/** Parse a 24h `\"HH:MM\"` string into hour/minute numbers, or nulls when empty/invalid. */\nfunction parseValue(value: string): ParsedTime {\n const match = /^(\\d{1,2}):(\\d{1,2})$/.exec(value.trim());\n if (!match) return { hour24: null, minute: null };\n const hour24 = Number(match[1]);\n const minute = Number(match[2]);\n if (hour24 < 0 || hour24 > 23 || minute < 0 || minute > 59) {\n return { hour24: null, minute: null };\n }\n return { hour24, minute };\n}\n\n/** Convert a 24h hour into its 12h display hour (1–12). */\nfunction to12Hour(hour24: number): number {\n const mod = hour24 % 12;\n return mod === 0 ? 12 : mod;\n}\n\n/** Convert a 12h display hour + period into a 24h hour (0–23). */\nfunction to24Hour(hour12: number, period: Period): number {\n const base = hour12 % 12;\n return period === \"PM\" ? base + 12 : base;\n}\n\n/**\n * TimePicker — inline, dependency-free time picker with Material \"spinner column\" styling.\n *\n * Renders scrollable columns of selectable cells (hours, minutes, and AM/PM when\n * `use12Hours`). Always emits a 24h `\"HH:MM\"` string via `onChange`, regardless of\n * whether the 12h display is enabled.\n */\nexport function TimePicker({\n value,\n onChange,\n minuteStep = 5,\n use12Hours = false,\n label,\n helperText,\n disabled,\n className,\n}: TimePickerProps) {\n const id = useId();\n const { hour24, minute } = useMemo(() => parseValue(value), [value]);\n\n const period: Period = hour24 !== null && hour24 >= 12 ? \"PM\" : \"AM\";\n\n const hourCells = useMemo<number[]>(() => {\n if (use12Hours) {\n return Array.from({ length: 12 }, (_, index) => index + 1);\n }\n return Array.from({ length: 24 }, (_, index) => index);\n }, [use12Hours]);\n\n const minuteCells = useMemo<number[]>(() => {\n const step = minuteStep > 0 ? minuteStep : 1;\n const cells: number[] = [];\n for (let current = 0; current < 60; current += step) {\n cells.push(current);\n }\n return cells;\n }, [minuteStep]);\n\n const selectedHourDisplay = hour24 === null ? null : use12Hours ? to12Hour(hour24) : hour24;\n\n const emit = (nextHour24: number, nextMinute: number): void => {\n onChange(`${pad2(nextHour24)}:${pad2(nextMinute)}`);\n };\n\n const handleHour = (displayHour: number): void => {\n if (disabled) return;\n const nextMinute = minute ?? 0;\n const nextHour24 = use12Hours ? to24Hour(displayHour, period) : displayHour;\n emit(nextHour24, nextMinute);\n };\n\n const handleMinute = (nextMinute: number): void => {\n if (disabled) return;\n const baseHour24 = hour24 ?? (use12Hours ? to24Hour(12, \"AM\") : 0);\n emit(baseHour24, nextMinute);\n };\n\n const handlePeriod = (nextPeriod: Period): void => {\n if (disabled) return;\n const displayHour = selectedHourDisplay ?? 12;\n const nextMinute = minute ?? 0;\n emit(to24Hour(displayHour, nextPeriod), nextMinute);\n };\n\n return (\n <div className={cn(styles.wrapper, disabled && styles.disabled, className)}>\n {label && (\n <span id={`${id}-label`} className={styles.label}>\n {label}\n </span>\n )}\n <div className={styles.columns}>\n <ul role=\"listbox\" aria-label=\"Horas\" className={styles.column}>\n {hourCells.map((cell) => {\n const active = cell === selectedHourDisplay;\n return (\n <li key={cell} className={styles.cellWrapper}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={active}\n disabled={disabled}\n className={cn(styles.cell, active && styles.active)}\n onClick={() => handleHour(cell)}\n >\n {use12Hours ? cell : pad2(cell)}\n </button>\n </li>\n );\n })}\n </ul>\n <ul role=\"listbox\" aria-label=\"Minutos\" className={styles.column}>\n {minuteCells.map((cell) => {\n const active = cell === minute;\n return (\n <li key={cell} className={styles.cellWrapper}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={active}\n disabled={disabled}\n className={cn(styles.cell, active && styles.active)}\n onClick={() => handleMinute(cell)}\n >\n {pad2(cell)}\n </button>\n </li>\n );\n })}\n </ul>\n {use12Hours && (\n <ul role=\"listbox\" aria-label=\"Período\" className={styles.column}>\n {([\"AM\", \"PM\"] as Period[]).map((cell) => {\n const active = selectedHourDisplay !== null && cell === period;\n return (\n <li key={cell} className={styles.cellWrapper}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={active}\n disabled={disabled}\n className={cn(styles.cell, active && styles.active)}\n onClick={() => handlePeriod(cell)}\n >\n {cell}\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n {helperText && <span className={styles.helper}>{helperText}</span>}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TimePicker.cjs","names":[],"sources":["../../../src/components/TimePicker/TimePicker.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — minuteStep and\n * use12Hours change both the list of options and how a typed value parses, so the\n * body holds parsing, formatting and the option list together; the remaining props\n * are the shared field contract.\n */\nimport { useId, useMemo } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./TimePicker.module.css\";\n\nexport interface TimePickerProps {\n /** Selected time as a 24h `\"HH:MM\"` string (e.g. `\"14:30\"`). May be `\"\"` for none. */\n value: string;\n /** Fired with the new 24h `\"HH:MM\"` string whenever a cell is picked. */\n onChange: (value: string) => void;\n /** Granularity of the minute column. Defaults to `5`. */\n minuteStep?: number;\n /** When true, show a 1–12 hour column plus an AM/PM column (still emits 24h). */\n use12Hours?: boolean;\n label?: string;\n helperText?: string;\n disabled?: boolean;\n className?: string;\n}\n\ntype Period = \"AM\" | \"PM\";\n\ninterface ParsedTime {\n hour24: number | null;\n minute: number | null;\n}\n\nfunction pad2(value: number): string {\n return value.toString().padStart(2, \"0\");\n}\n\n/** Parse a 24h `\"HH:MM\"` string into hour/minute numbers, or nulls when empty/invalid. */\nfunction parseValue(value: string): ParsedTime {\n const match = /^(\\d{1,2}):(\\d{1,2})$/.exec(value.trim());\n if (!match) return { hour24: null, minute: null };\n const hour24 = Number(match[1]);\n const minute = Number(match[2]);\n if (hour24 < 0 || hour24 > 23 || minute < 0 || minute > 59) {\n return { hour24: null, minute: null };\n }\n return { hour24, minute };\n}\n\n/** Convert a 24h hour into its 12h display hour (1–12). */\nfunction to12Hour(hour24: number): number {\n const mod = hour24 % 12;\n return mod === 0 ? 12 : mod;\n}\n\n/** Convert a 12h display hour + period into a 24h hour (0–23). */\nfunction to24Hour(hour12: number, period: Period): number {\n const base = hour12 % 12;\n return period === \"PM\" ? base + 12 : base;\n}\n\n/**\n * TimePicker — inline, dependency-free time picker with Material \"spinner column\" styling.\n *\n * Renders scrollable columns of selectable cells (hours, minutes, and AM/PM when\n * `use12Hours`). Always emits a 24h `\"HH:MM\"` string via `onChange`, regardless of\n * whether the 12h display is enabled.\n */\nexport function TimePicker({\n value,\n onChange,\n minuteStep = 5,\n use12Hours = false,\n label,\n helperText,\n disabled,\n className,\n}: TimePickerProps) {\n const id = useId();\n const { hour24, minute } = useMemo(() => parseValue(value), [value]);\n\n const period: Period = hour24 !== null && hour24 >= 12 ? \"PM\" : \"AM\";\n\n const hourCells = useMemo<number[]>(() => {\n if (use12Hours) {\n return Array.from({ length: 12 }, (_, index) => index + 1);\n }\n return Array.from({ length: 24 }, (_, index) => index);\n }, [use12Hours]);\n\n const minuteCells = useMemo<number[]>(() => {\n const step = minuteStep > 0 ? minuteStep : 1;\n const cells: number[] = [];\n for (let current = 0; current < 60; current += step) {\n cells.push(current);\n }\n return cells;\n }, [minuteStep]);\n\n const selectedHourDisplay = hour24 === null ? null : use12Hours ? to12Hour(hour24) : hour24;\n\n const emit = (nextHour24: number, nextMinute: number): void => {\n onChange(`${pad2(nextHour24)}:${pad2(nextMinute)}`);\n };\n\n const handleHour = (displayHour: number): void => {\n if (disabled) return;\n const nextMinute = minute ?? 0;\n const nextHour24 = use12Hours ? to24Hour(displayHour, period) : displayHour;\n emit(nextHour24, nextMinute);\n };\n\n const handleMinute = (nextMinute: number): void => {\n if (disabled) return;\n const baseHour24 = hour24 ?? (use12Hours ? to24Hour(12, \"AM\") : 0);\n emit(baseHour24, nextMinute);\n };\n\n const handlePeriod = (nextPeriod: Period): void => {\n if (disabled) return;\n const displayHour = selectedHourDisplay ?? 12;\n const nextMinute = minute ?? 0;\n emit(to24Hour(displayHour, nextPeriod), nextMinute);\n };\n\n return (\n <div className={cn(styles.wrapper, disabled && styles.disabled, className)}>\n {label && (\n <span id={`${id}-label`} className={styles.label}>\n {label}\n </span>\n )}\n <div className={styles.columns}>\n <ul role=\"listbox\" aria-label=\"Horas\" className={styles.column}>\n {hourCells.map((cell) => {\n const active = cell === selectedHourDisplay;\n return (\n <li key={cell} className={styles.cellWrapper}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={active}\n disabled={disabled}\n className={cn(styles.cell, active && styles.active)}\n onClick={() => handleHour(cell)}\n >\n {use12Hours ? cell : pad2(cell)}\n </button>\n </li>\n );\n })}\n </ul>\n <ul role=\"listbox\" aria-label=\"Minutos\" className={styles.column}>\n {minuteCells.map((cell) => {\n const active = cell === minute;\n return (\n <li key={cell} className={styles.cellWrapper}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={active}\n disabled={disabled}\n className={cn(styles.cell, active && styles.active)}\n onClick={() => handleMinute(cell)}\n >\n {pad2(cell)}\n </button>\n </li>\n );\n })}\n </ul>\n {use12Hours && (\n <ul role=\"listbox\" aria-label=\"Período\" className={styles.column}>\n {([\"AM\", \"PM\"] as Period[]).map((cell) => {\n const active = selectedHourDisplay !== null && cell === period;\n return (\n <li key={cell} className={styles.cellWrapper}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={active}\n disabled={disabled}\n className={cn(styles.cell, active && styles.active)}\n onClick={() => handlePeriod(cell)}\n >\n {cell}\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n {helperText && <span className={styles.helper}>{helperText}</span>}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimePicker.js","names":[],"sources":["../../../src/components/TimePicker/TimePicker.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — minuteStep and\n * use12Hours change both the list of options and how a typed value parses, so the\n * body holds parsing, formatting and the option list together; the remaining props\n * are the shared field contract.\n */\nimport { useId, useMemo } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./TimePicker.module.css\";\n\nexport interface TimePickerProps {\n /** Selected time as a 24h `\"HH:MM\"` string (e.g. `\"14:30\"`). May be `\"\"` for none. */\n value: string;\n /** Fired with the new 24h `\"HH:MM\"` string whenever a cell is picked. */\n onChange: (value: string) => void;\n /** Granularity of the minute column. Defaults to `5`. */\n minuteStep?: number;\n /** When true, show a 1–12 hour column plus an AM/PM column (still emits 24h). */\n use12Hours?: boolean;\n label?: string;\n helperText?: string;\n disabled?: boolean;\n className?: string;\n}\n\ntype Period = \"AM\" | \"PM\";\n\ninterface ParsedTime {\n hour24: number | null;\n minute: number | null;\n}\n\nfunction pad2(value: number): string {\n return value.toString().padStart(2, \"0\");\n}\n\n/** Parse a 24h `\"HH:MM\"` string into hour/minute numbers, or nulls when empty/invalid. */\nfunction parseValue(value: string): ParsedTime {\n const match = /^(\\d{1,2}):(\\d{1,2})$/.exec(value.trim());\n if (!match) return { hour24: null, minute: null };\n const hour24 = Number(match[1]);\n const minute = Number(match[2]);\n if (hour24 < 0 || hour24 > 23 || minute < 0 || minute > 59) {\n return { hour24: null, minute: null };\n }\n return { hour24, minute };\n}\n\n/** Convert a 24h hour into its 12h display hour (1–12). */\nfunction to12Hour(hour24: number): number {\n const mod = hour24 % 12;\n return mod === 0 ? 12 : mod;\n}\n\n/** Convert a 12h display hour + period into a 24h hour (0–23). */\nfunction to24Hour(hour12: number, period: Period): number {\n const base = hour12 % 12;\n return period === \"PM\" ? base + 12 : base;\n}\n\n/**\n * TimePicker — inline, dependency-free time picker with Material \"spinner column\" styling.\n *\n * Renders scrollable columns of selectable cells (hours, minutes, and AM/PM when\n * `use12Hours`). Always emits a 24h `\"HH:MM\"` string via `onChange`, regardless of\n * whether the 12h display is enabled.\n */\nexport function TimePicker({\n value,\n onChange,\n minuteStep = 5,\n use12Hours = false,\n label,\n helperText,\n disabled,\n className,\n}: TimePickerProps) {\n const id = useId();\n const { hour24, minute } = useMemo(() => parseValue(value), [value]);\n\n const period: Period = hour24 !== null && hour24 >= 12 ? \"PM\" : \"AM\";\n\n const hourCells = useMemo<number[]>(() => {\n if (use12Hours) {\n return Array.from({ length: 12 }, (_, index) => index + 1);\n }\n return Array.from({ length: 24 }, (_, index) => index);\n }, [use12Hours]);\n\n const minuteCells = useMemo<number[]>(() => {\n const step = minuteStep > 0 ? minuteStep : 1;\n const cells: number[] = [];\n for (let current = 0; current < 60; current += step) {\n cells.push(current);\n }\n return cells;\n }, [minuteStep]);\n\n const selectedHourDisplay = hour24 === null ? null : use12Hours ? to12Hour(hour24) : hour24;\n\n const emit = (nextHour24: number, nextMinute: number): void => {\n onChange(`${pad2(nextHour24)}:${pad2(nextMinute)}`);\n };\n\n const handleHour = (displayHour: number): void => {\n if (disabled) return;\n const nextMinute = minute ?? 0;\n const nextHour24 = use12Hours ? to24Hour(displayHour, period) : displayHour;\n emit(nextHour24, nextMinute);\n };\n\n const handleMinute = (nextMinute: number): void => {\n if (disabled) return;\n const baseHour24 = hour24 ?? (use12Hours ? to24Hour(12, \"AM\") : 0);\n emit(baseHour24, nextMinute);\n };\n\n const handlePeriod = (nextPeriod: Period): void => {\n if (disabled) return;\n const displayHour = selectedHourDisplay ?? 12;\n const nextMinute = minute ?? 0;\n emit(to24Hour(displayHour, nextPeriod), nextMinute);\n };\n\n return (\n <div className={cn(styles.wrapper, disabled && styles.disabled, className)}>\n {label && (\n <span id={`${id}-label`} className={styles.label}>\n {label}\n </span>\n )}\n <div className={styles.columns}>\n <ul role=\"listbox\" aria-label=\"Horas\" className={styles.column}>\n {hourCells.map((cell) => {\n const active = cell === selectedHourDisplay;\n return (\n <li key={cell} className={styles.cellWrapper}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={active}\n disabled={disabled}\n className={cn(styles.cell, active && styles.active)}\n onClick={() => handleHour(cell)}\n >\n {use12Hours ? cell : pad2(cell)}\n </button>\n </li>\n );\n })}\n </ul>\n <ul role=\"listbox\" aria-label=\"Minutos\" className={styles.column}>\n {minuteCells.map((cell) => {\n const active = cell === minute;\n return (\n <li key={cell} className={styles.cellWrapper}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={active}\n disabled={disabled}\n className={cn(styles.cell, active && styles.active)}\n onClick={() => handleMinute(cell)}\n >\n {pad2(cell)}\n </button>\n </li>\n );\n })}\n </ul>\n {use12Hours && (\n <ul role=\"listbox\" aria-label=\"Período\" className={styles.column}>\n {([\"AM\", \"PM\"] as Period[]).map((cell) => {\n const active = selectedHourDisplay !== null && cell === period;\n return (\n <li key={cell} className={styles.cellWrapper}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={active}\n disabled={disabled}\n className={cn(styles.cell, active && styles.active)}\n onClick={() => handlePeriod(cell)}\n >\n {cell}\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n {helperText && <span className={styles.helper}>{helperText}</span>}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TimePicker.js","names":[],"sources":["../../../src/components/TimePicker/TimePicker.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — minuteStep and\n * use12Hours change both the list of options and how a typed value parses, so the\n * body holds parsing, formatting and the option list together; the remaining props\n * are the shared field contract.\n */\nimport { useId, useMemo } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./TimePicker.module.css\";\n\nexport interface TimePickerProps {\n /** Selected time as a 24h `\"HH:MM\"` string (e.g. `\"14:30\"`). May be `\"\"` for none. */\n value: string;\n /** Fired with the new 24h `\"HH:MM\"` string whenever a cell is picked. */\n onChange: (value: string) => void;\n /** Granularity of the minute column. Defaults to `5`. */\n minuteStep?: number;\n /** When true, show a 1–12 hour column plus an AM/PM column (still emits 24h). */\n use12Hours?: boolean;\n label?: string;\n helperText?: string;\n disabled?: boolean;\n className?: string;\n}\n\ntype Period = \"AM\" | \"PM\";\n\ninterface ParsedTime {\n hour24: number | null;\n minute: number | null;\n}\n\nfunction pad2(value: number): string {\n return value.toString().padStart(2, \"0\");\n}\n\n/** Parse a 24h `\"HH:MM\"` string into hour/minute numbers, or nulls when empty/invalid. */\nfunction parseValue(value: string): ParsedTime {\n const match = /^(\\d{1,2}):(\\d{1,2})$/.exec(value.trim());\n if (!match) return { hour24: null, minute: null };\n const hour24 = Number(match[1]);\n const minute = Number(match[2]);\n if (hour24 < 0 || hour24 > 23 || minute < 0 || minute > 59) {\n return { hour24: null, minute: null };\n }\n return { hour24, minute };\n}\n\n/** Convert a 24h hour into its 12h display hour (1–12). */\nfunction to12Hour(hour24: number): number {\n const mod = hour24 % 12;\n return mod === 0 ? 12 : mod;\n}\n\n/** Convert a 12h display hour + period into a 24h hour (0–23). */\nfunction to24Hour(hour12: number, period: Period): number {\n const base = hour12 % 12;\n return period === \"PM\" ? base + 12 : base;\n}\n\n/**\n * TimePicker — inline, dependency-free time picker with Material \"spinner column\" styling.\n *\n * Renders scrollable columns of selectable cells (hours, minutes, and AM/PM when\n * `use12Hours`). Always emits a 24h `\"HH:MM\"` string via `onChange`, regardless of\n * whether the 12h display is enabled.\n */\nexport function TimePicker({\n value,\n onChange,\n minuteStep = 5,\n use12Hours = false,\n label,\n helperText,\n disabled,\n className,\n}: TimePickerProps) {\n const id = useId();\n const { hour24, minute } = useMemo(() => parseValue(value), [value]);\n\n const period: Period = hour24 !== null && hour24 >= 12 ? \"PM\" : \"AM\";\n\n const hourCells = useMemo<number[]>(() => {\n if (use12Hours) {\n return Array.from({ length: 12 }, (_, index) => index + 1);\n }\n return Array.from({ length: 24 }, (_, index) => index);\n }, [use12Hours]);\n\n const minuteCells = useMemo<number[]>(() => {\n const step = minuteStep > 0 ? minuteStep : 1;\n const cells: number[] = [];\n for (let current = 0; current < 60; current += step) {\n cells.push(current);\n }\n return cells;\n }, [minuteStep]);\n\n const selectedHourDisplay = hour24 === null ? null : use12Hours ? to12Hour(hour24) : hour24;\n\n const emit = (nextHour24: number, nextMinute: number): void => {\n onChange(`${pad2(nextHour24)}:${pad2(nextMinute)}`);\n };\n\n const handleHour = (displayHour: number): void => {\n if (disabled) return;\n const nextMinute = minute ?? 0;\n const nextHour24 = use12Hours ? to24Hour(displayHour, period) : displayHour;\n emit(nextHour24, nextMinute);\n };\n\n const handleMinute = (nextMinute: number): void => {\n if (disabled) return;\n const baseHour24 = hour24 ?? (use12Hours ? to24Hour(12, \"AM\") : 0);\n emit(baseHour24, nextMinute);\n };\n\n const handlePeriod = (nextPeriod: Period): void => {\n if (disabled) return;\n const displayHour = selectedHourDisplay ?? 12;\n const nextMinute = minute ?? 0;\n emit(to24Hour(displayHour, nextPeriod), nextMinute);\n };\n\n return (\n <div className={cn(styles.wrapper, disabled && styles.disabled, className)}>\n {label && (\n <span id={`${id}-label`} className={styles.label}>\n {label}\n </span>\n )}\n <div className={styles.columns}>\n <ul role=\"listbox\" aria-label=\"Horas\" className={styles.column}>\n {hourCells.map((cell) => {\n const active = cell === selectedHourDisplay;\n return (\n <li key={cell} className={styles.cellWrapper}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={active}\n disabled={disabled}\n className={cn(styles.cell, active && styles.active)}\n onClick={() => handleHour(cell)}\n >\n {use12Hours ? cell : pad2(cell)}\n </button>\n </li>\n );\n })}\n </ul>\n <ul role=\"listbox\" aria-label=\"Minutos\" className={styles.column}>\n {minuteCells.map((cell) => {\n const active = cell === minute;\n return (\n <li key={cell} className={styles.cellWrapper}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={active}\n disabled={disabled}\n className={cn(styles.cell, active && styles.active)}\n onClick={() => handleMinute(cell)}\n >\n {pad2(cell)}\n </button>\n </li>\n );\n })}\n </ul>\n {use12Hours && (\n <ul role=\"listbox\" aria-label=\"Período\" className={styles.column}>\n {([\"AM\", \"PM\"] as Period[]).map((cell) => {\n const active = selectedHourDisplay !== null && cell === period;\n return (\n <li key={cell} className={styles.cellWrapper}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={active}\n disabled={disabled}\n className={cn(styles.cell, active && styles.active)}\n onClick={() => handlePeriod(cell)}\n >\n {cell}\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n {helperText && <span className={styles.helper}>{helperText}</span>}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Timeline.cjs","names":[],"sources":["../../../src/components/Timeline/Timeline.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Timeline.module.css\";\n\nexport type TimelineMarker = \"primary\" | \"success\" | \"warning\" | \"danger\" | \"neutral\";\n\nexport interface TimelineItem {\n /** Stable identifier (used as React key). */\n id: string;\n /** Title rendered as the entry headline. */\n title: ReactNode;\n /** Optional subtitle / description below the title. */\n description?: ReactNode;\n /** Right-aligned meta column (timestamps, durations). */\n meta?: ReactNode;\n /** Optional custom icon rendered inside the marker. */\n icon?: ReactNode;\n /** Marker color. Default `\"primary\"`. */\n marker?: TimelineMarker;\n}\n\nexport interface TimelineProps extends HTMLAttributes<HTMLOListElement> {\n items: TimelineItem[];\n /** Show the connecting line between markers. Default `true`. */\n connector?: boolean;\n}\n\n/**\n * Vertical event timeline — activity feeds, order trackers, audit logs.\n * Each entry has a marker (color or custom icon), title, optional\n * description and right-aligned meta column.\n *\n * @example\n * <Timeline items={[\n * { id: \"1\", title: \"Pedido criado\", meta: \"10:24\", marker: \"primary\" },\n * { id: \"2\", title: \"Aprovação\", meta: \"10:25\", marker: \"success\" },\n * { id: \"3\", title: \"Saiu pra entrega\", meta: \"11:00\", marker: \"warning\" },\n * ]} />\n */\nexport function Timeline({ items, connector = true, className, ...props }: TimelineProps) {\n return (\n <ol className={cn(styles.timeline, connector && styles.connector, className)} {...props}>\n {items.map((item, index) => {\n const isLast = index === items.length - 1;\n return (\n <li key={item.id} className={styles.item}>\n <div className={styles.markerColumn}>\n <span\n className={cn(\n styles.marker,\n styles[`marker-${item.marker ?? \"primary\"}`],\n )}\n aria-hidden=\"true\"\n >\n {item.icon}\n </span>\n {connector && !isLast && (\n <span className={styles.line} aria-hidden=\"true\" />\n )}\n </div>\n <div className={styles.body}>\n <div className={styles.row}>\n <span className={styles.title}>{item.title}</span>\n {item.meta && <span className={styles.meta}>{item.meta}</span>}\n </div>\n {item.description && (\n <p className={styles.description}>{item.description}</p>\n )}\n </div>\n </li>\n );\n })}\n </ol>\n );\n}\n"],"mappings":"4GAuCA,SAAgB,EAAS,CAAE,QAAO,YAAY,GAAM,YAAW,GAAG,GAAwB,CACtF,OACI,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,GAAG,EAAA,QAAO,SAAU,GAAa,EAAA,QAAO,UAAW,CAAS,EAAG,GAAI,
|
|
1
|
+
{"version":3,"file":"Timeline.cjs","names":[],"sources":["../../../src/components/Timeline/Timeline.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Timeline.module.css\";\n\nexport type TimelineMarker = \"primary\" | \"success\" | \"warning\" | \"danger\" | \"neutral\";\n\nexport interface TimelineItem {\n /** Stable identifier (used as React key). */\n id: string;\n /** Title rendered as the entry headline. */\n title: ReactNode;\n /** Optional subtitle / description below the title. */\n description?: ReactNode;\n /** Right-aligned meta column (timestamps, durations). */\n meta?: ReactNode;\n /** Optional custom icon rendered inside the marker. */\n icon?: ReactNode;\n /** Marker color. Default `\"primary\"`. */\n marker?: TimelineMarker;\n}\n\nexport interface TimelineProps extends HTMLAttributes<HTMLOListElement> {\n items: TimelineItem[];\n /** Show the connecting line between markers. Default `true`. */\n connector?: boolean;\n}\n\n/**\n * Vertical event timeline — activity feeds, order trackers, audit logs.\n * Each entry has a marker (color or custom icon), title, optional\n * description and right-aligned meta column.\n *\n * @example\n * <Timeline items={[\n * { id: \"1\", title: \"Pedido criado\", meta: \"10:24\", marker: \"primary\" },\n * { id: \"2\", title: \"Aprovação\", meta: \"10:25\", marker: \"success\" },\n * { id: \"3\", title: \"Saiu pra entrega\", meta: \"11:00\", marker: \"warning\" },\n * ]} />\n */\nexport function Timeline({ items, connector = true, className, ...props }: TimelineProps) {\n return (\n <ol className={cn(styles.timeline, connector && styles.connector, className)} {...props}>\n {items.map((item, index) => {\n const isLast = index === items.length - 1;\n return (\n <li key={item.id} className={styles.item}>\n <div className={styles.markerColumn}>\n <span\n className={cn(\n styles.marker,\n styles[`marker-${item.marker ?? \"primary\"}`],\n )}\n aria-hidden=\"true\"\n >\n {item.icon}\n </span>\n {connector && !isLast && (\n <span className={styles.line} aria-hidden=\"true\" />\n )}\n </div>\n <div className={styles.body}>\n <div className={styles.row}>\n <span className={styles.title}>{item.title}</span>\n {item.meta && <span className={styles.meta}>{item.meta}</span>}\n </div>\n {item.description && (\n <p className={styles.description}>{item.description}</p>\n )}\n </div>\n </li>\n );\n })}\n </ol>\n );\n}\n"],"mappings":"4GAuCA,SAAgB,EAAS,CAAE,QAAO,YAAY,GAAM,YAAW,GAAG,GAAwB,CACtF,OACI,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,GAAG,EAAA,QAAO,SAAU,GAAa,EAAA,QAAO,UAAW,CAAS,EAAG,GAAI,EAC7E,SAAA,EAAM,KAAK,EAAM,IAAU,CACxB,IAAM,EAAS,IAAU,EAAM,OAAS,EACxC,OACI,EAAA,EAAA,KAAA,CAAC,KAAD,CAAkB,UAAW,EAAA,QAAO,KAApC,SAAA,EACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,aAAvB,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CACI,UAAW,EAAA,GACP,EAAA,QAAO,OACP,EAAA,QAAO,UAAU,EAAK,QAAU,YACpC,EACA,cAAY,OAEX,SAAA,EAAK,IACJ,CAAA,EACL,GAAa,CAAC,IACX,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,KAAM,cAAY,MAAQ,CAAA,CAErD,CACL,CAAA,GAAA,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAvB,SAAA,EACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,IAAvB,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,MAAQ,SAAA,EAAK,KAAY,CAAA,EAChD,EAAK,OAAQ,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,KAAO,SAAA,EAAK,IAAW,CAAA,CAC5D,CACJ,CAAA,EAAA,EAAK,cACF,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAA,QAAO,YAAc,SAAA,EAAK,WAAe,CAAA,CAE1D,CACL,CAAA,CAAA,CAxBK,EAAA,EAAK,EAwBV,CAEZ,CAAC,CACD,CAAA,CAEZ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Timeline.js","names":[],"sources":["../../../src/components/Timeline/Timeline.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Timeline.module.css\";\n\nexport type TimelineMarker = \"primary\" | \"success\" | \"warning\" | \"danger\" | \"neutral\";\n\nexport interface TimelineItem {\n /** Stable identifier (used as React key). */\n id: string;\n /** Title rendered as the entry headline. */\n title: ReactNode;\n /** Optional subtitle / description below the title. */\n description?: ReactNode;\n /** Right-aligned meta column (timestamps, durations). */\n meta?: ReactNode;\n /** Optional custom icon rendered inside the marker. */\n icon?: ReactNode;\n /** Marker color. Default `\"primary\"`. */\n marker?: TimelineMarker;\n}\n\nexport interface TimelineProps extends HTMLAttributes<HTMLOListElement> {\n items: TimelineItem[];\n /** Show the connecting line between markers. Default `true`. */\n connector?: boolean;\n}\n\n/**\n * Vertical event timeline — activity feeds, order trackers, audit logs.\n * Each entry has a marker (color or custom icon), title, optional\n * description and right-aligned meta column.\n *\n * @example\n * <Timeline items={[\n * { id: \"1\", title: \"Pedido criado\", meta: \"10:24\", marker: \"primary\" },\n * { id: \"2\", title: \"Aprovação\", meta: \"10:25\", marker: \"success\" },\n * { id: \"3\", title: \"Saiu pra entrega\", meta: \"11:00\", marker: \"warning\" },\n * ]} />\n */\nexport function Timeline({ items, connector = true, className, ...props }: TimelineProps) {\n return (\n <ol className={cn(styles.timeline, connector && styles.connector, className)} {...props}>\n {items.map((item, index) => {\n const isLast = index === items.length - 1;\n return (\n <li key={item.id} className={styles.item}>\n <div className={styles.markerColumn}>\n <span\n className={cn(\n styles.marker,\n styles[`marker-${item.marker ?? \"primary\"}`],\n )}\n aria-hidden=\"true\"\n >\n {item.icon}\n </span>\n {connector && !isLast && (\n <span className={styles.line} aria-hidden=\"true\" />\n )}\n </div>\n <div className={styles.body}>\n <div className={styles.row}>\n <span className={styles.title}>{item.title}</span>\n {item.meta && <span className={styles.meta}>{item.meta}</span>}\n </div>\n {item.description && (\n <p className={styles.description}>{item.description}</p>\n )}\n </div>\n </li>\n );\n })}\n </ol>\n );\n}\n"],"mappings":";;;;AAuCA,SAAgB,EAAS,EAAE,UAAO,eAAY,IAAM,cAAW,GAAG,KAAwB;CACtF,OACI,kBAAC,MAAD;EAAI,WAAW,EAAG,EAAO,UAAU,KAAa,EAAO,WAAW,CAAS;EAAG,GAAI;
|
|
1
|
+
{"version":3,"file":"Timeline.js","names":[],"sources":["../../../src/components/Timeline/Timeline.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Timeline.module.css\";\n\nexport type TimelineMarker = \"primary\" | \"success\" | \"warning\" | \"danger\" | \"neutral\";\n\nexport interface TimelineItem {\n /** Stable identifier (used as React key). */\n id: string;\n /** Title rendered as the entry headline. */\n title: ReactNode;\n /** Optional subtitle / description below the title. */\n description?: ReactNode;\n /** Right-aligned meta column (timestamps, durations). */\n meta?: ReactNode;\n /** Optional custom icon rendered inside the marker. */\n icon?: ReactNode;\n /** Marker color. Default `\"primary\"`. */\n marker?: TimelineMarker;\n}\n\nexport interface TimelineProps extends HTMLAttributes<HTMLOListElement> {\n items: TimelineItem[];\n /** Show the connecting line between markers. Default `true`. */\n connector?: boolean;\n}\n\n/**\n * Vertical event timeline — activity feeds, order trackers, audit logs.\n * Each entry has a marker (color or custom icon), title, optional\n * description and right-aligned meta column.\n *\n * @example\n * <Timeline items={[\n * { id: \"1\", title: \"Pedido criado\", meta: \"10:24\", marker: \"primary\" },\n * { id: \"2\", title: \"Aprovação\", meta: \"10:25\", marker: \"success\" },\n * { id: \"3\", title: \"Saiu pra entrega\", meta: \"11:00\", marker: \"warning\" },\n * ]} />\n */\nexport function Timeline({ items, connector = true, className, ...props }: TimelineProps) {\n return (\n <ol className={cn(styles.timeline, connector && styles.connector, className)} {...props}>\n {items.map((item, index) => {\n const isLast = index === items.length - 1;\n return (\n <li key={item.id} className={styles.item}>\n <div className={styles.markerColumn}>\n <span\n className={cn(\n styles.marker,\n styles[`marker-${item.marker ?? \"primary\"}`],\n )}\n aria-hidden=\"true\"\n >\n {item.icon}\n </span>\n {connector && !isLast && (\n <span className={styles.line} aria-hidden=\"true\" />\n )}\n </div>\n <div className={styles.body}>\n <div className={styles.row}>\n <span className={styles.title}>{item.title}</span>\n {item.meta && <span className={styles.meta}>{item.meta}</span>}\n </div>\n {item.description && (\n <p className={styles.description}>{item.description}</p>\n )}\n </div>\n </li>\n );\n })}\n </ol>\n );\n}\n"],"mappings":";;;;AAuCA,SAAgB,EAAS,EAAE,UAAO,eAAY,IAAM,cAAW,GAAG,KAAwB;CACtF,OACI,kBAAC,MAAD;EAAI,WAAW,EAAG,EAAO,UAAU,KAAa,EAAO,WAAW,CAAS;EAAG,GAAI;EAC7E,UAAA,EAAM,KAAK,GAAM,MAAU;GACxB,IAAM,IAAS,MAAU,EAAM,SAAS;GACxC,OACI,kBAAC,MAAD;IAAkB,WAAW,EAAO;IAApC,UAAA,CACI,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAvB,UAAA,CACI,kBAAC,QAAD;MACI,WAAW,EACP,EAAO,QACP,EAAO,UAAU,EAAK,UAAU,YACpC;MACA,eAAY;MAEX,UAAA,EAAK;KACJ,CAAA,GACL,KAAa,CAAC,KACX,kBAAC,QAAD;MAAM,WAAW,EAAO;MAAM,eAAY;KAAQ,CAAA,CAErD;IACL,CAAA,GAAA,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAvB,UAAA,CACI,kBAAC,OAAD;MAAK,WAAW,EAAO;MAAvB,UAAA,CACI,kBAAC,QAAD;OAAM,WAAW,EAAO;OAAQ,UAAA,EAAK;MAAY,CAAA,GAChD,EAAK,QAAQ,kBAAC,QAAD;OAAM,WAAW,EAAO;OAAO,UAAA,EAAK;MAAW,CAAA,CAC5D;KACJ,CAAA,GAAA,EAAK,eACF,kBAAC,KAAD;MAAG,WAAW,EAAO;MAAc,UAAA,EAAK;KAAe,CAAA,CAE1D;IACL,CAAA,CAAA;GAxBK,GAAA,EAAK,EAwBV;EAEZ,CAAC;CACD,CAAA;AAEZ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToastProvider.cjs","names":[],"sources":["../../../src/components/Toast/ToastProvider.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines — the provider is the queue: enqueue, dedupe, auto-\n * dismiss timers, pause on hover and the portal that renders them. Splitting the\n * queue from the renderer would put a timer in one file and the element it dismisses\n * in another.\n */\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Toast.module.css\";\n\nexport type ToastVariant = \"success\" | \"warning\" | \"error\" | \"info\";\n\nexport interface ToastOptions {\n id?: string;\n title?: string;\n description?: string;\n variant?: ToastVariant;\n /** Auto-dismiss timeout in ms. Pass `0` to keep the toast until dismissed manually. */\n duration?: number;\n}\n\ninterface ToastEntry extends Required<Omit<ToastOptions, \"id\" | \"title\" | \"description\">> {\n id: string;\n title?: string;\n description?: string;\n}\n\nexport interface ToastApi {\n show: (options: ToastOptions) => string;\n dismiss: (id: string) => void;\n success: (\n description: string,\n options?: Omit<ToastOptions, \"variant\" | \"description\">,\n ) => string;\n error: (description: string, options?: Omit<ToastOptions, \"variant\" | \"description\">) => string;\n warning: (\n description: string,\n options?: Omit<ToastOptions, \"variant\" | \"description\">,\n ) => string;\n info: (description: string, options?: Omit<ToastOptions, \"variant\" | \"description\">) => string;\n}\n\nconst ToastContext = createContext<ToastApi | null>(null);\n\n/**\n * Access the toast API. Must be used inside a {@link ToastProvider}.\n *\n * @returns Methods to show and dismiss toasts.\n */\nexport function useToast(): ToastApi {\n const ctx = useContext(ToastContext);\n if (!ctx) throw new Error(\"useToast must be used inside a <ToastProvider>\");\n return ctx;\n}\n\nexport type ToastPosition =\n \"top-right\" | \"top-left\" | \"top-center\" | \"bottom-right\" | \"bottom-left\" | \"bottom-center\";\n\nexport interface ToastProviderProps {\n children: ReactNode;\n /** Default auto-dismiss duration (ms). Default 4000. */\n defaultDuration?: number;\n /** Stack position on screen. Default `\"top-right\"`. */\n position?: ToastPosition;\n}\n\n/**\n * Renders a portalled toast container and exposes the imperative {@link useToast} API.\n */\nexport function ToastProvider({\n children,\n defaultDuration = 4000,\n position = \"top-right\",\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<ToastEntry[]>([]);\n const counter = useRef<number>(0);\n\n const dismiss = useCallback((id: string): void => {\n setToasts((current) => current.filter((toast) => toast.id !== id));\n }, []);\n\n const show = useCallback(\n (options: ToastOptions): string => {\n const id = options.id ?? `toast-${++counter.current}`;\n const entry: ToastEntry = {\n id,\n title: options.title,\n description: options.description,\n variant: options.variant ?? \"info\",\n duration: options.duration ?? defaultDuration,\n };\n setToasts((current) => [...current, entry]);\n return id;\n },\n [defaultDuration],\n );\n\n const api = useMemo<ToastApi>(\n () => ({\n show,\n dismiss,\n success: (description, options) =>\n show({ ...options, description, variant: \"success\" }),\n error: (description, options) => show({ ...options, description, variant: \"error\" }),\n warning: (description, options) =>\n show({ ...options, description, variant: \"warning\" }),\n info: (description, options) => show({ ...options, description, variant: \"info\" }),\n }),\n [show, dismiss],\n );\n\n return (\n <ToastContext.Provider value={api}>\n {children}\n <ToastContainer toasts={toasts} onDismiss={dismiss} position={position} />\n </ToastContext.Provider>\n );\n}\n\ninterface ContainerProps {\n toasts: ToastEntry[];\n onDismiss: (id: string) => void;\n position: ToastPosition;\n}\n\nfunction positionClass(position: ToastPosition): string {\n switch (position) {\n case \"top-left\":\n return styles.positionTopLeft;\n case \"top-center\":\n return styles.positionTopCenter;\n case \"bottom-right\":\n return styles.positionBottomRight;\n case \"bottom-left\":\n return styles.positionBottomLeft;\n case \"bottom-center\":\n return styles.positionBottomCenter;\n case \"top-right\":\n default:\n return styles.positionTopRight;\n }\n}\n\n/**\n * The portalled stack, and the page's live region for toasts.\n *\n * `aria-atomic=\"false\"` matters: with `\"true\"` a screen reader re-reads the\n * **entire** stack on every change, so the third toast of a batch is announced as\n * all three, and dismissing one re-announces the survivors. `\"false\"` announces only\n * the node that was added, which is what the user needs.\n *\n * The stack stays the live region rather than delegating to `useAnnounce`, because\n * routing it through the shared announcer would put the same text in the document\n * twice — once visible, once hidden — and every `getByText(\"Salvo\")` in a consuming\n * app's test suite would start matching two nodes. The announcer is for messages\n * that have no on-screen home; a toast has one.\n */\nfunction ToastContainer({ toasts, onDismiss, position }: ContainerProps) {\n if (typeof document === \"undefined\") return null;\n return createPortal(\n <div\n className={cn(styles.container, positionClass(position))}\n aria-live=\"polite\"\n aria-atomic=\"false\"\n >\n {toasts.map((toast) => (\n <ToastItem key={toast.id} toast={toast} onDismiss={onDismiss} />\n ))}\n </div>,\n document.body,\n );\n}\n\ninterface ItemProps {\n toast: ToastEntry;\n onDismiss: (id: string) => void;\n}\n\n/**\n * One toast.\n *\n * No `role=\"status\"` of its own: it already lives inside the container's live\n * region, and a live region nested in a live region is announced twice by some\n * screen readers.\n */\nfunction ToastItem({ toast, onDismiss }: ItemProps) {\n useEffect(() => {\n if (!toast.duration) return;\n const timer = setTimeout(() => onDismiss(toast.id), toast.duration);\n return () => clearTimeout(timer);\n }, [toast.id, toast.duration, onDismiss]);\n\n return (\n <div className={cn(styles.toast, styles[toast.variant])}>\n <div>\n {toast.title && <p className={styles.title}>{toast.title}</p>}\n {toast.description && <p className={styles.description}>{toast.description}</p>}\n </div>\n <button\n type=\"button\"\n className={styles.close}\n aria-label=\"Fechar notificação\"\n onClick={() => onDismiss(toast.id)}\n >\n <CloseIcon />\n </button>\n </div>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 6l12 12M6 18L18 6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ToastProvider.cjs","names":[],"sources":["../../../src/components/Toast/ToastProvider.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines — the provider is the queue: enqueue, dedupe, auto-\n * dismiss timers, pause on hover and the portal that renders them. Splitting the\n * queue from the renderer would put a timer in one file and the element it dismisses\n * in another.\n */\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Toast.module.css\";\n\nexport type ToastVariant = \"success\" | \"warning\" | \"error\" | \"info\";\n\nexport interface ToastOptions {\n id?: string;\n title?: string;\n description?: string;\n variant?: ToastVariant;\n /** Auto-dismiss timeout in ms. Pass `0` to keep the toast until dismissed manually. */\n duration?: number;\n}\n\ninterface ToastEntry extends Required<Omit<ToastOptions, \"id\" | \"title\" | \"description\">> {\n id: string;\n title?: string;\n description?: string;\n}\n\nexport interface ToastApi {\n show: (options: ToastOptions) => string;\n dismiss: (id: string) => void;\n success: (\n description: string,\n options?: Omit<ToastOptions, \"variant\" | \"description\">,\n ) => string;\n error: (description: string, options?: Omit<ToastOptions, \"variant\" | \"description\">) => string;\n warning: (\n description: string,\n options?: Omit<ToastOptions, \"variant\" | \"description\">,\n ) => string;\n info: (description: string, options?: Omit<ToastOptions, \"variant\" | \"description\">) => string;\n}\n\nconst ToastContext = createContext<ToastApi | null>(null);\n\n/**\n * Access the toast API. Must be used inside a {@link ToastProvider}.\n *\n * @returns Methods to show and dismiss toasts.\n */\nexport function useToast(): ToastApi {\n const ctx = useContext(ToastContext);\n if (!ctx) throw new Error(\"useToast must be used inside a <ToastProvider>\");\n return ctx;\n}\n\nexport type ToastPosition =\n \"top-right\" | \"top-left\" | \"top-center\" | \"bottom-right\" | \"bottom-left\" | \"bottom-center\";\n\nexport interface ToastProviderProps {\n children: ReactNode;\n /** Default auto-dismiss duration (ms). Default 4000. */\n defaultDuration?: number;\n /** Stack position on screen. Default `\"top-right\"`. */\n position?: ToastPosition;\n}\n\n/**\n * Renders a portalled toast container and exposes the imperative {@link useToast} API.\n */\nexport function ToastProvider({\n children,\n defaultDuration = 4000,\n position = \"top-right\",\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<ToastEntry[]>([]);\n const counter = useRef<number>(0);\n\n const dismiss = useCallback((id: string): void => {\n setToasts((current) => current.filter((toast) => toast.id !== id));\n }, []);\n\n const show = useCallback(\n (options: ToastOptions): string => {\n const id = options.id ?? `toast-${++counter.current}`;\n const entry: ToastEntry = {\n id,\n title: options.title,\n description: options.description,\n variant: options.variant ?? \"info\",\n duration: options.duration ?? defaultDuration,\n };\n setToasts((current) => [...current, entry]);\n return id;\n },\n [defaultDuration],\n );\n\n const api = useMemo<ToastApi>(\n () => ({\n show,\n dismiss,\n success: (description, options) =>\n show({ ...options, description, variant: \"success\" }),\n error: (description, options) => show({ ...options, description, variant: \"error\" }),\n warning: (description, options) =>\n show({ ...options, description, variant: \"warning\" }),\n info: (description, options) => show({ ...options, description, variant: \"info\" }),\n }),\n [show, dismiss],\n );\n\n return (\n <ToastContext.Provider value={api}>\n {children}\n <ToastContainer toasts={toasts} onDismiss={dismiss} position={position} />\n </ToastContext.Provider>\n );\n}\n\ninterface ContainerProps {\n toasts: ToastEntry[];\n onDismiss: (id: string) => void;\n position: ToastPosition;\n}\n\nfunction positionClass(position: ToastPosition): string {\n switch (position) {\n case \"top-left\":\n return styles.positionTopLeft;\n case \"top-center\":\n return styles.positionTopCenter;\n case \"bottom-right\":\n return styles.positionBottomRight;\n case \"bottom-left\":\n return styles.positionBottomLeft;\n case \"bottom-center\":\n return styles.positionBottomCenter;\n case \"top-right\":\n default:\n return styles.positionTopRight;\n }\n}\n\n/**\n * The portalled stack, and the page's live region for toasts.\n *\n * `aria-atomic=\"false\"` matters: with `\"true\"` a screen reader re-reads the\n * **entire** stack on every change, so the third toast of a batch is announced as\n * all three, and dismissing one re-announces the survivors. `\"false\"` announces only\n * the node that was added, which is what the user needs.\n *\n * The stack stays the live region rather than delegating to `useAnnounce`, because\n * routing it through the shared announcer would put the same text in the document\n * twice — once visible, once hidden — and every `getByText(\"Salvo\")` in a consuming\n * app's test suite would start matching two nodes. The announcer is for messages\n * that have no on-screen home; a toast has one.\n */\nfunction ToastContainer({ toasts, onDismiss, position }: ContainerProps) {\n if (typeof document === \"undefined\") return null;\n return createPortal(\n <div\n className={cn(styles.container, positionClass(position))}\n aria-live=\"polite\"\n aria-atomic=\"false\"\n >\n {toasts.map((toast) => (\n <ToastItem key={toast.id} toast={toast} onDismiss={onDismiss} />\n ))}\n </div>,\n document.body,\n );\n}\n\ninterface ItemProps {\n toast: ToastEntry;\n onDismiss: (id: string) => void;\n}\n\n/**\n * One toast.\n *\n * No `role=\"status\"` of its own: it already lives inside the container's live\n * region, and a live region nested in a live region is announced twice by some\n * screen readers.\n */\nfunction ToastItem({ toast, onDismiss }: ItemProps) {\n useEffect(() => {\n if (!toast.duration) return;\n const timer = setTimeout(() => onDismiss(toast.id), toast.duration);\n return () => clearTimeout(timer);\n }, [toast.id, toast.duration, onDismiss]);\n\n return (\n <div className={cn(styles.toast, styles[toast.variant])}>\n <div>\n {toast.title && <p className={styles.title}>{toast.title}</p>}\n {toast.description && <p className={styles.description}>{toast.description}</p>}\n </div>\n <button\n type=\"button\"\n className={styles.close}\n aria-label=\"Fechar notificação\"\n onClick={() => onDismiss(toast.id)}\n >\n <CloseIcon />\n </button>\n </div>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 6l12 12M6 18L18 6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToastProvider.js","names":[],"sources":["../../../src/components/Toast/ToastProvider.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines — the provider is the queue: enqueue, dedupe, auto-\n * dismiss timers, pause on hover and the portal that renders them. Splitting the\n * queue from the renderer would put a timer in one file and the element it dismisses\n * in another.\n */\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Toast.module.css\";\n\nexport type ToastVariant = \"success\" | \"warning\" | \"error\" | \"info\";\n\nexport interface ToastOptions {\n id?: string;\n title?: string;\n description?: string;\n variant?: ToastVariant;\n /** Auto-dismiss timeout in ms. Pass `0` to keep the toast until dismissed manually. */\n duration?: number;\n}\n\ninterface ToastEntry extends Required<Omit<ToastOptions, \"id\" | \"title\" | \"description\">> {\n id: string;\n title?: string;\n description?: string;\n}\n\nexport interface ToastApi {\n show: (options: ToastOptions) => string;\n dismiss: (id: string) => void;\n success: (\n description: string,\n options?: Omit<ToastOptions, \"variant\" | \"description\">,\n ) => string;\n error: (description: string, options?: Omit<ToastOptions, \"variant\" | \"description\">) => string;\n warning: (\n description: string,\n options?: Omit<ToastOptions, \"variant\" | \"description\">,\n ) => string;\n info: (description: string, options?: Omit<ToastOptions, \"variant\" | \"description\">) => string;\n}\n\nconst ToastContext = createContext<ToastApi | null>(null);\n\n/**\n * Access the toast API. Must be used inside a {@link ToastProvider}.\n *\n * @returns Methods to show and dismiss toasts.\n */\nexport function useToast(): ToastApi {\n const ctx = useContext(ToastContext);\n if (!ctx) throw new Error(\"useToast must be used inside a <ToastProvider>\");\n return ctx;\n}\n\nexport type ToastPosition =\n \"top-right\" | \"top-left\" | \"top-center\" | \"bottom-right\" | \"bottom-left\" | \"bottom-center\";\n\nexport interface ToastProviderProps {\n children: ReactNode;\n /** Default auto-dismiss duration (ms). Default 4000. */\n defaultDuration?: number;\n /** Stack position on screen. Default `\"top-right\"`. */\n position?: ToastPosition;\n}\n\n/**\n * Renders a portalled toast container and exposes the imperative {@link useToast} API.\n */\nexport function ToastProvider({\n children,\n defaultDuration = 4000,\n position = \"top-right\",\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<ToastEntry[]>([]);\n const counter = useRef<number>(0);\n\n const dismiss = useCallback((id: string): void => {\n setToasts((current) => current.filter((toast) => toast.id !== id));\n }, []);\n\n const show = useCallback(\n (options: ToastOptions): string => {\n const id = options.id ?? `toast-${++counter.current}`;\n const entry: ToastEntry = {\n id,\n title: options.title,\n description: options.description,\n variant: options.variant ?? \"info\",\n duration: options.duration ?? defaultDuration,\n };\n setToasts((current) => [...current, entry]);\n return id;\n },\n [defaultDuration],\n );\n\n const api = useMemo<ToastApi>(\n () => ({\n show,\n dismiss,\n success: (description, options) =>\n show({ ...options, description, variant: \"success\" }),\n error: (description, options) => show({ ...options, description, variant: \"error\" }),\n warning: (description, options) =>\n show({ ...options, description, variant: \"warning\" }),\n info: (description, options) => show({ ...options, description, variant: \"info\" }),\n }),\n [show, dismiss],\n );\n\n return (\n <ToastContext.Provider value={api}>\n {children}\n <ToastContainer toasts={toasts} onDismiss={dismiss} position={position} />\n </ToastContext.Provider>\n );\n}\n\ninterface ContainerProps {\n toasts: ToastEntry[];\n onDismiss: (id: string) => void;\n position: ToastPosition;\n}\n\nfunction positionClass(position: ToastPosition): string {\n switch (position) {\n case \"top-left\":\n return styles.positionTopLeft;\n case \"top-center\":\n return styles.positionTopCenter;\n case \"bottom-right\":\n return styles.positionBottomRight;\n case \"bottom-left\":\n return styles.positionBottomLeft;\n case \"bottom-center\":\n return styles.positionBottomCenter;\n case \"top-right\":\n default:\n return styles.positionTopRight;\n }\n}\n\n/**\n * The portalled stack, and the page's live region for toasts.\n *\n * `aria-atomic=\"false\"` matters: with `\"true\"` a screen reader re-reads the\n * **entire** stack on every change, so the third toast of a batch is announced as\n * all three, and dismissing one re-announces the survivors. `\"false\"` announces only\n * the node that was added, which is what the user needs.\n *\n * The stack stays the live region rather than delegating to `useAnnounce`, because\n * routing it through the shared announcer would put the same text in the document\n * twice — once visible, once hidden — and every `getByText(\"Salvo\")` in a consuming\n * app's test suite would start matching two nodes. The announcer is for messages\n * that have no on-screen home; a toast has one.\n */\nfunction ToastContainer({ toasts, onDismiss, position }: ContainerProps) {\n if (typeof document === \"undefined\") return null;\n return createPortal(\n <div\n className={cn(styles.container, positionClass(position))}\n aria-live=\"polite\"\n aria-atomic=\"false\"\n >\n {toasts.map((toast) => (\n <ToastItem key={toast.id} toast={toast} onDismiss={onDismiss} />\n ))}\n </div>,\n document.body,\n );\n}\n\ninterface ItemProps {\n toast: ToastEntry;\n onDismiss: (id: string) => void;\n}\n\n/**\n * One toast.\n *\n * No `role=\"status\"` of its own: it already lives inside the container's live\n * region, and a live region nested in a live region is announced twice by some\n * screen readers.\n */\nfunction ToastItem({ toast, onDismiss }: ItemProps) {\n useEffect(() => {\n if (!toast.duration) return;\n const timer = setTimeout(() => onDismiss(toast.id), toast.duration);\n return () => clearTimeout(timer);\n }, [toast.id, toast.duration, onDismiss]);\n\n return (\n <div className={cn(styles.toast, styles[toast.variant])}>\n <div>\n {toast.title && <p className={styles.title}>{toast.title}</p>}\n {toast.description && <p className={styles.description}>{toast.description}</p>}\n </div>\n <button\n type=\"button\"\n className={styles.close}\n aria-label=\"Fechar notificação\"\n onClick={() => onDismiss(toast.id)}\n >\n <CloseIcon />\n </button>\n </div>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 6l12 12M6 18L18 6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ToastProvider.js","names":[],"sources":["../../../src/components/Toast/ToastProvider.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines — the provider is the queue: enqueue, dedupe, auto-\n * dismiss timers, pause on hover and the portal that renders them. Splitting the\n * queue from the renderer would put a timer in one file and the element it dismisses\n * in another.\n */\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Toast.module.css\";\n\nexport type ToastVariant = \"success\" | \"warning\" | \"error\" | \"info\";\n\nexport interface ToastOptions {\n id?: string;\n title?: string;\n description?: string;\n variant?: ToastVariant;\n /** Auto-dismiss timeout in ms. Pass `0` to keep the toast until dismissed manually. */\n duration?: number;\n}\n\ninterface ToastEntry extends Required<Omit<ToastOptions, \"id\" | \"title\" | \"description\">> {\n id: string;\n title?: string;\n description?: string;\n}\n\nexport interface ToastApi {\n show: (options: ToastOptions) => string;\n dismiss: (id: string) => void;\n success: (\n description: string,\n options?: Omit<ToastOptions, \"variant\" | \"description\">,\n ) => string;\n error: (description: string, options?: Omit<ToastOptions, \"variant\" | \"description\">) => string;\n warning: (\n description: string,\n options?: Omit<ToastOptions, \"variant\" | \"description\">,\n ) => string;\n info: (description: string, options?: Omit<ToastOptions, \"variant\" | \"description\">) => string;\n}\n\nconst ToastContext = createContext<ToastApi | null>(null);\n\n/**\n * Access the toast API. Must be used inside a {@link ToastProvider}.\n *\n * @returns Methods to show and dismiss toasts.\n */\nexport function useToast(): ToastApi {\n const ctx = useContext(ToastContext);\n if (!ctx) throw new Error(\"useToast must be used inside a <ToastProvider>\");\n return ctx;\n}\n\nexport type ToastPosition =\n \"top-right\" | \"top-left\" | \"top-center\" | \"bottom-right\" | \"bottom-left\" | \"bottom-center\";\n\nexport interface ToastProviderProps {\n children: ReactNode;\n /** Default auto-dismiss duration (ms). Default 4000. */\n defaultDuration?: number;\n /** Stack position on screen. Default `\"top-right\"`. */\n position?: ToastPosition;\n}\n\n/**\n * Renders a portalled toast container and exposes the imperative {@link useToast} API.\n */\nexport function ToastProvider({\n children,\n defaultDuration = 4000,\n position = \"top-right\",\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<ToastEntry[]>([]);\n const counter = useRef<number>(0);\n\n const dismiss = useCallback((id: string): void => {\n setToasts((current) => current.filter((toast) => toast.id !== id));\n }, []);\n\n const show = useCallback(\n (options: ToastOptions): string => {\n const id = options.id ?? `toast-${++counter.current}`;\n const entry: ToastEntry = {\n id,\n title: options.title,\n description: options.description,\n variant: options.variant ?? \"info\",\n duration: options.duration ?? defaultDuration,\n };\n setToasts((current) => [...current, entry]);\n return id;\n },\n [defaultDuration],\n );\n\n const api = useMemo<ToastApi>(\n () => ({\n show,\n dismiss,\n success: (description, options) =>\n show({ ...options, description, variant: \"success\" }),\n error: (description, options) => show({ ...options, description, variant: \"error\" }),\n warning: (description, options) =>\n show({ ...options, description, variant: \"warning\" }),\n info: (description, options) => show({ ...options, description, variant: \"info\" }),\n }),\n [show, dismiss],\n );\n\n return (\n <ToastContext.Provider value={api}>\n {children}\n <ToastContainer toasts={toasts} onDismiss={dismiss} position={position} />\n </ToastContext.Provider>\n );\n}\n\ninterface ContainerProps {\n toasts: ToastEntry[];\n onDismiss: (id: string) => void;\n position: ToastPosition;\n}\n\nfunction positionClass(position: ToastPosition): string {\n switch (position) {\n case \"top-left\":\n return styles.positionTopLeft;\n case \"top-center\":\n return styles.positionTopCenter;\n case \"bottom-right\":\n return styles.positionBottomRight;\n case \"bottom-left\":\n return styles.positionBottomLeft;\n case \"bottom-center\":\n return styles.positionBottomCenter;\n case \"top-right\":\n default:\n return styles.positionTopRight;\n }\n}\n\n/**\n * The portalled stack, and the page's live region for toasts.\n *\n * `aria-atomic=\"false\"` matters: with `\"true\"` a screen reader re-reads the\n * **entire** stack on every change, so the third toast of a batch is announced as\n * all three, and dismissing one re-announces the survivors. `\"false\"` announces only\n * the node that was added, which is what the user needs.\n *\n * The stack stays the live region rather than delegating to `useAnnounce`, because\n * routing it through the shared announcer would put the same text in the document\n * twice — once visible, once hidden — and every `getByText(\"Salvo\")` in a consuming\n * app's test suite would start matching two nodes. The announcer is for messages\n * that have no on-screen home; a toast has one.\n */\nfunction ToastContainer({ toasts, onDismiss, position }: ContainerProps) {\n if (typeof document === \"undefined\") return null;\n return createPortal(\n <div\n className={cn(styles.container, positionClass(position))}\n aria-live=\"polite\"\n aria-atomic=\"false\"\n >\n {toasts.map((toast) => (\n <ToastItem key={toast.id} toast={toast} onDismiss={onDismiss} />\n ))}\n </div>,\n document.body,\n );\n}\n\ninterface ItemProps {\n toast: ToastEntry;\n onDismiss: (id: string) => void;\n}\n\n/**\n * One toast.\n *\n * No `role=\"status\"` of its own: it already lives inside the container's live\n * region, and a live region nested in a live region is announced twice by some\n * screen readers.\n */\nfunction ToastItem({ toast, onDismiss }: ItemProps) {\n useEffect(() => {\n if (!toast.duration) return;\n const timer = setTimeout(() => onDismiss(toast.id), toast.duration);\n return () => clearTimeout(timer);\n }, [toast.id, toast.duration, onDismiss]);\n\n return (\n <div className={cn(styles.toast, styles[toast.variant])}>\n <div>\n {toast.title && <p className={styles.title}>{toast.title}</p>}\n {toast.description && <p className={styles.description}>{toast.description}</p>}\n </div>\n <button\n type=\"button\"\n className={styles.close}\n aria-label=\"Fechar notificação\"\n onClick={() => onDismiss(toast.id)}\n >\n <CloseIcon />\n </button>\n </div>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 6l12 12M6 18L18 6\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":";;;;;;AAoDA,IAAM,IAAe,EAA+B,IAAI;AAOxD,SAAgB,IAAqB;CACjC,IAAM,IAAM,EAAW,CAAY;CACnC,IAAI,CAAC,GAAK,MAAU,MAAM,gDAAgD;CAC1E,OAAO;AACX;AAgBA,SAAgB,EAAc,EAC1B,aACA,qBAAkB,KAClB,cAAW,eACQ;CACnB,IAAM,CAAC,GAAQ,KAAa,EAAuB,CAAC,CAAC,GAC/C,IAAU,EAAe,CAAC,GAE1B,IAAU,GAAa,MAAqB;EAC9C,GAAW,MAAY,EAAQ,QAAQ,MAAU,EAAM,OAAO,CAAE,CAAC;CACrE,GAAG,CAAC,CAAC,GAEC,IAAO,GACR,MAAkC;EAC/B,IAAM,IAAK,EAAQ,MAAM,SAAS,EAAE,EAAQ,WACtC,IAAoB;GACtB;GACA,OAAO,EAAQ;GACf,aAAa,EAAQ;GACrB,SAAS,EAAQ,WAAW;GAC5B,UAAU,EAAQ,YAAY;EAClC;EAEA,OADA,GAAW,MAAY,CAAC,GAAG,GAAS,CAAK,CAAC,GACnC;CACX,GACA,CAAC,CAAe,CACpB,GAEM,IAAM,SACD;EACH;EACA;EACA,UAAU,GAAa,MACnB,EAAK;GAAE,GAAG;GAAS;GAAa,SAAS;EAAU,CAAC;EACxD,QAAQ,GAAa,MAAY,EAAK;GAAE,GAAG;GAAS;GAAa,SAAS;EAAQ,CAAC;EACnF,UAAU,GAAa,MACnB,EAAK;GAAE,GAAG;GAAS;GAAa,SAAS;EAAU,CAAC;EACxD,OAAO,GAAa,MAAY,EAAK;GAAE,GAAG;GAAS;GAAa,SAAS;EAAO,CAAC;CACrF,IACA,CAAC,GAAM,CAAO,CAClB;CAEA,OACI,kBAAC,EAAa,UAAd;EAAuB,OAAO;EAA9B,UAAA,CACK,GACD,kBAAC,GAAD;GAAwB;GAAQ,WAAW;GAAmB;EAAW,CAAA,CACtD;;AAE/B;AAQA,SAAS,EAAc,GAAiC;CACpD,QAAQ,GAAR;EACI,KAAK,YACD,OAAO,EAAO;EAClB,KAAK,cACD,OAAO,EAAO;EAClB,KAAK,gBACD,OAAO,EAAO;EAClB,KAAK,eACD,OAAO,EAAO;EAClB,KAAK,iBACD,OAAO,EAAO;EAElB,SACI,OAAO,EAAO;CACtB;AACJ;AAgBA,SAAS,EAAe,EAAE,WAAQ,cAAW,eAA4B;CAErE,OADI,OAAO,WAAa,MAAoB,OACrC,EACH,kBAAC,OAAD;EACI,WAAW,EAAG,EAAO,WAAW,EAAc,CAAQ,CAAC;EACvD,aAAU;EACV,eAAY;EAEX,UAAA,EAAO,KAAK,MACT,kBAAC,GAAD;GAAiC;GAAkB;EAAY,GAA/C,EAAM,EAAyC,CAClE;CACA,CAAA,GACL,SAAS,IACb;AACJ;AAcA,SAAS,EAAU,EAAE,UAAO,gBAAwB;CAOhD,OANA,QAAgB;EACZ,IAAI,CAAC,EAAM,UAAU;EACrB,IAAM,IAAQ,iBAAiB,EAAU,EAAM,EAAE,GAAG,EAAM,QAAQ;EAClE,aAAa,aAAa,CAAK;CACnC,GAAG;EAAC,EAAM;EAAI,EAAM;EAAU;CAAS,CAAC,GAGpC,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,OAAO,EAAO,EAAM,QAAQ;EAAtD,UAAA,CACI,kBAAC,OAAD,EAAA,UAAA,CACK,EAAM,SAAS,kBAAC,KAAD;GAAG,WAAW,EAAO;GAAQ,UAAA,EAAM;EAAS,CAAA,GAC3D,EAAM,eAAe,kBAAC,KAAD;GAAG,WAAW,EAAO;GAAc,UAAA,EAAM;EAAe,CAAA,CAC7E,EAAA,CAAA,GACL,kBAAC,UAAD;GACI,MAAK;GACL,WAAW,EAAO;GAClB,cAAW;GACX,eAAe,EAAU,EAAM,EAAE;GAEjC,UAAA,kBAAC,GAAD,CAAY,CAAA;EACR,CAAA,CACP;;AAEb;AAEA,SAAS,IAAY;CACjB,OACI,kBAAC,OAAD;EAAK,OAAM;EAAK,QAAO;EAAK,SAAQ;EAAY,MAAK;EACjD,UAAA,kBAAC,QAAD;GACI,GAAE;GACF,QAAO;GACP,aAAY;GACZ,eAAc;EACjB,CAAA;CACA,CAAA;AAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toggle.cjs","names":[],"sources":["../../../src/components/Toggle/Toggle.tsx"],"sourcesContent":["import { forwardRef, useCallback, useState } from \"react\";\nimport type { ButtonHTMLAttributes } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Toggle.module.css\";\n\nexport type ToggleSize = \"sm\" | \"md\" | \"lg\";\nexport type ToggleVariant = \"default\" | \"outline\";\n\nexport interface ToggleProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"onChange\"> {\n /** Controlled pressed state. When provided the component is controlled. */\n pressed?: boolean;\n /** Initial pressed state for the uncontrolled variant. Default `false`. */\n defaultPressed?: boolean;\n /** Fired with the next pressed state whenever the toggle is activated. */\n onPressedChange?: (pressed: boolean) => void;\n /** Visual size. Default `\"md\"`. */\n size?: ToggleSize;\n /** Visual style. Default `\"default\"`. */\n variant?: ToggleVariant;\n}\n\n/**\n * A pressable two-state button — like a checkbox styled as a button.\n *\n * Works controlled (pass `pressed` + `onPressedChange`) or uncontrolled\n * (pass `defaultPressed`). Renders a native `<button type=\"button\">` exposing\n * its state through `aria-pressed`.\n *\n * @param props - {@link ToggleProps}.\n * @returns The toggle button element.\n */\nexport const Toggle = forwardRef<HTMLButtonElement, ToggleProps>(function Toggle(\n {\n pressed,\n defaultPressed = false,\n onPressedChange,\n size = \"md\",\n variant = \"default\",\n className,\n disabled,\n onClick,\n children,\n ...props\n },\n ref,\n) {\n const isControlled = pressed !== undefined;\n const [internalPressed, setInternalPressed] = useState<boolean>(defaultPressed);\n const isPressed = isControlled ? pressed : internalPressed;\n\n const handleClick = useCallback(\n (event: React.MouseEvent<HTMLButtonElement>): void => {\n onClick?.(event);\n if (event.defaultPrevented) return;\n const next = !isPressed;\n if (!isControlled) setInternalPressed(next);\n onPressedChange?.(next);\n },\n [isPressed, isControlled, onClick, onPressedChange],\n );\n\n return (\n <button\n ref={ref}\n type=\"button\"\n aria-pressed={isPressed}\n disabled={disabled}\n data-state={isPressed ? \"on\" : \"off\"}\n className={cn(\n styles.toggle,\n styles[size],\n styles[variant],\n isPressed && styles.pressed,\n className,\n )}\n onClick={handleClick}\n {...props}\n >\n {children}\n </button>\n );\n});\n"],"mappings":"6HA+BA,IAAa,GAAA,
|
|
1
|
+
{"version":3,"file":"Toggle.cjs","names":[],"sources":["../../../src/components/Toggle/Toggle.tsx"],"sourcesContent":["import { forwardRef, useCallback, useState } from \"react\";\nimport type { ButtonHTMLAttributes } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Toggle.module.css\";\n\nexport type ToggleSize = \"sm\" | \"md\" | \"lg\";\nexport type ToggleVariant = \"default\" | \"outline\";\n\nexport interface ToggleProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"onChange\"> {\n /** Controlled pressed state. When provided the component is controlled. */\n pressed?: boolean;\n /** Initial pressed state for the uncontrolled variant. Default `false`. */\n defaultPressed?: boolean;\n /** Fired with the next pressed state whenever the toggle is activated. */\n onPressedChange?: (pressed: boolean) => void;\n /** Visual size. Default `\"md\"`. */\n size?: ToggleSize;\n /** Visual style. Default `\"default\"`. */\n variant?: ToggleVariant;\n}\n\n/**\n * A pressable two-state button — like a checkbox styled as a button.\n *\n * Works controlled (pass `pressed` + `onPressedChange`) or uncontrolled\n * (pass `defaultPressed`). Renders a native `<button type=\"button\">` exposing\n * its state through `aria-pressed`.\n *\n * @param props - {@link ToggleProps}.\n * @returns The toggle button element.\n */\nexport const Toggle = forwardRef<HTMLButtonElement, ToggleProps>(function Toggle(\n {\n pressed,\n defaultPressed = false,\n onPressedChange,\n size = \"md\",\n variant = \"default\",\n className,\n disabled,\n onClick,\n children,\n ...props\n },\n ref,\n) {\n const isControlled = pressed !== undefined;\n const [internalPressed, setInternalPressed] = useState<boolean>(defaultPressed);\n const isPressed = isControlled ? pressed : internalPressed;\n\n const handleClick = useCallback(\n (event: React.MouseEvent<HTMLButtonElement>): void => {\n onClick?.(event);\n if (event.defaultPrevented) return;\n const next = !isPressed;\n if (!isControlled) setInternalPressed(next);\n onPressedChange?.(next);\n },\n [isPressed, isControlled, onClick, onPressedChange],\n );\n\n return (\n <button\n ref={ref}\n type=\"button\"\n aria-pressed={isPressed}\n disabled={disabled}\n data-state={isPressed ? \"on\" : \"off\"}\n className={cn(\n styles.toggle,\n styles[size],\n styles[variant],\n isPressed && styles.pressed,\n className,\n )}\n onClick={handleClick}\n {...props}\n >\n {children}\n </button>\n );\n});\n"],"mappings":"6HA+BA,IAAa,GAAA,EAAS,EAAA,WAAA,CAA2C,SAC7D,CACI,UACA,iBAAiB,GACjB,kBACA,OAAO,KACP,UAAU,UACV,YACA,WACA,UACA,WACA,GAAG,GAEP,EACF,CACE,IAAM,EAAe,IAAY,IAAA,GAC3B,CAAC,EAAiB,IAAA,EAAsB,EAAA,SAAA,CAAkB,CAAc,EACxE,EAAY,EAAe,EAAU,EAErC,GAAA,EAAc,EAAA,YAAA,CACf,GAAqD,CAElD,GADA,IAAU,CAAK,EACX,EAAM,iBAAkB,OAC5B,IAAM,EAAO,CAAC,EACT,GAAc,EAAmB,CAAI,EAC1C,IAAkB,CAAI,CAC1B,EACA,CAAC,EAAW,EAAc,EAAS,CAAe,CACtD,EAEA,OACI,EAAA,EAAA,IAAA,CAAC,SAAD,CACS,MACL,KAAK,SACL,eAAc,EACJ,WACV,aAAY,EAAY,KAAO,MAC/B,UAAW,EAAA,GACP,EAAA,QAAO,OACP,EAAA,QAAO,GACP,EAAA,QAAO,GACP,GAAa,EAAA,QAAO,QACpB,CACJ,EACA,QAAS,EACT,GAAI,EAEH,UACG,CAAA,CAEhB,CAAC"}
|