tempest-react-sdk 0.38.3 → 0.39.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- 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/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.map +1 -1
- package/dist/forms/use-viacep.cjs.map +1 -1
- package/dist/forms/use-zod-form.cjs.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/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/canvas.cjs +1 -1
- package/dist/vision/core/canvas.cjs.map +1 -1
- package/dist/vision/core/canvas.js +4 -4
- package/dist/vision/core/canvas.js.map +1 -1
- package/dist/vision/core/exceptions.cjs +1 -1
- package/dist/vision/core/exceptions.cjs.map +1 -1
- package/dist/vision/core/exceptions.js +2 -2
- package/dist/vision/core/exceptions.js.map +1 -1
- package/dist/vision/core/metadata.cjs +2 -2
- package/dist/vision/core/metadata.cjs.map +1 -1
- package/dist/vision/core/metadata.js +11 -8
- package/dist/vision/core/metadata.js.map +1 -1
- package/dist/vision/core/session.cjs +1 -1
- package/dist/vision/core/session.cjs.map +1 -1
- package/dist/vision/core/session.js +8 -5
- package/dist/vision/core/session.js.map +1 -1
- package/dist/vision/fusion.cjs +2 -0
- package/dist/vision/fusion.cjs.map +1 -0
- package/dist/vision/fusion.js +42 -0
- package/dist/vision/fusion.js.map +1 -0
- package/dist/vision/index.cjs +1 -1
- package/dist/vision/index.cjs.map +1 -1
- package/dist/vision/index.js +23 -20
- package/dist/vision/index.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/labels.cjs +1 -1
- package/dist/vision/labels.cjs.map +1 -1
- package/dist/vision/labels.js +7 -4
- package/dist/vision/labels.js.map +1 -1
- package/dist/vision/postprocess/detection.cjs +1 -1
- package/dist/vision/postprocess/detection.cjs.map +1 -1
- package/dist/vision/postprocess/detection.js +3 -10
- package/dist/vision/postprocess/detection.js.map +1 -1
- package/dist/vision/postprocess/segmentation.cjs +1 -1
- package/dist/vision/postprocess/segmentation.cjs.map +1 -1
- package/dist/vision/postprocess/segmentation.js +11 -15
- package/dist/vision/postprocess/segmentation.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/preprocess/pipeline.cjs +2 -0
- package/dist/vision/preprocess/pipeline.cjs.map +1 -0
- package/dist/vision/preprocess/pipeline.js +61 -0
- package/dist/vision/preprocess/pipeline.js.map +1 -0
- package/dist/vision/results.cjs +1 -1
- package/dist/vision/results.cjs.map +1 -1
- package/dist/vision/results.js +23 -2
- package/dist/vision/results.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 +11 -2
- 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 +2 -0
- package/dist/vision/tasks/detectClassify.cjs.map +1 -0
- package/dist/vision/tasks/detectClassify.js +222 -0
- package/dist/vision/tasks/detectClassify.js.map +1 -0
- package/dist/vision/tasks/detector.cjs +1 -1
- package/dist/vision/tasks/detector.cjs.map +1 -1
- package/dist/vision/tasks/detector.js +54 -29
- package/dist/vision/tasks/detector.js.map +1 -1
- package/dist/vision/tasks/segmenter.cjs +1 -1
- package/dist/vision/tasks/segmenter.cjs.map +1 -1
- package/dist/vision/tasks/segmenter.js +53 -28
- package/dist/vision/tasks/segmenter.js.map +1 -1
- package/dist/vision/types.cjs.map +1 -1
- package/dist/vision/types.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/vision.cjs +1 -1
- package/dist/vision.d.ts +1517 -962
- package/dist/vision.js +25 -22
- 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":"NotificationCenter.js","names":[],"sources":["../../../src/components/NotificationCenter/NotificationCenter.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count, function-lines — an inbox has four actions the app\n * must implement (onSelect, onMarkRead, onMarkAllRead, onDismiss) over one list,\n * plus the presentation it needs to render a readable feed: renderIcon, locale, now\n * for relative timestamps, emptyState and title.\n */\nimport type { HTMLAttributes, ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\nimport { relativeTime, type RelativeTimeLocale } from \"@/utils/relative-time\";\n\nimport { Badge } from \"../Badge\";\nimport { EmptyState } from \"../EmptyState\";\nimport type { NotificationItem } from \"./use-notification-inbox\";\nimport styles from \"./NotificationCenter.module.css\";\n\n/**\n * DOM attributes this component redefines.\n *\n * `title` becomes a rendered heading node instead of a tooltip string, and\n * `onSelect` becomes \"an entry was activated\" instead of the DOM text-selection\n * event. Both would be type errors if merged, and silently confusing if allowed\n * through.\n */\ntype OverriddenDomProps = \"children\" | \"title\" | \"onSelect\";\n\nexport interface NotificationCenterProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n OverriddenDomProps\n> {\n /** Entries to show. Rendered in the order given — `useNotificationInbox` sorts newest first. */\n items: readonly NotificationItem[];\n /**\n * Panel heading. Pass `null` to render the list with no header.\n *\n * Widened from the DOM `title` attribute (a `string`) on purpose: this is a\n * rendered heading, not a tooltip, so it takes a node.\n */\n title?: ReactNode;\n /** Activate an entry: click, `Enter` or `Space`. Also marks it read when `onMarkRead` is set. */\n onSelect?: (item: NotificationItem) => void;\n /** Mark one entry as read. Enables the per-item read control. */\n onMarkRead?: (id: string) => void;\n /** Mark every entry as read. Enables the header action. */\n onMarkAllRead?: () => void;\n /** Remove one entry. Enables the per-item dismiss control. */\n onDismiss?: (id: string) => void;\n /** Icon rendered at the leading edge of each row — an `<Icon name={…} />`, say. */\n renderIcon?: (item: NotificationItem) => ReactNode;\n /** Locale for the relative timestamps. Default `\"pt-BR\"`. */\n locale?: RelativeTimeLocale;\n /** Shown when `items` is empty. */\n emptyState?: ReactNode;\n /** Reference point for the relative timestamps. Default: now, at render time. */\n now?: number;\n}\n\n/**\n * Inbox panel for notifications the app has received.\n *\n * Deliberately presentational and controlled: it takes a list and emits intent.\n * Where the list comes from — an API, a service-worker push, `localStorage` — and\n * where read state is written are app decisions, and a component that assumed any\n * of them would be wrong for most apps. `useNotificationInbox` is the companion\n * that holds the state, including the service-worker bridge.\n *\n * It is also just the panel, not a popover: apps mount it inside their own\n * `Popover`, `Drawer` or route. That keeps one component from owning both the\n * inbox and a positioning strategy.\n *\n * @example\n * const inbox = useNotificationInbox();\n *\n * <Popover trigger={<Button>Notificações ({inbox.unreadCount})</Button>}>\n * <NotificationCenter\n * items={inbox.items}\n * onMarkRead={inbox.markRead}\n * onMarkAllRead={inbox.markAllRead}\n * onDismiss={inbox.remove}\n * onSelect={(item) => item.url && navigate(item.url)}\n * />\n * </Popover>\n */\nexport function NotificationCenter({\n items,\n title = \"Notificações\",\n onSelect,\n onMarkRead,\n onMarkAllRead,\n onDismiss,\n renderIcon,\n locale = \"pt-BR\",\n emptyState,\n now,\n className,\n ...rest\n}: NotificationCenterProps) {\n const unreadCount = items.filter((item) => !item.read).length;\n const reference = now ?? new Date().getTime();\n\n /**\n * Activate an entry.\n *\n * Reading a notification is implied by opening it, so activation marks it read\n * as well — otherwise every app would have to remember to call both, and the\n * unread badge would keep counting something the user already saw.\n */\n const activate = (item: NotificationItem): void => {\n if (!item.read) onMarkRead?.(item.id);\n onSelect?.(item);\n };\n\n const interactive = Boolean(onSelect || onMarkRead);\n\n return (\n <div className={cn(styles.panel, className)} {...rest}>\n {(title || (onMarkAllRead && unreadCount > 0)) && (\n <header className={styles.header}>\n {title ? (\n <h2 className={styles.title}>\n {title}\n {unreadCount > 0 && (\n <Badge variant=\"primary\" aria-label={`${unreadCount} não lidas`}>\n {unreadCount}\n </Badge>\n )}\n </h2>\n ) : (\n <span />\n )}\n {onMarkAllRead && unreadCount > 0 && (\n <button\n type=\"button\"\n className={styles.headerAction}\n onClick={onMarkAllRead}\n >\n Marcar todas como lidas\n </button>\n )}\n </header>\n )}\n\n {items.length === 0 ? (\n (emptyState ?? <EmptyState title=\"Nenhuma notificação\" />)\n ) : (\n <ul className={styles.list}>\n {items.map((item) => (\n <li\n key={item.id}\n className={cn(styles.item, !item.read && styles.unread)}\n aria-current={!item.read ? \"true\" : undefined}\n >\n {renderIcon && <span className={styles.icon}>{renderIcon(item)}</span>}\n\n <div className={styles.body}>\n {interactive ? (\n <button\n type=\"button\"\n className={styles.trigger}\n onClick={() => activate(item)}\n >\n <span className={styles.itemTitle}>{item.title}</span>\n {item.body && (\n <span className={styles.itemBody}>{item.body}</span>\n )}\n </button>\n ) : (\n <>\n <span className={styles.itemTitle}>{item.title}</span>\n {item.body && (\n <span className={styles.itemBody}>{item.body}</span>\n )}\n </>\n )}\n <time\n className={styles.time}\n dateTime={new Date(item.receivedAt).toISOString()}\n >\n {relativeTime(item.receivedAt, { locale, now: reference })}\n </time>\n </div>\n\n {onDismiss && (\n <button\n type=\"button\"\n className={styles.dismiss}\n onClick={() => onDismiss(item.id)}\n aria-label={`Descartar: ${item.title}`}\n >\n ×\n </button>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAmFA,SAAgB,EAAmB,EAC/B,UACA,WAAQ,gBACR,aACA,eACA,kBACA,cACA,eACA,YAAS,SACT,eACA,QACA,cACA,GAAG,KACqB;CACxB,IAAM,IAAc,EAAM,QAAQ,MAAS,CAAC,EAAK,IAAI,CAAC,CAAC,QACjD,IAAY,sBAAO,IAAI,KAAK,EAAA,CAAE,QAAQ,GAStC,KAAY,MAAiC;EAE/C,AADK,EAAK,QAAM,IAAa,EAAK,EAAE,GACpC,IAAW,CAAI;CACnB,GAEM,IAAc,GAAQ,KAAY;CAExC,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,OAAO,CAAS;EAAG,GAAI;YAAjD,EACM,KAAU,KAAiB,IAAc,MACvC,kBAAC,UAAD;GAAQ,WAAW,EAAO;aAA1B,CACK,IACG,kBAAC,MAAD;IAAI,WAAW,EAAO;cAAtB,CACK,GACA,IAAc,KACX,kBAAC,GAAD;KAAO,SAAQ;KAAU,cAAY,GAAG,EAAY;eAC/C;IACE,CAAA,CAEX;QAEJ,kBAAC,QAAD,CAAO,CAAA,GAEV,KAAiB,IAAc,KAC5B,kBAAC,UAAD;IACI,MAAK;IACL,WAAW,EAAO;IAClB,SAAS;cACZ;GAEO,CAAA,CAER;MAGX,EAAM,WAAW,IACb,KAAc,kBAAC,GAAD,EAAY,OAAM,sBAAuB,CAAA,IAExD,kBAAC,MAAD;GAAI,WAAW,EAAO;aACjB,EAAM,KAAK,MACR,kBAAC,MAAD;IAEI,WAAW,EAAG,EAAO,MAAM,CAAC,EAAK,QAAQ,EAAO,MAAM;IACtD,gBAAe,EAAK,OAAgB,KAAA,IAAT;cAH/B;KAKK,KAAc,kBAAC,QAAD;MAAM,WAAW,EAAO;gBAAO,EAAW,CAAI;KAAQ,CAAA;KAErE,kBAAC,OAAD;MAAK,WAAW,EAAO;gBAAvB,CACK,IACG,kBAAC,UAAD;OACI,MAAK;OACL,WAAW,EAAO;OAClB,eAAe,EAAS,CAAI;iBAHhC,CAKI,kBAAC,QAAD;QAAM,WAAW,EAAO;kBAAY,EAAK;OAAY,CAAA,GACpD,EAAK,QACF,kBAAC,QAAD;QAAM,WAAW,EAAO;kBAAW,EAAK;OAAW,CAAA,CAEnD;WAER,kBAAA,GAAA,EAAA,UAAA,CACI,kBAAC,QAAD;OAAM,WAAW,EAAO;iBAAY,EAAK;MAAY,CAAA,GACpD,EAAK,QACF,kBAAC,QAAD;OAAM,WAAW,EAAO;iBAAW,EAAK;MAAW,CAAA,CAEzD,EAAA,CAAA,GAEN,kBAAC,QAAD;OACI,WAAW,EAAO;OAClB,UAAU,IAAI,KAAK,EAAK,UAAU,CAAC,CAAC,YAAY;iBAE/C,EAAa,EAAK,YAAY;QAAE;QAAQ,KAAK;OAAU,CAAC;MACvD,CAAA,CACL;;KAEJ,KACG,kBAAC,UAAD;MACI,MAAK;MACL,WAAW,EAAO;MAClB,eAAe,EAAU,EAAK,EAAE;MAChC,cAAY,cAAc,EAAK;gBAClC;KAEO,CAAA;IAEZ;MA5CK,EAAK,EA4CV,CACP;EACD,CAAA,CAEP;;AAEb"}
|
|
1
|
+
{"version":3,"file":"NotificationCenter.js","names":[],"sources":["../../../src/components/NotificationCenter/NotificationCenter.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count, function-lines — an inbox has four actions the app\n * must implement (onSelect, onMarkRead, onMarkAllRead, onDismiss) over one list,\n * plus the presentation it needs to render a readable feed: renderIcon, locale, now\n * for relative timestamps, emptyState and title.\n */\nimport type { HTMLAttributes, ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\nimport { relativeTime, type RelativeTimeLocale } from \"@/utils/relative-time\";\n\nimport { Badge } from \"../Badge\";\nimport { EmptyState } from \"../EmptyState\";\nimport type { NotificationItem } from \"./use-notification-inbox\";\nimport styles from \"./NotificationCenter.module.css\";\n\n/**\n * DOM attributes this component redefines.\n *\n * `title` becomes a rendered heading node instead of a tooltip string, and\n * `onSelect` becomes \"an entry was activated\" instead of the DOM text-selection\n * event. Both would be type errors if merged, and silently confusing if allowed\n * through.\n */\ntype OverriddenDomProps = \"children\" | \"title\" | \"onSelect\";\n\nexport interface NotificationCenterProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n OverriddenDomProps\n> {\n /** Entries to show. Rendered in the order given — `useNotificationInbox` sorts newest first. */\n items: readonly NotificationItem[];\n /**\n * Panel heading. Pass `null` to render the list with no header.\n *\n * Widened from the DOM `title` attribute (a `string`) on purpose: this is a\n * rendered heading, not a tooltip, so it takes a node.\n */\n title?: ReactNode;\n /** Activate an entry: click, `Enter` or `Space`. Also marks it read when `onMarkRead` is set. */\n onSelect?: (item: NotificationItem) => void;\n /** Mark one entry as read. Enables the per-item read control. */\n onMarkRead?: (id: string) => void;\n /** Mark every entry as read. Enables the header action. */\n onMarkAllRead?: () => void;\n /** Remove one entry. Enables the per-item dismiss control. */\n onDismiss?: (id: string) => void;\n /** Icon rendered at the leading edge of each row — an `<Icon name={…} />`, say. */\n renderIcon?: (item: NotificationItem) => ReactNode;\n /** Locale for the relative timestamps. Default `\"pt-BR\"`. */\n locale?: RelativeTimeLocale;\n /** Shown when `items` is empty. */\n emptyState?: ReactNode;\n /** Reference point for the relative timestamps. Default: now, at render time. */\n now?: number;\n}\n\n/**\n * Inbox panel for notifications the app has received.\n *\n * Deliberately presentational and controlled: it takes a list and emits intent.\n * Where the list comes from — an API, a service-worker push, `localStorage` — and\n * where read state is written are app decisions, and a component that assumed any\n * of them would be wrong for most apps. `useNotificationInbox` is the companion\n * that holds the state, including the service-worker bridge.\n *\n * It is also just the panel, not a popover: apps mount it inside their own\n * `Popover`, `Drawer` or route. That keeps one component from owning both the\n * inbox and a positioning strategy.\n *\n * @example\n * const inbox = useNotificationInbox();\n *\n * <Popover trigger={<Button>Notificações ({inbox.unreadCount})</Button>}>\n * <NotificationCenter\n * items={inbox.items}\n * onMarkRead={inbox.markRead}\n * onMarkAllRead={inbox.markAllRead}\n * onDismiss={inbox.remove}\n * onSelect={(item) => item.url && navigate(item.url)}\n * />\n * </Popover>\n */\nexport function NotificationCenter({\n items,\n title = \"Notificações\",\n onSelect,\n onMarkRead,\n onMarkAllRead,\n onDismiss,\n renderIcon,\n locale = \"pt-BR\",\n emptyState,\n now,\n className,\n ...rest\n}: NotificationCenterProps) {\n const unreadCount = items.filter((item) => !item.read).length;\n const reference = now ?? new Date().getTime();\n\n /**\n * Activate an entry.\n *\n * Reading a notification is implied by opening it, so activation marks it read\n * as well — otherwise every app would have to remember to call both, and the\n * unread badge would keep counting something the user already saw.\n */\n const activate = (item: NotificationItem): void => {\n if (!item.read) onMarkRead?.(item.id);\n onSelect?.(item);\n };\n\n const interactive = Boolean(onSelect || onMarkRead);\n\n return (\n <div className={cn(styles.panel, className)} {...rest}>\n {(title || (onMarkAllRead && unreadCount > 0)) && (\n <header className={styles.header}>\n {title ? (\n <h2 className={styles.title}>\n {title}\n {unreadCount > 0 && (\n <Badge variant=\"primary\" aria-label={`${unreadCount} não lidas`}>\n {unreadCount}\n </Badge>\n )}\n </h2>\n ) : (\n <span />\n )}\n {onMarkAllRead && unreadCount > 0 && (\n <button\n type=\"button\"\n className={styles.headerAction}\n onClick={onMarkAllRead}\n >\n Marcar todas como lidas\n </button>\n )}\n </header>\n )}\n\n {items.length === 0 ? (\n (emptyState ?? <EmptyState title=\"Nenhuma notificação\" />)\n ) : (\n <ul className={styles.list}>\n {items.map((item) => (\n <li\n key={item.id}\n className={cn(styles.item, !item.read && styles.unread)}\n aria-current={!item.read ? \"true\" : undefined}\n >\n {renderIcon && <span className={styles.icon}>{renderIcon(item)}</span>}\n\n <div className={styles.body}>\n {interactive ? (\n <button\n type=\"button\"\n className={styles.trigger}\n onClick={() => activate(item)}\n >\n <span className={styles.itemTitle}>{item.title}</span>\n {item.body && (\n <span className={styles.itemBody}>{item.body}</span>\n )}\n </button>\n ) : (\n <>\n <span className={styles.itemTitle}>{item.title}</span>\n {item.body && (\n <span className={styles.itemBody}>{item.body}</span>\n )}\n </>\n )}\n <time\n className={styles.time}\n dateTime={new Date(item.receivedAt).toISOString()}\n >\n {relativeTime(item.receivedAt, { locale, now: reference })}\n </time>\n </div>\n\n {onDismiss && (\n <button\n type=\"button\"\n className={styles.dismiss}\n onClick={() => onDismiss(item.id)}\n aria-label={`Descartar: ${item.title}`}\n >\n ×\n </button>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAmFA,SAAgB,EAAmB,EAC/B,UACA,WAAQ,gBACR,aACA,eACA,kBACA,cACA,eACA,YAAS,SACT,eACA,QACA,cACA,GAAG,KACqB;CACxB,IAAM,IAAc,EAAM,QAAQ,MAAS,CAAC,EAAK,IAAI,CAAC,CAAC,QACjD,IAAY,sBAAO,IAAI,KAAK,EAAA,CAAE,QAAQ,GAStC,KAAY,MAAiC;EAE/C,AADK,EAAK,QAAM,IAAa,EAAK,EAAE,GACpC,IAAW,CAAI;CACnB,GAEM,IAAc,GAAQ,KAAY;CAExC,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,OAAO,CAAS;EAAG,GAAI;EAAjD,UAAA,EACM,KAAU,KAAiB,IAAc,MACvC,kBAAC,UAAD;GAAQ,WAAW,EAAO;GAA1B,UAAA,CACK,IACG,kBAAC,MAAD;IAAI,WAAW,EAAO;IAAtB,UAAA,CACK,GACA,IAAc,KACX,kBAAC,GAAD;KAAO,SAAQ;KAAU,cAAY,GAAG,EAAY;KAC/C,UAAA;IACE,CAAA,CAEX;GAEJ,CAAA,IAAA,kBAAC,QAAD,CAAO,CAAA,GAEV,KAAiB,IAAc,KAC5B,kBAAC,UAAD;IACI,MAAK;IACL,WAAW,EAAO;IAClB,SAAS;IACZ,UAAA;GAEO,CAAA,CAER;EAGX,CAAA,GAAA,EAAM,WAAW,IACb,KAAc,kBAAC,GAAD,EAAY,OAAM,sBAAuB,CAAA,IAExD,kBAAC,MAAD;GAAI,WAAW,EAAO;GACjB,UAAA,EAAM,KAAK,MACR,kBAAC,MAAD;IAEI,WAAW,EAAG,EAAO,MAAM,CAAC,EAAK,QAAQ,EAAO,MAAM;IACtD,gBAAe,EAAK,OAAgB,KAAA,IAAT;IAH/B,UAAA;KAKK,KAAc,kBAAC,QAAD;MAAM,WAAW,EAAO;MAAO,UAAA,EAAW,CAAI;KAAQ,CAAA;KAErE,kBAAC,OAAD;MAAK,WAAW,EAAO;MAAvB,UAAA,CACK,IACG,kBAAC,UAAD;OACI,MAAK;OACL,WAAW,EAAO;OAClB,eAAe,EAAS,CAAI;OAHhC,UAAA,CAKI,kBAAC,QAAD;QAAM,WAAW,EAAO;QAAY,UAAA,EAAK;OAAY,CAAA,GACpD,EAAK,QACF,kBAAC,QAAD;QAAM,WAAW,EAAO;QAAW,UAAA,EAAK;OAAW,CAAA,CAEnD;MAER,CAAA,IAAA,kBAAA,GAAA,EAAA,UAAA,CACI,kBAAC,QAAD;OAAM,WAAW,EAAO;OAAY,UAAA,EAAK;MAAY,CAAA,GACpD,EAAK,QACF,kBAAC,QAAD;OAAM,WAAW,EAAO;OAAW,UAAA,EAAK;MAAW,CAAA,CAEzD,EAAA,CAAA,GAEN,kBAAC,QAAD;OACI,WAAW,EAAO;OAClB,UAAU,IAAI,KAAK,EAAK,UAAU,CAAC,CAAC,YAAY;OAE/C,UAAA,EAAa,EAAK,YAAY;QAAE;QAAQ,KAAK;OAAU,CAAC;MACvD,CAAA,CACL;;KAEJ,KACG,kBAAC,UAAD;MACI,MAAK;MACL,WAAW,EAAO;MAClB,eAAe,EAAU,EAAK,EAAE;MAChC,cAAY,cAAc,EAAK;MAClC,UAAA;KAEO,CAAA;IAEZ;GA5CK,GAAA,EAAK,EA4CV,CACP;EACD,CAAA,CAEP;;AAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-notification-inbox.cjs","names":[],"sources":["../../../src/components/NotificationCenter/use-notification-inbox.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from \"react\";\n\n/** One entry in the inbox. */\nexport interface NotificationItem {\n /** Stable id. Re-adding an existing id updates that entry instead of duplicating it. */\n id: string;\n title: string;\n /** Body text. Optional — a title-only notification is a legitimate shape. */\n body?: string;\n /** Epoch milliseconds. Used for ordering and for the relative timestamp. */\n receivedAt: number;\n read?: boolean;\n /** Where activating the notification should take the user. */\n url?: string;\n /** Free-form payload the app passes through, e.g. the entity it refers to. */\n data?: Record<string, unknown>;\n}\n\nexport interface UseNotificationInboxOptions {\n /** Entries the inbox starts with — typically what the API returned. */\n initialItems?: readonly NotificationItem[];\n /**\n * Listen for `message` events from the service worker and add whatever\n * arrives. Default `true`.\n *\n * This is the missing half of web push: a service worker runs outside the\n * page and cannot touch React state, so a push that arrives while the app is\n * open shows an OS notification and then vanishes as far as the UI is\n * concerned. Have the worker `postMessage` the payload and it lands here.\n */\n listenToServiceWorker?: boolean;\n /**\n * Message `type` to accept from the worker. Default `\"tempest:notification\"`.\n *\n * Filtering by type matters because the SW message channel is shared — a\n * sync-progress ping or a cache-updated notice would otherwise show up in the\n * user's inbox.\n */\n messageType?: string;\n /**\n * Cap on stored entries; the oldest are dropped past it. Default `100`.\n *\n * An inbox fed by push grows without bound otherwise, and it lives in memory.\n */\n limit?: number;\n /** Called whenever the list changes — the hook for persisting it. */\n onChange?: (items: readonly NotificationItem[]) => void;\n}\n\nexport interface UseNotificationInboxResult {\n items: NotificationItem[];\n unreadCount: number;\n /** Add an entry, or update the existing one with the same id. */\n add: (item: NotificationItem) => void;\n markRead: (id: string) => void;\n markUnread: (id: string) => void;\n markAllRead: () => void;\n remove: (id: string) => void;\n clear: () => void;\n}\n\n/** Coerce an unknown service-worker payload into an inbox entry. */\nfunction toItem(payload: Record<string, unknown>, index: number): NotificationItem | null {\n const title = typeof payload.title === \"string\" ? payload.title : null;\n if (!title) return null;\n return {\n id: typeof payload.id === \"string\" ? payload.id : `sw-${payload.tag ?? index}-${title}`,\n title,\n body: typeof payload.body === \"string\" ? payload.body : undefined,\n receivedAt:\n typeof payload.receivedAt === \"number\" ? payload.receivedAt : new Date().getTime(),\n url: typeof payload.url === \"string\" ? payload.url : undefined,\n data: (payload.data as Record<string, unknown> | undefined) ?? undefined,\n read: false,\n };\n}\n\n/**\n * Client-side inbox state for received notifications.\n *\n * Newest first, deduplicated by `id`, capped at `limit`. Pairs with\n * `NotificationCenter` for the UI and with the `push` module for the source:\n * point a service worker's `postMessage` at it and a push that arrives while the\n * app is open shows up in the inbox instead of only as an OS notification.\n *\n * Persistence is deliberately left out — where an inbox belongs (server, Dexie,\n * `localStorage`) is an app decision. Use `onChange` to write it wherever it goes,\n * and `initialItems` to read it back.\n *\n * @example\n * const inbox = useNotificationInbox({\n * initialItems: await api.notifications.list(),\n * onChange: (items) => storage.set(\"inbox\", items),\n * });\n *\n * <NotificationCenter\n * items={inbox.items}\n * onMarkRead={inbox.markRead}\n * onMarkAllRead={inbox.markAllRead}\n * onDismiss={inbox.remove}\n * />\n */\nexport function useNotificationInbox(\n options: UseNotificationInboxOptions = {},\n): UseNotificationInboxResult {\n const {\n initialItems = [],\n listenToServiceWorker = true,\n messageType = \"tempest:notification\",\n limit = 100,\n onChange,\n } = options;\n\n const [items, setItems] = useState<NotificationItem[]>(() =>\n [...initialItems].sort((a, b) => b.receivedAt - a.receivedAt).slice(0, limit),\n );\n\n const update = useCallback(\n (next: (current: NotificationItem[]) => NotificationItem[]) => {\n setItems((current) => {\n const result = next(current);\n onChange?.(result);\n return result;\n });\n },\n [onChange],\n );\n\n const add = useCallback(\n (item: NotificationItem) => {\n update((current) => {\n const without = current.filter((entry) => entry.id !== item.id);\n return [item, ...without]\n .sort((a, b) => b.receivedAt - a.receivedAt)\n .slice(0, limit);\n });\n },\n [update, limit],\n );\n\n const setRead = useCallback(\n (id: string, read: boolean) => {\n update((current) =>\n current.map((entry) => (entry.id === id ? { ...entry, read } : entry)),\n );\n },\n [update],\n );\n\n const markRead = useCallback((id: string) => setRead(id, true), [setRead]);\n const markUnread = useCallback((id: string) => setRead(id, false), [setRead]);\n\n const markAllRead = useCallback(() => {\n update((current) => current.map((entry) => ({ ...entry, read: true })));\n }, [update]);\n\n const remove = useCallback(\n (id: string) => {\n update((current) => current.filter((entry) => entry.id !== id));\n },\n [update],\n );\n\n const clear = useCallback(() => update(() => []), [update]);\n\n useEffect(() => {\n if (!listenToServiceWorker) return;\n if (typeof navigator === \"undefined\" || !navigator.serviceWorker) return;\n\n /**\n * Captured, not re-read in the cleanup.\n *\n * Looking `navigator.serviceWorker` up again at teardown throws if it is\n * gone by then, and the listener would leak either way — the container has\n * to be the same object the listener was added to.\n */\n const container = navigator.serviceWorker;\n\n const handler = (event: MessageEvent) => {\n const payload = event.data as Record<string, unknown> | null;\n if (!payload || payload.type !== messageType) return;\n const raw = (payload.notification ?? payload.payload ?? payload) as Record<\n string,\n unknown\n >;\n const item = toItem(raw, 0);\n if (item) add(item);\n };\n\n container.addEventListener(\"message\", handler);\n return () => container.removeEventListener(\"message\", handler);\n }, [listenToServiceWorker, messageType, add]);\n\n const unreadCount = useMemo(() => items.filter((item) => !item.read).length, [items]);\n\n return { items, unreadCount, add, markRead, markUnread, markAllRead, remove, clear };\n}\n"],"mappings":"uBA8DA,SAAS,EAAO,EAAkC,EAAwC,CACtF,IAAM,EAAQ,OAAO,EAAQ,OAAU,SAAW,EAAQ,MAAQ,KAElE,OADK,EACE,CACH,GAAI,OAAO,EAAQ,IAAO,SAAW,EAAQ,GAAK,MAAM,EAAQ,KAAO,EAAM,GAAG,IAChF,QACA,KAAM,OAAO,EAAQ,MAAS,SAAW,EAAQ,KAAO,IAAA,GACxD,WACI,OAAO,EAAQ,YAAe,SAAW,EAAQ,WAAa,IAAI,KAAK,CAAA,CAAE,QAAQ,EACrF,IAAK,OAAO,EAAQ,KAAQ,SAAW,EAAQ,IAAM,IAAA,GACrD,KAAO,EAAQ,MAAgD,IAAA,GAC/D,KAAM,EACV,EAVmB,IAWvB,CA2BA,SAAgB,EACZ,EAAuC,CAAC,EACd,CAC1B,GAAM,CACF,eAAe,CAAC,EAChB,wBAAwB,GACxB,cAAc,uBACd,QAAQ,IACR,YACA,EAEE,CAAC,EAAO,IAAA,
|
|
1
|
+
{"version":3,"file":"use-notification-inbox.cjs","names":[],"sources":["../../../src/components/NotificationCenter/use-notification-inbox.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from \"react\";\n\n/** One entry in the inbox. */\nexport interface NotificationItem {\n /** Stable id. Re-adding an existing id updates that entry instead of duplicating it. */\n id: string;\n title: string;\n /** Body text. Optional — a title-only notification is a legitimate shape. */\n body?: string;\n /** Epoch milliseconds. Used for ordering and for the relative timestamp. */\n receivedAt: number;\n read?: boolean;\n /** Where activating the notification should take the user. */\n url?: string;\n /** Free-form payload the app passes through, e.g. the entity it refers to. */\n data?: Record<string, unknown>;\n}\n\nexport interface UseNotificationInboxOptions {\n /** Entries the inbox starts with — typically what the API returned. */\n initialItems?: readonly NotificationItem[];\n /**\n * Listen for `message` events from the service worker and add whatever\n * arrives. Default `true`.\n *\n * This is the missing half of web push: a service worker runs outside the\n * page and cannot touch React state, so a push that arrives while the app is\n * open shows an OS notification and then vanishes as far as the UI is\n * concerned. Have the worker `postMessage` the payload and it lands here.\n */\n listenToServiceWorker?: boolean;\n /**\n * Message `type` to accept from the worker. Default `\"tempest:notification\"`.\n *\n * Filtering by type matters because the SW message channel is shared — a\n * sync-progress ping or a cache-updated notice would otherwise show up in the\n * user's inbox.\n */\n messageType?: string;\n /**\n * Cap on stored entries; the oldest are dropped past it. Default `100`.\n *\n * An inbox fed by push grows without bound otherwise, and it lives in memory.\n */\n limit?: number;\n /** Called whenever the list changes — the hook for persisting it. */\n onChange?: (items: readonly NotificationItem[]) => void;\n}\n\nexport interface UseNotificationInboxResult {\n items: NotificationItem[];\n unreadCount: number;\n /** Add an entry, or update the existing one with the same id. */\n add: (item: NotificationItem) => void;\n markRead: (id: string) => void;\n markUnread: (id: string) => void;\n markAllRead: () => void;\n remove: (id: string) => void;\n clear: () => void;\n}\n\n/** Coerce an unknown service-worker payload into an inbox entry. */\nfunction toItem(payload: Record<string, unknown>, index: number): NotificationItem | null {\n const title = typeof payload.title === \"string\" ? payload.title : null;\n if (!title) return null;\n return {\n id: typeof payload.id === \"string\" ? payload.id : `sw-${payload.tag ?? index}-${title}`,\n title,\n body: typeof payload.body === \"string\" ? payload.body : undefined,\n receivedAt:\n typeof payload.receivedAt === \"number\" ? payload.receivedAt : new Date().getTime(),\n url: typeof payload.url === \"string\" ? payload.url : undefined,\n data: (payload.data as Record<string, unknown> | undefined) ?? undefined,\n read: false,\n };\n}\n\n/**\n * Client-side inbox state for received notifications.\n *\n * Newest first, deduplicated by `id`, capped at `limit`. Pairs with\n * `NotificationCenter` for the UI and with the `push` module for the source:\n * point a service worker's `postMessage` at it and a push that arrives while the\n * app is open shows up in the inbox instead of only as an OS notification.\n *\n * Persistence is deliberately left out — where an inbox belongs (server, Dexie,\n * `localStorage`) is an app decision. Use `onChange` to write it wherever it goes,\n * and `initialItems` to read it back.\n *\n * @example\n * const inbox = useNotificationInbox({\n * initialItems: await api.notifications.list(),\n * onChange: (items) => storage.set(\"inbox\", items),\n * });\n *\n * <NotificationCenter\n * items={inbox.items}\n * onMarkRead={inbox.markRead}\n * onMarkAllRead={inbox.markAllRead}\n * onDismiss={inbox.remove}\n * />\n */\nexport function useNotificationInbox(\n options: UseNotificationInboxOptions = {},\n): UseNotificationInboxResult {\n const {\n initialItems = [],\n listenToServiceWorker = true,\n messageType = \"tempest:notification\",\n limit = 100,\n onChange,\n } = options;\n\n const [items, setItems] = useState<NotificationItem[]>(() =>\n [...initialItems].sort((a, b) => b.receivedAt - a.receivedAt).slice(0, limit),\n );\n\n const update = useCallback(\n (next: (current: NotificationItem[]) => NotificationItem[]) => {\n setItems((current) => {\n const result = next(current);\n onChange?.(result);\n return result;\n });\n },\n [onChange],\n );\n\n const add = useCallback(\n (item: NotificationItem) => {\n update((current) => {\n const without = current.filter((entry) => entry.id !== item.id);\n return [item, ...without]\n .sort((a, b) => b.receivedAt - a.receivedAt)\n .slice(0, limit);\n });\n },\n [update, limit],\n );\n\n const setRead = useCallback(\n (id: string, read: boolean) => {\n update((current) =>\n current.map((entry) => (entry.id === id ? { ...entry, read } : entry)),\n );\n },\n [update],\n );\n\n const markRead = useCallback((id: string) => setRead(id, true), [setRead]);\n const markUnread = useCallback((id: string) => setRead(id, false), [setRead]);\n\n const markAllRead = useCallback(() => {\n update((current) => current.map((entry) => ({ ...entry, read: true })));\n }, [update]);\n\n const remove = useCallback(\n (id: string) => {\n update((current) => current.filter((entry) => entry.id !== id));\n },\n [update],\n );\n\n const clear = useCallback(() => update(() => []), [update]);\n\n useEffect(() => {\n if (!listenToServiceWorker) return;\n if (typeof navigator === \"undefined\" || !navigator.serviceWorker) return;\n\n /**\n * Captured, not re-read in the cleanup.\n *\n * Looking `navigator.serviceWorker` up again at teardown throws if it is\n * gone by then, and the listener would leak either way — the container has\n * to be the same object the listener was added to.\n */\n const container = navigator.serviceWorker;\n\n const handler = (event: MessageEvent) => {\n const payload = event.data as Record<string, unknown> | null;\n if (!payload || payload.type !== messageType) return;\n const raw = (payload.notification ?? payload.payload ?? payload) as Record<\n string,\n unknown\n >;\n const item = toItem(raw, 0);\n if (item) add(item);\n };\n\n container.addEventListener(\"message\", handler);\n return () => container.removeEventListener(\"message\", handler);\n }, [listenToServiceWorker, messageType, add]);\n\n const unreadCount = useMemo(() => items.filter((item) => !item.read).length, [items]);\n\n return { items, unreadCount, add, markRead, markUnread, markAllRead, remove, clear };\n}\n"],"mappings":"uBA8DA,SAAS,EAAO,EAAkC,EAAwC,CACtF,IAAM,EAAQ,OAAO,EAAQ,OAAU,SAAW,EAAQ,MAAQ,KAElE,OADK,EACE,CACH,GAAI,OAAO,EAAQ,IAAO,SAAW,EAAQ,GAAK,MAAM,EAAQ,KAAO,EAAM,GAAG,IAChF,QACA,KAAM,OAAO,EAAQ,MAAS,SAAW,EAAQ,KAAO,IAAA,GACxD,WACI,OAAO,EAAQ,YAAe,SAAW,EAAQ,WAAa,IAAI,KAAK,CAAA,CAAE,QAAQ,EACrF,IAAK,OAAO,EAAQ,KAAQ,SAAW,EAAQ,IAAM,IAAA,GACrD,KAAO,EAAQ,MAAgD,IAAA,GAC/D,KAAM,EACV,EAVmB,IAWvB,CA2BA,SAAgB,EACZ,EAAuC,CAAC,EACd,CAC1B,GAAM,CACF,eAAe,CAAC,EAChB,wBAAwB,GACxB,cAAc,uBACd,QAAQ,IACR,YACA,EAEE,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,KACtB,CAAC,GAAG,CAAY,CAAC,CAAC,MAAM,EAAG,IAAM,EAAE,WAAa,EAAE,UAAU,CAAC,CAAC,MAAM,EAAG,CAAK,CAChF,EAEM,GAAA,EAAS,EAAA,YAAA,CACV,GAA8D,CAC3D,EAAU,GAAY,CAClB,IAAM,EAAS,EAAK,CAAO,EAE3B,OADA,IAAW,CAAM,EACV,CACX,CAAC,CACL,EACA,CAAC,CAAQ,CACb,EAEM,GAAA,EAAM,EAAA,YAAA,CACP,GAA2B,CACxB,EAAQ,GAEG,CAAC,EAAM,GADE,EAAQ,OAAQ,GAAU,EAAM,KAAO,EAAK,EAC3C,CAAO,CAAC,CACpB,MAAM,EAAG,IAAM,EAAE,WAAa,EAAE,UAAU,CAAC,CAC3C,MAAM,EAAG,CAAK,CACtB,CACL,EACA,CAAC,EAAQ,CAAK,CAClB,EAEM,GAAA,EAAU,EAAA,YAAA,EACX,EAAY,IAAkB,CAC3B,EAAQ,GACJ,EAAQ,IAAK,GAAW,EAAM,KAAO,EAAK,CAAE,GAAG,EAAO,MAAK,EAAI,CAAM,CACzE,CACJ,EACA,CAAC,CAAM,CACX,EAEM,GAAA,EAAW,EAAA,YAAA,CAAa,GAAe,EAAQ,EAAI,EAAI,EAAG,CAAC,CAAO,CAAC,EACnE,GAAA,EAAa,EAAA,YAAA,CAAa,GAAe,EAAQ,EAAI,EAAK,EAAG,CAAC,CAAO,CAAC,EAEtE,GAAA,EAAc,EAAA,YAAA,KAAkB,CAClC,EAAQ,GAAY,EAAQ,IAAK,IAAW,CAAE,GAAG,EAAO,KAAM,EAAK,EAAE,CAAC,CAC1E,EAAG,CAAC,CAAM,CAAC,EAEL,GAAA,EAAS,EAAA,YAAA,CACV,GAAe,CACZ,EAAQ,GAAY,EAAQ,OAAQ,GAAU,EAAM,KAAO,CAAE,CAAC,CAClE,EACA,CAAC,CAAM,CACX,EAEM,GAAA,EAAQ,EAAA,YAAA,KAAkB,MAAa,CAAC,CAAC,EAAG,CAAC,CAAM,CAAC,EAgC1D,OA9BA,EAAA,EAAA,UAAA,KAAgB,CAEZ,GADI,CAAC,GACD,OAAO,UAAc,KAAe,CAAC,UAAU,cAAe,OASlE,IAAM,EAAY,UAAU,cAEtB,EAAW,GAAwB,CACrC,IAAM,EAAU,EAAM,KACtB,GAAI,CAAC,GAAW,EAAQ,OAAS,EAAa,OAK9C,IAAM,EAAO,EAJA,EAAQ,cAAgB,EAAQ,SAAW,EAI/B,CAAC,EACtB,GAAM,EAAI,CAAI,CACtB,EAGA,OADA,EAAU,iBAAiB,UAAW,CAAO,MAChC,EAAU,oBAAoB,UAAW,CAAO,CACjE,EAAG,CAAC,EAAuB,EAAa,CAAG,CAAC,EAIrC,CAAE,QAAO,aAAA,EAFI,EAAA,QAAA,KAAc,EAAM,OAAQ,GAAS,CAAC,EAAK,IAAI,CAAC,CAAC,OAAQ,CAAC,CAAK,CAEnE,EAAa,MAAK,WAAU,aAAY,cAAa,SAAQ,OAAM,CACvF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OfflineIndicator.cjs","names":[],"sources":["../../../src/components/OfflineIndicator/OfflineIndicator.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { CloudOff, Wifi } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport { useOnline } from \"@/hooks\";\nimport styles from \"./OfflineIndicator.module.css\";\n\nexport type OfflineIndicatorPosition = \"top\" | \"bottom\";\n\nexport interface OfflineIndicatorProps extends HTMLAttributes<HTMLDivElement> {\n /** Where to pin the fixed bar. Default `\"bottom\"`. */\n position?: OfflineIndicatorPosition;\n /** Message shown while offline. */\n offlineLabel?: ReactNode;\n /** Message flashed briefly when connectivity returns. */\n onlineLabel?: ReactNode;\n /**\n * How long (ms) to keep the \"back online\" flash visible. `0` hides it\n * entirely. Default `3000`.\n */\n onlineFlashMs?: number;\n /** Override the offline body entirely (icon + label ignored). */\n children?: ReactNode;\n}\n\n/**\n * Fixed bar that appears while the browser is offline and, by default, flashes\n * a brief confirmation when the connection returns. Backed by {@link useOnline}\n * — no props needed for the common case.\n *\n * Renders nothing while online (after any flash has elapsed), so it is safe to\n * mount unconditionally at the app root.\n *\n * @example\n * <OfflineIndicator position=\"top\" />\n */\nexport function OfflineIndicator({\n position = \"bottom\",\n offlineLabel = \"Você está offline. As alterações serão sincronizadas ao reconectar.\",\n onlineLabel = \"Conexão restabelecida.\",\n onlineFlashMs = 3000,\n className,\n children,\n ...props\n}: OfflineIndicatorProps) {\n const online = useOnline();\n const [flashOnline, setFlashOnline] = useState<boolean>(false);\n const wasOfflineRef = useRef<boolean>(false);\n\n useEffect(() => {\n if (!online) {\n wasOfflineRef.current = true;\n setFlashOnline(false);\n return;\n }\n if (!wasOfflineRef.current || onlineFlashMs <= 0) return;\n wasOfflineRef.current = false;\n setFlashOnline(true);\n const id = window.setTimeout(() => setFlashOnline(false), onlineFlashMs);\n return () => window.clearTimeout(id);\n }, [online, onlineFlashMs]);\n\n if (online && !flashOnline) return null;\n\n const showingOnline = online && flashOnline;\n return (\n <div\n className={cn(\n styles.bar,\n styles[position],\n showingOnline ? styles.online : styles.offline,\n className,\n )}\n role=\"status\"\n aria-live=\"polite\"\n {...props}\n >\n {children ?? (\n <>\n {showingOnline ? (\n <Wifi className={styles.icon} size={16} aria-hidden=\"true\" />\n ) : (\n <CloudOff className={styles.icon} size={16} aria-hidden=\"true\" />\n )}\n <span>{showingOnline ? onlineLabel : offlineLabel}</span>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"yMAoCA,SAAgB,EAAiB,CAC7B,WAAW,SACX,eAAe,sEACf,cAAc,yBACd,gBAAgB,IAChB,YACA,WACA,GAAG,GACmB,CACtB,IAAM,EAAS,EAAA,UAAU,EACnB,CAAC,EAAa,IAAA,
|
|
1
|
+
{"version":3,"file":"OfflineIndicator.cjs","names":[],"sources":["../../../src/components/OfflineIndicator/OfflineIndicator.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { CloudOff, Wifi } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport { useOnline } from \"@/hooks\";\nimport styles from \"./OfflineIndicator.module.css\";\n\nexport type OfflineIndicatorPosition = \"top\" | \"bottom\";\n\nexport interface OfflineIndicatorProps extends HTMLAttributes<HTMLDivElement> {\n /** Where to pin the fixed bar. Default `\"bottom\"`. */\n position?: OfflineIndicatorPosition;\n /** Message shown while offline. */\n offlineLabel?: ReactNode;\n /** Message flashed briefly when connectivity returns. */\n onlineLabel?: ReactNode;\n /**\n * How long (ms) to keep the \"back online\" flash visible. `0` hides it\n * entirely. Default `3000`.\n */\n onlineFlashMs?: number;\n /** Override the offline body entirely (icon + label ignored). */\n children?: ReactNode;\n}\n\n/**\n * Fixed bar that appears while the browser is offline and, by default, flashes\n * a brief confirmation when the connection returns. Backed by {@link useOnline}\n * — no props needed for the common case.\n *\n * Renders nothing while online (after any flash has elapsed), so it is safe to\n * mount unconditionally at the app root.\n *\n * @example\n * <OfflineIndicator position=\"top\" />\n */\nexport function OfflineIndicator({\n position = \"bottom\",\n offlineLabel = \"Você está offline. As alterações serão sincronizadas ao reconectar.\",\n onlineLabel = \"Conexão restabelecida.\",\n onlineFlashMs = 3000,\n className,\n children,\n ...props\n}: OfflineIndicatorProps) {\n const online = useOnline();\n const [flashOnline, setFlashOnline] = useState<boolean>(false);\n const wasOfflineRef = useRef<boolean>(false);\n\n useEffect(() => {\n if (!online) {\n wasOfflineRef.current = true;\n setFlashOnline(false);\n return;\n }\n if (!wasOfflineRef.current || onlineFlashMs <= 0) return;\n wasOfflineRef.current = false;\n setFlashOnline(true);\n const id = window.setTimeout(() => setFlashOnline(false), onlineFlashMs);\n return () => window.clearTimeout(id);\n }, [online, onlineFlashMs]);\n\n if (online && !flashOnline) return null;\n\n const showingOnline = online && flashOnline;\n return (\n <div\n className={cn(\n styles.bar,\n styles[position],\n showingOnline ? styles.online : styles.offline,\n className,\n )}\n role=\"status\"\n aria-live=\"polite\"\n {...props}\n >\n {children ?? (\n <>\n {showingOnline ? (\n <Wifi className={styles.icon} size={16} aria-hidden=\"true\" />\n ) : (\n <CloudOff className={styles.icon} size={16} aria-hidden=\"true\" />\n )}\n <span>{showingOnline ? onlineLabel : offlineLabel}</span>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"yMAoCA,SAAgB,EAAiB,CAC7B,WAAW,SACX,eAAe,sEACf,cAAc,yBACd,gBAAgB,IAChB,YACA,WACA,GAAG,GACmB,CACtB,IAAM,EAAS,EAAA,UAAU,EACnB,CAAC,EAAa,IAAA,EAAkB,EAAA,SAAA,CAAkB,EAAK,EACvD,GAAA,EAAgB,EAAA,OAAA,CAAgB,EAAK,EAe3C,IAbA,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,CAAC,EAAQ,CACT,EAAc,QAAU,GACxB,EAAe,EAAK,EACpB,MACJ,CACA,GAAI,CAAC,EAAc,SAAW,GAAiB,EAAG,OAClD,EAAc,QAAU,GACxB,EAAe,EAAI,EACnB,IAAM,EAAK,OAAO,eAAiB,EAAe,EAAK,EAAG,CAAa,EACvE,UAAa,OAAO,aAAa,CAAE,CACvC,EAAG,CAAC,EAAQ,CAAa,CAAC,EAEtB,GAAU,CAAC,EAAa,OAAO,KAEnC,IAAM,EAAgB,GAAU,EAChC,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,GACP,EAAA,QAAO,IACP,EAAA,QAAO,GACP,EAAgB,EAAA,QAAO,OAAS,EAAA,QAAO,QACvC,CACJ,EACA,KAAK,SACL,YAAU,SACV,GAAI,EAEH,SAAA,IACG,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,CACK,GACG,EAAA,EAAA,IAAA,CAAC,EAAA,KAAD,CAAM,UAAW,EAAA,QAAO,KAAM,KAAM,GAAI,cAAY,MAAQ,CAAA,GAE5D,EAAA,EAAA,IAAA,CAAC,EAAA,SAAD,CAAU,UAAW,EAAA,QAAO,KAAM,KAAM,GAAI,cAAY,MAAQ,CAAA,GAEpE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAA,SAAO,EAAgB,EAAc,CAAmB,CAAA,CAC1D,CAAA,CAAA,CAEL,CAAA,CAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OfflineIndicator.js","names":[],"sources":["../../../src/components/OfflineIndicator/OfflineIndicator.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { CloudOff, Wifi } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport { useOnline } from \"@/hooks\";\nimport styles from \"./OfflineIndicator.module.css\";\n\nexport type OfflineIndicatorPosition = \"top\" | \"bottom\";\n\nexport interface OfflineIndicatorProps extends HTMLAttributes<HTMLDivElement> {\n /** Where to pin the fixed bar. Default `\"bottom\"`. */\n position?: OfflineIndicatorPosition;\n /** Message shown while offline. */\n offlineLabel?: ReactNode;\n /** Message flashed briefly when connectivity returns. */\n onlineLabel?: ReactNode;\n /**\n * How long (ms) to keep the \"back online\" flash visible. `0` hides it\n * entirely. Default `3000`.\n */\n onlineFlashMs?: number;\n /** Override the offline body entirely (icon + label ignored). */\n children?: ReactNode;\n}\n\n/**\n * Fixed bar that appears while the browser is offline and, by default, flashes\n * a brief confirmation when the connection returns. Backed by {@link useOnline}\n * — no props needed for the common case.\n *\n * Renders nothing while online (after any flash has elapsed), so it is safe to\n * mount unconditionally at the app root.\n *\n * @example\n * <OfflineIndicator position=\"top\" />\n */\nexport function OfflineIndicator({\n position = \"bottom\",\n offlineLabel = \"Você está offline. As alterações serão sincronizadas ao reconectar.\",\n onlineLabel = \"Conexão restabelecida.\",\n onlineFlashMs = 3000,\n className,\n children,\n ...props\n}: OfflineIndicatorProps) {\n const online = useOnline();\n const [flashOnline, setFlashOnline] = useState<boolean>(false);\n const wasOfflineRef = useRef<boolean>(false);\n\n useEffect(() => {\n if (!online) {\n wasOfflineRef.current = true;\n setFlashOnline(false);\n return;\n }\n if (!wasOfflineRef.current || onlineFlashMs <= 0) return;\n wasOfflineRef.current = false;\n setFlashOnline(true);\n const id = window.setTimeout(() => setFlashOnline(false), onlineFlashMs);\n return () => window.clearTimeout(id);\n }, [online, onlineFlashMs]);\n\n if (online && !flashOnline) return null;\n\n const showingOnline = online && flashOnline;\n return (\n <div\n className={cn(\n styles.bar,\n styles[position],\n showingOnline ? styles.online : styles.offline,\n className,\n )}\n role=\"status\"\n aria-live=\"polite\"\n {...props}\n >\n {children ?? (\n <>\n {showingOnline ? (\n <Wifi className={styles.icon} size={16} aria-hidden=\"true\" />\n ) : (\n <CloudOff className={styles.icon} size={16} aria-hidden=\"true\" />\n )}\n <span>{showingOnline ? onlineLabel : offlineLabel}</span>\n </>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAoCA,SAAgB,EAAiB,EAC7B,cAAW,UACX,kBAAe,uEACf,iBAAc,0BACd,mBAAgB,KAChB,cACA,aACA,GAAG,KACmB;CACtB,IAAM,IAAS,EAAU,GACnB,CAAC,GAAa,KAAkB,EAAkB,EAAK,GACvD,IAAgB,EAAgB,EAAK;CAe3C,IAbA,QAAgB;EACZ,IAAI,CAAC,GAAQ;GAET,AADA,EAAc,UAAU,IACxB,EAAe,EAAK;GACpB;EACJ;EACA,IAAI,CAAC,EAAc,WAAW,KAAiB,GAAG;EAElD,AADA,EAAc,UAAU,IACxB,EAAe,EAAI;EACnB,IAAM,IAAK,OAAO,iBAAiB,EAAe,EAAK,GAAG,CAAa;EACvE,aAAa,OAAO,aAAa,CAAE;CACvC,GAAG,CAAC,GAAQ,CAAa,CAAC,GAEtB,KAAU,CAAC,GAAa,OAAO;CAEnC,IAAM,IAAgB,KAAU;CAChC,OACI,kBAAC,OAAD;EACI,WAAW,EACP,EAAO,KACP,EAAO,IACP,IAAgB,EAAO,SAAS,EAAO,SACvC,CACJ;EACA,MAAK;EACL,aAAU;EACV,GAAI;
|
|
1
|
+
{"version":3,"file":"OfflineIndicator.js","names":[],"sources":["../../../src/components/OfflineIndicator/OfflineIndicator.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { CloudOff, Wifi } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport { useOnline } from \"@/hooks\";\nimport styles from \"./OfflineIndicator.module.css\";\n\nexport type OfflineIndicatorPosition = \"top\" | \"bottom\";\n\nexport interface OfflineIndicatorProps extends HTMLAttributes<HTMLDivElement> {\n /** Where to pin the fixed bar. Default `\"bottom\"`. */\n position?: OfflineIndicatorPosition;\n /** Message shown while offline. */\n offlineLabel?: ReactNode;\n /** Message flashed briefly when connectivity returns. */\n onlineLabel?: ReactNode;\n /**\n * How long (ms) to keep the \"back online\" flash visible. `0` hides it\n * entirely. Default `3000`.\n */\n onlineFlashMs?: number;\n /** Override the offline body entirely (icon + label ignored). */\n children?: ReactNode;\n}\n\n/**\n * Fixed bar that appears while the browser is offline and, by default, flashes\n * a brief confirmation when the connection returns. Backed by {@link useOnline}\n * — no props needed for the common case.\n *\n * Renders nothing while online (after any flash has elapsed), so it is safe to\n * mount unconditionally at the app root.\n *\n * @example\n * <OfflineIndicator position=\"top\" />\n */\nexport function OfflineIndicator({\n position = \"bottom\",\n offlineLabel = \"Você está offline. As alterações serão sincronizadas ao reconectar.\",\n onlineLabel = \"Conexão restabelecida.\",\n onlineFlashMs = 3000,\n className,\n children,\n ...props\n}: OfflineIndicatorProps) {\n const online = useOnline();\n const [flashOnline, setFlashOnline] = useState<boolean>(false);\n const wasOfflineRef = useRef<boolean>(false);\n\n useEffect(() => {\n if (!online) {\n wasOfflineRef.current = true;\n setFlashOnline(false);\n return;\n }\n if (!wasOfflineRef.current || onlineFlashMs <= 0) return;\n wasOfflineRef.current = false;\n setFlashOnline(true);\n const id = window.setTimeout(() => setFlashOnline(false), onlineFlashMs);\n return () => window.clearTimeout(id);\n }, [online, onlineFlashMs]);\n\n if (online && !flashOnline) return null;\n\n const showingOnline = online && flashOnline;\n return (\n <div\n className={cn(\n styles.bar,\n styles[position],\n showingOnline ? styles.online : styles.offline,\n className,\n )}\n role=\"status\"\n aria-live=\"polite\"\n {...props}\n >\n {children ?? (\n <>\n {showingOnline ? (\n <Wifi className={styles.icon} size={16} aria-hidden=\"true\" />\n ) : (\n <CloudOff className={styles.icon} size={16} aria-hidden=\"true\" />\n )}\n <span>{showingOnline ? onlineLabel : offlineLabel}</span>\n </>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAoCA,SAAgB,EAAiB,EAC7B,cAAW,UACX,kBAAe,uEACf,iBAAc,0BACd,mBAAgB,KAChB,cACA,aACA,GAAG,KACmB;CACtB,IAAM,IAAS,EAAU,GACnB,CAAC,GAAa,KAAkB,EAAkB,EAAK,GACvD,IAAgB,EAAgB,EAAK;CAe3C,IAbA,QAAgB;EACZ,IAAI,CAAC,GAAQ;GAET,AADA,EAAc,UAAU,IACxB,EAAe,EAAK;GACpB;EACJ;EACA,IAAI,CAAC,EAAc,WAAW,KAAiB,GAAG;EAElD,AADA,EAAc,UAAU,IACxB,EAAe,EAAI;EACnB,IAAM,IAAK,OAAO,iBAAiB,EAAe,EAAK,GAAG,CAAa;EACvE,aAAa,OAAO,aAAa,CAAE;CACvC,GAAG,CAAC,GAAQ,CAAa,CAAC,GAEtB,KAAU,CAAC,GAAa,OAAO;CAEnC,IAAM,IAAgB,KAAU;CAChC,OACI,kBAAC,OAAD;EACI,WAAW,EACP,EAAO,KACP,EAAO,IACP,IAAgB,EAAO,SAAS,EAAO,SACvC,CACJ;EACA,MAAK;EACL,aAAU;EACV,GAAI;EAEH,UAAA,KACG,kBAAA,GAAA,EAAA,UAAA,CAEQ,EADH,IACI,IAEA,GAFD;GAAM,WAAW,EAAO;GAAM,MAAM;GAAI,eAAY;EAAQ,CAEI,GAEpE,kBAAC,QAAD,EAAA,UAAO,IAAgB,IAAc,EAAmB,CAAA,CAC1D,EAAA,CAAA;CAEL,CAAA;AAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Page.cjs","names":[],"sources":["../../../src/components/Page/Page.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a page shell is slots: eyebrow, title, description,\n * actions, toolbar, footer and children, with padded as the one behavioural switch.\n * Slots are the component.\n */\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Page.module.css\";\n\nexport interface PageProps extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n /** Page title rendered as `<h1>`. */\n title?: ReactNode;\n /** Optional subtitle / breadcrumbs slot rendered above the title. */\n eyebrow?: ReactNode;\n /** Optional description rendered below the title. */\n description?: ReactNode;\n /** Right-side actions slot in the header (buttons, menus). */\n actions?: ReactNode;\n /** Sticky tab bar / filter row rendered just below the header. */\n toolbar?: ReactNode;\n /** Footer slot rendered at the bottom of the content area. */\n footer?: ReactNode;\n /** Page-level padding. Default `true`. */\n padded?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Page wrapper with header + (optional) toolbar + content + footer. Pairs\n * with `Container` when you want a max-width content well.\n *\n * @example\n * <Page title=\"Pedidos\" description=\"Acompanhe seus pedidos\" actions={<Button>Novo</Button>}>\n * <Table {...} />\n * </Page>\n */\nexport function Page({\n title,\n eyebrow,\n description,\n actions,\n toolbar,\n footer,\n padded = true,\n className,\n children,\n ...props\n}: PageProps) {\n const hasHeader = title || eyebrow || description || actions;\n return (\n <main className={cn(styles.page, padded && styles.padded, className)} {...props}>\n {hasHeader && (\n <header className={styles.header}>\n <div className={styles.headerText}>\n {eyebrow && <div className={styles.eyebrow}>{eyebrow}</div>}\n {title && <h1 className={styles.title}>{title}</h1>}\n {description && <p className={styles.description}>{description}</p>}\n </div>\n {actions && <div className={styles.actions}>{actions}</div>}\n </header>\n )}\n {toolbar && <div className={styles.toolbar}>{toolbar}</div>}\n <div className={styles.content}>{children}</div>\n {footer && <footer className={styles.footer}>{footer}</footer>}\n </main>\n );\n}\n"],"mappings":"wGAoCA,SAAgB,EAAK,CACjB,QACA,UACA,cACA,UACA,UACA,SACA,SAAS,GACT,YACA,WACA,GAAG,GACO,CACV,IAAM,EAAY,GAAS,GAAW,GAAe,EACrD,OACI,EAAA,EAAA,KAAA,CAAC,OAAD,CAAM,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,GAAU,EAAA,QAAO,OAAQ,CAAS,EAAG,GAAI,
|
|
1
|
+
{"version":3,"file":"Page.cjs","names":[],"sources":["../../../src/components/Page/Page.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a page shell is slots: eyebrow, title, description,\n * actions, toolbar, footer and children, with padded as the one behavioural switch.\n * Slots are the component.\n */\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Page.module.css\";\n\nexport interface PageProps extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n /** Page title rendered as `<h1>`. */\n title?: ReactNode;\n /** Optional subtitle / breadcrumbs slot rendered above the title. */\n eyebrow?: ReactNode;\n /** Optional description rendered below the title. */\n description?: ReactNode;\n /** Right-side actions slot in the header (buttons, menus). */\n actions?: ReactNode;\n /** Sticky tab bar / filter row rendered just below the header. */\n toolbar?: ReactNode;\n /** Footer slot rendered at the bottom of the content area. */\n footer?: ReactNode;\n /** Page-level padding. Default `true`. */\n padded?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Page wrapper with header + (optional) toolbar + content + footer. Pairs\n * with `Container` when you want a max-width content well.\n *\n * @example\n * <Page title=\"Pedidos\" description=\"Acompanhe seus pedidos\" actions={<Button>Novo</Button>}>\n * <Table {...} />\n * </Page>\n */\nexport function Page({\n title,\n eyebrow,\n description,\n actions,\n toolbar,\n footer,\n padded = true,\n className,\n children,\n ...props\n}: PageProps) {\n const hasHeader = title || eyebrow || description || actions;\n return (\n <main className={cn(styles.page, padded && styles.padded, className)} {...props}>\n {hasHeader && (\n <header className={styles.header}>\n <div className={styles.headerText}>\n {eyebrow && <div className={styles.eyebrow}>{eyebrow}</div>}\n {title && <h1 className={styles.title}>{title}</h1>}\n {description && <p className={styles.description}>{description}</p>}\n </div>\n {actions && <div className={styles.actions}>{actions}</div>}\n </header>\n )}\n {toolbar && <div className={styles.toolbar}>{toolbar}</div>}\n <div className={styles.content}>{children}</div>\n {footer && <footer className={styles.footer}>{footer}</footer>}\n </main>\n );\n}\n"],"mappings":"wGAoCA,SAAgB,EAAK,CACjB,QACA,UACA,cACA,UACA,UACA,SACA,SAAS,GACT,YACA,WACA,GAAG,GACO,CACV,IAAM,EAAY,GAAS,GAAW,GAAe,EACrD,OACI,EAAA,EAAA,KAAA,CAAC,OAAD,CAAM,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,GAAU,EAAA,QAAO,OAAQ,CAAS,EAAG,GAAI,EAA1E,SAAA,CACK,IACG,EAAA,EAAA,KAAA,CAAC,SAAD,CAAQ,UAAW,EAAA,QAAO,OAA1B,SAAA,EACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,WAAvB,SAAA,CACK,IAAW,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,QAAU,SAAA,CAAa,CAAA,EACzD,IAAS,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,MAAQ,SAAA,CAAU,CAAA,EACjD,IAAe,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAA,QAAO,YAAc,SAAA,CAAe,CAAA,CACjE,CACJ,CAAA,EAAA,IAAW,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,QAAU,SAAA,CAAa,CAAA,CACtD,IAEX,IAAW,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,QAAU,SAAA,CAAa,CAAA,GAC1D,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,QAAU,UAAc,CAAA,EAC9C,IAAU,EAAA,EAAA,IAAA,CAAC,SAAD,CAAQ,UAAW,EAAA,QAAO,OAAS,SAAA,CAAe,CAAA,CAC3D,GAEd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Page.js","names":[],"sources":["../../../src/components/Page/Page.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a page shell is slots: eyebrow, title, description,\n * actions, toolbar, footer and children, with padded as the one behavioural switch.\n * Slots are the component.\n */\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Page.module.css\";\n\nexport interface PageProps extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n /** Page title rendered as `<h1>`. */\n title?: ReactNode;\n /** Optional subtitle / breadcrumbs slot rendered above the title. */\n eyebrow?: ReactNode;\n /** Optional description rendered below the title. */\n description?: ReactNode;\n /** Right-side actions slot in the header (buttons, menus). */\n actions?: ReactNode;\n /** Sticky tab bar / filter row rendered just below the header. */\n toolbar?: ReactNode;\n /** Footer slot rendered at the bottom of the content area. */\n footer?: ReactNode;\n /** Page-level padding. Default `true`. */\n padded?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Page wrapper with header + (optional) toolbar + content + footer. Pairs\n * with `Container` when you want a max-width content well.\n *\n * @example\n * <Page title=\"Pedidos\" description=\"Acompanhe seus pedidos\" actions={<Button>Novo</Button>}>\n * <Table {...} />\n * </Page>\n */\nexport function Page({\n title,\n eyebrow,\n description,\n actions,\n toolbar,\n footer,\n padded = true,\n className,\n children,\n ...props\n}: PageProps) {\n const hasHeader = title || eyebrow || description || actions;\n return (\n <main className={cn(styles.page, padded && styles.padded, className)} {...props}>\n {hasHeader && (\n <header className={styles.header}>\n <div className={styles.headerText}>\n {eyebrow && <div className={styles.eyebrow}>{eyebrow}</div>}\n {title && <h1 className={styles.title}>{title}</h1>}\n {description && <p className={styles.description}>{description}</p>}\n </div>\n {actions && <div className={styles.actions}>{actions}</div>}\n </header>\n )}\n {toolbar && <div className={styles.toolbar}>{toolbar}</div>}\n <div className={styles.content}>{children}</div>\n {footer && <footer className={styles.footer}>{footer}</footer>}\n </main>\n );\n}\n"],"mappings":";;;;AAoCA,SAAgB,EAAK,EACjB,UACA,YACA,gBACA,YACA,YACA,WACA,YAAS,IACT,cACA,aACA,GAAG,KACO;CACV,IAAM,IAAY,KAAS,KAAW,KAAe;CACrD,OACI,kBAAC,QAAD;EAAM,WAAW,EAAG,EAAO,MAAM,KAAU,EAAO,QAAQ,CAAS;EAAG,GAAI;
|
|
1
|
+
{"version":3,"file":"Page.js","names":[],"sources":["../../../src/components/Page/Page.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a page shell is slots: eyebrow, title, description,\n * actions, toolbar, footer and children, with padded as the one behavioural switch.\n * Slots are the component.\n */\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Page.module.css\";\n\nexport interface PageProps extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n /** Page title rendered as `<h1>`. */\n title?: ReactNode;\n /** Optional subtitle / breadcrumbs slot rendered above the title. */\n eyebrow?: ReactNode;\n /** Optional description rendered below the title. */\n description?: ReactNode;\n /** Right-side actions slot in the header (buttons, menus). */\n actions?: ReactNode;\n /** Sticky tab bar / filter row rendered just below the header. */\n toolbar?: ReactNode;\n /** Footer slot rendered at the bottom of the content area. */\n footer?: ReactNode;\n /** Page-level padding. Default `true`. */\n padded?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Page wrapper with header + (optional) toolbar + content + footer. Pairs\n * with `Container` when you want a max-width content well.\n *\n * @example\n * <Page title=\"Pedidos\" description=\"Acompanhe seus pedidos\" actions={<Button>Novo</Button>}>\n * <Table {...} />\n * </Page>\n */\nexport function Page({\n title,\n eyebrow,\n description,\n actions,\n toolbar,\n footer,\n padded = true,\n className,\n children,\n ...props\n}: PageProps) {\n const hasHeader = title || eyebrow || description || actions;\n return (\n <main className={cn(styles.page, padded && styles.padded, className)} {...props}>\n {hasHeader && (\n <header className={styles.header}>\n <div className={styles.headerText}>\n {eyebrow && <div className={styles.eyebrow}>{eyebrow}</div>}\n {title && <h1 className={styles.title}>{title}</h1>}\n {description && <p className={styles.description}>{description}</p>}\n </div>\n {actions && <div className={styles.actions}>{actions}</div>}\n </header>\n )}\n {toolbar && <div className={styles.toolbar}>{toolbar}</div>}\n <div className={styles.content}>{children}</div>\n {footer && <footer className={styles.footer}>{footer}</footer>}\n </main>\n );\n}\n"],"mappings":";;;;AAoCA,SAAgB,EAAK,EACjB,UACA,YACA,gBACA,YACA,YACA,WACA,YAAS,IACT,cACA,aACA,GAAG,KACO;CACV,IAAM,IAAY,KAAS,KAAW,KAAe;CACrD,OACI,kBAAC,QAAD;EAAM,WAAW,EAAG,EAAO,MAAM,KAAU,EAAO,QAAQ,CAAS;EAAG,GAAI;EAA1E,UAAA;GACK,KACG,kBAAC,UAAD;IAAQ,WAAW,EAAO;IAA1B,UAAA,CACI,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAvB,UAAA;MACK,KAAW,kBAAC,OAAD;OAAK,WAAW,EAAO;OAAU,UAAA;MAAa,CAAA;MACzD,KAAS,kBAAC,MAAD;OAAI,WAAW,EAAO;OAAQ,UAAA;MAAU,CAAA;MACjD,KAAe,kBAAC,KAAD;OAAG,WAAW,EAAO;OAAc,UAAA;MAAe,CAAA;KACjE;IACJ,CAAA,GAAA,KAAW,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAU,UAAA;IAAa,CAAA,CACtD;;GAEX,KAAW,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAU,UAAA;GAAa,CAAA;GAC1D,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAU;GAAc,CAAA;GAC9C,KAAU,kBAAC,UAAD;IAAQ,WAAW,EAAO;IAAS,UAAA;GAAe,CAAA;EAC3D;;AAEd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pagination.cjs","names":[],"sources":["../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — page/totalPages/onPageChange is the pager,\n * pageSize/onPageSizeChange/ pageSizeOptions is the size control that sits in the\n * same bar, and totalItems plus siblingCount decide the copy and how many page\n * buttons are rendered. They ship together because a footer that pages but cannot\n * resize is half a footer.\n */\nimport { useMemo } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Pagination.module.css\";\n\nexport interface PaginationProps {\n page: number;\n totalPages: number;\n onPageChange: (page: number) => void;\n pageSize?: number;\n onPageSizeChange?: (size: number) => void;\n pageSizeOptions?: number[];\n /** Total items count; if provided, renders the summary text. */\n totalItems?: number;\n /** Max number of numbered page buttons to show. Default 7. */\n siblingCount?: number;\n className?: string;\n}\n\nfunction buildRange(page: number, totalPages: number, siblings: number): (number | \"...\")[] {\n const totalSlots = siblings + 4;\n if (totalPages <= totalSlots) {\n return Array.from({ length: totalPages }, (_, i) => i + 1);\n }\n const start = Math.max(2, page - Math.floor(siblings / 2));\n const end = Math.min(totalPages - 1, start + siblings - 1);\n const range: (number | \"...\")[] = [1];\n if (start > 2) range.push(\"...\");\n for (let i = start; i <= end; i++) range.push(i);\n if (end < totalPages - 1) range.push(\"...\");\n range.push(totalPages);\n return range;\n}\n\n/**\n * Numeric pagination controls. Pair with {@link usePagination} for state.\n */\nexport function Pagination({\n page,\n totalPages,\n onPageChange,\n pageSize,\n onPageSizeChange,\n pageSizeOptions = [10, 25, 50, 100],\n totalItems,\n siblingCount = 3,\n className,\n}: PaginationProps) {\n const pages = useMemo(\n () => buildRange(page, totalPages, siblingCount),\n [page, totalPages, siblingCount],\n );\n\n if (totalPages <= 1 && !onPageSizeChange) return null;\n\n return (\n <div className={cn(styles.wrapper, className)}>\n <div className={styles.summary}>\n {typeof totalItems === \"number\"\n ? `${totalItems} resultado${totalItems === 1 ? \"\" : \"s\"}`\n : `Página ${page} de ${totalPages}`}\n </div>\n <div className={styles.controls}>\n <button\n type=\"button\"\n className={styles.page}\n onClick={() => onPageChange(Math.max(1, page - 1))}\n disabled={page <= 1}\n aria-label=\"Página anterior\"\n >\n ‹\n </button>\n {pages.map((entry, index) =>\n entry === \"...\" ? (\n <span\n key={`ellipsis-${index}`}\n className={cn(styles.ellipsis, styles.numeric)}\n >\n …\n </span>\n ) : (\n <button\n type=\"button\"\n key={entry}\n className={cn(\n styles.page,\n styles.numeric,\n entry === page && styles.active,\n )}\n onClick={() => onPageChange(entry)}\n aria-current={entry === page ? \"page\" : undefined}\n >\n {entry}\n </button>\n ),\n )}\n <button\n type=\"button\"\n className={styles.page}\n onClick={() => onPageChange(Math.min(totalPages, page + 1))}\n disabled={page >= totalPages}\n aria-label=\"Próxima página\"\n >\n ›\n </button>\n {onPageSizeChange && (\n <select\n className={styles.sizeSelect}\n value={pageSize}\n onChange={(event) => onPageSizeChange(Number(event.target.value))}\n aria-label=\"Itens por página\"\n >\n {pageSizeOptions.map((opt) => (\n <option key={opt} value={opt}>\n {opt} / página\n </option>\n ))}\n </select>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"iIAyBA,SAAS,EAAW,EAAc,EAAoB,EAAsC,CAExF,GAAI,GADe,EAAW,EAE1B,OAAO,MAAM,KAAK,CAAE,OAAQ,CAAW,GAAI,EAAG,IAAM,EAAI,CAAC,EAE7D,IAAM,EAAQ,KAAK,IAAI,EAAG,EAAO,KAAK,MAAM,EAAW,CAAC,CAAC,EACnD,EAAM,KAAK,IAAI,EAAa,EAAG,EAAQ,EAAW,CAAC,EACnD,EAA4B,CAAC,CAAC,EAChC,EAAQ,GAAG,EAAM,KAAK,KAAK,EAC/B,IAAK,IAAI,EAAI,EAAO,GAAK,EAAK,IAAK,EAAM,KAAK,CAAC,EAG/C,OAFI,EAAM,EAAa,GAAG,EAAM,KAAK,KAAK,EAC1C,EAAM,KAAK,CAAU,EACd,CACX,CAKA,SAAgB,EAAW,CACvB,OACA,aACA,eACA,WACA,mBACA,kBAAkB,CAAC,GAAI,GAAI,GAAI,GAAG,EAClC,aACA,eAAe,EACf,aACgB,CAChB,IAAM,GAAA,
|
|
1
|
+
{"version":3,"file":"Pagination.cjs","names":[],"sources":["../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — page/totalPages/onPageChange is the pager,\n * pageSize/onPageSizeChange/ pageSizeOptions is the size control that sits in the\n * same bar, and totalItems plus siblingCount decide the copy and how many page\n * buttons are rendered. They ship together because a footer that pages but cannot\n * resize is half a footer.\n */\nimport { useMemo } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Pagination.module.css\";\n\nexport interface PaginationProps {\n page: number;\n totalPages: number;\n onPageChange: (page: number) => void;\n pageSize?: number;\n onPageSizeChange?: (size: number) => void;\n pageSizeOptions?: number[];\n /** Total items count; if provided, renders the summary text. */\n totalItems?: number;\n /** Max number of numbered page buttons to show. Default 7. */\n siblingCount?: number;\n className?: string;\n}\n\nfunction buildRange(page: number, totalPages: number, siblings: number): (number | \"...\")[] {\n const totalSlots = siblings + 4;\n if (totalPages <= totalSlots) {\n return Array.from({ length: totalPages }, (_, i) => i + 1);\n }\n const start = Math.max(2, page - Math.floor(siblings / 2));\n const end = Math.min(totalPages - 1, start + siblings - 1);\n const range: (number | \"...\")[] = [1];\n if (start > 2) range.push(\"...\");\n for (let i = start; i <= end; i++) range.push(i);\n if (end < totalPages - 1) range.push(\"...\");\n range.push(totalPages);\n return range;\n}\n\n/**\n * Numeric pagination controls. Pair with {@link usePagination} for state.\n */\nexport function Pagination({\n page,\n totalPages,\n onPageChange,\n pageSize,\n onPageSizeChange,\n pageSizeOptions = [10, 25, 50, 100],\n totalItems,\n siblingCount = 3,\n className,\n}: PaginationProps) {\n const pages = useMemo(\n () => buildRange(page, totalPages, siblingCount),\n [page, totalPages, siblingCount],\n );\n\n if (totalPages <= 1 && !onPageSizeChange) return null;\n\n return (\n <div className={cn(styles.wrapper, className)}>\n <div className={styles.summary}>\n {typeof totalItems === \"number\"\n ? `${totalItems} resultado${totalItems === 1 ? \"\" : \"s\"}`\n : `Página ${page} de ${totalPages}`}\n </div>\n <div className={styles.controls}>\n <button\n type=\"button\"\n className={styles.page}\n onClick={() => onPageChange(Math.max(1, page - 1))}\n disabled={page <= 1}\n aria-label=\"Página anterior\"\n >\n ‹\n </button>\n {pages.map((entry, index) =>\n entry === \"...\" ? (\n <span\n key={`ellipsis-${index}`}\n className={cn(styles.ellipsis, styles.numeric)}\n >\n …\n </span>\n ) : (\n <button\n type=\"button\"\n key={entry}\n className={cn(\n styles.page,\n styles.numeric,\n entry === page && styles.active,\n )}\n onClick={() => onPageChange(entry)}\n aria-current={entry === page ? \"page\" : undefined}\n >\n {entry}\n </button>\n ),\n )}\n <button\n type=\"button\"\n className={styles.page}\n onClick={() => onPageChange(Math.min(totalPages, page + 1))}\n disabled={page >= totalPages}\n aria-label=\"Próxima página\"\n >\n ›\n </button>\n {onPageSizeChange && (\n <select\n className={styles.sizeSelect}\n value={pageSize}\n onChange={(event) => onPageSizeChange(Number(event.target.value))}\n aria-label=\"Itens por página\"\n >\n {pageSizeOptions.map((opt) => (\n <option key={opt} value={opt}>\n {opt} / página\n </option>\n ))}\n </select>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"iIAyBA,SAAS,EAAW,EAAc,EAAoB,EAAsC,CAExF,GAAI,GADe,EAAW,EAE1B,OAAO,MAAM,KAAK,CAAE,OAAQ,CAAW,GAAI,EAAG,IAAM,EAAI,CAAC,EAE7D,IAAM,EAAQ,KAAK,IAAI,EAAG,EAAO,KAAK,MAAM,EAAW,CAAC,CAAC,EACnD,EAAM,KAAK,IAAI,EAAa,EAAG,EAAQ,EAAW,CAAC,EACnD,EAA4B,CAAC,CAAC,EAChC,EAAQ,GAAG,EAAM,KAAK,KAAK,EAC/B,IAAK,IAAI,EAAI,EAAO,GAAK,EAAK,IAAK,EAAM,KAAK,CAAC,EAG/C,OAFI,EAAM,EAAa,GAAG,EAAM,KAAK,KAAK,EAC1C,EAAM,KAAK,CAAU,EACd,CACX,CAKA,SAAgB,EAAW,CACvB,OACA,aACA,eACA,WACA,mBACA,kBAAkB,CAAC,GAAI,GAAI,GAAI,GAAG,EAClC,aACA,eAAe,EACf,aACgB,CAChB,IAAM,GAAA,EAAQ,EAAA,QAAA,KACJ,EAAW,EAAM,EAAY,CAAY,EAC/C,CAAC,EAAM,EAAY,CAAY,CACnC,EAIA,OAFI,GAAc,GAAK,CAAC,EAAyB,MAG7C,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EAA5C,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,QAClB,SAAA,OAAO,GAAe,SACjB,GAAG,EAAW,YAAY,IAAe,EAAI,GAAK,MAClD,UAAU,EAAK,MAAM,GAC1B,CAAA,GACL,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,SAAvB,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,KAClB,YAAe,EAAa,KAAK,IAAI,EAAG,EAAO,CAAC,CAAC,EACjD,SAAU,GAAQ,EAClB,aAAW,kBACd,SAAA,GAEO,CAAA,EACP,EAAM,KAAK,EAAO,IACf,IAAU,OACN,EAAA,EAAA,IAAA,CAAC,OAAD,CAEI,UAAW,EAAA,GAAG,EAAA,QAAO,SAAU,EAAA,QAAO,OAAO,EAChD,SAAA,GAEK,EAJG,YAAY,GAIf,GAEN,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SAEL,UAAW,EAAA,GACP,EAAA,QAAO,KACP,EAAA,QAAO,QACP,IAAU,GAAQ,EAAA,QAAO,MAC7B,EACA,YAAe,EAAa,CAAK,EACjC,eAAc,IAAU,EAAO,OAAS,IAAA,GAEvC,SAAA,CACG,EAVC,CAUD,CAEhB,GACA,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,KAClB,YAAe,EAAa,KAAK,IAAI,EAAY,EAAO,CAAC,CAAC,EAC1D,SAAU,GAAQ,EAClB,aAAW,iBACd,SAAA,GAEO,CAAA,EACP,IACG,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,UAAW,EAAA,QAAO,WAClB,MAAO,EACP,SAAW,GAAU,EAAiB,OAAO,EAAM,OAAO,KAAK,CAAC,EAChE,aAAW,mBAEV,SAAA,EAAgB,IAAK,IAClB,EAAA,EAAA,KAAA,CAAC,SAAD,CAAkB,MAAO,EAAzB,SAAA,CACK,EAAI,WACD,CAFK,EAAA,CAEL,CACX,CACG,CAAA,CAEX,CACJ,CAAA,CAAA,GAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pagination.js","names":[],"sources":["../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — page/totalPages/onPageChange is the pager,\n * pageSize/onPageSizeChange/ pageSizeOptions is the size control that sits in the\n * same bar, and totalItems plus siblingCount decide the copy and how many page\n * buttons are rendered. They ship together because a footer that pages but cannot\n * resize is half a footer.\n */\nimport { useMemo } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Pagination.module.css\";\n\nexport interface PaginationProps {\n page: number;\n totalPages: number;\n onPageChange: (page: number) => void;\n pageSize?: number;\n onPageSizeChange?: (size: number) => void;\n pageSizeOptions?: number[];\n /** Total items count; if provided, renders the summary text. */\n totalItems?: number;\n /** Max number of numbered page buttons to show. Default 7. */\n siblingCount?: number;\n className?: string;\n}\n\nfunction buildRange(page: number, totalPages: number, siblings: number): (number | \"...\")[] {\n const totalSlots = siblings + 4;\n if (totalPages <= totalSlots) {\n return Array.from({ length: totalPages }, (_, i) => i + 1);\n }\n const start = Math.max(2, page - Math.floor(siblings / 2));\n const end = Math.min(totalPages - 1, start + siblings - 1);\n const range: (number | \"...\")[] = [1];\n if (start > 2) range.push(\"...\");\n for (let i = start; i <= end; i++) range.push(i);\n if (end < totalPages - 1) range.push(\"...\");\n range.push(totalPages);\n return range;\n}\n\n/**\n * Numeric pagination controls. Pair with {@link usePagination} for state.\n */\nexport function Pagination({\n page,\n totalPages,\n onPageChange,\n pageSize,\n onPageSizeChange,\n pageSizeOptions = [10, 25, 50, 100],\n totalItems,\n siblingCount = 3,\n className,\n}: PaginationProps) {\n const pages = useMemo(\n () => buildRange(page, totalPages, siblingCount),\n [page, totalPages, siblingCount],\n );\n\n if (totalPages <= 1 && !onPageSizeChange) return null;\n\n return (\n <div className={cn(styles.wrapper, className)}>\n <div className={styles.summary}>\n {typeof totalItems === \"number\"\n ? `${totalItems} resultado${totalItems === 1 ? \"\" : \"s\"}`\n : `Página ${page} de ${totalPages}`}\n </div>\n <div className={styles.controls}>\n <button\n type=\"button\"\n className={styles.page}\n onClick={() => onPageChange(Math.max(1, page - 1))}\n disabled={page <= 1}\n aria-label=\"Página anterior\"\n >\n ‹\n </button>\n {pages.map((entry, index) =>\n entry === \"...\" ? (\n <span\n key={`ellipsis-${index}`}\n className={cn(styles.ellipsis, styles.numeric)}\n >\n …\n </span>\n ) : (\n <button\n type=\"button\"\n key={entry}\n className={cn(\n styles.page,\n styles.numeric,\n entry === page && styles.active,\n )}\n onClick={() => onPageChange(entry)}\n aria-current={entry === page ? \"page\" : undefined}\n >\n {entry}\n </button>\n ),\n )}\n <button\n type=\"button\"\n className={styles.page}\n onClick={() => onPageChange(Math.min(totalPages, page + 1))}\n disabled={page >= totalPages}\n aria-label=\"Próxima página\"\n >\n ›\n </button>\n {onPageSizeChange && (\n <select\n className={styles.sizeSelect}\n value={pageSize}\n onChange={(event) => onPageSizeChange(Number(event.target.value))}\n aria-label=\"Itens por página\"\n >\n {pageSizeOptions.map((opt) => (\n <option key={opt} value={opt}>\n {opt} / página\n </option>\n ))}\n </select>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAyBA,SAAS,EAAW,GAAc,GAAoB,GAAsC;CAExF,IAAI,KADe,IAAW,GAE1B,OAAO,MAAM,KAAK,EAAE,QAAQ,EAAW,IAAI,GAAG,MAAM,IAAI,CAAC;CAE7D,IAAM,IAAQ,KAAK,IAAI,GAAG,IAAO,KAAK,MAAM,IAAW,CAAC,CAAC,GACnD,IAAM,KAAK,IAAI,IAAa,GAAG,IAAQ,IAAW,CAAC,GACnD,IAA4B,CAAC,CAAC;CACpC,AAAI,IAAQ,KAAG,EAAM,KAAK,KAAK;CAC/B,KAAK,IAAI,IAAI,GAAO,KAAK,GAAK,KAAK,EAAM,KAAK,CAAC;CAG/C,OAFI,IAAM,IAAa,KAAG,EAAM,KAAK,KAAK,GAC1C,EAAM,KAAK,CAAU,GACd;AACX;AAKA,SAAgB,EAAW,EACvB,SACA,eACA,iBACA,aACA,qBACA,qBAAkB;CAAC;CAAI;CAAI;CAAI;AAAG,GAClC,eACA,kBAAe,GACf,gBACgB;CAChB,IAAM,IAAQ,QACJ,EAAW,GAAM,GAAY,CAAY,GAC/C;EAAC;EAAM;EAAY;CAAY,CACnC;CAIA,OAFI,KAAc,KAAK,CAAC,IAAyB,OAG7C,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAS;
|
|
1
|
+
{"version":3,"file":"Pagination.js","names":[],"sources":["../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — page/totalPages/onPageChange is the pager,\n * pageSize/onPageSizeChange/ pageSizeOptions is the size control that sits in the\n * same bar, and totalItems plus siblingCount decide the copy and how many page\n * buttons are rendered. They ship together because a footer that pages but cannot\n * resize is half a footer.\n */\nimport { useMemo } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Pagination.module.css\";\n\nexport interface PaginationProps {\n page: number;\n totalPages: number;\n onPageChange: (page: number) => void;\n pageSize?: number;\n onPageSizeChange?: (size: number) => void;\n pageSizeOptions?: number[];\n /** Total items count; if provided, renders the summary text. */\n totalItems?: number;\n /** Max number of numbered page buttons to show. Default 7. */\n siblingCount?: number;\n className?: string;\n}\n\nfunction buildRange(page: number, totalPages: number, siblings: number): (number | \"...\")[] {\n const totalSlots = siblings + 4;\n if (totalPages <= totalSlots) {\n return Array.from({ length: totalPages }, (_, i) => i + 1);\n }\n const start = Math.max(2, page - Math.floor(siblings / 2));\n const end = Math.min(totalPages - 1, start + siblings - 1);\n const range: (number | \"...\")[] = [1];\n if (start > 2) range.push(\"...\");\n for (let i = start; i <= end; i++) range.push(i);\n if (end < totalPages - 1) range.push(\"...\");\n range.push(totalPages);\n return range;\n}\n\n/**\n * Numeric pagination controls. Pair with {@link usePagination} for state.\n */\nexport function Pagination({\n page,\n totalPages,\n onPageChange,\n pageSize,\n onPageSizeChange,\n pageSizeOptions = [10, 25, 50, 100],\n totalItems,\n siblingCount = 3,\n className,\n}: PaginationProps) {\n const pages = useMemo(\n () => buildRange(page, totalPages, siblingCount),\n [page, totalPages, siblingCount],\n );\n\n if (totalPages <= 1 && !onPageSizeChange) return null;\n\n return (\n <div className={cn(styles.wrapper, className)}>\n <div className={styles.summary}>\n {typeof totalItems === \"number\"\n ? `${totalItems} resultado${totalItems === 1 ? \"\" : \"s\"}`\n : `Página ${page} de ${totalPages}`}\n </div>\n <div className={styles.controls}>\n <button\n type=\"button\"\n className={styles.page}\n onClick={() => onPageChange(Math.max(1, page - 1))}\n disabled={page <= 1}\n aria-label=\"Página anterior\"\n >\n ‹\n </button>\n {pages.map((entry, index) =>\n entry === \"...\" ? (\n <span\n key={`ellipsis-${index}`}\n className={cn(styles.ellipsis, styles.numeric)}\n >\n …\n </span>\n ) : (\n <button\n type=\"button\"\n key={entry}\n className={cn(\n styles.page,\n styles.numeric,\n entry === page && styles.active,\n )}\n onClick={() => onPageChange(entry)}\n aria-current={entry === page ? \"page\" : undefined}\n >\n {entry}\n </button>\n ),\n )}\n <button\n type=\"button\"\n className={styles.page}\n onClick={() => onPageChange(Math.min(totalPages, page + 1))}\n disabled={page >= totalPages}\n aria-label=\"Próxima página\"\n >\n ›\n </button>\n {onPageSizeChange && (\n <select\n className={styles.sizeSelect}\n value={pageSize}\n onChange={(event) => onPageSizeChange(Number(event.target.value))}\n aria-label=\"Itens por página\"\n >\n {pageSizeOptions.map((opt) => (\n <option key={opt} value={opt}>\n {opt} / página\n </option>\n ))}\n </select>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAyBA,SAAS,EAAW,GAAc,GAAoB,GAAsC;CAExF,IAAI,KADe,IAAW,GAE1B,OAAO,MAAM,KAAK,EAAE,QAAQ,EAAW,IAAI,GAAG,MAAM,IAAI,CAAC;CAE7D,IAAM,IAAQ,KAAK,IAAI,GAAG,IAAO,KAAK,MAAM,IAAW,CAAC,CAAC,GACnD,IAAM,KAAK,IAAI,IAAa,GAAG,IAAQ,IAAW,CAAC,GACnD,IAA4B,CAAC,CAAC;CACpC,AAAI,IAAQ,KAAG,EAAM,KAAK,KAAK;CAC/B,KAAK,IAAI,IAAI,GAAO,KAAK,GAAK,KAAK,EAAM,KAAK,CAAC;CAG/C,OAFI,IAAM,IAAa,KAAG,EAAM,KAAK,KAAK,GAC1C,EAAM,KAAK,CAAU,GACd;AACX;AAKA,SAAgB,EAAW,EACvB,SACA,eACA,iBACA,aACA,qBACA,qBAAkB;CAAC;CAAI;CAAI;CAAI;AAAG,GAClC,eACA,kBAAe,GACf,gBACgB;CAChB,IAAM,IAAQ,QACJ,EAAW,GAAM,GAAY,CAAY,GAC/C;EAAC;EAAM;EAAY;CAAY,CACnC;CAIA,OAFI,KAAc,KAAK,CAAC,IAAyB,OAG7C,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAS;EAA5C,UAAA,CACI,kBAAC,OAAD;GAAK,WAAW,EAAO;GAClB,UAAA,OAAO,KAAe,WACjB,GAAG,EAAW,YAAY,MAAe,IAAI,KAAK,QAClD,UAAU,EAAK,MAAM;EAC1B,CAAA,GACL,kBAAC,OAAD;GAAK,WAAW,EAAO;GAAvB,UAAA;IACI,kBAAC,UAAD;KACI,MAAK;KACL,WAAW,EAAO;KAClB,eAAe,EAAa,KAAK,IAAI,GAAG,IAAO,CAAC,CAAC;KACjD,UAAU,KAAQ;KAClB,cAAW;KACd,UAAA;IAEO,CAAA;IACP,EAAM,KAAK,GAAO,MACf,MAAU,QACN,kBAAC,QAAD;KAEI,WAAW,EAAG,EAAO,UAAU,EAAO,OAAO;KAChD,UAAA;IAEK,GAJG,YAAY,GAIf,IAEN,kBAAC,UAAD;KACI,MAAK;KAEL,WAAW,EACP,EAAO,MACP,EAAO,SACP,MAAU,KAAQ,EAAO,MAC7B;KACA,eAAe,EAAa,CAAK;KACjC,gBAAc,MAAU,IAAO,SAAS,KAAA;KAEvC,UAAA;IACG,GAVC,CAUD,CAEhB;IACA,kBAAC,UAAD;KACI,MAAK;KACL,WAAW,EAAO;KAClB,eAAe,EAAa,KAAK,IAAI,GAAY,IAAO,CAAC,CAAC;KAC1D,UAAU,KAAQ;KAClB,cAAW;KACd,UAAA;IAEO,CAAA;IACP,KACG,kBAAC,UAAD;KACI,WAAW,EAAO;KAClB,OAAO;KACP,WAAW,MAAU,EAAiB,OAAO,EAAM,OAAO,KAAK,CAAC;KAChE,cAAW;KAEV,UAAA,EAAgB,KAAK,MAClB,kBAAC,UAAD;MAAkB,OAAO;MAAzB,UAAA,CACK,GAAI,WACD;KAFK,GAAA,CAEL,CACX;IACG,CAAA;GAEX;EACJ,CAAA,CAAA;;AAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PasswordInput.cjs","names":[],"sources":["../../../src/components/PasswordInput/PasswordInput.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — on top of the SDK's shared field props,\n * showStrength/strength/strengthLabels are the meter and toggleLabels is the\n * show/hide button's accessible name — both need their copy from the app, since\n * neither can be translated by the SDK.\n */\nimport { forwardRef, useId, useState } from \"react\";\nimport type { InputHTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./PasswordInput.module.css\";\n\nexport type PasswordStrength = 0 | 1 | 2 | 3 | 4;\n\nexport interface PasswordInputProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"type\" | \"size\"\n> {\n /** Label rendered above the input. */\n label?: ReactNode;\n /** Helper text below — replaced by `error` when set. */\n helperText?: ReactNode;\n /** Error message. Adds `aria-invalid` + red border. */\n error?: string;\n /** Visual size of the input. */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Show a strength meter below the field. Default `false`. */\n showStrength?: boolean;\n /** Override the automatic strength calc (0–4). */\n strength?: PasswordStrength;\n /** Custom labels per strength level (5 entries). */\n strengthLabels?: readonly [string, string, string, string, string];\n /** Custom toggle button labels for accessibility. */\n toggleLabels?: { show: string; hide: string };\n}\n\nconst DEFAULT_STRENGTH_LABELS = [\"Muito fraca\", \"Fraca\", \"Razoável\", \"Forte\", \"Excelente\"] as const;\n\nexport function estimatePasswordStrength(value: string): PasswordStrength {\n if (!value) return 0;\n let score = 0;\n if (value.length >= 8) score += 1;\n if (value.length >= 12) score += 1;\n if (/[a-z]/.test(value) && /[A-Z]/.test(value)) score += 1;\n if (/[0-9]/.test(value)) score += 1;\n if (/[^A-Za-z0-9]/.test(value)) score += 1;\n return Math.min(4, score) as PasswordStrength;\n}\n\n/**\n * Password field with toggle-visibility button and optional strength meter.\n *\n * @example\n * <PasswordInput label=\"Senha\" showStrength autoComplete=\"new-password\" />\n */\nexport const PasswordInput = forwardRef<HTMLInputElement, PasswordInputProps>(\n function PasswordInput(\n {\n label,\n helperText,\n error,\n size = \"md\",\n showStrength = false,\n strength,\n strengthLabels = DEFAULT_STRENGTH_LABELS,\n toggleLabels = { show: \"Mostrar senha\", hide: \"Esconder senha\" },\n className,\n value,\n defaultValue,\n id,\n ...inputProps\n },\n ref,\n ) {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const describedById = error\n ? `${inputId}-error`\n : helperText\n ? `${inputId}-helper`\n : undefined;\n const [revealed, setRevealed] = useState<boolean>(false);\n const stringValue = String((value ?? defaultValue ?? \"\") as string);\n const computedStrength: PasswordStrength =\n strength ?? estimatePasswordStrength(stringValue);\n\n return (\n <div className={cn(styles.wrapper, styles[size], error && styles.error, className)}>\n {label && (\n <label htmlFor={inputId} className={styles.label}>\n {label}\n </label>\n )}\n <div className={styles.field}>\n <input\n ref={ref}\n {...inputProps}\n id={inputId}\n value={value}\n defaultValue={defaultValue}\n type={revealed ? \"text\" : \"password\"}\n aria-invalid={!!error}\n aria-describedby={describedById}\n className={styles.input}\n />\n <button\n type=\"button\"\n className={styles.toggle}\n aria-label={revealed ? toggleLabels.hide : toggleLabels.show}\n aria-pressed={revealed}\n onClick={() => setRevealed((on) => !on)}\n >\n {revealed ? \"🙈\" : \"👁\"}\n </button>\n </div>\n {showStrength && (\n <div\n className={cn(styles.strength, styles[`level${computedStrength}`])}\n aria-label={strengthLabels[computedStrength]}\n >\n <div className={styles.strengthBar}>\n <span style={{ width: `${(computedStrength / 4) * 100}%` }} />\n </div>\n <span className={styles.strengthLabel}>\n {strengthLabels[computedStrength]}\n </span>\n </div>\n )}\n {error ? (\n <span id={`${inputId}-error`} className={styles.errorText}>\n {error}\n </span>\n ) : helperText ? (\n <span id={`${inputId}-helper`} className={styles.helper}>\n {helperText}\n </span>\n ) : null}\n </div>\n );\n },\n);\n"],"mappings":"oIAmCA,IAAM,EAA0B,CAAC,cAAe,QAAS,WAAY,QAAS,WAAW,EAEzF,SAAgB,EAAyB,EAAiC,CACtE,GAAI,CAAC,EAAO,MAAO,GACnB,IAAI,EAAQ,EAMZ,OALI,EAAM,QAAU,IAAG,GAAS,GAC5B,EAAM,QAAU,KAAI,GAAS,GAC7B,QAAQ,KAAK,CAAK,GAAK,QAAQ,KAAK,CAAK,IAAG,GAAS,GACrD,QAAQ,KAAK,CAAK,IAAG,GAAS,GAC9B,eAAe,KAAK,CAAK,IAAG,GAAS,GAClC,KAAK,IAAI,EAAG,CAAK,CAC5B,CAQA,IAAa,GAAA,
|
|
1
|
+
{"version":3,"file":"PasswordInput.cjs","names":[],"sources":["../../../src/components/PasswordInput/PasswordInput.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — on top of the SDK's shared field props,\n * showStrength/strength/strengthLabels are the meter and toggleLabels is the\n * show/hide button's accessible name — both need their copy from the app, since\n * neither can be translated by the SDK.\n */\nimport { forwardRef, useId, useState } from \"react\";\nimport type { InputHTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./PasswordInput.module.css\";\n\nexport type PasswordStrength = 0 | 1 | 2 | 3 | 4;\n\nexport interface PasswordInputProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"type\" | \"size\"\n> {\n /** Label rendered above the input. */\n label?: ReactNode;\n /** Helper text below — replaced by `error` when set. */\n helperText?: ReactNode;\n /** Error message. Adds `aria-invalid` + red border. */\n error?: string;\n /** Visual size of the input. */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Show a strength meter below the field. Default `false`. */\n showStrength?: boolean;\n /** Override the automatic strength calc (0–4). */\n strength?: PasswordStrength;\n /** Custom labels per strength level (5 entries). */\n strengthLabels?: readonly [string, string, string, string, string];\n /** Custom toggle button labels for accessibility. */\n toggleLabels?: { show: string; hide: string };\n}\n\nconst DEFAULT_STRENGTH_LABELS = [\"Muito fraca\", \"Fraca\", \"Razoável\", \"Forte\", \"Excelente\"] as const;\n\nexport function estimatePasswordStrength(value: string): PasswordStrength {\n if (!value) return 0;\n let score = 0;\n if (value.length >= 8) score += 1;\n if (value.length >= 12) score += 1;\n if (/[a-z]/.test(value) && /[A-Z]/.test(value)) score += 1;\n if (/[0-9]/.test(value)) score += 1;\n if (/[^A-Za-z0-9]/.test(value)) score += 1;\n return Math.min(4, score) as PasswordStrength;\n}\n\n/**\n * Password field with toggle-visibility button and optional strength meter.\n *\n * @example\n * <PasswordInput label=\"Senha\" showStrength autoComplete=\"new-password\" />\n */\nexport const PasswordInput = forwardRef<HTMLInputElement, PasswordInputProps>(\n function PasswordInput(\n {\n label,\n helperText,\n error,\n size = \"md\",\n showStrength = false,\n strength,\n strengthLabels = DEFAULT_STRENGTH_LABELS,\n toggleLabels = { show: \"Mostrar senha\", hide: \"Esconder senha\" },\n className,\n value,\n defaultValue,\n id,\n ...inputProps\n },\n ref,\n ) {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const describedById = error\n ? `${inputId}-error`\n : helperText\n ? `${inputId}-helper`\n : undefined;\n const [revealed, setRevealed] = useState<boolean>(false);\n const stringValue = String((value ?? defaultValue ?? \"\") as string);\n const computedStrength: PasswordStrength =\n strength ?? estimatePasswordStrength(stringValue);\n\n return (\n <div className={cn(styles.wrapper, styles[size], error && styles.error, className)}>\n {label && (\n <label htmlFor={inputId} className={styles.label}>\n {label}\n </label>\n )}\n <div className={styles.field}>\n <input\n ref={ref}\n {...inputProps}\n id={inputId}\n value={value}\n defaultValue={defaultValue}\n type={revealed ? \"text\" : \"password\"}\n aria-invalid={!!error}\n aria-describedby={describedById}\n className={styles.input}\n />\n <button\n type=\"button\"\n className={styles.toggle}\n aria-label={revealed ? toggleLabels.hide : toggleLabels.show}\n aria-pressed={revealed}\n onClick={() => setRevealed((on) => !on)}\n >\n {revealed ? \"🙈\" : \"👁\"}\n </button>\n </div>\n {showStrength && (\n <div\n className={cn(styles.strength, styles[`level${computedStrength}`])}\n aria-label={strengthLabels[computedStrength]}\n >\n <div className={styles.strengthBar}>\n <span style={{ width: `${(computedStrength / 4) * 100}%` }} />\n </div>\n <span className={styles.strengthLabel}>\n {strengthLabels[computedStrength]}\n </span>\n </div>\n )}\n {error ? (\n <span id={`${inputId}-error`} className={styles.errorText}>\n {error}\n </span>\n ) : helperText ? (\n <span id={`${inputId}-helper`} className={styles.helper}>\n {helperText}\n </span>\n ) : null}\n </div>\n );\n },\n);\n"],"mappings":"oIAmCA,IAAM,EAA0B,CAAC,cAAe,QAAS,WAAY,QAAS,WAAW,EAEzF,SAAgB,EAAyB,EAAiC,CACtE,GAAI,CAAC,EAAO,MAAO,GACnB,IAAI,EAAQ,EAMZ,OALI,EAAM,QAAU,IAAG,GAAS,GAC5B,EAAM,QAAU,KAAI,GAAS,GAC7B,QAAQ,KAAK,CAAK,GAAK,QAAQ,KAAK,CAAK,IAAG,GAAS,GACrD,QAAQ,KAAK,CAAK,IAAG,GAAS,GAC9B,eAAe,KAAK,CAAK,IAAG,GAAS,GAClC,KAAK,IAAI,EAAG,CAAK,CAC5B,CAQA,IAAa,GAAA,EAAgB,EAAA,WAAA,CACzB,SACI,CACI,QACA,aACA,QACA,OAAO,KACP,eAAe,GACf,WACA,iBAAiB,EACjB,eAAe,CAAE,KAAM,gBAAiB,KAAM,gBAAiB,EAC/D,YACA,QACA,eACA,KACA,GAAG,GAEP,EACF,CACE,IAAM,GAAA,EAAc,EAAA,MAAA,CAAM,EACpB,EAAU,GAAM,EAChB,EAAgB,EAChB,GAAG,EAAQ,QACX,EACE,GAAG,EAAQ,SACX,IAAA,GACF,CAAC,EAAU,IAAA,EAAe,EAAA,SAAA,CAAkB,EAAK,EAEjD,EACF,GAAY,EAFI,OAAQ,GAAS,GAAgB,EAEZ,CAAW,EAEpD,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,EAAA,QAAO,GAAO,GAAS,EAAA,QAAO,MAAO,CAAS,EAAjF,SAAA,CACK,IACG,EAAA,EAAA,IAAA,CAAC,QAAD,CAAO,QAAS,EAAS,UAAW,EAAA,QAAO,MACtC,SAAA,CACE,CAAA,GAEX,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,MAAvB,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,QAAD,CACS,MACL,GAAI,EACJ,GAAI,EACG,QACO,eACd,KAAM,EAAW,OAAS,WAC1B,eAAc,CAAC,CAAC,EAChB,mBAAkB,EAClB,UAAW,EAAA,QAAO,KACrB,CAAA,GACD,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,OAClB,aAAY,EAAW,EAAa,KAAO,EAAa,KACxD,eAAc,EACd,YAAe,EAAa,GAAO,CAAC,CAAE,EAErC,SAAA,EAAW,KAAO,IACf,CAAA,CACP,IACJ,IACG,EAAA,EAAA,KAAA,CAAC,MAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,SAAU,EAAA,QAAO,QAAQ,IAAmB,EACjE,aAAY,EAAe,GAF/B,SAAA,EAII,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,YACnB,UAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,MAAO,CAAE,MAAO,GAAI,EAAmB,EAAK,IAAI,EAAG,CAAI,CAAA,CAC5D,CAAA,GACL,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,cACnB,SAAA,EAAe,EACd,CAAA,CACL,IAER,GACG,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,GAAI,GAAG,EAAQ,QAAS,UAAW,EAAA,QAAO,UAC3C,SAAA,CACC,CAAA,EACN,GACA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,GAAI,GAAG,EAAQ,SAAU,UAAW,EAAA,QAAO,OAC5C,SAAA,CACC,CAAA,EACN,IACH,GAEb,CACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PasswordInput.js","names":[],"sources":["../../../src/components/PasswordInput/PasswordInput.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — on top of the SDK's shared field props,\n * showStrength/strength/strengthLabels are the meter and toggleLabels is the\n * show/hide button's accessible name — both need their copy from the app, since\n * neither can be translated by the SDK.\n */\nimport { forwardRef, useId, useState } from \"react\";\nimport type { InputHTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./PasswordInput.module.css\";\n\nexport type PasswordStrength = 0 | 1 | 2 | 3 | 4;\n\nexport interface PasswordInputProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"type\" | \"size\"\n> {\n /** Label rendered above the input. */\n label?: ReactNode;\n /** Helper text below — replaced by `error` when set. */\n helperText?: ReactNode;\n /** Error message. Adds `aria-invalid` + red border. */\n error?: string;\n /** Visual size of the input. */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Show a strength meter below the field. Default `false`. */\n showStrength?: boolean;\n /** Override the automatic strength calc (0–4). */\n strength?: PasswordStrength;\n /** Custom labels per strength level (5 entries). */\n strengthLabels?: readonly [string, string, string, string, string];\n /** Custom toggle button labels for accessibility. */\n toggleLabels?: { show: string; hide: string };\n}\n\nconst DEFAULT_STRENGTH_LABELS = [\"Muito fraca\", \"Fraca\", \"Razoável\", \"Forte\", \"Excelente\"] as const;\n\nexport function estimatePasswordStrength(value: string): PasswordStrength {\n if (!value) return 0;\n let score = 0;\n if (value.length >= 8) score += 1;\n if (value.length >= 12) score += 1;\n if (/[a-z]/.test(value) && /[A-Z]/.test(value)) score += 1;\n if (/[0-9]/.test(value)) score += 1;\n if (/[^A-Za-z0-9]/.test(value)) score += 1;\n return Math.min(4, score) as PasswordStrength;\n}\n\n/**\n * Password field with toggle-visibility button and optional strength meter.\n *\n * @example\n * <PasswordInput label=\"Senha\" showStrength autoComplete=\"new-password\" />\n */\nexport const PasswordInput = forwardRef<HTMLInputElement, PasswordInputProps>(\n function PasswordInput(\n {\n label,\n helperText,\n error,\n size = \"md\",\n showStrength = false,\n strength,\n strengthLabels = DEFAULT_STRENGTH_LABELS,\n toggleLabels = { show: \"Mostrar senha\", hide: \"Esconder senha\" },\n className,\n value,\n defaultValue,\n id,\n ...inputProps\n },\n ref,\n ) {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const describedById = error\n ? `${inputId}-error`\n : helperText\n ? `${inputId}-helper`\n : undefined;\n const [revealed, setRevealed] = useState<boolean>(false);\n const stringValue = String((value ?? defaultValue ?? \"\") as string);\n const computedStrength: PasswordStrength =\n strength ?? estimatePasswordStrength(stringValue);\n\n return (\n <div className={cn(styles.wrapper, styles[size], error && styles.error, className)}>\n {label && (\n <label htmlFor={inputId} className={styles.label}>\n {label}\n </label>\n )}\n <div className={styles.field}>\n <input\n ref={ref}\n {...inputProps}\n id={inputId}\n value={value}\n defaultValue={defaultValue}\n type={revealed ? \"text\" : \"password\"}\n aria-invalid={!!error}\n aria-describedby={describedById}\n className={styles.input}\n />\n <button\n type=\"button\"\n className={styles.toggle}\n aria-label={revealed ? toggleLabels.hide : toggleLabels.show}\n aria-pressed={revealed}\n onClick={() => setRevealed((on) => !on)}\n >\n {revealed ? \"🙈\" : \"👁\"}\n </button>\n </div>\n {showStrength && (\n <div\n className={cn(styles.strength, styles[`level${computedStrength}`])}\n aria-label={strengthLabels[computedStrength]}\n >\n <div className={styles.strengthBar}>\n <span style={{ width: `${(computedStrength / 4) * 100}%` }} />\n </div>\n <span className={styles.strengthLabel}>\n {strengthLabels[computedStrength]}\n </span>\n </div>\n )}\n {error ? (\n <span id={`${inputId}-error`} className={styles.errorText}>\n {error}\n </span>\n ) : helperText ? (\n <span id={`${inputId}-helper`} className={styles.helper}>\n {helperText}\n </span>\n ) : null}\n </div>\n );\n },\n);\n"],"mappings":";;;;;AAmCA,IAAM,IAA0B;CAAC;CAAe;CAAS;CAAY;CAAS;AAAW;AAEzF,SAAgB,EAAyB,GAAiC;CACtE,IAAI,CAAC,GAAO,OAAO;CACnB,IAAI,IAAQ;CAMZ,OALI,EAAM,UAAU,MAAG,KAAS,IAC5B,EAAM,UAAU,OAAI,KAAS,IAC7B,QAAQ,KAAK,CAAK,KAAK,QAAQ,KAAK,CAAK,MAAG,KAAS,IACrD,QAAQ,KAAK,CAAK,MAAG,KAAS,IAC9B,eAAe,KAAK,CAAK,MAAG,KAAS,IAClC,KAAK,IAAI,GAAG,CAAK;AAC5B;AAQA,IAAa,IAAgB,EACzB,SACI,EACI,UACA,eACA,UACA,UAAO,MACP,kBAAe,IACf,aACA,oBAAiB,GACjB,kBAAe;CAAE,MAAM;CAAiB,MAAM;AAAiB,GAC/D,cACA,UACA,iBACA,OACA,GAAG,KAEP,GACF;CACE,IAAM,IAAc,EAAM,GACpB,IAAU,KAAM,GAChB,IAAgB,IAChB,GAAG,EAAQ,UACX,IACE,GAAG,EAAQ,WACX,KAAA,GACF,CAAC,GAAU,KAAe,EAAkB,EAAK,GAEjD,IACF,KAAY,EAFI,OAAQ,KAAS,KAAgB,EAEZ,CAAW;CAEpD,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,EAAO,IAAO,KAAS,EAAO,OAAO,CAAS;
|
|
1
|
+
{"version":3,"file":"PasswordInput.js","names":[],"sources":["../../../src/components/PasswordInput/PasswordInput.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — on top of the SDK's shared field props,\n * showStrength/strength/strengthLabels are the meter and toggleLabels is the\n * show/hide button's accessible name — both need their copy from the app, since\n * neither can be translated by the SDK.\n */\nimport { forwardRef, useId, useState } from \"react\";\nimport type { InputHTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./PasswordInput.module.css\";\n\nexport type PasswordStrength = 0 | 1 | 2 | 3 | 4;\n\nexport interface PasswordInputProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"type\" | \"size\"\n> {\n /** Label rendered above the input. */\n label?: ReactNode;\n /** Helper text below — replaced by `error` when set. */\n helperText?: ReactNode;\n /** Error message. Adds `aria-invalid` + red border. */\n error?: string;\n /** Visual size of the input. */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Show a strength meter below the field. Default `false`. */\n showStrength?: boolean;\n /** Override the automatic strength calc (0–4). */\n strength?: PasswordStrength;\n /** Custom labels per strength level (5 entries). */\n strengthLabels?: readonly [string, string, string, string, string];\n /** Custom toggle button labels for accessibility. */\n toggleLabels?: { show: string; hide: string };\n}\n\nconst DEFAULT_STRENGTH_LABELS = [\"Muito fraca\", \"Fraca\", \"Razoável\", \"Forte\", \"Excelente\"] as const;\n\nexport function estimatePasswordStrength(value: string): PasswordStrength {\n if (!value) return 0;\n let score = 0;\n if (value.length >= 8) score += 1;\n if (value.length >= 12) score += 1;\n if (/[a-z]/.test(value) && /[A-Z]/.test(value)) score += 1;\n if (/[0-9]/.test(value)) score += 1;\n if (/[^A-Za-z0-9]/.test(value)) score += 1;\n return Math.min(4, score) as PasswordStrength;\n}\n\n/**\n * Password field with toggle-visibility button and optional strength meter.\n *\n * @example\n * <PasswordInput label=\"Senha\" showStrength autoComplete=\"new-password\" />\n */\nexport const PasswordInput = forwardRef<HTMLInputElement, PasswordInputProps>(\n function PasswordInput(\n {\n label,\n helperText,\n error,\n size = \"md\",\n showStrength = false,\n strength,\n strengthLabels = DEFAULT_STRENGTH_LABELS,\n toggleLabels = { show: \"Mostrar senha\", hide: \"Esconder senha\" },\n className,\n value,\n defaultValue,\n id,\n ...inputProps\n },\n ref,\n ) {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const describedById = error\n ? `${inputId}-error`\n : helperText\n ? `${inputId}-helper`\n : undefined;\n const [revealed, setRevealed] = useState<boolean>(false);\n const stringValue = String((value ?? defaultValue ?? \"\") as string);\n const computedStrength: PasswordStrength =\n strength ?? estimatePasswordStrength(stringValue);\n\n return (\n <div className={cn(styles.wrapper, styles[size], error && styles.error, className)}>\n {label && (\n <label htmlFor={inputId} className={styles.label}>\n {label}\n </label>\n )}\n <div className={styles.field}>\n <input\n ref={ref}\n {...inputProps}\n id={inputId}\n value={value}\n defaultValue={defaultValue}\n type={revealed ? \"text\" : \"password\"}\n aria-invalid={!!error}\n aria-describedby={describedById}\n className={styles.input}\n />\n <button\n type=\"button\"\n className={styles.toggle}\n aria-label={revealed ? toggleLabels.hide : toggleLabels.show}\n aria-pressed={revealed}\n onClick={() => setRevealed((on) => !on)}\n >\n {revealed ? \"🙈\" : \"👁\"}\n </button>\n </div>\n {showStrength && (\n <div\n className={cn(styles.strength, styles[`level${computedStrength}`])}\n aria-label={strengthLabels[computedStrength]}\n >\n <div className={styles.strengthBar}>\n <span style={{ width: `${(computedStrength / 4) * 100}%` }} />\n </div>\n <span className={styles.strengthLabel}>\n {strengthLabels[computedStrength]}\n </span>\n </div>\n )}\n {error ? (\n <span id={`${inputId}-error`} className={styles.errorText}>\n {error}\n </span>\n ) : helperText ? (\n <span id={`${inputId}-helper`} className={styles.helper}>\n {helperText}\n </span>\n ) : null}\n </div>\n );\n },\n);\n"],"mappings":";;;;;AAmCA,IAAM,IAA0B;CAAC;CAAe;CAAS;CAAY;CAAS;AAAW;AAEzF,SAAgB,EAAyB,GAAiC;CACtE,IAAI,CAAC,GAAO,OAAO;CACnB,IAAI,IAAQ;CAMZ,OALI,EAAM,UAAU,MAAG,KAAS,IAC5B,EAAM,UAAU,OAAI,KAAS,IAC7B,QAAQ,KAAK,CAAK,KAAK,QAAQ,KAAK,CAAK,MAAG,KAAS,IACrD,QAAQ,KAAK,CAAK,MAAG,KAAS,IAC9B,eAAe,KAAK,CAAK,MAAG,KAAS,IAClC,KAAK,IAAI,GAAG,CAAK;AAC5B;AAQA,IAAa,IAAgB,EACzB,SACI,EACI,UACA,eACA,UACA,UAAO,MACP,kBAAe,IACf,aACA,oBAAiB,GACjB,kBAAe;CAAE,MAAM;CAAiB,MAAM;AAAiB,GAC/D,cACA,UACA,iBACA,OACA,GAAG,KAEP,GACF;CACE,IAAM,IAAc,EAAM,GACpB,IAAU,KAAM,GAChB,IAAgB,IAChB,GAAG,EAAQ,UACX,IACE,GAAG,EAAQ,WACX,KAAA,GACF,CAAC,GAAU,KAAe,EAAkB,EAAK,GAEjD,IACF,KAAY,EAFI,OAAQ,KAAS,KAAgB,EAEZ,CAAW;CAEpD,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,EAAO,IAAO,KAAS,EAAO,OAAO,CAAS;EAAjF,UAAA;GACK,KACG,kBAAC,SAAD;IAAO,SAAS;IAAS,WAAW,EAAO;IACtC,UAAA;GACE,CAAA;GAEX,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAvB,UAAA,CACI,kBAAC,SAAD;KACS;KACL,GAAI;KACJ,IAAI;KACG;KACO;KACd,MAAM,IAAW,SAAS;KAC1B,gBAAc,CAAC,CAAC;KAChB,oBAAkB;KAClB,WAAW,EAAO;IACrB,CAAA,GACD,kBAAC,UAAD;KACI,MAAK;KACL,WAAW,EAAO;KAClB,cAAY,IAAW,EAAa,OAAO,EAAa;KACxD,gBAAc;KACd,eAAe,GAAa,MAAO,CAAC,CAAE;KAErC,UAAA,IAAW,OAAO;IACf,CAAA,CACP;;GACJ,KACG,kBAAC,OAAD;IACI,WAAW,EAAG,EAAO,UAAU,EAAO,QAAQ,IAAmB;IACjE,cAAY,EAAe;IAF/B,UAAA,CAII,kBAAC,OAAD;KAAK,WAAW,EAAO;KACnB,UAAA,kBAAC,QAAD,EAAM,OAAO,EAAE,OAAO,GAAI,IAAmB,IAAK,IAAI,GAAG,EAAI,CAAA;IAC5D,CAAA,GACL,kBAAC,QAAD;KAAM,WAAW,EAAO;KACnB,UAAA,EAAe;IACd,CAAA,CACL;;GAER,IACG,kBAAC,QAAD;IAAM,IAAI,GAAG,EAAQ;IAAS,WAAW,EAAO;IAC3C,UAAA;GACC,CAAA,IACN,IACA,kBAAC,QAAD;IAAM,IAAI,GAAG,EAAQ;IAAU,WAAW,EAAO;IAC5C,UAAA;GACC,CAAA,IACN;EACH;;AAEb,CACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PinInput.cjs","names":[],"sources":["../../../src/components/PinInput/PinInput.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count, function-lines — one input per digit, so length,\n * type, masked and autoFocus shape the boxes while\n * value/defaultValue/onChange/onComplete drive them as a single value. The body owns\n * the per-box refs, paste distribution and backspace traversal, which only make\n * sense with the whole array in scope.\n */\nimport { forwardRef, useEffect, useId, useRef, useState } from \"react\";\nimport type { ChangeEvent, ClipboardEvent, KeyboardEvent } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./PinInput.module.css\";\n\nexport type PinInputType = \"numeric\" | \"alphanumeric\";\nexport type PinInputSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface PinInputProps {\n /** Number of cells. Default `6`. */\n length?: number;\n /** Allowed character set. `numeric` (default) rejects letters, `alphanumeric` allows both. */\n type?: PinInputType;\n /** Visual size. Default `\"md\"`. */\n size?: PinInputSize;\n /** Controlled value. */\n value?: string;\n /** Initial value (uncontrolled mode). */\n defaultValue?: string;\n /** Fires on every change with the current concatenated value. */\n onChange?: (value: string) => void;\n /** Fires when the user fills the last cell. */\n onComplete?: (value: string) => void;\n /** Show characters obscured (`*`). Default `false`. */\n masked?: boolean;\n /** Label rendered above the cells. */\n label?: string;\n /** Helper text below the cells. */\n helperText?: string;\n /** Error message — turns cells red and replaces helperText. */\n error?: string;\n /** Disable all cells. */\n disabled?: boolean;\n /** Auto-focus the first cell on mount. Default `false`. */\n autoFocus?: boolean;\n /** id for the wrapping group label association. */\n id?: string;\n className?: string;\n}\n\nconst NUMERIC = /[0-9]/;\nconst ALNUM = /[A-Za-z0-9]/;\n\n/**\n * One-time-password style input — N independent cells, paste support, auto-\n * advance on input, backspace flows back, arrow keys navigate.\n *\n * @example\n * <PinInput length={6} type=\"numeric\" onComplete={(otp) => verify(otp)} />\n */\nexport const PinInput = forwardRef<HTMLDivElement, PinInputProps>(function PinInput(\n {\n length = 6,\n type = \"numeric\",\n size = \"md\",\n value,\n defaultValue,\n onChange,\n onComplete,\n masked = false,\n label,\n helperText,\n error,\n disabled = false,\n autoFocus = false,\n id,\n className,\n },\n ref,\n) {\n const internalId = useId();\n const wrapperId = id ?? internalId;\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState<string>(defaultValue ?? \"\");\n const current = isControlled ? (value ?? \"\") : internal;\n const cells = Array.from({ length }, (_, index) => current[index] ?? \"\");\n const inputsRef = useRef<(HTMLInputElement | null)[]>([]);\n const pattern = type === \"numeric\" ? NUMERIC : ALNUM;\n\n useEffect(() => {\n if (autoFocus) inputsRef.current[0]?.focus();\n }, [autoFocus]);\n\n const update = (next: string): void => {\n const trimmed = next.slice(0, length);\n if (!isControlled) setInternal(trimmed);\n onChange?.(trimmed);\n if (trimmed.length === length) onComplete?.(trimmed);\n };\n\n const focusCell = (index: number): void => {\n const safe = Math.max(0, Math.min(length - 1, index));\n inputsRef.current[safe]?.focus();\n inputsRef.current[safe]?.select();\n };\n\n const onCellChange = (index: number) => (event: ChangeEvent<HTMLInputElement>) => {\n const char = event.target.value.slice(-1);\n if (char && !pattern.test(char)) return;\n const next = cells.slice();\n next[index] = char;\n update(next.join(\"\"));\n if (char) focusCell(index + 1);\n };\n\n const onCellKeyDown = (index: number) => (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === \"Backspace\") {\n if (!cells[index] && index > 0) {\n event.preventDefault();\n const next = cells.slice();\n next[index - 1] = \"\";\n update(next.join(\"\"));\n focusCell(index - 1);\n }\n } else if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n focusCell(index - 1);\n } else if (event.key === \"ArrowRight\") {\n event.preventDefault();\n focusCell(index + 1);\n }\n };\n\n const onPaste = (event: ClipboardEvent<HTMLInputElement>): void => {\n const text = event.clipboardData\n .getData(\"text\")\n .split(\"\")\n .filter((c) => pattern.test(c))\n .join(\"\");\n if (!text) return;\n event.preventDefault();\n update(text);\n focusCell(Math.min(length - 1, text.length));\n };\n\n return (\n <div\n ref={ref}\n className={cn(styles.wrapper, error && styles.error, className)}\n id={wrapperId}\n >\n {label && <label className={styles.label}>{label}</label>}\n <div className={cn(styles.cells, styles[size])} role=\"group\" aria-label={label}>\n {cells.map((cell, index) => (\n <input\n key={index}\n ref={(node) => {\n inputsRef.current[index] = node;\n }}\n type={masked ? \"password\" : \"text\"}\n inputMode={type === \"numeric\" ? \"numeric\" : \"text\"}\n autoComplete={index === 0 ? \"one-time-code\" : \"off\"}\n maxLength={1}\n value={cell}\n disabled={disabled}\n className={styles.cell}\n aria-label={`Dígito ${index + 1}`}\n aria-invalid={!!error}\n onChange={onCellChange(index)}\n onKeyDown={onCellKeyDown(index)}\n onPaste={onPaste}\n />\n ))}\n </div>\n {error ? (\n <span className={styles.errorText}>{error}</span>\n ) : helperText ? (\n <span className={styles.helper}>{helperText}</span>\n ) : null}\n </div>\n );\n});\n"],"mappings":"+HA+CA,IAAM,EAAU,QACV,EAAQ,cASD,GAAA,
|
|
1
|
+
{"version":3,"file":"PinInput.cjs","names":[],"sources":["../../../src/components/PinInput/PinInput.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count, function-lines — one input per digit, so length,\n * type, masked and autoFocus shape the boxes while\n * value/defaultValue/onChange/onComplete drive them as a single value. The body owns\n * the per-box refs, paste distribution and backspace traversal, which only make\n * sense with the whole array in scope.\n */\nimport { forwardRef, useEffect, useId, useRef, useState } from \"react\";\nimport type { ChangeEvent, ClipboardEvent, KeyboardEvent } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./PinInput.module.css\";\n\nexport type PinInputType = \"numeric\" | \"alphanumeric\";\nexport type PinInputSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface PinInputProps {\n /** Number of cells. Default `6`. */\n length?: number;\n /** Allowed character set. `numeric` (default) rejects letters, `alphanumeric` allows both. */\n type?: PinInputType;\n /** Visual size. Default `\"md\"`. */\n size?: PinInputSize;\n /** Controlled value. */\n value?: string;\n /** Initial value (uncontrolled mode). */\n defaultValue?: string;\n /** Fires on every change with the current concatenated value. */\n onChange?: (value: string) => void;\n /** Fires when the user fills the last cell. */\n onComplete?: (value: string) => void;\n /** Show characters obscured (`*`). Default `false`. */\n masked?: boolean;\n /** Label rendered above the cells. */\n label?: string;\n /** Helper text below the cells. */\n helperText?: string;\n /** Error message — turns cells red and replaces helperText. */\n error?: string;\n /** Disable all cells. */\n disabled?: boolean;\n /** Auto-focus the first cell on mount. Default `false`. */\n autoFocus?: boolean;\n /** id for the wrapping group label association. */\n id?: string;\n className?: string;\n}\n\nconst NUMERIC = /[0-9]/;\nconst ALNUM = /[A-Za-z0-9]/;\n\n/**\n * One-time-password style input — N independent cells, paste support, auto-\n * advance on input, backspace flows back, arrow keys navigate.\n *\n * @example\n * <PinInput length={6} type=\"numeric\" onComplete={(otp) => verify(otp)} />\n */\nexport const PinInput = forwardRef<HTMLDivElement, PinInputProps>(function PinInput(\n {\n length = 6,\n type = \"numeric\",\n size = \"md\",\n value,\n defaultValue,\n onChange,\n onComplete,\n masked = false,\n label,\n helperText,\n error,\n disabled = false,\n autoFocus = false,\n id,\n className,\n },\n ref,\n) {\n const internalId = useId();\n const wrapperId = id ?? internalId;\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState<string>(defaultValue ?? \"\");\n const current = isControlled ? (value ?? \"\") : internal;\n const cells = Array.from({ length }, (_, index) => current[index] ?? \"\");\n const inputsRef = useRef<(HTMLInputElement | null)[]>([]);\n const pattern = type === \"numeric\" ? NUMERIC : ALNUM;\n\n useEffect(() => {\n if (autoFocus) inputsRef.current[0]?.focus();\n }, [autoFocus]);\n\n const update = (next: string): void => {\n const trimmed = next.slice(0, length);\n if (!isControlled) setInternal(trimmed);\n onChange?.(trimmed);\n if (trimmed.length === length) onComplete?.(trimmed);\n };\n\n const focusCell = (index: number): void => {\n const safe = Math.max(0, Math.min(length - 1, index));\n inputsRef.current[safe]?.focus();\n inputsRef.current[safe]?.select();\n };\n\n const onCellChange = (index: number) => (event: ChangeEvent<HTMLInputElement>) => {\n const char = event.target.value.slice(-1);\n if (char && !pattern.test(char)) return;\n const next = cells.slice();\n next[index] = char;\n update(next.join(\"\"));\n if (char) focusCell(index + 1);\n };\n\n const onCellKeyDown = (index: number) => (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === \"Backspace\") {\n if (!cells[index] && index > 0) {\n event.preventDefault();\n const next = cells.slice();\n next[index - 1] = \"\";\n update(next.join(\"\"));\n focusCell(index - 1);\n }\n } else if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n focusCell(index - 1);\n } else if (event.key === \"ArrowRight\") {\n event.preventDefault();\n focusCell(index + 1);\n }\n };\n\n const onPaste = (event: ClipboardEvent<HTMLInputElement>): void => {\n const text = event.clipboardData\n .getData(\"text\")\n .split(\"\")\n .filter((c) => pattern.test(c))\n .join(\"\");\n if (!text) return;\n event.preventDefault();\n update(text);\n focusCell(Math.min(length - 1, text.length));\n };\n\n return (\n <div\n ref={ref}\n className={cn(styles.wrapper, error && styles.error, className)}\n id={wrapperId}\n >\n {label && <label className={styles.label}>{label}</label>}\n <div className={cn(styles.cells, styles[size])} role=\"group\" aria-label={label}>\n {cells.map((cell, index) => (\n <input\n key={index}\n ref={(node) => {\n inputsRef.current[index] = node;\n }}\n type={masked ? \"password\" : \"text\"}\n inputMode={type === \"numeric\" ? \"numeric\" : \"text\"}\n autoComplete={index === 0 ? \"one-time-code\" : \"off\"}\n maxLength={1}\n value={cell}\n disabled={disabled}\n className={styles.cell}\n aria-label={`Dígito ${index + 1}`}\n aria-invalid={!!error}\n onChange={onCellChange(index)}\n onKeyDown={onCellKeyDown(index)}\n onPaste={onPaste}\n />\n ))}\n </div>\n {error ? (\n <span className={styles.errorText}>{error}</span>\n ) : helperText ? (\n <span className={styles.helper}>{helperText}</span>\n ) : null}\n </div>\n );\n});\n"],"mappings":"+HA+CA,IAAM,EAAU,QACV,EAAQ,cASD,GAAA,EAAW,EAAA,WAAA,CAA0C,SAC9D,CACI,SAAS,EACT,OAAO,UACP,OAAO,KACP,QACA,eACA,WACA,aACA,SAAS,GACT,QACA,aACA,QACA,WAAW,GACX,YAAY,GACZ,KACA,aAEJ,EACF,CACE,IAAM,GAAA,EAAa,EAAA,MAAA,CAAM,EACnB,EAAY,GAAM,EAClB,EAAe,IAAU,IAAA,GACzB,CAAC,EAAU,IAAA,EAAe,EAAA,SAAA,CAAiB,GAAgB,EAAE,EAC7D,EAAU,EAAgB,GAAS,GAAM,EACzC,EAAQ,MAAM,KAAK,CAAE,QAAO,GAAI,EAAG,IAAU,EAAQ,IAAU,EAAE,EACjE,GAAA,EAAY,EAAA,OAAA,CAAoC,CAAC,CAAC,EAClD,EAAU,IAAS,UAAY,EAAU,GAE/C,EAAA,EAAA,UAAA,KAAgB,CACR,GAAW,EAAU,QAAQ,EAAE,EAAE,MAAM,CAC/C,EAAG,CAAC,CAAS,CAAC,EAEd,IAAM,EAAU,GAAuB,CACnC,IAAM,EAAU,EAAK,MAAM,EAAG,CAAM,EAC/B,GAAc,EAAY,CAAO,EACtC,IAAW,CAAO,EACd,EAAQ,SAAW,GAAQ,IAAa,CAAO,CACvD,EAEM,EAAa,GAAwB,CACvC,IAAM,EAAO,KAAK,IAAI,EAAG,KAAK,IAAI,EAAS,EAAG,CAAK,CAAC,EACpD,EAAU,QAAQ,EAAK,EAAE,MAAM,EAC/B,EAAU,QAAQ,EAAK,EAAE,OAAO,CACpC,EAEM,EAAgB,GAAmB,GAAyC,CAC9E,IAAM,EAAO,EAAM,OAAO,MAAM,MAAM,EAAE,EACxC,GAAI,GAAQ,CAAC,EAAQ,KAAK,CAAI,EAAG,OACjC,IAAM,EAAO,EAAM,MAAM,EACzB,EAAK,GAAS,EACd,EAAO,EAAK,KAAK,EAAE,CAAC,EAChB,GAAM,EAAU,EAAQ,CAAC,CACjC,EAEM,EAAiB,GAAmB,GAA2C,CACjF,GAAI,EAAM,MAAQ,YACV,IAAA,CAAC,EAAM,IAAU,EAAQ,EAAG,CAC5B,EAAM,eAAe,EACrB,IAAM,EAAO,EAAM,MAAM,EACzB,EAAK,EAAQ,GAAK,GAClB,EAAO,EAAK,KAAK,EAAE,CAAC,EACpB,EAAU,EAAQ,CAAC,CACvB,OACO,EAAM,MAAQ,aACrB,EAAM,eAAe,EACrB,EAAU,EAAQ,CAAC,GACZ,EAAM,MAAQ,eACrB,EAAM,eAAe,EACrB,EAAU,EAAQ,CAAC,EAE3B,EAEM,EAAW,GAAkD,CAC/D,IAAM,EAAO,EAAM,cACd,QAAQ,MAAM,CAAC,CACf,MAAM,EAAE,CAAC,CACT,OAAQ,GAAM,EAAQ,KAAK,CAAC,CAAC,CAAC,CAC9B,KAAK,EAAE,EACP,IACL,EAAM,eAAe,EACrB,EAAO,CAAI,EACX,EAAU,KAAK,IAAI,EAAS,EAAG,EAAK,MAAM,CAAC,EAC/C,EAEA,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CACS,MACL,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,GAAS,EAAA,QAAO,MAAO,CAAS,EAC9D,GAAI,EAHR,SAAA,CAKK,IAAS,EAAA,EAAA,IAAA,CAAC,QAAD,CAAO,UAAW,EAAA,QAAO,MAAQ,SAAA,CAAa,CAAA,GACxD,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,EAAA,QAAO,EAAK,EAAG,KAAK,QAAQ,aAAY,EACpE,SAAA,EAAM,KAAK,EAAM,KACd,EAAA,EAAA,IAAA,CAAC,QAAD,CAEI,IAAM,GAAS,CACX,EAAU,QAAQ,GAAS,CAC/B,EACA,KAAM,EAAS,WAAa,OAC5B,UAAW,IAAS,UAAY,UAAY,OAC5C,aAAc,IAAU,EAAI,gBAAkB,MAC9C,UAAW,EACX,MAAO,EACG,WACV,UAAW,EAAA,QAAO,KAClB,aAAY,UAAU,EAAQ,IAC9B,eAAc,CAAC,CAAC,EAChB,SAAU,EAAa,CAAK,EAC5B,UAAW,EAAc,CAAK,EACrB,SACZ,EAhBQ,CAgBR,CACJ,CACA,CAAA,EACJ,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":"PinInput.js","names":[],"sources":["../../../src/components/PinInput/PinInput.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count, function-lines — one input per digit, so length,\n * type, masked and autoFocus shape the boxes while\n * value/defaultValue/onChange/onComplete drive them as a single value. The body owns\n * the per-box refs, paste distribution and backspace traversal, which only make\n * sense with the whole array in scope.\n */\nimport { forwardRef, useEffect, useId, useRef, useState } from \"react\";\nimport type { ChangeEvent, ClipboardEvent, KeyboardEvent } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./PinInput.module.css\";\n\nexport type PinInputType = \"numeric\" | \"alphanumeric\";\nexport type PinInputSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface PinInputProps {\n /** Number of cells. Default `6`. */\n length?: number;\n /** Allowed character set. `numeric` (default) rejects letters, `alphanumeric` allows both. */\n type?: PinInputType;\n /** Visual size. Default `\"md\"`. */\n size?: PinInputSize;\n /** Controlled value. */\n value?: string;\n /** Initial value (uncontrolled mode). */\n defaultValue?: string;\n /** Fires on every change with the current concatenated value. */\n onChange?: (value: string) => void;\n /** Fires when the user fills the last cell. */\n onComplete?: (value: string) => void;\n /** Show characters obscured (`*`). Default `false`. */\n masked?: boolean;\n /** Label rendered above the cells. */\n label?: string;\n /** Helper text below the cells. */\n helperText?: string;\n /** Error message — turns cells red and replaces helperText. */\n error?: string;\n /** Disable all cells. */\n disabled?: boolean;\n /** Auto-focus the first cell on mount. Default `false`. */\n autoFocus?: boolean;\n /** id for the wrapping group label association. */\n id?: string;\n className?: string;\n}\n\nconst NUMERIC = /[0-9]/;\nconst ALNUM = /[A-Za-z0-9]/;\n\n/**\n * One-time-password style input — N independent cells, paste support, auto-\n * advance on input, backspace flows back, arrow keys navigate.\n *\n * @example\n * <PinInput length={6} type=\"numeric\" onComplete={(otp) => verify(otp)} />\n */\nexport const PinInput = forwardRef<HTMLDivElement, PinInputProps>(function PinInput(\n {\n length = 6,\n type = \"numeric\",\n size = \"md\",\n value,\n defaultValue,\n onChange,\n onComplete,\n masked = false,\n label,\n helperText,\n error,\n disabled = false,\n autoFocus = false,\n id,\n className,\n },\n ref,\n) {\n const internalId = useId();\n const wrapperId = id ?? internalId;\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState<string>(defaultValue ?? \"\");\n const current = isControlled ? (value ?? \"\") : internal;\n const cells = Array.from({ length }, (_, index) => current[index] ?? \"\");\n const inputsRef = useRef<(HTMLInputElement | null)[]>([]);\n const pattern = type === \"numeric\" ? NUMERIC : ALNUM;\n\n useEffect(() => {\n if (autoFocus) inputsRef.current[0]?.focus();\n }, [autoFocus]);\n\n const update = (next: string): void => {\n const trimmed = next.slice(0, length);\n if (!isControlled) setInternal(trimmed);\n onChange?.(trimmed);\n if (trimmed.length === length) onComplete?.(trimmed);\n };\n\n const focusCell = (index: number): void => {\n const safe = Math.max(0, Math.min(length - 1, index));\n inputsRef.current[safe]?.focus();\n inputsRef.current[safe]?.select();\n };\n\n const onCellChange = (index: number) => (event: ChangeEvent<HTMLInputElement>) => {\n const char = event.target.value.slice(-1);\n if (char && !pattern.test(char)) return;\n const next = cells.slice();\n next[index] = char;\n update(next.join(\"\"));\n if (char) focusCell(index + 1);\n };\n\n const onCellKeyDown = (index: number) => (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === \"Backspace\") {\n if (!cells[index] && index > 0) {\n event.preventDefault();\n const next = cells.slice();\n next[index - 1] = \"\";\n update(next.join(\"\"));\n focusCell(index - 1);\n }\n } else if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n focusCell(index - 1);\n } else if (event.key === \"ArrowRight\") {\n event.preventDefault();\n focusCell(index + 1);\n }\n };\n\n const onPaste = (event: ClipboardEvent<HTMLInputElement>): void => {\n const text = event.clipboardData\n .getData(\"text\")\n .split(\"\")\n .filter((c) => pattern.test(c))\n .join(\"\");\n if (!text) return;\n event.preventDefault();\n update(text);\n focusCell(Math.min(length - 1, text.length));\n };\n\n return (\n <div\n ref={ref}\n className={cn(styles.wrapper, error && styles.error, className)}\n id={wrapperId}\n >\n {label && <label className={styles.label}>{label}</label>}\n <div className={cn(styles.cells, styles[size])} role=\"group\" aria-label={label}>\n {cells.map((cell, index) => (\n <input\n key={index}\n ref={(node) => {\n inputsRef.current[index] = node;\n }}\n type={masked ? \"password\" : \"text\"}\n inputMode={type === \"numeric\" ? \"numeric\" : \"text\"}\n autoComplete={index === 0 ? \"one-time-code\" : \"off\"}\n maxLength={1}\n value={cell}\n disabled={disabled}\n className={styles.cell}\n aria-label={`Dígito ${index + 1}`}\n aria-invalid={!!error}\n onChange={onCellChange(index)}\n onKeyDown={onCellKeyDown(index)}\n onPaste={onPaste}\n />\n ))}\n </div>\n {error ? (\n <span className={styles.errorText}>{error}</span>\n ) : helperText ? (\n <span className={styles.helper}>{helperText}</span>\n ) : null}\n </div>\n );\n});\n"],"mappings":";;;;;AA+CA,IAAM,IAAU,SACV,IAAQ,eASD,IAAW,EAA0C,SAC9D,EACI,YAAS,GACT,UAAO,WACP,UAAO,MACP,UACA,iBACA,aACA,eACA,YAAS,IACT,UACA,eACA,UACA,cAAW,IACX,eAAY,IACZ,OACA,gBAEJ,GACF;CACE,IAAM,IAAa,EAAM,GACnB,IAAY,KAAM,GAClB,IAAe,MAAU,KAAA,GACzB,CAAC,GAAU,KAAe,EAAiB,KAAgB,EAAE,GAC7D,IAAU,IAAgB,KAAS,KAAM,GACzC,IAAQ,MAAM,KAAK,EAAE,UAAO,IAAI,GAAG,MAAU,EAAQ,MAAU,EAAE,GACjE,IAAY,EAAoC,CAAC,CAAC,GAClD,IAAU,MAAS,YAAY,IAAU;CAE/C,QAAgB;EACZ,AAAI,KAAW,EAAU,QAAQ,EAAE,EAAE,MAAM;CAC/C,GAAG,CAAC,CAAS,CAAC;CAEd,IAAM,KAAU,MAAuB;EACnC,IAAM,IAAU,EAAK,MAAM,GAAG,CAAM;EAGpC,AAFK,KAAc,EAAY,CAAO,GACtC,IAAW,CAAO,GACd,EAAQ,WAAW,KAAQ,IAAa,CAAO;CACvD,GAEM,KAAa,MAAwB;EACvC,IAAM,IAAO,KAAK,IAAI,GAAG,KAAK,IAAI,IAAS,GAAG,CAAK,CAAC;EAEpD,AADA,EAAU,QAAQ,EAAK,EAAE,MAAM,GAC/B,EAAU,QAAQ,EAAK,EAAE,OAAO;CACpC,GAEM,KAAgB,OAAmB,MAAyC;EAC9E,IAAM,IAAO,EAAM,OAAO,MAAM,MAAM,EAAE;EACxC,IAAI,KAAQ,CAAC,EAAQ,KAAK,CAAI,GAAG;EACjC,IAAM,IAAO,EAAM,MAAM;EAGzB,AAFA,EAAK,KAAS,GACd,EAAO,EAAK,KAAK,EAAE,CAAC,GAChB,KAAM,EAAU,IAAQ,CAAC;CACjC,GAEM,KAAiB,OAAmB,MAA2C;EACjF,IAAI,EAAM,QAAQ;
|
|
1
|
+
{"version":3,"file":"PinInput.js","names":[],"sources":["../../../src/components/PinInput/PinInput.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count, function-lines — one input per digit, so length,\n * type, masked and autoFocus shape the boxes while\n * value/defaultValue/onChange/onComplete drive them as a single value. The body owns\n * the per-box refs, paste distribution and backspace traversal, which only make\n * sense with the whole array in scope.\n */\nimport { forwardRef, useEffect, useId, useRef, useState } from \"react\";\nimport type { ChangeEvent, ClipboardEvent, KeyboardEvent } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./PinInput.module.css\";\n\nexport type PinInputType = \"numeric\" | \"alphanumeric\";\nexport type PinInputSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface PinInputProps {\n /** Number of cells. Default `6`. */\n length?: number;\n /** Allowed character set. `numeric` (default) rejects letters, `alphanumeric` allows both. */\n type?: PinInputType;\n /** Visual size. Default `\"md\"`. */\n size?: PinInputSize;\n /** Controlled value. */\n value?: string;\n /** Initial value (uncontrolled mode). */\n defaultValue?: string;\n /** Fires on every change with the current concatenated value. */\n onChange?: (value: string) => void;\n /** Fires when the user fills the last cell. */\n onComplete?: (value: string) => void;\n /** Show characters obscured (`*`). Default `false`. */\n masked?: boolean;\n /** Label rendered above the cells. */\n label?: string;\n /** Helper text below the cells. */\n helperText?: string;\n /** Error message — turns cells red and replaces helperText. */\n error?: string;\n /** Disable all cells. */\n disabled?: boolean;\n /** Auto-focus the first cell on mount. Default `false`. */\n autoFocus?: boolean;\n /** id for the wrapping group label association. */\n id?: string;\n className?: string;\n}\n\nconst NUMERIC = /[0-9]/;\nconst ALNUM = /[A-Za-z0-9]/;\n\n/**\n * One-time-password style input — N independent cells, paste support, auto-\n * advance on input, backspace flows back, arrow keys navigate.\n *\n * @example\n * <PinInput length={6} type=\"numeric\" onComplete={(otp) => verify(otp)} />\n */\nexport const PinInput = forwardRef<HTMLDivElement, PinInputProps>(function PinInput(\n {\n length = 6,\n type = \"numeric\",\n size = \"md\",\n value,\n defaultValue,\n onChange,\n onComplete,\n masked = false,\n label,\n helperText,\n error,\n disabled = false,\n autoFocus = false,\n id,\n className,\n },\n ref,\n) {\n const internalId = useId();\n const wrapperId = id ?? internalId;\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState<string>(defaultValue ?? \"\");\n const current = isControlled ? (value ?? \"\") : internal;\n const cells = Array.from({ length }, (_, index) => current[index] ?? \"\");\n const inputsRef = useRef<(HTMLInputElement | null)[]>([]);\n const pattern = type === \"numeric\" ? NUMERIC : ALNUM;\n\n useEffect(() => {\n if (autoFocus) inputsRef.current[0]?.focus();\n }, [autoFocus]);\n\n const update = (next: string): void => {\n const trimmed = next.slice(0, length);\n if (!isControlled) setInternal(trimmed);\n onChange?.(trimmed);\n if (trimmed.length === length) onComplete?.(trimmed);\n };\n\n const focusCell = (index: number): void => {\n const safe = Math.max(0, Math.min(length - 1, index));\n inputsRef.current[safe]?.focus();\n inputsRef.current[safe]?.select();\n };\n\n const onCellChange = (index: number) => (event: ChangeEvent<HTMLInputElement>) => {\n const char = event.target.value.slice(-1);\n if (char && !pattern.test(char)) return;\n const next = cells.slice();\n next[index] = char;\n update(next.join(\"\"));\n if (char) focusCell(index + 1);\n };\n\n const onCellKeyDown = (index: number) => (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === \"Backspace\") {\n if (!cells[index] && index > 0) {\n event.preventDefault();\n const next = cells.slice();\n next[index - 1] = \"\";\n update(next.join(\"\"));\n focusCell(index - 1);\n }\n } else if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n focusCell(index - 1);\n } else if (event.key === \"ArrowRight\") {\n event.preventDefault();\n focusCell(index + 1);\n }\n };\n\n const onPaste = (event: ClipboardEvent<HTMLInputElement>): void => {\n const text = event.clipboardData\n .getData(\"text\")\n .split(\"\")\n .filter((c) => pattern.test(c))\n .join(\"\");\n if (!text) return;\n event.preventDefault();\n update(text);\n focusCell(Math.min(length - 1, text.length));\n };\n\n return (\n <div\n ref={ref}\n className={cn(styles.wrapper, error && styles.error, className)}\n id={wrapperId}\n >\n {label && <label className={styles.label}>{label}</label>}\n <div className={cn(styles.cells, styles[size])} role=\"group\" aria-label={label}>\n {cells.map((cell, index) => (\n <input\n key={index}\n ref={(node) => {\n inputsRef.current[index] = node;\n }}\n type={masked ? \"password\" : \"text\"}\n inputMode={type === \"numeric\" ? \"numeric\" : \"text\"}\n autoComplete={index === 0 ? \"one-time-code\" : \"off\"}\n maxLength={1}\n value={cell}\n disabled={disabled}\n className={styles.cell}\n aria-label={`Dígito ${index + 1}`}\n aria-invalid={!!error}\n onChange={onCellChange(index)}\n onKeyDown={onCellKeyDown(index)}\n onPaste={onPaste}\n />\n ))}\n </div>\n {error ? (\n <span className={styles.errorText}>{error}</span>\n ) : helperText ? (\n <span className={styles.helper}>{helperText}</span>\n ) : null}\n </div>\n );\n});\n"],"mappings":";;;;;AA+CA,IAAM,IAAU,SACV,IAAQ,eASD,IAAW,EAA0C,SAC9D,EACI,YAAS,GACT,UAAO,WACP,UAAO,MACP,UACA,iBACA,aACA,eACA,YAAS,IACT,UACA,eACA,UACA,cAAW,IACX,eAAY,IACZ,OACA,gBAEJ,GACF;CACE,IAAM,IAAa,EAAM,GACnB,IAAY,KAAM,GAClB,IAAe,MAAU,KAAA,GACzB,CAAC,GAAU,KAAe,EAAiB,KAAgB,EAAE,GAC7D,IAAU,IAAgB,KAAS,KAAM,GACzC,IAAQ,MAAM,KAAK,EAAE,UAAO,IAAI,GAAG,MAAU,EAAQ,MAAU,EAAE,GACjE,IAAY,EAAoC,CAAC,CAAC,GAClD,IAAU,MAAS,YAAY,IAAU;CAE/C,QAAgB;EACZ,AAAI,KAAW,EAAU,QAAQ,EAAE,EAAE,MAAM;CAC/C,GAAG,CAAC,CAAS,CAAC;CAEd,IAAM,KAAU,MAAuB;EACnC,IAAM,IAAU,EAAK,MAAM,GAAG,CAAM;EAGpC,AAFK,KAAc,EAAY,CAAO,GACtC,IAAW,CAAO,GACd,EAAQ,WAAW,KAAQ,IAAa,CAAO;CACvD,GAEM,KAAa,MAAwB;EACvC,IAAM,IAAO,KAAK,IAAI,GAAG,KAAK,IAAI,IAAS,GAAG,CAAK,CAAC;EAEpD,AADA,EAAU,QAAQ,EAAK,EAAE,MAAM,GAC/B,EAAU,QAAQ,EAAK,EAAE,OAAO;CACpC,GAEM,KAAgB,OAAmB,MAAyC;EAC9E,IAAM,IAAO,EAAM,OAAO,MAAM,MAAM,EAAE;EACxC,IAAI,KAAQ,CAAC,EAAQ,KAAK,CAAI,GAAG;EACjC,IAAM,IAAO,EAAM,MAAM;EAGzB,AAFA,EAAK,KAAS,GACd,EAAO,EAAK,KAAK,EAAE,CAAC,GAChB,KAAM,EAAU,IAAQ,CAAC;CACjC,GAEM,KAAiB,OAAmB,MAA2C;EACjF,IAAI,EAAM,QAAQ,aACV;OAAA,CAAC,EAAM,MAAU,IAAQ,GAAG;IAC5B,EAAM,eAAe;IACrB,IAAM,IAAO,EAAM,MAAM;IAGzB,AAFA,EAAK,IAAQ,KAAK,IAClB,EAAO,EAAK,KAAK,EAAE,CAAC,GACpB,EAAU,IAAQ,CAAC;GACvB;SACG,AAAI,EAAM,QAAQ,eACrB,EAAM,eAAe,GACrB,EAAU,IAAQ,CAAC,KACZ,EAAM,QAAQ,iBACrB,EAAM,eAAe,GACrB,EAAU,IAAQ,CAAC;CAE3B,GAEM,KAAW,MAAkD;EAC/D,IAAM,IAAO,EAAM,cACd,QAAQ,MAAM,CAAC,CACf,MAAM,EAAE,CAAC,CACT,QAAQ,MAAM,EAAQ,KAAK,CAAC,CAAC,CAAC,CAC9B,KAAK,EAAE;EACP,MACL,EAAM,eAAe,GACrB,EAAO,CAAI,GACX,EAAU,KAAK,IAAI,IAAS,GAAG,EAAK,MAAM,CAAC;CAC/C;CAEA,OACI,kBAAC,OAAD;EACS;EACL,WAAW,EAAG,EAAO,SAAS,KAAS,EAAO,OAAO,CAAS;EAC9D,IAAI;EAHR,UAAA;GAKK,KAAS,kBAAC,SAAD;IAAO,WAAW,EAAO;IAAQ,UAAA;GAAa,CAAA;GACxD,kBAAC,OAAD;IAAK,WAAW,EAAG,EAAO,OAAO,EAAO,EAAK;IAAG,MAAK;IAAQ,cAAY;IACpE,UAAA,EAAM,KAAK,GAAM,MACd,kBAAC,SAAD;KAEI,MAAM,MAAS;MACX,EAAU,QAAQ,KAAS;KAC/B;KACA,MAAM,IAAS,aAAa;KAC5B,WAAW,MAAS,YAAY,YAAY;KAC5C,cAAc,MAAU,IAAI,kBAAkB;KAC9C,WAAW;KACX,OAAO;KACG;KACV,WAAW,EAAO;KAClB,cAAY,UAAU,IAAQ;KAC9B,gBAAc,CAAC,CAAC;KAChB,UAAU,EAAa,CAAK;KAC5B,WAAW,EAAc,CAAK;KACrB;IACZ,GAhBQ,CAgBR,CACJ;GACA,CAAA;GACJ,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":"Popover.cjs","names":[],"sources":["../../../src/components/Popover/Popover.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — trigger and children are the two halves, placement\n * is where it lands, and open/onOpenChange/defaultOpen is the standard controlled-\n * or-not pair. closeOnEsc and closeOnOutsideClick are separate because a popover\n * holding a form wants one and not the other.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Popover.module.css\";\n\nexport type PopoverPlacement = \"top\" | \"bottom\" | \"left\" | \"right\";\n\nexport interface PopoverProps {\n /** Trigger element. Receives `onClick`/`aria-expanded`/`aria-controls`. */\n trigger: ReactElement<{\n onClick?: (e: React.MouseEvent) => void;\n \"aria-expanded\"?: boolean;\n \"aria-controls\"?: string;\n }>;\n children: ReactNode;\n placement?: PopoverPlacement;\n /** Controlled open state. */\n open?: boolean;\n /** Called when the user toggles or dismisses. */\n onOpenChange?: (open: boolean) => void;\n /** Default open state for uncontrolled usage. */\n defaultOpen?: boolean;\n /** Close on Escape. Default true. */\n closeOnEsc?: boolean;\n /** Close on outside click. Default true. */\n closeOnOutsideClick?: boolean;\n className?: string;\n}\n\n/**\n * Lightweight popover. Renders a positioned panel anchored to a trigger,\n * dismissed on outside click / Escape. Does NOT include collision detection\n * or smart positioning — pair with Floating UI if you need that.\n */\nexport function Popover({\n trigger,\n children,\n placement = \"bottom\",\n open,\n onOpenChange,\n defaultOpen = false,\n closeOnEsc = true,\n closeOnOutsideClick = true,\n className,\n}: PopoverProps) {\n const isControlled = open !== undefined;\n const [internalOpen, setInternalOpen] = useState<boolean>(defaultOpen);\n const isOpen = isControlled ? open : internalOpen;\n const id = useId();\n const rootRef = useRef<HTMLSpanElement>(null);\n\n const setOpen = useCallback(\n (next: boolean): void => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n useEffect(() => {\n if (!isOpen) return;\n const onKey = (event: KeyboardEvent): void => {\n if (closeOnEsc && event.key === \"Escape\") setOpen(false);\n };\n const onDown = (event: MouseEvent): void => {\n if (!closeOnOutsideClick) return;\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n setOpen(false);\n }\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onDown);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onDown);\n };\n }, [isOpen, closeOnEsc, closeOnOutsideClick, setOpen]);\n\n const handleTriggerClick = (event: React.MouseEvent): void => {\n trigger.props.onClick?.(event);\n setOpen(!isOpen);\n };\n\n const triggerClone = {\n ...trigger,\n props: {\n ...trigger.props,\n onClick: handleTriggerClick,\n \"aria-expanded\": isOpen,\n \"aria-controls\": id,\n },\n } as ReactElement;\n\n return (\n <span ref={rootRef} className={styles.root}>\n {triggerClone}\n {isOpen && (\n <div\n id={id}\n role=\"dialog\"\n className={cn(styles.popover, styles[placement], className)}\n >\n {children}\n </div>\n )}\n </span>\n );\n}\n"],"mappings":"8HAwCA,SAAgB,EAAQ,CACpB,UACA,WACA,YAAY,SACZ,OACA,eACA,cAAc,GACd,aAAa,GACb,sBAAsB,GACtB,aACa,CACb,IAAM,EAAe,IAAS,IAAA,GACxB,CAAC,EAAc,IAAA,
|
|
1
|
+
{"version":3,"file":"Popover.cjs","names":[],"sources":["../../../src/components/Popover/Popover.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — trigger and children are the two halves, placement\n * is where it lands, and open/onOpenChange/defaultOpen is the standard controlled-\n * or-not pair. closeOnEsc and closeOnOutsideClick are separate because a popover\n * holding a form wants one and not the other.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Popover.module.css\";\n\nexport type PopoverPlacement = \"top\" | \"bottom\" | \"left\" | \"right\";\n\nexport interface PopoverProps {\n /** Trigger element. Receives `onClick`/`aria-expanded`/`aria-controls`. */\n trigger: ReactElement<{\n onClick?: (e: React.MouseEvent) => void;\n \"aria-expanded\"?: boolean;\n \"aria-controls\"?: string;\n }>;\n children: ReactNode;\n placement?: PopoverPlacement;\n /** Controlled open state. */\n open?: boolean;\n /** Called when the user toggles or dismisses. */\n onOpenChange?: (open: boolean) => void;\n /** Default open state for uncontrolled usage. */\n defaultOpen?: boolean;\n /** Close on Escape. Default true. */\n closeOnEsc?: boolean;\n /** Close on outside click. Default true. */\n closeOnOutsideClick?: boolean;\n className?: string;\n}\n\n/**\n * Lightweight popover. Renders a positioned panel anchored to a trigger,\n * dismissed on outside click / Escape. Does NOT include collision detection\n * or smart positioning — pair with Floating UI if you need that.\n */\nexport function Popover({\n trigger,\n children,\n placement = \"bottom\",\n open,\n onOpenChange,\n defaultOpen = false,\n closeOnEsc = true,\n closeOnOutsideClick = true,\n className,\n}: PopoverProps) {\n const isControlled = open !== undefined;\n const [internalOpen, setInternalOpen] = useState<boolean>(defaultOpen);\n const isOpen = isControlled ? open : internalOpen;\n const id = useId();\n const rootRef = useRef<HTMLSpanElement>(null);\n\n const setOpen = useCallback(\n (next: boolean): void => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n useEffect(() => {\n if (!isOpen) return;\n const onKey = (event: KeyboardEvent): void => {\n if (closeOnEsc && event.key === \"Escape\") setOpen(false);\n };\n const onDown = (event: MouseEvent): void => {\n if (!closeOnOutsideClick) return;\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n setOpen(false);\n }\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onDown);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onDown);\n };\n }, [isOpen, closeOnEsc, closeOnOutsideClick, setOpen]);\n\n const handleTriggerClick = (event: React.MouseEvent): void => {\n trigger.props.onClick?.(event);\n setOpen(!isOpen);\n };\n\n const triggerClone = {\n ...trigger,\n props: {\n ...trigger.props,\n onClick: handleTriggerClick,\n \"aria-expanded\": isOpen,\n \"aria-controls\": id,\n },\n } as ReactElement;\n\n return (\n <span ref={rootRef} className={styles.root}>\n {triggerClone}\n {isOpen && (\n <div\n id={id}\n role=\"dialog\"\n className={cn(styles.popover, styles[placement], className)}\n >\n {children}\n </div>\n )}\n </span>\n );\n}\n"],"mappings":"8HAwCA,SAAgB,EAAQ,CACpB,UACA,WACA,YAAY,SACZ,OACA,eACA,cAAc,GACd,aAAa,GACb,sBAAsB,GACtB,aACa,CACb,IAAM,EAAe,IAAS,IAAA,GACxB,CAAC,EAAc,IAAA,EAAmB,EAAA,SAAA,CAAkB,CAAW,EAC/D,EAAS,EAAe,EAAO,EAC/B,GAAA,EAAK,EAAA,MAAA,CAAM,EACX,GAAA,EAAU,EAAA,OAAA,CAAwB,IAAI,EAEtC,GAAA,EAAU,EAAA,YAAA,CACX,GAAwB,CAChB,GAAc,EAAgB,CAAI,EACvC,IAAe,CAAI,CACvB,EACA,CAAC,EAAc,CAAY,CAC/B,GAEA,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,CAAC,EAAQ,OACb,IAAM,EAAS,GAA+B,CACtC,GAAc,EAAM,MAAQ,UAAU,EAAQ,EAAK,CAC3D,EACM,EAAU,GAA4B,CACnC,GACD,EAAQ,SAAW,CAAC,EAAQ,QAAQ,SAAS,EAAM,MAAc,GACjE,EAAQ,EAAK,CAErB,EAGA,OAFA,OAAO,iBAAiB,UAAW,CAAK,EACxC,OAAO,iBAAiB,YAAa,CAAM,MAC9B,CACT,OAAO,oBAAoB,UAAW,CAAK,EAC3C,OAAO,oBAAoB,YAAa,CAAM,CAClD,CACJ,EAAG,CAAC,EAAQ,EAAY,EAAqB,CAAO,CAAC,EAErD,IAAM,EAAsB,GAAkC,CAC1D,EAAQ,MAAM,UAAU,CAAK,EAC7B,EAAQ,CAAC,CAAM,CACnB,EAEM,EAAe,CACjB,GAAG,EACH,MAAO,CACH,GAAG,EAAQ,MACX,QAAS,EACT,gBAAiB,EACjB,gBAAiB,CACrB,CACJ,EAEA,OACI,EAAA,EAAA,KAAA,CAAC,OAAD,CAAM,IAAK,EAAS,UAAW,EAAA,QAAO,KAAtC,SAAA,CACK,EACA,IACG,EAAA,EAAA,IAAA,CAAC,MAAD,CACQ,KACJ,KAAK,SACL,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,EAAA,QAAO,GAAY,CAAS,EAEzD,UACA,CAAA,CAEP,GAEd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popover.js","names":[],"sources":["../../../src/components/Popover/Popover.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — trigger and children are the two halves, placement\n * is where it lands, and open/onOpenChange/defaultOpen is the standard controlled-\n * or-not pair. closeOnEsc and closeOnOutsideClick are separate because a popover\n * holding a form wants one and not the other.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Popover.module.css\";\n\nexport type PopoverPlacement = \"top\" | \"bottom\" | \"left\" | \"right\";\n\nexport interface PopoverProps {\n /** Trigger element. Receives `onClick`/`aria-expanded`/`aria-controls`. */\n trigger: ReactElement<{\n onClick?: (e: React.MouseEvent) => void;\n \"aria-expanded\"?: boolean;\n \"aria-controls\"?: string;\n }>;\n children: ReactNode;\n placement?: PopoverPlacement;\n /** Controlled open state. */\n open?: boolean;\n /** Called when the user toggles or dismisses. */\n onOpenChange?: (open: boolean) => void;\n /** Default open state for uncontrolled usage. */\n defaultOpen?: boolean;\n /** Close on Escape. Default true. */\n closeOnEsc?: boolean;\n /** Close on outside click. Default true. */\n closeOnOutsideClick?: boolean;\n className?: string;\n}\n\n/**\n * Lightweight popover. Renders a positioned panel anchored to a trigger,\n * dismissed on outside click / Escape. Does NOT include collision detection\n * or smart positioning — pair with Floating UI if you need that.\n */\nexport function Popover({\n trigger,\n children,\n placement = \"bottom\",\n open,\n onOpenChange,\n defaultOpen = false,\n closeOnEsc = true,\n closeOnOutsideClick = true,\n className,\n}: PopoverProps) {\n const isControlled = open !== undefined;\n const [internalOpen, setInternalOpen] = useState<boolean>(defaultOpen);\n const isOpen = isControlled ? open : internalOpen;\n const id = useId();\n const rootRef = useRef<HTMLSpanElement>(null);\n\n const setOpen = useCallback(\n (next: boolean): void => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n useEffect(() => {\n if (!isOpen) return;\n const onKey = (event: KeyboardEvent): void => {\n if (closeOnEsc && event.key === \"Escape\") setOpen(false);\n };\n const onDown = (event: MouseEvent): void => {\n if (!closeOnOutsideClick) return;\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n setOpen(false);\n }\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onDown);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onDown);\n };\n }, [isOpen, closeOnEsc, closeOnOutsideClick, setOpen]);\n\n const handleTriggerClick = (event: React.MouseEvent): void => {\n trigger.props.onClick?.(event);\n setOpen(!isOpen);\n };\n\n const triggerClone = {\n ...trigger,\n props: {\n ...trigger.props,\n onClick: handleTriggerClick,\n \"aria-expanded\": isOpen,\n \"aria-controls\": id,\n },\n } as ReactElement;\n\n return (\n <span ref={rootRef} className={styles.root}>\n {triggerClone}\n {isOpen && (\n <div\n id={id}\n role=\"dialog\"\n className={cn(styles.popover, styles[placement], className)}\n >\n {children}\n </div>\n )}\n </span>\n );\n}\n"],"mappings":";;;;;AAwCA,SAAgB,EAAQ,EACpB,YACA,aACA,eAAY,UACZ,SACA,iBACA,iBAAc,IACd,gBAAa,IACb,yBAAsB,IACtB,gBACa;CACb,IAAM,IAAe,MAAS,KAAA,GACxB,CAAC,GAAc,KAAmB,EAAkB,CAAW,GAC/D,IAAS,IAAe,IAAO,GAC/B,IAAK,EAAM,GACX,IAAU,EAAwB,IAAI,GAEtC,IAAU,GACX,MAAwB;EAErB,AADK,KAAc,EAAgB,CAAI,GACvC,IAAe,CAAI;CACvB,GACA,CAAC,GAAc,CAAY,CAC/B;CAEA,QAAgB;EACZ,IAAI,CAAC,GAAQ;EACb,IAAM,KAAS,MAA+B;GAC1C,AAAI,KAAc,EAAM,QAAQ,YAAU,EAAQ,EAAK;EAC3D,GACM,KAAU,MAA4B;GACnC,KACD,EAAQ,WAAW,CAAC,EAAQ,QAAQ,SAAS,EAAM,MAAc,KACjE,EAAQ,EAAK;EAErB;EAGA,OAFA,OAAO,iBAAiB,WAAW,CAAK,GACxC,OAAO,iBAAiB,aAAa,CAAM,SAC9B;GAET,AADA,OAAO,oBAAoB,WAAW,CAAK,GAC3C,OAAO,oBAAoB,aAAa,CAAM;EAClD;CACJ,GAAG;EAAC;EAAQ;EAAY;EAAqB;CAAO,CAAC;CAErD,IAAM,KAAsB,MAAkC;EAE1D,AADA,EAAQ,MAAM,UAAU,CAAK,GAC7B,EAAQ,CAAC,CAAM;CACnB,GAEM,IAAe;EACjB,GAAG;EACH,OAAO;GACH,GAAG,EAAQ;GACX,SAAS;GACT,iBAAiB;GACjB,iBAAiB;EACrB;CACJ;CAEA,OACI,kBAAC,QAAD;EAAM,KAAK;EAAS,WAAW,EAAO;
|
|
1
|
+
{"version":3,"file":"Popover.js","names":[],"sources":["../../../src/components/Popover/Popover.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — trigger and children are the two halves, placement\n * is where it lands, and open/onOpenChange/defaultOpen is the standard controlled-\n * or-not pair. closeOnEsc and closeOnOutsideClick are separate because a popover\n * holding a form wants one and not the other.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Popover.module.css\";\n\nexport type PopoverPlacement = \"top\" | \"bottom\" | \"left\" | \"right\";\n\nexport interface PopoverProps {\n /** Trigger element. Receives `onClick`/`aria-expanded`/`aria-controls`. */\n trigger: ReactElement<{\n onClick?: (e: React.MouseEvent) => void;\n \"aria-expanded\"?: boolean;\n \"aria-controls\"?: string;\n }>;\n children: ReactNode;\n placement?: PopoverPlacement;\n /** Controlled open state. */\n open?: boolean;\n /** Called when the user toggles or dismisses. */\n onOpenChange?: (open: boolean) => void;\n /** Default open state for uncontrolled usage. */\n defaultOpen?: boolean;\n /** Close on Escape. Default true. */\n closeOnEsc?: boolean;\n /** Close on outside click. Default true. */\n closeOnOutsideClick?: boolean;\n className?: string;\n}\n\n/**\n * Lightweight popover. Renders a positioned panel anchored to a trigger,\n * dismissed on outside click / Escape. Does NOT include collision detection\n * or smart positioning — pair with Floating UI if you need that.\n */\nexport function Popover({\n trigger,\n children,\n placement = \"bottom\",\n open,\n onOpenChange,\n defaultOpen = false,\n closeOnEsc = true,\n closeOnOutsideClick = true,\n className,\n}: PopoverProps) {\n const isControlled = open !== undefined;\n const [internalOpen, setInternalOpen] = useState<boolean>(defaultOpen);\n const isOpen = isControlled ? open : internalOpen;\n const id = useId();\n const rootRef = useRef<HTMLSpanElement>(null);\n\n const setOpen = useCallback(\n (next: boolean): void => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n useEffect(() => {\n if (!isOpen) return;\n const onKey = (event: KeyboardEvent): void => {\n if (closeOnEsc && event.key === \"Escape\") setOpen(false);\n };\n const onDown = (event: MouseEvent): void => {\n if (!closeOnOutsideClick) return;\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n setOpen(false);\n }\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onDown);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onDown);\n };\n }, [isOpen, closeOnEsc, closeOnOutsideClick, setOpen]);\n\n const handleTriggerClick = (event: React.MouseEvent): void => {\n trigger.props.onClick?.(event);\n setOpen(!isOpen);\n };\n\n const triggerClone = {\n ...trigger,\n props: {\n ...trigger.props,\n onClick: handleTriggerClick,\n \"aria-expanded\": isOpen,\n \"aria-controls\": id,\n },\n } as ReactElement;\n\n return (\n <span ref={rootRef} className={styles.root}>\n {triggerClone}\n {isOpen && (\n <div\n id={id}\n role=\"dialog\"\n className={cn(styles.popover, styles[placement], className)}\n >\n {children}\n </div>\n )}\n </span>\n );\n}\n"],"mappings":";;;;;AAwCA,SAAgB,EAAQ,EACpB,YACA,aACA,eAAY,UACZ,SACA,iBACA,iBAAc,IACd,gBAAa,IACb,yBAAsB,IACtB,gBACa;CACb,IAAM,IAAe,MAAS,KAAA,GACxB,CAAC,GAAc,KAAmB,EAAkB,CAAW,GAC/D,IAAS,IAAe,IAAO,GAC/B,IAAK,EAAM,GACX,IAAU,EAAwB,IAAI,GAEtC,IAAU,GACX,MAAwB;EAErB,AADK,KAAc,EAAgB,CAAI,GACvC,IAAe,CAAI;CACvB,GACA,CAAC,GAAc,CAAY,CAC/B;CAEA,QAAgB;EACZ,IAAI,CAAC,GAAQ;EACb,IAAM,KAAS,MAA+B;GAC1C,AAAI,KAAc,EAAM,QAAQ,YAAU,EAAQ,EAAK;EAC3D,GACM,KAAU,MAA4B;GACnC,KACD,EAAQ,WAAW,CAAC,EAAQ,QAAQ,SAAS,EAAM,MAAc,KACjE,EAAQ,EAAK;EAErB;EAGA,OAFA,OAAO,iBAAiB,WAAW,CAAK,GACxC,OAAO,iBAAiB,aAAa,CAAM,SAC9B;GAET,AADA,OAAO,oBAAoB,WAAW,CAAK,GAC3C,OAAO,oBAAoB,aAAa,CAAM;EAClD;CACJ,GAAG;EAAC;EAAQ;EAAY;EAAqB;CAAO,CAAC;CAErD,IAAM,KAAsB,MAAkC;EAE1D,AADA,EAAQ,MAAM,UAAU,CAAK,GAC7B,EAAQ,CAAC,CAAM;CACnB,GAEM,IAAe;EACjB,GAAG;EACH,OAAO;GACH,GAAG,EAAQ;GACX,SAAS;GACT,iBAAiB;GACjB,iBAAiB;EACrB;CACJ;CAEA,OACI,kBAAC,QAAD;EAAM,KAAK;EAAS,WAAW,EAAO;EAAtC,UAAA,CACK,GACA,KACG,kBAAC,OAAD;GACQ;GACJ,MAAK;GACL,WAAW,EAAG,EAAO,SAAS,EAAO,IAAY,CAAS;GAEzD;EACA,CAAA,CAEP;;AAEd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Portal.cjs","names":[],"sources":["../../../src/components/Portal/Portal.tsx"],"sourcesContent":["import { useEffect, useState, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nexport interface PortalProps {\n /** Content rendered through the portal. */\n children: ReactNode;\n /** Target DOM node to render into. Defaults to `document.body`. */\n container?: Element | null;\n}\n\n/**\n * Renders its children into a different part of the DOM tree via a React portal.\n *\n * Useful for overlays (modals, tooltips, dropdowns) that must escape parent\n * overflow/stacking contexts. Defaults to `document.body` when no `container`\n * is provided.\n *\n * SSR-safe: renders `null` on the server and on the first client render, then\n * mounts the portal after hydration (when `document` is available).\n *\n * @param props - The portal props.\n * @returns The portal node once mounted, otherwise `null`.\n */\nexport function Portal({ children, container }: PortalProps): ReactNode {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n return () => setMounted(false);\n }, []);\n\n if (!mounted || typeof document === \"undefined\") {\n return null;\n }\n\n return createPortal(children, container ?? document.body);\n}\n"],"mappings":"8CAuBA,SAAgB,EAAO,CAAE,WAAU,aAAqC,CACpE,GAAM,CAAC,EAAS,IAAA,
|
|
1
|
+
{"version":3,"file":"Portal.cjs","names":[],"sources":["../../../src/components/Portal/Portal.tsx"],"sourcesContent":["import { useEffect, useState, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nexport interface PortalProps {\n /** Content rendered through the portal. */\n children: ReactNode;\n /** Target DOM node to render into. Defaults to `document.body`. */\n container?: Element | null;\n}\n\n/**\n * Renders its children into a different part of the DOM tree via a React portal.\n *\n * Useful for overlays (modals, tooltips, dropdowns) that must escape parent\n * overflow/stacking contexts. Defaults to `document.body` when no `container`\n * is provided.\n *\n * SSR-safe: renders `null` on the server and on the first client render, then\n * mounts the portal after hydration (when `document` is available).\n *\n * @param props - The portal props.\n * @returns The portal node once mounted, otherwise `null`.\n */\nexport function Portal({ children, container }: PortalProps): ReactNode {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n return () => setMounted(false);\n }, []);\n\n if (!mounted || typeof document === \"undefined\") {\n return null;\n }\n\n return createPortal(children, container ?? document.body);\n}\n"],"mappings":"8CAuBA,SAAgB,EAAO,CAAE,WAAU,aAAqC,CACpE,GAAM,CAAC,EAAS,IAAA,EAAc,EAAA,SAAA,CAAS,EAAK,EAW5C,OATA,EAAA,EAAA,UAAA,MACI,EAAW,EAAI,MACF,EAAW,EAAK,GAC9B,CAAC,CAAC,EAED,CAAC,GAAW,OAAO,SAAa,IACzB,MAGX,EAAO,EAAA,aAAA,CAAa,EAAU,GAAa,SAAS,IAAI,CAC5D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Progress.cjs","names":[],"sources":["../../../src/components/Progress/Progress.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — value, max, indeterminate, size, tone, label,\n * showValue and className: a progress bar is one element with eight independent\n * presentation choices, and the destructuring counts them all because none has a\n * sensible sub-object.\n */\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Progress.module.css\";\n\nexport type ProgressVariant = \"primary\" | \"success\" | \"warning\" | \"danger\";\n\nexport interface ProgressProps {\n /** Value between 0 and `max` (or 0-100 by default). Ignored when `indeterminate`. */\n value?: number;\n max?: number;\n variant?: ProgressVariant;\n /** Show an animated indeterminate bar. Default: false. */\n indeterminate?: boolean;\n /** Render a numeric label \"x% / max\" above the bar. Default: false. */\n showLabel?: boolean;\n /** Optional left-aligned descriptor (e.g. \"Enviando arquivo…\"). */\n label?: string;\n /**\n * Accessible name for the bar. Defaults to `label` when that is set —\n * provide it explicitly whenever the bar renders without a visible label,\n * otherwise screen readers announce an unnamed progressbar.\n */\n \"aria-label\"?: string;\n /** Id of an existing element that names the bar (alternative to `aria-label`). */\n \"aria-labelledby\"?: string;\n className?: string;\n}\n\n/**\n * Linear progress bar with determinate / indeterminate modes.\n *\n * The `progressbar` role requires an accessible name: it comes from\n * `aria-labelledby`, then explicit `aria-label`, then the visible `label`.\n */\nexport function Progress({\n value = 0,\n max = 100,\n variant = \"primary\",\n indeterminate = false,\n showLabel = false,\n label,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n className,\n}: ProgressProps) {\n const pct = indeterminate ? 0 : Math.max(0, Math.min(100, (value / max) * 100));\n\n return (\n <div className={cn(styles.wrapper, className)}>\n {(showLabel || label) && (\n <div className={styles.label}>\n {label && <span>{label}</span>}\n {showLabel && !indeterminate && <span>{Math.round(pct)}%</span>}\n </div>\n )}\n <div\n role=\"progressbar\"\n aria-label={ariaLabelledBy ? undefined : (ariaLabel ?? label)}\n aria-labelledby={ariaLabelledBy}\n aria-valuemin={0}\n aria-valuemax={max}\n aria-valuenow={indeterminate ? undefined : value}\n className={cn(styles.bar, indeterminate && styles.indeterminate)}\n >\n <div\n className={cn(styles.fill, variant !== \"primary\" && styles[variant])}\n style={{ width: indeterminate ? undefined : `${pct}%` }}\n />\n </div>\n </div>\n );\n}\n"],"mappings":"4GAuCA,SAAgB,EAAS,CACrB,QAAQ,EACR,MAAM,IACN,UAAU,UACV,gBAAgB,GAChB,YAAY,GACZ,QACA,aAAc,EACd,kBAAmB,EACnB,aACc,CACd,IAAM,EAAM,EAAgB,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,IAAM,EAAQ,EAAO,GAAG,CAAC,EAE9E,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,
|
|
1
|
+
{"version":3,"file":"Progress.cjs","names":[],"sources":["../../../src/components/Progress/Progress.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — value, max, indeterminate, size, tone, label,\n * showValue and className: a progress bar is one element with eight independent\n * presentation choices, and the destructuring counts them all because none has a\n * sensible sub-object.\n */\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Progress.module.css\";\n\nexport type ProgressVariant = \"primary\" | \"success\" | \"warning\" | \"danger\";\n\nexport interface ProgressProps {\n /** Value between 0 and `max` (or 0-100 by default). Ignored when `indeterminate`. */\n value?: number;\n max?: number;\n variant?: ProgressVariant;\n /** Show an animated indeterminate bar. Default: false. */\n indeterminate?: boolean;\n /** Render a numeric label \"x% / max\" above the bar. Default: false. */\n showLabel?: boolean;\n /** Optional left-aligned descriptor (e.g. \"Enviando arquivo…\"). */\n label?: string;\n /**\n * Accessible name for the bar. Defaults to `label` when that is set —\n * provide it explicitly whenever the bar renders without a visible label,\n * otherwise screen readers announce an unnamed progressbar.\n */\n \"aria-label\"?: string;\n /** Id of an existing element that names the bar (alternative to `aria-label`). */\n \"aria-labelledby\"?: string;\n className?: string;\n}\n\n/**\n * Linear progress bar with determinate / indeterminate modes.\n *\n * The `progressbar` role requires an accessible name: it comes from\n * `aria-labelledby`, then explicit `aria-label`, then the visible `label`.\n */\nexport function Progress({\n value = 0,\n max = 100,\n variant = \"primary\",\n indeterminate = false,\n showLabel = false,\n label,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n className,\n}: ProgressProps) {\n const pct = indeterminate ? 0 : Math.max(0, Math.min(100, (value / max) * 100));\n\n return (\n <div className={cn(styles.wrapper, className)}>\n {(showLabel || label) && (\n <div className={styles.label}>\n {label && <span>{label}</span>}\n {showLabel && !indeterminate && <span>{Math.round(pct)}%</span>}\n </div>\n )}\n <div\n role=\"progressbar\"\n aria-label={ariaLabelledBy ? undefined : (ariaLabel ?? label)}\n aria-labelledby={ariaLabelledBy}\n aria-valuemin={0}\n aria-valuemax={max}\n aria-valuenow={indeterminate ? undefined : value}\n className={cn(styles.bar, indeterminate && styles.indeterminate)}\n >\n <div\n className={cn(styles.fill, variant !== \"primary\" && styles[variant])}\n style={{ width: indeterminate ? undefined : `${pct}%` }}\n />\n </div>\n </div>\n );\n}\n"],"mappings":"4GAuCA,SAAgB,EAAS,CACrB,QAAQ,EACR,MAAM,IACN,UAAU,UACV,gBAAgB,GAChB,YAAY,GACZ,QACA,aAAc,EACd,kBAAmB,EACnB,aACc,CACd,IAAM,EAAM,EAAgB,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,IAAM,EAAQ,EAAO,GAAG,CAAC,EAE9E,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EAA5C,SAAA,EACM,GAAa,KACX,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,MAAvB,SAAA,CACK,IAAS,EAAA,EAAA,IAAA,CAAC,OAAD,CAAA,SAAO,CAAY,CAAA,EAC5B,GAAa,CAAC,IAAiB,EAAA,EAAA,KAAA,CAAC,OAAD,CAAA,SAAA,CAAO,KAAK,MAAM,CAAG,EAAE,GAAO,CAAA,CAAA,CAC7D,CAET,CAAA,GAAA,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,KAAK,cACL,aAAY,EAAiB,IAAA,GAAa,GAAa,EACvD,kBAAiB,EACjB,gBAAe,EACf,gBAAe,EACf,gBAAe,EAAgB,IAAA,GAAY,EAC3C,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,GAAiB,EAAA,QAAO,aAAa,EAE/D,UAAA,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,IAAY,WAAa,EAAA,QAAO,EAAQ,EACnE,MAAO,CAAE,MAAO,EAAgB,IAAA,GAAY,GAAG,EAAI,EAAG,CACzD,CAAA,CACA,CAAA,CACJ,GAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Progress.js","names":[],"sources":["../../../src/components/Progress/Progress.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — value, max, indeterminate, size, tone, label,\n * showValue and className: a progress bar is one element with eight independent\n * presentation choices, and the destructuring counts them all because none has a\n * sensible sub-object.\n */\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Progress.module.css\";\n\nexport type ProgressVariant = \"primary\" | \"success\" | \"warning\" | \"danger\";\n\nexport interface ProgressProps {\n /** Value between 0 and `max` (or 0-100 by default). Ignored when `indeterminate`. */\n value?: number;\n max?: number;\n variant?: ProgressVariant;\n /** Show an animated indeterminate bar. Default: false. */\n indeterminate?: boolean;\n /** Render a numeric label \"x% / max\" above the bar. Default: false. */\n showLabel?: boolean;\n /** Optional left-aligned descriptor (e.g. \"Enviando arquivo…\"). */\n label?: string;\n /**\n * Accessible name for the bar. Defaults to `label` when that is set —\n * provide it explicitly whenever the bar renders without a visible label,\n * otherwise screen readers announce an unnamed progressbar.\n */\n \"aria-label\"?: string;\n /** Id of an existing element that names the bar (alternative to `aria-label`). */\n \"aria-labelledby\"?: string;\n className?: string;\n}\n\n/**\n * Linear progress bar with determinate / indeterminate modes.\n *\n * The `progressbar` role requires an accessible name: it comes from\n * `aria-labelledby`, then explicit `aria-label`, then the visible `label`.\n */\nexport function Progress({\n value = 0,\n max = 100,\n variant = \"primary\",\n indeterminate = false,\n showLabel = false,\n label,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n className,\n}: ProgressProps) {\n const pct = indeterminate ? 0 : Math.max(0, Math.min(100, (value / max) * 100));\n\n return (\n <div className={cn(styles.wrapper, className)}>\n {(showLabel || label) && (\n <div className={styles.label}>\n {label && <span>{label}</span>}\n {showLabel && !indeterminate && <span>{Math.round(pct)}%</span>}\n </div>\n )}\n <div\n role=\"progressbar\"\n aria-label={ariaLabelledBy ? undefined : (ariaLabel ?? label)}\n aria-labelledby={ariaLabelledBy}\n aria-valuemin={0}\n aria-valuemax={max}\n aria-valuenow={indeterminate ? undefined : value}\n className={cn(styles.bar, indeterminate && styles.indeterminate)}\n >\n <div\n className={cn(styles.fill, variant !== \"primary\" && styles[variant])}\n style={{ width: indeterminate ? undefined : `${pct}%` }}\n />\n </div>\n </div>\n );\n}\n"],"mappings":";;;;AAuCA,SAAgB,EAAS,EACrB,WAAQ,GACR,SAAM,KACN,aAAU,WACV,mBAAgB,IAChB,eAAY,IACZ,UACA,cAAc,GACd,mBAAmB,GACnB,gBACc;CACd,IAAM,IAAM,IAAgB,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,KAAM,IAAQ,IAAO,GAAG,CAAC;CAE9E,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAS;
|
|
1
|
+
{"version":3,"file":"Progress.js","names":[],"sources":["../../../src/components/Progress/Progress.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — value, max, indeterminate, size, tone, label,\n * showValue and className: a progress bar is one element with eight independent\n * presentation choices, and the destructuring counts them all because none has a\n * sensible sub-object.\n */\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Progress.module.css\";\n\nexport type ProgressVariant = \"primary\" | \"success\" | \"warning\" | \"danger\";\n\nexport interface ProgressProps {\n /** Value between 0 and `max` (or 0-100 by default). Ignored when `indeterminate`. */\n value?: number;\n max?: number;\n variant?: ProgressVariant;\n /** Show an animated indeterminate bar. Default: false. */\n indeterminate?: boolean;\n /** Render a numeric label \"x% / max\" above the bar. Default: false. */\n showLabel?: boolean;\n /** Optional left-aligned descriptor (e.g. \"Enviando arquivo…\"). */\n label?: string;\n /**\n * Accessible name for the bar. Defaults to `label` when that is set —\n * provide it explicitly whenever the bar renders without a visible label,\n * otherwise screen readers announce an unnamed progressbar.\n */\n \"aria-label\"?: string;\n /** Id of an existing element that names the bar (alternative to `aria-label`). */\n \"aria-labelledby\"?: string;\n className?: string;\n}\n\n/**\n * Linear progress bar with determinate / indeterminate modes.\n *\n * The `progressbar` role requires an accessible name: it comes from\n * `aria-labelledby`, then explicit `aria-label`, then the visible `label`.\n */\nexport function Progress({\n value = 0,\n max = 100,\n variant = \"primary\",\n indeterminate = false,\n showLabel = false,\n label,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n className,\n}: ProgressProps) {\n const pct = indeterminate ? 0 : Math.max(0, Math.min(100, (value / max) * 100));\n\n return (\n <div className={cn(styles.wrapper, className)}>\n {(showLabel || label) && (\n <div className={styles.label}>\n {label && <span>{label}</span>}\n {showLabel && !indeterminate && <span>{Math.round(pct)}%</span>}\n </div>\n )}\n <div\n role=\"progressbar\"\n aria-label={ariaLabelledBy ? undefined : (ariaLabel ?? label)}\n aria-labelledby={ariaLabelledBy}\n aria-valuemin={0}\n aria-valuemax={max}\n aria-valuenow={indeterminate ? undefined : value}\n className={cn(styles.bar, indeterminate && styles.indeterminate)}\n >\n <div\n className={cn(styles.fill, variant !== \"primary\" && styles[variant])}\n style={{ width: indeterminate ? undefined : `${pct}%` }}\n />\n </div>\n </div>\n );\n}\n"],"mappings":";;;;AAuCA,SAAgB,EAAS,EACrB,WAAQ,GACR,SAAM,KACN,aAAU,WACV,mBAAgB,IAChB,eAAY,IACZ,UACA,cAAc,GACd,mBAAmB,GACnB,gBACc;CACd,IAAM,IAAM,IAAgB,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,KAAM,IAAQ,IAAO,GAAG,CAAC;CAE9E,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,SAAS,CAAS;EAA5C,UAAA,EACM,KAAa,MACX,kBAAC,OAAD;GAAK,WAAW,EAAO;GAAvB,UAAA,CACK,KAAS,kBAAC,QAAD,EAAA,UAAO,EAAY,CAAA,GAC5B,KAAa,CAAC,KAAiB,kBAAC,QAAD,EAAA,UAAA,CAAO,KAAK,MAAM,CAAG,GAAE,GAAO,EAAA,CAAA,CAC7D;EAET,CAAA,GAAA,kBAAC,OAAD;GACI,MAAK;GACL,cAAY,IAAiB,KAAA,IAAa,KAAa;GACvD,mBAAiB;GACjB,iBAAe;GACf,iBAAe;GACf,iBAAe,IAAgB,KAAA,IAAY;GAC3C,WAAW,EAAG,EAAO,KAAK,KAAiB,EAAO,aAAa;GAE/D,UAAA,kBAAC,OAAD;IACI,WAAW,EAAG,EAAO,MAAM,MAAY,aAAa,EAAO,EAAQ;IACnE,OAAO,EAAE,OAAO,IAAgB,KAAA,IAAY,GAAG,EAAI,GAAG;GACzD,CAAA;EACA,CAAA,CACJ;;AAEb"}
|