@zendir/ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/LICENSE +21 -0
- package/README.md +589 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +421 -0
- package/dist/index.js.map +1 -0
- package/dist/react/3d/EarthViewer.d.ts +46 -0
- package/dist/react/3d/EarthViewer.js +836 -0
- package/dist/react/3d/EarthViewer.js.map +1 -0
- package/dist/react/3d/SolarSystemViewer.d.ts +43 -0
- package/dist/react/3d/SolarSystemViewer.js +372 -0
- package/dist/react/3d/SolarSystemViewer.js.map +1 -0
- package/dist/react/3d/ZenSpace3D.d.ts +16 -0
- package/dist/react/3d/ZenSpace3D.js +1253 -0
- package/dist/react/3d/ZenSpace3D.js.map +1 -0
- package/dist/react/3d/ZenSpace3DCesium.d.ts +9 -0
- package/dist/react/3d/ZenSpace3DCesium.js +186 -0
- package/dist/react/3d/ZenSpace3DCesium.js.map +1 -0
- package/dist/react/3d/ZenSpace3DShaders.d.ts +78 -0
- package/dist/react/3d/ZenSpace3DShaders.js +94 -0
- package/dist/react/3d/ZenSpace3DShaders.js.map +1 -0
- package/dist/react/3d/ZenSpace3DTypes.d.ts +614 -0
- package/dist/react/3d/ZenSpace3DUtils.d.ts +183 -0
- package/dist/react/3d/ZenSpace3DUtils.js +213 -0
- package/dist/react/3d/ZenSpace3DUtils.js.map +1 -0
- package/dist/react/3d/index.d.ts +23 -0
- package/dist/react/3d/threeLoader.d.ts +22 -0
- package/dist/react/3d/threeLoader.js +18 -0
- package/dist/react/3d/threeLoader.js.map +1 -0
- package/dist/react/astro/ClassificationBanner.d.ts +25 -0
- package/dist/react/astro/ClassificationBanner.js +83 -0
- package/dist/react/astro/ClassificationBanner.js.map +1 -0
- package/dist/react/astro/GlobalStatusBar.d.ts +42 -0
- package/dist/react/astro/GlobalStatusBar.js +165 -0
- package/dist/react/astro/GlobalStatusBar.js.map +1 -0
- package/dist/react/astro/MissionClock.d.ts +169 -0
- package/dist/react/astro/MissionClock.js +411 -0
- package/dist/react/astro/MissionClock.js.map +1 -0
- package/dist/react/astro/MonitoringIcon.d.ts +60 -0
- package/dist/react/astro/MonitoringIcon.js +369 -0
- package/dist/react/astro/MonitoringIcon.js.map +1 -0
- package/dist/react/astro/Notification.d.ts +42 -0
- package/dist/react/astro/Notification.js +156 -0
- package/dist/react/astro/Notification.js.map +1 -0
- package/dist/react/astro/Progress.d.ts +39 -0
- package/dist/react/astro/Progress.js +149 -0
- package/dist/react/astro/Progress.js.map +1 -0
- package/dist/react/astro/SimulationControls.d.ts +136 -0
- package/dist/react/astro/SimulationControls.js +668 -0
- package/dist/react/astro/SimulationControls.js.map +1 -0
- package/dist/react/astro/StatusIndicator.d.ts +34 -0
- package/dist/react/astro/StatusIndicator.js +189 -0
- package/dist/react/astro/StatusIndicator.js.map +1 -0
- package/dist/react/astro/UnifiedTimeline.d.ts +106 -0
- package/dist/react/astro/UnifiedTimeline.js +1768 -0
- package/dist/react/astro/UnifiedTimeline.js.map +1 -0
- package/dist/react/astro/index.d.ts +63 -0
- package/dist/react/cards/AccessCard.d.ts +37 -0
- package/dist/react/cards/AccessCard.js +410 -0
- package/dist/react/cards/AccessCard.js.map +1 -0
- package/dist/react/cards/OrbitCard.d.ts +31 -0
- package/dist/react/cards/OrbitCard.js +372 -0
- package/dist/react/cards/OrbitCard.js.map +1 -0
- package/dist/react/cards/SpacecraftCard.d.ts +54 -0
- package/dist/react/cards/SpacecraftCard.js +941 -0
- package/dist/react/cards/SpacecraftCard.js.map +1 -0
- package/dist/react/cards/TelemetryCard.d.ts +40 -0
- package/dist/react/cards/TelemetryCard.js +742 -0
- package/dist/react/cards/TelemetryCard.js.map +1 -0
- package/dist/react/cards/TelemetryStreamCard.d.ts +59 -0
- package/dist/react/cards/TelemetryStreamCard.js +309 -0
- package/dist/react/cards/TelemetryStreamCard.js.map +1 -0
- package/dist/react/cards/index.d.ts +13 -0
- package/dist/react/charts/GroundTrackMap.d.ts +112 -0
- package/dist/react/charts/GroundTrackMap.js +1123 -0
- package/dist/react/charts/GroundTrackMap.js.map +1 -0
- package/dist/react/charts/GroundTrackMapLeaflet.d.ts +26 -0
- package/dist/react/charts/GroundTrackMapLeaflet.js +571 -0
- package/dist/react/charts/GroundTrackMapLeaflet.js.map +1 -0
- package/dist/react/charts/groundTrackMapLeafletTiles.d.ts +22 -0
- package/dist/react/charts/groundTrackMapLeafletTiles.js +11 -0
- package/dist/react/charts/groundTrackMapLeafletTiles.js.map +1 -0
- package/dist/react/charts/groundTrackMapLeafletUtils.d.ts +24 -0
- package/dist/react/charts/groundTrackMapLeafletUtils.js +109 -0
- package/dist/react/charts/groundTrackMapLeafletUtils.js.map +1 -0
- package/dist/react/charts/index.d.ts +10 -0
- package/dist/react/charts/unified/AstroChart.d.ts +24 -0
- package/dist/react/charts/unified/AstroChart.js +1405 -0
- package/dist/react/charts/unified/AstroChart.js.map +1 -0
- package/dist/react/charts/unified/PowerOverviewChart.d.ts +73 -0
- package/dist/react/charts/unified/PowerOverviewChart.js +488 -0
- package/dist/react/charts/unified/PowerOverviewChart.js.map +1 -0
- package/dist/react/charts/unified/domain.d.ts +845 -0
- package/dist/react/charts/unified/domain.js +3168 -0
- package/dist/react/charts/unified/domain.js.map +1 -0
- package/dist/react/charts/unified/generators.d.ts +276 -0
- package/dist/react/charts/unified/generators.js +518 -0
- package/dist/react/charts/unified/generators.js.map +1 -0
- package/dist/react/charts/unified/index.d.ts +55 -0
- package/dist/react/charts/unified/presets.d.ts +290 -0
- package/dist/react/charts/unified/presets.js +999 -0
- package/dist/react/charts/unified/presets.js.map +1 -0
- package/dist/react/charts/unified/sync.d.ts +69 -0
- package/dist/react/charts/unified/sync.js +219 -0
- package/dist/react/charts/unified/sync.js.map +1 -0
- package/dist/react/charts/unified/theme.d.ts +447 -0
- package/dist/react/charts/unified/theme.js +562 -0
- package/dist/react/charts/unified/theme.js.map +1 -0
- package/dist/react/charts/unified/types.d.ts +826 -0
- package/dist/react/charts/unified/useChartStream.d.ts +58 -0
- package/dist/react/charts/unified/useChartStream.js +226 -0
- package/dist/react/charts/unified/useChartStream.js.map +1 -0
- package/dist/react/chatgpt/AppCard.d.ts +59 -0
- package/dist/react/chatgpt/AppCard.js +306 -0
- package/dist/react/chatgpt/AppCard.js.map +1 -0
- package/dist/react/chatgpt/ChatGPTCard.d.ts +6 -0
- package/dist/react/chatgpt/index.d.ts +167 -0
- package/dist/react/chatgpt/index.js +166 -0
- package/dist/react/chatgpt/index.js.map +1 -0
- package/dist/react/context/DisplaySettingsContext.d.ts +107 -0
- package/dist/react/context/DisplaySettingsContext.js +169 -0
- package/dist/react/context/DisplaySettingsContext.js.map +1 -0
- package/dist/react/context/index.d.ts +5 -0
- package/dist/react/core/ActivityPlanner.d.ts +45 -0
- package/dist/react/core/ActivityPlanner.js +532 -0
- package/dist/react/core/ActivityPlanner.js.map +1 -0
- package/dist/react/core/AppBar.d.ts +71 -0
- package/dist/react/core/AppBar.js +817 -0
- package/dist/react/core/AppBar.js.map +1 -0
- package/dist/react/core/AstroIcon.d.ts +84 -0
- package/dist/react/core/AstroIcon.js +1243 -0
- package/dist/react/core/AstroIcon.js.map +1 -0
- package/dist/react/core/Badge.d.ts +27 -0
- package/dist/react/core/Badge.js +134 -0
- package/dist/react/core/Badge.js.map +1 -0
- package/dist/react/core/Button.d.ts +26 -0
- package/dist/react/core/Button.js +306 -0
- package/dist/react/core/Button.js.map +1 -0
- package/dist/react/core/CardHeader.d.ts +34 -0
- package/dist/react/core/CardHeader.js +316 -0
- package/dist/react/core/CardHeader.js.map +1 -0
- package/dist/react/core/ChatPanel.d.ts +627 -0
- package/dist/react/core/ChatPanel.js +1144 -0
- package/dist/react/core/ChatPanel.js.map +1 -0
- package/dist/react/core/Checkbox.d.ts +26 -0
- package/dist/react/core/Checkbox.js +130 -0
- package/dist/react/core/Checkbox.js.map +1 -0
- package/dist/react/core/ColorPickerPanel.d.ts +25 -0
- package/dist/react/core/ColorPickerPanel.js +293 -0
- package/dist/react/core/ColorPickerPanel.js.map +1 -0
- package/dist/react/core/CommandBuilder.d.ts +74 -0
- package/dist/react/core/CommandBuilder.js +518 -0
- package/dist/react/core/CommandBuilder.js.map +1 -0
- package/dist/react/core/ConfirmDialog.d.ts +45 -0
- package/dist/react/core/ConfirmDialog.js +315 -0
- package/dist/react/core/ConfirmDialog.js.map +1 -0
- package/dist/react/core/ConnectionForm.d.ts +57 -0
- package/dist/react/core/ConnectionForm.js +496 -0
- package/dist/react/core/ConnectionForm.js.map +1 -0
- package/dist/react/core/Container.d.ts +51 -0
- package/dist/react/core/Container.js +670 -0
- package/dist/react/core/Container.js.map +1 -0
- package/dist/react/core/CopyButton.d.ts +39 -0
- package/dist/react/core/CopyButton.js +105 -0
- package/dist/react/core/CopyButton.js.map +1 -0
- package/dist/react/core/DataTable.d.ts +113 -0
- package/dist/react/core/DataTable.js +446 -0
- package/dist/react/core/DataTable.js.map +1 -0
- package/dist/react/core/DataValue.d.ts +64 -0
- package/dist/react/core/DataValue.js +545 -0
- package/dist/react/core/DataValue.js.map +1 -0
- package/dist/react/core/Dialog.d.ts +32 -0
- package/dist/react/core/Dialog.js +201 -0
- package/dist/react/core/Dialog.js.map +1 -0
- package/dist/react/core/FileExplorer.d.ts +65 -0
- package/dist/react/core/FileExplorer.js +520 -0
- package/dist/react/core/FileExplorer.js.map +1 -0
- package/dist/react/core/GlassCard.d.ts +129 -0
- package/dist/react/core/GlassCard.js +375 -0
- package/dist/react/core/GlassCard.js.map +1 -0
- package/dist/react/core/HeaderIconWithStatus.d.ts +39 -0
- package/dist/react/core/HeaderIconWithStatus.js +157 -0
- package/dist/react/core/HeaderIconWithStatus.js.map +1 -0
- package/dist/react/core/HexViewer.d.ts +143 -0
- package/dist/react/core/HexViewer.js +1106 -0
- package/dist/react/core/HexViewer.js.map +1 -0
- package/dist/react/core/Icon.d.ts +32 -0
- package/dist/react/core/Icon.js +142 -0
- package/dist/react/core/Icon.js.map +1 -0
- package/dist/react/core/ImageGallery.d.ts +41 -0
- package/dist/react/core/ImageGallery.js +320 -0
- package/dist/react/core/ImageGallery.js.map +1 -0
- package/dist/react/core/Input.d.ts +38 -0
- package/dist/react/core/Input.js +288 -0
- package/dist/react/core/Input.js.map +1 -0
- package/dist/react/core/LimitsBar.d.ts +51 -0
- package/dist/react/core/LimitsBar.js +200 -0
- package/dist/react/core/LimitsBar.js.map +1 -0
- package/dist/react/core/LogViewer.d.ts +61 -0
- package/dist/react/core/LogViewer.js +599 -0
- package/dist/react/core/LogViewer.js.map +1 -0
- package/dist/react/core/MessageStream.d.ts +58 -0
- package/dist/react/core/MessageStream.js +455 -0
- package/dist/react/core/MessageStream.js.map +1 -0
- package/dist/react/core/MissionCalendar.d.ts +81 -0
- package/dist/react/core/MissionCalendar.js +1049 -0
- package/dist/react/core/MissionCalendar.js.map +1 -0
- package/dist/react/core/NumberInput.d.ts +85 -0
- package/dist/react/core/NumberInput.js +507 -0
- package/dist/react/core/NumberInput.js.map +1 -0
- package/dist/react/core/PacketViewer.d.ts +73 -0
- package/dist/react/core/PacketViewer.js +431 -0
- package/dist/react/core/PacketViewer.js.map +1 -0
- package/dist/react/core/Pagination.d.ts +30 -0
- package/dist/react/core/Pagination.js +190 -0
- package/dist/react/core/Pagination.js.map +1 -0
- package/dist/react/core/PinInput.d.ts +41 -0
- package/dist/react/core/PinInput.js +210 -0
- package/dist/react/core/PinInput.js.map +1 -0
- package/dist/react/core/Popover.d.ts +55 -0
- package/dist/react/core/Popover.js +288 -0
- package/dist/react/core/Popover.js.map +1 -0
- package/dist/react/core/Select.d.ts +42 -0
- package/dist/react/core/Select.js +303 -0
- package/dist/react/core/Select.js.map +1 -0
- package/dist/react/core/SideNav.d.ts +103 -0
- package/dist/react/core/SideNav.js +551 -0
- package/dist/react/core/SideNav.js.map +1 -0
- package/dist/react/core/SidePanel.d.ts +33 -0
- package/dist/react/core/SidePanel.js +199 -0
- package/dist/react/core/SidePanel.js.map +1 -0
- package/dist/react/core/Tabs.d.ts +47 -0
- package/dist/react/core/Tabs.js +129 -0
- package/dist/react/core/Tabs.js.map +1 -0
- package/dist/react/core/Toast.d.ts +56 -0
- package/dist/react/core/Toast.js +229 -0
- package/dist/react/core/Toast.js.map +1 -0
- package/dist/react/core/Toggle.d.ts +22 -0
- package/dist/react/core/Toggle.js +151 -0
- package/dist/react/core/Toggle.js.map +1 -0
- package/dist/react/core/Tooltip.d.ts +19 -0
- package/dist/react/core/Tooltip.js +179 -0
- package/dist/react/core/Tooltip.js.map +1 -0
- package/dist/react/core/Typography.d.ts +127 -0
- package/dist/react/core/Typography.js +187 -0
- package/dist/react/core/Typography.js.map +1 -0
- package/dist/react/core/index.d.ts +108 -0
- package/dist/react/core/layout/Box.d.ts +77 -0
- package/dist/react/core/layout/Box.js +126 -0
- package/dist/react/core/layout/Box.js.map +1 -0
- package/dist/react/core/layout/Center.d.ts +20 -0
- package/dist/react/core/layout/Center.js +34 -0
- package/dist/react/core/layout/Center.js.map +1 -0
- package/dist/react/core/layout/Divider.d.ts +16 -0
- package/dist/react/core/layout/Divider.js +108 -0
- package/dist/react/core/layout/Divider.js.map +1 -0
- package/dist/react/core/layout/Flex.d.ts +30 -0
- package/dist/react/core/layout/Flex.js +128 -0
- package/dist/react/core/layout/Flex.js.map +1 -0
- package/dist/react/core/layout/Grid.d.ts +36 -0
- package/dist/react/core/layout/Grid.js +142 -0
- package/dist/react/core/layout/Grid.js.map +1 -0
- package/dist/react/core/layout/Spacer.d.ts +8 -0
- package/dist/react/core/layout/Spacer.js +31 -0
- package/dist/react/core/layout/Spacer.js.map +1 -0
- package/dist/react/core/layout/Stack.d.ts +54 -0
- package/dist/react/core/layout/Stack.js +74 -0
- package/dist/react/core/layout/Stack.js.map +1 -0
- package/dist/react/core/layout/index.d.ts +38 -0
- package/dist/react/core/layout/responsive.d.ts +23 -0
- package/dist/react/core/layout/responsive.js +26 -0
- package/dist/react/core/layout/responsive.js.map +1 -0
- package/dist/react/core/layout/useBreakpoint.d.ts +77 -0
- package/dist/react/core/layout/useBreakpoint.js +73 -0
- package/dist/react/core/layout/useBreakpoint.js.map +1 -0
- package/dist/react/core/propertyConfig.d.ts +443 -0
- package/dist/react/core/propertyConfig.js +399 -0
- package/dist/react/core/propertyConfig.js.map +1 -0
- package/dist/react/hooks/index.d.ts +21 -0
- package/dist/react/hooks/useAccessWindows.d.ts +66 -0
- package/dist/react/hooks/useCompactMode.d.ts +82 -0
- package/dist/react/hooks/useCompactMode.js +62 -0
- package/dist/react/hooks/useCompactMode.js.map +1 -0
- package/dist/react/hooks/useLiveSelection.d.ts +57 -0
- package/dist/react/hooks/useSimulationPlayback.d.ts +97 -0
- package/dist/react/hooks/useSimulationTime.d.ts +61 -0
- package/dist/react/hooks/useSpacecraftPosition.d.ts +50 -0
- package/dist/react/hooks/useSpacecraftPosition.js +89 -0
- package/dist/react/hooks/useSpacecraftPosition.js.map +1 -0
- package/dist/react/hooks/useTelemetry.d.ts +55 -0
- package/dist/react/hooks/useTelemetry.js +73 -0
- package/dist/react/hooks/useTelemetry.js.map +1 -0
- package/dist/react/hooks/useZendirSession.d.ts +109 -0
- package/dist/react/hooks/useZendirSession.js +148 -0
- package/dist/react/hooks/useZendirSession.js.map +1 -0
- package/dist/react/index.d.ts +74 -0
- package/dist/react/shared/ErrorBoundary.d.ts +63 -0
- package/dist/react/shared/ErrorBoundary.js +142 -0
- package/dist/react/shared/ErrorBoundary.js.map +1 -0
- package/dist/react/shared/Skeleton.d.ts +110 -0
- package/dist/react/shared/Skeleton.js +324 -0
- package/dist/react/shared/Skeleton.js.map +1 -0
- package/dist/react/shared/index.d.ts +12 -0
- package/dist/react/theme/ThemeProvider.d.ts +385 -0
- package/dist/react/theme/ThemeProvider.js +1096 -0
- package/dist/react/theme/ThemeProvider.js.map +1 -0
- package/dist/react/theme/astro-tokens.d.ts +153 -0
- package/dist/react/theme/cardAccent.d.ts +75 -0
- package/dist/react/theme/cardAccent.js +137 -0
- package/dist/react/theme/cardAccent.js.map +1 -0
- package/dist/react/theme/config.d.ts +39 -0
- package/dist/react/theme/index.d.ts +9 -0
- package/dist/react/types.d.ts +360 -0
- package/dist/react/types.js +58 -0
- package/dist/react/types.js.map +1 -0
- package/dist/react/utils/index.d.ts +247 -0
- package/dist/react/utils/index.js +423 -0
- package/dist/react/utils/index.js.map +1 -0
- package/dist/react/visualizations/EclipseTimerCard.d.ts +17 -0
- package/dist/react/visualizations/EclipseTimerCard.js +250 -0
- package/dist/react/visualizations/EclipseTimerCard.js.map +1 -0
- package/dist/react/visualizations/LinkBudgetCard.d.ts +50 -0
- package/dist/react/visualizations/LinkBudgetCard.js +444 -0
- package/dist/react/visualizations/LinkBudgetCard.js.map +1 -0
- package/dist/react/visualizations/NavBallCard.d.ts +17 -0
- package/dist/react/visualizations/NavBallCard.js +243 -0
- package/dist/react/visualizations/NavBallCard.js.map +1 -0
- package/dist/react/visualizations/PropulsionCard.d.ts +37 -0
- package/dist/react/visualizations/PropulsionCard.js +298 -0
- package/dist/react/visualizations/PropulsionCard.js.map +1 -0
- package/dist/react/visualizations/SensorFootprintCard.d.ts +33 -0
- package/dist/react/visualizations/SensorFootprintCard.js +326 -0
- package/dist/react/visualizations/SensorFootprintCard.js.map +1 -0
- package/dist/react/visualizations/ThermalHeatmapCard.d.ts +38 -0
- package/dist/react/visualizations/ThermalHeatmapCard.js +372 -0
- package/dist/react/visualizations/ThermalHeatmapCard.js.map +1 -0
- package/dist/react/visualizations/index.d.ts +17 -0
- package/dist/react.d.ts +1 -0
- package/dist/react.js +421 -0
- package/dist/react.js.map +1 -0
- package/dist/shaders/atmosphere.frag.js +5 -0
- package/dist/shaders/atmosphere.frag.js.map +1 -0
- package/dist/shaders/atmosphere.vert.js +5 -0
- package/dist/shaders/atmosphere.vert.js.map +1 -0
- package/dist/shaders/stars.frag.js +5 -0
- package/dist/shaders/stars.frag.js.map +1 -0
- package/dist/shaders/stars.vert.js +5 -0
- package/dist/shaders/stars.vert.js.map +1 -0
- package/dist/style.css +143 -0
- package/dist/tokens/index.d.ts +296 -0
- package/dist/tokens/index.js +263 -0
- package/dist/tokens/index.js.map +1 -0
- package/dist/tokens/tokens.css +155 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +220 -0
- package/sdk-stub.js +22 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCompactMode.js","sources":["../../../src/react/hooks/useCompactMode.ts"],"sourcesContent":["/**\n * @zendir/ui - useCompactMode Hook\n * \n * Provides compact mode functionality for data cards with:\n * - Hover-to-expand behavior\n * - Click-to-pin (stays expanded until clicked again)\n * - Keyboard accessibility (Enter/Space to toggle pin)\n * - Reduced motion support\n * - Integration with DisplaySettingsContext for global compact mode\n * \n * Priority for compact mode:\n * 1. Explicit `compact` prop (if provided)\n * 2. Global compact mode from DisplaySettingsContext\n * 3. Default: false\n * \n * Usage:\n * ```tsx\n * const { expanded, isPinned, handlers, transitionDuration } = useCompactMode({\n * compact: true, // Optional - if omitted, uses global setting\n * defaultExpanded: false,\n * onPinChange: (pinned) => {},\n * });\n * \n * return (\n * <div {...handlers}>\n * {expanded ? <FullContent /> : <CompactContent />}\n * </div>\n * );\n * ```\n */\n\nimport { useState, useCallback, useMemo } from 'react';\nimport { useTheme } from '../theme';\nimport { useDisplaySettingsOptional } from '../context/DisplaySettingsContext';\n\n/**\n * Options for useCompactMode hook\n */\nexport interface UseCompactModeOptions {\n /** Whether compact mode is enabled */\n compact?: boolean;\n /** Start in expanded (pinned) state */\n defaultExpanded?: boolean;\n /** Callback when pin state changes */\n onPinChange?: (isPinned: boolean) => void;\n}\n\n/**\n * Result from useCompactMode hook\n */\nexport interface UseCompactModeResult {\n /** Whether the component should render in expanded state */\n expanded: boolean;\n /** Whether the component is pinned (clicked to stay expanded) */\n isPinned: boolean;\n /** Whether the component is being hovered */\n isHovered: boolean;\n /** Whether compact mode is active */\n isCompact: boolean;\n /** Event handlers to spread on the container element */\n handlers: {\n onMouseEnter: () => void;\n onMouseLeave: () => void;\n onClick: () => void;\n onKeyDown: (e: React.KeyboardEvent) => void;\n tabIndex: number;\n role: string;\n 'aria-expanded': boolean;\n };\n /** Transition duration respecting reduced motion */\n transitionDuration: string;\n /** Toggle the pinned state programmatically */\n togglePin: () => void;\n /** Set pinned state programmatically */\n setPin: (pinned: boolean) => void;\n}\n\n/**\n * Hook for managing compact mode state and interactions\n * \n * Provides hover-to-expand and click-to-pin functionality with\n * full keyboard accessibility and reduced motion support.\n * \n * Priority for compact mode:\n * 1. Explicit `compact` prop (if provided)\n * 2. Global compact mode from DisplaySettingsContext\n * 3. Default: false\n */\nexport function useCompactMode(options: UseCompactModeOptions = {}): UseCompactModeResult {\n const { compact: compactProp, defaultExpanded = false, onPinChange } = options;\n const { prefersReducedMotion } = useTheme();\n const displaySettings = useDisplaySettingsOptional();\n \n // Resolve compact mode: prop > context > default (false)\n const compact = compactProp ?? displaySettings?.compactMode ?? false;\n \n const [isHovered, setIsHovered] = useState(false);\n const [isPinned, setIsPinned] = useState(defaultExpanded);\n \n // Transition duration respects reduced motion preference\n const transitionDuration = prefersReducedMotion ? '0ms' : '200ms';\n \n // Expanded state: pinned OR hovered (only matters when compact is true)\n const expanded = !compact || isPinned || isHovered;\n \n // Toggle pin state\n const togglePin = useCallback(() => {\n const newPinned = !isPinned;\n setIsPinned(newPinned);\n onPinChange?.(newPinned);\n }, [isPinned, onPinChange]);\n \n // Set pin state directly\n const setPin = useCallback((pinned: boolean) => {\n setIsPinned(pinned);\n onPinChange?.(pinned);\n }, [onPinChange]);\n \n // Mouse enter handler\n const onMouseEnter = useCallback(() => {\n setIsHovered(true);\n }, []);\n \n // Mouse leave handler\n const onMouseLeave = useCallback(() => {\n setIsHovered(false);\n }, []);\n \n // Click handler - toggle pin state when in compact mode\n const onClick = useCallback(() => {\n if (compact) {\n togglePin();\n }\n }, [compact, togglePin]);\n \n // Keyboard handler for accessibility\n const onKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (compact && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault();\n togglePin();\n }\n }, [compact, togglePin]);\n \n // Memoized handlers object\n const handlers = useMemo(() => ({\n onMouseEnter,\n onMouseLeave,\n onClick,\n onKeyDown,\n tabIndex: compact ? 0 : -1,\n role: compact ? 'button' : 'article',\n 'aria-expanded': expanded,\n }), [onMouseEnter, onMouseLeave, onClick, onKeyDown, compact, expanded]);\n \n return {\n expanded,\n isPinned,\n isHovered,\n isCompact: compact,\n handlers,\n transitionDuration,\n togglePin,\n setPin,\n };\n}\n"],"names":[],"mappings":";;;AAwFO,SAAS,eAAe,UAAiC,IAA0B;AACxF,QAAM,EAAE,SAAS,aAAa,kBAAkB,OAAO,gBAAgB;AACvE,QAAM,EAAE,qBAAA,IAAyB,SAAA;AACjC,QAAM,kBAAkB,2BAAA;AAGxB,QAAM,UAAU,gBAAe,mDAAiB,gBAAe;AAE/D,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,eAAe;AAGxD,QAAM,qBAAqB,uBAAuB,QAAQ;AAG1D,QAAM,WAAW,CAAC,WAAW,YAAY;AAGzC,QAAM,YAAY,YAAY,MAAM;AAClC,UAAM,YAAY,CAAC;AACnB,gBAAY,SAAS;AACrB,+CAAc;AAAA,EAChB,GAAG,CAAC,UAAU,WAAW,CAAC;AAG1B,QAAM,SAAS,YAAY,CAAC,WAAoB;AAC9C,gBAAY,MAAM;AAClB,+CAAc;AAAA,EAChB,GAAG,CAAC,WAAW,CAAC;AAGhB,QAAM,eAAe,YAAY,MAAM;AACrC,iBAAa,IAAI;AAAA,EACnB,GAAG,CAAA,CAAE;AAGL,QAAM,eAAe,YAAY,MAAM;AACrC,iBAAa,KAAK;AAAA,EACpB,GAAG,CAAA,CAAE;AAGL,QAAM,UAAU,YAAY,MAAM;AAChC,QAAI,SAAS;AACX,gBAAA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,SAAS,SAAS,CAAC;AAGvB,QAAM,YAAY,YAAY,CAAC,MAA2B;AACxD,QAAI,YAAY,EAAE,QAAQ,WAAW,EAAE,QAAQ,MAAM;AACnD,QAAE,eAAA;AACF,gBAAA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,SAAS,SAAS,CAAC;AAGvB,QAAM,WAAW,QAAQ,OAAO;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,UAAU,IAAI;AAAA,IACxB,MAAM,UAAU,WAAW;AAAA,IAC3B,iBAAiB;AAAA,EAAA,IACf,CAAC,cAAc,cAAc,SAAS,WAAW,SAAS,QAAQ,CAAC;AAEvE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @zendir/ui - useLiveSelection Hook
|
|
3
|
+
*
|
|
4
|
+
* Manages "live follow" vs "pinned" selection for any streaming list.
|
|
5
|
+
*
|
|
6
|
+
* Behaviour:
|
|
7
|
+
* - **Live mode** (default): the selection automatically tracks the newest
|
|
8
|
+
* item in the list (index 0 after sorting newest-first).
|
|
9
|
+
* - **Pinned mode**: the user has manually selected an item. The list can
|
|
10
|
+
* continue to receive new items but the highlighted row stays fixed on the
|
|
11
|
+
* chosen packet until the user explicitly resumes live follow.
|
|
12
|
+
* - **Paused mode**: live updates to the list are frozen externally (handled
|
|
13
|
+
* by the caller). Pinned selection is preserved across pause/resume.
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* ```ts
|
|
17
|
+
* const { selectedId, isLive, isPinned, pin, resume } = useLiveSelection({
|
|
18
|
+
* items: filteredPackets,
|
|
19
|
+
* getId: getPacketId,
|
|
20
|
+
* isPaused,
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export interface UseLiveSelectionOptions<T> {
|
|
25
|
+
/** The current (possibly filtered) ordered list, newest first. */
|
|
26
|
+
items: T[];
|
|
27
|
+
/** Derive a stable string identity from an item. */
|
|
28
|
+
getId: (item: T) => string | null;
|
|
29
|
+
/**
|
|
30
|
+
* When true, the caller is freezing new items from being added.
|
|
31
|
+
* useLiveSelection will not try to auto-follow while paused.
|
|
32
|
+
*/
|
|
33
|
+
isPaused: boolean;
|
|
34
|
+
}
|
|
35
|
+
export interface UseLiveSelectionResult<T> {
|
|
36
|
+
/** The stable id of the currently selected item (null = nothing selected). */
|
|
37
|
+
selectedId: string | null;
|
|
38
|
+
/** The currently selected item, or null. */
|
|
39
|
+
selectedItem: T | null;
|
|
40
|
+
/** Index of the selected item within `items` (−1 if not found). */
|
|
41
|
+
selectedIndex: number;
|
|
42
|
+
/** True when auto-following the newest item. False when user has pinned a selection. */
|
|
43
|
+
isLive: boolean;
|
|
44
|
+
/** True when the user has manually pinned a specific item. */
|
|
45
|
+
isPinned: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Call this when the user manually clicks a row.
|
|
48
|
+
* Switches to pinned mode and locks the given item as the selection.
|
|
49
|
+
*/
|
|
50
|
+
pin: (item: T) => void;
|
|
51
|
+
/**
|
|
52
|
+
* Call this to return to live-follow mode.
|
|
53
|
+
* Clears the pinned selection and immediately selects the newest item.
|
|
54
|
+
*/
|
|
55
|
+
resume: () => void;
|
|
56
|
+
}
|
|
57
|
+
export declare function useLiveSelection<T>({ items, getId, isPaused, }: UseLiveSelectionOptions<T>): UseLiveSelectionResult<T>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @zendir/ui - useSimulationPlayback Hook
|
|
3
|
+
*
|
|
4
|
+
* Hook for managing simulation playback state with play/pause/stop controls.
|
|
5
|
+
* Designed to work seamlessly with SimulationControls component.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Play/pause/stop state management
|
|
9
|
+
* - Configurable time scale (playback speed)
|
|
10
|
+
* - Step forward/backward functionality
|
|
11
|
+
* - Automatic time updates when playing
|
|
12
|
+
* - Zendir SDK integration ready
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* const sim = useSimulationPlayback({
|
|
17
|
+
* epoch: new Date('2026-01-01T00:00:00Z'),
|
|
18
|
+
* initialElapsedSeconds: 0,
|
|
19
|
+
* initialTimeScale: 1,
|
|
20
|
+
* stepSize: 60, // 1 minute steps
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* <SimulationControls
|
|
24
|
+
* isPlaying={sim.isPlaying}
|
|
25
|
+
* onPlay={sim.play}
|
|
26
|
+
* onPause={sim.pause}
|
|
27
|
+
* onStop={sim.stop}
|
|
28
|
+
* onStepForward={sim.stepForward}
|
|
29
|
+
* onStepBackward={sim.stepBackward}
|
|
30
|
+
* currentTime={sim.currentTime}
|
|
31
|
+
* epoch={sim.epoch}
|
|
32
|
+
* elapsedSeconds={sim.elapsedSeconds}
|
|
33
|
+
* timeScale={sim.timeScale}
|
|
34
|
+
* onTimeScaleChange={sim.setTimeScale}
|
|
35
|
+
* />
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export interface UseSimulationPlaybackOptions {
|
|
39
|
+
/** Simulation epoch (t=0). Defaults to current date at midnight UTC. */
|
|
40
|
+
epoch?: Date | string;
|
|
41
|
+
/** Initial elapsed seconds from epoch. Defaults to 0. */
|
|
42
|
+
initialElapsedSeconds?: number;
|
|
43
|
+
/** Initial time scale factor. Defaults to 1 (realtime). */
|
|
44
|
+
initialTimeScale?: number;
|
|
45
|
+
/** Step size in seconds for step forward/backward. Defaults to 60 (1 minute). */
|
|
46
|
+
stepSize?: number;
|
|
47
|
+
/** Update interval in milliseconds. Defaults to 1000. */
|
|
48
|
+
updateInterval?: number;
|
|
49
|
+
/** Callback when state changes */
|
|
50
|
+
onChange?: (state: SimulationPlaybackState) => void;
|
|
51
|
+
/** Maximum elapsed seconds (optional upper bound) */
|
|
52
|
+
maxElapsedSeconds?: number;
|
|
53
|
+
/** Whether to loop back to start when max is reached */
|
|
54
|
+
loop?: boolean;
|
|
55
|
+
}
|
|
56
|
+
export interface SimulationPlaybackState {
|
|
57
|
+
/** Whether simulation is currently playing */
|
|
58
|
+
isPlaying: boolean;
|
|
59
|
+
/** Whether simulation is paused (not playing but not at start) */
|
|
60
|
+
isPaused: boolean;
|
|
61
|
+
/** Whether simulation is stopped (at start position) */
|
|
62
|
+
isStopped: boolean;
|
|
63
|
+
/** Current time scale factor (playback speed) */
|
|
64
|
+
timeScale: number;
|
|
65
|
+
/** Simulation epoch (t=0) */
|
|
66
|
+
epoch: Date;
|
|
67
|
+
/** Elapsed seconds from epoch */
|
|
68
|
+
elapsedSeconds: number;
|
|
69
|
+
/** Current simulation time as Date */
|
|
70
|
+
currentTime: Date;
|
|
71
|
+
/** Step size in seconds */
|
|
72
|
+
stepSize: number;
|
|
73
|
+
}
|
|
74
|
+
export interface UseSimulationPlaybackResult extends SimulationPlaybackState {
|
|
75
|
+
/** Start playing the simulation */
|
|
76
|
+
play: () => void;
|
|
77
|
+
/** Pause the simulation */
|
|
78
|
+
pause: () => void;
|
|
79
|
+
/** Stop and reset to start */
|
|
80
|
+
stop: () => void;
|
|
81
|
+
/** Toggle play/pause state */
|
|
82
|
+
toggle: () => void;
|
|
83
|
+
/** Step forward by stepSize seconds */
|
|
84
|
+
stepForward: () => void;
|
|
85
|
+
/** Step backward by stepSize seconds */
|
|
86
|
+
stepBackward: () => void;
|
|
87
|
+
/** Set time scale (playback speed) */
|
|
88
|
+
setTimeScale: (scale: number) => void;
|
|
89
|
+
/** Set step size in seconds */
|
|
90
|
+
setStepSize: (size: number) => void;
|
|
91
|
+
/** Jump to a specific elapsed time in seconds */
|
|
92
|
+
seekTo: (seconds: number) => void;
|
|
93
|
+
/** Set the epoch (resets elapsed time to 0) */
|
|
94
|
+
setEpoch: (epoch: Date | string) => void;
|
|
95
|
+
}
|
|
96
|
+
export declare function useSimulationPlayback(options?: UseSimulationPlaybackOptions): UseSimulationPlaybackResult;
|
|
97
|
+
export default useSimulationPlayback;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @zendir/ui - useSimulationTime Hook
|
|
3
|
+
*
|
|
4
|
+
* Hook for integrating with Zendir SDK simulation time.
|
|
5
|
+
* Provides real-time simulation epoch and elapsed time for MissionClock
|
|
6
|
+
* and other time-sensitive components.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Automatic SDK detection (graceful fallback when SDK not available)
|
|
10
|
+
* - Real-time simulation time updates
|
|
11
|
+
* - MET (Mission Elapsed Time) calculation
|
|
12
|
+
* - Time scaling support
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* const { simulationTime, epoch, elapsedSeconds, isConnected } = useSimulationTime({
|
|
17
|
+
* updateInterval: 1000,
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* <MissionClock
|
|
21
|
+
* timeSource="simulation"
|
|
22
|
+
* simulationConfig={{
|
|
23
|
+
* epoch,
|
|
24
|
+
* elapsedSeconds,
|
|
25
|
+
* isRunning: isConnected,
|
|
26
|
+
* }}
|
|
27
|
+
* />
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export interface SimulationTimeState {
|
|
31
|
+
/** Current simulation time as Date */
|
|
32
|
+
simulationTime: Date;
|
|
33
|
+
/** Simulation epoch (t=0) */
|
|
34
|
+
epoch: Date | null;
|
|
35
|
+
/** Elapsed seconds since epoch */
|
|
36
|
+
elapsedSeconds: number;
|
|
37
|
+
/** Time scale factor (1 = realtime) */
|
|
38
|
+
timeScale: number;
|
|
39
|
+
/** Whether simulation is running */
|
|
40
|
+
isRunning: boolean;
|
|
41
|
+
/** Whether connected to Zendir SDK */
|
|
42
|
+
isConnected: boolean;
|
|
43
|
+
/** Whether SDK is available */
|
|
44
|
+
isSdkAvailable: boolean;
|
|
45
|
+
/** Error message if any */
|
|
46
|
+
error: string | null;
|
|
47
|
+
}
|
|
48
|
+
export interface UseSimulationTimeOptions {
|
|
49
|
+
/** Update interval in milliseconds (default: 1000) */
|
|
50
|
+
updateInterval?: number;
|
|
51
|
+
/** Custom simulation epoch (for manual mode without SDK) */
|
|
52
|
+
manualEpoch?: Date;
|
|
53
|
+
/** Manual elapsed seconds (for manual mode without SDK) */
|
|
54
|
+
manualElapsedSeconds?: number;
|
|
55
|
+
/** Manual time scale (for manual mode without SDK) */
|
|
56
|
+
manualTimeScale?: number;
|
|
57
|
+
/** Custom time provider function */
|
|
58
|
+
customTimeProvider?: () => Date;
|
|
59
|
+
}
|
|
60
|
+
export declare function useSimulationTime(options?: UseSimulationTimeOptions): SimulationTimeState;
|
|
61
|
+
export default useSimulationTime;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { SpacecraftPosition } from '../types';
|
|
2
|
+
|
|
3
|
+
export type { SpacecraftPosition };
|
|
4
|
+
/**
|
|
5
|
+
* Compact ground track point for real-time orbit visualization
|
|
6
|
+
* Uses abbreviated property names for performance in streaming contexts
|
|
7
|
+
* Note: For full ground track data, use GroundTrackPoint from '../types'
|
|
8
|
+
*/
|
|
9
|
+
export interface CompactGroundTrackPoint {
|
|
10
|
+
/** Latitude in degrees */
|
|
11
|
+
lat: number;
|
|
12
|
+
/** Longitude in degrees */
|
|
13
|
+
lon: number;
|
|
14
|
+
/** Timestamp (epoch ms or ISO string) */
|
|
15
|
+
t: number;
|
|
16
|
+
}
|
|
17
|
+
/** Client interface (compatible with @zendir/sdk ZendirClient) */
|
|
18
|
+
export interface PositionClientInterface {
|
|
19
|
+
fetchSpacecraftPositions: () => Promise<SpacecraftPosition[]>;
|
|
20
|
+
}
|
|
21
|
+
export interface UseSpacecraftPositionOptions {
|
|
22
|
+
/** Zendir client instance (or any compatible client) */
|
|
23
|
+
client: PositionClientInterface;
|
|
24
|
+
/** Polling interval in ms (default: 1000) */
|
|
25
|
+
interval?: number;
|
|
26
|
+
/** Enable polling */
|
|
27
|
+
enabled?: boolean;
|
|
28
|
+
/** Track ground track history */
|
|
29
|
+
trackHistory?: boolean;
|
|
30
|
+
/** Maximum history points */
|
|
31
|
+
maxHistory?: number;
|
|
32
|
+
}
|
|
33
|
+
export interface UseSpacecraftPositionResult {
|
|
34
|
+
/** All spacecraft positions */
|
|
35
|
+
spacecraft: SpacecraftPosition[];
|
|
36
|
+
/** Ground track history per spacecraft */
|
|
37
|
+
groundTracks: Map<string, CompactGroundTrackPoint[]>;
|
|
38
|
+
/** Loading state */
|
|
39
|
+
isLoading: boolean;
|
|
40
|
+
/** Error message */
|
|
41
|
+
error: string | null;
|
|
42
|
+
/** Last update timestamp */
|
|
43
|
+
lastUpdate: number | null;
|
|
44
|
+
/** Get specific spacecraft */
|
|
45
|
+
getSpacecraft: (id: string) => SpacecraftPosition | undefined;
|
|
46
|
+
/** Manually refresh positions */
|
|
47
|
+
refresh: () => Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
export declare function useSpacecraftPosition(options: UseSpacecraftPositionOptions): UseSpacecraftPositionResult;
|
|
50
|
+
export default useSpacecraftPosition;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { useState, useRef, useCallback, useEffect } from "react";
|
|
2
|
+
const DEFAULT_MAX_HISTORY = 500;
|
|
3
|
+
function useSpacecraftPosition(options) {
|
|
4
|
+
const {
|
|
5
|
+
client,
|
|
6
|
+
interval = 1e3,
|
|
7
|
+
enabled = true,
|
|
8
|
+
trackHistory = true,
|
|
9
|
+
maxHistory = DEFAULT_MAX_HISTORY
|
|
10
|
+
} = options;
|
|
11
|
+
const [spacecraft, setSpacecraft] = useState([]);
|
|
12
|
+
const [groundTracks, setGroundTracks] = useState(/* @__PURE__ */ new Map());
|
|
13
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
14
|
+
const [error, setError] = useState(null);
|
|
15
|
+
const [lastUpdate, setLastUpdate] = useState(null);
|
|
16
|
+
const intervalRef = useRef(null);
|
|
17
|
+
const startTimeRef = useRef(Date.now());
|
|
18
|
+
const fetchPositions = useCallback(async () => {
|
|
19
|
+
setIsLoading(true);
|
|
20
|
+
setError(null);
|
|
21
|
+
try {
|
|
22
|
+
const positions = await client.fetchSpacecraftPositions();
|
|
23
|
+
setSpacecraft(positions);
|
|
24
|
+
setLastUpdate(Date.now());
|
|
25
|
+
if (trackHistory) {
|
|
26
|
+
const elapsed = (Date.now() - startTimeRef.current) / 1e3;
|
|
27
|
+
setGroundTracks((prev) => {
|
|
28
|
+
const newTracks = new Map(prev);
|
|
29
|
+
for (const sc of positions) {
|
|
30
|
+
if (!sc.id) continue;
|
|
31
|
+
const point = {
|
|
32
|
+
lat: sc.latitude,
|
|
33
|
+
lon: sc.longitude,
|
|
34
|
+
t: elapsed
|
|
35
|
+
};
|
|
36
|
+
const existing = newTracks.get(sc.id) || [];
|
|
37
|
+
const updated = [...existing, point];
|
|
38
|
+
if (updated.length > maxHistory) {
|
|
39
|
+
newTracks.set(sc.id, updated.slice(-maxHistory));
|
|
40
|
+
} else {
|
|
41
|
+
newTracks.set(sc.id, updated);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return newTracks;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
} catch (err) {
|
|
48
|
+
const message = err instanceof Error ? err.message : "Failed to fetch positions";
|
|
49
|
+
setError(message);
|
|
50
|
+
} finally {
|
|
51
|
+
setIsLoading(false);
|
|
52
|
+
}
|
|
53
|
+
}, [client, trackHistory, maxHistory]);
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (!enabled) {
|
|
56
|
+
if (intervalRef.current) {
|
|
57
|
+
clearInterval(intervalRef.current);
|
|
58
|
+
intervalRef.current = null;
|
|
59
|
+
}
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
startTimeRef.current = Date.now();
|
|
63
|
+
fetchPositions();
|
|
64
|
+
intervalRef.current = setInterval(fetchPositions, interval);
|
|
65
|
+
return () => {
|
|
66
|
+
if (intervalRef.current) {
|
|
67
|
+
clearInterval(intervalRef.current);
|
|
68
|
+
intervalRef.current = null;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}, [enabled, interval, fetchPositions]);
|
|
72
|
+
const getSpacecraft = useCallback(
|
|
73
|
+
(id) => spacecraft.find((sc) => sc.id === id),
|
|
74
|
+
[spacecraft]
|
|
75
|
+
);
|
|
76
|
+
return {
|
|
77
|
+
spacecraft,
|
|
78
|
+
groundTracks,
|
|
79
|
+
isLoading,
|
|
80
|
+
error,
|
|
81
|
+
lastUpdate,
|
|
82
|
+
getSpacecraft,
|
|
83
|
+
refresh: fetchPositions
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export {
|
|
87
|
+
useSpacecraftPosition
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=useSpacecraftPosition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSpacecraftPosition.js","sources":["../../../src/react/hooks/useSpacecraftPosition.ts"],"sourcesContent":["/**\n * @zendir/ui - useSpacecraftPosition Hook\n * \n * React hook for fetching and tracking spacecraft positions.\n * \n * OPTIONAL DEPENDENCY: Requires @zendir/sdk client instance.\n * The client must be passed as a prop (allows using any compatible client).\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport type { SpacecraftPosition } from '../types';\n\n// Re-export the canonical type for consumers\nexport type { SpacecraftPosition };\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Compact ground track point for real-time orbit visualization\n * Uses abbreviated property names for performance in streaming contexts\n * Note: For full ground track data, use GroundTrackPoint from '../types'\n */\nexport interface CompactGroundTrackPoint {\n /** Latitude in degrees */\n lat: number;\n /** Longitude in degrees */\n lon: number;\n /** Timestamp (epoch ms or ISO string) */\n t: number;\n}\n\n/** Client interface (compatible with @zendir/sdk ZendirClient) */\nexport interface PositionClientInterface {\n fetchSpacecraftPositions: () => Promise<SpacecraftPosition[]>;\n}\n\n// ============================================================================\n// Hook Types\n// ============================================================================\n\nexport interface UseSpacecraftPositionOptions {\n /** Zendir client instance (or any compatible client) */\n client: PositionClientInterface;\n /** Polling interval in ms (default: 1000) */\n interval?: number;\n /** Enable polling */\n enabled?: boolean;\n /** Track ground track history */\n trackHistory?: boolean;\n /** Maximum history points */\n maxHistory?: number;\n}\n\nexport interface UseSpacecraftPositionResult {\n /** All spacecraft positions */\n spacecraft: SpacecraftPosition[];\n /** Ground track history per spacecraft */\n groundTracks: Map<string, CompactGroundTrackPoint[]>;\n /** Loading state */\n isLoading: boolean;\n /** Error message */\n error: string | null;\n /** Last update timestamp */\n lastUpdate: number | null;\n /** Get specific spacecraft */\n getSpacecraft: (id: string) => SpacecraftPosition | undefined;\n /** Manually refresh positions */\n refresh: () => Promise<void>;\n}\n\nconst DEFAULT_MAX_HISTORY = 500;\n\nexport function useSpacecraftPosition(\n options: UseSpacecraftPositionOptions\n): UseSpacecraftPositionResult {\n const {\n client,\n interval = 1000,\n enabled = true,\n trackHistory = true,\n maxHistory = DEFAULT_MAX_HISTORY,\n } = options;\n\n const [spacecraft, setSpacecraft] = useState<SpacecraftPosition[]>([]);\n const [groundTracks, setGroundTracks] = useState<Map<string, CompactGroundTrackPoint[]>>(new Map());\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [lastUpdate, setLastUpdate] = useState<number | null>(null);\n\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const startTimeRef = useRef<number>(Date.now());\n\n const fetchPositions = useCallback(async () => {\n setIsLoading(true);\n setError(null);\n\n try {\n const positions = await client.fetchSpacecraftPositions();\n setSpacecraft(positions);\n setLastUpdate(Date.now());\n\n // Update ground tracks\n if (trackHistory) {\n const elapsed = (Date.now() - startTimeRef.current) / 1000;\n\n setGroundTracks(prev => {\n const newTracks = new Map(prev);\n\n for (const sc of positions) {\n // Skip if no id\n if (!sc.id) continue;\n \n const point: CompactGroundTrackPoint = {\n lat: sc.latitude,\n lon: sc.longitude,\n t: elapsed,\n };\n\n const existing = newTracks.get(sc.id) || [];\n const updated = [...existing, point];\n\n if (updated.length > maxHistory) {\n newTracks.set(sc.id, updated.slice(-maxHistory));\n } else {\n newTracks.set(sc.id, updated);\n }\n }\n\n return newTracks;\n });\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to fetch positions';\n setError(message);\n } finally {\n setIsLoading(false);\n }\n }, [client, trackHistory, maxHistory]);\n\n // Set up polling\n useEffect(() => {\n if (!enabled) {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n return;\n }\n\n startTimeRef.current = Date.now();\n\n // Initial fetch\n fetchPositions();\n\n // Set up polling\n intervalRef.current = setInterval(fetchPositions, interval);\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n };\n }, [enabled, interval, fetchPositions]);\n\n const getSpacecraft = useCallback(\n (id: string) => spacecraft.find(sc => sc.id === id),\n [spacecraft]\n );\n\n return {\n spacecraft,\n groundTracks,\n isLoading,\n error,\n lastUpdate,\n getSpacecraft,\n refresh: fetchPositions,\n };\n}\n\nexport default useSpacecraftPosition;\n\n\n\n\n"],"names":[],"mappings":";AAwEA,MAAM,sBAAsB;AAErB,SAAS,sBACd,SAC6B;AAC7B,QAAM;AAAA,IACJ;AAAA,IACA,WAAW;AAAA,IACX,UAAU;AAAA,IACV,eAAe;AAAA,IACf,aAAa;AAAA,EAAA,IACX;AAEJ,QAAM,CAAC,YAAY,aAAa,IAAI,SAA+B,CAAA,CAAE;AACrE,QAAM,CAAC,cAAc,eAAe,IAAI,SAAiD,oBAAI,KAAK;AAClG,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,CAAC,YAAY,aAAa,IAAI,SAAwB,IAAI;AAEhE,QAAM,cAAc,OAA8C,IAAI;AACtE,QAAM,eAAe,OAAe,KAAK,IAAA,CAAK;AAE9C,QAAM,iBAAiB,YAAY,YAAY;AAC7C,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,YAAM,YAAY,MAAM,OAAO,yBAAA;AAC/B,oBAAc,SAAS;AACvB,oBAAc,KAAK,KAAK;AAGxB,UAAI,cAAc;AAChB,cAAM,WAAW,KAAK,IAAA,IAAQ,aAAa,WAAW;AAEtD,wBAAgB,CAAA,SAAQ;AACtB,gBAAM,YAAY,IAAI,IAAI,IAAI;AAE9B,qBAAW,MAAM,WAAW;AAE1B,gBAAI,CAAC,GAAG,GAAI;AAEZ,kBAAM,QAAiC;AAAA,cACrC,KAAK,GAAG;AAAA,cACR,KAAK,GAAG;AAAA,cACR,GAAG;AAAA,YAAA;AAGL,kBAAM,WAAW,UAAU,IAAI,GAAG,EAAE,KAAK,CAAA;AACzC,kBAAM,UAAU,CAAC,GAAG,UAAU,KAAK;AAEnC,gBAAI,QAAQ,SAAS,YAAY;AAC/B,wBAAU,IAAI,GAAG,IAAI,QAAQ,MAAM,CAAC,UAAU,CAAC;AAAA,YACjD,OAAO;AACL,wBAAU,IAAI,GAAG,IAAI,OAAO;AAAA,YAC9B;AAAA,UACF;AAEA,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,eAAS,OAAO;AAAA,IAClB,UAAA;AACE,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,QAAQ,cAAc,UAAU,CAAC;AAGrC,YAAU,MAAM;AACd,QAAI,CAAC,SAAS;AACZ,UAAI,YAAY,SAAS;AACvB,sBAAc,YAAY,OAAO;AACjC,oBAAY,UAAU;AAAA,MACxB;AACA;AAAA,IACF;AAEA,iBAAa,UAAU,KAAK,IAAA;AAG5B,mBAAA;AAGA,gBAAY,UAAU,YAAY,gBAAgB,QAAQ;AAE1D,WAAO,MAAM;AACX,UAAI,YAAY,SAAS;AACvB,sBAAc,YAAY,OAAO;AACjC,oBAAY,UAAU;AAAA,MACxB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,SAAS,UAAU,cAAc,CAAC;AAEtC,QAAM,gBAAgB;AAAA,IACpB,CAAC,OAAe,WAAW,KAAK,CAAA,OAAM,GAAG,OAAO,EAAE;AAAA,IAClD,CAAC,UAAU;AAAA,EAAA;AAGb,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,EAAA;AAEb;"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { TelemetryData } from '../types';
|
|
2
|
+
|
|
3
|
+
/** Attitude data from spacecraft */
|
|
4
|
+
export interface AttitudeData {
|
|
5
|
+
quaternion?: {
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
z: number;
|
|
9
|
+
w: number;
|
|
10
|
+
};
|
|
11
|
+
euler?: {
|
|
12
|
+
roll: number;
|
|
13
|
+
pitch: number;
|
|
14
|
+
yaw: number;
|
|
15
|
+
};
|
|
16
|
+
angularVelocity?: {
|
|
17
|
+
x: number;
|
|
18
|
+
y: number;
|
|
19
|
+
z: number;
|
|
20
|
+
};
|
|
21
|
+
timestamp?: string;
|
|
22
|
+
}
|
|
23
|
+
/** Client interface (compatible with @zendir/sdk ZendirClient) */
|
|
24
|
+
export interface TelemetryClientInterface {
|
|
25
|
+
getTelemetry: (spacecraftId: string) => Promise<unknown>;
|
|
26
|
+
getAttitude: (spacecraftId: string) => Promise<AttitudeData>;
|
|
27
|
+
}
|
|
28
|
+
export interface UseTelemetryOptions {
|
|
29
|
+
/** Zendir client instance (or any compatible client) */
|
|
30
|
+
client: TelemetryClientInterface;
|
|
31
|
+
/** Spacecraft ID to fetch telemetry for */
|
|
32
|
+
spacecraftId: string;
|
|
33
|
+
/** Polling interval in ms (default: 2000) */
|
|
34
|
+
interval?: number;
|
|
35
|
+
/** Enable polling */
|
|
36
|
+
enabled?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface UseTelemetryResult {
|
|
39
|
+
/** Latest telemetry data */
|
|
40
|
+
telemetry: TelemetryData | null;
|
|
41
|
+
/** Latest attitude data */
|
|
42
|
+
attitude: AttitudeData | null;
|
|
43
|
+
/** Telemetry history */
|
|
44
|
+
history: TelemetryData[];
|
|
45
|
+
/** Loading state */
|
|
46
|
+
isLoading: boolean;
|
|
47
|
+
/** Error message */
|
|
48
|
+
error: string | null;
|
|
49
|
+
/** Last update timestamp */
|
|
50
|
+
lastUpdate: number | null;
|
|
51
|
+
/** Manually refresh telemetry */
|
|
52
|
+
refresh: () => Promise<void>;
|
|
53
|
+
}
|
|
54
|
+
export declare function useTelemetry(options: UseTelemetryOptions): UseTelemetryResult;
|
|
55
|
+
export default useTelemetry;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { useState, useRef, useCallback, useEffect } from "react";
|
|
2
|
+
const MAX_HISTORY = 100;
|
|
3
|
+
function useTelemetry(options) {
|
|
4
|
+
const { client, spacecraftId, interval = 2e3, enabled = true } = options;
|
|
5
|
+
const [telemetry, setTelemetry] = useState(null);
|
|
6
|
+
const [attitude, setAttitude] = useState(null);
|
|
7
|
+
const [history, setHistory] = useState([]);
|
|
8
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
9
|
+
const [error, setError] = useState(null);
|
|
10
|
+
const [lastUpdate, setLastUpdate] = useState(null);
|
|
11
|
+
const intervalRef = useRef(null);
|
|
12
|
+
const fetchTelemetry = useCallback(async () => {
|
|
13
|
+
if (!spacecraftId) return;
|
|
14
|
+
setIsLoading(true);
|
|
15
|
+
setError(null);
|
|
16
|
+
try {
|
|
17
|
+
const [telemetryData, attitudeData] = await Promise.all([
|
|
18
|
+
client.getTelemetry(spacecraftId),
|
|
19
|
+
client.getAttitude(spacecraftId)
|
|
20
|
+
]);
|
|
21
|
+
setTelemetry(telemetryData);
|
|
22
|
+
setAttitude(attitudeData);
|
|
23
|
+
setLastUpdate(Date.now());
|
|
24
|
+
setHistory((prev) => {
|
|
25
|
+
const newHistory = [...prev, telemetryData];
|
|
26
|
+
if (newHistory.length > MAX_HISTORY) {
|
|
27
|
+
return newHistory.slice(-MAX_HISTORY);
|
|
28
|
+
}
|
|
29
|
+
return newHistory;
|
|
30
|
+
});
|
|
31
|
+
} catch (err) {
|
|
32
|
+
const message = err instanceof Error ? err.message : "Failed to fetch telemetry";
|
|
33
|
+
setError(message);
|
|
34
|
+
} finally {
|
|
35
|
+
setIsLoading(false);
|
|
36
|
+
}
|
|
37
|
+
}, [client, spacecraftId]);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (!enabled || !spacecraftId) {
|
|
40
|
+
if (intervalRef.current) {
|
|
41
|
+
clearInterval(intervalRef.current);
|
|
42
|
+
intervalRef.current = null;
|
|
43
|
+
}
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
fetchTelemetry();
|
|
47
|
+
intervalRef.current = setInterval(fetchTelemetry, interval);
|
|
48
|
+
return () => {
|
|
49
|
+
if (intervalRef.current) {
|
|
50
|
+
clearInterval(intervalRef.current);
|
|
51
|
+
intervalRef.current = null;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}, [enabled, spacecraftId, interval, fetchTelemetry]);
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
setHistory([]);
|
|
57
|
+
setTelemetry(null);
|
|
58
|
+
setAttitude(null);
|
|
59
|
+
}, [spacecraftId]);
|
|
60
|
+
return {
|
|
61
|
+
telemetry,
|
|
62
|
+
attitude,
|
|
63
|
+
history,
|
|
64
|
+
isLoading,
|
|
65
|
+
error,
|
|
66
|
+
lastUpdate,
|
|
67
|
+
refresh: fetchTelemetry
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export {
|
|
71
|
+
useTelemetry
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=useTelemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTelemetry.js","sources":["../../../src/react/hooks/useTelemetry.ts"],"sourcesContent":["/**\n * @zendir/ui - useTelemetry Hook\n * \n * React hook for fetching and updating spacecraft telemetry data.\n * \n * OPTIONAL DEPENDENCY: Requires @zendir/sdk client instance.\n * The client must be passed as a prop (allows using any compatible client).\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport type { TelemetryData } from '../types';\n\n// ============================================================================\n// Types (defined locally to avoid hard dependency on @zendir/sdk)\n// ============================================================================\n\n/** Attitude data from spacecraft */\nexport interface AttitudeData {\n quaternion?: { x: number; y: number; z: number; w: number };\n euler?: { roll: number; pitch: number; yaw: number };\n angularVelocity?: { x: number; y: number; z: number };\n timestamp?: string;\n}\n\n/** Client interface (compatible with @zendir/sdk ZendirClient) */\nexport interface TelemetryClientInterface {\n getTelemetry: (spacecraftId: string) => Promise<unknown>;\n getAttitude: (spacecraftId: string) => Promise<AttitudeData>;\n}\n\n// ============================================================================\n// Hook Types\n// ============================================================================\n\nexport interface UseTelemetryOptions {\n /** Zendir client instance (or any compatible client) */\n client: TelemetryClientInterface;\n /** Spacecraft ID to fetch telemetry for */\n spacecraftId: string;\n /** Polling interval in ms (default: 2000) */\n interval?: number;\n /** Enable polling */\n enabled?: boolean;\n}\n\nexport interface UseTelemetryResult {\n /** Latest telemetry data */\n telemetry: TelemetryData | null;\n /** Latest attitude data */\n attitude: AttitudeData | null;\n /** Telemetry history */\n history: TelemetryData[];\n /** Loading state */\n isLoading: boolean;\n /** Error message */\n error: string | null;\n /** Last update timestamp */\n lastUpdate: number | null;\n /** Manually refresh telemetry */\n refresh: () => Promise<void>;\n}\n\nconst MAX_HISTORY = 100;\n\nexport function useTelemetry(options: UseTelemetryOptions): UseTelemetryResult {\n const { client, spacecraftId, interval = 2000, enabled = true } = options;\n\n const [telemetry, setTelemetry] = useState<TelemetryData | null>(null);\n const [attitude, setAttitude] = useState<AttitudeData | null>(null);\n const [history, setHistory] = useState<TelemetryData[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [lastUpdate, setLastUpdate] = useState<number | null>(null);\n\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const fetchTelemetry = useCallback(async () => {\n if (!spacecraftId) return;\n\n setIsLoading(true);\n setError(null);\n\n try {\n const [telemetryData, attitudeData] = await Promise.all([\n client.getTelemetry(spacecraftId),\n client.getAttitude(spacecraftId),\n ]);\n\n setTelemetry(telemetryData as unknown as TelemetryData);\n setAttitude(attitudeData);\n setLastUpdate(Date.now());\n\n // Add to history\n setHistory(prev => {\n const newHistory = [...prev, telemetryData as unknown as TelemetryData];\n if (newHistory.length > MAX_HISTORY) {\n return newHistory.slice(-MAX_HISTORY);\n }\n return newHistory;\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to fetch telemetry';\n setError(message);\n } finally {\n setIsLoading(false);\n }\n }, [client, spacecraftId]);\n\n // Set up polling\n useEffect(() => {\n if (!enabled || !spacecraftId) {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n return;\n }\n\n // Initial fetch\n fetchTelemetry();\n\n // Set up polling\n intervalRef.current = setInterval(fetchTelemetry, interval);\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n };\n }, [enabled, spacecraftId, interval, fetchTelemetry]);\n\n // Clear history when spacecraft changes\n useEffect(() => {\n setHistory([]);\n setTelemetry(null);\n setAttitude(null);\n }, [spacecraftId]);\n\n return {\n telemetry,\n attitude,\n history,\n isLoading,\n error,\n lastUpdate,\n refresh: fetchTelemetry,\n };\n}\n\nexport default useTelemetry;\n\n\n\n\n"],"names":[],"mappings":";AA8DA,MAAM,cAAc;AAEb,SAAS,aAAa,SAAkD;AAC7E,QAAM,EAAE,QAAQ,cAAc,WAAW,KAAM,UAAU,SAAS;AAElE,QAAM,CAAC,WAAW,YAAY,IAAI,SAA+B,IAAI;AACrE,QAAM,CAAC,UAAU,WAAW,IAAI,SAA8B,IAAI;AAClE,QAAM,CAAC,SAAS,UAAU,IAAI,SAA0B,CAAA,CAAE;AAC1D,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,CAAC,YAAY,aAAa,IAAI,SAAwB,IAAI;AAEhE,QAAM,cAAc,OAA8C,IAAI;AAEtE,QAAM,iBAAiB,YAAY,YAAY;AAC7C,QAAI,CAAC,aAAc;AAEnB,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,YAAM,CAAC,eAAe,YAAY,IAAI,MAAM,QAAQ,IAAI;AAAA,QACtD,OAAO,aAAa,YAAY;AAAA,QAChC,OAAO,YAAY,YAAY;AAAA,MAAA,CAChC;AAED,mBAAa,aAAyC;AACtD,kBAAY,YAAY;AACxB,oBAAc,KAAK,KAAK;AAGxB,iBAAW,CAAA,SAAQ;AACjB,cAAM,aAAa,CAAC,GAAG,MAAM,aAAyC;AACtE,YAAI,WAAW,SAAS,aAAa;AACnC,iBAAO,WAAW,MAAM,CAAC,WAAW;AAAA,QACtC;AACA,eAAO;AAAA,MACT,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,eAAS,OAAO;AAAA,IAClB,UAAA;AACE,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,QAAQ,YAAY,CAAC;AAGzB,YAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,cAAc;AAC7B,UAAI,YAAY,SAAS;AACvB,sBAAc,YAAY,OAAO;AACjC,oBAAY,UAAU;AAAA,MACxB;AACA;AAAA,IACF;AAGA,mBAAA;AAGA,gBAAY,UAAU,YAAY,gBAAgB,QAAQ;AAE1D,WAAO,MAAM;AACX,UAAI,YAAY,SAAS;AACvB,sBAAc,YAAY,OAAO;AACjC,oBAAY,UAAU;AAAA,MACxB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,SAAS,cAAc,UAAU,cAAc,CAAC;AAGpD,YAAU,MAAM;AACd,eAAW,CAAA,CAAE;AACb,iBAAa,IAAI;AACjB,gBAAY,IAAI;AAAA,EAClB,GAAG,CAAC,YAAY,CAAC;AAEjB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,EAAA;AAEb;"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @zendir/ui - useZendirSession Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for managing Zendir API session lifecycle.
|
|
5
|
+
*
|
|
6
|
+
* OPTIONAL DEPENDENCY: Requires @zendir/sdk to be installed.
|
|
7
|
+
* If not installed, the hook returns an error state.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useZendirSession } from '@zendir/ui/react';
|
|
12
|
+
*
|
|
13
|
+
* function App() {
|
|
14
|
+
* const { session, connect, isLoading, error } = useZendirSession({
|
|
15
|
+
* apiKey: 'your-api-key',
|
|
16
|
+
* autoConnect: true,
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* if (error) return <div>Error: {error}</div>;
|
|
20
|
+
* if (isLoading) return <div>Connecting...</div>;
|
|
21
|
+
* if (!session) return <button onClick={connect}>Connect</button>;
|
|
22
|
+
*
|
|
23
|
+
* return <div>Connected: {session.id}</div>;
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
/** Session info from Zendir API */
|
|
28
|
+
export interface SessionInfo {
|
|
29
|
+
id: string;
|
|
30
|
+
status: 'active' | 'expired' | 'error';
|
|
31
|
+
createdAt?: string;
|
|
32
|
+
expiresAt?: string;
|
|
33
|
+
}
|
|
34
|
+
/** Simulation info from Zendir API */
|
|
35
|
+
export interface SimulationInfo {
|
|
36
|
+
id: string;
|
|
37
|
+
name?: string;
|
|
38
|
+
status: 'running' | 'paused' | 'stopped';
|
|
39
|
+
spacecraftCount?: number;
|
|
40
|
+
}
|
|
41
|
+
/** Zendir client interface (matches @zendir/sdk) */
|
|
42
|
+
export interface ZendirClientInterface {
|
|
43
|
+
createSession: () => Promise<SessionInfo>;
|
|
44
|
+
createSimulation: (params: {
|
|
45
|
+
name?: string;
|
|
46
|
+
spacecraft: Array<{
|
|
47
|
+
name: string;
|
|
48
|
+
tle?: {
|
|
49
|
+
line1: string;
|
|
50
|
+
line2: string;
|
|
51
|
+
};
|
|
52
|
+
catalogNumber?: number;
|
|
53
|
+
}>;
|
|
54
|
+
}) => Promise<SimulationInfo>;
|
|
55
|
+
clearSession: () => void;
|
|
56
|
+
}
|
|
57
|
+
export interface UseZendirSessionOptions {
|
|
58
|
+
/** API key (optional - can be set via client) */
|
|
59
|
+
apiKey?: string;
|
|
60
|
+
/** Base URL override */
|
|
61
|
+
baseUrl?: string;
|
|
62
|
+
/** Auto-connect on mount */
|
|
63
|
+
autoConnect?: boolean;
|
|
64
|
+
/** Enable debug logging */
|
|
65
|
+
debug?: boolean;
|
|
66
|
+
}
|
|
67
|
+
export interface UseZendirSessionResult {
|
|
68
|
+
/** Current session info */
|
|
69
|
+
session: SessionInfo | null;
|
|
70
|
+
/** Current simulation info */
|
|
71
|
+
simulation: SimulationInfo | null;
|
|
72
|
+
/** Loading state */
|
|
73
|
+
isLoading: boolean;
|
|
74
|
+
/** Error message */
|
|
75
|
+
error: string | null;
|
|
76
|
+
/** Connected status */
|
|
77
|
+
isConnected: boolean;
|
|
78
|
+
/** Whether SDK is available */
|
|
79
|
+
isSdkAvailable: boolean;
|
|
80
|
+
/** Zendir client instance (null if SDK not loaded) */
|
|
81
|
+
client: ZendirClientInterface | null;
|
|
82
|
+
/** Connect/create session */
|
|
83
|
+
connect: () => Promise<void>;
|
|
84
|
+
/** Create simulation */
|
|
85
|
+
createSimulation: (params: {
|
|
86
|
+
name?: string;
|
|
87
|
+
spacecraft: Array<{
|
|
88
|
+
name: string;
|
|
89
|
+
tle?: {
|
|
90
|
+
line1: string;
|
|
91
|
+
line2: string;
|
|
92
|
+
};
|
|
93
|
+
catalogNumber?: number;
|
|
94
|
+
}>;
|
|
95
|
+
}) => Promise<void>;
|
|
96
|
+
/** Disconnect/clear session */
|
|
97
|
+
disconnect: () => void;
|
|
98
|
+
}
|
|
99
|
+
export declare function useZendirSession(options?: UseZendirSessionOptions): UseZendirSessionResult;
|
|
100
|
+
/**
|
|
101
|
+
* Check if @zendir/sdk is available
|
|
102
|
+
*/
|
|
103
|
+
export declare function isZendirSdkAvailable(): boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Preload the @zendir/sdk module
|
|
106
|
+
* Call this early in your app to ensure SDK is ready
|
|
107
|
+
*/
|
|
108
|
+
export declare function preloadZendirSdk(): Promise<boolean>;
|
|
109
|
+
export default useZendirSession;
|