@zendir/ui 0.5.0 → 0.6.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/CHANGELOG.md +419 -386
- package/README.md +640 -631
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/index.js +17 -221
- package/dist/react/3d/CesiumCaptureSource.d.ts +0 -1
- package/dist/react/3d/CesiumCaptureSource.js +364 -283
- package/dist/react/3d/CesiumCaptureSource.js.map +1 -1
- package/dist/react/3d/ZenSpace3D.d.ts +2 -3
- package/dist/react/3d/ZenSpace3D.js +1681 -1237
- package/dist/react/3d/ZenSpace3D.js.map +1 -1
- package/dist/react/3d/ZenSpace3DCesium.d.ts +0 -1
- package/dist/react/3d/ZenSpace3DCesium.js +513 -560
- package/dist/react/3d/ZenSpace3DCesium.js.map +1 -1
- package/dist/react/3d/ZenSpace3DShaders.js +61 -66
- package/dist/react/3d/ZenSpace3DShaders.js.map +1 -1
- package/dist/react/3d/ZenSpace3DTypes.d.ts +19 -20
- package/dist/react/3d/ZenSpace3DUtils.d.ts +0 -1
- package/dist/react/3d/ZenSpace3DUtils.js +37 -24
- package/dist/react/3d/ZenSpace3DUtils.js.map +1 -1
- package/dist/react/3d/capturePngAnalysis.js +42 -36
- package/dist/react/3d/capturePngAnalysis.js.map +1 -1
- package/dist/react/3d/index.d.ts +3 -3
- package/dist/react/3d/index.js +5 -53
- package/dist/react/3d/threeLoader.d.ts +1 -1
- package/dist/react/3d/threeLoader.js +23 -18
- package/dist/react/3d/threeLoader.js.map +1 -1
- package/dist/react/astro/ClassificationBanner.d.ts +2 -3
- package/dist/react/astro/ClassificationBanner.js +95 -79
- package/dist/react/astro/ClassificationBanner.js.map +1 -1
- package/dist/react/astro/GlobalStatusBar.d.ts +0 -1
- package/dist/react/astro/GlobalStatusBar.js +157 -163
- package/dist/react/astro/GlobalStatusBar.js.map +1 -1
- package/dist/react/astro/MissionClock.d.ts +7 -8
- package/dist/react/astro/MissionClock.js +377 -400
- package/dist/react/astro/MissionClock.js.map +1 -1
- package/dist/react/astro/MonitoringIcon.d.ts +1 -2
- package/dist/react/astro/MonitoringIcon.js +422 -358
- package/dist/react/astro/MonitoringIcon.js.map +1 -1
- package/dist/react/astro/Notification.d.ts +1 -2
- package/dist/react/astro/Notification.js +229 -126
- package/dist/react/astro/Notification.js.map +1 -1
- package/dist/react/astro/Progress.d.ts +0 -1
- package/dist/react/astro/Progress.js +199 -141
- package/dist/react/astro/Progress.js.map +1 -1
- package/dist/react/astro/SimulationControls.d.ts +3 -4
- package/dist/react/astro/SimulationControls.js +596 -650
- package/dist/react/astro/SimulationControls.js.map +1 -1
- package/dist/react/astro/StatusIndicator.d.ts +0 -1
- package/dist/react/astro/StatusIndicator.js +236 -170
- package/dist/react/astro/StatusIndicator.js.map +1 -1
- package/dist/react/astro/UnifiedTimeline.d.ts +9 -10
- package/dist/react/astro/UnifiedTimeline.js +2345 -2392
- package/dist/react/astro/UnifiedTimeline.js.map +1 -1
- package/dist/react/astro/index.d.ts +5 -5
- package/dist/react/astro/index.js +1 -25
- package/dist/react/cards/AccessCard.d.ts +0 -1
- package/dist/react/cards/AccessCard.js +471 -405
- package/dist/react/cards/AccessCard.js.map +1 -1
- package/dist/react/cards/OrbitCard.d.ts +0 -1
- package/dist/react/cards/OrbitCard.js +487 -364
- package/dist/react/cards/OrbitCard.js.map +1 -1
- package/dist/react/cards/SpacecraftCard.d.ts +0 -1
- package/dist/react/cards/SpacecraftCard.js +813 -925
- package/dist/react/cards/SpacecraftCard.js.map +1 -1
- package/dist/react/cards/TelemetryCard.d.ts +0 -1
- package/dist/react/cards/TelemetryCard.js +1055 -732
- package/dist/react/cards/TelemetryCard.js.map +1 -1
- package/dist/react/cards/TelemetryStreamCard.d.ts +0 -1
- package/dist/react/cards/TelemetryStreamCard.js +323 -297
- package/dist/react/cards/TelemetryStreamCard.js.map +1 -1
- package/dist/react/cards/index.d.ts +1 -1
- package/dist/react/cards/index.js +1 -8
- package/dist/react/charts/GroundTrackMap.d.ts +6 -7
- package/dist/react/charts/GroundTrackMap.js +1377 -1256
- package/dist/react/charts/GroundTrackMap.js.map +1 -1
- package/dist/react/charts/GroundTrackMapLeaflet.d.ts +1 -2
- package/dist/react/charts/GroundTrackMapLeaflet.js +1065 -987
- package/dist/react/charts/GroundTrackMapLeaflet.js.map +1 -1
- package/dist/react/charts/groundTrackMapLeafletTiles.js +34 -25
- package/dist/react/charts/groundTrackMapLeafletTiles.js.map +1 -1
- package/dist/react/charts/groundTrackMapLeafletUtils.js +70 -61
- package/dist/react/charts/groundTrackMapLeafletUtils.js.map +1 -1
- package/dist/react/charts/index.d.ts +1 -1
- package/dist/react/charts/index.js +7 -100
- package/dist/react/charts/unified/AstroChart.d.ts +1 -2
- package/dist/react/charts/unified/AstroChart.js +1331 -1411
- package/dist/react/charts/unified/AstroChart.js.map +1 -1
- package/dist/react/charts/unified/PowerOverviewChart.d.ts +3 -3
- package/dist/react/charts/unified/PowerOverviewChart.js +495 -478
- package/dist/react/charts/unified/PowerOverviewChart.js.map +1 -1
- package/dist/react/charts/unified/domain.d.ts +12 -13
- package/dist/react/charts/unified/domain.js +3999 -3145
- package/dist/react/charts/unified/domain.js.map +1 -1
- package/dist/react/charts/unified/generators.d.ts +3 -4
- package/dist/react/charts/unified/generators.js +561 -498
- package/dist/react/charts/unified/generators.js.map +1 -1
- package/dist/react/charts/unified/index.d.ts +1 -1
- package/dist/react/charts/unified/presets.d.ts +14 -15
- package/dist/react/charts/unified/presets.js +857 -994
- package/dist/react/charts/unified/presets.js.map +1 -1
- package/dist/react/charts/unified/sync.d.ts +2 -3
- package/dist/react/charts/unified/sync.js +229 -195
- package/dist/react/charts/unified/sync.js.map +1 -1
- package/dist/react/charts/unified/theme.d.ts +11 -12
- package/dist/react/charts/unified/theme.js +606 -642
- package/dist/react/charts/unified/theme.js.map +1 -1
- package/dist/react/charts/unified/types.d.ts +32 -33
- package/dist/react/charts/unified/useChartStream.d.ts +1 -2
- package/dist/react/charts/unified/useChartStream.js +203 -216
- package/dist/react/charts/unified/useChartStream.js.map +1 -1
- package/dist/react/chatgpt/AppCard.d.ts +1 -2
- package/dist/react/chatgpt/index.d.ts +7 -7
- package/dist/react/chatgpt/index.js +160 -139
- package/dist/react/chatgpt/index.js.map +1 -1
- package/dist/react/context/CategoryContext.d.ts +0 -1
- package/dist/react/context/CategoryContext.js +78 -29
- package/dist/react/context/CategoryContext.js.map +1 -1
- package/dist/react/context/DisplaySettingsContext.d.ts +1 -2
- package/dist/react/context/DisplaySettingsContext.js +205 -156
- package/dist/react/context/DisplaySettingsContext.js.map +1 -1
- package/dist/react/context/SpatialSelectionContext.d.ts +0 -1
- package/dist/react/context/SpatialSelectionContext.js +36 -7
- package/dist/react/context/SpatialSelectionContext.js.map +1 -1
- package/dist/react/core/data/DataTable.d.ts +3 -4
- package/dist/react/core/data/DataTable.js +473 -440
- package/dist/react/core/data/DataTable.js.map +1 -1
- package/dist/react/core/data/DataValue.d.ts +4 -5
- package/dist/react/core/data/DataValue.js +605 -571
- package/dist/react/core/data/DataValue.js.map +1 -1
- package/dist/react/core/data/propertyConfig.d.ts +1 -2
- package/dist/react/core/data/propertyConfig.js +446 -382
- package/dist/react/core/data/propertyConfig.js.map +1 -1
- package/dist/react/core/display/AstroIcon.d.ts +4 -5
- package/dist/react/core/display/AstroIcon.js +339 -429
- package/dist/react/core/display/AstroIcon.js.map +1 -1
- package/dist/react/core/display/Badge.d.ts +2 -3
- package/dist/react/core/display/Badge.js +131 -131
- package/dist/react/core/display/Badge.js.map +1 -1
- package/dist/react/core/display/CardHeader.d.ts +0 -1
- package/dist/react/core/display/CardHeader.js +398 -311
- package/dist/react/core/display/CardHeader.js.map +1 -1
- package/dist/react/core/display/Container.d.ts +2 -3
- package/dist/react/core/display/Container.js +640 -668
- package/dist/react/core/display/Container.js.map +1 -1
- package/dist/react/core/display/CopyButton.d.ts +1 -2
- package/dist/react/core/display/CopyButton.js +158 -101
- package/dist/react/core/display/CopyButton.js.map +1 -1
- package/dist/react/core/display/GlassCard.d.ts +3 -4
- package/dist/react/core/display/GlassCard.js +416 -369
- package/dist/react/core/display/GlassCard.js.map +1 -1
- package/dist/react/core/display/HeaderIconWithStatus.d.ts +0 -1
- package/dist/react/core/display/HeaderIconWithStatus.js +152 -152
- package/dist/react/core/display/HeaderIconWithStatus.js.map +1 -1
- package/dist/react/core/display/Icon.d.ts +2 -3
- package/dist/react/core/display/Icon.js +172 -143
- package/dist/react/core/display/Icon.js.map +1 -1
- package/dist/react/core/display/Typography.d.ts +24 -25
- package/dist/react/core/display/Typography.js +360 -178
- package/dist/react/core/display/Typography.js.map +1 -1
- package/dist/react/core/feedback/ConfirmDialog.d.ts +1 -2
- package/dist/react/core/feedback/ConfirmDialog.js +343 -304
- package/dist/react/core/feedback/ConfirmDialog.js.map +1 -1
- package/dist/react/core/feedback/Dialog.d.ts +2 -3
- package/dist/react/core/feedback/Dialog.js +189 -197
- package/dist/react/core/feedback/Dialog.js.map +1 -1
- package/dist/react/core/feedback/Toast.d.ts +2 -3
- package/dist/react/core/feedback/Toast.js +346 -207
- package/dist/react/core/feedback/Toast.js.map +1 -1
- package/dist/react/core/index.d.ts +26 -26
- package/dist/react/core/index.js +7 -119
- package/dist/react/core/inputs/Button.d.ts +2 -3
- package/dist/react/core/inputs/Button.js +281 -304
- package/dist/react/core/inputs/Button.js.map +1 -1
- package/dist/react/core/inputs/Checkbox.d.ts +2 -3
- package/dist/react/core/inputs/Checkbox.js +139 -127
- package/dist/react/core/inputs/Checkbox.js.map +1 -1
- package/dist/react/core/inputs/Input.d.ts +3 -4
- package/dist/react/core/inputs/Input.js +277 -285
- package/dist/react/core/inputs/Input.js.map +1 -1
- package/dist/react/core/inputs/LimitsBar.d.ts +1 -2
- package/dist/react/core/inputs/LimitsBar.js +271 -196
- package/dist/react/core/inputs/LimitsBar.js.map +1 -1
- package/dist/react/core/inputs/NumberInput.d.ts +2 -3
- package/dist/react/core/inputs/NumberInput.js +531 -503
- package/dist/react/core/inputs/NumberInput.js.map +1 -1
- package/dist/react/core/inputs/PinInput.d.ts +2 -3
- package/dist/react/core/inputs/PinInput.js +224 -207
- package/dist/react/core/inputs/PinInput.js.map +1 -1
- package/dist/react/core/inputs/Select.d.ts +1 -2
- package/dist/react/core/inputs/Select.js +298 -299
- package/dist/react/core/inputs/Select.js.map +1 -1
- package/dist/react/core/inputs/Toggle.d.ts +2 -3
- package/dist/react/core/inputs/Toggle.js +142 -148
- package/dist/react/core/inputs/Toggle.js.map +1 -1
- package/dist/react/core/layout/Box.d.ts +3 -4
- package/dist/react/core/layout/Box.js +118 -122
- package/dist/react/core/layout/Box.js.map +1 -1
- package/dist/react/core/layout/Center.d.ts +0 -1
- package/dist/react/core/layout/Center.js +45 -32
- package/dist/react/core/layout/Center.js.map +1 -1
- package/dist/react/core/layout/Divider.d.ts +1 -2
- package/dist/react/core/layout/Divider.js +112 -106
- package/dist/react/core/layout/Divider.js.map +1 -1
- package/dist/react/core/layout/Flex.d.ts +4 -5
- package/dist/react/core/layout/Flex.js +120 -124
- package/dist/react/core/layout/Flex.js.map +1 -1
- package/dist/react/core/layout/Grid.d.ts +5 -6
- package/dist/react/core/layout/Grid.js +131 -138
- package/dist/react/core/layout/Grid.js.map +1 -1
- package/dist/react/core/layout/Spacer.d.ts +0 -1
- package/dist/react/core/layout/Spacer.js +36 -29
- package/dist/react/core/layout/Spacer.js.map +1 -1
- package/dist/react/core/layout/Stack.d.ts +4 -5
- package/dist/react/core/layout/Stack.js +127 -70
- package/dist/react/core/layout/Stack.js.map +1 -1
- package/dist/react/core/layout/responsive.d.ts +1 -2
- package/dist/react/core/layout/responsive.js +25 -19
- package/dist/react/core/layout/responsive.js.map +1 -1
- package/dist/react/core/layout/useBreakpoint.d.ts +1 -1
- package/dist/react/core/layout/useBreakpoint.js +119 -66
- package/dist/react/core/layout/useBreakpoint.js.map +1 -1
- package/dist/react/core/navigation/AppBar.d.ts +1 -2
- package/dist/react/core/navigation/AppBar.js +827 -805
- package/dist/react/core/navigation/AppBar.js.map +1 -1
- package/dist/react/core/navigation/Pagination.d.ts +2 -3
- package/dist/react/core/navigation/Pagination.js +207 -187
- package/dist/react/core/navigation/Pagination.js.map +1 -1
- package/dist/react/core/navigation/SideNav.d.ts +5 -6
- package/dist/react/core/navigation/SideNav.js +855 -629
- package/dist/react/core/navigation/SideNav.js.map +1 -1
- package/dist/react/core/navigation/Tabs.d.ts +0 -1
- package/dist/react/core/navigation/Tabs.js +113 -119
- package/dist/react/core/navigation/Tabs.js.map +1 -1
- package/dist/react/core/overlays/Popover.d.ts +2 -3
- package/dist/react/core/overlays/Popover.js +303 -282
- package/dist/react/core/overlays/Popover.js.map +1 -1
- package/dist/react/core/overlays/SidePanel.d.ts +1 -2
- package/dist/react/core/overlays/SidePanel.js +217 -212
- package/dist/react/core/overlays/SidePanel.js.map +1 -1
- package/dist/react/core/overlays/Tooltip.d.ts +1 -2
- package/dist/react/core/overlays/Tooltip.js +170 -176
- package/dist/react/core/overlays/Tooltip.js.map +1 -1
- package/dist/react/core/widgets/ActivityPlanner.d.ts +0 -1
- package/dist/react/core/widgets/ActivityPlanner.js +855 -517
- package/dist/react/core/widgets/ActivityPlanner.js.map +1 -1
- package/dist/react/core/widgets/Capture.d.ts +2 -3
- package/dist/react/core/widgets/Capture.js +965 -779
- package/dist/react/core/widgets/Capture.js.map +1 -1
- package/dist/react/core/widgets/ChatPanel.d.ts +16 -17
- package/dist/react/core/widgets/ChatPanel.js +1734 -1034
- package/dist/react/core/widgets/ChatPanel.js.map +1 -1
- package/dist/react/core/widgets/ColorPickerPanel.d.ts +0 -1
- package/dist/react/core/widgets/ColorPickerPanel.js +298 -287
- package/dist/react/core/widgets/ColorPickerPanel.js.map +1 -1
- package/dist/react/core/widgets/CommandBuilder.d.ts +2 -3
- package/dist/react/core/widgets/CommandBuilder.js +624 -516
- package/dist/react/core/widgets/CommandBuilder.js.map +1 -1
- package/dist/react/core/widgets/ConnectionForm.d.ts +2 -3
- package/dist/react/core/widgets/ConnectionForm.js +528 -492
- package/dist/react/core/widgets/ConnectionForm.js.map +1 -1
- package/dist/react/core/widgets/FileExplorer.d.ts +3 -4
- package/dist/react/core/widgets/FileExplorer.js +617 -505
- package/dist/react/core/widgets/FileExplorer.js.map +1 -1
- package/dist/react/core/widgets/HexViewer.d.ts +2 -3
- package/dist/react/core/widgets/HexViewer.js +1353 -1091
- package/dist/react/core/widgets/HexViewer.js.map +1 -1
- package/dist/react/core/widgets/ImageFrame.d.ts +1 -2
- package/dist/react/core/widgets/ImageFrame.js +230 -193
- package/dist/react/core/widgets/ImageFrame.js.map +1 -1
- package/dist/react/core/widgets/ImageGallery.d.ts +2 -1
- package/dist/react/core/widgets/ImageGallery.js +380 -314
- package/dist/react/core/widgets/ImageGallery.js.map +1 -1
- package/dist/react/core/widgets/ImagePanel.d.ts +0 -1
- package/dist/react/core/widgets/ImagePanel.js +110 -101
- package/dist/react/core/widgets/ImagePanel.js.map +1 -1
- package/dist/react/core/widgets/LogViewer.d.ts +2 -3
- package/dist/react/core/widgets/LogViewer.js +711 -607
- package/dist/react/core/widgets/LogViewer.js.map +1 -1
- package/dist/react/core/widgets/MessageStream.d.ts +3 -4
- package/dist/react/core/widgets/MessageStream.js +514 -444
- package/dist/react/core/widgets/MessageStream.js.map +1 -1
- package/dist/react/core/widgets/MissionCalendar.d.ts +3 -4
- package/dist/react/core/widgets/MissionCalendar.js +1488 -1020
- package/dist/react/core/widgets/MissionCalendar.js.map +1 -1
- package/dist/react/core/widgets/PacketViewer.d.ts +2 -3
- package/dist/react/core/widgets/PacketViewer.js +550 -421
- package/dist/react/core/widgets/PacketViewer.js.map +1 -1
- package/dist/react/core/widgets/capture-placeholder.png.js +6 -5
- package/dist/react/core/widgets/capture-placeholder.png.js.map +1 -1
- package/dist/react/hooks/index.d.ts +5 -5
- package/dist/react/hooks/useAccessWindows.d.ts +0 -1
- package/dist/react/hooks/useCompactMode.d.ts +1 -1
- package/dist/react/hooks/useCompactMode.js +104 -58
- package/dist/react/hooks/useCompactMode.js.map +1 -1
- package/dist/react/hooks/useGroundTrackHistory.d.ts +0 -1
- package/dist/react/hooks/useSimulationScene.d.ts +1 -2
- package/dist/react/hooks/useSimulationScene.js +481 -374
- package/dist/react/hooks/useSimulationScene.js.map +1 -1
- package/dist/react/index.d.ts +3 -3
- package/dist/react/panels/LayerControlPanel.d.ts +1 -2
- package/dist/react/panels/LayerControlPanel.js +223 -180
- package/dist/react/panels/LayerControlPanel.js.map +1 -1
- package/dist/react/panels/ObjectInventoryPanel.d.ts +2 -3
- package/dist/react/panels/ObjectInventoryPanel.js +315 -250
- package/dist/react/panels/ObjectInventoryPanel.js.map +1 -1
- package/dist/react/panels/index.d.ts +1 -1
- package/dist/react/panels/index.js +1 -6
- package/dist/react/shared/ErrorBoundary.d.ts +1 -2
- package/dist/react/shared/ErrorBoundary.js +170 -139
- package/dist/react/shared/ErrorBoundary.js.map +1 -1
- package/dist/react/shared/Skeleton.d.ts +1 -2
- package/dist/react/shared/Skeleton.js +300 -301
- package/dist/react/shared/Skeleton.js.map +1 -1
- package/dist/react/theme/ThemeProvider.d.ts +2 -321
- package/dist/react/theme/ThemeProvider.js +313 -939
- package/dist/react/theme/ThemeProvider.js.map +1 -1
- package/dist/react/theme/cardAccent.d.ts +1 -2
- package/dist/react/theme/cardAccent.js +196 -126
- package/dist/react/theme/cardAccent.js.map +1 -1
- package/dist/react/theme/config.d.ts +0 -1
- package/dist/react/theme/config.js +47 -25
- package/dist/react/theme/config.js.map +1 -1
- package/dist/react/theme/index.d.ts +2 -2
- package/dist/react/theme/index.js +1 -16
- package/dist/react/theme/types.d.ts +332 -0
- package/dist/react/theme/types.js +39 -0
- package/dist/react/theme/types.js.map +1 -0
- package/dist/react/types.d.ts +8 -8
- package/dist/react/types.js +147 -47
- package/dist/react/types.js.map +1 -1
- package/dist/react/utils/categoryPalette.d.ts +0 -1
- package/dist/react/utils/categoryPalette.js +91 -102
- package/dist/react/utils/categoryPalette.js.map +1 -1
- package/dist/react/utils/index.d.ts +5 -5
- package/dist/react/utils/index.js +457 -371
- package/dist/react/utils/index.js.map +1 -1
- package/dist/react/visualizations/EclipseTimerCard.d.ts +0 -1
- package/dist/react/visualizations/LinkBudgetCard.d.ts +0 -1
- package/dist/react/visualizations/NavBallCard.d.ts +0 -1
- package/dist/react/visualizations/PropulsionCard.d.ts +1 -2
- package/dist/react/visualizations/SensorFootprintCard.d.ts +1 -2
- package/dist/react/visualizations/ThermalHeatmapCard.d.ts +0 -1
- package/dist/react/visualizations/index.d.ts +3 -3
- package/dist/react.d.ts +2 -1
- package/dist/react.js +17 -221
- package/dist/shaders/atmosphere.frag.js +6 -5
- package/dist/shaders/atmosphere.frag.js.map +1 -1
- package/dist/shaders/atmosphere.vert.js +6 -5
- package/dist/shaders/atmosphere.vert.js.map +1 -1
- package/dist/shaders/stars.frag.js +6 -5
- package/dist/shaders/stars.frag.js.map +1 -1
- package/dist/shaders/stars.vert.js +6 -5
- package/dist/shaders/stars.vert.js.map +1 -1
- package/dist/style.css +26 -3
- package/dist/tokens/core.d.ts +159 -0
- package/dist/tokens/core.js +144 -0
- package/dist/tokens/core.js.map +1 -0
- package/dist/tokens/css-vars.d.ts +213 -2
- package/dist/tokens/css-vars.js +590 -227
- package/dist/tokens/css-vars.js.map +1 -1
- package/dist/tokens/index.d.ts +31 -228
- package/dist/tokens/index.js +281 -366
- package/dist/tokens/index.js.map +1 -1
- package/dist/tokens/palettes/astro.d.ts +129 -0
- package/dist/tokens/palettes/astro.js +112 -0
- package/dist/tokens/palettes/astro.js.map +1 -0
- package/dist/tokens/palettes/index.d.ts +288 -0
- package/dist/tokens/palettes/index.js +35 -0
- package/dist/tokens/palettes/index.js.map +1 -0
- package/dist/tokens/palettes/tailwind.d.ts +324 -0
- package/dist/tokens/palettes/tailwind.js +201 -0
- package/dist/tokens/palettes/tailwind.js.map +1 -0
- package/dist/tokens/palettes/zendir.d.ts +126 -0
- package/dist/tokens/palettes/zendir.js +92 -0
- package/dist/tokens/palettes/zendir.js.map +1 -0
- package/dist/tokens/themes.d.ts +30 -0
- package/dist/tokens/themes.js +704 -0
- package/dist/tokens/themes.js.map +1 -0
- package/dist/tokens/tokens.css +533 -155
- package/dist/types/index.d.ts +2 -2
- package/package.json +310 -313
- package/dist/index.js.map +0 -1
- package/dist/react/3d/index.js.map +0 -1
- package/dist/react/astro/index.js.map +0 -1
- package/dist/react/cards/index.js.map +0 -1
- package/dist/react/charts/index.js.map +0 -1
- package/dist/react/core/index.js.map +0 -1
- package/dist/react/panels/index.js.map +0 -1
- package/dist/react/theme/astro-tokens.d.ts +0 -153
- package/dist/react/theme/index.js.map +0 -1
- package/dist/react.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SidePanel.js","sources":["../../../../src/react/core/overlays/SidePanel.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - SidePanel Component\r\n * \r\n * A sliding panel that pushes content instead of overlaying it.\r\n * Designed to be placed as a flex sibling so the parent layout\r\n * naturally adjusts when the panel opens/closes.\r\n * \r\n * Features:\r\n * - Push-content behavior (flex sibling, content adjusts automatically)\r\n * - Smooth slide-in/out animation\r\n * - Configurable width, position (left/right)\r\n * - Optional overlay backdrop (for modal-like behavior)\r\n * - Theme-integrated via useTheme()\r\n * - Accessible (focus trap, keyboard support)\r\n * - Close on escape key\r\n * \r\n * @example\r\n * ```tsx\r\n * // Push-content pattern: SidePanel as flex sibling\r\n * <div style={{ display: 'flex', height: '100vh' }}>\r\n * <main style={{ flex: 1, transition: 'all 0.3s ease' }}>\r\n * {children}\r\n * </main>\r\n * <SidePanel\r\n * open={isChatOpen}\r\n * onClose={() => setIsChatOpen(false)}\r\n * title=\"Chat Assistant\"\r\n * width={380}\r\n * >\r\n * <ChatPanel messages={messages} onSend={handleSend} />\r\n * </SidePanel>\r\n * </div>\r\n * ```\r\n */\r\n\r\nimport React, { memo, useEffect, useRef, useCallback, useState } from 'react';\r\nimport { useTheme } from '../../theme';\r\nimport { classNames } from '../../utils';\r\nimport { useBreakpoint } from '../layout/useBreakpoint';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport type SidePanelPosition = 'left' | 'right';\r\n\r\nexport interface SidePanelProps {\r\n /** Whether the panel is open */\r\n open: boolean;\r\n /** Called when the panel should close */\r\n onClose: () => void;\r\n /** Panel title displayed in the header */\r\n title?: string;\r\n /** Panel width in px or CSS string (default: 380) */\r\n width?: number | string;\r\n /** Which side the panel slides in from (default: 'right') */\r\n position?: SidePanelPosition;\r\n /** Show a close button in the header (default: true) */\r\n showCloseButton?: boolean;\r\n /** Close when pressing Escape (default: true) */\r\n closeOnEscape?: boolean;\r\n /** Show a semi-transparent overlay behind the panel (default: false) */\r\n overlay?: boolean;\r\n /** Close when clicking the overlay (default: true, only applies when overlay=true) */\r\n closeOnOverlayClick?: boolean;\r\n /** Panel content */\r\n children: React.ReactNode;\r\n /** Optional header actions (rendered in header, right of title) */\r\n headerActions?: React.ReactNode;\r\n /** Optional leading element (rendered in header, left of title — useful for collapse icons) */\r\n headerLeading?: React.ReactNode;\r\n /** Called when the header bar is clicked (useful for collapse-on-click) */\r\n onHeaderClick?: () => void;\r\n /** Custom style overrides for the header bar */\r\n headerStyle?: React.CSSProperties;\r\n /** Custom className */\r\n className?: string;\r\n /** Custom style overrides for the panel container */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n// ============================================================================\r\n// Unique animation ID\r\n// ============================================================================\r\n\r\nlet sidePanelInstanceCount = 0;\r\n\r\n// ============================================================================\r\n// Component\r\n// ============================================================================\r\n\r\nexport const SidePanel = memo(function SidePanel({\r\n open,\r\n onClose,\r\n title,\r\n width = 380,\r\n position = 'right',\r\n showCloseButton = true,\r\n closeOnEscape = true,\r\n overlay = false,\r\n closeOnOverlayClick = true,\r\n children,\r\n headerActions,\r\n headerLeading,\r\n onHeaderClick,\r\n headerStyle: headerStyleProp,\r\n className = '',\r\n style: styleProp,\r\n}: SidePanelProps): React.ReactElement | null {\r\n const { tokens, theme } = useTheme();\r\n const isTransparentTheme = theme === 'transparent' || theme === 'transparent-bold' || theme === 'transparent-minimal';\r\n const panelRef = useRef<HTMLDivElement>(null);\r\n const [animState, setAnimState] = useState<'closed' | 'opening' | 'open' | 'closing'>('closed');\r\n const _instanceId = useRef(++sidePanelInstanceCount);\r\n\r\n const { isMobile } = useBreakpoint();\r\n const resolvedWidth = isMobile ? '100%' : (typeof width === 'number' ? `${width}px` : width);\r\n\r\n // Animate open/close\r\n useEffect(() => {\r\n if (open) {\r\n setAnimState('opening');\r\n const timer = setTimeout(() => setAnimState('open'), 30);\r\n return () => clearTimeout(timer);\r\n } else {\r\n if (animState === 'open' || animState === 'opening') {\r\n setAnimState('closing');\r\n const timer = setTimeout(() => setAnimState('closed'), 550);\r\n return () => clearTimeout(timer);\r\n }\r\n }\r\n }, [open]);\r\n\r\n // Escape key handler\r\n const handleKeyDown = useCallback((e: KeyboardEvent) => {\r\n if (closeOnEscape && e.key === 'Escape') {\r\n onClose();\r\n }\r\n }, [closeOnEscape, onClose]);\r\n\r\n useEffect(() => {\r\n if (open) {\r\n document.addEventListener('keydown', handleKeyDown);\r\n return () => document.removeEventListener('keydown', handleKeyDown);\r\n }\r\n }, [open, handleKeyDown]);\r\n\r\n // Don't render at all when fully closed\r\n if (animState === 'closed') return null;\r\n\r\n const isVisible = animState === 'open';\r\n const slideFrom = position === 'right' ? 'translateX(100%)' : 'translateX(-100%)';\r\n\r\n return (\r\n <>\r\n {/* Optional overlay */}\r\n {overlay && (\r\n <div\r\n className=\"zendir-sidepanel-overlay\"\r\n onClick={closeOnOverlayClick ? onClose : undefined}\r\n style={{\r\n position: 'fixed',\r\n inset: 0,\r\n backgroundColor: isTransparentTheme ? `${tokens.colors.background.base}4D` : `${tokens.colors.background.base}66`,\r\n backdropFilter: isTransparentTheme ? 'blur(2px)' : undefined,\r\n WebkitBackdropFilter: isTransparentTheme ? 'blur(2px)' : undefined,\r\n zIndex: 999,\r\n opacity: isVisible ? 1 : 0,\r\n transition: 'opacity 0.3s ease',\r\n pointerEvents: isVisible ? 'auto' : 'none',\r\n }}\r\n />\r\n )}\r\n\r\n {/* Panel */}\r\n <div\r\n ref={panelRef}\r\n className={classNames('zendir-sidepanel', className)}\r\n style={{\r\n width: isVisible ? resolvedWidth : '0px',\r\n minWidth: isVisible ? resolvedWidth : '0px',\r\n maxWidth: resolvedWidth,\r\n height: '100%',\r\n overflow: 'hidden',\r\n transition: 'width 0.6s cubic-bezier(0.2, 0.8, 0.2, 1), min-width 0.6s cubic-bezier(0.2, 0.8, 0.2, 1)',\r\n flexShrink: 0,\r\n position: 'relative',\r\n zIndex: overlay ? 1000 : 'auto',\r\n ...(overlay && { position: 'fixed', top: 0, [position]: 0 }),\r\n ...styleProp,\r\n }}\r\n >\r\n <div\r\n style={{\r\n width: resolvedWidth,\r\n height: '100%',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n backgroundColor: isTransparentTheme\r\n ? 'rgba(15, 15, 35, 0.85)'\r\n : tokens.colors.background.surface,\r\n ...(isTransparentTheme && {\r\n backdropFilter: 'blur(16px)',\r\n WebkitBackdropFilter: 'blur(16px)',\r\n }),\r\n borderLeft: position === 'right' ? tokens.borders.divider : undefined,\r\n borderRight: position === 'left' ? tokens.borders.divider : undefined,\r\n transform: isVisible ? 'translateX(0)' : slideFrom,\r\n transition: 'transform 0.6s cubic-bezier(0.2, 0.8, 0.2, 1)',\r\n overflow: 'hidden',\r\n }}\r\n >\r\n {/* Header */}\r\n {(title || showCloseButton || headerActions || headerLeading) && (\r\n <div\r\n onClick={onHeaderClick}\r\n role={onHeaderClick ? 'button' : undefined}\r\n tabIndex={onHeaderClick ? 0 : undefined}\r\n onKeyDown={onHeaderClick ? (e: React.KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onHeaderClick(); } } : undefined}\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'space-between',\r\n padding: `${tokens.spacing.md} ${tokens.spacing.md}`,\r\n borderBottom: tokens.borders.divider,\r\n flexShrink: 0,\r\n gap: tokens.spacing.sm,\r\n ...(onHeaderClick && { cursor: 'pointer' }),\r\n ...headerStyleProp,\r\n }}\r\n >\r\n <div style={{ display: 'flex', alignItems: 'center', gap: tokens.spacing.sm, flex: 1, minWidth: 0 }}>\r\n {headerLeading}\r\n {title && (\r\n <h3\r\n style={{\r\n margin: 0,\r\n fontSize: tokens.typography.fontSize.base,\r\n fontWeight: tokens.typography.fontWeight.semibold,\r\n color: tokens.colors.text.primary,\r\n whiteSpace: 'nowrap',\r\n overflow: 'hidden',\r\n textOverflow: 'ellipsis',\r\n }}\r\n >\r\n {title}\r\n </h3>\r\n )}\r\n </div>\r\n <div style={{ display: 'flex', alignItems: 'center', gap: tokens.spacing.xs, flexShrink: 0 }}>\r\n {headerActions}\r\n {showCloseButton && (\r\n <button\r\n type=\"button\"\r\n onClick={onClose}\r\n aria-label=\"Close panel\"\r\n style={{\r\n padding: tokens.spacing.sm,\r\n minWidth: 44,\r\n minHeight: 44,\r\n backgroundColor: 'transparent',\r\n border: 'none',\r\n borderRadius: tokens.borderRadius.sm,\r\n cursor: 'pointer',\r\n color: tokens.colors.text.muted ?? tokens.colors.text.tertiary,\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n transition: `color 0.15s ease, background-color 0.15s ease`,\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.color = tokens.colors.text.primary;\r\n e.currentTarget.style.backgroundColor = tokens.colors.background.base;\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.color = tokens.colors.text.muted ?? tokens.colors.text.tertiary;\r\n e.currentTarget.style.backgroundColor = 'transparent';\r\n }}\r\n >\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\" />\r\n </svg>\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Content */}\r\n <div\r\n style={{\r\n flex: 1,\r\n overflow: 'auto',\r\n minHeight: 0,\r\n }}\r\n >\r\n {children}\r\n </div>\r\n </div>\r\n </div>\r\n </>\r\n );\r\n});\r\n\r\nexport default SidePanel;\r\n"],"names":["SidePanel"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SidePanel.js","names":[],"sources":["../../../../src/react/core/overlays/SidePanel.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - SidePanel Component\r\n *\r\n * A sliding panel that pushes content instead of overlaying it.\r\n * Designed to be placed as a flex sibling so the parent layout\r\n * naturally adjusts when the panel opens/closes.\r\n *\r\n * Features:\r\n * - Push-content behavior (flex sibling, content adjusts automatically)\r\n * - Smooth slide-in/out animation\r\n * - Configurable width, position (left/right)\r\n * - Optional overlay backdrop (for modal-like behavior)\r\n * - Theme-integrated via useTheme()\r\n * - Accessible (focus trap, keyboard support)\r\n * - Close on escape key\r\n *\r\n * @example\r\n * ```tsx\r\n * // Push-content pattern: SidePanel as flex sibling\r\n * <div style={{ display: 'flex', height: '100vh' }}>\r\n * <main style={{ flex: 1, transition: 'all 0.3s ease' }}>\r\n * {children}\r\n * </main>\r\n * <SidePanel\r\n * open={isChatOpen}\r\n * onClose={() => setIsChatOpen(false)}\r\n * title=\"Chat Assistant\"\r\n * width={380}\r\n * >\r\n * <ChatPanel messages={messages} onSend={handleSend} />\r\n * </SidePanel>\r\n * </div>\r\n * ```\r\n */\r\n\r\nimport React, { memo, useEffect, useRef, useCallback, useState } from \"react\";\r\nimport { useTheme } from \"../../theme\";\r\nimport { classNames } from \"../../utils\";\r\nimport { useBreakpoint } from \"../layout/useBreakpoint\";\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport type SidePanelPosition = \"left\" | \"right\";\r\n\r\nexport interface SidePanelProps {\r\n /** Whether the panel is open */\r\n open: boolean;\r\n /** Called when the panel should close */\r\n onClose: () => void;\r\n /** Panel title displayed in the header */\r\n title?: string;\r\n /** Panel width in px or CSS string (default: 380) */\r\n width?: number | string;\r\n /** Which side the panel slides in from (default: 'right') */\r\n position?: SidePanelPosition;\r\n /** Show a close button in the header (default: true) */\r\n showCloseButton?: boolean;\r\n /** Close when pressing Escape (default: true) */\r\n closeOnEscape?: boolean;\r\n /** Show a semi-transparent overlay behind the panel (default: false) */\r\n overlay?: boolean;\r\n /** Close when clicking the overlay (default: true, only applies when overlay=true) */\r\n closeOnOverlayClick?: boolean;\r\n /** Panel content */\r\n children: React.ReactNode;\r\n /** Optional header actions (rendered in header, right of title) */\r\n headerActions?: React.ReactNode;\r\n /** Optional leading element (rendered in header, left of title — useful for collapse icons) */\r\n headerLeading?: React.ReactNode;\r\n /** Called when the header bar is clicked (useful for collapse-on-click) */\r\n onHeaderClick?: () => void;\r\n /** Custom style overrides for the header bar */\r\n headerStyle?: React.CSSProperties;\r\n /** Custom className */\r\n className?: string;\r\n /** Custom style overrides for the panel container */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n// ============================================================================\r\n// Unique animation ID\r\n// ============================================================================\r\n\r\nlet sidePanelInstanceCount = 0;\r\n\r\n// ============================================================================\r\n// Component\r\n// ============================================================================\r\n\r\nexport const SidePanel = memo(function SidePanel({\r\n open,\r\n onClose,\r\n title,\r\n width = 380,\r\n position = \"right\",\r\n showCloseButton = true,\r\n closeOnEscape = true,\r\n overlay = false,\r\n closeOnOverlayClick = true,\r\n children,\r\n headerActions,\r\n headerLeading,\r\n onHeaderClick,\r\n headerStyle: headerStyleProp,\r\n className = \"\",\r\n style: styleProp,\r\n}: SidePanelProps): React.ReactElement | null {\r\n const { tokens, theme } = useTheme();\r\n const isTransparentTheme =\r\n theme === \"transparent\" ||\r\n theme === \"transparent-bold\" ||\r\n theme === \"transparent-minimal\";\r\n const panelRef = useRef<HTMLDivElement>(null);\r\n const [animState, setAnimState] = useState<\r\n \"closed\" | \"opening\" | \"open\" | \"closing\"\r\n >(\"closed\");\r\n const _instanceId = useRef(++sidePanelInstanceCount);\r\n\r\n const { isMobile } = useBreakpoint();\r\n const resolvedWidth = isMobile\r\n ? \"100%\"\r\n : typeof width === \"number\"\r\n ? `${width}px`\r\n : width;\r\n\r\n // Animate open/close\r\n useEffect(() => {\r\n if (open) {\r\n setAnimState(\"opening\");\r\n const timer = setTimeout(() => setAnimState(\"open\"), 30);\r\n return () => clearTimeout(timer);\r\n } else {\r\n if (animState === \"open\" || animState === \"opening\") {\r\n setAnimState(\"closing\");\r\n const timer = setTimeout(() => setAnimState(\"closed\"), 550);\r\n return () => clearTimeout(timer);\r\n }\r\n }\r\n }, [open]);\r\n\r\n // Escape key handler\r\n const handleKeyDown = useCallback(\r\n (e: KeyboardEvent) => {\r\n if (closeOnEscape && e.key === \"Escape\") {\r\n onClose();\r\n }\r\n },\r\n [closeOnEscape, onClose],\r\n );\r\n\r\n useEffect(() => {\r\n if (open) {\r\n document.addEventListener(\"keydown\", handleKeyDown);\r\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\r\n }\r\n }, [open, handleKeyDown]);\r\n\r\n // Don't render at all when fully closed\r\n if (animState === \"closed\") return null;\r\n\r\n const isVisible = animState === \"open\";\r\n const slideFrom =\r\n position === \"right\" ? \"translateX(100%)\" : \"translateX(-100%)\";\r\n\r\n return (\r\n <>\r\n {/* Optional overlay */}\r\n {overlay && (\r\n <div\r\n className=\"zendir-sidepanel-overlay\"\r\n onClick={closeOnOverlayClick ? onClose : undefined}\r\n style={{\r\n position: \"fixed\",\r\n inset: 0,\r\n backgroundColor: isTransparentTheme\r\n ? `${tokens.colors.background.base}4D`\r\n : `${tokens.colors.background.base}66`,\r\n backdropFilter: isTransparentTheme ? \"blur(2px)\" : undefined,\r\n WebkitBackdropFilter: isTransparentTheme ? \"blur(2px)\" : undefined,\r\n zIndex: 999,\r\n opacity: isVisible ? 1 : 0,\r\n transition: \"opacity 0.3s ease\",\r\n pointerEvents: isVisible ? \"auto\" : \"none\",\r\n }}\r\n />\r\n )}\r\n\r\n {/* Panel */}\r\n <div\r\n ref={panelRef}\r\n className={classNames(\"zendir-sidepanel\", className)}\r\n style={{\r\n width: isVisible ? resolvedWidth : \"0px\",\r\n minWidth: isVisible ? resolvedWidth : \"0px\",\r\n maxWidth: resolvedWidth,\r\n height: \"100%\",\r\n overflow: \"hidden\",\r\n transition:\r\n \"width 0.6s cubic-bezier(0.2, 0.8, 0.2, 1), min-width 0.6s cubic-bezier(0.2, 0.8, 0.2, 1)\",\r\n flexShrink: 0,\r\n position: \"relative\",\r\n zIndex: overlay ? 1000 : \"auto\",\r\n ...(overlay && { position: \"fixed\", top: 0, [position]: 0 }),\r\n ...styleProp,\r\n }}\r\n >\r\n <div\r\n style={{\r\n width: resolvedWidth,\r\n height: \"100%\",\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n backgroundColor: isTransparentTheme\r\n ? \"rgba(15, 15, 35, 0.85)\"\r\n : tokens.colors.background.surface,\r\n ...(isTransparentTheme && {\r\n backdropFilter: \"blur(16px)\",\r\n WebkitBackdropFilter: \"blur(16px)\",\r\n }),\r\n borderLeft:\r\n position === \"right\" ? tokens.borders.divider : undefined,\r\n borderRight:\r\n position === \"left\" ? tokens.borders.divider : undefined,\r\n transform: isVisible ? \"translateX(0)\" : slideFrom,\r\n transition: \"transform 0.6s cubic-bezier(0.2, 0.8, 0.2, 1)\",\r\n overflow: \"hidden\",\r\n }}\r\n >\r\n {/* Header */}\r\n {(title || showCloseButton || headerActions || headerLeading) && (\r\n <div\r\n onClick={onHeaderClick}\r\n role={onHeaderClick ? \"button\" : undefined}\r\n tabIndex={onHeaderClick ? 0 : undefined}\r\n onKeyDown={\r\n onHeaderClick\r\n ? (e: React.KeyboardEvent) => {\r\n if (e.key === \"Enter\" || e.key === \" \") {\r\n e.preventDefault();\r\n onHeaderClick();\r\n }\r\n }\r\n : undefined\r\n }\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"space-between\",\r\n padding: `${tokens.spacing.md} ${tokens.spacing.md}`,\r\n borderBottom: tokens.borders.divider,\r\n flexShrink: 0,\r\n gap: tokens.spacing.sm,\r\n ...(onHeaderClick && { cursor: \"pointer\" }),\r\n ...headerStyleProp,\r\n }}\r\n >\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: tokens.spacing.sm,\r\n flex: 1,\r\n minWidth: 0,\r\n }}\r\n >\r\n {headerLeading}\r\n {title && (\r\n <h3\r\n style={{\r\n margin: 0,\r\n fontSize: tokens.typography.fontSize.base,\r\n fontWeight: tokens.typography.fontWeight.semibold,\r\n color: tokens.colors.text.primary,\r\n whiteSpace: \"nowrap\",\r\n overflow: \"hidden\",\r\n textOverflow: \"ellipsis\",\r\n }}\r\n >\r\n {title}\r\n </h3>\r\n )}\r\n </div>\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: tokens.spacing.xs,\r\n flexShrink: 0,\r\n }}\r\n >\r\n {headerActions}\r\n {showCloseButton && (\r\n <button\r\n type=\"button\"\r\n onClick={onClose}\r\n aria-label=\"Close panel\"\r\n style={{\r\n padding: tokens.spacing.sm,\r\n minWidth: 44,\r\n minHeight: 44,\r\n backgroundColor: \"transparent\",\r\n border: \"none\",\r\n borderRadius: tokens.borderRadius.sm,\r\n cursor: \"pointer\",\r\n color:\r\n tokens.colors.text.muted ?? tokens.colors.text.tertiary,\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n transition: `color 0.15s ease, background-color 0.15s ease`,\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.color = tokens.colors.text.primary;\r\n e.currentTarget.style.backgroundColor =\r\n tokens.colors.background.base;\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.color =\r\n tokens.colors.text.muted ?? tokens.colors.text.tertiary;\r\n e.currentTarget.style.backgroundColor = \"transparent\";\r\n }}\r\n >\r\n <svg\r\n width=\"20\"\r\n height=\"20\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"currentColor\"\r\n >\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\" />\r\n </svg>\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Content */}\r\n <div\r\n style={{\r\n flex: 1,\r\n overflow: \"auto\",\r\n minHeight: 0,\r\n }}\r\n >\r\n {children}\r\n </div>\r\n </div>\r\n </div>\r\n </>\r\n );\r\n});\r\n\r\nexport default SidePanel;\r\n"],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
|
|
3
|
-
export type TooltipPlacement = 'top' | 'bottom' | 'left' | 'right';
|
|
2
|
+
export type TooltipPlacement = "top" | "bottom" | "left" | "right";
|
|
4
3
|
export interface TooltipProps {
|
|
5
4
|
/** Tooltip content */
|
|
6
5
|
content: React.ReactNode;
|
|
@@ -1,179 +1,173 @@
|
|
|
1
|
-
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
2
|
-
import { memo, useState, useRef, useCallback, useLayoutEffect, useEffect } from "react";
|
|
3
|
-
import ReactDOM from "react-dom";
|
|
4
1
|
import { useTheme } from "../../theme/ThemeProvider.js";
|
|
5
2
|
import { classNames } from "../../utils/index.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
document.body
|
|
173
|
-
)
|
|
174
|
-
] });
|
|
3
|
+
import { memo, useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import ReactDOM from "react-dom";
|
|
6
|
+
//#region src/react/core/overlays/Tooltip.tsx
|
|
7
|
+
/**
|
|
8
|
+
* @zendir/ui - Tooltip Component
|
|
9
|
+
*
|
|
10
|
+
* Tooltip following Astro UX Design System.
|
|
11
|
+
* Uses a portal to render in document.body, ensuring correct positioning
|
|
12
|
+
* even when the trigger is inside containers with CSS transforms or overflow.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* <Tooltip content="Click to enable telemetry">
|
|
17
|
+
* <Button>Enable</Button>
|
|
18
|
+
* </Tooltip>
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
var Tooltip = memo(function Tooltip({ content, placement = "top", delay = 200, disabled = false, children, className = "" }) {
|
|
22
|
+
const { tokens } = useTheme();
|
|
23
|
+
const [visible, setVisible] = useState(false);
|
|
24
|
+
const [positioned, setPositioned] = useState(false);
|
|
25
|
+
const [position, setPosition] = useState({
|
|
26
|
+
top: 0,
|
|
27
|
+
left: 0
|
|
28
|
+
});
|
|
29
|
+
const triggerRef = useRef(null);
|
|
30
|
+
const tooltipRef = useRef(null);
|
|
31
|
+
const timeoutRef = useRef();
|
|
32
|
+
const hideTimeoutRef = useRef();
|
|
33
|
+
const showTooltip = useCallback(() => {
|
|
34
|
+
if (disabled) return;
|
|
35
|
+
if (hideTimeoutRef.current) {
|
|
36
|
+
clearTimeout(hideTimeoutRef.current);
|
|
37
|
+
hideTimeoutRef.current = void 0;
|
|
38
|
+
}
|
|
39
|
+
timeoutRef.current = window.setTimeout(() => {
|
|
40
|
+
setVisible(true);
|
|
41
|
+
setPositioned(false);
|
|
42
|
+
}, delay);
|
|
43
|
+
}, [disabled, delay]);
|
|
44
|
+
const hideTooltip = useCallback(() => {
|
|
45
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
46
|
+
hideTimeoutRef.current = window.setTimeout(() => {
|
|
47
|
+
setVisible(false);
|
|
48
|
+
setPositioned(false);
|
|
49
|
+
}, 100);
|
|
50
|
+
}, []);
|
|
51
|
+
const hideImmediately = useCallback(() => {
|
|
52
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
53
|
+
if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
|
|
54
|
+
setVisible(false);
|
|
55
|
+
setPositioned(false);
|
|
56
|
+
}, []);
|
|
57
|
+
const calculatePosition = useCallback(() => {
|
|
58
|
+
if (!triggerRef.current || !tooltipRef.current) return;
|
|
59
|
+
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
60
|
+
const tooltipRect = tooltipRef.current.getBoundingClientRect();
|
|
61
|
+
const gap = 8;
|
|
62
|
+
const viewportWidth = window.innerWidth;
|
|
63
|
+
const viewportHeight = window.innerHeight;
|
|
64
|
+
let top = 0;
|
|
65
|
+
let left = 0;
|
|
66
|
+
switch (placement) {
|
|
67
|
+
case "top":
|
|
68
|
+
top = triggerRect.top - tooltipRect.height - gap;
|
|
69
|
+
left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
|
|
70
|
+
break;
|
|
71
|
+
case "bottom":
|
|
72
|
+
top = triggerRect.bottom + gap;
|
|
73
|
+
left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
|
|
74
|
+
break;
|
|
75
|
+
case "left":
|
|
76
|
+
top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;
|
|
77
|
+
left = triggerRect.left - tooltipRect.width - gap;
|
|
78
|
+
break;
|
|
79
|
+
case "right":
|
|
80
|
+
top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;
|
|
81
|
+
left = triggerRect.right + gap;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
if (left < gap) left = gap;
|
|
85
|
+
if (left + tooltipRect.width > viewportWidth - gap) left = viewportWidth - tooltipRect.width - gap;
|
|
86
|
+
if (top < gap) top = gap;
|
|
87
|
+
if (top + tooltipRect.height > viewportHeight - gap) top = viewportHeight - tooltipRect.height - gap;
|
|
88
|
+
setPosition({
|
|
89
|
+
top,
|
|
90
|
+
left
|
|
91
|
+
});
|
|
92
|
+
setPositioned(true);
|
|
93
|
+
}, [placement]);
|
|
94
|
+
useLayoutEffect(() => {
|
|
95
|
+
if (visible && triggerRef.current && tooltipRef.current) calculatePosition();
|
|
96
|
+
}, [visible, calculatePosition]);
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (!visible) return;
|
|
99
|
+
const handleScrollOrResize = () => {
|
|
100
|
+
calculatePosition();
|
|
101
|
+
};
|
|
102
|
+
window.addEventListener("scroll", handleScrollOrResize, true);
|
|
103
|
+
window.addEventListener("resize", handleScrollOrResize);
|
|
104
|
+
return () => {
|
|
105
|
+
window.removeEventListener("scroll", handleScrollOrResize, true);
|
|
106
|
+
window.removeEventListener("resize", handleScrollOrResize);
|
|
107
|
+
};
|
|
108
|
+
}, [visible, calculatePosition]);
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (!visible) return;
|
|
111
|
+
const handleEscape = (e) => {
|
|
112
|
+
if (e.key === "Escape") hideImmediately();
|
|
113
|
+
};
|
|
114
|
+
document.addEventListener("keydown", handleEscape);
|
|
115
|
+
return () => document.removeEventListener("keydown", handleEscape);
|
|
116
|
+
}, [visible, hideImmediately]);
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
return () => {
|
|
119
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
120
|
+
if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
|
|
121
|
+
};
|
|
122
|
+
}, []);
|
|
123
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
124
|
+
ref: triggerRef,
|
|
125
|
+
className: classNames("zendir-tooltip-trigger", className),
|
|
126
|
+
style: {
|
|
127
|
+
display: "inline-flex",
|
|
128
|
+
pointerEvents: "auto",
|
|
129
|
+
maxWidth: "100%",
|
|
130
|
+
width: "inherit"
|
|
131
|
+
},
|
|
132
|
+
onMouseEnter: showTooltip,
|
|
133
|
+
onMouseLeave: hideTooltip,
|
|
134
|
+
onFocus: showTooltip,
|
|
135
|
+
onBlur: hideTooltip,
|
|
136
|
+
children
|
|
137
|
+
}), visible && ReactDOM.createPortal(/* @__PURE__ */ jsxs("div", {
|
|
138
|
+
ref: tooltipRef,
|
|
139
|
+
role: "tooltip",
|
|
140
|
+
onMouseEnter: showTooltip,
|
|
141
|
+
onMouseLeave: hideTooltip,
|
|
142
|
+
style: {
|
|
143
|
+
position: "fixed",
|
|
144
|
+
top: positioned ? position.top : 0,
|
|
145
|
+
left: positioned ? position.left : 0,
|
|
146
|
+
width: "max-content",
|
|
147
|
+
padding: `${tokens.spacing.sm} ${tokens.spacing.smd}`,
|
|
148
|
+
backgroundColor: tokens.colors.background.elevated,
|
|
149
|
+
color: tokens.colors.text.primary,
|
|
150
|
+
fontSize: "0.75rem",
|
|
151
|
+
fontWeight: 500,
|
|
152
|
+
fontFamily: tokens.typography.fontFamily.primary,
|
|
153
|
+
borderRadius: tokens.borderRadius.md,
|
|
154
|
+
border: `1px solid ${tokens.colors.accent.primary}20`,
|
|
155
|
+
boxShadow: positioned ? `${tokens.shadows.lg}, 0 0 20px ${tokens.colors.accent.primary}10` : "none",
|
|
156
|
+
zIndex: 2147483100,
|
|
157
|
+
maxWidth: "min(280px, calc(100vw - 24px))",
|
|
158
|
+
whiteSpace: "normal",
|
|
159
|
+
pointerEvents: "auto",
|
|
160
|
+
visibility: positioned ? "visible" : "hidden",
|
|
161
|
+
opacity: positioned ? 1 : 0,
|
|
162
|
+
transition: positioned ? void 0 : "none",
|
|
163
|
+
animation: positioned ? `zendir-tooltip ${tokens.animation.duration.fast}ms ${tokens.animation.easing.default} both` : "none",
|
|
164
|
+
backdropFilter: "blur(8px)"
|
|
165
|
+
},
|
|
166
|
+
children: [content, /* @__PURE__ */ jsx("style", { children: `@keyframes zendir-tooltip { from { opacity: 0; transform: scale(0.95) translateY(${placement === "bottom" ? "-4px" : placement === "top" ? "4px" : "0"}); } to { opacity: 1; transform: scale(1) translateY(0); } }
|
|
167
|
+
@media (prefers-reduced-motion: reduce) { @keyframes zendir-tooltip { from, to { opacity: 1; transform: none; } } }` })]
|
|
168
|
+
}), document.body)] });
|
|
175
169
|
});
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
//# sourceMappingURL=Tooltip.js.map
|
|
170
|
+
//#endregion
|
|
171
|
+
export { Tooltip, Tooltip as default };
|
|
172
|
+
|
|
173
|
+
//# sourceMappingURL=Tooltip.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tooltip.js","sources":["../../../../src/react/core/overlays/Tooltip.tsx"],"sourcesContent":["/**\n * @zendir/ui - Tooltip Component\n * \n * Tooltip following Astro UX Design System.\n * Uses a portal to render in document.body, ensuring correct positioning\n * even when the trigger is inside containers with CSS transforms or overflow.\n * \n * @example\n * ```tsx\n * <Tooltip content=\"Click to enable telemetry\">\n * <Button>Enable</Button>\n * </Tooltip>\n * ```\n */\n\nimport React, { memo, useState, useRef, useEffect, useLayoutEffect, useCallback } from 'react';\nimport ReactDOM from 'react-dom';\nimport { useTheme } from '../../theme';\nimport { classNames } from '../../utils';\n\nexport type TooltipPlacement = 'top' | 'bottom' | 'left' | 'right';\n\nexport interface TooltipProps {\n /** Tooltip content */\n content: React.ReactNode;\n /** Placement */\n placement?: TooltipPlacement;\n /** Delay before showing (ms) */\n delay?: number;\n /** Disabled state */\n disabled?: boolean;\n /** Children element to trigger tooltip */\n children: React.ReactElement;\n /** Custom className */\n className?: string;\n}\n\nexport const Tooltip = memo(function Tooltip({\n content,\n placement = 'top',\n delay = 200,\n disabled = false,\n children,\n className = '',\n}: TooltipProps): React.ReactElement {\n const { tokens } = useTheme();\n const [visible, setVisible] = useState(false);\n const [positioned, setPositioned] = useState(false);\n const [position, setPosition] = useState({ top: 0, left: 0 });\n const triggerRef = useRef<HTMLDivElement>(null);\n const tooltipRef = useRef<HTMLDivElement>(null);\n const timeoutRef = useRef<number>();\n const hideTimeoutRef = useRef<number>();\n \n const showTooltip = useCallback(() => {\n if (disabled) return;\n // Cancel any pending hide so moving between trigger ↔ tooltip keeps it open\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = undefined;\n }\n timeoutRef.current = window.setTimeout(() => {\n setVisible(true);\n setPositioned(false);\n }, delay);\n }, [disabled, delay]);\n \n const hideTooltip = useCallback(() => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n // Small delay so user can move pointer from trigger to tooltip (WCAG 1.4.13)\n hideTimeoutRef.current = window.setTimeout(() => {\n setVisible(false);\n setPositioned(false);\n }, 100);\n }, []);\n \n const hideImmediately = useCallback(() => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);\n setVisible(false);\n setPositioned(false);\n }, []);\n \n const calculatePosition = useCallback(() => {\n if (!triggerRef.current || !tooltipRef.current) return;\n \n const triggerRect = triggerRef.current.getBoundingClientRect();\n const tooltipRect = tooltipRef.current.getBoundingClientRect();\n const gap = 8;\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n \n let top = 0;\n let left = 0;\n \n switch (placement) {\n case 'top':\n top = triggerRect.top - tooltipRect.height - gap;\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\n break;\n case 'bottom':\n top = triggerRect.bottom + gap;\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\n break;\n case 'left':\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\n left = triggerRect.left - tooltipRect.width - gap;\n break;\n case 'right':\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\n left = triggerRect.right + gap;\n break;\n }\n \n // Keep tooltip within viewport bounds\n if (left < gap) left = gap;\n if (left + tooltipRect.width > viewportWidth - gap) {\n left = viewportWidth - tooltipRect.width - gap;\n }\n if (top < gap) top = gap;\n if (top + tooltipRect.height > viewportHeight - gap) {\n top = viewportHeight - tooltipRect.height - gap;\n }\n \n setPosition({ top, left });\n setPositioned(true);\n }, [placement]);\n \n // Use useLayoutEffect for initial positioning - runs synchronously\n // before browser paint, preventing flash at wrong position\n useLayoutEffect(() => {\n if (visible && triggerRef.current && tooltipRef.current) {\n calculatePosition();\n }\n }, [visible, calculatePosition]);\n \n // Use useEffect for scroll/resize listeners\n useEffect(() => {\n if (!visible) return;\n \n const handleScrollOrResize = () => {\n calculatePosition();\n };\n \n window.addEventListener('scroll', handleScrollOrResize, true);\n window.addEventListener('resize', handleScrollOrResize);\n \n return () => {\n window.removeEventListener('scroll', handleScrollOrResize, true);\n window.removeEventListener('resize', handleScrollOrResize);\n };\n }, [visible, calculatePosition]);\n \n // Escape key dismisses tooltip (WCAG 1.4.13 Content on Hover or Focus)\n useEffect(() => {\n if (!visible) return;\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n hideImmediately();\n }\n };\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }, [visible, hideImmediately]);\n \n useEffect(() => {\n return () => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);\n };\n }, []);\n \n return (\n <>\n <div\n ref={triggerRef}\n className={classNames('zendir-tooltip-trigger', className)}\n style={{ display: 'inline-flex', pointerEvents: 'auto', maxWidth: '100%', width: 'inherit' }}\n onMouseEnter={showTooltip}\n onMouseLeave={hideTooltip}\n onFocus={showTooltip}\n onBlur={hideTooltip}\n >\n {children}\n </div>\n \n {visible && ReactDOM.createPortal(\n <div\n ref={tooltipRef}\n role=\"tooltip\"\n onMouseEnter={showTooltip}\n onMouseLeave={hideTooltip}\n style={{\n position: 'fixed',\n top: positioned ? position.top : 0,\n left: positioned ? position.left : 0,\n width: 'max-content',\n padding: `${tokens.spacing.sm} ${tokens.spacing.smd}`,\n backgroundColor: tokens.colors.background.elevated,\n color: tokens.colors.text.primary,\n fontSize: '0.75rem',\n fontWeight: 500,\n fontFamily: tokens.typography.fontFamily.primary,\n borderRadius: tokens.borderRadius.md,\n border: `1px solid ${tokens.colors.accent.primary}20`,\n boxShadow: positioned ? `${tokens.shadows.lg}, 0 0 20px ${tokens.colors.accent.primary}10` : 'none',\n zIndex: 2147483100,\n maxWidth: 'min(280px, calc(100vw - 24px))',\n whiteSpace: 'normal',\n pointerEvents: 'auto',\n visibility: positioned ? 'visible' : 'hidden',\n opacity: positioned ? 1 : 0,\n transition: positioned ? undefined : 'none',\n animation: positioned ? `zendir-tooltip ${tokens.animation.duration.fast}ms ${tokens.animation.easing.default} both` : 'none',\n backdropFilter: 'blur(8px)',\n }}\n >\n {content}\n <style>\n {`@keyframes zendir-tooltip { from { opacity: 0; transform: scale(0.95) translateY(${placement === 'bottom' ? '-4px' : placement === 'top' ? '4px' : '0'}); } to { opacity: 1; transform: scale(1) translateY(0); } }\n @media (prefers-reduced-motion: reduce) { @keyframes zendir-tooltip { from, to { opacity: 1; transform: none; } } }`}\n </style>\n </div>,\n document.body\n )}\n </>\n );\n});\n\nexport default Tooltip;\n"],"names":["Tooltip"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Tooltip.js","names":[],"sources":["../../../../src/react/core/overlays/Tooltip.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - Tooltip Component\r\n *\r\n * Tooltip following Astro UX Design System.\r\n * Uses a portal to render in document.body, ensuring correct positioning\r\n * even when the trigger is inside containers with CSS transforms or overflow.\r\n *\r\n * @example\r\n * ```tsx\r\n * <Tooltip content=\"Click to enable telemetry\">\r\n * <Button>Enable</Button>\r\n * </Tooltip>\r\n * ```\r\n */\r\n\r\nimport React, {\r\n memo,\r\n useState,\r\n useRef,\r\n useEffect,\r\n useLayoutEffect,\r\n useCallback,\r\n} from \"react\";\r\nimport ReactDOM from \"react-dom\";\r\nimport { useTheme } from \"../../theme\";\r\nimport { classNames } from \"../../utils\";\r\n\r\nexport type TooltipPlacement = \"top\" | \"bottom\" | \"left\" | \"right\";\r\n\r\nexport interface TooltipProps {\r\n /** Tooltip content */\r\n content: React.ReactNode;\r\n /** Placement */\r\n placement?: TooltipPlacement;\r\n /** Delay before showing (ms) */\r\n delay?: number;\r\n /** Disabled state */\r\n disabled?: boolean;\r\n /** Children element to trigger tooltip */\r\n children: React.ReactElement;\r\n /** Custom className */\r\n className?: string;\r\n}\r\n\r\nexport const Tooltip = memo(function Tooltip({\r\n content,\r\n placement = \"top\",\r\n delay = 200,\r\n disabled = false,\r\n children,\r\n className = \"\",\r\n}: TooltipProps): React.ReactElement {\r\n const { tokens } = useTheme();\r\n const [visible, setVisible] = useState(false);\r\n const [positioned, setPositioned] = useState(false);\r\n const [position, setPosition] = useState({ top: 0, left: 0 });\r\n const triggerRef = useRef<HTMLDivElement>(null);\r\n const tooltipRef = useRef<HTMLDivElement>(null);\r\n const timeoutRef = useRef<number>();\r\n const hideTimeoutRef = useRef<number>();\r\n\r\n const showTooltip = useCallback(() => {\r\n if (disabled) return;\r\n // Cancel any pending hide so moving between trigger ↔ tooltip keeps it open\r\n if (hideTimeoutRef.current) {\r\n clearTimeout(hideTimeoutRef.current);\r\n hideTimeoutRef.current = undefined;\r\n }\r\n timeoutRef.current = window.setTimeout(() => {\r\n setVisible(true);\r\n setPositioned(false);\r\n }, delay);\r\n }, [disabled, delay]);\r\n\r\n const hideTooltip = useCallback(() => {\r\n if (timeoutRef.current) {\r\n clearTimeout(timeoutRef.current);\r\n }\r\n // Small delay so user can move pointer from trigger to tooltip (WCAG 1.4.13)\r\n hideTimeoutRef.current = window.setTimeout(() => {\r\n setVisible(false);\r\n setPositioned(false);\r\n }, 100);\r\n }, []);\r\n\r\n const hideImmediately = useCallback(() => {\r\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\r\n if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);\r\n setVisible(false);\r\n setPositioned(false);\r\n }, []);\r\n\r\n const calculatePosition = useCallback(() => {\r\n if (!triggerRef.current || !tooltipRef.current) return;\r\n\r\n const triggerRect = triggerRef.current.getBoundingClientRect();\r\n const tooltipRect = tooltipRef.current.getBoundingClientRect();\r\n const gap = 8;\r\n const viewportWidth = window.innerWidth;\r\n const viewportHeight = window.innerHeight;\r\n\r\n let top = 0;\r\n let left = 0;\r\n\r\n switch (placement) {\r\n case \"top\":\r\n top = triggerRect.top - tooltipRect.height - gap;\r\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\r\n break;\r\n case \"bottom\":\r\n top = triggerRect.bottom + gap;\r\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\r\n break;\r\n case \"left\":\r\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\r\n left = triggerRect.left - tooltipRect.width - gap;\r\n break;\r\n case \"right\":\r\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\r\n left = triggerRect.right + gap;\r\n break;\r\n }\r\n\r\n // Keep tooltip within viewport bounds\r\n if (left < gap) left = gap;\r\n if (left + tooltipRect.width > viewportWidth - gap) {\r\n left = viewportWidth - tooltipRect.width - gap;\r\n }\r\n if (top < gap) top = gap;\r\n if (top + tooltipRect.height > viewportHeight - gap) {\r\n top = viewportHeight - tooltipRect.height - gap;\r\n }\r\n\r\n setPosition({ top, left });\r\n setPositioned(true);\r\n }, [placement]);\r\n\r\n // Use useLayoutEffect for initial positioning - runs synchronously\r\n // before browser paint, preventing flash at wrong position\r\n useLayoutEffect(() => {\r\n if (visible && triggerRef.current && tooltipRef.current) {\r\n calculatePosition();\r\n }\r\n }, [visible, calculatePosition]);\r\n\r\n // Use useEffect for scroll/resize listeners\r\n useEffect(() => {\r\n if (!visible) return;\r\n\r\n const handleScrollOrResize = () => {\r\n calculatePosition();\r\n };\r\n\r\n window.addEventListener(\"scroll\", handleScrollOrResize, true);\r\n window.addEventListener(\"resize\", handleScrollOrResize);\r\n\r\n return () => {\r\n window.removeEventListener(\"scroll\", handleScrollOrResize, true);\r\n window.removeEventListener(\"resize\", handleScrollOrResize);\r\n };\r\n }, [visible, calculatePosition]);\r\n\r\n // Escape key dismisses tooltip (WCAG 1.4.13 Content on Hover or Focus)\r\n useEffect(() => {\r\n if (!visible) return;\r\n const handleEscape = (e: KeyboardEvent) => {\r\n if (e.key === \"Escape\") {\r\n hideImmediately();\r\n }\r\n };\r\n document.addEventListener(\"keydown\", handleEscape);\r\n return () => document.removeEventListener(\"keydown\", handleEscape);\r\n }, [visible, hideImmediately]);\r\n\r\n useEffect(() => {\r\n return () => {\r\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\r\n if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);\r\n };\r\n }, []);\r\n\r\n return (\r\n <>\r\n <div\r\n ref={triggerRef}\r\n className={classNames(\"zendir-tooltip-trigger\", className)}\r\n style={{\r\n display: \"inline-flex\",\r\n pointerEvents: \"auto\",\r\n maxWidth: \"100%\",\r\n width: \"inherit\",\r\n }}\r\n onMouseEnter={showTooltip}\r\n onMouseLeave={hideTooltip}\r\n onFocus={showTooltip}\r\n onBlur={hideTooltip}\r\n >\r\n {children}\r\n </div>\r\n\r\n {visible &&\r\n ReactDOM.createPortal(\r\n <div\r\n ref={tooltipRef}\r\n role=\"tooltip\"\r\n onMouseEnter={showTooltip}\r\n onMouseLeave={hideTooltip}\r\n style={{\r\n position: \"fixed\",\r\n top: positioned ? position.top : 0,\r\n left: positioned ? position.left : 0,\r\n width: \"max-content\",\r\n padding: `${tokens.spacing.sm} ${tokens.spacing.smd}`,\r\n backgroundColor: tokens.colors.background.elevated,\r\n color: tokens.colors.text.primary,\r\n fontSize: \"0.75rem\",\r\n fontWeight: 500,\r\n fontFamily: tokens.typography.fontFamily.primary,\r\n borderRadius: tokens.borderRadius.md,\r\n border: `1px solid ${tokens.colors.accent.primary}20`,\r\n boxShadow: positioned\r\n ? `${tokens.shadows.lg}, 0 0 20px ${tokens.colors.accent.primary}10`\r\n : \"none\",\r\n zIndex: 2147483100,\r\n maxWidth: \"min(280px, calc(100vw - 24px))\",\r\n whiteSpace: \"normal\",\r\n pointerEvents: \"auto\",\r\n visibility: positioned ? \"visible\" : \"hidden\",\r\n opacity: positioned ? 1 : 0,\r\n transition: positioned ? undefined : \"none\",\r\n animation: positioned\r\n ? `zendir-tooltip ${tokens.animation.duration.fast}ms ${tokens.animation.easing.default} both`\r\n : \"none\",\r\n backdropFilter: \"blur(8px)\",\r\n }}\r\n >\r\n {content}\r\n <style>\r\n {`@keyframes zendir-tooltip { from { opacity: 0; transform: scale(0.95) translateY(${placement === \"bottom\" ? \"-4px\" : placement === \"top\" ? \"4px\" : \"0\"}); } to { opacity: 1; transform: scale(1) translateY(0); } }\r\n @media (prefers-reduced-motion: reduce) { @keyframes zendir-tooltip { from, to { opacity: 1; transform: none; } } }`}\r\n </style>\r\n </div>,\r\n document.body,\r\n )}\r\n </>\r\n );\r\n});\r\n\r\nexport default Tooltip;\r\n"],"mappings":"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"}
|