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":"BrazilStateCitySelect.cjs","names":[],"sources":["../../src/br/BrazilStateCitySelect.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — two dependent selects in one control, so every knob\n * comes in pairs: stateLabel and cityLabel, statePlaceholder and cityPlaceholder,\n * defaultUf and defaultCity. The pairing is the feature — the city list is derived\n * from the chosen UF, which is exactly what a caller wiring two separate selects has\n * to reimplement.\n */\nimport { useMemo, useState, type ReactElement } from \"react\";\nimport { Select } from \"@/components/Select\";\nimport { cityChoices, listStates, normalizeUf, type UF } from \"./locations\";\n\n/** Current selection emitted by {@link BrazilStateCitySelect}. */\nexport interface BrazilStateCitySelection {\n /** Selected federative unit, or `null` when none. */\n uf: UF | null;\n /** Selected city, or `null` when none. */\n city: string | null;\n}\n\nexport interface BrazilStateCitySelectProps {\n /** Pre-selected UF (uncontrolled initial value). */\n defaultUf?: UF;\n /** Pre-selected city (uncontrolled initial value). */\n defaultCity?: string;\n /** Fired whenever the state or city changes. */\n onChange?: (selection: BrazilStateCitySelection) => void;\n /** Label for the state select. Default: `\"Estado\"`. */\n stateLabel?: string;\n /** Label for the city select. Default: `\"Cidade\"`. */\n cityLabel?: string;\n /** Placeholder for the state select. Default: `\"Selecione o estado\"`. */\n statePlaceholder?: string;\n /** Placeholder for the city select. Default: `\"Selecione a cidade\"`. */\n cityPlaceholder?: string;\n /** Disable both selects. */\n disabled?: boolean;\n /** Layout of the two selects. Default: `\"row\"`. */\n layout?: \"row\" | \"column\";\n}\n\n/**\n * Cascading Estado → Cidade selector backed by the bundled BR locations data —\n * pick a state and the city list narrows to that UF's municipalities. No\n * network, no external API. Complements {@link BrazilMap} (wire the map's\n * `onSelect` to drive the same UF).\n *\n * @example\n * <BrazilStateCitySelect onChange={({ uf, city }) => console.log(uf, city)} />\n */\nexport function BrazilStateCitySelect({\n defaultUf,\n defaultCity,\n onChange,\n stateLabel = \"Estado\",\n cityLabel = \"Cidade\",\n statePlaceholder = \"Selecione o estado\",\n cityPlaceholder = \"Selecione a cidade\",\n disabled = false,\n layout = \"row\",\n}: BrazilStateCitySelectProps): ReactElement {\n const [uf, setUf] = useState<UF | null>(defaultUf ?? null);\n const [city, setCity] = useState<string | null>(defaultCity ?? null);\n\n const stateOptions = useMemo(\n () => listStates().map((s) => ({ value: s.uf, label: s.name })),\n [],\n );\n const cityOptions = useMemo(() => (uf ? cityChoices(uf) : []), [uf]);\n\n function handleUf(next: string): void {\n const nextUf = normalizeUf(next);\n setUf(nextUf);\n setCity(null);\n onChange?.({ uf: nextUf, city: null });\n }\n\n function handleCity(next: string): void {\n const nextCity = next || null;\n setCity(nextCity);\n onChange?.({ uf, city: nextCity });\n }\n\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: layout === \"row\" ? \"row\" : \"column\",\n gap: \"var(--tempest-space-3, 12px)\",\n flexWrap: \"wrap\",\n }}\n >\n <Select\n label={stateLabel}\n placeholder={statePlaceholder}\n options={stateOptions}\n value={uf ?? \"\"}\n disabled={disabled}\n onChange={(e) => handleUf(e.target.value)}\n style={{ minWidth: 0 }}\n />\n <Select\n label={cityLabel}\n placeholder={cityPlaceholder}\n options={cityOptions}\n value={city ?? \"\"}\n disabled={disabled || !uf}\n onChange={(e) => handleCity(e.target.value)}\n style={{ minWidth: 0 }}\n />\n </div>\n );\n}\n"],"mappings":"sIAiDA,SAAgB,EAAsB,CAClC,YACA,cACA,WACA,aAAa,SACb,YAAY,SACZ,mBAAmB,qBACnB,kBAAkB,qBAClB,WAAW,GACX,SAAS,OACgC,CACzC,GAAM,CAAC,EAAI,IAAA,
|
|
1
|
+
{"version":3,"file":"BrazilStateCitySelect.cjs","names":[],"sources":["../../src/br/BrazilStateCitySelect.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — two dependent selects in one control, so every knob\n * comes in pairs: stateLabel and cityLabel, statePlaceholder and cityPlaceholder,\n * defaultUf and defaultCity. The pairing is the feature — the city list is derived\n * from the chosen UF, which is exactly what a caller wiring two separate selects has\n * to reimplement.\n */\nimport { useMemo, useState, type ReactElement } from \"react\";\nimport { Select } from \"@/components/Select\";\nimport { cityChoices, listStates, normalizeUf, type UF } from \"./locations\";\n\n/** Current selection emitted by {@link BrazilStateCitySelect}. */\nexport interface BrazilStateCitySelection {\n /** Selected federative unit, or `null` when none. */\n uf: UF | null;\n /** Selected city, or `null` when none. */\n city: string | null;\n}\n\nexport interface BrazilStateCitySelectProps {\n /** Pre-selected UF (uncontrolled initial value). */\n defaultUf?: UF;\n /** Pre-selected city (uncontrolled initial value). */\n defaultCity?: string;\n /** Fired whenever the state or city changes. */\n onChange?: (selection: BrazilStateCitySelection) => void;\n /** Label for the state select. Default: `\"Estado\"`. */\n stateLabel?: string;\n /** Label for the city select. Default: `\"Cidade\"`. */\n cityLabel?: string;\n /** Placeholder for the state select. Default: `\"Selecione o estado\"`. */\n statePlaceholder?: string;\n /** Placeholder for the city select. Default: `\"Selecione a cidade\"`. */\n cityPlaceholder?: string;\n /** Disable both selects. */\n disabled?: boolean;\n /** Layout of the two selects. Default: `\"row\"`. */\n layout?: \"row\" | \"column\";\n}\n\n/**\n * Cascading Estado → Cidade selector backed by the bundled BR locations data —\n * pick a state and the city list narrows to that UF's municipalities. No\n * network, no external API. Complements {@link BrazilMap} (wire the map's\n * `onSelect` to drive the same UF).\n *\n * @example\n * <BrazilStateCitySelect onChange={({ uf, city }) => console.log(uf, city)} />\n */\nexport function BrazilStateCitySelect({\n defaultUf,\n defaultCity,\n onChange,\n stateLabel = \"Estado\",\n cityLabel = \"Cidade\",\n statePlaceholder = \"Selecione o estado\",\n cityPlaceholder = \"Selecione a cidade\",\n disabled = false,\n layout = \"row\",\n}: BrazilStateCitySelectProps): ReactElement {\n const [uf, setUf] = useState<UF | null>(defaultUf ?? null);\n const [city, setCity] = useState<string | null>(defaultCity ?? null);\n\n const stateOptions = useMemo(\n () => listStates().map((s) => ({ value: s.uf, label: s.name })),\n [],\n );\n const cityOptions = useMemo(() => (uf ? cityChoices(uf) : []), [uf]);\n\n function handleUf(next: string): void {\n const nextUf = normalizeUf(next);\n setUf(nextUf);\n setCity(null);\n onChange?.({ uf: nextUf, city: null });\n }\n\n function handleCity(next: string): void {\n const nextCity = next || null;\n setCity(nextCity);\n onChange?.({ uf, city: nextCity });\n }\n\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: layout === \"row\" ? \"row\" : \"column\",\n gap: \"var(--tempest-space-3, 12px)\",\n flexWrap: \"wrap\",\n }}\n >\n <Select\n label={stateLabel}\n placeholder={statePlaceholder}\n options={stateOptions}\n value={uf ?? \"\"}\n disabled={disabled}\n onChange={(e) => handleUf(e.target.value)}\n style={{ minWidth: 0 }}\n />\n <Select\n label={cityLabel}\n placeholder={cityPlaceholder}\n options={cityOptions}\n value={city ?? \"\"}\n disabled={disabled || !uf}\n onChange={(e) => handleCity(e.target.value)}\n style={{ minWidth: 0 }}\n />\n </div>\n );\n}\n"],"mappings":"sIAiDA,SAAgB,EAAsB,CAClC,YACA,cACA,WACA,aAAa,SACb,YAAY,SACZ,mBAAmB,qBACnB,kBAAkB,qBAClB,WAAW,GACX,SAAS,OACgC,CACzC,GAAM,CAAC,EAAI,IAAA,EAAS,EAAA,SAAA,CAAoB,GAAa,IAAI,EACnD,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,CAAwB,GAAe,IAAI,EAE7D,GAAA,EAAe,EAAA,QAAA,KACX,EAAA,WAAW,CAAC,CAAC,IAAK,IAAO,CAAE,MAAO,EAAE,GAAI,MAAO,EAAE,IAAK,EAAE,EAC9D,CAAC,CACL,EACM,GAAA,EAAc,EAAA,QAAA,KAAe,EAAK,EAAA,YAAY,CAAE,EAAI,CAAC,EAAI,CAAC,CAAE,CAAC,EAEnE,SAAS,EAAS,EAAoB,CAClC,IAAM,EAAS,EAAA,YAAY,CAAI,EAC/B,EAAM,CAAM,EACZ,EAAQ,IAAI,EACZ,IAAW,CAAE,GAAI,EAAQ,KAAM,IAAK,CAAC,CACzC,CAEA,SAAS,EAAW,EAAoB,CACpC,IAAM,EAAW,GAAQ,KACzB,EAAQ,CAAQ,EAChB,IAAW,CAAE,KAAI,KAAM,CAAS,CAAC,CACrC,CAEA,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CACI,MAAO,CACH,QAAS,OACT,cAAe,IAAW,MAAQ,MAAQ,SAC1C,IAAK,+BACL,SAAU,MACd,EANJ,SAAA,EAQI,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CACI,MAAO,EACP,YAAa,EACb,QAAS,EACT,MAAO,GAAM,GACH,WACV,SAAW,GAAM,EAAS,EAAE,OAAO,KAAK,EACxC,MAAO,CAAE,SAAU,CAAE,CACxB,CAAA,GACD,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CACI,MAAO,EACP,YAAa,EACb,QAAS,EACT,MAAO,GAAQ,GACf,SAAU,GAAY,CAAC,EACvB,SAAW,GAAM,EAAW,EAAE,OAAO,KAAK,EAC1C,MAAO,CAAE,SAAU,CAAE,CACxB,CAAA,CACA,GAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrazilStateCitySelect.js","names":[],"sources":["../../src/br/BrazilStateCitySelect.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — two dependent selects in one control, so every knob\n * comes in pairs: stateLabel and cityLabel, statePlaceholder and cityPlaceholder,\n * defaultUf and defaultCity. The pairing is the feature — the city list is derived\n * from the chosen UF, which is exactly what a caller wiring two separate selects has\n * to reimplement.\n */\nimport { useMemo, useState, type ReactElement } from \"react\";\nimport { Select } from \"@/components/Select\";\nimport { cityChoices, listStates, normalizeUf, type UF } from \"./locations\";\n\n/** Current selection emitted by {@link BrazilStateCitySelect}. */\nexport interface BrazilStateCitySelection {\n /** Selected federative unit, or `null` when none. */\n uf: UF | null;\n /** Selected city, or `null` when none. */\n city: string | null;\n}\n\nexport interface BrazilStateCitySelectProps {\n /** Pre-selected UF (uncontrolled initial value). */\n defaultUf?: UF;\n /** Pre-selected city (uncontrolled initial value). */\n defaultCity?: string;\n /** Fired whenever the state or city changes. */\n onChange?: (selection: BrazilStateCitySelection) => void;\n /** Label for the state select. Default: `\"Estado\"`. */\n stateLabel?: string;\n /** Label for the city select. Default: `\"Cidade\"`. */\n cityLabel?: string;\n /** Placeholder for the state select. Default: `\"Selecione o estado\"`. */\n statePlaceholder?: string;\n /** Placeholder for the city select. Default: `\"Selecione a cidade\"`. */\n cityPlaceholder?: string;\n /** Disable both selects. */\n disabled?: boolean;\n /** Layout of the two selects. Default: `\"row\"`. */\n layout?: \"row\" | \"column\";\n}\n\n/**\n * Cascading Estado → Cidade selector backed by the bundled BR locations data —\n * pick a state and the city list narrows to that UF's municipalities. No\n * network, no external API. Complements {@link BrazilMap} (wire the map's\n * `onSelect` to drive the same UF).\n *\n * @example\n * <BrazilStateCitySelect onChange={({ uf, city }) => console.log(uf, city)} />\n */\nexport function BrazilStateCitySelect({\n defaultUf,\n defaultCity,\n onChange,\n stateLabel = \"Estado\",\n cityLabel = \"Cidade\",\n statePlaceholder = \"Selecione o estado\",\n cityPlaceholder = \"Selecione a cidade\",\n disabled = false,\n layout = \"row\",\n}: BrazilStateCitySelectProps): ReactElement {\n const [uf, setUf] = useState<UF | null>(defaultUf ?? null);\n const [city, setCity] = useState<string | null>(defaultCity ?? null);\n\n const stateOptions = useMemo(\n () => listStates().map((s) => ({ value: s.uf, label: s.name })),\n [],\n );\n const cityOptions = useMemo(() => (uf ? cityChoices(uf) : []), [uf]);\n\n function handleUf(next: string): void {\n const nextUf = normalizeUf(next);\n setUf(nextUf);\n setCity(null);\n onChange?.({ uf: nextUf, city: null });\n }\n\n function handleCity(next: string): void {\n const nextCity = next || null;\n setCity(nextCity);\n onChange?.({ uf, city: nextCity });\n }\n\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: layout === \"row\" ? \"row\" : \"column\",\n gap: \"var(--tempest-space-3, 12px)\",\n flexWrap: \"wrap\",\n }}\n >\n <Select\n label={stateLabel}\n placeholder={statePlaceholder}\n options={stateOptions}\n value={uf ?? \"\"}\n disabled={disabled}\n onChange={(e) => handleUf(e.target.value)}\n style={{ minWidth: 0 }}\n />\n <Select\n label={cityLabel}\n placeholder={cityPlaceholder}\n options={cityOptions}\n value={city ?? \"\"}\n disabled={disabled || !uf}\n onChange={(e) => handleCity(e.target.value)}\n style={{ minWidth: 0 }}\n />\n </div>\n );\n}\n"],"mappings":";;;;;AAiDA,SAAgB,EAAsB,EAClC,cACA,gBACA,aACA,gBAAa,UACb,eAAY,UACZ,sBAAmB,sBACnB,qBAAkB,sBAClB,cAAW,IACX,YAAS,SACgC;CACzC,IAAM,CAAC,GAAI,KAAS,EAAoB,KAAa,IAAI,GACnD,CAAC,GAAM,KAAW,EAAwB,KAAe,IAAI,GAE7D,IAAe,QACX,EAAW,CAAC,CAAC,KAAK,OAAO;EAAE,OAAO,EAAE;EAAI,OAAO,EAAE;CAAK,EAAE,GAC9D,CAAC,CACL,GACM,IAAc,QAAe,IAAK,EAAY,CAAE,IAAI,CAAC,GAAI,CAAC,CAAE,CAAC;CAEnE,SAAS,EAAS,GAAoB;EAClC,IAAM,IAAS,EAAY,CAAI;EAG/B,AAFA,EAAM,CAAM,GACZ,EAAQ,IAAI,GACZ,IAAW;GAAE,IAAI;GAAQ,MAAM;EAAK,CAAC;CACzC;CAEA,SAAS,EAAW,GAAoB;EACpC,IAAM,IAAW,KAAQ;EAEzB,AADA,EAAQ,CAAQ,GAChB,IAAW;GAAE;GAAI,MAAM;EAAS,CAAC;CACrC;CAEA,OACI,kBAAC,OAAD;EACI,OAAO;GACH,SAAS;GACT,eAAe,MAAW,QAAQ,QAAQ;GAC1C,KAAK;GACL,UAAU;EACd;
|
|
1
|
+
{"version":3,"file":"BrazilStateCitySelect.js","names":[],"sources":["../../src/br/BrazilStateCitySelect.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — two dependent selects in one control, so every knob\n * comes in pairs: stateLabel and cityLabel, statePlaceholder and cityPlaceholder,\n * defaultUf and defaultCity. The pairing is the feature — the city list is derived\n * from the chosen UF, which is exactly what a caller wiring two separate selects has\n * to reimplement.\n */\nimport { useMemo, useState, type ReactElement } from \"react\";\nimport { Select } from \"@/components/Select\";\nimport { cityChoices, listStates, normalizeUf, type UF } from \"./locations\";\n\n/** Current selection emitted by {@link BrazilStateCitySelect}. */\nexport interface BrazilStateCitySelection {\n /** Selected federative unit, or `null` when none. */\n uf: UF | null;\n /** Selected city, or `null` when none. */\n city: string | null;\n}\n\nexport interface BrazilStateCitySelectProps {\n /** Pre-selected UF (uncontrolled initial value). */\n defaultUf?: UF;\n /** Pre-selected city (uncontrolled initial value). */\n defaultCity?: string;\n /** Fired whenever the state or city changes. */\n onChange?: (selection: BrazilStateCitySelection) => void;\n /** Label for the state select. Default: `\"Estado\"`. */\n stateLabel?: string;\n /** Label for the city select. Default: `\"Cidade\"`. */\n cityLabel?: string;\n /** Placeholder for the state select. Default: `\"Selecione o estado\"`. */\n statePlaceholder?: string;\n /** Placeholder for the city select. Default: `\"Selecione a cidade\"`. */\n cityPlaceholder?: string;\n /** Disable both selects. */\n disabled?: boolean;\n /** Layout of the two selects. Default: `\"row\"`. */\n layout?: \"row\" | \"column\";\n}\n\n/**\n * Cascading Estado → Cidade selector backed by the bundled BR locations data —\n * pick a state and the city list narrows to that UF's municipalities. No\n * network, no external API. Complements {@link BrazilMap} (wire the map's\n * `onSelect` to drive the same UF).\n *\n * @example\n * <BrazilStateCitySelect onChange={({ uf, city }) => console.log(uf, city)} />\n */\nexport function BrazilStateCitySelect({\n defaultUf,\n defaultCity,\n onChange,\n stateLabel = \"Estado\",\n cityLabel = \"Cidade\",\n statePlaceholder = \"Selecione o estado\",\n cityPlaceholder = \"Selecione a cidade\",\n disabled = false,\n layout = \"row\",\n}: BrazilStateCitySelectProps): ReactElement {\n const [uf, setUf] = useState<UF | null>(defaultUf ?? null);\n const [city, setCity] = useState<string | null>(defaultCity ?? null);\n\n const stateOptions = useMemo(\n () => listStates().map((s) => ({ value: s.uf, label: s.name })),\n [],\n );\n const cityOptions = useMemo(() => (uf ? cityChoices(uf) : []), [uf]);\n\n function handleUf(next: string): void {\n const nextUf = normalizeUf(next);\n setUf(nextUf);\n setCity(null);\n onChange?.({ uf: nextUf, city: null });\n }\n\n function handleCity(next: string): void {\n const nextCity = next || null;\n setCity(nextCity);\n onChange?.({ uf, city: nextCity });\n }\n\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: layout === \"row\" ? \"row\" : \"column\",\n gap: \"var(--tempest-space-3, 12px)\",\n flexWrap: \"wrap\",\n }}\n >\n <Select\n label={stateLabel}\n placeholder={statePlaceholder}\n options={stateOptions}\n value={uf ?? \"\"}\n disabled={disabled}\n onChange={(e) => handleUf(e.target.value)}\n style={{ minWidth: 0 }}\n />\n <Select\n label={cityLabel}\n placeholder={cityPlaceholder}\n options={cityOptions}\n value={city ?? \"\"}\n disabled={disabled || !uf}\n onChange={(e) => handleCity(e.target.value)}\n style={{ minWidth: 0 }}\n />\n </div>\n );\n}\n"],"mappings":";;;;;AAiDA,SAAgB,EAAsB,EAClC,cACA,gBACA,aACA,gBAAa,UACb,eAAY,UACZ,sBAAmB,sBACnB,qBAAkB,sBAClB,cAAW,IACX,YAAS,SACgC;CACzC,IAAM,CAAC,GAAI,KAAS,EAAoB,KAAa,IAAI,GACnD,CAAC,GAAM,KAAW,EAAwB,KAAe,IAAI,GAE7D,IAAe,QACX,EAAW,CAAC,CAAC,KAAK,OAAO;EAAE,OAAO,EAAE;EAAI,OAAO,EAAE;CAAK,EAAE,GAC9D,CAAC,CACL,GACM,IAAc,QAAe,IAAK,EAAY,CAAE,IAAI,CAAC,GAAI,CAAC,CAAE,CAAC;CAEnE,SAAS,EAAS,GAAoB;EAClC,IAAM,IAAS,EAAY,CAAI;EAG/B,AAFA,EAAM,CAAM,GACZ,EAAQ,IAAI,GACZ,IAAW;GAAE,IAAI;GAAQ,MAAM;EAAK,CAAC;CACzC;CAEA,SAAS,EAAW,GAAoB;EACpC,IAAM,IAAW,KAAQ;EAEzB,AADA,EAAQ,CAAQ,GAChB,IAAW;GAAE;GAAI,MAAM;EAAS,CAAC;CACrC;CAEA,OACI,kBAAC,OAAD;EACI,OAAO;GACH,SAAS;GACT,eAAe,MAAW,QAAQ,QAAQ;GAC1C,KAAK;GACL,UAAU;EACd;EANJ,UAAA,CAQI,kBAAC,GAAD;GACI,OAAO;GACP,aAAa;GACb,SAAS;GACT,OAAO,KAAM;GACH;GACV,WAAW,MAAM,EAAS,EAAE,OAAO,KAAK;GACxC,OAAO,EAAE,UAAU,EAAE;EACxB,CAAA,GACD,kBAAC,GAAD;GACI,OAAO;GACP,aAAa;GACb,SAAS;GACT,OAAO,KAAQ;GACf,UAAU,KAAY,CAAC;GACvB,WAAW,MAAM,EAAW,EAAE,OAAO,KAAK;GAC1C,OAAO,EAAE,UAAU,EAAE;EACxB,CAAA,CACA;;AAEb"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../utils/cn.cjs"),t=require("../geo/projection.cjs"),n=require("./locations.cjs"),r=require("./state-geo.cjs"),i=require("./BrazilMap.module.cjs"),a=require("./MapMarkers.cjs"),o=require("./MapTooltip.cjs"),s=require("./use-map-zoom.cjs"),c=require("./svg-utils.cjs"),l=require("./use-map-hover.cjs");let u=require("react"),d=require("react/jsx-runtime");function f({uf:f,selected:p,onSelect:m,values:h,minColor:g=`#dbeafe`,maxColor:_=`#2563eb`,colorScale:v,height:y=440,padding:b=12,showLabels:x=!1,label:S,loadingContent:C,showTooltip:w=!0,renderTooltip:T,markers:E,onMarkerClick:D,zoomable:O=!1,className:k,style:A,...j}){let M=(0,u.useRef)(null),[N,P]=(0,u.useState)(600),[F,I]=(0,u.useState)(null),L=s.useMapZoom(O),{hover:R,onMove:z,onLeave:B}=l.useMapHover(M);(0,u.useEffect)(()=>{let e=!0;return I(null),r.loadStateMunicipalities(f).then(t=>{e&&I(t)}),()=>{e=!1}},[f]),(0,u.useEffect)(()=>{let e=M.current;if(!e||typeof ResizeObserver>`u`)return;let t=new ResizeObserver(e=>{let t=e[0]?.contentRect.width;t&&t>0&&P(t)});return t.observe(e),()=>t.disconnect()},[]);let V=(0,u.useMemo)(()=>p?new Set(Array.isArray(p)?p:[p]):new Set,[p]),H=(0,u.useMemo)(()=>{if(!h)return null;let e=Object.values(h).filter(e=>typeof e==`number`);return e.length===0?null:[Math.min(...e),Math.max(...e)]},[h]),U=(0,u.useMemo)(()=>{if(!F)return null;let e=t.fitProjection(c.geometriesBounds(F.features.map(e=>e.geometry)),N,y,{padding:b});return{projection:e,items:F.features.map(t=>({id:t.properties.id,name:t.properties.name,d:c.geometryPath(t.geometry,e),centroid:c.geometryCentroid(t.geometry,e)}))}},[F,N,y,b]);function W(e,t){let n=h?.[e]??h?.[t];if(typeof n!=`number`)return;if(v)return v(n);if(!H)return;let[r,i]=H
|
|
1
|
+
const e=require("../utils/cn.cjs"),t=require("../geo/projection.cjs"),n=require("./locations.cjs"),r=require("./state-geo.cjs"),i=require("./BrazilMap.module.cjs"),a=require("./MapMarkers.cjs"),o=require("./MapTooltip.cjs"),s=require("./use-map-zoom.cjs"),c=require("./svg-utils.cjs"),l=require("./use-map-hover.cjs");let u=require("react"),d=require("react/jsx-runtime");function f({uf:f,selected:p,onSelect:m,values:h,minColor:g=`#dbeafe`,maxColor:_=`#2563eb`,colorScale:v,height:y=440,padding:b=12,showLabels:x=!1,label:S,loadingContent:C,showTooltip:w=!0,renderTooltip:T,markers:E,onMarkerClick:D,zoomable:O=!1,className:k,style:A,...j}){let M=(0,u.useRef)(null),[N,P]=(0,u.useState)(600),[F,I]=(0,u.useState)(null),L=s.useMapZoom(O),{hover:R,onMove:z,onLeave:B}=l.useMapHover(M);(0,u.useEffect)(()=>{let e=!0;return I(null),r.loadStateMunicipalities(f).then(t=>{e&&I(t)}),()=>{e=!1}},[f]),(0,u.useEffect)(()=>{let e=M.current;if(!e||typeof ResizeObserver>`u`)return;let t=new ResizeObserver(e=>{let t=e[0]?.contentRect.width;t&&t>0&&P(t)});return t.observe(e),()=>t.disconnect()},[]);let V=(0,u.useMemo)(()=>p?new Set(Array.isArray(p)?p:[p]):new Set,[p]),H=(0,u.useMemo)(()=>{if(!h)return null;let e=Object.values(h).filter(e=>typeof e==`number`);return e.length===0?null:[Math.min(...e),Math.max(...e)]},[h]),U=(0,u.useMemo)(()=>{if(!F)return null;let e=t.fitProjection(c.geometriesBounds(F.features.map(e=>e.geometry)),N,y,{padding:b});return{projection:e,items:F.features.map(t=>({id:t.properties.id,name:t.properties.name,d:c.geometryPath(t.geometry,e),centroid:c.geometryCentroid(t.geometry,e)}))}},[F,N,y,b]);function W(e,t){let n=h?.[e]??h?.[t];if(typeof n!=`number`)return;if(v)return v(n);if(!H)return;let[r,i]=H,a=i===r?1:(n-r)/(i-r);return c.lerpColor(g,_,a)}let G=(0,u.useMemo)(()=>U?U.items.map(t=>{let n=V.has(t.id)||V.has(t.name),r=n?void 0:W(t.id,t.name);return(0,d.jsx)(`path`,{className:e.cn(i.default.state,n&&i.default.selected),d:t.d,fillRule:`evenodd`,style:r?{fill:r}:void 0,"data-city-id":t.id,"data-city":t.name,tabIndex:m?0:void 0,role:m?`button`:void 0,"aria-label":t.name,"aria-pressed":m?n:void 0,onClick:m?()=>m({id:t.id,name:t.name}):void 0,onMouseMove:w?e=>z({id:t.id,name:t.name},e):void 0,onMouseLeave:w?B:void 0,onKeyDown:m?e=>{(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),m({id:t.id,name:t.name}))}:void 0},t.id)}):null,[U,V,h,v,g,_,m,w,z,B]),K=S??`Municípios de ${n.getState(f)?.name??f}`;return(0,d.jsxs)(`div`,{ref:M,className:e.cn(i.default.map,k),style:{height:y,...A},role:`group`,"aria-label":K,...j,children:[U?(0,d.jsx)(`svg`,{className:i.default.svg,width:`100%`,height:y,viewBox:`0 0 ${N} ${y}`,preserveAspectRatio:`xMidYMid meet`,...L.handlers,children:(0,d.jsxs)(`g`,{transform:L.transform||void 0,children:[G,x&&U.items.map(e=>(0,d.jsx)(`text`,{className:i.default.label,x:e.centroid.x,y:e.centroid.y,textAnchor:`middle`,dominantBaseline:`central`,children:e.name},`label-${e.id}`)),E&&E.length>0&&(0,d.jsx)(a.MapMarkers,{projection:U.projection,markers:E,onMarkerClick:D})]})}):(0,d.jsx)(`div`,{className:i.default.loading,children:C??`Carregando municípios…`}),L.isTransformed&&(0,d.jsx)(`button`,{type:`button`,className:i.default.zoomReset,onClick:L.reset,children:`Reset`}),w&&R&&(0,d.jsx)(o.MapTooltip,{x:R.x,y:R.y,children:T?T({...R.item,value:h?.[R.item.id]??h?.[R.item.name]}):(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(`div`,{className:i.default.tooltipTitle,children:R.item.name}),(0,d.jsxs)(`div`,{className:i.default.tooltipMeta,children:[`IBGE `,R.item.id,(()=>{let e=h?.[R.item.id]??h?.[R.item.name];return typeof e==`number`?` · ${e}`:``})()]})]})})]})}exports.BrazilStateMap=f;
|
|
2
2
|
//# sourceMappingURL=BrazilStateMap.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrazilStateMap.cjs","names":[],"sources":["../../src/br/BrazilStateMap.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the municipality-level\n * twin of BrazilMap, prop for prop, plus the `uf` that selects which state's\n * geometry to load. Splitting it differently from BrazilMap would mean two maps with\n * two shapes for the same job.\n */\nimport { useEffect, useMemo, useRef, useState, type HTMLAttributes, type ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { fitProjection } from \"@/geo/projection\";\nimport type { GeoMarker } from \"@/geo/types\";\nimport { getState, type UF } from \"./locations\";\nimport { MapMarkers } from \"./MapMarkers\";\nimport { MapTooltip } from \"./MapTooltip\";\nimport type { ColorScale } from \"./scales\";\nimport { useMapZoom } from \"./use-map-zoom\";\nimport { loadStateMunicipalities, type StateMunicipalities } from \"./state-geo\";\nimport { geometriesBounds, geometryCentroid, geometryPath, lerpColor } from \"./svg-utils\";\nimport { useMapHover } from \"./use-map-hover\";\nimport styles from \"./BrazilMap.module.css\";\n\n/** A municipality identified for selection callbacks. */\nexport interface Municipality {\n /** 7-digit IBGE code. */\n id: string;\n /** Municipality name. */\n name: string;\n}\n\n/** Data passed to a {@link BrazilStateMapProps.renderTooltip} callback. */\nexport interface BrazilStateMapTooltipData extends Municipality {\n /** Choropleth value for this municipality, if `values` was provided. */\n value?: number;\n}\n\nexport interface BrazilStateMapProps extends Omit<HTMLAttributes<HTMLDivElement>, \"onSelect\"> {\n /** Federative unit to draw (required). */\n uf: UF;\n /** Selected municipality — matched by IBGE `id` or by `name`. Accepts many. */\n selected?: string | readonly string[] | null;\n /** Fired when a municipality is clicked. */\n onSelect?: (municipality: Municipality) => void;\n /**\n * Choropleth values keyed by municipality `id` **or** `name`. When set, each\n * municipality is tinted between `minColor` and `maxColor`.\n */\n values?: Record<string, number>;\n /** Choropleth low-end color (2-color linear ramp). Default: a light primary tint. */\n minColor?: string;\n /** Choropleth high-end color (2-color linear ramp). Default: the primary token. */\n maxColor?: string;\n /**\n * Custom value→color scale (from `sequentialScale`/`quantizeScale`). Takes\n * precedence over `minColor`/`maxColor`. Pair with a `<MapLegend>`.\n */\n colorScale?: ColorScale;\n /** Viewport height in pixels. Default: `440`. */\n height?: number;\n /** Inner padding in pixels. Default: `12`. */\n padding?: number;\n /**\n * Render each municipality name at its centroid. Off by default — a state\n * can have hundreds of municipalities and labels overlap badly.\n */\n showLabels?: boolean;\n /** Accessible label. Default: derived from the state name. */\n label?: string;\n /** Content while the state geometry is loading. */\n loadingContent?: ReactNode;\n /** Show a floating tooltip (name + IBGE code + value) on hover. Default: `true`. */\n showTooltip?: boolean;\n /** Override the default tooltip content. */\n renderTooltip?: (data: BrazilStateMapTooltipData) => ReactNode;\n /** Point markers to overlay on the state (e.g. addresses, POIs). */\n markers?: readonly GeoMarker[];\n /** Fired when a marker is clicked. */\n onMarkerClick?: (marker: GeoMarker, index: number) => void;\n /** Enable wheel-zoom + drag-pan (double-click resets). Default: `false`. */\n zoomable?: boolean;\n}\n\n/**\n * Clickable submap of a single Brazilian state showing **all its\n * municipalities** as SVG paths — no external tiles or paid API. The state's\n * geometry (~40-70 KB gzip) is loaded lazily per UF, so switching states fetches\n * only what is shown.\n *\n * @example\n * const [city, setCity] = useState<string | null>(null);\n * <BrazilStateMap uf=\"SP\" selected={city} onSelect={(m) => setCity(m.name)} />\n *\n * @example\n * // Choropleth of a metric by municipality name\n * <BrazilStateMap uf=\"RJ\" values={{ \"Rio de Janeiro\": 100, Niterói: 40 }} />\n */\nexport function BrazilStateMap({\n uf,\n selected,\n onSelect,\n values,\n minColor = \"#dbeafe\",\n maxColor = \"#2563eb\",\n colorScale,\n height = 440,\n padding = 12,\n showLabels = false,\n label,\n loadingContent,\n showTooltip = true,\n renderTooltip,\n markers,\n onMarkerClick,\n zoomable = false,\n className,\n style,\n ...rest\n}: BrazilStateMapProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState<number>(600);\n const [collection, setCollection] = useState<StateMunicipalities | null>(null);\n const mapZoom = useMapZoom(zoomable);\n const { hover, onMove, onLeave } = useMapHover<Municipality>(containerRef);\n\n useEffect(() => {\n let active = true;\n setCollection(null);\n void loadStateMunicipalities(uf).then((data) => {\n if (active) setCollection(data);\n });\n return () => {\n active = false;\n };\n }, [uf]);\n\n useEffect(() => {\n const node = containerRef.current;\n if (!node || typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver((entries) => {\n const measured = entries[0]?.contentRect.width;\n if (measured && measured > 0) setWidth(measured);\n });\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n const selectedSet = useMemo<Set<string>>(() => {\n if (!selected) return new Set();\n return new Set(Array.isArray(selected) ? selected : [selected as string]);\n }, [selected]);\n\n const valueRange = useMemo<[number, number] | null>(() => {\n if (!values) return null;\n const nums = Object.values(values).filter((v): v is number => typeof v === \"number\");\n if (nums.length === 0) return null;\n return [Math.min(...nums), Math.max(...nums)];\n }, [values]);\n\n const shapes = useMemo(() => {\n if (!collection) return null;\n const projection = fitProjection(\n geometriesBounds(collection.features.map((f) => f.geometry)),\n width,\n height,\n { padding },\n );\n const items = collection.features.map((feature) => ({\n id: feature.properties.id,\n name: feature.properties.name,\n d: geometryPath(feature.geometry, projection),\n centroid: geometryCentroid(feature.geometry, projection),\n }));\n return { projection, items };\n }, [collection, width, height, padding]);\n\n function fillFor(id: string, name: string): string | undefined {\n const v = values?.[id] ?? values?.[name];\n if (typeof v !== \"number\") return undefined;\n if (colorScale) return colorScale(v);\n if (!valueRange) return undefined;\n const [min, max] = valueRange;\n const t = max === min ? 1 : (v - min) / (max - min);\n return lerpColor(minColor, maxColor, t);\n }\n\n // Memoized so hover re-renders don't rebuild hundreds of municipality paths.\n const cityEls = useMemo(() => {\n if (!shapes) return null;\n return shapes.items.map((shape) => {\n const isSelected = selectedSet.has(shape.id) || selectedSet.has(shape.name);\n const fillColor = isSelected ? undefined : fillFor(shape.id, shape.name);\n return (\n <path\n key={shape.id}\n className={cn(styles.state, isSelected && styles.selected)}\n d={shape.d}\n fillRule=\"evenodd\"\n style={fillColor ? { fill: fillColor } : undefined}\n data-city-id={shape.id}\n data-city={shape.name}\n tabIndex={onSelect ? 0 : undefined}\n role={onSelect ? \"button\" : undefined}\n aria-label={shape.name}\n aria-pressed={onSelect ? isSelected : undefined}\n onClick={\n onSelect ? () => onSelect({ id: shape.id, name: shape.name }) : undefined\n }\n onMouseMove={\n showTooltip\n ? (e) => onMove({ id: shape.id, name: shape.name }, e)\n : undefined\n }\n onMouseLeave={showTooltip ? onLeave : undefined}\n onKeyDown={\n onSelect\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onSelect({ id: shape.id, name: shape.name });\n }\n }\n : undefined\n }\n />\n );\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n shapes,\n selectedSet,\n values,\n colorScale,\n minColor,\n maxColor,\n onSelect,\n showTooltip,\n onMove,\n onLeave,\n ]);\n\n const resolvedLabel = label ?? `Municípios de ${getState(uf)?.name ?? uf}`;\n\n return (\n <div\n ref={containerRef}\n className={cn(styles.map, className)}\n style={{ height, ...style }}\n role=\"group\"\n aria-label={resolvedLabel}\n {...rest}\n >\n {!shapes ? (\n <div className={styles.loading}>{loadingContent ?? \"Carregando municípios…\"}</div>\n ) : (\n <svg\n className={styles.svg}\n width=\"100%\"\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n preserveAspectRatio=\"xMidYMid meet\"\n {...mapZoom.handlers}\n >\n <g transform={mapZoom.transform || undefined}>\n {cityEls}\n\n {showLabels &&\n shapes.items.map((shape) => (\n <text\n key={`label-${shape.id}`}\n className={styles.label}\n x={shape.centroid.x}\n y={shape.centroid.y}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n >\n {shape.name}\n </text>\n ))}\n\n {markers && markers.length > 0 && (\n <MapMarkers\n projection={shapes.projection}\n markers={markers}\n onMarkerClick={onMarkerClick}\n />\n )}\n </g>\n </svg>\n )}\n\n {mapZoom.isTransformed && (\n <button type=\"button\" className={styles.zoomReset} onClick={mapZoom.reset}>\n Reset\n </button>\n )}\n\n {showTooltip && hover && (\n <MapTooltip x={hover.x} y={hover.y}>\n {renderTooltip ? (\n renderTooltip({\n ...hover.item,\n value: values?.[hover.item.id] ?? values?.[hover.item.name],\n })\n ) : (\n <>\n <div className={styles.tooltipTitle}>{hover.item.name}</div>\n <div className={styles.tooltipMeta}>\n IBGE {hover.item.id}\n {(() => {\n const v = values?.[hover.item.id] ?? values?.[hover.item.name];\n return typeof v === \"number\" ? ` · ${v}` : \"\";\n })()}\n </div>\n </>\n )}\n </MapTooltip>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BrazilStateMap.cjs","names":[],"sources":["../../src/br/BrazilStateMap.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the municipality-level\n * twin of BrazilMap, prop for prop, plus the `uf` that selects which state's\n * geometry to load. Splitting it differently from BrazilMap would mean two maps with\n * two shapes for the same job.\n */\nimport { useEffect, useMemo, useRef, useState, type HTMLAttributes, type ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { fitProjection } from \"@/geo/projection\";\nimport type { GeoMarker } from \"@/geo/types\";\nimport { getState, type UF } from \"./locations\";\nimport { MapMarkers } from \"./MapMarkers\";\nimport { MapTooltip } from \"./MapTooltip\";\nimport type { ColorScale } from \"./scales\";\nimport { useMapZoom } from \"./use-map-zoom\";\nimport { loadStateMunicipalities, type StateMunicipalities } from \"./state-geo\";\nimport { geometriesBounds, geometryCentroid, geometryPath, lerpColor } from \"./svg-utils\";\nimport { useMapHover } from \"./use-map-hover\";\nimport styles from \"./BrazilMap.module.css\";\n\n/** A municipality identified for selection callbacks. */\nexport interface Municipality {\n /** 7-digit IBGE code. */\n id: string;\n /** Municipality name. */\n name: string;\n}\n\n/** Data passed to a {@link BrazilStateMapProps.renderTooltip} callback. */\nexport interface BrazilStateMapTooltipData extends Municipality {\n /** Choropleth value for this municipality, if `values` was provided. */\n value?: number;\n}\n\nexport interface BrazilStateMapProps extends Omit<HTMLAttributes<HTMLDivElement>, \"onSelect\"> {\n /** Federative unit to draw (required). */\n uf: UF;\n /** Selected municipality — matched by IBGE `id` or by `name`. Accepts many. */\n selected?: string | readonly string[] | null;\n /** Fired when a municipality is clicked. */\n onSelect?: (municipality: Municipality) => void;\n /**\n * Choropleth values keyed by municipality `id` **or** `name`. When set, each\n * municipality is tinted between `minColor` and `maxColor`.\n */\n values?: Record<string, number>;\n /** Choropleth low-end color (2-color linear ramp). Default: a light primary tint. */\n minColor?: string;\n /** Choropleth high-end color (2-color linear ramp). Default: the primary token. */\n maxColor?: string;\n /**\n * Custom value→color scale (from `sequentialScale`/`quantizeScale`). Takes\n * precedence over `minColor`/`maxColor`. Pair with a `<MapLegend>`.\n */\n colorScale?: ColorScale;\n /** Viewport height in pixels. Default: `440`. */\n height?: number;\n /** Inner padding in pixels. Default: `12`. */\n padding?: number;\n /**\n * Render each municipality name at its centroid. Off by default — a state\n * can have hundreds of municipalities and labels overlap badly.\n */\n showLabels?: boolean;\n /** Accessible label. Default: derived from the state name. */\n label?: string;\n /** Content while the state geometry is loading. */\n loadingContent?: ReactNode;\n /** Show a floating tooltip (name + IBGE code + value) on hover. Default: `true`. */\n showTooltip?: boolean;\n /** Override the default tooltip content. */\n renderTooltip?: (data: BrazilStateMapTooltipData) => ReactNode;\n /** Point markers to overlay on the state (e.g. addresses, POIs). */\n markers?: readonly GeoMarker[];\n /** Fired when a marker is clicked. */\n onMarkerClick?: (marker: GeoMarker, index: number) => void;\n /** Enable wheel-zoom + drag-pan (double-click resets). Default: `false`. */\n zoomable?: boolean;\n}\n\n/**\n * Clickable submap of a single Brazilian state showing **all its\n * municipalities** as SVG paths — no external tiles or paid API. The state's\n * geometry (~40-70 KB gzip) is loaded lazily per UF, so switching states fetches\n * only what is shown.\n *\n * @example\n * const [city, setCity] = useState<string | null>(null);\n * <BrazilStateMap uf=\"SP\" selected={city} onSelect={(m) => setCity(m.name)} />\n *\n * @example\n * // Choropleth of a metric by municipality name\n * <BrazilStateMap uf=\"RJ\" values={{ \"Rio de Janeiro\": 100, Niterói: 40 }} />\n */\nexport function BrazilStateMap({\n uf,\n selected,\n onSelect,\n values,\n minColor = \"#dbeafe\",\n maxColor = \"#2563eb\",\n colorScale,\n height = 440,\n padding = 12,\n showLabels = false,\n label,\n loadingContent,\n showTooltip = true,\n renderTooltip,\n markers,\n onMarkerClick,\n zoomable = false,\n className,\n style,\n ...rest\n}: BrazilStateMapProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState<number>(600);\n const [collection, setCollection] = useState<StateMunicipalities | null>(null);\n const mapZoom = useMapZoom(zoomable);\n const { hover, onMove, onLeave } = useMapHover<Municipality>(containerRef);\n\n useEffect(() => {\n let active = true;\n setCollection(null);\n void loadStateMunicipalities(uf).then((data) => {\n if (active) setCollection(data);\n });\n return () => {\n active = false;\n };\n }, [uf]);\n\n useEffect(() => {\n const node = containerRef.current;\n if (!node || typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver((entries) => {\n const measured = entries[0]?.contentRect.width;\n if (measured && measured > 0) setWidth(measured);\n });\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n const selectedSet = useMemo<Set<string>>(() => {\n if (!selected) return new Set();\n return new Set(Array.isArray(selected) ? selected : [selected as string]);\n }, [selected]);\n\n const valueRange = useMemo<[number, number] | null>(() => {\n if (!values) return null;\n const nums = Object.values(values).filter((v): v is number => typeof v === \"number\");\n if (nums.length === 0) return null;\n return [Math.min(...nums), Math.max(...nums)];\n }, [values]);\n\n const shapes = useMemo(() => {\n if (!collection) return null;\n const projection = fitProjection(\n geometriesBounds(collection.features.map((f) => f.geometry)),\n width,\n height,\n { padding },\n );\n const items = collection.features.map((feature) => ({\n id: feature.properties.id,\n name: feature.properties.name,\n d: geometryPath(feature.geometry, projection),\n centroid: geometryCentroid(feature.geometry, projection),\n }));\n return { projection, items };\n }, [collection, width, height, padding]);\n\n function fillFor(id: string, name: string): string | undefined {\n const v = values?.[id] ?? values?.[name];\n if (typeof v !== \"number\") return undefined;\n if (colorScale) return colorScale(v);\n if (!valueRange) return undefined;\n const [min, max] = valueRange;\n const t = max === min ? 1 : (v - min) / (max - min);\n return lerpColor(minColor, maxColor, t);\n }\n\n // Memoized so hover re-renders don't rebuild hundreds of municipality paths.\n const cityEls = useMemo(() => {\n if (!shapes) return null;\n return shapes.items.map((shape) => {\n const isSelected = selectedSet.has(shape.id) || selectedSet.has(shape.name);\n const fillColor = isSelected ? undefined : fillFor(shape.id, shape.name);\n return (\n <path\n key={shape.id}\n className={cn(styles.state, isSelected && styles.selected)}\n d={shape.d}\n fillRule=\"evenodd\"\n style={fillColor ? { fill: fillColor } : undefined}\n data-city-id={shape.id}\n data-city={shape.name}\n tabIndex={onSelect ? 0 : undefined}\n role={onSelect ? \"button\" : undefined}\n aria-label={shape.name}\n aria-pressed={onSelect ? isSelected : undefined}\n onClick={\n onSelect ? () => onSelect({ id: shape.id, name: shape.name }) : undefined\n }\n onMouseMove={\n showTooltip\n ? (e) => onMove({ id: shape.id, name: shape.name }, e)\n : undefined\n }\n onMouseLeave={showTooltip ? onLeave : undefined}\n onKeyDown={\n onSelect\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onSelect({ id: shape.id, name: shape.name });\n }\n }\n : undefined\n }\n />\n );\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n shapes,\n selectedSet,\n values,\n colorScale,\n minColor,\n maxColor,\n onSelect,\n showTooltip,\n onMove,\n onLeave,\n ]);\n\n const resolvedLabel = label ?? `Municípios de ${getState(uf)?.name ?? uf}`;\n\n return (\n <div\n ref={containerRef}\n className={cn(styles.map, className)}\n style={{ height, ...style }}\n role=\"group\"\n aria-label={resolvedLabel}\n {...rest}\n >\n {!shapes ? (\n <div className={styles.loading}>{loadingContent ?? \"Carregando municípios…\"}</div>\n ) : (\n <svg\n className={styles.svg}\n width=\"100%\"\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n preserveAspectRatio=\"xMidYMid meet\"\n {...mapZoom.handlers}\n >\n <g transform={mapZoom.transform || undefined}>\n {cityEls}\n\n {showLabels &&\n shapes.items.map((shape) => (\n <text\n key={`label-${shape.id}`}\n className={styles.label}\n x={shape.centroid.x}\n y={shape.centroid.y}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n >\n {shape.name}\n </text>\n ))}\n\n {markers && markers.length > 0 && (\n <MapMarkers\n projection={shapes.projection}\n markers={markers}\n onMarkerClick={onMarkerClick}\n />\n )}\n </g>\n </svg>\n )}\n\n {mapZoom.isTransformed && (\n <button type=\"button\" className={styles.zoomReset} onClick={mapZoom.reset}>\n Reset\n </button>\n )}\n\n {showTooltip && hover && (\n <MapTooltip x={hover.x} y={hover.y}>\n {renderTooltip ? (\n renderTooltip({\n ...hover.item,\n value: values?.[hover.item.id] ?? values?.[hover.item.name],\n })\n ) : (\n <>\n <div className={styles.tooltipTitle}>{hover.item.name}</div>\n <div className={styles.tooltipMeta}>\n IBGE {hover.item.id}\n {(() => {\n const v = values?.[hover.item.id] ?? values?.[hover.item.name];\n return typeof v === \"number\" ? ` · ${v}` : \"\";\n })()}\n </div>\n </>\n )}\n </MapTooltip>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -56,8 +56,8 @@ function b({ uf: b, selected: x, onSelect: S, values: C, minColor: w = "#dbeafe"
|
|
|
56
56
|
if (typeof n != "number") return;
|
|
57
57
|
if (E) return E(n);
|
|
58
58
|
if (!X) return;
|
|
59
|
-
let [r, i] = X;
|
|
60
|
-
return d(w, T,
|
|
59
|
+
let [r, i] = X, a = i === r ? 1 : (n - r) / (i - r);
|
|
60
|
+
return d(w, T, a);
|
|
61
61
|
}
|
|
62
62
|
let $ = m(() => Z ? Z.items.map((t) => {
|
|
63
63
|
let n = Y.has(t.id) || Y.has(t.name), r = n ? void 0 : Q(t.id, t.name);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrazilStateMap.js","names":[],"sources":["../../src/br/BrazilStateMap.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the municipality-level\n * twin of BrazilMap, prop for prop, plus the `uf` that selects which state's\n * geometry to load. Splitting it differently from BrazilMap would mean two maps with\n * two shapes for the same job.\n */\nimport { useEffect, useMemo, useRef, useState, type HTMLAttributes, type ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { fitProjection } from \"@/geo/projection\";\nimport type { GeoMarker } from \"@/geo/types\";\nimport { getState, type UF } from \"./locations\";\nimport { MapMarkers } from \"./MapMarkers\";\nimport { MapTooltip } from \"./MapTooltip\";\nimport type { ColorScale } from \"./scales\";\nimport { useMapZoom } from \"./use-map-zoom\";\nimport { loadStateMunicipalities, type StateMunicipalities } from \"./state-geo\";\nimport { geometriesBounds, geometryCentroid, geometryPath, lerpColor } from \"./svg-utils\";\nimport { useMapHover } from \"./use-map-hover\";\nimport styles from \"./BrazilMap.module.css\";\n\n/** A municipality identified for selection callbacks. */\nexport interface Municipality {\n /** 7-digit IBGE code. */\n id: string;\n /** Municipality name. */\n name: string;\n}\n\n/** Data passed to a {@link BrazilStateMapProps.renderTooltip} callback. */\nexport interface BrazilStateMapTooltipData extends Municipality {\n /** Choropleth value for this municipality, if `values` was provided. */\n value?: number;\n}\n\nexport interface BrazilStateMapProps extends Omit<HTMLAttributes<HTMLDivElement>, \"onSelect\"> {\n /** Federative unit to draw (required). */\n uf: UF;\n /** Selected municipality — matched by IBGE `id` or by `name`. Accepts many. */\n selected?: string | readonly string[] | null;\n /** Fired when a municipality is clicked. */\n onSelect?: (municipality: Municipality) => void;\n /**\n * Choropleth values keyed by municipality `id` **or** `name`. When set, each\n * municipality is tinted between `minColor` and `maxColor`.\n */\n values?: Record<string, number>;\n /** Choropleth low-end color (2-color linear ramp). Default: a light primary tint. */\n minColor?: string;\n /** Choropleth high-end color (2-color linear ramp). Default: the primary token. */\n maxColor?: string;\n /**\n * Custom value→color scale (from `sequentialScale`/`quantizeScale`). Takes\n * precedence over `minColor`/`maxColor`. Pair with a `<MapLegend>`.\n */\n colorScale?: ColorScale;\n /** Viewport height in pixels. Default: `440`. */\n height?: number;\n /** Inner padding in pixels. Default: `12`. */\n padding?: number;\n /**\n * Render each municipality name at its centroid. Off by default — a state\n * can have hundreds of municipalities and labels overlap badly.\n */\n showLabels?: boolean;\n /** Accessible label. Default: derived from the state name. */\n label?: string;\n /** Content while the state geometry is loading. */\n loadingContent?: ReactNode;\n /** Show a floating tooltip (name + IBGE code + value) on hover. Default: `true`. */\n showTooltip?: boolean;\n /** Override the default tooltip content. */\n renderTooltip?: (data: BrazilStateMapTooltipData) => ReactNode;\n /** Point markers to overlay on the state (e.g. addresses, POIs). */\n markers?: readonly GeoMarker[];\n /** Fired when a marker is clicked. */\n onMarkerClick?: (marker: GeoMarker, index: number) => void;\n /** Enable wheel-zoom + drag-pan (double-click resets). Default: `false`. */\n zoomable?: boolean;\n}\n\n/**\n * Clickable submap of a single Brazilian state showing **all its\n * municipalities** as SVG paths — no external tiles or paid API. The state's\n * geometry (~40-70 KB gzip) is loaded lazily per UF, so switching states fetches\n * only what is shown.\n *\n * @example\n * const [city, setCity] = useState<string | null>(null);\n * <BrazilStateMap uf=\"SP\" selected={city} onSelect={(m) => setCity(m.name)} />\n *\n * @example\n * // Choropleth of a metric by municipality name\n * <BrazilStateMap uf=\"RJ\" values={{ \"Rio de Janeiro\": 100, Niterói: 40 }} />\n */\nexport function BrazilStateMap({\n uf,\n selected,\n onSelect,\n values,\n minColor = \"#dbeafe\",\n maxColor = \"#2563eb\",\n colorScale,\n height = 440,\n padding = 12,\n showLabels = false,\n label,\n loadingContent,\n showTooltip = true,\n renderTooltip,\n markers,\n onMarkerClick,\n zoomable = false,\n className,\n style,\n ...rest\n}: BrazilStateMapProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState<number>(600);\n const [collection, setCollection] = useState<StateMunicipalities | null>(null);\n const mapZoom = useMapZoom(zoomable);\n const { hover, onMove, onLeave } = useMapHover<Municipality>(containerRef);\n\n useEffect(() => {\n let active = true;\n setCollection(null);\n void loadStateMunicipalities(uf).then((data) => {\n if (active) setCollection(data);\n });\n return () => {\n active = false;\n };\n }, [uf]);\n\n useEffect(() => {\n const node = containerRef.current;\n if (!node || typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver((entries) => {\n const measured = entries[0]?.contentRect.width;\n if (measured && measured > 0) setWidth(measured);\n });\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n const selectedSet = useMemo<Set<string>>(() => {\n if (!selected) return new Set();\n return new Set(Array.isArray(selected) ? selected : [selected as string]);\n }, [selected]);\n\n const valueRange = useMemo<[number, number] | null>(() => {\n if (!values) return null;\n const nums = Object.values(values).filter((v): v is number => typeof v === \"number\");\n if (nums.length === 0) return null;\n return [Math.min(...nums), Math.max(...nums)];\n }, [values]);\n\n const shapes = useMemo(() => {\n if (!collection) return null;\n const projection = fitProjection(\n geometriesBounds(collection.features.map((f) => f.geometry)),\n width,\n height,\n { padding },\n );\n const items = collection.features.map((feature) => ({\n id: feature.properties.id,\n name: feature.properties.name,\n d: geometryPath(feature.geometry, projection),\n centroid: geometryCentroid(feature.geometry, projection),\n }));\n return { projection, items };\n }, [collection, width, height, padding]);\n\n function fillFor(id: string, name: string): string | undefined {\n const v = values?.[id] ?? values?.[name];\n if (typeof v !== \"number\") return undefined;\n if (colorScale) return colorScale(v);\n if (!valueRange) return undefined;\n const [min, max] = valueRange;\n const t = max === min ? 1 : (v - min) / (max - min);\n return lerpColor(minColor, maxColor, t);\n }\n\n // Memoized so hover re-renders don't rebuild hundreds of municipality paths.\n const cityEls = useMemo(() => {\n if (!shapes) return null;\n return shapes.items.map((shape) => {\n const isSelected = selectedSet.has(shape.id) || selectedSet.has(shape.name);\n const fillColor = isSelected ? undefined : fillFor(shape.id, shape.name);\n return (\n <path\n key={shape.id}\n className={cn(styles.state, isSelected && styles.selected)}\n d={shape.d}\n fillRule=\"evenodd\"\n style={fillColor ? { fill: fillColor } : undefined}\n data-city-id={shape.id}\n data-city={shape.name}\n tabIndex={onSelect ? 0 : undefined}\n role={onSelect ? \"button\" : undefined}\n aria-label={shape.name}\n aria-pressed={onSelect ? isSelected : undefined}\n onClick={\n onSelect ? () => onSelect({ id: shape.id, name: shape.name }) : undefined\n }\n onMouseMove={\n showTooltip\n ? (e) => onMove({ id: shape.id, name: shape.name }, e)\n : undefined\n }\n onMouseLeave={showTooltip ? onLeave : undefined}\n onKeyDown={\n onSelect\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onSelect({ id: shape.id, name: shape.name });\n }\n }\n : undefined\n }\n />\n );\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n shapes,\n selectedSet,\n values,\n colorScale,\n minColor,\n maxColor,\n onSelect,\n showTooltip,\n onMove,\n onLeave,\n ]);\n\n const resolvedLabel = label ?? `Municípios de ${getState(uf)?.name ?? uf}`;\n\n return (\n <div\n ref={containerRef}\n className={cn(styles.map, className)}\n style={{ height, ...style }}\n role=\"group\"\n aria-label={resolvedLabel}\n {...rest}\n >\n {!shapes ? (\n <div className={styles.loading}>{loadingContent ?? \"Carregando municípios…\"}</div>\n ) : (\n <svg\n className={styles.svg}\n width=\"100%\"\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n preserveAspectRatio=\"xMidYMid meet\"\n {...mapZoom.handlers}\n >\n <g transform={mapZoom.transform || undefined}>\n {cityEls}\n\n {showLabels &&\n shapes.items.map((shape) => (\n <text\n key={`label-${shape.id}`}\n className={styles.label}\n x={shape.centroid.x}\n y={shape.centroid.y}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n >\n {shape.name}\n </text>\n ))}\n\n {markers && markers.length > 0 && (\n <MapMarkers\n projection={shapes.projection}\n markers={markers}\n onMarkerClick={onMarkerClick}\n />\n )}\n </g>\n </svg>\n )}\n\n {mapZoom.isTransformed && (\n <button type=\"button\" className={styles.zoomReset} onClick={mapZoom.reset}>\n Reset\n </button>\n )}\n\n {showTooltip && hover && (\n <MapTooltip x={hover.x} y={hover.y}>\n {renderTooltip ? (\n renderTooltip({\n ...hover.item,\n value: values?.[hover.item.id] ?? values?.[hover.item.name],\n })\n ) : (\n <>\n <div className={styles.tooltipTitle}>{hover.item.name}</div>\n <div className={styles.tooltipMeta}>\n IBGE {hover.item.id}\n {(() => {\n const v = values?.[hover.item.id] ?? values?.[hover.item.name];\n return typeof v === \"number\" ? ` · ${v}` : \"\";\n })()}\n </div>\n </>\n )}\n </MapTooltip>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BrazilStateMap.js","names":[],"sources":["../../src/br/BrazilStateMap.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the municipality-level\n * twin of BrazilMap, prop for prop, plus the `uf` that selects which state's\n * geometry to load. Splitting it differently from BrazilMap would mean two maps with\n * two shapes for the same job.\n */\nimport { useEffect, useMemo, useRef, useState, type HTMLAttributes, type ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { fitProjection } from \"@/geo/projection\";\nimport type { GeoMarker } from \"@/geo/types\";\nimport { getState, type UF } from \"./locations\";\nimport { MapMarkers } from \"./MapMarkers\";\nimport { MapTooltip } from \"./MapTooltip\";\nimport type { ColorScale } from \"./scales\";\nimport { useMapZoom } from \"./use-map-zoom\";\nimport { loadStateMunicipalities, type StateMunicipalities } from \"./state-geo\";\nimport { geometriesBounds, geometryCentroid, geometryPath, lerpColor } from \"./svg-utils\";\nimport { useMapHover } from \"./use-map-hover\";\nimport styles from \"./BrazilMap.module.css\";\n\n/** A municipality identified for selection callbacks. */\nexport interface Municipality {\n /** 7-digit IBGE code. */\n id: string;\n /** Municipality name. */\n name: string;\n}\n\n/** Data passed to a {@link BrazilStateMapProps.renderTooltip} callback. */\nexport interface BrazilStateMapTooltipData extends Municipality {\n /** Choropleth value for this municipality, if `values` was provided. */\n value?: number;\n}\n\nexport interface BrazilStateMapProps extends Omit<HTMLAttributes<HTMLDivElement>, \"onSelect\"> {\n /** Federative unit to draw (required). */\n uf: UF;\n /** Selected municipality — matched by IBGE `id` or by `name`. Accepts many. */\n selected?: string | readonly string[] | null;\n /** Fired when a municipality is clicked. */\n onSelect?: (municipality: Municipality) => void;\n /**\n * Choropleth values keyed by municipality `id` **or** `name`. When set, each\n * municipality is tinted between `minColor` and `maxColor`.\n */\n values?: Record<string, number>;\n /** Choropleth low-end color (2-color linear ramp). Default: a light primary tint. */\n minColor?: string;\n /** Choropleth high-end color (2-color linear ramp). Default: the primary token. */\n maxColor?: string;\n /**\n * Custom value→color scale (from `sequentialScale`/`quantizeScale`). Takes\n * precedence over `minColor`/`maxColor`. Pair with a `<MapLegend>`.\n */\n colorScale?: ColorScale;\n /** Viewport height in pixels. Default: `440`. */\n height?: number;\n /** Inner padding in pixels. Default: `12`. */\n padding?: number;\n /**\n * Render each municipality name at its centroid. Off by default — a state\n * can have hundreds of municipalities and labels overlap badly.\n */\n showLabels?: boolean;\n /** Accessible label. Default: derived from the state name. */\n label?: string;\n /** Content while the state geometry is loading. */\n loadingContent?: ReactNode;\n /** Show a floating tooltip (name + IBGE code + value) on hover. Default: `true`. */\n showTooltip?: boolean;\n /** Override the default tooltip content. */\n renderTooltip?: (data: BrazilStateMapTooltipData) => ReactNode;\n /** Point markers to overlay on the state (e.g. addresses, POIs). */\n markers?: readonly GeoMarker[];\n /** Fired when a marker is clicked. */\n onMarkerClick?: (marker: GeoMarker, index: number) => void;\n /** Enable wheel-zoom + drag-pan (double-click resets). Default: `false`. */\n zoomable?: boolean;\n}\n\n/**\n * Clickable submap of a single Brazilian state showing **all its\n * municipalities** as SVG paths — no external tiles or paid API. The state's\n * geometry (~40-70 KB gzip) is loaded lazily per UF, so switching states fetches\n * only what is shown.\n *\n * @example\n * const [city, setCity] = useState<string | null>(null);\n * <BrazilStateMap uf=\"SP\" selected={city} onSelect={(m) => setCity(m.name)} />\n *\n * @example\n * // Choropleth of a metric by municipality name\n * <BrazilStateMap uf=\"RJ\" values={{ \"Rio de Janeiro\": 100, Niterói: 40 }} />\n */\nexport function BrazilStateMap({\n uf,\n selected,\n onSelect,\n values,\n minColor = \"#dbeafe\",\n maxColor = \"#2563eb\",\n colorScale,\n height = 440,\n padding = 12,\n showLabels = false,\n label,\n loadingContent,\n showTooltip = true,\n renderTooltip,\n markers,\n onMarkerClick,\n zoomable = false,\n className,\n style,\n ...rest\n}: BrazilStateMapProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState<number>(600);\n const [collection, setCollection] = useState<StateMunicipalities | null>(null);\n const mapZoom = useMapZoom(zoomable);\n const { hover, onMove, onLeave } = useMapHover<Municipality>(containerRef);\n\n useEffect(() => {\n let active = true;\n setCollection(null);\n void loadStateMunicipalities(uf).then((data) => {\n if (active) setCollection(data);\n });\n return () => {\n active = false;\n };\n }, [uf]);\n\n useEffect(() => {\n const node = containerRef.current;\n if (!node || typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver((entries) => {\n const measured = entries[0]?.contentRect.width;\n if (measured && measured > 0) setWidth(measured);\n });\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n const selectedSet = useMemo<Set<string>>(() => {\n if (!selected) return new Set();\n return new Set(Array.isArray(selected) ? selected : [selected as string]);\n }, [selected]);\n\n const valueRange = useMemo<[number, number] | null>(() => {\n if (!values) return null;\n const nums = Object.values(values).filter((v): v is number => typeof v === \"number\");\n if (nums.length === 0) return null;\n return [Math.min(...nums), Math.max(...nums)];\n }, [values]);\n\n const shapes = useMemo(() => {\n if (!collection) return null;\n const projection = fitProjection(\n geometriesBounds(collection.features.map((f) => f.geometry)),\n width,\n height,\n { padding },\n );\n const items = collection.features.map((feature) => ({\n id: feature.properties.id,\n name: feature.properties.name,\n d: geometryPath(feature.geometry, projection),\n centroid: geometryCentroid(feature.geometry, projection),\n }));\n return { projection, items };\n }, [collection, width, height, padding]);\n\n function fillFor(id: string, name: string): string | undefined {\n const v = values?.[id] ?? values?.[name];\n if (typeof v !== \"number\") return undefined;\n if (colorScale) return colorScale(v);\n if (!valueRange) return undefined;\n const [min, max] = valueRange;\n const t = max === min ? 1 : (v - min) / (max - min);\n return lerpColor(minColor, maxColor, t);\n }\n\n // Memoized so hover re-renders don't rebuild hundreds of municipality paths.\n const cityEls = useMemo(() => {\n if (!shapes) return null;\n return shapes.items.map((shape) => {\n const isSelected = selectedSet.has(shape.id) || selectedSet.has(shape.name);\n const fillColor = isSelected ? undefined : fillFor(shape.id, shape.name);\n return (\n <path\n key={shape.id}\n className={cn(styles.state, isSelected && styles.selected)}\n d={shape.d}\n fillRule=\"evenodd\"\n style={fillColor ? { fill: fillColor } : undefined}\n data-city-id={shape.id}\n data-city={shape.name}\n tabIndex={onSelect ? 0 : undefined}\n role={onSelect ? \"button\" : undefined}\n aria-label={shape.name}\n aria-pressed={onSelect ? isSelected : undefined}\n onClick={\n onSelect ? () => onSelect({ id: shape.id, name: shape.name }) : undefined\n }\n onMouseMove={\n showTooltip\n ? (e) => onMove({ id: shape.id, name: shape.name }, e)\n : undefined\n }\n onMouseLeave={showTooltip ? onLeave : undefined}\n onKeyDown={\n onSelect\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onSelect({ id: shape.id, name: shape.name });\n }\n }\n : undefined\n }\n />\n );\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n shapes,\n selectedSet,\n values,\n colorScale,\n minColor,\n maxColor,\n onSelect,\n showTooltip,\n onMove,\n onLeave,\n ]);\n\n const resolvedLabel = label ?? `Municípios de ${getState(uf)?.name ?? uf}`;\n\n return (\n <div\n ref={containerRef}\n className={cn(styles.map, className)}\n style={{ height, ...style }}\n role=\"group\"\n aria-label={resolvedLabel}\n {...rest}\n >\n {!shapes ? (\n <div className={styles.loading}>{loadingContent ?? \"Carregando municípios…\"}</div>\n ) : (\n <svg\n className={styles.svg}\n width=\"100%\"\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n preserveAspectRatio=\"xMidYMid meet\"\n {...mapZoom.handlers}\n >\n <g transform={mapZoom.transform || undefined}>\n {cityEls}\n\n {showLabels &&\n shapes.items.map((shape) => (\n <text\n key={`label-${shape.id}`}\n className={styles.label}\n x={shape.centroid.x}\n y={shape.centroid.y}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n >\n {shape.name}\n </text>\n ))}\n\n {markers && markers.length > 0 && (\n <MapMarkers\n projection={shapes.projection}\n markers={markers}\n onMarkerClick={onMarkerClick}\n />\n )}\n </g>\n </svg>\n )}\n\n {mapZoom.isTransformed && (\n <button type=\"button\" className={styles.zoomReset} onClick={mapZoom.reset}>\n Reset\n </button>\n )}\n\n {showTooltip && hover && (\n <MapTooltip x={hover.x} y={hover.y}>\n {renderTooltip ? (\n renderTooltip({\n ...hover.item,\n value: values?.[hover.item.id] ?? values?.[hover.item.name],\n })\n ) : (\n <>\n <div className={styles.tooltipTitle}>{hover.item.name}</div>\n <div className={styles.tooltipMeta}>\n IBGE {hover.item.id}\n {(() => {\n const v = values?.[hover.item.id] ?? values?.[hover.item.name];\n return typeof v === \"number\" ? ` · ${v}` : \"\";\n })()}\n </div>\n </>\n )}\n </MapTooltip>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MapLegend.cjs","names":[],"sources":["../../src/br/MapLegend.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { SEQUENTIAL_BLUES } from \"./scales\";\nimport styles from \"./MapLegend.module.css\";\n\n/** A discrete legend entry. */\nexport interface LegendItem {\n color: string;\n label: ReactNode;\n}\n\nexport interface MapLegendProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Legend heading. */\n title?: ReactNode;\n /**\n * Discrete entries (swatch + label). When provided the legend renders in\n * \"steps\" mode; otherwise it renders a continuous gradient from `min`/`max`.\n */\n items?: readonly LegendItem[];\n /** Continuous mode: low end of the domain. */\n min?: number;\n /** Continuous mode: high end of the domain. */\n max?: number;\n /** Continuous mode: palette (light → dark). Default: sequential blues. */\n palette?: readonly string[];\n /** Continuous mode: format the min/mid/max tick labels. */\n format?: (value: number) => string;\n}\n\n/**\n * Legend for a choropleth map. Renders a **continuous gradient** (with\n * min/mid/max ticks) from `min`/`max`/`palette`, or **discrete swatches** when\n * `items` is given. Pair it with a `BrazilMap`/`BrazilStateMap` `colorScale`.\n *\n * @example\n * // Continuous, matching a sequentialScale(0, 100)\n * <MapLegend title=\"Vendas\" min={0} max={100} palette={SEQUENTIAL_BLUES} />\n *\n * @example\n * // Discrete buckets\n * <MapLegend\n * title=\"Faixa\"\n * items={[\n * { color: \"#c6dbef\", label: \"< 10\" },\n * { color: \"#6baed6\", label: \"10–50\" },\n * { color: \"#08519c\", label: \"> 50\" },\n * ]}\n * />\n */\nexport function MapLegend({\n title,\n items,\n min = 0,\n max = 1,\n palette = SEQUENTIAL_BLUES,\n format = (v) => String(Math.round(v)),\n className,\n ...rest\n}: MapLegendProps) {\n return (\n <div className={cn(styles.legend, className)} {...rest}>\n {title != null && <div className={styles.title}>{title}</div>}\n\n {items ? (\n <ul className={styles.items}>\n {items.map((item, i) => (\n <li key={i} className={styles.item}>\n <span className={styles.swatch} style={{ background: item.color }} />\n <span className={styles.itemLabel}>{item.label}</span>\n </li>\n ))}\n </ul>\n ) : (\n <>\n <div\n className={styles.gradient}\n style={{ background: `linear-gradient(to right, ${palette.join(\", \")})` }}\n />\n <div className={styles.ticks}>\n <span>{format(min)}</span>\n <span>{format((min + max) / 2)}</span>\n <span>{format(max)}</span>\n </div>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"oIAiDA,SAAgB,EAAU,CACtB,QACA,QACA,MAAM,EACN,MAAM,EACN,UAAU,EAAA,iBACV,SAAU,GAAM,OAAO,KAAK,MAAM,CAAC,CAAC,EACpC,YACA,GAAG,GACY,CACf,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,OAAQ,CAAS,EAAG,GAAI,
|
|
1
|
+
{"version":3,"file":"MapLegend.cjs","names":[],"sources":["../../src/br/MapLegend.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { SEQUENTIAL_BLUES } from \"./scales\";\nimport styles from \"./MapLegend.module.css\";\n\n/** A discrete legend entry. */\nexport interface LegendItem {\n color: string;\n label: ReactNode;\n}\n\nexport interface MapLegendProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Legend heading. */\n title?: ReactNode;\n /**\n * Discrete entries (swatch + label). When provided the legend renders in\n * \"steps\" mode; otherwise it renders a continuous gradient from `min`/`max`.\n */\n items?: readonly LegendItem[];\n /** Continuous mode: low end of the domain. */\n min?: number;\n /** Continuous mode: high end of the domain. */\n max?: number;\n /** Continuous mode: palette (light → dark). Default: sequential blues. */\n palette?: readonly string[];\n /** Continuous mode: format the min/mid/max tick labels. */\n format?: (value: number) => string;\n}\n\n/**\n * Legend for a choropleth map. Renders a **continuous gradient** (with\n * min/mid/max ticks) from `min`/`max`/`palette`, or **discrete swatches** when\n * `items` is given. Pair it with a `BrazilMap`/`BrazilStateMap` `colorScale`.\n *\n * @example\n * // Continuous, matching a sequentialScale(0, 100)\n * <MapLegend title=\"Vendas\" min={0} max={100} palette={SEQUENTIAL_BLUES} />\n *\n * @example\n * // Discrete buckets\n * <MapLegend\n * title=\"Faixa\"\n * items={[\n * { color: \"#c6dbef\", label: \"< 10\" },\n * { color: \"#6baed6\", label: \"10–50\" },\n * { color: \"#08519c\", label: \"> 50\" },\n * ]}\n * />\n */\nexport function MapLegend({\n title,\n items,\n min = 0,\n max = 1,\n palette = SEQUENTIAL_BLUES,\n format = (v) => String(Math.round(v)),\n className,\n ...rest\n}: MapLegendProps) {\n return (\n <div className={cn(styles.legend, className)} {...rest}>\n {title != null && <div className={styles.title}>{title}</div>}\n\n {items ? (\n <ul className={styles.items}>\n {items.map((item, i) => (\n <li key={i} className={styles.item}>\n <span className={styles.swatch} style={{ background: item.color }} />\n <span className={styles.itemLabel}>{item.label}</span>\n </li>\n ))}\n </ul>\n ) : (\n <>\n <div\n className={styles.gradient}\n style={{ background: `linear-gradient(to right, ${palette.join(\", \")})` }}\n />\n <div className={styles.ticks}>\n <span>{format(min)}</span>\n <span>{format((min + max) / 2)}</span>\n <span>{format(max)}</span>\n </div>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"oIAiDA,SAAgB,EAAU,CACtB,QACA,QACA,MAAM,EACN,MAAM,EACN,UAAU,EAAA,iBACV,SAAU,GAAM,OAAO,KAAK,MAAM,CAAC,CAAC,EACpC,YACA,GAAG,GACY,CACf,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,OAAQ,CAAS,EAAG,GAAI,EAAlD,SAAA,CACK,GAAS,OAAQ,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,MAAQ,SAAA,CAAW,CAAA,EAE3D,GACG,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,MACjB,SAAA,EAAM,KAAK,EAAM,KACd,EAAA,EAAA,KAAA,CAAC,KAAD,CAAY,UAAW,EAAA,QAAO,KAA9B,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,OAAQ,MAAO,CAAE,WAAY,EAAK,KAAM,CAAI,CAAA,GACpE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,UAAY,SAAA,EAAK,KAAY,CAAA,CACrD,CAHK,EAAA,CAGL,CACP,CACD,CAAA,GAEJ,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,QAAO,SAClB,MAAO,CAAE,WAAY,6BAA6B,EAAQ,KAAK,IAAI,EAAE,EAAG,CAC3E,CAAA,GACD,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,MAAvB,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAA,SAAO,EAAO,CAAG,CAAQ,CAAA,GACzB,EAAA,EAAA,IAAA,CAAC,OAAD,CAAA,SAAO,GAAQ,EAAM,GAAO,CAAC,CAAQ,CAAA,GACrC,EAAA,EAAA,IAAA,CAAC,OAAD,CAAA,SAAO,EAAO,CAAG,CAAQ,CAAA,CACxB,CACP,CAAA,CAAA,CAAA,CAAA,CAEL,GAEb"}
|
package/dist/br/MapLegend.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MapLegend.js","names":[],"sources":["../../src/br/MapLegend.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { SEQUENTIAL_BLUES } from \"./scales\";\nimport styles from \"./MapLegend.module.css\";\n\n/** A discrete legend entry. */\nexport interface LegendItem {\n color: string;\n label: ReactNode;\n}\n\nexport interface MapLegendProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Legend heading. */\n title?: ReactNode;\n /**\n * Discrete entries (swatch + label). When provided the legend renders in\n * \"steps\" mode; otherwise it renders a continuous gradient from `min`/`max`.\n */\n items?: readonly LegendItem[];\n /** Continuous mode: low end of the domain. */\n min?: number;\n /** Continuous mode: high end of the domain. */\n max?: number;\n /** Continuous mode: palette (light → dark). Default: sequential blues. */\n palette?: readonly string[];\n /** Continuous mode: format the min/mid/max tick labels. */\n format?: (value: number) => string;\n}\n\n/**\n * Legend for a choropleth map. Renders a **continuous gradient** (with\n * min/mid/max ticks) from `min`/`max`/`palette`, or **discrete swatches** when\n * `items` is given. Pair it with a `BrazilMap`/`BrazilStateMap` `colorScale`.\n *\n * @example\n * // Continuous, matching a sequentialScale(0, 100)\n * <MapLegend title=\"Vendas\" min={0} max={100} palette={SEQUENTIAL_BLUES} />\n *\n * @example\n * // Discrete buckets\n * <MapLegend\n * title=\"Faixa\"\n * items={[\n * { color: \"#c6dbef\", label: \"< 10\" },\n * { color: \"#6baed6\", label: \"10–50\" },\n * { color: \"#08519c\", label: \"> 50\" },\n * ]}\n * />\n */\nexport function MapLegend({\n title,\n items,\n min = 0,\n max = 1,\n palette = SEQUENTIAL_BLUES,\n format = (v) => String(Math.round(v)),\n className,\n ...rest\n}: MapLegendProps) {\n return (\n <div className={cn(styles.legend, className)} {...rest}>\n {title != null && <div className={styles.title}>{title}</div>}\n\n {items ? (\n <ul className={styles.items}>\n {items.map((item, i) => (\n <li key={i} className={styles.item}>\n <span className={styles.swatch} style={{ background: item.color }} />\n <span className={styles.itemLabel}>{item.label}</span>\n </li>\n ))}\n </ul>\n ) : (\n <>\n <div\n className={styles.gradient}\n style={{ background: `linear-gradient(to right, ${palette.join(\", \")})` }}\n />\n <div className={styles.ticks}>\n <span>{format(min)}</span>\n <span>{format((min + max) / 2)}</span>\n <span>{format(max)}</span>\n </div>\n </>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AAiDA,SAAgB,EAAU,EACtB,UACA,UACA,SAAM,GACN,SAAM,GACN,aAAU,GACV,aAAU,MAAM,OAAO,KAAK,MAAM,CAAC,CAAC,GACpC,cACA,GAAG,KACY;CACf,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,QAAQ,CAAS;EAAG,GAAI;
|
|
1
|
+
{"version":3,"file":"MapLegend.js","names":[],"sources":["../../src/br/MapLegend.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { SEQUENTIAL_BLUES } from \"./scales\";\nimport styles from \"./MapLegend.module.css\";\n\n/** A discrete legend entry. */\nexport interface LegendItem {\n color: string;\n label: ReactNode;\n}\n\nexport interface MapLegendProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Legend heading. */\n title?: ReactNode;\n /**\n * Discrete entries (swatch + label). When provided the legend renders in\n * \"steps\" mode; otherwise it renders a continuous gradient from `min`/`max`.\n */\n items?: readonly LegendItem[];\n /** Continuous mode: low end of the domain. */\n min?: number;\n /** Continuous mode: high end of the domain. */\n max?: number;\n /** Continuous mode: palette (light → dark). Default: sequential blues. */\n palette?: readonly string[];\n /** Continuous mode: format the min/mid/max tick labels. */\n format?: (value: number) => string;\n}\n\n/**\n * Legend for a choropleth map. Renders a **continuous gradient** (with\n * min/mid/max ticks) from `min`/`max`/`palette`, or **discrete swatches** when\n * `items` is given. Pair it with a `BrazilMap`/`BrazilStateMap` `colorScale`.\n *\n * @example\n * // Continuous, matching a sequentialScale(0, 100)\n * <MapLegend title=\"Vendas\" min={0} max={100} palette={SEQUENTIAL_BLUES} />\n *\n * @example\n * // Discrete buckets\n * <MapLegend\n * title=\"Faixa\"\n * items={[\n * { color: \"#c6dbef\", label: \"< 10\" },\n * { color: \"#6baed6\", label: \"10–50\" },\n * { color: \"#08519c\", label: \"> 50\" },\n * ]}\n * />\n */\nexport function MapLegend({\n title,\n items,\n min = 0,\n max = 1,\n palette = SEQUENTIAL_BLUES,\n format = (v) => String(Math.round(v)),\n className,\n ...rest\n}: MapLegendProps) {\n return (\n <div className={cn(styles.legend, className)} {...rest}>\n {title != null && <div className={styles.title}>{title}</div>}\n\n {items ? (\n <ul className={styles.items}>\n {items.map((item, i) => (\n <li key={i} className={styles.item}>\n <span className={styles.swatch} style={{ background: item.color }} />\n <span className={styles.itemLabel}>{item.label}</span>\n </li>\n ))}\n </ul>\n ) : (\n <>\n <div\n className={styles.gradient}\n style={{ background: `linear-gradient(to right, ${palette.join(\", \")})` }}\n />\n <div className={styles.ticks}>\n <span>{format(min)}</span>\n <span>{format((min + max) / 2)}</span>\n <span>{format(max)}</span>\n </div>\n </>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AAiDA,SAAgB,EAAU,EACtB,UACA,UACA,SAAM,GACN,SAAM,GACN,aAAU,GACV,aAAU,MAAM,OAAO,KAAK,MAAM,CAAC,CAAC,GACpC,cACA,GAAG,KACY;CACf,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,QAAQ,CAAS;EAAG,GAAI;EAAlD,UAAA,CACK,KAAS,QAAQ,kBAAC,OAAD;GAAK,WAAW,EAAO;GAAQ,UAAA;EAAW,CAAA,GAE3D,IACG,kBAAC,MAAD;GAAI,WAAW,EAAO;GACjB,UAAA,EAAM,KAAK,GAAM,MACd,kBAAC,MAAD;IAAY,WAAW,EAAO;IAA9B,UAAA,CACI,kBAAC,QAAD;KAAM,WAAW,EAAO;KAAQ,OAAO,EAAE,YAAY,EAAK,MAAM;IAAI,CAAA,GACpE,kBAAC,QAAD;KAAM,WAAW,EAAO;KAAY,UAAA,EAAK;IAAY,CAAA,CACrD;GAHK,GAAA,CAGL,CACP;EACD,CAAA,IAEJ,kBAAA,GAAA,EAAA,UAAA,CACI,kBAAC,OAAD;GACI,WAAW,EAAO;GAClB,OAAO,EAAE,YAAY,6BAA6B,EAAQ,KAAK,IAAI,EAAE,GAAG;EAC3E,CAAA,GACD,kBAAC,OAAD;GAAK,WAAW,EAAO;GAAvB,UAAA;IACI,kBAAC,QAAD,EAAA,UAAO,EAAO,CAAG,EAAQ,CAAA;IACzB,kBAAC,QAAD,EAAA,UAAO,GAAQ,IAAM,KAAO,CAAC,EAAQ,CAAA;IACrC,kBAAC,QAAD,EAAA,UAAO,EAAO,CAAG,EAAQ,CAAA;GACxB;EACP,CAAA,CAAA,EAAA,CAAA,CAEL;;AAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MapMarkers.cjs","names":[],"sources":["../../src/br/MapMarkers.tsx"],"sourcesContent":["import type { FittedProjection } from \"@/geo/projection\";\nimport type { GeoMarker } from \"@/geo/types\";\nimport styles from \"./BrazilMap.module.css\";\n\nexport interface MapMarkersProps {\n /** Projection used by the host map (markers must share it to line up). */\n projection: FittedProjection;\n /** Pins to plot. */\n markers: readonly GeoMarker[];\n /** Fired when a marker is clicked. */\n onMarkerClick?: (marker: GeoMarker, index: number) => void;\n}\n\n/**\n * SVG overlay of point markers, projected with the host map's projection so\n * they align with its shapes. Each marker carries a native `<title>` (its\n * `label`) and is clickable when `onMarkerClick` is set.\n */\nexport function MapMarkers({ projection, markers, onMarkerClick }: MapMarkersProps) {\n return (\n <g className={styles.markers}>\n {markers.map((marker, index) => {\n const p = projection.project(marker);\n const interactive = Boolean(onMarkerClick);\n return (\n <circle\n key={marker.id ?? index}\n className={styles.marker}\n cx={p.x}\n cy={p.y}\n r={marker.radius ?? 6}\n fill={marker.color ?? \"var(--tempest-primary)\"}\n data-marker-id={marker.id ?? index}\n tabIndex={interactive ? 0 : undefined}\n role={interactive ? \"button\" : undefined}\n aria-label={marker.label}\n onClick={interactive ? () => onMarkerClick?.(marker, index) : undefined}\n onKeyDown={\n interactive\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onMarkerClick?.(marker, index);\n }\n }\n : undefined\n }\n >\n {marker.label ? <title>{marker.label}</title> : null}\n </circle>\n );\n })}\n </g>\n );\n}\n"],"mappings":"6EAkBA,SAAgB,EAAW,CAAE,aAAY,UAAS,iBAAkC,CAChF,OACI,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAA,QAAO,
|
|
1
|
+
{"version":3,"file":"MapMarkers.cjs","names":[],"sources":["../../src/br/MapMarkers.tsx"],"sourcesContent":["import type { FittedProjection } from \"@/geo/projection\";\nimport type { GeoMarker } from \"@/geo/types\";\nimport styles from \"./BrazilMap.module.css\";\n\nexport interface MapMarkersProps {\n /** Projection used by the host map (markers must share it to line up). */\n projection: FittedProjection;\n /** Pins to plot. */\n markers: readonly GeoMarker[];\n /** Fired when a marker is clicked. */\n onMarkerClick?: (marker: GeoMarker, index: number) => void;\n}\n\n/**\n * SVG overlay of point markers, projected with the host map's projection so\n * they align with its shapes. Each marker carries a native `<title>` (its\n * `label`) and is clickable when `onMarkerClick` is set.\n */\nexport function MapMarkers({ projection, markers, onMarkerClick }: MapMarkersProps) {\n return (\n <g className={styles.markers}>\n {markers.map((marker, index) => {\n const p = projection.project(marker);\n const interactive = Boolean(onMarkerClick);\n return (\n <circle\n key={marker.id ?? index}\n className={styles.marker}\n cx={p.x}\n cy={p.y}\n r={marker.radius ?? 6}\n fill={marker.color ?? \"var(--tempest-primary)\"}\n data-marker-id={marker.id ?? index}\n tabIndex={interactive ? 0 : undefined}\n role={interactive ? \"button\" : undefined}\n aria-label={marker.label}\n onClick={interactive ? () => onMarkerClick?.(marker, index) : undefined}\n onKeyDown={\n interactive\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onMarkerClick?.(marker, index);\n }\n }\n : undefined\n }\n >\n {marker.label ? <title>{marker.label}</title> : null}\n </circle>\n );\n })}\n </g>\n );\n}\n"],"mappings":"6EAkBA,SAAgB,EAAW,CAAE,aAAY,UAAS,iBAAkC,CAChF,OACI,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAA,QAAO,QAChB,SAAA,EAAQ,KAAK,EAAQ,IAAU,CAC5B,IAAM,EAAI,EAAW,QAAQ,CAAM,EAC7B,EAAc,EAAQ,EAC5B,OACI,EAAA,EAAA,IAAA,CAAC,SAAD,CAEI,UAAW,EAAA,QAAO,OAClB,GAAI,EAAE,EACN,GAAI,EAAE,EACN,EAAG,EAAO,QAAU,EACpB,KAAM,EAAO,OAAS,yBACtB,iBAAgB,EAAO,IAAM,EAC7B,SAAU,EAAc,EAAI,IAAA,GAC5B,KAAM,EAAc,SAAW,IAAA,GAC/B,aAAY,EAAO,MACnB,QAAS,MAAoB,IAAgB,EAAQ,CAAK,EAAI,IAAA,GAC9D,UACI,EACO,GAAM,EACC,EAAE,MAAQ,SAAW,EAAE,MAAQ,OAC/B,EAAE,eAAe,EACjB,IAAgB,EAAQ,CAAK,EAErC,EACA,IAAA,GAGT,SAAA,EAAO,OAAQ,EAAA,EAAA,IAAA,CAAC,QAAD,CAAA,SAAQ,EAAO,KAAa,CAAA,EAAI,IAC5C,EAvBC,EAAO,IAAM,CAuBd,CAEhB,CAAC,CACF,CAAA,CAEX"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MapMarkers.js","names":[],"sources":["../../src/br/MapMarkers.tsx"],"sourcesContent":["import type { FittedProjection } from \"@/geo/projection\";\nimport type { GeoMarker } from \"@/geo/types\";\nimport styles from \"./BrazilMap.module.css\";\n\nexport interface MapMarkersProps {\n /** Projection used by the host map (markers must share it to line up). */\n projection: FittedProjection;\n /** Pins to plot. */\n markers: readonly GeoMarker[];\n /** Fired when a marker is clicked. */\n onMarkerClick?: (marker: GeoMarker, index: number) => void;\n}\n\n/**\n * SVG overlay of point markers, projected with the host map's projection so\n * they align with its shapes. Each marker carries a native `<title>` (its\n * `label`) and is clickable when `onMarkerClick` is set.\n */\nexport function MapMarkers({ projection, markers, onMarkerClick }: MapMarkersProps) {\n return (\n <g className={styles.markers}>\n {markers.map((marker, index) => {\n const p = projection.project(marker);\n const interactive = Boolean(onMarkerClick);\n return (\n <circle\n key={marker.id ?? index}\n className={styles.marker}\n cx={p.x}\n cy={p.y}\n r={marker.radius ?? 6}\n fill={marker.color ?? \"var(--tempest-primary)\"}\n data-marker-id={marker.id ?? index}\n tabIndex={interactive ? 0 : undefined}\n role={interactive ? \"button\" : undefined}\n aria-label={marker.label}\n onClick={interactive ? () => onMarkerClick?.(marker, index) : undefined}\n onKeyDown={\n interactive\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onMarkerClick?.(marker, index);\n }\n }\n : undefined\n }\n >\n {marker.label ? <title>{marker.label}</title> : null}\n </circle>\n );\n })}\n </g>\n );\n}\n"],"mappings":";;;AAkBA,SAAgB,EAAW,EAAE,eAAY,YAAS,oBAAkC;CAChF,OACI,kBAAC,KAAD;EAAG,WAAW,EAAO;
|
|
1
|
+
{"version":3,"file":"MapMarkers.js","names":[],"sources":["../../src/br/MapMarkers.tsx"],"sourcesContent":["import type { FittedProjection } from \"@/geo/projection\";\nimport type { GeoMarker } from \"@/geo/types\";\nimport styles from \"./BrazilMap.module.css\";\n\nexport interface MapMarkersProps {\n /** Projection used by the host map (markers must share it to line up). */\n projection: FittedProjection;\n /** Pins to plot. */\n markers: readonly GeoMarker[];\n /** Fired when a marker is clicked. */\n onMarkerClick?: (marker: GeoMarker, index: number) => void;\n}\n\n/**\n * SVG overlay of point markers, projected with the host map's projection so\n * they align with its shapes. Each marker carries a native `<title>` (its\n * `label`) and is clickable when `onMarkerClick` is set.\n */\nexport function MapMarkers({ projection, markers, onMarkerClick }: MapMarkersProps) {\n return (\n <g className={styles.markers}>\n {markers.map((marker, index) => {\n const p = projection.project(marker);\n const interactive = Boolean(onMarkerClick);\n return (\n <circle\n key={marker.id ?? index}\n className={styles.marker}\n cx={p.x}\n cy={p.y}\n r={marker.radius ?? 6}\n fill={marker.color ?? \"var(--tempest-primary)\"}\n data-marker-id={marker.id ?? index}\n tabIndex={interactive ? 0 : undefined}\n role={interactive ? \"button\" : undefined}\n aria-label={marker.label}\n onClick={interactive ? () => onMarkerClick?.(marker, index) : undefined}\n onKeyDown={\n interactive\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onMarkerClick?.(marker, index);\n }\n }\n : undefined\n }\n >\n {marker.label ? <title>{marker.label}</title> : null}\n </circle>\n );\n })}\n </g>\n );\n}\n"],"mappings":";;;AAkBA,SAAgB,EAAW,EAAE,eAAY,YAAS,oBAAkC;CAChF,OACI,kBAAC,KAAD;EAAG,WAAW,EAAO;EAChB,UAAA,EAAQ,KAAK,GAAQ,MAAU;GAC5B,IAAM,IAAI,EAAW,QAAQ,CAAM,GAC7B,IAAc,EAAQ;GAC5B,OACI,kBAAC,UAAD;IAEI,WAAW,EAAO;IAClB,IAAI,EAAE;IACN,IAAI,EAAE;IACN,GAAG,EAAO,UAAU;IACpB,MAAM,EAAO,SAAS;IACtB,kBAAgB,EAAO,MAAM;IAC7B,UAAU,IAAc,IAAI,KAAA;IAC5B,MAAM,IAAc,WAAW,KAAA;IAC/B,cAAY,EAAO;IACnB,SAAS,UAAoB,IAAgB,GAAQ,CAAK,IAAI,KAAA;IAC9D,WACI,KACO,MAAM;KACH,CAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SAC/B,EAAE,eAAe,GACjB,IAAgB,GAAQ,CAAK;IAErC,IACA,KAAA;IAGT,UAAA,EAAO,QAAQ,kBAAC,SAAD,EAAA,UAAQ,EAAO,MAAa,CAAA,IAAI;GAC5C,GAvBC,EAAO,MAAM,CAuBd;EAEhB,CAAC;CACF,CAAA;AAEX"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MunicipalitySearch.cjs","names":[],"sources":["../../src/br/MunicipalitySearch.tsx"],"sourcesContent":["import { useEffect, useId, useRef, useState, type ReactElement } from \"react\";\nimport { Input } from \"@/components/Input\";\nimport { useDebounce } from \"@/hooks\";\nimport { searchMunicipalities, type MunicipalityCentroid } from \"./geocode\";\nimport type { UF } from \"./locations\";\nimport styles from \"./MunicipalitySearch.module.css\";\n\nexport interface MunicipalitySearchProps {\n /** Restrict the search to a single UF. */\n uf?: UF;\n /** Fired when a municipality is picked from the results. */\n onSelect: (municipality: MunicipalityCentroid) => void;\n /** Field label. */\n label?: string;\n /** Input placeholder. Default: `\"Buscar município…\"`. */\n placeholder?: string;\n /** Max results shown. Default: `8`. */\n limit?: number;\n /** Debounce in ms before searching. Default: `250`. */\n debounceMs?: number;\n /** Disable the field. */\n disabled?: boolean;\n}\n\n/**\n * Debounced municipality autocomplete backed by the offline\n * {@link searchMunicipalities} index — no network. Type a partial name, pick a\n * result, and `onSelect` fires with its `{ id, name, uf, latitude, longitude }`.\n * Wire `onSelect` to a `BrazilStateMap` `selected` to highlight it on the map.\n *\n * @example\n * const [uf, setUf] = useState<UF>(\"SP\");\n * const [city, setCity] = useState<string | null>(null);\n * <MunicipalitySearch uf={uf} onSelect={(m) => setCity(m.name)} />\n * <BrazilStateMap uf={uf} selected={city} />\n */\nexport function MunicipalitySearch({\n uf,\n onSelect,\n label,\n placeholder = \"Buscar município…\",\n limit = 8,\n debounceMs = 250,\n disabled = false,\n}: MunicipalitySearchProps): ReactElement {\n const [query, setQuery] = useState<string>(\"\");\n const [results, setResults] = useState<MunicipalityCentroid[]>([]);\n const [open, setOpen] = useState<boolean>(false);\n const debounced = useDebounce(query, debounceMs);\n const listId = useId();\n const blurTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n let active = true;\n if (!debounced.trim()) {\n setResults([]);\n return;\n }\n void searchMunicipalities(debounced, { uf, limit }).then((hits) => {\n if (active) setResults(hits);\n });\n return () => {\n active = false;\n };\n }, [debounced, uf, limit]);\n\n function choose(municipality: MunicipalityCentroid): void {\n onSelect(municipality);\n setQuery(municipality.name);\n setOpen(false);\n }\n\n return (\n <div className={styles.search}>\n <Input\n label={label}\n value={query}\n placeholder={placeholder}\n disabled={disabled}\n role=\"combobox\"\n aria-expanded={open && results.length > 0}\n aria-controls={listId}\n autoComplete=\"off\"\n onChange={(e) => {\n setQuery(e.target.value);\n setOpen(true);\n }}\n onFocus={() => setOpen(true)}\n onBlur={() => {\n // Delay so a result click registers before the list closes.\n blurTimer.current = setTimeout(() => setOpen(false), 120);\n }}\n />\n {open && results.length > 0 && (\n <ul id={listId} className={styles.results} role=\"listbox\">\n {results.map((m) => (\n <li key={m.id}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={false}\n className={styles.result}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => {\n if (blurTimer.current) clearTimeout(blurTimer.current);\n choose(m);\n }}\n >\n <span>{m.name}</span>\n <span className={styles.uf}>{m.uf}</span>\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":"sNAoCA,SAAgB,EAAmB,CAC/B,KACA,WACA,QACA,cAAc,oBACd,QAAQ,EACR,aAAa,IACb,WAAW,IAC2B,CACtC,GAAM,CAAC,EAAO,IAAA,
|
|
1
|
+
{"version":3,"file":"MunicipalitySearch.cjs","names":[],"sources":["../../src/br/MunicipalitySearch.tsx"],"sourcesContent":["import { useEffect, useId, useRef, useState, type ReactElement } from \"react\";\nimport { Input } from \"@/components/Input\";\nimport { useDebounce } from \"@/hooks\";\nimport { searchMunicipalities, type MunicipalityCentroid } from \"./geocode\";\nimport type { UF } from \"./locations\";\nimport styles from \"./MunicipalitySearch.module.css\";\n\nexport interface MunicipalitySearchProps {\n /** Restrict the search to a single UF. */\n uf?: UF;\n /** Fired when a municipality is picked from the results. */\n onSelect: (municipality: MunicipalityCentroid) => void;\n /** Field label. */\n label?: string;\n /** Input placeholder. Default: `\"Buscar município…\"`. */\n placeholder?: string;\n /** Max results shown. Default: `8`. */\n limit?: number;\n /** Debounce in ms before searching. Default: `250`. */\n debounceMs?: number;\n /** Disable the field. */\n disabled?: boolean;\n}\n\n/**\n * Debounced municipality autocomplete backed by the offline\n * {@link searchMunicipalities} index — no network. Type a partial name, pick a\n * result, and `onSelect` fires with its `{ id, name, uf, latitude, longitude }`.\n * Wire `onSelect` to a `BrazilStateMap` `selected` to highlight it on the map.\n *\n * @example\n * const [uf, setUf] = useState<UF>(\"SP\");\n * const [city, setCity] = useState<string | null>(null);\n * <MunicipalitySearch uf={uf} onSelect={(m) => setCity(m.name)} />\n * <BrazilStateMap uf={uf} selected={city} />\n */\nexport function MunicipalitySearch({\n uf,\n onSelect,\n label,\n placeholder = \"Buscar município…\",\n limit = 8,\n debounceMs = 250,\n disabled = false,\n}: MunicipalitySearchProps): ReactElement {\n const [query, setQuery] = useState<string>(\"\");\n const [results, setResults] = useState<MunicipalityCentroid[]>([]);\n const [open, setOpen] = useState<boolean>(false);\n const debounced = useDebounce(query, debounceMs);\n const listId = useId();\n const blurTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n let active = true;\n if (!debounced.trim()) {\n setResults([]);\n return;\n }\n void searchMunicipalities(debounced, { uf, limit }).then((hits) => {\n if (active) setResults(hits);\n });\n return () => {\n active = false;\n };\n }, [debounced, uf, limit]);\n\n function choose(municipality: MunicipalityCentroid): void {\n onSelect(municipality);\n setQuery(municipality.name);\n setOpen(false);\n }\n\n return (\n <div className={styles.search}>\n <Input\n label={label}\n value={query}\n placeholder={placeholder}\n disabled={disabled}\n role=\"combobox\"\n aria-expanded={open && results.length > 0}\n aria-controls={listId}\n autoComplete=\"off\"\n onChange={(e) => {\n setQuery(e.target.value);\n setOpen(true);\n }}\n onFocus={() => setOpen(true)}\n onBlur={() => {\n // Delay so a result click registers before the list closes.\n blurTimer.current = setTimeout(() => setOpen(false), 120);\n }}\n />\n {open && results.length > 0 && (\n <ul id={listId} className={styles.results} role=\"listbox\">\n {results.map((m) => (\n <li key={m.id}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={false}\n className={styles.result}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => {\n if (blurTimer.current) clearTimeout(blurTimer.current);\n choose(m);\n }}\n >\n <span>{m.name}</span>\n <span className={styles.uf}>{m.uf}</span>\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":"sNAoCA,SAAgB,EAAmB,CAC/B,KACA,WACA,QACA,cAAc,oBACd,QAAQ,EACR,aAAa,IACb,WAAW,IAC2B,CACtC,GAAM,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAiB,EAAE,EACvC,CAAC,EAAS,IAAA,EAAc,EAAA,SAAA,CAAiC,CAAC,CAAC,EAC3D,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,CAAkB,EAAK,EACzC,EAAY,EAAA,YAAY,EAAO,CAAU,EACzC,GAAA,EAAS,EAAA,MAAA,CAAM,EACf,GAAA,EAAY,EAAA,OAAA,CAA6C,IAAI,GAEnE,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAI,EAAS,GACb,GAAI,CAAC,EAAU,KAAK,EAAG,CACnB,EAAW,CAAC,CAAC,EACb,MACJ,CAIA,OAHA,EAAK,qBAAqB,EAAW,CAAE,KAAI,OAAM,CAAC,CAAC,CAAC,KAAM,GAAS,CAC3D,GAAQ,EAAW,CAAI,CAC/B,CAAC,MACY,CACT,EAAS,EACb,CACJ,EAAG,CAAC,EAAW,EAAI,CAAK,CAAC,EAEzB,SAAS,EAAO,EAA0C,CACtD,EAAS,CAAY,EACrB,EAAS,EAAa,IAAI,EAC1B,EAAQ,EAAK,CACjB,CAEA,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,OAAvB,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,EAAA,MAAD,CACW,QACP,MAAO,EACM,cACH,WACV,KAAK,WACL,gBAAe,GAAQ,EAAQ,OAAS,EACxC,gBAAe,EACf,aAAa,MACb,SAAW,GAAM,CACb,EAAS,EAAE,OAAO,KAAK,EACvB,EAAQ,EAAI,CAChB,EACA,YAAe,EAAQ,EAAI,EAC3B,WAAc,CAEV,EAAU,QAAU,eAAiB,EAAQ,EAAK,EAAG,GAAG,CAC5D,CACH,CAAA,EACA,GAAQ,EAAQ,OAAS,IACtB,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,GAAI,EAAQ,UAAW,EAAA,QAAO,QAAS,KAAK,UAC3C,SAAA,EAAQ,IAAK,IACV,EAAA,EAAA,IAAA,CAAC,KAAD,CAAA,UACI,EAAA,EAAA,KAAA,CAAC,SAAD,CACI,KAAK,SACL,KAAK,SACL,gBAAe,GACf,UAAW,EAAA,QAAO,OAClB,YAAc,GAAM,EAAE,eAAe,EACrC,YAAe,CACP,EAAU,SAAS,aAAa,EAAU,OAAO,EACrD,EAAO,CAAC,CACZ,EATJ,SAAA,EAWI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAA,SAAO,EAAE,IAAW,CAAA,GACpB,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,GAAK,SAAA,EAAE,EAAS,CAAA,CACpC,CACR,CAAA,CAAA,EAfK,EAAE,EAeP,CACP,CACD,CAAA,CAEP,GAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MunicipalitySearch.js","names":[],"sources":["../../src/br/MunicipalitySearch.tsx"],"sourcesContent":["import { useEffect, useId, useRef, useState, type ReactElement } from \"react\";\nimport { Input } from \"@/components/Input\";\nimport { useDebounce } from \"@/hooks\";\nimport { searchMunicipalities, type MunicipalityCentroid } from \"./geocode\";\nimport type { UF } from \"./locations\";\nimport styles from \"./MunicipalitySearch.module.css\";\n\nexport interface MunicipalitySearchProps {\n /** Restrict the search to a single UF. */\n uf?: UF;\n /** Fired when a municipality is picked from the results. */\n onSelect: (municipality: MunicipalityCentroid) => void;\n /** Field label. */\n label?: string;\n /** Input placeholder. Default: `\"Buscar município…\"`. */\n placeholder?: string;\n /** Max results shown. Default: `8`. */\n limit?: number;\n /** Debounce in ms before searching. Default: `250`. */\n debounceMs?: number;\n /** Disable the field. */\n disabled?: boolean;\n}\n\n/**\n * Debounced municipality autocomplete backed by the offline\n * {@link searchMunicipalities} index — no network. Type a partial name, pick a\n * result, and `onSelect` fires with its `{ id, name, uf, latitude, longitude }`.\n * Wire `onSelect` to a `BrazilStateMap` `selected` to highlight it on the map.\n *\n * @example\n * const [uf, setUf] = useState<UF>(\"SP\");\n * const [city, setCity] = useState<string | null>(null);\n * <MunicipalitySearch uf={uf} onSelect={(m) => setCity(m.name)} />\n * <BrazilStateMap uf={uf} selected={city} />\n */\nexport function MunicipalitySearch({\n uf,\n onSelect,\n label,\n placeholder = \"Buscar município…\",\n limit = 8,\n debounceMs = 250,\n disabled = false,\n}: MunicipalitySearchProps): ReactElement {\n const [query, setQuery] = useState<string>(\"\");\n const [results, setResults] = useState<MunicipalityCentroid[]>([]);\n const [open, setOpen] = useState<boolean>(false);\n const debounced = useDebounce(query, debounceMs);\n const listId = useId();\n const blurTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n let active = true;\n if (!debounced.trim()) {\n setResults([]);\n return;\n }\n void searchMunicipalities(debounced, { uf, limit }).then((hits) => {\n if (active) setResults(hits);\n });\n return () => {\n active = false;\n };\n }, [debounced, uf, limit]);\n\n function choose(municipality: MunicipalityCentroid): void {\n onSelect(municipality);\n setQuery(municipality.name);\n setOpen(false);\n }\n\n return (\n <div className={styles.search}>\n <Input\n label={label}\n value={query}\n placeholder={placeholder}\n disabled={disabled}\n role=\"combobox\"\n aria-expanded={open && results.length > 0}\n aria-controls={listId}\n autoComplete=\"off\"\n onChange={(e) => {\n setQuery(e.target.value);\n setOpen(true);\n }}\n onFocus={() => setOpen(true)}\n onBlur={() => {\n // Delay so a result click registers before the list closes.\n blurTimer.current = setTimeout(() => setOpen(false), 120);\n }}\n />\n {open && results.length > 0 && (\n <ul id={listId} className={styles.results} role=\"listbox\">\n {results.map((m) => (\n <li key={m.id}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={false}\n className={styles.result}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => {\n if (blurTimer.current) clearTimeout(blurTimer.current);\n choose(m);\n }}\n >\n <span>{m.name}</span>\n <span className={styles.uf}>{m.uf}</span>\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAoCA,SAAgB,EAAmB,EAC/B,OACA,aACA,UACA,iBAAc,qBACd,WAAQ,GACR,gBAAa,KACb,cAAW,MAC2B;CACtC,IAAM,CAAC,GAAO,KAAY,EAAiB,EAAE,GACvC,CAAC,GAAS,KAAc,EAAiC,CAAC,CAAC,GAC3D,CAAC,GAAM,KAAW,EAAkB,EAAK,GACzC,IAAY,EAAY,GAAO,CAAU,GACzC,IAAS,EAAM,GACf,IAAY,EAA6C,IAAI;CAEnE,QAAgB;EACZ,IAAI,IAAS;EACb,IAAI,CAAC,EAAU,KAAK,GAAG;GACnB,EAAW,CAAC,CAAC;GACb;EACJ;EAIA,OAHA,EAA0B,GAAW;GAAE;GAAI;EAAM,CAAC,CAAC,CAAC,MAAM,MAAS;GAC/D,AAAI,KAAQ,EAAW,CAAI;EAC/B,CAAC,SACY;GACT,IAAS;EACb;CACJ,GAAG;EAAC;EAAW;EAAI;CAAK,CAAC;CAEzB,SAAS,EAAO,GAA0C;EAGtD,AAFA,EAAS,CAAY,GACrB,EAAS,EAAa,IAAI,GAC1B,EAAQ,EAAK;CACjB;CAEA,OACI,kBAAC,OAAD;EAAK,WAAW,EAAO;
|
|
1
|
+
{"version":3,"file":"MunicipalitySearch.js","names":[],"sources":["../../src/br/MunicipalitySearch.tsx"],"sourcesContent":["import { useEffect, useId, useRef, useState, type ReactElement } from \"react\";\nimport { Input } from \"@/components/Input\";\nimport { useDebounce } from \"@/hooks\";\nimport { searchMunicipalities, type MunicipalityCentroid } from \"./geocode\";\nimport type { UF } from \"./locations\";\nimport styles from \"./MunicipalitySearch.module.css\";\n\nexport interface MunicipalitySearchProps {\n /** Restrict the search to a single UF. */\n uf?: UF;\n /** Fired when a municipality is picked from the results. */\n onSelect: (municipality: MunicipalityCentroid) => void;\n /** Field label. */\n label?: string;\n /** Input placeholder. Default: `\"Buscar município…\"`. */\n placeholder?: string;\n /** Max results shown. Default: `8`. */\n limit?: number;\n /** Debounce in ms before searching. Default: `250`. */\n debounceMs?: number;\n /** Disable the field. */\n disabled?: boolean;\n}\n\n/**\n * Debounced municipality autocomplete backed by the offline\n * {@link searchMunicipalities} index — no network. Type a partial name, pick a\n * result, and `onSelect` fires with its `{ id, name, uf, latitude, longitude }`.\n * Wire `onSelect` to a `BrazilStateMap` `selected` to highlight it on the map.\n *\n * @example\n * const [uf, setUf] = useState<UF>(\"SP\");\n * const [city, setCity] = useState<string | null>(null);\n * <MunicipalitySearch uf={uf} onSelect={(m) => setCity(m.name)} />\n * <BrazilStateMap uf={uf} selected={city} />\n */\nexport function MunicipalitySearch({\n uf,\n onSelect,\n label,\n placeholder = \"Buscar município…\",\n limit = 8,\n debounceMs = 250,\n disabled = false,\n}: MunicipalitySearchProps): ReactElement {\n const [query, setQuery] = useState<string>(\"\");\n const [results, setResults] = useState<MunicipalityCentroid[]>([]);\n const [open, setOpen] = useState<boolean>(false);\n const debounced = useDebounce(query, debounceMs);\n const listId = useId();\n const blurTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n let active = true;\n if (!debounced.trim()) {\n setResults([]);\n return;\n }\n void searchMunicipalities(debounced, { uf, limit }).then((hits) => {\n if (active) setResults(hits);\n });\n return () => {\n active = false;\n };\n }, [debounced, uf, limit]);\n\n function choose(municipality: MunicipalityCentroid): void {\n onSelect(municipality);\n setQuery(municipality.name);\n setOpen(false);\n }\n\n return (\n <div className={styles.search}>\n <Input\n label={label}\n value={query}\n placeholder={placeholder}\n disabled={disabled}\n role=\"combobox\"\n aria-expanded={open && results.length > 0}\n aria-controls={listId}\n autoComplete=\"off\"\n onChange={(e) => {\n setQuery(e.target.value);\n setOpen(true);\n }}\n onFocus={() => setOpen(true)}\n onBlur={() => {\n // Delay so a result click registers before the list closes.\n blurTimer.current = setTimeout(() => setOpen(false), 120);\n }}\n />\n {open && results.length > 0 && (\n <ul id={listId} className={styles.results} role=\"listbox\">\n {results.map((m) => (\n <li key={m.id}>\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={false}\n className={styles.result}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => {\n if (blurTimer.current) clearTimeout(blurTimer.current);\n choose(m);\n }}\n >\n <span>{m.name}</span>\n <span className={styles.uf}>{m.uf}</span>\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAoCA,SAAgB,EAAmB,EAC/B,OACA,aACA,UACA,iBAAc,qBACd,WAAQ,GACR,gBAAa,KACb,cAAW,MAC2B;CACtC,IAAM,CAAC,GAAO,KAAY,EAAiB,EAAE,GACvC,CAAC,GAAS,KAAc,EAAiC,CAAC,CAAC,GAC3D,CAAC,GAAM,KAAW,EAAkB,EAAK,GACzC,IAAY,EAAY,GAAO,CAAU,GACzC,IAAS,EAAM,GACf,IAAY,EAA6C,IAAI;CAEnE,QAAgB;EACZ,IAAI,IAAS;EACb,IAAI,CAAC,EAAU,KAAK,GAAG;GACnB,EAAW,CAAC,CAAC;GACb;EACJ;EAIA,OAHA,EAA0B,GAAW;GAAE;GAAI;EAAM,CAAC,CAAC,CAAC,MAAM,MAAS;GAC/D,AAAI,KAAQ,EAAW,CAAI;EAC/B,CAAC,SACY;GACT,IAAS;EACb;CACJ,GAAG;EAAC;EAAW;EAAI;CAAK,CAAC;CAEzB,SAAS,EAAO,GAA0C;EAGtD,AAFA,EAAS,CAAY,GACrB,EAAS,EAAa,IAAI,GAC1B,EAAQ,EAAK;CACjB;CAEA,OACI,kBAAC,OAAD;EAAK,WAAW,EAAO;EAAvB,UAAA,CACI,kBAAC,GAAD;GACW;GACP,OAAO;GACM;GACH;GACV,MAAK;GACL,iBAAe,KAAQ,EAAQ,SAAS;GACxC,iBAAe;GACf,cAAa;GACb,WAAW,MAAM;IAEb,AADA,EAAS,EAAE,OAAO,KAAK,GACvB,EAAQ,EAAI;GAChB;GACA,eAAe,EAAQ,EAAI;GAC3B,cAAc;IAEV,EAAU,UAAU,iBAAiB,EAAQ,EAAK,GAAG,GAAG;GAC5D;EACH,CAAA,GACA,KAAQ,EAAQ,SAAS,KACtB,kBAAC,MAAD;GAAI,IAAI;GAAQ,WAAW,EAAO;GAAS,MAAK;GAC3C,UAAA,EAAQ,KAAK,MACV,kBAAC,MAAD,EAAA,UACI,kBAAC,UAAD;IACI,MAAK;IACL,MAAK;IACL,iBAAe;IACf,WAAW,EAAO;IAClB,cAAc,MAAM,EAAE,eAAe;IACrC,eAAe;KAEX,AADI,EAAU,WAAS,aAAa,EAAU,OAAO,GACrD,EAAO,CAAC;IACZ;IATJ,UAAA,CAWI,kBAAC,QAAD,EAAA,UAAO,EAAE,KAAW,CAAA,GACpB,kBAAC,QAAD;KAAM,WAAW,EAAO;KAAK,UAAA,EAAE;IAAS,CAAA,CACpC;GACR,CAAA,EAAA,GAfK,EAAE,EAeP,CACP;EACD,CAAA,CAEP;;AAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PixQRCode.cjs","names":[],"sources":["../../src/br/PixQRCode.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — `pix` and `payload` are the two ways to supply the\n * same code (build it, or bring one already built), `size`/`level` are the symbol,\n * and amountLabel/payeeLabel/labels exist so the surrounding copy can be translated\n * without wrapping the component.\n */\nimport type { HTMLAttributes } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { CopyButton } from \"@/components/CopyButton\";\nimport { QRCode } from \"@/components/QRCode\";\nimport type { QRErrorCorrection } from \"@/components/QRCode\";\nimport { cn } from \"@/utils/cn\";\n\nimport { PixError, pixPayload } from \"./pix\";\nimport type { PixInput } from \"./pix\";\nimport styles from \"./PixQRCode.module.css\";\n\n/** Strings the component renders, so an app can translate them. */\nexport interface PixQRCodeLabels {\n /** Accessible name of the symbol. */\n qr: string;\n /** Copy button, idle. */\n copy: string;\n /** Copy button, just clicked. */\n copied: string;\n}\n\nconst DEFAULT_LABELS: PixQRCodeLabels = {\n qr: \"QR code do Pix\",\n copy: \"Copiar código\",\n copied: \"Copiado\",\n};\n\nexport interface PixQRCodeProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * Build the payload from its parts. Mutually exclusive with {@link payload}.\n */\n pix?: PixInput;\n /**\n * A payload your PSP already produced, used verbatim.\n *\n * Prefer this for a dynamic charge: the PSP signed that string, and rebuilding\n * it here from parsed parts would only add a way to get it wrong.\n */\n payload?: string;\n /** Rendered side of the symbol in px, quiet zone included. Default `192`. */\n size?: number;\n /**\n * Error-correction level. Default `\"M\"`.\n *\n * A printed QR that will be photographed at an angle scans better at `\"Q\"` or\n * `\"H\"`; the cost is a denser symbol, so raise the size with it.\n */\n level?: QRErrorCorrection;\n /** Render the copia-e-cola line and its copy button. Default `true`. */\n showCopy?: boolean;\n /** Amount caption, e.g. `\"R$ 25,50\"`. Rendered above the symbol when set. */\n amountLabel?: string;\n /** Payee caption. Rendered under the amount when set. */\n payeeLabel?: string;\n labels?: Partial<PixQRCodeLabels>;\n /** Called after the payload reaches the clipboard. */\n onCopied?: () => void;\n}\n\n/**\n * A Pix QR code with the copia-e-cola string next to it.\n *\n * The two affordances belong together: a QR is unusable on the device that is\n * *showing* it, which is exactly where a mobile checkout puts it, so every real\n * Pix screen ends up needing the copyable string as well. Rendering only the\n * symbol is the single most common mistake in a Pix flow.\n *\n * Everything is computed locally — {@link pixPayload} builds the string and the\n * SDK's own encoder draws the symbol — so the key, the amount and the txid never\n * leave the page. A QR-image service would receive all three.\n *\n * @throws {PixError} When neither `pix` nor `payload` is given, when both are, or\n * when `pix` fails validation. A bad key is a programming or data error rather\n * than a state to render, so it surfaces; wrap the screen in `ErrorBoundary` when\n * the values come from user input.\n *\n * @example\n * <PixQRCode\n * pix={{\n * key: \"loja@tempest.dev\",\n * merchantName: \"Loja Tempest\",\n * merchantCity: \"São Paulo\",\n * amount: 25.5,\n * txid: \"PEDIDO123\",\n * }}\n * amountLabel=\"R$ 25,50\"\n * payeeLabel=\"Loja Tempest\"\n * />\n *\n * @example\n * <PixQRCode payload={charge.brcode} level=\"Q\" size={220} />\n */\nexport function PixQRCode({\n pix,\n payload,\n size = 192,\n level = \"M\",\n showCopy = true,\n amountLabel,\n payeeLabel,\n labels,\n onCopied,\n className,\n ...rest\n}: PixQRCodeProps) {\n const value = useMemo(() => {\n if (payload !== undefined && pix !== undefined) {\n throw new PixError(\"Pass either `pix` or `payload` to PixQRCode, not both.\");\n }\n if (payload !== undefined) return payload.trim();\n if (pix !== undefined) return pixPayload(pix);\n throw new PixError(\"PixQRCode needs either `pix` or `payload`.\");\n }, [pix, payload]);\n\n const text = { ...DEFAULT_LABELS, ...labels };\n\n return (\n <div className={cn(styles.pix, className)} {...rest}>\n {amountLabel !== undefined && <span className={styles.amount}>{amountLabel}</span>}\n {payeeLabel !== undefined && <span className={styles.payee}>{payeeLabel}</span>}\n <div className={styles.symbol}>\n <QRCode value={value} size={size} level={level} label={text.qr} margin={2} />\n </div>\n {showCopy && (\n <div className={styles.copy}>\n <code className={styles.payload} data-testid=\"pix-payload\">\n {value}\n </code>\n <CopyButton value={value} onCopied={onCopied}>\n <span className={styles.copyIdle}>{text.copy}</span>\n <span className={styles.copyDone}>{text.copied}</span>\n </CopyButton>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"sPA4BA,IAAM,EAAkC,CACpC,GAAI,iBACJ,KAAM,gBACN,OAAQ,SACZ,EAmEA,SAAgB,EAAU,CACtB,MACA,UACA,OAAO,IACP,QAAQ,IACR,WAAW,GACX,cACA,aACA,SACA,WACA,YACA,GAAG,GACY,CACf,IAAM,GAAA,
|
|
1
|
+
{"version":3,"file":"PixQRCode.cjs","names":[],"sources":["../../src/br/PixQRCode.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — `pix` and `payload` are the two ways to supply the\n * same code (build it, or bring one already built), `size`/`level` are the symbol,\n * and amountLabel/payeeLabel/labels exist so the surrounding copy can be translated\n * without wrapping the component.\n */\nimport type { HTMLAttributes } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { CopyButton } from \"@/components/CopyButton\";\nimport { QRCode } from \"@/components/QRCode\";\nimport type { QRErrorCorrection } from \"@/components/QRCode\";\nimport { cn } from \"@/utils/cn\";\n\nimport { PixError, pixPayload } from \"./pix\";\nimport type { PixInput } from \"./pix\";\nimport styles from \"./PixQRCode.module.css\";\n\n/** Strings the component renders, so an app can translate them. */\nexport interface PixQRCodeLabels {\n /** Accessible name of the symbol. */\n qr: string;\n /** Copy button, idle. */\n copy: string;\n /** Copy button, just clicked. */\n copied: string;\n}\n\nconst DEFAULT_LABELS: PixQRCodeLabels = {\n qr: \"QR code do Pix\",\n copy: \"Copiar código\",\n copied: \"Copiado\",\n};\n\nexport interface PixQRCodeProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * Build the payload from its parts. Mutually exclusive with {@link payload}.\n */\n pix?: PixInput;\n /**\n * A payload your PSP already produced, used verbatim.\n *\n * Prefer this for a dynamic charge: the PSP signed that string, and rebuilding\n * it here from parsed parts would only add a way to get it wrong.\n */\n payload?: string;\n /** Rendered side of the symbol in px, quiet zone included. Default `192`. */\n size?: number;\n /**\n * Error-correction level. Default `\"M\"`.\n *\n * A printed QR that will be photographed at an angle scans better at `\"Q\"` or\n * `\"H\"`; the cost is a denser symbol, so raise the size with it.\n */\n level?: QRErrorCorrection;\n /** Render the copia-e-cola line and its copy button. Default `true`. */\n showCopy?: boolean;\n /** Amount caption, e.g. `\"R$ 25,50\"`. Rendered above the symbol when set. */\n amountLabel?: string;\n /** Payee caption. Rendered under the amount when set. */\n payeeLabel?: string;\n labels?: Partial<PixQRCodeLabels>;\n /** Called after the payload reaches the clipboard. */\n onCopied?: () => void;\n}\n\n/**\n * A Pix QR code with the copia-e-cola string next to it.\n *\n * The two affordances belong together: a QR is unusable on the device that is\n * *showing* it, which is exactly where a mobile checkout puts it, so every real\n * Pix screen ends up needing the copyable string as well. Rendering only the\n * symbol is the single most common mistake in a Pix flow.\n *\n * Everything is computed locally — {@link pixPayload} builds the string and the\n * SDK's own encoder draws the symbol — so the key, the amount and the txid never\n * leave the page. A QR-image service would receive all three.\n *\n * @throws {PixError} When neither `pix` nor `payload` is given, when both are, or\n * when `pix` fails validation. A bad key is a programming or data error rather\n * than a state to render, so it surfaces; wrap the screen in `ErrorBoundary` when\n * the values come from user input.\n *\n * @example\n * <PixQRCode\n * pix={{\n * key: \"loja@tempest.dev\",\n * merchantName: \"Loja Tempest\",\n * merchantCity: \"São Paulo\",\n * amount: 25.5,\n * txid: \"PEDIDO123\",\n * }}\n * amountLabel=\"R$ 25,50\"\n * payeeLabel=\"Loja Tempest\"\n * />\n *\n * @example\n * <PixQRCode payload={charge.brcode} level=\"Q\" size={220} />\n */\nexport function PixQRCode({\n pix,\n payload,\n size = 192,\n level = \"M\",\n showCopy = true,\n amountLabel,\n payeeLabel,\n labels,\n onCopied,\n className,\n ...rest\n}: PixQRCodeProps) {\n const value = useMemo(() => {\n if (payload !== undefined && pix !== undefined) {\n throw new PixError(\"Pass either `pix` or `payload` to PixQRCode, not both.\");\n }\n if (payload !== undefined) return payload.trim();\n if (pix !== undefined) return pixPayload(pix);\n throw new PixError(\"PixQRCode needs either `pix` or `payload`.\");\n }, [pix, payload]);\n\n const text = { ...DEFAULT_LABELS, ...labels };\n\n return (\n <div className={cn(styles.pix, className)} {...rest}>\n {amountLabel !== undefined && <span className={styles.amount}>{amountLabel}</span>}\n {payeeLabel !== undefined && <span className={styles.payee}>{payeeLabel}</span>}\n <div className={styles.symbol}>\n <QRCode value={value} size={size} level={level} label={text.qr} margin={2} />\n </div>\n {showCopy && (\n <div className={styles.copy}>\n <code className={styles.payload} data-testid=\"pix-payload\">\n {value}\n </code>\n <CopyButton value={value} onCopied={onCopied}>\n <span className={styles.copyIdle}>{text.copy}</span>\n <span className={styles.copyDone}>{text.copied}</span>\n </CopyButton>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"sPA4BA,IAAM,EAAkC,CACpC,GAAI,iBACJ,KAAM,gBACN,OAAQ,SACZ,EAmEA,SAAgB,EAAU,CACtB,MACA,UACA,OAAO,IACP,QAAQ,IACR,WAAW,GACX,cACA,aACA,SACA,WACA,YACA,GAAG,GACY,CACf,IAAM,GAAA,EAAQ,EAAA,QAAA,KAAc,CACxB,GAAI,IAAY,IAAA,IAAa,IAAQ,IAAA,GACjC,MAAM,IAAI,EAAA,SAAS,wDAAwD,EAE/E,GAAI,IAAY,IAAA,GAAW,OAAO,EAAQ,KAAK,EAC/C,GAAI,IAAQ,IAAA,GAAW,OAAO,EAAA,WAAW,CAAG,EAC5C,MAAM,IAAI,EAAA,SAAS,4CAA4C,CACnE,EAAG,CAAC,EAAK,CAAO,CAAC,EAEX,EAAO,CAAE,GAAG,EAAgB,GAAG,CAAO,EAE5C,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,CAAS,EAAG,GAAI,EAA/C,SAAA,CACK,IAAgB,IAAA,KAAa,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,OAAS,SAAA,CAAkB,CAAA,EAChF,IAAe,IAAA,KAAa,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,MAAQ,SAAA,CAAiB,CAAA,GAC9E,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,OACnB,UAAA,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CAAe,QAAa,OAAa,QAAO,MAAO,EAAK,GAAI,OAAQ,CAAI,CAAA,CAC3E,CAAA,EACJ,IACG,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAvB,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,QAAS,cAAY,cACxC,SAAA,CACC,CAAA,GACN,EAAA,EAAA,KAAA,CAAC,EAAA,WAAD,CAAmB,QAAiB,WAApC,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,SAAW,SAAA,EAAK,IAAW,CAAA,GACnD,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,SAAW,SAAA,EAAK,MAAa,CAAA,CAC7C,CACX,CAAA,CAAA,GAER,GAEb"}
|
package/dist/br/PixQRCode.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PixQRCode.js","names":[],"sources":["../../src/br/PixQRCode.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — `pix` and `payload` are the two ways to supply the\n * same code (build it, or bring one already built), `size`/`level` are the symbol,\n * and amountLabel/payeeLabel/labels exist so the surrounding copy can be translated\n * without wrapping the component.\n */\nimport type { HTMLAttributes } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { CopyButton } from \"@/components/CopyButton\";\nimport { QRCode } from \"@/components/QRCode\";\nimport type { QRErrorCorrection } from \"@/components/QRCode\";\nimport { cn } from \"@/utils/cn\";\n\nimport { PixError, pixPayload } from \"./pix\";\nimport type { PixInput } from \"./pix\";\nimport styles from \"./PixQRCode.module.css\";\n\n/** Strings the component renders, so an app can translate them. */\nexport interface PixQRCodeLabels {\n /** Accessible name of the symbol. */\n qr: string;\n /** Copy button, idle. */\n copy: string;\n /** Copy button, just clicked. */\n copied: string;\n}\n\nconst DEFAULT_LABELS: PixQRCodeLabels = {\n qr: \"QR code do Pix\",\n copy: \"Copiar código\",\n copied: \"Copiado\",\n};\n\nexport interface PixQRCodeProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * Build the payload from its parts. Mutually exclusive with {@link payload}.\n */\n pix?: PixInput;\n /**\n * A payload your PSP already produced, used verbatim.\n *\n * Prefer this for a dynamic charge: the PSP signed that string, and rebuilding\n * it here from parsed parts would only add a way to get it wrong.\n */\n payload?: string;\n /** Rendered side of the symbol in px, quiet zone included. Default `192`. */\n size?: number;\n /**\n * Error-correction level. Default `\"M\"`.\n *\n * A printed QR that will be photographed at an angle scans better at `\"Q\"` or\n * `\"H\"`; the cost is a denser symbol, so raise the size with it.\n */\n level?: QRErrorCorrection;\n /** Render the copia-e-cola line and its copy button. Default `true`. */\n showCopy?: boolean;\n /** Amount caption, e.g. `\"R$ 25,50\"`. Rendered above the symbol when set. */\n amountLabel?: string;\n /** Payee caption. Rendered under the amount when set. */\n payeeLabel?: string;\n labels?: Partial<PixQRCodeLabels>;\n /** Called after the payload reaches the clipboard. */\n onCopied?: () => void;\n}\n\n/**\n * A Pix QR code with the copia-e-cola string next to it.\n *\n * The two affordances belong together: a QR is unusable on the device that is\n * *showing* it, which is exactly where a mobile checkout puts it, so every real\n * Pix screen ends up needing the copyable string as well. Rendering only the\n * symbol is the single most common mistake in a Pix flow.\n *\n * Everything is computed locally — {@link pixPayload} builds the string and the\n * SDK's own encoder draws the symbol — so the key, the amount and the txid never\n * leave the page. A QR-image service would receive all three.\n *\n * @throws {PixError} When neither `pix` nor `payload` is given, when both are, or\n * when `pix` fails validation. A bad key is a programming or data error rather\n * than a state to render, so it surfaces; wrap the screen in `ErrorBoundary` when\n * the values come from user input.\n *\n * @example\n * <PixQRCode\n * pix={{\n * key: \"loja@tempest.dev\",\n * merchantName: \"Loja Tempest\",\n * merchantCity: \"São Paulo\",\n * amount: 25.5,\n * txid: \"PEDIDO123\",\n * }}\n * amountLabel=\"R$ 25,50\"\n * payeeLabel=\"Loja Tempest\"\n * />\n *\n * @example\n * <PixQRCode payload={charge.brcode} level=\"Q\" size={220} />\n */\nexport function PixQRCode({\n pix,\n payload,\n size = 192,\n level = \"M\",\n showCopy = true,\n amountLabel,\n payeeLabel,\n labels,\n onCopied,\n className,\n ...rest\n}: PixQRCodeProps) {\n const value = useMemo(() => {\n if (payload !== undefined && pix !== undefined) {\n throw new PixError(\"Pass either `pix` or `payload` to PixQRCode, not both.\");\n }\n if (payload !== undefined) return payload.trim();\n if (pix !== undefined) return pixPayload(pix);\n throw new PixError(\"PixQRCode needs either `pix` or `payload`.\");\n }, [pix, payload]);\n\n const text = { ...DEFAULT_LABELS, ...labels };\n\n return (\n <div className={cn(styles.pix, className)} {...rest}>\n {amountLabel !== undefined && <span className={styles.amount}>{amountLabel}</span>}\n {payeeLabel !== undefined && <span className={styles.payee}>{payeeLabel}</span>}\n <div className={styles.symbol}>\n <QRCode value={value} size={size} level={level} label={text.qr} margin={2} />\n </div>\n {showCopy && (\n <div className={styles.copy}>\n <code className={styles.payload} data-testid=\"pix-payload\">\n {value}\n </code>\n <CopyButton value={value} onCopied={onCopied}>\n <span className={styles.copyIdle}>{text.copy}</span>\n <span className={styles.copyDone}>{text.copied}</span>\n </CopyButton>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AA4BA,IAAM,IAAkC;CACpC,IAAI;CACJ,MAAM;CACN,QAAQ;AACZ;AAmEA,SAAgB,EAAU,EACtB,QACA,YACA,UAAO,KACP,WAAQ,KACR,cAAW,IACX,gBACA,eACA,WACA,aACA,cACA,GAAG,KACY;CACf,IAAM,IAAQ,QAAc;EACxB,IAAI,MAAY,KAAA,KAAa,MAAQ,KAAA,GACjC,MAAM,IAAI,EAAS,wDAAwD;EAE/E,IAAI,MAAY,KAAA,GAAW,OAAO,EAAQ,KAAK;EAC/C,IAAI,MAAQ,KAAA,GAAW,OAAO,EAAW,CAAG;EAC5C,MAAM,IAAI,EAAS,4CAA4C;CACnE,GAAG,CAAC,GAAK,CAAO,CAAC,GAEX,IAAO;EAAE,GAAG;EAAgB,GAAG;CAAO;CAE5C,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,KAAK,CAAS;EAAG,GAAI;
|
|
1
|
+
{"version":3,"file":"PixQRCode.js","names":[],"sources":["../../src/br/PixQRCode.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — `pix` and `payload` are the two ways to supply the\n * same code (build it, or bring one already built), `size`/`level` are the symbol,\n * and amountLabel/payeeLabel/labels exist so the surrounding copy can be translated\n * without wrapping the component.\n */\nimport type { HTMLAttributes } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { CopyButton } from \"@/components/CopyButton\";\nimport { QRCode } from \"@/components/QRCode\";\nimport type { QRErrorCorrection } from \"@/components/QRCode\";\nimport { cn } from \"@/utils/cn\";\n\nimport { PixError, pixPayload } from \"./pix\";\nimport type { PixInput } from \"./pix\";\nimport styles from \"./PixQRCode.module.css\";\n\n/** Strings the component renders, so an app can translate them. */\nexport interface PixQRCodeLabels {\n /** Accessible name of the symbol. */\n qr: string;\n /** Copy button, idle. */\n copy: string;\n /** Copy button, just clicked. */\n copied: string;\n}\n\nconst DEFAULT_LABELS: PixQRCodeLabels = {\n qr: \"QR code do Pix\",\n copy: \"Copiar código\",\n copied: \"Copiado\",\n};\n\nexport interface PixQRCodeProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * Build the payload from its parts. Mutually exclusive with {@link payload}.\n */\n pix?: PixInput;\n /**\n * A payload your PSP already produced, used verbatim.\n *\n * Prefer this for a dynamic charge: the PSP signed that string, and rebuilding\n * it here from parsed parts would only add a way to get it wrong.\n */\n payload?: string;\n /** Rendered side of the symbol in px, quiet zone included. Default `192`. */\n size?: number;\n /**\n * Error-correction level. Default `\"M\"`.\n *\n * A printed QR that will be photographed at an angle scans better at `\"Q\"` or\n * `\"H\"`; the cost is a denser symbol, so raise the size with it.\n */\n level?: QRErrorCorrection;\n /** Render the copia-e-cola line and its copy button. Default `true`. */\n showCopy?: boolean;\n /** Amount caption, e.g. `\"R$ 25,50\"`. Rendered above the symbol when set. */\n amountLabel?: string;\n /** Payee caption. Rendered under the amount when set. */\n payeeLabel?: string;\n labels?: Partial<PixQRCodeLabels>;\n /** Called after the payload reaches the clipboard. */\n onCopied?: () => void;\n}\n\n/**\n * A Pix QR code with the copia-e-cola string next to it.\n *\n * The two affordances belong together: a QR is unusable on the device that is\n * *showing* it, which is exactly where a mobile checkout puts it, so every real\n * Pix screen ends up needing the copyable string as well. Rendering only the\n * symbol is the single most common mistake in a Pix flow.\n *\n * Everything is computed locally — {@link pixPayload} builds the string and the\n * SDK's own encoder draws the symbol — so the key, the amount and the txid never\n * leave the page. A QR-image service would receive all three.\n *\n * @throws {PixError} When neither `pix` nor `payload` is given, when both are, or\n * when `pix` fails validation. A bad key is a programming or data error rather\n * than a state to render, so it surfaces; wrap the screen in `ErrorBoundary` when\n * the values come from user input.\n *\n * @example\n * <PixQRCode\n * pix={{\n * key: \"loja@tempest.dev\",\n * merchantName: \"Loja Tempest\",\n * merchantCity: \"São Paulo\",\n * amount: 25.5,\n * txid: \"PEDIDO123\",\n * }}\n * amountLabel=\"R$ 25,50\"\n * payeeLabel=\"Loja Tempest\"\n * />\n *\n * @example\n * <PixQRCode payload={charge.brcode} level=\"Q\" size={220} />\n */\nexport function PixQRCode({\n pix,\n payload,\n size = 192,\n level = \"M\",\n showCopy = true,\n amountLabel,\n payeeLabel,\n labels,\n onCopied,\n className,\n ...rest\n}: PixQRCodeProps) {\n const value = useMemo(() => {\n if (payload !== undefined && pix !== undefined) {\n throw new PixError(\"Pass either `pix` or `payload` to PixQRCode, not both.\");\n }\n if (payload !== undefined) return payload.trim();\n if (pix !== undefined) return pixPayload(pix);\n throw new PixError(\"PixQRCode needs either `pix` or `payload`.\");\n }, [pix, payload]);\n\n const text = { ...DEFAULT_LABELS, ...labels };\n\n return (\n <div className={cn(styles.pix, className)} {...rest}>\n {amountLabel !== undefined && <span className={styles.amount}>{amountLabel}</span>}\n {payeeLabel !== undefined && <span className={styles.payee}>{payeeLabel}</span>}\n <div className={styles.symbol}>\n <QRCode value={value} size={size} level={level} label={text.qr} margin={2} />\n </div>\n {showCopy && (\n <div className={styles.copy}>\n <code className={styles.payload} data-testid=\"pix-payload\">\n {value}\n </code>\n <CopyButton value={value} onCopied={onCopied}>\n <span className={styles.copyIdle}>{text.copy}</span>\n <span className={styles.copyDone}>{text.copied}</span>\n </CopyButton>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AA4BA,IAAM,IAAkC;CACpC,IAAI;CACJ,MAAM;CACN,QAAQ;AACZ;AAmEA,SAAgB,EAAU,EACtB,QACA,YACA,UAAO,KACP,WAAQ,KACR,cAAW,IACX,gBACA,eACA,WACA,aACA,cACA,GAAG,KACY;CACf,IAAM,IAAQ,QAAc;EACxB,IAAI,MAAY,KAAA,KAAa,MAAQ,KAAA,GACjC,MAAM,IAAI,EAAS,wDAAwD;EAE/E,IAAI,MAAY,KAAA,GAAW,OAAO,EAAQ,KAAK;EAC/C,IAAI,MAAQ,KAAA,GAAW,OAAO,EAAW,CAAG;EAC5C,MAAM,IAAI,EAAS,4CAA4C;CACnE,GAAG,CAAC,GAAK,CAAO,CAAC,GAEX,IAAO;EAAE,GAAG;EAAgB,GAAG;CAAO;CAE5C,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,KAAK,CAAS;EAAG,GAAI;EAA/C,UAAA;GACK,MAAgB,KAAA,KAAa,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAS,UAAA;GAAkB,CAAA;GAChF,MAAe,KAAA,KAAa,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAQ,UAAA;GAAiB,CAAA;GAC9E,kBAAC,OAAD;IAAK,WAAW,EAAO;IACnB,UAAA,kBAAC,GAAD;KAAe;KAAa;KAAa;KAAO,OAAO,EAAK;KAAI,QAAQ;IAAI,CAAA;GAC3E,CAAA;GACJ,KACG,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAvB,UAAA,CACI,kBAAC,QAAD;KAAM,WAAW,EAAO;KAAS,eAAY;KACxC,UAAA;IACC,CAAA,GACN,kBAAC,GAAD;KAAmB;KAAiB;KAApC,UAAA,CACI,kBAAC,QAAD;MAAM,WAAW,EAAO;MAAW,UAAA,EAAK;KAAW,CAAA,GACnD,kBAAC,QAAD;MAAM,WAAW,EAAO;MAAW,UAAA,EAAK;KAAa,CAAA,CAC7C;IACX,CAAA,CAAA;;EAER;;AAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-map-hover.cjs","names":[],"sources":["../../src/br/use-map-hover.ts"],"sourcesContent":["import { useCallback, useState, type MouseEvent, type RefObject } from \"react\";\n\n/** The currently hovered item plus cursor position within the map container. */\nexport interface MapHover<T> {\n item: T;\n x: number;\n y: number;\n}\n\n/**\n * Track which shape the cursor is over and where, for a floating map tooltip.\n * Positions are computed relative to `containerRef` so the tooltip can be\n * placed with plain `left`/`top` inside the (relatively positioned) container.\n */\nexport function useMapHover<T>(containerRef: RefObject<HTMLDivElement | null>): {\n hover: MapHover<T> | null;\n onMove: (item: T, event: MouseEvent) => void;\n onLeave: () => void;\n} {\n const [hover, setHover] = useState<MapHover<T> | null>(null);\n\n const onMove = useCallback(\n (item: T, event: MouseEvent): void => {\n const rect = containerRef.current?.getBoundingClientRect();\n if (!rect) return;\n setHover({ item, x: event.clientX - rect.left, y: event.clientY - rect.top });\n },\n [containerRef],\n );\n\n const onLeave = useCallback((): void => setHover(null), []);\n\n return { hover, onMove, onLeave };\n}\n"],"mappings":"uBAcA,SAAgB,EAAe,EAI7B,CACE,GAAM,CAAC,EAAO,IAAA,
|
|
1
|
+
{"version":3,"file":"use-map-hover.cjs","names":[],"sources":["../../src/br/use-map-hover.ts"],"sourcesContent":["import { useCallback, useState, type MouseEvent, type RefObject } from \"react\";\n\n/** The currently hovered item plus cursor position within the map container. */\nexport interface MapHover<T> {\n item: T;\n x: number;\n y: number;\n}\n\n/**\n * Track which shape the cursor is over and where, for a floating map tooltip.\n * Positions are computed relative to `containerRef` so the tooltip can be\n * placed with plain `left`/`top` inside the (relatively positioned) container.\n */\nexport function useMapHover<T>(containerRef: RefObject<HTMLDivElement | null>): {\n hover: MapHover<T> | null;\n onMove: (item: T, event: MouseEvent) => void;\n onLeave: () => void;\n} {\n const [hover, setHover] = useState<MapHover<T> | null>(null);\n\n const onMove = useCallback(\n (item: T, event: MouseEvent): void => {\n const rect = containerRef.current?.getBoundingClientRect();\n if (!rect) return;\n setHover({ item, x: event.clientX - rect.left, y: event.clientY - rect.top });\n },\n [containerRef],\n );\n\n const onLeave = useCallback((): void => setHover(null), []);\n\n return { hover, onMove, onLeave };\n}\n"],"mappings":"uBAcA,SAAgB,EAAe,EAI7B,CACE,GAAM,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAA6B,IAAI,EAa3D,MAAO,CAAE,QAAO,QAAA,EAXD,EAAA,YAAA,EACV,EAAS,IAA4B,CAClC,IAAM,EAAO,EAAa,SAAS,sBAAsB,EACpD,GACL,EAAS,CAAE,OAAM,EAAG,EAAM,QAAU,EAAK,KAAM,EAAG,EAAM,QAAU,EAAK,GAAI,CAAC,CAChF,EACA,CAAC,CAAY,CAKD,EAAQ,SAAA,EAFR,EAAA,YAAA,KAAwB,EAAS,IAAI,EAAG,CAAC,CAEjC,CAAQ,CACpC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-map-zoom.cjs","names":[],"sources":["../../src/br/use-map-zoom.ts"],"sourcesContent":["import { useCallback, useRef, useState, type PointerEvent, type WheelEvent } from \"react\";\n\n/** Pan/zoom transform state. */\nexport interface MapTransform {\n /** Zoom factor (1 = fit). */\n k: number;\n /** X translation in pixels. */\n x: number;\n /** Y translation in pixels. */\n y: number;\n}\n\nconst MIN_K = 1;\nconst MAX_K = 12;\n\nexport interface UseMapZoom {\n /** SVG `transform` string for the content `<g>`. */\n transform: string;\n /** Current zoom factor. */\n zoom: number;\n /** True when panned/zoomed away from the initial fit. */\n isTransformed: boolean;\n /** Reset to the initial fit. */\n reset: () => void;\n /** Handlers to spread on the `<svg>` element. */\n handlers: {\n onWheel?: (e: WheelEvent) => void;\n onPointerDown?: (e: PointerEvent) => void;\n onPointerMove?: (e: PointerEvent) => void;\n onPointerUp?: (e: PointerEvent) => void;\n onPointerLeave?: (e: PointerEvent) => void;\n onDoubleClick?: () => void;\n style?: { cursor: string; touchAction: string };\n };\n}\n\n/**\n * Wheel-zoom (anchored at the cursor) + drag-pan for an SVG map. Returns a\n * `transform` to apply to a content `<g>` and handlers for the `<svg>`. A no-op\n * (identity transform, empty handlers) when `enabled` is false.\n */\nexport function useMapZoom(enabled: boolean): UseMapZoom {\n const [t, setT] = useState<MapTransform>({ k: 1, x: 0, y: 0 });\n const drag = useRef<{ x: number; y: number; ox: number; oy: number } | null>(null);\n\n const reset = useCallback(() => setT({ k: 1, x: 0, y: 0 }), []);\n\n const onWheel = useCallback((e: WheelEvent) => {\n e.preventDefault();\n const rect = e.currentTarget.getBoundingClientRect();\n const cx = e.clientX - rect.left;\n const cy = e.clientY - rect.top;\n setT((prev) => {\n const factor = e.deltaY < 0 ? 1.15 : 1 / 1.15;\n const k = Math.max(MIN_K, Math.min(MAX_K, prev.k * factor));\n const scale = k / prev.k;\n return { k, x: cx - (cx - prev.x) * scale, y: cy - (cy - prev.y) * scale };\n });\n }, []);\n\n const onPointerDown = useCallback((e: PointerEvent) => {\n drag.current = { x: e.clientX, y: e.clientY, ox: 0, oy: 0 };\n e.currentTarget.setPointerCapture?.(e.pointerId);\n }, []);\n\n const onPointerMove = useCallback((e: PointerEvent) => {\n if (!drag.current) return;\n const dx = e.clientX - drag.current.x;\n const dy = e.clientY - drag.current.y;\n drag.current.x = e.clientX;\n drag.current.y = e.clientY;\n setT((prev) => ({ ...prev, x: prev.x + dx, y: prev.y + dy }));\n }, []);\n\n const endDrag = useCallback((e: PointerEvent) => {\n drag.current = null;\n e.currentTarget.releasePointerCapture?.(e.pointerId);\n }, []);\n\n if (!enabled) {\n return {\n transform: \"\",\n zoom: 1,\n isTransformed: false,\n reset,\n handlers: {},\n };\n }\n\n const isTransformed = t.k !== 1 || t.x !== 0 || t.y !== 0;\n return {\n transform: `translate(${t.x} ${t.y}) scale(${t.k})`,\n zoom: t.k,\n isTransformed,\n reset,\n handlers: {\n onWheel,\n onPointerDown,\n onPointerMove,\n onPointerUp: endDrag,\n onPointerLeave: endDrag,\n onDoubleClick: reset,\n style: { cursor: isTransformed ? \"grab\" : \"default\", touchAction: \"none\" },\n },\n };\n}\n"],"mappings":"uBAYA,IAAM,EAAQ,EACR,EAAQ,GA4Bd,SAAgB,EAAW,EAA8B,CACrD,GAAM,CAAC,EAAG,IAAA,
|
|
1
|
+
{"version":3,"file":"use-map-zoom.cjs","names":[],"sources":["../../src/br/use-map-zoom.ts"],"sourcesContent":["import { useCallback, useRef, useState, type PointerEvent, type WheelEvent } from \"react\";\n\n/** Pan/zoom transform state. */\nexport interface MapTransform {\n /** Zoom factor (1 = fit). */\n k: number;\n /** X translation in pixels. */\n x: number;\n /** Y translation in pixels. */\n y: number;\n}\n\nconst MIN_K = 1;\nconst MAX_K = 12;\n\nexport interface UseMapZoom {\n /** SVG `transform` string for the content `<g>`. */\n transform: string;\n /** Current zoom factor. */\n zoom: number;\n /** True when panned/zoomed away from the initial fit. */\n isTransformed: boolean;\n /** Reset to the initial fit. */\n reset: () => void;\n /** Handlers to spread on the `<svg>` element. */\n handlers: {\n onWheel?: (e: WheelEvent) => void;\n onPointerDown?: (e: PointerEvent) => void;\n onPointerMove?: (e: PointerEvent) => void;\n onPointerUp?: (e: PointerEvent) => void;\n onPointerLeave?: (e: PointerEvent) => void;\n onDoubleClick?: () => void;\n style?: { cursor: string; touchAction: string };\n };\n}\n\n/**\n * Wheel-zoom (anchored at the cursor) + drag-pan for an SVG map. Returns a\n * `transform` to apply to a content `<g>` and handlers for the `<svg>`. A no-op\n * (identity transform, empty handlers) when `enabled` is false.\n */\nexport function useMapZoom(enabled: boolean): UseMapZoom {\n const [t, setT] = useState<MapTransform>({ k: 1, x: 0, y: 0 });\n const drag = useRef<{ x: number; y: number; ox: number; oy: number } | null>(null);\n\n const reset = useCallback(() => setT({ k: 1, x: 0, y: 0 }), []);\n\n const onWheel = useCallback((e: WheelEvent) => {\n e.preventDefault();\n const rect = e.currentTarget.getBoundingClientRect();\n const cx = e.clientX - rect.left;\n const cy = e.clientY - rect.top;\n setT((prev) => {\n const factor = e.deltaY < 0 ? 1.15 : 1 / 1.15;\n const k = Math.max(MIN_K, Math.min(MAX_K, prev.k * factor));\n const scale = k / prev.k;\n return { k, x: cx - (cx - prev.x) * scale, y: cy - (cy - prev.y) * scale };\n });\n }, []);\n\n const onPointerDown = useCallback((e: PointerEvent) => {\n drag.current = { x: e.clientX, y: e.clientY, ox: 0, oy: 0 };\n e.currentTarget.setPointerCapture?.(e.pointerId);\n }, []);\n\n const onPointerMove = useCallback((e: PointerEvent) => {\n if (!drag.current) return;\n const dx = e.clientX - drag.current.x;\n const dy = e.clientY - drag.current.y;\n drag.current.x = e.clientX;\n drag.current.y = e.clientY;\n setT((prev) => ({ ...prev, x: prev.x + dx, y: prev.y + dy }));\n }, []);\n\n const endDrag = useCallback((e: PointerEvent) => {\n drag.current = null;\n e.currentTarget.releasePointerCapture?.(e.pointerId);\n }, []);\n\n if (!enabled) {\n return {\n transform: \"\",\n zoom: 1,\n isTransformed: false,\n reset,\n handlers: {},\n };\n }\n\n const isTransformed = t.k !== 1 || t.x !== 0 || t.y !== 0;\n return {\n transform: `translate(${t.x} ${t.y}) scale(${t.k})`,\n zoom: t.k,\n isTransformed,\n reset,\n handlers: {\n onWheel,\n onPointerDown,\n onPointerMove,\n onPointerUp: endDrag,\n onPointerLeave: endDrag,\n onDoubleClick: reset,\n style: { cursor: isTransformed ? \"grab\" : \"default\", touchAction: \"none\" },\n },\n };\n}\n"],"mappings":"uBAYA,IAAM,EAAQ,EACR,EAAQ,GA4Bd,SAAgB,EAAW,EAA8B,CACrD,GAAM,CAAC,EAAG,IAAA,EAAQ,EAAA,SAAA,CAAuB,CAAE,EAAG,EAAG,EAAG,EAAG,EAAG,CAAE,CAAC,EACvD,GAAA,EAAO,EAAA,OAAA,CAAgE,IAAI,EAE3E,GAAA,EAAQ,EAAA,YAAA,KAAkB,EAAK,CAAE,EAAG,EAAG,EAAG,EAAG,EAAG,CAAE,CAAC,EAAG,CAAC,CAAC,EAExD,GAAA,EAAU,EAAA,YAAA,CAAa,GAAkB,CAC3C,EAAE,eAAe,EACjB,IAAM,EAAO,EAAE,cAAc,sBAAsB,EAC7C,EAAK,EAAE,QAAU,EAAK,KACtB,EAAK,EAAE,QAAU,EAAK,IAC5B,EAAM,GAAS,CACX,IAAM,EAAS,EAAE,OAAS,EAAI,KAAO,EAAI,KACnC,EAAI,KAAK,IAAI,EAAO,KAAK,IAAI,EAAO,EAAK,EAAI,CAAM,CAAC,EACpD,EAAQ,EAAI,EAAK,EACvB,MAAO,CAAE,IAAG,EAAG,GAAM,EAAK,EAAK,GAAK,EAAO,EAAG,GAAM,EAAK,EAAK,GAAK,CAAM,CAC7E,CAAC,CACL,EAAG,CAAC,CAAC,EAEC,GAAA,EAAgB,EAAA,YAAA,CAAa,GAAoB,CACnD,EAAK,QAAU,CAAE,EAAG,EAAE,QAAS,EAAG,EAAE,QAAS,GAAI,EAAG,GAAI,CAAE,EAC1D,EAAE,cAAc,oBAAoB,EAAE,SAAS,CACnD,EAAG,CAAC,CAAC,EAEC,GAAA,EAAgB,EAAA,YAAA,CAAa,GAAoB,CACnD,GAAI,CAAC,EAAK,QAAS,OACnB,IAAM,EAAK,EAAE,QAAU,EAAK,QAAQ,EAC9B,EAAK,EAAE,QAAU,EAAK,QAAQ,EACpC,EAAK,QAAQ,EAAI,EAAE,QACnB,EAAK,QAAQ,EAAI,EAAE,QACnB,EAAM,IAAU,CAAE,GAAG,EAAM,EAAG,EAAK,EAAI,EAAI,EAAG,EAAK,EAAI,CAAG,EAAE,CAChE,EAAG,CAAC,CAAC,EAEC,GAAA,EAAU,EAAA,YAAA,CAAa,GAAoB,CAC7C,EAAK,QAAU,KACf,EAAE,cAAc,wBAAwB,EAAE,SAAS,CACvD,EAAG,CAAC,CAAC,EAEL,GAAI,CAAC,EACD,MAAO,CACH,UAAW,GACX,KAAM,EACN,cAAe,GACf,QACA,SAAU,CAAC,CACf,EAGJ,IAAM,EAAgB,EAAE,IAAM,GAAK,EAAE,IAAM,GAAK,EAAE,IAAM,EACxD,MAAO,CACH,UAAW,aAAa,EAAE,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,EAAE,GACjD,KAAM,EAAE,EACR,gBACA,QACA,SAAU,CACN,UACA,gBACA,gBACA,YAAa,EACb,eAAgB,EAChB,cAAe,EACf,MAAO,CAAE,OAAQ,EAAgB,OAAS,UAAW,YAAa,MAAO,CAC7E,CACJ,CACJ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function e(e){return typeof MediaRecorder>`u`?null:typeof MediaRecorder.isTypeSupported==`function`?e.find(e=>MediaRecorder.isTypeSupported(e))??null:e[0]??null}function t(t,n){let{candidates:r,kind:i,mimeType:a,audioBitsPerSecond:o,videoBitsPerSecond:s,timesliceMs:c,onChunk:l,onError:u}=n;if(typeof MediaRecorder>`u`)throw Error(`MediaRecorder is not available in this environment.`);let d=a??e(r);if(d===null)throw Error(`This browser cannot record any supported ${i} container.`);if(a!==void 0&&typeof MediaRecorder.isTypeSupported==`function`&&!MediaRecorder.isTypeSupported(a))throw Error(`This browser cannot record "${a}".`);let f=new MediaRecorder(t,{mimeType:d,...o===void 0?{}:{audioBitsPerSecond:o},...s===void 0?{}:{videoBitsPerSecond:s}}),p=[],m=`idle`,h=0,g=0,_=null,v=!1,y=()=>h+(m===`recording`?Date.now()-g:0);return f.ondataavailable=e=>{e.data.size!==0&&(v||(p.push(e.data),l?.(e.data)))},f.onerror=e=>{u?.(e.error??e)},f.onstop=()=>{let e=y();m=`stopped`;let t=_;if(_=null,v){p=[];return}let n=f.mimeType||d;t?.({blob:new Blob(p,{type:n}),mimeType:n,durationMs:e}),p=[]},{mimeType:d,status:()=>m,durationMs:y,start(){m
|
|
1
|
+
function e(e){return typeof MediaRecorder>`u`?null:typeof MediaRecorder.isTypeSupported==`function`?e.find(e=>MediaRecorder.isTypeSupported(e))??null:e[0]??null}function t(t,n){let{candidates:r,kind:i,mimeType:a,audioBitsPerSecond:o,videoBitsPerSecond:s,timesliceMs:c,onChunk:l,onError:u}=n;if(typeof MediaRecorder>`u`)throw Error(`MediaRecorder is not available in this environment.`);let d=a??e(r);if(d===null)throw Error(`This browser cannot record any supported ${i} container.`);if(a!==void 0&&typeof MediaRecorder.isTypeSupported==`function`&&!MediaRecorder.isTypeSupported(a))throw Error(`This browser cannot record "${a}".`);let f=new MediaRecorder(t,{mimeType:d,...o===void 0?{}:{audioBitsPerSecond:o},...s===void 0?{}:{videoBitsPerSecond:s}}),p=[],m=`idle`,h=0,g=0,_=null,v=!1,y=()=>h+(m===`recording`?Date.now()-g:0);return f.ondataavailable=e=>{e.data.size!==0&&(v||(p.push(e.data),l?.(e.data)))},f.onerror=e=>{u?.(e.error??e)},f.onstop=()=>{let e=y();m=`stopped`;let t=_;if(_=null,v){p=[];return}let n=f.mimeType||d;t?.({blob:new Blob(p,{type:n}),mimeType:n,durationMs:e}),p=[]},{mimeType:d,status:()=>m,durationMs:y,start(){m!==`recording`&&m!==`paused`&&(p=[],h=0,v=!1,g=Date.now(),m=`recording`,c===void 0?f.start():f.start(c))},pause(){m===`recording`&&(h+=Date.now()-g,m=`paused`,f.pause())},resume(){m===`paused`&&(g=Date.now(),m=`recording`,f.resume())},stop(){return m===`idle`||m===`stopped`?Promise.resolve({blob:new Blob([],{type:d}),mimeType:d,durationMs:0}):new Promise(e=>{_=e,f.stop()})},cancel(){m!==`idle`&&m!==`stopped`&&(v=!0,_=null,f.stop())}}}exports.createMediaRecorder=t,exports.pickRecordingMimeType=e;
|
|
2
2
|
//# sourceMappingURL=media-recorder.cjs.map
|
|
@@ -36,7 +36,7 @@ function t(t, n) {
|
|
|
36
36
|
status: () => m,
|
|
37
37
|
durationMs: y,
|
|
38
38
|
start() {
|
|
39
|
-
m
|
|
39
|
+
m !== "recording" && m !== "paused" && (p = [], h = 0, v = !1, g = Date.now(), m = "recording", c === void 0 ? f.start() : f.start(c));
|
|
40
40
|
},
|
|
41
41
|
pause() {
|
|
42
42
|
m === "recording" && (h += Date.now() - g, m = "paused", f.pause());
|
|
@@ -54,7 +54,7 @@ function t(t, n) {
|
|
|
54
54
|
});
|
|
55
55
|
},
|
|
56
56
|
cancel() {
|
|
57
|
-
m
|
|
57
|
+
m !== "idle" && m !== "stopped" && (v = !0, _ = null, f.stop());
|
|
58
58
|
}
|
|
59
59
|
};
|
|
60
60
|
}
|