@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,229 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { memo, useState, useRef, useCallback, useContext, createContext, useEffect } from "react";
|
|
3
|
+
import { safeAccentText } from "../utils/index.js";
|
|
4
|
+
import { useBreakpoint } from "./layout/useBreakpoint.js";
|
|
5
|
+
import { useTheme } from "../theme/ThemeProvider.js";
|
|
6
|
+
const ToastContext = createContext(null);
|
|
7
|
+
function useToast() {
|
|
8
|
+
const ctx = useContext(ToastContext);
|
|
9
|
+
if (!ctx) throw new Error("useToast must be used within <ToastProvider>");
|
|
10
|
+
return ctx.toast;
|
|
11
|
+
}
|
|
12
|
+
function useToastManager() {
|
|
13
|
+
const ctx = useContext(ToastContext);
|
|
14
|
+
if (!ctx) throw new Error("useToastManager must be used within <ToastProvider>");
|
|
15
|
+
return ctx;
|
|
16
|
+
}
|
|
17
|
+
const ToastItem = memo(function ToastItem2({
|
|
18
|
+
toast: t,
|
|
19
|
+
onDismiss
|
|
20
|
+
}) {
|
|
21
|
+
const { tokens } = useTheme();
|
|
22
|
+
const [exiting, setExiting] = useState(false);
|
|
23
|
+
const dismissTimeoutRef = useRef();
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
return () => {
|
|
26
|
+
clearTimeout(dismissTimeoutRef.current);
|
|
27
|
+
};
|
|
28
|
+
}, []);
|
|
29
|
+
const statusColors = {
|
|
30
|
+
normal: tokens.colors.status.normal,
|
|
31
|
+
standby: tokens.colors.status.standby,
|
|
32
|
+
caution: tokens.colors.status.caution,
|
|
33
|
+
serious: tokens.colors.status.serious,
|
|
34
|
+
critical: tokens.colors.status.critical,
|
|
35
|
+
off: tokens.colors.status.off
|
|
36
|
+
};
|
|
37
|
+
const color = statusColors[t.status || "off"] || tokens.colors.status.off;
|
|
38
|
+
const handleDismiss = useCallback(() => {
|
|
39
|
+
setExiting(true);
|
|
40
|
+
dismissTimeoutRef.current = setTimeout(() => onDismiss(t.id), 200);
|
|
41
|
+
}, [t.id, onDismiss]);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
const dur = t.duration ?? 5e3;
|
|
44
|
+
if (dur <= 0) return;
|
|
45
|
+
const timer = setTimeout(handleDismiss, dur);
|
|
46
|
+
return () => clearTimeout(timer);
|
|
47
|
+
}, [t.duration, handleDismiss]);
|
|
48
|
+
const statusIcon = (() => {
|
|
49
|
+
const s = 10;
|
|
50
|
+
const h = s / 2;
|
|
51
|
+
const status = t.status || "off";
|
|
52
|
+
const sharedStyle = { flexShrink: 0, marginTop: "3px" };
|
|
53
|
+
switch (status) {
|
|
54
|
+
case "critical":
|
|
55
|
+
return /* @__PURE__ */ jsx("svg", { width: s, height: s, viewBox: `0 0 ${s} ${s}`, style: sharedStyle, children: /* @__PURE__ */ jsx("polygon", { points: `${h},${s} 0,0 ${s},0`, fill: color }) });
|
|
56
|
+
case "serious":
|
|
57
|
+
return /* @__PURE__ */ jsx("svg", { width: s, height: s, viewBox: `0 0 ${s} ${s}`, style: sharedStyle, children: /* @__PURE__ */ jsx("polygon", { points: `${h},0 ${s},${h} ${h},${s} 0,${h}`, fill: color }) });
|
|
58
|
+
case "caution":
|
|
59
|
+
return /* @__PURE__ */ jsx("svg", { width: s, height: s, viewBox: `0 0 ${s} ${s}`, style: sharedStyle, children: /* @__PURE__ */ jsx("rect", { width: s, height: s, fill: color }) });
|
|
60
|
+
case "standby":
|
|
61
|
+
return /* @__PURE__ */ jsx("svg", { width: s, height: s, viewBox: "0 0 12 12", style: sharedStyle, children: /* @__PURE__ */ jsx("circle", { cx: "6", cy: "6", r: "3.5", fill: "none", stroke: color, strokeWidth: "2" }) });
|
|
62
|
+
case "off":
|
|
63
|
+
return /* @__PURE__ */ jsx("svg", { width: s, height: s, viewBox: "0 0 12 12", style: sharedStyle, children: /* @__PURE__ */ jsx("circle", { cx: "6", cy: "6", r: "3", fill: color }) });
|
|
64
|
+
default:
|
|
65
|
+
return /* @__PURE__ */ jsx("svg", { width: s, height: s, viewBox: `0 0 ${s} ${s}`, style: sharedStyle, children: /* @__PURE__ */ jsx("circle", { cx: h, cy: h, r: h, fill: color }) });
|
|
66
|
+
}
|
|
67
|
+
})();
|
|
68
|
+
return /* @__PURE__ */ jsxs(
|
|
69
|
+
"div",
|
|
70
|
+
{
|
|
71
|
+
role: "alert",
|
|
72
|
+
style: {
|
|
73
|
+
display: "flex",
|
|
74
|
+
gap: tokens.spacing.sm,
|
|
75
|
+
padding: `${tokens.spacing.sm} ${tokens.spacing.md}`,
|
|
76
|
+
backgroundColor: tokens.colors.background.elevated,
|
|
77
|
+
border: `1px solid ${color}30`,
|
|
78
|
+
borderLeft: `3px solid ${color}`,
|
|
79
|
+
borderRadius: tokens.borderRadius.md,
|
|
80
|
+
boxShadow: `${tokens.shadows.lg}, 0 0 20px ${color}15`,
|
|
81
|
+
maxWidth: "min(400px, calc(100vw - 32px))",
|
|
82
|
+
minWidth: "min(280px, calc(100vw - 32px))",
|
|
83
|
+
fontFamily: tokens.typography.fontFamily.primary,
|
|
84
|
+
animation: exiting ? `zendir-toast-exit 200ms ${tokens.animation.easing.default} forwards` : `zendir-toast-enter 300ms ${tokens.animation.easing.default}`,
|
|
85
|
+
transition: tokens.animation.normal
|
|
86
|
+
},
|
|
87
|
+
children: [
|
|
88
|
+
t.icon || statusIcon,
|
|
89
|
+
/* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
90
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
91
|
+
fontSize: tokens.typography.fontSize.sm,
|
|
92
|
+
fontWeight: tokens.typography.fontWeight.semibold,
|
|
93
|
+
color: tokens.colors.text.primary,
|
|
94
|
+
lineHeight: tokens.typography.lineHeight.tight
|
|
95
|
+
}, children: t.title }),
|
|
96
|
+
t.message && /* @__PURE__ */ jsx("div", { style: {
|
|
97
|
+
fontSize: tokens.typography.fontSize.xs,
|
|
98
|
+
color: tokens.colors.text.secondary,
|
|
99
|
+
marginTop: "2px",
|
|
100
|
+
lineHeight: tokens.typography.lineHeight.normal
|
|
101
|
+
}, children: t.message }),
|
|
102
|
+
t.action && /* @__PURE__ */ jsx(
|
|
103
|
+
"button",
|
|
104
|
+
{
|
|
105
|
+
onClick: t.action.onClick,
|
|
106
|
+
style: {
|
|
107
|
+
marginTop: tokens.spacing.xs,
|
|
108
|
+
fontSize: tokens.typography.fontSize.xs,
|
|
109
|
+
fontWeight: tokens.typography.fontWeight.semibold,
|
|
110
|
+
color: safeAccentText(tokens.colors.accent.primary),
|
|
111
|
+
background: "none",
|
|
112
|
+
border: "none",
|
|
113
|
+
padding: 0,
|
|
114
|
+
cursor: "pointer",
|
|
115
|
+
fontFamily: tokens.typography.fontFamily.primary
|
|
116
|
+
},
|
|
117
|
+
children: t.action.label
|
|
118
|
+
}
|
|
119
|
+
)
|
|
120
|
+
] }),
|
|
121
|
+
t.dismissible !== false && /* @__PURE__ */ jsx(
|
|
122
|
+
"button",
|
|
123
|
+
{
|
|
124
|
+
"aria-label": "Dismiss notification",
|
|
125
|
+
onClick: handleDismiss,
|
|
126
|
+
style: {
|
|
127
|
+
display: "flex",
|
|
128
|
+
alignItems: "center",
|
|
129
|
+
justifyContent: "center",
|
|
130
|
+
width: 44,
|
|
131
|
+
height: 44,
|
|
132
|
+
border: "none",
|
|
133
|
+
background: "none",
|
|
134
|
+
color: tokens.colors.text.tertiary,
|
|
135
|
+
cursor: "pointer",
|
|
136
|
+
borderRadius: tokens.borderRadius.sm,
|
|
137
|
+
padding: tokens.spacing.xs,
|
|
138
|
+
flexShrink: 0,
|
|
139
|
+
transition: tokens.animation.fast
|
|
140
|
+
},
|
|
141
|
+
children: /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: [
|
|
142
|
+
/* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
143
|
+
/* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
144
|
+
] })
|
|
145
|
+
}
|
|
146
|
+
)
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
const ToastProvider = memo(function ToastProvider2({
|
|
152
|
+
position = "top-right",
|
|
153
|
+
maxVisible = 5,
|
|
154
|
+
defaultDuration = 5e3,
|
|
155
|
+
children
|
|
156
|
+
}) {
|
|
157
|
+
const { tokens } = useTheme();
|
|
158
|
+
const { isMobile } = useBreakpoint();
|
|
159
|
+
const [toasts, setToasts] = useState([]);
|
|
160
|
+
const idCounter = useRef(0);
|
|
161
|
+
const toast = useCallback((options) => {
|
|
162
|
+
const id = `toast-${++idCounter.current}-${Date.now()}`;
|
|
163
|
+
const instance = {
|
|
164
|
+
...options,
|
|
165
|
+
id,
|
|
166
|
+
createdAt: Date.now(),
|
|
167
|
+
duration: options.duration ?? defaultDuration
|
|
168
|
+
};
|
|
169
|
+
setToasts((prev) => [...prev, instance].slice(-maxVisible * 2));
|
|
170
|
+
return id;
|
|
171
|
+
}, [defaultDuration, maxVisible]);
|
|
172
|
+
const dismiss = useCallback((id) => {
|
|
173
|
+
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
174
|
+
}, []);
|
|
175
|
+
const dismissAll = useCallback(() => {
|
|
176
|
+
setToasts([]);
|
|
177
|
+
}, []);
|
|
178
|
+
const inset = isMobile ? tokens.spacing.sm : tokens.spacing.md;
|
|
179
|
+
const positionStyles = {
|
|
180
|
+
"top-right": { top: inset, right: inset },
|
|
181
|
+
"top-left": { top: inset, left: inset },
|
|
182
|
+
"bottom-right": { bottom: inset, right: inset },
|
|
183
|
+
"bottom-left": { bottom: inset, left: inset },
|
|
184
|
+
"top-center": { top: inset, left: "50%", transform: "translateX(-50%)" },
|
|
185
|
+
"bottom-center": { bottom: inset, left: "50%", transform: "translateX(-50%)" }
|
|
186
|
+
};
|
|
187
|
+
const isBottom = position.startsWith("bottom");
|
|
188
|
+
const visibleToasts = toasts.slice(-maxVisible);
|
|
189
|
+
return /* @__PURE__ */ jsxs(ToastContext.Provider, { value: { toast, dismiss, dismissAll }, children: [
|
|
190
|
+
children,
|
|
191
|
+
visibleToasts.length > 0 && /* @__PURE__ */ jsx(
|
|
192
|
+
"div",
|
|
193
|
+
{
|
|
194
|
+
"aria-live": visibleToasts.some((t) => t.status === "critical" || t.status === "serious") ? "assertive" : "polite",
|
|
195
|
+
"aria-atomic": "false",
|
|
196
|
+
style: {
|
|
197
|
+
position: "fixed",
|
|
198
|
+
zIndex: 9999,
|
|
199
|
+
display: "flex",
|
|
200
|
+
flexDirection: isBottom ? "column-reverse" : "column",
|
|
201
|
+
gap: tokens.spacing.sm,
|
|
202
|
+
pointerEvents: "none",
|
|
203
|
+
...positionStyles[position]
|
|
204
|
+
},
|
|
205
|
+
children: visibleToasts.map((t) => /* @__PURE__ */ jsx("div", { style: { pointerEvents: "auto" }, children: /* @__PURE__ */ jsx(ToastItem, { toast: t, onDismiss: dismiss }) }, t.id))
|
|
206
|
+
}
|
|
207
|
+
),
|
|
208
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
209
|
+
@keyframes zendir-toast-enter {
|
|
210
|
+
from { opacity: 0; transform: translateX(20px); }
|
|
211
|
+
to { opacity: 1; transform: translateX(0); }
|
|
212
|
+
}
|
|
213
|
+
@keyframes zendir-toast-exit {
|
|
214
|
+
from { opacity: 1; transform: translateX(0); }
|
|
215
|
+
to { opacity: 0; transform: translateX(20px); }
|
|
216
|
+
}
|
|
217
|
+
@media (prefers-reduced-motion: reduce) {
|
|
218
|
+
@keyframes zendir-toast-enter { from { opacity: 0; } to { opacity: 1; } }
|
|
219
|
+
@keyframes zendir-toast-exit { from { opacity: 1; } to { opacity: 0; } }
|
|
220
|
+
}
|
|
221
|
+
` })
|
|
222
|
+
] });
|
|
223
|
+
});
|
|
224
|
+
export {
|
|
225
|
+
ToastProvider,
|
|
226
|
+
useToast,
|
|
227
|
+
useToastManager
|
|
228
|
+
};
|
|
229
|
+
//# sourceMappingURL=Toast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toast.js","sources":["../../../src/react/core/Toast.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - Toast / Notification System\r\n * \r\n * Contextual toast notifications with queue management, auto-dismiss,\r\n * and Astro UX status colors. Essential for operator dashboards surfacing\r\n * connection events, command results, and system alerts.\r\n * \r\n * Astro UX Compliance:\r\n * - 6-level status colors (off, standby, normal, caution, serious, critical)\r\n * - Positioned top-right (operator dashboard convention)\r\n * - Reduced motion support\r\n * - ARIA live region for screen readers\r\n * \r\n * @example\r\n * ```tsx\r\n * // Wrap app in ToastProvider\r\n * <ToastProvider>\r\n * <App />\r\n * </ToastProvider>\r\n * \r\n * // Use in any component\r\n * const toast = useToast();\r\n * toast({ status: 'normal', title: 'Connected', message: 'MQTT link established' });\r\n * toast({ status: 'caution', title: 'SAFE Mode', message: 'Spacecraft entered SAFE mode', duration: 0 });\r\n * toast({ status: 'critical', title: 'Link Lost', message: 'Downlink signal below threshold' });\r\n * ```\r\n */\r\n\r\nimport React, { memo, createContext, useContext, useState, useCallback, useRef, useEffect } from 'react';\r\nimport { useTheme } from '../theme';\r\nimport { safeAccentText } from '../utils';\r\nimport { useBreakpoint } from './layout/useBreakpoint';\r\n\r\n// ─── Types ───────────────────────────────────────────────────────────────────\r\n\r\nexport type ToastStatus = 'normal' | 'standby' | 'caution' | 'serious' | 'critical' | 'off';\r\nexport type ToastPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center';\r\n\r\nexport interface ToastOptions {\r\n /** Status level (determines color) */\r\n status?: ToastStatus;\r\n /** Title text (bold) */\r\n title: string;\r\n /** Description text */\r\n message?: string;\r\n /** Auto-dismiss duration in ms (0 = persistent, default 5000) */\r\n duration?: number;\r\n /** Dismissible by user click (default true) */\r\n dismissible?: boolean;\r\n /** Icon override */\r\n icon?: React.ReactNode;\r\n /** Action button */\r\n action?: {\r\n label: string;\r\n onClick: () => void;\r\n };\r\n}\r\n\r\ninterface ToastInstance extends ToastOptions {\r\n id: string;\r\n createdAt: number;\r\n}\r\n\r\n// ─── Context ─────────────────────────────────────────────────────────────────\r\n\r\ntype ToastFn = (options: ToastOptions) => string;\r\n\r\ninterface ToastContextValue {\r\n toast: ToastFn;\r\n dismiss: (id: string) => void;\r\n dismissAll: () => void;\r\n}\r\n\r\nconst ToastContext = createContext<ToastContextValue | null>(null);\r\n\r\n// ─── Hook ────────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Hook to show toast notifications.\r\n * Must be used within a `<ToastProvider>`.\r\n * \r\n * @example\r\n * ```tsx\r\n * const toast = useToast();\r\n * toast({ status: 'normal', title: 'Success', message: 'Command sent' });\r\n * ```\r\n */\r\nexport function useToast(): ToastFn {\r\n const ctx = useContext(ToastContext);\r\n if (!ctx) throw new Error('useToast must be used within <ToastProvider>');\r\n return ctx.toast;\r\n}\r\n\r\n/**\r\n * Hook to access full toast API (toast, dismiss, dismissAll).\r\n */\r\nexport function useToastManager(): ToastContextValue {\r\n const ctx = useContext(ToastContext);\r\n if (!ctx) throw new Error('useToastManager must be used within <ToastProvider>');\r\n return ctx;\r\n}\r\n\r\n// ─── Toast Item ──────────────────────────────────────────────────────────────\r\n\r\nconst ToastItem = memo(function ToastItem({\r\n toast: t,\r\n onDismiss,\r\n}: {\r\n toast: ToastInstance;\r\n onDismiss: (id: string) => void;\r\n}): React.ReactElement {\r\n const { tokens } = useTheme();\r\n const [exiting, setExiting] = useState(false);\r\n const dismissTimeoutRef = useRef<ReturnType<typeof setTimeout>>();\r\n \r\n // Cleanup dismiss timeout on unmount\r\n useEffect(() => {\r\n return () => { clearTimeout(dismissTimeoutRef.current); };\r\n }, []);\r\n \r\n const statusColors: Record<string, string> = {\r\n normal: tokens.colors.status.normal,\r\n standby: tokens.colors.status.standby,\r\n caution: tokens.colors.status.caution,\r\n serious: tokens.colors.status.serious,\r\n critical: tokens.colors.status.critical,\r\n off: tokens.colors.status.off,\r\n };\r\n \r\n const color = statusColors[t.status || 'off'] || tokens.colors.status.off;\r\n \r\n const handleDismiss = useCallback(() => {\r\n setExiting(true);\r\n dismissTimeoutRef.current = setTimeout(() => onDismiss(t.id), 200);\r\n }, [t.id, onDismiss]);\r\n \r\n // Auto-dismiss\r\n useEffect(() => {\r\n const dur = t.duration ?? 5000;\r\n if (dur <= 0) return;\r\n const timer = setTimeout(handleDismiss, dur);\r\n return () => clearTimeout(timer);\r\n }, [t.duration, handleDismiss]);\r\n \r\n // Status icon — Astro UX dual-coded shapes\r\n const statusIcon = (() => {\r\n const s = 10;\r\n const h = s / 2;\r\n const status = t.status || 'off';\r\n const sharedStyle: React.CSSProperties = { flexShrink: 0, marginTop: '3px' };\r\n switch (status) {\r\n case 'critical':\r\n return (\r\n <svg width={s} height={s} viewBox={`0 0 ${s} ${s}`} style={sharedStyle}>\r\n <polygon points={`${h},${s} 0,0 ${s},0`} fill={color} />\r\n </svg>\r\n );\r\n case 'serious':\r\n return (\r\n <svg width={s} height={s} viewBox={`0 0 ${s} ${s}`} style={sharedStyle}>\r\n <polygon points={`${h},0 ${s},${h} ${h},${s} 0,${h}`} fill={color} />\r\n </svg>\r\n );\r\n case 'caution':\r\n return (\r\n <svg width={s} height={s} viewBox={`0 0 ${s} ${s}`} style={sharedStyle}>\r\n <rect width={s} height={s} fill={color} />\r\n </svg>\r\n );\r\n case 'standby':\r\n return (\r\n <svg width={s} height={s} viewBox=\"0 0 12 12\" style={sharedStyle}>\r\n <circle cx=\"6\" cy=\"6\" r=\"3.5\" fill=\"none\" stroke={color} strokeWidth=\"2\" />\r\n </svg>\r\n );\r\n case 'off':\r\n return (\r\n <svg width={s} height={s} viewBox=\"0 0 12 12\" style={sharedStyle}>\r\n <circle cx=\"6\" cy=\"6\" r=\"3\" fill={color} />\r\n </svg>\r\n );\r\n default: // normal\r\n return (\r\n <svg width={s} height={s} viewBox={`0 0 ${s} ${s}`} style={sharedStyle}>\r\n <circle cx={h} cy={h} r={h} fill={color} />\r\n </svg>\r\n );\r\n }\r\n })();\r\n \r\n return (\r\n <div\r\n role=\"alert\"\r\n style={{\r\n display: 'flex',\r\n gap: tokens.spacing.sm,\r\n padding: `${tokens.spacing.sm} ${tokens.spacing.md}`,\r\n backgroundColor: tokens.colors.background.elevated,\r\n border: `1px solid ${color}30`,\r\n borderLeft: `3px solid ${color}`,\r\n borderRadius: tokens.borderRadius.md,\r\n boxShadow: `${tokens.shadows.lg}, 0 0 20px ${color}15`,\r\n maxWidth: 'min(400px, calc(100vw - 32px))',\r\n minWidth: 'min(280px, calc(100vw - 32px))',\r\n fontFamily: tokens.typography.fontFamily.primary,\r\n animation: exiting\r\n ? `zendir-toast-exit 200ms ${tokens.animation.easing.default} forwards`\r\n : `zendir-toast-enter 300ms ${tokens.animation.easing.default}`,\r\n transition: tokens.animation.normal,\r\n }}\r\n >\r\n {t.icon || statusIcon}\r\n \r\n <div style={{ flex: 1, minWidth: 0 }}>\r\n <div style={{\r\n fontSize: tokens.typography.fontSize.sm,\r\n fontWeight: tokens.typography.fontWeight.semibold,\r\n color: tokens.colors.text.primary,\r\n lineHeight: tokens.typography.lineHeight.tight,\r\n }}>\r\n {t.title}\r\n </div>\r\n {t.message && (\r\n <div style={{\r\n fontSize: tokens.typography.fontSize.xs,\r\n color: tokens.colors.text.secondary,\r\n marginTop: '2px',\r\n lineHeight: tokens.typography.lineHeight.normal,\r\n }}>\r\n {t.message}\r\n </div>\r\n )}\r\n {t.action && (\r\n <button\r\n onClick={t.action.onClick}\r\n style={{\r\n marginTop: tokens.spacing.xs,\r\n fontSize: tokens.typography.fontSize.xs,\r\n fontWeight: tokens.typography.fontWeight.semibold,\r\n color: safeAccentText(tokens.colors.accent.primary),\r\n background: 'none',\r\n border: 'none',\r\n padding: 0,\r\n cursor: 'pointer',\r\n fontFamily: tokens.typography.fontFamily.primary,\r\n }}\r\n >\r\n {t.action.label}\r\n </button>\r\n )}\r\n </div>\r\n \r\n {(t.dismissible !== false) && (\r\n <button\r\n aria-label=\"Dismiss notification\"\r\n onClick={handleDismiss}\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n width: 44,\r\n height: 44,\r\n border: 'none',\r\n background: 'none',\r\n color: tokens.colors.text.tertiary,\r\n cursor: 'pointer',\r\n borderRadius: tokens.borderRadius.sm,\r\n padding: tokens.spacing.xs,\r\n flexShrink: 0,\r\n transition: tokens.animation.fast,\r\n }}\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\r\n </svg>\r\n </button>\r\n )}\r\n </div>\r\n );\r\n});\r\n\r\n// ─── Provider ────────────────────────────────────────────────────────────────\r\n\r\nexport interface ToastProviderProps {\r\n /** Toast position (default: top-right) */\r\n position?: ToastPosition;\r\n /** Maximum visible toasts (default: 5) */\r\n maxVisible?: number;\r\n /** Default duration in ms (default: 5000) */\r\n defaultDuration?: number;\r\n /** Children */\r\n children: React.ReactNode;\r\n}\r\n\r\nexport const ToastProvider = memo(function ToastProvider({\r\n position = 'top-right',\r\n maxVisible = 5,\r\n defaultDuration = 5000,\r\n children,\r\n}: ToastProviderProps): React.ReactElement {\r\n const { tokens } = useTheme();\r\n const { isMobile } = useBreakpoint();\r\n const [toasts, setToasts] = useState<ToastInstance[]>([]);\r\n const idCounter = useRef(0);\r\n \r\n const toast = useCallback((options: ToastOptions): string => {\r\n const id = `toast-${++idCounter.current}-${Date.now()}`;\r\n const instance: ToastInstance = {\r\n ...options,\r\n id,\r\n createdAt: Date.now(),\r\n duration: options.duration ?? defaultDuration,\r\n };\r\n setToasts(prev => [...prev, instance].slice(-maxVisible * 2)); // Keep buffer\r\n return id;\r\n }, [defaultDuration, maxVisible]);\r\n \r\n const dismiss = useCallback((id: string) => {\r\n setToasts(prev => prev.filter(t => t.id !== id));\r\n }, []);\r\n \r\n const dismissAll = useCallback(() => {\r\n setToasts([]);\r\n }, []);\r\n \r\n // Position styles\r\n const inset = isMobile ? tokens.spacing.sm : tokens.spacing.md;\r\n const positionStyles: Record<ToastPosition, React.CSSProperties> = {\r\n 'top-right': { top: inset, right: inset },\r\n 'top-left': { top: inset, left: inset },\r\n 'bottom-right': { bottom: inset, right: inset },\r\n 'bottom-left': { bottom: inset, left: inset },\r\n 'top-center': { top: inset, left: '50%', transform: 'translateX(-50%)' },\r\n 'bottom-center': { bottom: inset, left: '50%', transform: 'translateX(-50%)' },\r\n };\r\n \r\n const isBottom = position.startsWith('bottom');\r\n const visibleToasts = toasts.slice(-maxVisible);\r\n \r\n return (\r\n <ToastContext.Provider value={{ toast, dismiss, dismissAll }}>\r\n {children}\r\n \r\n {/* Toast container */}\r\n {visibleToasts.length > 0 && (\r\n <div\r\n aria-live={visibleToasts.some(t => t.status === 'critical' || t.status === 'serious') ? 'assertive' : 'polite'}\r\n aria-atomic=\"false\"\r\n style={{\r\n position: 'fixed',\r\n zIndex: 9999,\r\n display: 'flex',\r\n flexDirection: isBottom ? 'column-reverse' : 'column',\r\n gap: tokens.spacing.sm,\r\n pointerEvents: 'none',\r\n ...positionStyles[position],\r\n }}\r\n >\r\n {visibleToasts.map(t => (\r\n <div key={t.id} style={{ pointerEvents: 'auto' }}>\r\n <ToastItem toast={t} onDismiss={dismiss} />\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n \r\n <style>{`\r\n @keyframes zendir-toast-enter {\r\n from { opacity: 0; transform: translateX(20px); }\r\n to { opacity: 1; transform: translateX(0); }\r\n }\r\n @keyframes zendir-toast-exit {\r\n from { opacity: 1; transform: translateX(0); }\r\n to { opacity: 0; transform: translateX(20px); }\r\n }\r\n @media (prefers-reduced-motion: reduce) {\r\n @keyframes zendir-toast-enter { from { opacity: 0; } to { opacity: 1; } }\r\n @keyframes zendir-toast-exit { from { opacity: 1; } to { opacity: 0; } }\r\n }\r\n `}</style>\r\n </ToastContext.Provider>\r\n );\r\n});\r\n\r\nexport default ToastProvider;\r\n"],"names":["ToastItem","ToastProvider"],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface ToggleProps {
|
|
4
|
+
/** Checked state */
|
|
5
|
+
checked?: boolean;
|
|
6
|
+
/** Change handler */
|
|
7
|
+
onChange?: (checked: boolean) => void;
|
|
8
|
+
/** Label text */
|
|
9
|
+
label?: string;
|
|
10
|
+
/** Label position */
|
|
11
|
+
labelPosition?: 'left' | 'right';
|
|
12
|
+
/** Disabled state */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** Size variant */
|
|
15
|
+
size?: 'small' | 'medium';
|
|
16
|
+
/** Custom className */
|
|
17
|
+
className?: string;
|
|
18
|
+
/** Name attribute */
|
|
19
|
+
name?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const Toggle: React.MemoExoticComponent<React.ForwardRefExoticComponent<ToggleProps & React.RefAttributes<HTMLInputElement>>>;
|
|
22
|
+
export default Toggle;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { memo, forwardRef, useState, useId } from "react";
|
|
3
|
+
import { classNames } from "../utils/index.js";
|
|
4
|
+
import { useTheme } from "../theme/ThemeProvider.js";
|
|
5
|
+
const Toggle = memo(forwardRef(function Toggle2({
|
|
6
|
+
checked = false,
|
|
7
|
+
onChange,
|
|
8
|
+
label,
|
|
9
|
+
labelPosition = "right",
|
|
10
|
+
disabled = false,
|
|
11
|
+
size = "medium",
|
|
12
|
+
className = "",
|
|
13
|
+
name
|
|
14
|
+
}, ref) {
|
|
15
|
+
const { tokens, theme } = useTheme();
|
|
16
|
+
const [focused, setFocused] = useState(false);
|
|
17
|
+
const [hovered, setHovered] = useState(false);
|
|
18
|
+
const id = useId();
|
|
19
|
+
const sizeConfig = {
|
|
20
|
+
small: { width: 34, height: 18, knobSize: 14 },
|
|
21
|
+
medium: { width: 40, height: 22, knobSize: 16 }
|
|
22
|
+
};
|
|
23
|
+
const config = sizeConfig[size];
|
|
24
|
+
const touchPadV = Math.max(0, (44 - config.height) / 2);
|
|
25
|
+
const touchPadH = Math.max(0, (44 - config.width) / 2);
|
|
26
|
+
const handleClick = () => {
|
|
27
|
+
if (!disabled) {
|
|
28
|
+
onChange == null ? void 0 : onChange(!checked);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const isTransparentTheme = theme === "transparent" || theme === "transparent-bold" || theme === "transparent-minimal";
|
|
32
|
+
const transparentDefault = tokens.colors.interactive.transparentDefault;
|
|
33
|
+
const transparentHover = tokens.colors.interactive.transparentHover;
|
|
34
|
+
const bgColor = checked ? tokens.colors.accent.primary : isTransparentTheme && transparentDefault && transparentHover ? hovered && !disabled ? transparentHover : transparentDefault : hovered && !disabled ? `${tokens.colors.border.muted}` : tokens.colors.border.muted;
|
|
35
|
+
const toggle = /* @__PURE__ */ jsxs(
|
|
36
|
+
"div",
|
|
37
|
+
{
|
|
38
|
+
role: "switch",
|
|
39
|
+
"aria-checked": checked,
|
|
40
|
+
"aria-disabled": disabled,
|
|
41
|
+
"aria-label": !label ? name ?? "Toggle" : void 0,
|
|
42
|
+
tabIndex: disabled ? -1 : 0,
|
|
43
|
+
onClick: handleClick,
|
|
44
|
+
onKeyDown: (e) => (e.key === " " || e.key === "Enter") && (e.preventDefault(), handleClick()),
|
|
45
|
+
onMouseEnter: () => setHovered(true),
|
|
46
|
+
onMouseLeave: () => setHovered(false),
|
|
47
|
+
onFocus: () => setFocused(true),
|
|
48
|
+
onBlur: () => setFocused(false),
|
|
49
|
+
style: {
|
|
50
|
+
padding: `${touchPadV}px ${touchPadH}px`,
|
|
51
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
52
|
+
flexShrink: 0,
|
|
53
|
+
outline: "none",
|
|
54
|
+
display: "inline-flex",
|
|
55
|
+
alignItems: "center"
|
|
56
|
+
},
|
|
57
|
+
children: [
|
|
58
|
+
/* @__PURE__ */ jsx(
|
|
59
|
+
"div",
|
|
60
|
+
{
|
|
61
|
+
style: {
|
|
62
|
+
width: config.width,
|
|
63
|
+
height: config.height,
|
|
64
|
+
backgroundColor: bgColor,
|
|
65
|
+
...isTransparentTheme && !checked && { backdropFilter: "blur(8px)", WebkitBackdropFilter: "blur(8px)" },
|
|
66
|
+
borderRadius: config.height / 2,
|
|
67
|
+
opacity: disabled ? 0.5 : 1,
|
|
68
|
+
position: "relative",
|
|
69
|
+
transition: `${tokens.animation.normal}, opacity ${tokens.animation.duration.normal}ms ${tokens.animation.easing.default}`,
|
|
70
|
+
flexShrink: 0,
|
|
71
|
+
boxShadow: checked ? `0 0 10px ${tokens.colors.accent.primary}25, inset 0 1px 1px rgba(255,255,255,0.08)` : focused ? `0 0 0 2px ${tokens.colors.accent.primary}25` : "inset 0 1px 2px rgba(0,0,0,0.15)"
|
|
72
|
+
},
|
|
73
|
+
children: /* @__PURE__ */ jsx(
|
|
74
|
+
"div",
|
|
75
|
+
{
|
|
76
|
+
style: {
|
|
77
|
+
position: "absolute",
|
|
78
|
+
top: (config.height - config.knobSize) / 2,
|
|
79
|
+
left: checked ? config.width - config.knobSize - 3 : 3,
|
|
80
|
+
width: config.knobSize,
|
|
81
|
+
height: config.knobSize,
|
|
82
|
+
backgroundColor: "#ffffff",
|
|
83
|
+
borderRadius: "50%",
|
|
84
|
+
boxShadow: checked ? "0 1px 4px rgba(0,0,0,0.25)" : "0 1px 3px rgba(0,0,0,0.2)",
|
|
85
|
+
transition: tokens.animation.spring,
|
|
86
|
+
transform: hovered && !disabled ? "scale(1.05)" : "scale(1)"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
),
|
|
92
|
+
/* @__PURE__ */ jsx(
|
|
93
|
+
"input",
|
|
94
|
+
{
|
|
95
|
+
ref,
|
|
96
|
+
type: "checkbox",
|
|
97
|
+
id,
|
|
98
|
+
name,
|
|
99
|
+
checked,
|
|
100
|
+
disabled,
|
|
101
|
+
onChange: () => {
|
|
102
|
+
},
|
|
103
|
+
tabIndex: -1,
|
|
104
|
+
"aria-hidden": "true",
|
|
105
|
+
style: {
|
|
106
|
+
position: "absolute",
|
|
107
|
+
opacity: 0,
|
|
108
|
+
width: 0,
|
|
109
|
+
height: 0,
|
|
110
|
+
pointerEvents: "none"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
if (!label) {
|
|
118
|
+
return /* @__PURE__ */ jsx("div", { className: classNames("zendir-toggle", className), children: toggle });
|
|
119
|
+
}
|
|
120
|
+
return /* @__PURE__ */ jsxs(
|
|
121
|
+
"label",
|
|
122
|
+
{
|
|
123
|
+
htmlFor: id,
|
|
124
|
+
className: classNames("zendir-toggle", className),
|
|
125
|
+
style: {
|
|
126
|
+
display: "inline-flex",
|
|
127
|
+
alignItems: "center",
|
|
128
|
+
gap: tokens.spacing.sm,
|
|
129
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
130
|
+
flexDirection: labelPosition === "left" ? "row-reverse" : "row"
|
|
131
|
+
},
|
|
132
|
+
children: [
|
|
133
|
+
toggle,
|
|
134
|
+
/* @__PURE__ */ jsx(
|
|
135
|
+
"span",
|
|
136
|
+
{
|
|
137
|
+
style: {
|
|
138
|
+
fontSize: tokens.typography.fontSize.sm,
|
|
139
|
+
color: disabled ? tokens.colors.text.muted : tokens.colors.text.primary
|
|
140
|
+
},
|
|
141
|
+
children: label
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
}));
|
|
148
|
+
export {
|
|
149
|
+
Toggle
|
|
150
|
+
};
|
|
151
|
+
//# sourceMappingURL=Toggle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toggle.js","sources":["../../../src/react/core/Toggle.tsx"],"sourcesContent":["/**\n * @zendir/ui - Toggle/Switch Component\n * \n * Toggle switch following Astro UX Design System with Zendir purple accents.\n * \n * Astro UX Compliance:\n * - Binary on/off control\n * - Clear visual states\n * - Accessible keyboard support\n * \n * Zendir Enhancements:\n * - Purple accent when active\n * - Subtle glow effect\n * - Smooth spring animation\n * \n * @example\n * ```tsx\n * <Toggle checked={enabled} onChange={setEnabled} label=\"Enable telemetry\" />\n * ```\n */\n\nimport React, { memo, forwardRef, useId, useState } from 'react';\nimport { useTheme } from '../theme';\nimport { classNames } from '../utils';\n\nexport interface ToggleProps {\n /** Checked state */\n checked?: boolean;\n /** Change handler */\n onChange?: (checked: boolean) => void;\n /** Label text */\n label?: string;\n /** Label position */\n labelPosition?: 'left' | 'right';\n /** Disabled state */\n disabled?: boolean;\n /** Size variant */\n size?: 'small' | 'medium';\n /** Custom className */\n className?: string;\n /** Name attribute */\n name?: string;\n}\n\nexport const Toggle = memo(forwardRef<HTMLInputElement, ToggleProps>(function Toggle(\n {\n checked = false,\n onChange,\n label,\n labelPosition = 'right',\n disabled = false,\n size = 'medium',\n className = '',\n name,\n },\n ref\n): React.ReactElement {\n const { tokens, theme } = useTheme();\n const [focused, setFocused] = useState(false);\n const [hovered, setHovered] = useState(false);\n const id = useId();\n \n const sizeConfig = {\n small: { width: 34, height: 18, knobSize: 14 },\n medium: { width: 40, height: 22, knobSize: 16 },\n };\n const config = sizeConfig[size];\n // Touch target: 44px minimum via padding around the visual toggle\n const touchPadV = Math.max(0, (44 - config.height) / 2);\n const touchPadH = Math.max(0, (44 - config.width) / 2);\n \n const handleClick = () => {\n if (!disabled) {\n onChange?.(!checked);\n }\n };\n \n const isTransparentTheme = theme === 'transparent' || theme === 'transparent-bold' || theme === 'transparent-minimal';\n const transparentDefault = tokens.colors.interactive.transparentDefault;\n const transparentHover = tokens.colors.interactive.transparentHover;\n const bgColor = checked\n ? tokens.colors.accent.primary\n : isTransparentTheme && transparentDefault && transparentHover\n ? (hovered && !disabled ? transparentHover : transparentDefault)\n : hovered && !disabled\n ? `${tokens.colors.border.muted}`\n : tokens.colors.border.muted;\n \n const toggle = (\n <div\n role=\"switch\"\n aria-checked={checked}\n aria-disabled={disabled}\n aria-label={!label ? (name ?? 'Toggle') : undefined}\n tabIndex={disabled ? -1 : 0}\n onClick={handleClick}\n onKeyDown={(e) => (e.key === ' ' || e.key === 'Enter') && (e.preventDefault(), handleClick())}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n onFocus={() => setFocused(true)}\n onBlur={() => setFocused(false)}\n style={{\n padding: `${touchPadV}px ${touchPadH}px`,\n cursor: disabled ? 'not-allowed' : 'pointer',\n flexShrink: 0,\n outline: 'none',\n display: 'inline-flex',\n alignItems: 'center',\n }}\n >\n <div\n style={{\n width: config.width,\n height: config.height,\n backgroundColor: bgColor,\n ...(isTransparentTheme && !checked && { backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)' }),\n borderRadius: config.height / 2,\n opacity: disabled ? 0.5 : 1,\n position: 'relative',\n transition: `${tokens.animation.normal}, opacity ${tokens.animation.duration.normal}ms ${tokens.animation.easing.default}`,\n flexShrink: 0,\n boxShadow: checked \n ? `0 0 10px ${tokens.colors.accent.primary}25, inset 0 1px 1px rgba(255,255,255,0.08)` \n : focused \n ? `0 0 0 2px ${tokens.colors.accent.primary}25` \n : 'inset 0 1px 2px rgba(0,0,0,0.15)',\n }}\n >\n <div\n style={{\n position: 'absolute',\n top: (config.height - config.knobSize) / 2,\n left: checked ? config.width - config.knobSize - 3 : 3,\n width: config.knobSize,\n height: config.knobSize,\n backgroundColor: '#ffffff',\n borderRadius: '50%',\n boxShadow: checked \n ? '0 1px 4px rgba(0,0,0,0.25)' \n : '0 1px 3px rgba(0,0,0,0.2)',\n transition: tokens.animation.spring,\n transform: hovered && !disabled ? 'scale(1.05)' : 'scale(1)',\n }}\n />\n </div>\n <input\n ref={ref}\n type=\"checkbox\"\n id={id}\n name={name}\n checked={checked}\n disabled={disabled}\n onChange={() => {}}\n tabIndex={-1}\n aria-hidden=\"true\"\n style={{\n position: 'absolute',\n opacity: 0,\n width: 0,\n height: 0,\n pointerEvents: 'none',\n }}\n />\n </div>\n );\n \n if (!label) {\n return (\n <div className={classNames('zendir-toggle', className)}>\n {toggle}\n </div>\n );\n }\n \n return (\n <label\n htmlFor={id}\n className={classNames('zendir-toggle', className)}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: tokens.spacing.sm,\n cursor: disabled ? 'not-allowed' : 'pointer',\n flexDirection: labelPosition === 'left' ? 'row-reverse' : 'row',\n }}\n >\n {toggle}\n <span\n style={{\n fontSize: tokens.typography.fontSize.sm,\n color: disabled ? tokens.colors.text.muted : tokens.colors.text.primary,\n }}\n >\n {label}\n </span>\n </label>\n );\n}));\n\nexport default Toggle;\n"],"names":["Toggle"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
export type TooltipPlacement = 'top' | 'bottom' | 'left' | 'right';
|
|
4
|
+
export interface TooltipProps {
|
|
5
|
+
/** Tooltip content */
|
|
6
|
+
content: React.ReactNode;
|
|
7
|
+
/** Placement */
|
|
8
|
+
placement?: TooltipPlacement;
|
|
9
|
+
/** Delay before showing (ms) */
|
|
10
|
+
delay?: number;
|
|
11
|
+
/** Disabled state */
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** Children element to trigger tooltip */
|
|
14
|
+
children: React.ReactElement;
|
|
15
|
+
/** Custom className */
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const Tooltip: React.NamedExoticComponent<TooltipProps>;
|
|
19
|
+
export default Tooltip;
|