@zendir/ui 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.md +419 -406
  2. package/dist/react/3d/CesiumCaptureSource.js.map +1 -1
  3. package/dist/react/3d/ZenSpace3D.js.map +1 -1
  4. package/dist/react/3d/ZenSpace3DCesium.js.map +1 -1
  5. package/dist/react/3d/ZenSpace3DShaders.js.map +1 -1
  6. package/dist/react/3d/ZenSpace3DUtils.js.map +1 -1
  7. package/dist/react/3d/capturePngAnalysis.js.map +1 -1
  8. package/dist/react/3d/threeLoader.js.map +1 -1
  9. package/dist/react/astro/ClassificationBanner.js.map +1 -1
  10. package/dist/react/astro/GlobalStatusBar.js.map +1 -1
  11. package/dist/react/astro/MissionClock.js.map +1 -1
  12. package/dist/react/astro/MonitoringIcon.js.map +1 -1
  13. package/dist/react/astro/Notification.js.map +1 -1
  14. package/dist/react/astro/Progress.js.map +1 -1
  15. package/dist/react/astro/SimulationControls.js.map +1 -1
  16. package/dist/react/astro/StatusIndicator.js.map +1 -1
  17. package/dist/react/astro/UnifiedTimeline.js.map +1 -1
  18. package/dist/react/cards/AccessCard.js.map +1 -1
  19. package/dist/react/cards/OrbitCard.js.map +1 -1
  20. package/dist/react/cards/SpacecraftCard.js.map +1 -1
  21. package/dist/react/cards/TelemetryCard.js.map +1 -1
  22. package/dist/react/cards/TelemetryStreamCard.js.map +1 -1
  23. package/dist/react/charts/GroundTrackMap.js.map +1 -1
  24. package/dist/react/charts/GroundTrackMapLeaflet.js.map +1 -1
  25. package/dist/react/charts/groundTrackMapLeafletTiles.js.map +1 -1
  26. package/dist/react/charts/groundTrackMapLeafletUtils.js.map +1 -1
  27. package/dist/react/charts/unified/AstroChart.js.map +1 -1
  28. package/dist/react/charts/unified/PowerOverviewChart.js.map +1 -1
  29. package/dist/react/charts/unified/domain.js.map +1 -1
  30. package/dist/react/charts/unified/generators.js.map +1 -1
  31. package/dist/react/charts/unified/presets.js.map +1 -1
  32. package/dist/react/charts/unified/sync.js.map +1 -1
  33. package/dist/react/charts/unified/theme.js.map +1 -1
  34. package/dist/react/charts/unified/useChartStream.js.map +1 -1
  35. package/dist/react/chatgpt/index.js.map +1 -1
  36. package/dist/react/context/CategoryContext.js.map +1 -1
  37. package/dist/react/context/DisplaySettingsContext.js.map +1 -1
  38. package/dist/react/context/SpatialSelectionContext.js.map +1 -1
  39. package/dist/react/core/data/DataTable.js.map +1 -1
  40. package/dist/react/core/data/DataValue.js.map +1 -1
  41. package/dist/react/core/data/propertyConfig.js.map +1 -1
  42. package/dist/react/core/display/AstroIcon.js.map +1 -1
  43. package/dist/react/core/display/Badge.js.map +1 -1
  44. package/dist/react/core/display/CardHeader.js.map +1 -1
  45. package/dist/react/core/display/Container.js.map +1 -1
  46. package/dist/react/core/display/CopyButton.js.map +1 -1
  47. package/dist/react/core/display/GlassCard.js.map +1 -1
  48. package/dist/react/core/display/HeaderIconWithStatus.js.map +1 -1
  49. package/dist/react/core/display/Icon.js.map +1 -1
  50. package/dist/react/core/display/Typography.js.map +1 -1
  51. package/dist/react/core/feedback/ConfirmDialog.js.map +1 -1
  52. package/dist/react/core/feedback/Dialog.js.map +1 -1
  53. package/dist/react/core/feedback/Toast.js.map +1 -1
  54. package/dist/react/core/inputs/Button.js.map +1 -1
  55. package/dist/react/core/inputs/Checkbox.js.map +1 -1
  56. package/dist/react/core/inputs/Input.js.map +1 -1
  57. package/dist/react/core/inputs/LimitsBar.js.map +1 -1
  58. package/dist/react/core/inputs/NumberInput.js.map +1 -1
  59. package/dist/react/core/inputs/PinInput.js.map +1 -1
  60. package/dist/react/core/inputs/Select.js.map +1 -1
  61. package/dist/react/core/inputs/Toggle.js.map +1 -1
  62. package/dist/react/core/layout/Box.js.map +1 -1
  63. package/dist/react/core/layout/Center.js.map +1 -1
  64. package/dist/react/core/layout/Divider.js.map +1 -1
  65. package/dist/react/core/layout/Flex.js.map +1 -1
  66. package/dist/react/core/layout/Grid.js.map +1 -1
  67. package/dist/react/core/layout/Spacer.js.map +1 -1
  68. package/dist/react/core/layout/Stack.js.map +1 -1
  69. package/dist/react/core/layout/responsive.js.map +1 -1
  70. package/dist/react/core/layout/useBreakpoint.js.map +1 -1
  71. package/dist/react/core/navigation/AppBar.js.map +1 -1
  72. package/dist/react/core/navigation/Pagination.js.map +1 -1
  73. package/dist/react/core/navigation/SideNav.js.map +1 -1
  74. package/dist/react/core/navigation/Tabs.js.map +1 -1
  75. package/dist/react/core/overlays/Popover.js.map +1 -1
  76. package/dist/react/core/overlays/SidePanel.js.map +1 -1
  77. package/dist/react/core/overlays/Tooltip.js.map +1 -1
  78. package/dist/react/core/widgets/ActivityPlanner.js.map +1 -1
  79. package/dist/react/core/widgets/Capture.js.map +1 -1
  80. package/dist/react/core/widgets/ChatPanel.js.map +1 -1
  81. package/dist/react/core/widgets/ColorPickerPanel.js.map +1 -1
  82. package/dist/react/core/widgets/CommandBuilder.js.map +1 -1
  83. package/dist/react/core/widgets/ConnectionForm.js.map +1 -1
  84. package/dist/react/core/widgets/FileExplorer.js.map +1 -1
  85. package/dist/react/core/widgets/HexViewer.js.map +1 -1
  86. package/dist/react/core/widgets/ImageFrame.js.map +1 -1
  87. package/dist/react/core/widgets/ImageGallery.js.map +1 -1
  88. package/dist/react/core/widgets/ImagePanel.js.map +1 -1
  89. package/dist/react/core/widgets/LogViewer.js.map +1 -1
  90. package/dist/react/core/widgets/MessageStream.js.map +1 -1
  91. package/dist/react/core/widgets/MissionCalendar.js.map +1 -1
  92. package/dist/react/core/widgets/PacketViewer.js.map +1 -1
  93. package/dist/react/hooks/useCompactMode.js.map +1 -1
  94. package/dist/react/hooks/useSimulationScene.js.map +1 -1
  95. package/dist/react/panels/LayerControlPanel.js.map +1 -1
  96. package/dist/react/panels/ObjectInventoryPanel.js.map +1 -1
  97. package/dist/react/shared/ErrorBoundary.js.map +1 -1
  98. package/dist/react/shared/Skeleton.js.map +1 -1
  99. package/dist/react/theme/ThemeProvider.js +2 -1
  100. package/dist/react/theme/ThemeProvider.js.map +1 -1
  101. package/dist/react/theme/cardAccent.js.map +1 -1
  102. package/dist/react/theme/config.js.map +1 -1
  103. package/dist/react/theme/types.js.map +1 -1
  104. package/dist/react/types.js.map +1 -1
  105. package/dist/react/utils/categoryPalette.js.map +1 -1
  106. package/dist/react/utils/index.js.map +1 -1
  107. package/dist/style.css +216 -216
  108. package/dist/tokens/core.js.map +1 -1
  109. package/dist/tokens/index.js.map +1 -1
  110. package/dist/tokens/palettes/astro.js.map +1 -1
  111. package/dist/tokens/palettes/index.js.map +1 -1
  112. package/dist/tokens/palettes/tailwind.js.map +1 -1
  113. package/dist/tokens/palettes/zendir.js.map +1 -1
  114. package/dist/tokens/themes.js.map +1 -1
  115. package/dist/tokens/tokens.css +533 -533
  116. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"MissionClock.js","names":[],"sources":["../../../src/react/astro/MissionClock.tsx"],"sourcesContent":["/**\n * @zendir/ui - MissionClock Component (Pure React)\n *\n * Advanced mission time display following Astro UX patterns with full\n * space operations support.\n *\n * Features:\n * - Theme-integrated via useTheme()\n * - UTC/Zulu time display\n * - Configurable formats (12h, 24h, ISO)\n * - Optional seconds display\n * - AOS/LOS timer support (Acquisition/Loss of Signal)\n * - MET (Mission Elapsed Time) display\n * - Julian day format (DOY-###)\n * - Simulation time support (custom epoch/time source)\n * - Tabular numbers for stability\n * - Zendir SDK integration for real-time data\n *\n * Space Operations Terminology:\n * - AOS: Acquisition of Signal - when satellite rises above horizon\n * - LOS: Loss of Signal - when satellite passes below horizon\n * - TCA: Time of Closest Approach - maximum elevation point\n * - MET: Mission Elapsed Time - time since launch (dd:hh:mm:ss)\n * - DOY: Day of Year - Julian day format\n */\n\nimport React, { memo, useState, useEffect, useCallback, useMemo } from \"react\";\nimport { useTheme } from \"../theme\";\nimport { classNames, tabularNumsStyle } from \"../utils\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type ClockFormat = \"12h\" | \"24h\" | \"iso\" | \"met\";\nexport type DateFormat = \"iso\" | \"julian\" | \"gregorian\" | \"none\";\nexport type TimeSource = \"realtime\" | \"simulation\" | \"custom\";\n\n/**\n * Timer configuration for AOS/LOS countdown/up timers\n */\nexport interface TimerConfig {\n /** Timer label (e.g., \"AOS\", \"LOS\", \"MET\") */\n label: string;\n /** Target timestamp (for countdown) or start timestamp (for countup) */\n timestamp: Date;\n /** Timer direction: 'countdown' counts to target, 'countup' counts from start */\n direction: \"countdown\" | \"countup\";\n /** Optional status color */\n status?: \"normal\" | \"caution\" | \"critical\" | \"standby\";\n /** Show days in timer format */\n showDays?: boolean;\n}\n\n/**\n * Simulation time configuration\n */\nexport interface SimulationTimeConfig {\n /** Simulation epoch (t=0) as Date or ISO string */\n epoch: Date | string;\n /** Current simulation time offset in seconds from epoch */\n elapsedSeconds?: number;\n /** Time scale factor (1 = realtime, 2 = 2x speed, etc.) */\n timeScale?: number;\n /** Whether simulation is running */\n isRunning?: boolean;\n /** Callback to get current simulation time */\n getCurrentTime?: () => Date;\n}\n\nexport interface MissionClockProps {\n /** Clock format */\n format?: ClockFormat;\n /** Timezone label to display */\n timezone?: string;\n /** Hide seconds */\n hideSeconds?: boolean;\n /** Small size variant */\n small?: boolean;\n /** Show date */\n showDate?: boolean;\n /** Date format (iso, julian, gregorian) */\n dateFormat?: DateFormat;\n /** Custom className */\n className?: string;\n /** Click handler */\n onClick?: () => void;\n\n // === AOS/LOS Timer Support ===\n /** AOS timer - countdown/up to Acquisition of Signal */\n aosTimer?: TimerConfig | Date;\n /** LOS timer - countdown/up to Loss of Signal */\n losTimer?: TimerConfig | Date;\n /** Additional custom timers */\n customTimers?: TimerConfig[];\n\n // === Simulation Time Support ===\n /** Time source: realtime, simulation, or custom */\n timeSource?: TimeSource;\n /** Simulation time configuration (for timeSource='simulation') */\n simulationConfig?: SimulationTimeConfig;\n /** Custom time provider (for timeSource='custom') */\n customTime?: Date | (() => Date);\n\n // === Mission Elapsed Time ===\n /** Mission start time for MET display */\n missionStart?: Date | string;\n /** Show MET (Mission Elapsed Time) instead of wall clock */\n showMET?: boolean;\n\n // === Advanced Options ===\n /** Update interval in milliseconds (default: 1000) */\n updateInterval?: number;\n /** Compact mode - single line display */\n compact?: boolean;\n /** Show milliseconds */\n showMilliseconds?: boolean;\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Format duration as dd:hh:mm:ss (MET format)\n */\nfunction formatMET(ms: number, showMilliseconds = false): string {\n const totalSeconds = Math.floor(Math.abs(ms) / 1000);\n const days = Math.floor(totalSeconds / 86400);\n const hours = Math.floor((totalSeconds % 86400) / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n\n const sign = ms < 0 ? \"-\" : \"\";\n\n if (showMilliseconds) {\n const millis = Math.floor(Math.abs(ms) % 1000);\n return `${sign}${days.toString().padStart(2, \"0\")}:${hours.toString().padStart(2, \"0\")}:${minutes.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}.${millis.toString().padStart(3, \"0\")}`;\n }\n\n return `${sign}${days.toString().padStart(2, \"0\")}:${hours.toString().padStart(2, \"0\")}:${minutes.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}`;\n}\n\n/**\n * Format duration for timers (compact: hh:mm:ss or mm:ss)\n */\nfunction formatTimerDuration(ms: number, showDays = false): string {\n const totalSeconds = Math.floor(Math.abs(ms) / 1000);\n const days = Math.floor(totalSeconds / 86400);\n const hours = Math.floor((totalSeconds % 86400) / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n\n const sign = ms < 0 ? \"-\" : \"\";\n\n if (showDays && days > 0) {\n return `${sign}${days}d ${hours.toString().padStart(2, \"0\")}:${minutes.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}`;\n }\n\n if (hours > 0 || showDays) {\n return `${sign}${hours.toString().padStart(2, \"0\")}:${minutes.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}`;\n }\n\n return `${sign}${minutes.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}`;\n}\n\n/**\n * Get Julian day (day of year 001-366)\n */\nfunction getJulianDay(date: Date): string {\n const start = new Date(Date.UTC(date.getUTCFullYear(), 0, 0));\n const diff = date.getTime() - start.getTime();\n const oneDay = 1000 * 60 * 60 * 24;\n const day = Math.floor(diff / oneDay);\n return day.toString().padStart(3, \"0\");\n}\n\n/**\n * Normalize timer config from Date or TimerConfig\n */\nfunction normalizeTimerConfig(\n timer: TimerConfig | Date | undefined,\n label: string,\n): TimerConfig | undefined {\n if (!timer) return undefined;\n if (timer instanceof Date) {\n return {\n label,\n timestamp: timer,\n direction: \"countdown\",\n };\n }\n return timer;\n}\n\n// ============================================================================\n// Timer Sub-component\n// ============================================================================\n\ninterface TimerDisplayProps {\n timer: TimerConfig;\n currentTime: Date;\n tokens: ReturnType<typeof useTheme>[\"tokens\"];\n compact?: boolean;\n}\n\nconst TimerDisplay = memo(function TimerDisplay({\n timer,\n currentTime,\n tokens,\n compact = false,\n}: TimerDisplayProps) {\n const diff =\n timer.direction === \"countdown\"\n ? timer.timestamp.getTime() - currentTime.getTime()\n : currentTime.getTime() - timer.timestamp.getTime();\n\n const isNegative = diff < 0;\n const statusColor = timer.status\n ? tokens.colors.status[timer.status]\n : isNegative\n ? tokens.colors.status.caution\n : tokens.colors.status.normal;\n\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: compact ? \"center\" : \"flex-start\",\n flexDirection: compact ? \"row\" : \"column\",\n gap: compact ? 8 : 2,\n padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`,\n backgroundColor: `${statusColor}15`,\n borderRadius: tokens.borderRadius.sm,\n border: `1px solid ${statusColor}30`,\n }}\n >\n <span\n style={{\n fontSize: tokens.typography.fontSize.xs,\n fontWeight: tokens.typography.fontWeight.semibold,\n color: statusColor,\n textTransform: \"uppercase\",\n letterSpacing: tokens.typography.letterSpacing.wide,\n }}\n >\n {timer.label}\n </span>\n <span\n style={{\n fontSize: compact\n ? tokens.typography.fontSize.sm\n : tokens.typography.fontSize.base,\n fontWeight: tokens.typography.fontWeight.bold, // Bold (700) for timer readability\n fontFamily: tokens.typography.fontFamily.mono,\n color: statusColor,\n ...tabularNumsStyle,\n }}\n >\n {isNegative ? \"+\" : \"\"}\n {formatTimerDuration(diff, timer.showDays)}\n </span>\n </div>\n );\n});\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\n/**\n * MissionClock - Advanced mission time display for space operations\n *\n * Supports real-time clock, simulation time, MET (Mission Elapsed Time),\n * and AOS/LOS timers following Astro UX Design System patterns.\n *\n * @example\n * ```tsx\n * // Basic clock\n * <MissionClock format=\"24h\" timezone=\"UTC\" />\n *\n * // With AOS/LOS timers\n * <MissionClock\n * format=\"24h\"\n * aosTimer={{ label: 'AOS', timestamp: new Date('2024-03-15T10:30:00Z'), direction: 'countdown' }}\n * losTimer={{ label: 'LOS', timestamp: new Date('2024-03-15T10:45:00Z'), direction: 'countdown' }}\n * />\n *\n * // Simulation time\n * <MissionClock\n * timeSource=\"simulation\"\n * simulationConfig={{\n * epoch: new Date('2026-01-01T00:00:00Z'),\n * elapsedSeconds: 3600,\n * timeScale: 1,\n * }}\n * />\n *\n * // Mission Elapsed Time\n * <MissionClock\n * showMET\n * missionStart={new Date('2026-01-01T00:00:00Z')}\n * />\n *\n * // Julian day format\n * <MissionClock showDate dateFormat=\"julian\" />\n * ```\n */\nexport const MissionClock = memo(function MissionClock({\n format = \"24h\",\n timezone = \"UTC\",\n hideSeconds = false,\n small = false,\n showDate = false,\n dateFormat = \"iso\",\n className = \"\",\n onClick,\n aosTimer,\n losTimer,\n customTimers = [],\n timeSource = \"realtime\",\n simulationConfig,\n customTime,\n missionStart,\n showMET = false,\n updateInterval = 1000,\n compact = false,\n showMilliseconds = false,\n}: MissionClockProps): React.ReactElement {\n const { tokens, theme } = useTheme();\n const isTransparentTheme =\n theme === \"transparent\" ||\n theme === \"transparent-bold\" ||\n theme === \"transparent-minimal\";\n\n // State for current time\n const [time, setTime] = useState(() => getCurrentTimeFromSource());\n\n // Normalize timer configs\n const normalizedAOS = useMemo(\n () => normalizeTimerConfig(aosTimer, \"AOS\"),\n [aosTimer],\n );\n const normalizedLOS = useMemo(\n () => normalizeTimerConfig(losTimer, \"LOS\"),\n [losTimer],\n );\n\n // All timers combined\n const allTimers = useMemo(() => {\n const timers: TimerConfig[] = [];\n if (normalizedAOS) timers.push(normalizedAOS);\n if (normalizedLOS) timers.push(normalizedLOS);\n return [...timers, ...customTimers];\n }, [normalizedAOS, normalizedLOS, customTimers]);\n\n // Get current time based on source\n function getCurrentTimeFromSource(): Date {\n switch (timeSource) {\n case \"simulation\":\n if (simulationConfig) {\n if (simulationConfig.getCurrentTime) {\n return simulationConfig.getCurrentTime();\n }\n const epoch =\n typeof simulationConfig.epoch === \"string\"\n ? new Date(simulationConfig.epoch)\n : simulationConfig.epoch;\n const elapsed = (simulationConfig.elapsedSeconds || 0) * 1000;\n return new Date(epoch.getTime() + elapsed);\n }\n return new Date();\n\n case \"custom\":\n if (customTime) {\n return typeof customTime === \"function\" ? customTime() : customTime;\n }\n return new Date();\n\n case \"realtime\":\n default:\n return new Date();\n }\n }\n\n // Format time display\n const formatTimeDisplay = useCallback(\n (date: Date): string => {\n if (showMET && missionStart) {\n const start =\n typeof missionStart === \"string\"\n ? new Date(missionStart)\n : missionStart;\n const elapsed = date.getTime() - start.getTime();\n return formatMET(elapsed, showMilliseconds);\n }\n\n if (format === \"met\" && missionStart) {\n const start =\n typeof missionStart === \"string\"\n ? new Date(missionStart)\n : missionStart;\n const elapsed = date.getTime() - start.getTime();\n return formatMET(elapsed, showMilliseconds);\n }\n\n const hours = date.getUTCHours();\n const mins = date.getUTCMinutes();\n const secs = date.getUTCSeconds();\n const millis = date.getUTCMilliseconds();\n\n let hoursStr: string;\n let suffix = \"\";\n\n if (format === \"12h\") {\n const h12 = hours % 12 || 12;\n hoursStr = h12.toString().padStart(2, \"0\");\n suffix = hours >= 12 ? \" PM\" : \" AM\";\n } else {\n hoursStr = hours.toString().padStart(2, \"0\");\n }\n\n const minsStr = mins.toString().padStart(2, \"0\");\n const secsStr = secs.toString().padStart(2, \"0\");\n const millisStr = millis.toString().padStart(3, \"0\");\n\n if (hideSeconds) {\n return `${hoursStr}:${minsStr}${suffix}`;\n }\n\n if (showMilliseconds) {\n return `${hoursStr}:${minsStr}:${secsStr}.${millisStr}${suffix}`;\n }\n\n return `${hoursStr}:${minsStr}:${secsStr}${suffix}`;\n },\n [format, hideSeconds, showMET, missionStart, showMilliseconds],\n );\n\n // Format date display\n const formatDateDisplay = useCallback(\n (date: Date): string => {\n switch (dateFormat) {\n case \"julian\": {\n const year = date.getUTCFullYear();\n const doy = getJulianDay(date);\n return `${year}/${doy}`;\n }\n case \"gregorian\": {\n const year = date.getUTCFullYear();\n const month = (date.getUTCMonth() + 1).toString().padStart(2, \"0\");\n const day = date.getUTCDate().toString().padStart(2, \"0\");\n return `${month}/${day}/${year}`;\n }\n case \"iso\":\n default:\n if (format === \"iso\") {\n return date.toISOString().split(\"T\")[0];\n }\n const year = date.getUTCFullYear();\n const month = (date.getUTCMonth() + 1).toString().padStart(2, \"0\");\n const day = date.getUTCDate().toString().padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n }\n },\n [format, dateFormat],\n );\n\n // Update time at interval\n useEffect(() => {\n // Calculate effective update interval\n const effectiveInterval = showMilliseconds\n ? Math.min(updateInterval, 100)\n : hideSeconds\n ? 60000\n : updateInterval;\n\n const intervalId = setInterval(() => {\n setTime(getCurrentTimeFromSource());\n }, effectiveInterval);\n\n return () => clearInterval(intervalId);\n }, [\n hideSeconds,\n updateInterval,\n showMilliseconds,\n timeSource,\n simulationConfig,\n customTime,\n ]);\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (onClick && (e.key === \"Enter\" || e.key === \" \")) {\n e.preventDefault();\n onClick();\n }\n };\n\n // Determine display label\n const displayLabel = useMemo(() => {\n if (showMET || format === \"met\") {\n return \"MET\";\n }\n if (timeSource === \"simulation\") {\n return \"SIM\";\n }\n return timezone;\n }, [showMET, format, timeSource, timezone]);\n\n return (\n <div\n className={classNames(\"zendir-mission-clock\", className)}\n onClick={onClick}\n onKeyDown={onClick ? handleKeyDown : undefined}\n tabIndex={onClick ? 0 : undefined}\n role=\"timer\"\n aria-label={`Current time: ${formatTimeDisplay(time)} ${displayLabel}`}\n style={{\n display: \"inline-flex\",\n flexDirection: compact ? \"row\" : \"column\",\n alignItems: \"center\",\n gap: compact ? 16 : 4,\n padding: small\n ? `${tokens.spacing.xs} ${tokens.spacing.sm}`\n : `${tokens.spacing.sm} ${tokens.spacing.md}`,\n backgroundColor: isTransparentTheme\n ? \"transparent\"\n : tokens.colors.background.surface,\n ...(isTransparentTheme && {\n backdropFilter: \"blur(12px)\",\n WebkitBackdropFilter: \"blur(12px)\" as const,\n }),\n ...(tokens.colors.border.cardStyle ?? {\n border: `1px solid ${tokens.colors.border.muted}`,\n }),\n borderRadius: tokens.borderRadius.md,\n cursor: onClick ? \"pointer\" : \"default\",\n outline: \"none\",\n transition: tokens.animation.fast,\n ...tabularNumsStyle,\n }}\n >\n {/* Main clock section */}\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: 2,\n }}\n >\n {/* Date (optional) */}\n {showDate && dateFormat !== \"none\" && (\n <span\n style={{\n fontSize: tokens.typography.fontSize.xs,\n fontWeight: tokens.typography.fontWeight.normal,\n fontFamily: tokens.typography.fontFamily.mono,\n color: tokens.colors.text.tertiary,\n letterSpacing: tokens.typography.letterSpacing.normal,\n }}\n >\n {formatDateDisplay(time)}\n </span>\n )}\n\n {/* Time - Using bold weight for critical time displays (Apple/Google best practice) */}\n <span\n style={{\n fontSize: small\n ? tokens.typography.fontSize.base\n : tokens.typography.fontSize.xl,\n fontWeight: tokens.typography.fontWeight.bold, // Bold (700) for readability - time is critical info\n fontFamily: tokens.typography.fontFamily.mono,\n letterSpacing: tokens.typography.letterSpacing.normal,\n color: tokens.colors.text.primary,\n }}\n >\n {formatTimeDisplay(time)}\n </span>\n\n {/* Label (timezone/MET/SIM) */}\n {displayLabel && (\n <span\n style={{\n fontSize: tokens.typography.fontSize.xs,\n fontWeight: tokens.typography.fontWeight.medium,\n color:\n timeSource === \"simulation\"\n ? tokens.colors.status.caution\n : tokens.colors.text.tertiary,\n textTransform: \"uppercase\",\n letterSpacing: tokens.typography.letterSpacing.wide,\n }}\n >\n {displayLabel}\n </span>\n )}\n </div>\n\n {/* AOS/LOS Timers */}\n {allTimers.length > 0 && (\n <div\n style={{\n display: \"flex\",\n flexDirection: compact ? \"row\" : \"column\",\n gap: 8,\n }}\n >\n {allTimers.map((timer, index) => (\n <TimerDisplay\n key={`${timer.label}-${index}`}\n timer={timer}\n currentTime={time}\n tokens={tokens}\n compact={compact}\n />\n ))}\n </div>\n )}\n </div>\n );\n});\n\n// ============================================================================\n// Convenience Components\n// ============================================================================\n\n/**\n * SimpleTimer - Standalone countdown/up timer\n */\nexport interface SimpleTimerProps {\n /** Timer label */\n label: string;\n /** Target/start timestamp */\n timestamp: Date;\n /** Timer direction */\n direction?: \"countdown\" | \"countup\";\n /** Status color */\n status?: \"normal\" | \"caution\" | \"critical\" | \"standby\";\n /** Show days */\n showDays?: boolean;\n /** Custom className */\n className?: string;\n}\n\nexport const SimpleTimer = memo(function SimpleTimer({\n label,\n timestamp,\n direction = \"countdown\",\n status,\n showDays = false,\n className = \"\",\n}: SimpleTimerProps): React.ReactElement {\n const { tokens } = useTheme();\n const [now, setNow] = useState(new Date());\n\n useEffect(() => {\n const interval = setInterval(() => setNow(new Date()), 1000);\n return () => clearInterval(interval);\n }, []);\n\n const timer: TimerConfig = { label, timestamp, direction, status, showDays };\n\n return (\n <div className={classNames(\"zendir-simple-timer\", className)}>\n <TimerDisplay timer={timer} currentTime={now} tokens={tokens} />\n </div>\n );\n});\n\n/**\n * MissionElapsedTime - Dedicated MET display\n */\nexport interface MissionElapsedTimeProps {\n /** Mission launch/start time */\n launchTime: Date | string;\n /** Show milliseconds */\n showMilliseconds?: boolean;\n /** Custom className */\n className?: string;\n /** Small variant */\n small?: boolean;\n}\n\nexport const MissionElapsedTime = memo(function MissionElapsedTime({\n launchTime,\n showMilliseconds = false,\n className = \"\",\n small = false,\n}: MissionElapsedTimeProps): React.ReactElement {\n return (\n <MissionClock\n format=\"met\"\n missionStart={launchTime}\n showMET\n showMilliseconds={showMilliseconds}\n className={className}\n small={small}\n timezone=\"\"\n />\n );\n});\n\n/**\n * SimulationClock - Clock driven by simulation time\n */\nexport interface SimulationClockProps {\n /** Simulation epoch */\n epoch: Date | string;\n /** Elapsed seconds from epoch */\n elapsedSeconds?: number;\n /** Time scale factor */\n timeScale?: number;\n /** Whether simulation is running */\n isRunning?: boolean;\n /** Show date */\n showDate?: boolean;\n /** Date format */\n dateFormat?: DateFormat;\n /** Custom className */\n className?: string;\n /** Small variant */\n small?: boolean;\n}\n\nexport const SimulationClock = memo(function SimulationClock({\n epoch,\n elapsedSeconds = 0,\n timeScale = 1,\n isRunning = true,\n showDate = true,\n dateFormat = \"julian\",\n className = \"\",\n small = false,\n}: SimulationClockProps): React.ReactElement {\n return (\n <MissionClock\n timeSource=\"simulation\"\n simulationConfig={{\n epoch,\n elapsedSeconds,\n timeScale,\n isRunning,\n }}\n showDate={showDate}\n dateFormat={dateFormat}\n className={className}\n small={small}\n />\n );\n});\n\nexport default MissionClock;\n"],"mappings":"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"}
1
+ {"version":3,"file":"MissionClock.js","names":[],"sources":["../../../src/react/astro/MissionClock.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - MissionClock Component (Pure React)\r\n *\r\n * Advanced mission time display following Astro UX patterns with full\r\n * space operations support.\r\n *\r\n * Features:\r\n * - Theme-integrated via useTheme()\r\n * - UTC/Zulu time display\r\n * - Configurable formats (12h, 24h, ISO)\r\n * - Optional seconds display\r\n * - AOS/LOS timer support (Acquisition/Loss of Signal)\r\n * - MET (Mission Elapsed Time) display\r\n * - Julian day format (DOY-###)\r\n * - Simulation time support (custom epoch/time source)\r\n * - Tabular numbers for stability\r\n * - Zendir SDK integration for real-time data\r\n *\r\n * Space Operations Terminology:\r\n * - AOS: Acquisition of Signal - when satellite rises above horizon\r\n * - LOS: Loss of Signal - when satellite passes below horizon\r\n * - TCA: Time of Closest Approach - maximum elevation point\r\n * - MET: Mission Elapsed Time - time since launch (dd:hh:mm:ss)\r\n * - DOY: Day of Year - Julian day format\r\n */\r\n\r\nimport React, { memo, useState, useEffect, useCallback, useMemo } from \"react\";\r\nimport { useTheme } from \"../theme\";\r\nimport { classNames, tabularNumsStyle } from \"../utils\";\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport type ClockFormat = \"12h\" | \"24h\" | \"iso\" | \"met\";\r\nexport type DateFormat = \"iso\" | \"julian\" | \"gregorian\" | \"none\";\r\nexport type TimeSource = \"realtime\" | \"simulation\" | \"custom\";\r\n\r\n/**\r\n * Timer configuration for AOS/LOS countdown/up timers\r\n */\r\nexport interface TimerConfig {\r\n /** Timer label (e.g., \"AOS\", \"LOS\", \"MET\") */\r\n label: string;\r\n /** Target timestamp (for countdown) or start timestamp (for countup) */\r\n timestamp: Date;\r\n /** Timer direction: 'countdown' counts to target, 'countup' counts from start */\r\n direction: \"countdown\" | \"countup\";\r\n /** Optional status color */\r\n status?: \"normal\" | \"caution\" | \"critical\" | \"standby\";\r\n /** Show days in timer format */\r\n showDays?: boolean;\r\n}\r\n\r\n/**\r\n * Simulation time configuration\r\n */\r\nexport interface SimulationTimeConfig {\r\n /** Simulation epoch (t=0) as Date or ISO string */\r\n epoch: Date | string;\r\n /** Current simulation time offset in seconds from epoch */\r\n elapsedSeconds?: number;\r\n /** Time scale factor (1 = realtime, 2 = 2x speed, etc.) */\r\n timeScale?: number;\r\n /** Whether simulation is running */\r\n isRunning?: boolean;\r\n /** Callback to get current simulation time */\r\n getCurrentTime?: () => Date;\r\n}\r\n\r\nexport interface MissionClockProps {\r\n /** Clock format */\r\n format?: ClockFormat;\r\n /** Timezone label to display */\r\n timezone?: string;\r\n /** Hide seconds */\r\n hideSeconds?: boolean;\r\n /** Small size variant */\r\n small?: boolean;\r\n /** Show date */\r\n showDate?: boolean;\r\n /** Date format (iso, julian, gregorian) */\r\n dateFormat?: DateFormat;\r\n /** Custom className */\r\n className?: string;\r\n /** Click handler */\r\n onClick?: () => void;\r\n\r\n // === AOS/LOS Timer Support ===\r\n /** AOS timer - countdown/up to Acquisition of Signal */\r\n aosTimer?: TimerConfig | Date;\r\n /** LOS timer - countdown/up to Loss of Signal */\r\n losTimer?: TimerConfig | Date;\r\n /** Additional custom timers */\r\n customTimers?: TimerConfig[];\r\n\r\n // === Simulation Time Support ===\r\n /** Time source: realtime, simulation, or custom */\r\n timeSource?: TimeSource;\r\n /** Simulation time configuration (for timeSource='simulation') */\r\n simulationConfig?: SimulationTimeConfig;\r\n /** Custom time provider (for timeSource='custom') */\r\n customTime?: Date | (() => Date);\r\n\r\n // === Mission Elapsed Time ===\r\n /** Mission start time for MET display */\r\n missionStart?: Date | string;\r\n /** Show MET (Mission Elapsed Time) instead of wall clock */\r\n showMET?: boolean;\r\n\r\n // === Advanced Options ===\r\n /** Update interval in milliseconds (default: 1000) */\r\n updateInterval?: number;\r\n /** Compact mode - single line display */\r\n compact?: boolean;\r\n /** Show milliseconds */\r\n showMilliseconds?: boolean;\r\n}\r\n\r\n// ============================================================================\r\n// Utility Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Format duration as dd:hh:mm:ss (MET format)\r\n */\r\nfunction formatMET(ms: number, showMilliseconds = false): string {\r\n const totalSeconds = Math.floor(Math.abs(ms) / 1000);\r\n const days = Math.floor(totalSeconds / 86400);\r\n const hours = Math.floor((totalSeconds % 86400) / 3600);\r\n const minutes = Math.floor((totalSeconds % 3600) / 60);\r\n const seconds = totalSeconds % 60;\r\n\r\n const sign = ms < 0 ? \"-\" : \"\";\r\n\r\n if (showMilliseconds) {\r\n const millis = Math.floor(Math.abs(ms) % 1000);\r\n return `${sign}${days.toString().padStart(2, \"0\")}:${hours.toString().padStart(2, \"0\")}:${minutes.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}.${millis.toString().padStart(3, \"0\")}`;\r\n }\r\n\r\n return `${sign}${days.toString().padStart(2, \"0\")}:${hours.toString().padStart(2, \"0\")}:${minutes.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}`;\r\n}\r\n\r\n/**\r\n * Format duration for timers (compact: hh:mm:ss or mm:ss)\r\n */\r\nfunction formatTimerDuration(ms: number, showDays = false): string {\r\n const totalSeconds = Math.floor(Math.abs(ms) / 1000);\r\n const days = Math.floor(totalSeconds / 86400);\r\n const hours = Math.floor((totalSeconds % 86400) / 3600);\r\n const minutes = Math.floor((totalSeconds % 3600) / 60);\r\n const seconds = totalSeconds % 60;\r\n\r\n const sign = ms < 0 ? \"-\" : \"\";\r\n\r\n if (showDays && days > 0) {\r\n return `${sign}${days}d ${hours.toString().padStart(2, \"0\")}:${minutes.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}`;\r\n }\r\n\r\n if (hours > 0 || showDays) {\r\n return `${sign}${hours.toString().padStart(2, \"0\")}:${minutes.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}`;\r\n }\r\n\r\n return `${sign}${minutes.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}`;\r\n}\r\n\r\n/**\r\n * Get Julian day (day of year 001-366)\r\n */\r\nfunction getJulianDay(date: Date): string {\r\n const start = new Date(Date.UTC(date.getUTCFullYear(), 0, 0));\r\n const diff = date.getTime() - start.getTime();\r\n const oneDay = 1000 * 60 * 60 * 24;\r\n const day = Math.floor(diff / oneDay);\r\n return day.toString().padStart(3, \"0\");\r\n}\r\n\r\n/**\r\n * Normalize timer config from Date or TimerConfig\r\n */\r\nfunction normalizeTimerConfig(\r\n timer: TimerConfig | Date | undefined,\r\n label: string,\r\n): TimerConfig | undefined {\r\n if (!timer) return undefined;\r\n if (timer instanceof Date) {\r\n return {\r\n label,\r\n timestamp: timer,\r\n direction: \"countdown\",\r\n };\r\n }\r\n return timer;\r\n}\r\n\r\n// ============================================================================\r\n// Timer Sub-component\r\n// ============================================================================\r\n\r\ninterface TimerDisplayProps {\r\n timer: TimerConfig;\r\n currentTime: Date;\r\n tokens: ReturnType<typeof useTheme>[\"tokens\"];\r\n compact?: boolean;\r\n}\r\n\r\nconst TimerDisplay = memo(function TimerDisplay({\r\n timer,\r\n currentTime,\r\n tokens,\r\n compact = false,\r\n}: TimerDisplayProps) {\r\n const diff =\r\n timer.direction === \"countdown\"\r\n ? timer.timestamp.getTime() - currentTime.getTime()\r\n : currentTime.getTime() - timer.timestamp.getTime();\r\n\r\n const isNegative = diff < 0;\r\n const statusColor = timer.status\r\n ? tokens.colors.status[timer.status]\r\n : isNegative\r\n ? tokens.colors.status.caution\r\n : tokens.colors.status.normal;\r\n\r\n return (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: compact ? \"center\" : \"flex-start\",\r\n flexDirection: compact ? \"row\" : \"column\",\r\n gap: compact ? 8 : 2,\r\n padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`,\r\n backgroundColor: `${statusColor}15`,\r\n borderRadius: tokens.borderRadius.sm,\r\n border: `1px solid ${statusColor}30`,\r\n }}\r\n >\r\n <span\r\n style={{\r\n fontSize: tokens.typography.fontSize.xs,\r\n fontWeight: tokens.typography.fontWeight.semibold,\r\n color: statusColor,\r\n textTransform: \"uppercase\",\r\n letterSpacing: tokens.typography.letterSpacing.wide,\r\n }}\r\n >\r\n {timer.label}\r\n </span>\r\n <span\r\n style={{\r\n fontSize: compact\r\n ? tokens.typography.fontSize.sm\r\n : tokens.typography.fontSize.base,\r\n fontWeight: tokens.typography.fontWeight.bold, // Bold (700) for timer readability\r\n fontFamily: tokens.typography.fontFamily.mono,\r\n color: statusColor,\r\n ...tabularNumsStyle,\r\n }}\r\n >\r\n {isNegative ? \"+\" : \"\"}\r\n {formatTimerDuration(diff, timer.showDays)}\r\n </span>\r\n </div>\r\n );\r\n});\r\n\r\n// ============================================================================\r\n// Main Component\r\n// ============================================================================\r\n\r\n/**\r\n * MissionClock - Advanced mission time display for space operations\r\n *\r\n * Supports real-time clock, simulation time, MET (Mission Elapsed Time),\r\n * and AOS/LOS timers following Astro UX Design System patterns.\r\n *\r\n * @example\r\n * ```tsx\r\n * // Basic clock\r\n * <MissionClock format=\"24h\" timezone=\"UTC\" />\r\n *\r\n * // With AOS/LOS timers\r\n * <MissionClock\r\n * format=\"24h\"\r\n * aosTimer={{ label: 'AOS', timestamp: new Date('2024-03-15T10:30:00Z'), direction: 'countdown' }}\r\n * losTimer={{ label: 'LOS', timestamp: new Date('2024-03-15T10:45:00Z'), direction: 'countdown' }}\r\n * />\r\n *\r\n * // Simulation time\r\n * <MissionClock\r\n * timeSource=\"simulation\"\r\n * simulationConfig={{\r\n * epoch: new Date('2026-01-01T00:00:00Z'),\r\n * elapsedSeconds: 3600,\r\n * timeScale: 1,\r\n * }}\r\n * />\r\n *\r\n * // Mission Elapsed Time\r\n * <MissionClock\r\n * showMET\r\n * missionStart={new Date('2026-01-01T00:00:00Z')}\r\n * />\r\n *\r\n * // Julian day format\r\n * <MissionClock showDate dateFormat=\"julian\" />\r\n * ```\r\n */\r\nexport const MissionClock = memo(function MissionClock({\r\n format = \"24h\",\r\n timezone = \"UTC\",\r\n hideSeconds = false,\r\n small = false,\r\n showDate = false,\r\n dateFormat = \"iso\",\r\n className = \"\",\r\n onClick,\r\n aosTimer,\r\n losTimer,\r\n customTimers = [],\r\n timeSource = \"realtime\",\r\n simulationConfig,\r\n customTime,\r\n missionStart,\r\n showMET = false,\r\n updateInterval = 1000,\r\n compact = false,\r\n showMilliseconds = false,\r\n}: MissionClockProps): React.ReactElement {\r\n const { tokens, theme } = useTheme();\r\n const isTransparentTheme =\r\n theme === \"transparent\" ||\r\n theme === \"transparent-bold\" ||\r\n theme === \"transparent-minimal\";\r\n\r\n // State for current time\r\n const [time, setTime] = useState(() => getCurrentTimeFromSource());\r\n\r\n // Normalize timer configs\r\n const normalizedAOS = useMemo(\r\n () => normalizeTimerConfig(aosTimer, \"AOS\"),\r\n [aosTimer],\r\n );\r\n const normalizedLOS = useMemo(\r\n () => normalizeTimerConfig(losTimer, \"LOS\"),\r\n [losTimer],\r\n );\r\n\r\n // All timers combined\r\n const allTimers = useMemo(() => {\r\n const timers: TimerConfig[] = [];\r\n if (normalizedAOS) timers.push(normalizedAOS);\r\n if (normalizedLOS) timers.push(normalizedLOS);\r\n return [...timers, ...customTimers];\r\n }, [normalizedAOS, normalizedLOS, customTimers]);\r\n\r\n // Get current time based on source\r\n function getCurrentTimeFromSource(): Date {\r\n switch (timeSource) {\r\n case \"simulation\":\r\n if (simulationConfig) {\r\n if (simulationConfig.getCurrentTime) {\r\n return simulationConfig.getCurrentTime();\r\n }\r\n const epoch =\r\n typeof simulationConfig.epoch === \"string\"\r\n ? new Date(simulationConfig.epoch)\r\n : simulationConfig.epoch;\r\n const elapsed = (simulationConfig.elapsedSeconds || 0) * 1000;\r\n return new Date(epoch.getTime() + elapsed);\r\n }\r\n return new Date();\r\n\r\n case \"custom\":\r\n if (customTime) {\r\n return typeof customTime === \"function\" ? customTime() : customTime;\r\n }\r\n return new Date();\r\n\r\n case \"realtime\":\r\n default:\r\n return new Date();\r\n }\r\n }\r\n\r\n // Format time display\r\n const formatTimeDisplay = useCallback(\r\n (date: Date): string => {\r\n if (showMET && missionStart) {\r\n const start =\r\n typeof missionStart === \"string\"\r\n ? new Date(missionStart)\r\n : missionStart;\r\n const elapsed = date.getTime() - start.getTime();\r\n return formatMET(elapsed, showMilliseconds);\r\n }\r\n\r\n if (format === \"met\" && missionStart) {\r\n const start =\r\n typeof missionStart === \"string\"\r\n ? new Date(missionStart)\r\n : missionStart;\r\n const elapsed = date.getTime() - start.getTime();\r\n return formatMET(elapsed, showMilliseconds);\r\n }\r\n\r\n const hours = date.getUTCHours();\r\n const mins = date.getUTCMinutes();\r\n const secs = date.getUTCSeconds();\r\n const millis = date.getUTCMilliseconds();\r\n\r\n let hoursStr: string;\r\n let suffix = \"\";\r\n\r\n if (format === \"12h\") {\r\n const h12 = hours % 12 || 12;\r\n hoursStr = h12.toString().padStart(2, \"0\");\r\n suffix = hours >= 12 ? \" PM\" : \" AM\";\r\n } else {\r\n hoursStr = hours.toString().padStart(2, \"0\");\r\n }\r\n\r\n const minsStr = mins.toString().padStart(2, \"0\");\r\n const secsStr = secs.toString().padStart(2, \"0\");\r\n const millisStr = millis.toString().padStart(3, \"0\");\r\n\r\n if (hideSeconds) {\r\n return `${hoursStr}:${minsStr}${suffix}`;\r\n }\r\n\r\n if (showMilliseconds) {\r\n return `${hoursStr}:${minsStr}:${secsStr}.${millisStr}${suffix}`;\r\n }\r\n\r\n return `${hoursStr}:${minsStr}:${secsStr}${suffix}`;\r\n },\r\n [format, hideSeconds, showMET, missionStart, showMilliseconds],\r\n );\r\n\r\n // Format date display\r\n const formatDateDisplay = useCallback(\r\n (date: Date): string => {\r\n switch (dateFormat) {\r\n case \"julian\": {\r\n const year = date.getUTCFullYear();\r\n const doy = getJulianDay(date);\r\n return `${year}/${doy}`;\r\n }\r\n case \"gregorian\": {\r\n const year = date.getUTCFullYear();\r\n const month = (date.getUTCMonth() + 1).toString().padStart(2, \"0\");\r\n const day = date.getUTCDate().toString().padStart(2, \"0\");\r\n return `${month}/${day}/${year}`;\r\n }\r\n case \"iso\":\r\n default:\r\n if (format === \"iso\") {\r\n return date.toISOString().split(\"T\")[0];\r\n }\r\n const year = date.getUTCFullYear();\r\n const month = (date.getUTCMonth() + 1).toString().padStart(2, \"0\");\r\n const day = date.getUTCDate().toString().padStart(2, \"0\");\r\n return `${year}-${month}-${day}`;\r\n }\r\n },\r\n [format, dateFormat],\r\n );\r\n\r\n // Update time at interval\r\n useEffect(() => {\r\n // Calculate effective update interval\r\n const effectiveInterval = showMilliseconds\r\n ? Math.min(updateInterval, 100)\r\n : hideSeconds\r\n ? 60000\r\n : updateInterval;\r\n\r\n const intervalId = setInterval(() => {\r\n setTime(getCurrentTimeFromSource());\r\n }, effectiveInterval);\r\n\r\n return () => clearInterval(intervalId);\r\n }, [\r\n hideSeconds,\r\n updateInterval,\r\n showMilliseconds,\r\n timeSource,\r\n simulationConfig,\r\n customTime,\r\n ]);\r\n\r\n const handleKeyDown = (e: React.KeyboardEvent) => {\r\n if (onClick && (e.key === \"Enter\" || e.key === \" \")) {\r\n e.preventDefault();\r\n onClick();\r\n }\r\n };\r\n\r\n // Determine display label\r\n const displayLabel = useMemo(() => {\r\n if (showMET || format === \"met\") {\r\n return \"MET\";\r\n }\r\n if (timeSource === \"simulation\") {\r\n return \"SIM\";\r\n }\r\n return timezone;\r\n }, [showMET, format, timeSource, timezone]);\r\n\r\n return (\r\n <div\r\n className={classNames(\"zendir-mission-clock\", className)}\r\n onClick={onClick}\r\n onKeyDown={onClick ? handleKeyDown : undefined}\r\n tabIndex={onClick ? 0 : undefined}\r\n role=\"timer\"\r\n aria-label={`Current time: ${formatTimeDisplay(time)} ${displayLabel}`}\r\n style={{\r\n display: \"inline-flex\",\r\n flexDirection: compact ? \"row\" : \"column\",\r\n alignItems: \"center\",\r\n gap: compact ? 16 : 4,\r\n padding: small\r\n ? `${tokens.spacing.xs} ${tokens.spacing.sm}`\r\n : `${tokens.spacing.sm} ${tokens.spacing.md}`,\r\n backgroundColor: isTransparentTheme\r\n ? \"transparent\"\r\n : tokens.colors.background.surface,\r\n ...(isTransparentTheme && {\r\n backdropFilter: \"blur(12px)\",\r\n WebkitBackdropFilter: \"blur(12px)\" as const,\r\n }),\r\n ...(tokens.colors.border.cardStyle ?? {\r\n border: `1px solid ${tokens.colors.border.muted}`,\r\n }),\r\n borderRadius: tokens.borderRadius.md,\r\n cursor: onClick ? \"pointer\" : \"default\",\r\n outline: \"none\",\r\n transition: tokens.animation.fast,\r\n ...tabularNumsStyle,\r\n }}\r\n >\r\n {/* Main clock section */}\r\n <div\r\n style={{\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n alignItems: \"center\",\r\n gap: 2,\r\n }}\r\n >\r\n {/* Date (optional) */}\r\n {showDate && dateFormat !== \"none\" && (\r\n <span\r\n style={{\r\n fontSize: tokens.typography.fontSize.xs,\r\n fontWeight: tokens.typography.fontWeight.normal,\r\n fontFamily: tokens.typography.fontFamily.mono,\r\n color: tokens.colors.text.tertiary,\r\n letterSpacing: tokens.typography.letterSpacing.normal,\r\n }}\r\n >\r\n {formatDateDisplay(time)}\r\n </span>\r\n )}\r\n\r\n {/* Time - Using bold weight for critical time displays (Apple/Google best practice) */}\r\n <span\r\n style={{\r\n fontSize: small\r\n ? tokens.typography.fontSize.base\r\n : tokens.typography.fontSize.xl,\r\n fontWeight: tokens.typography.fontWeight.bold, // Bold (700) for readability - time is critical info\r\n fontFamily: tokens.typography.fontFamily.mono,\r\n letterSpacing: tokens.typography.letterSpacing.normal,\r\n color: tokens.colors.text.primary,\r\n }}\r\n >\r\n {formatTimeDisplay(time)}\r\n </span>\r\n\r\n {/* Label (timezone/MET/SIM) */}\r\n {displayLabel && (\r\n <span\r\n style={{\r\n fontSize: tokens.typography.fontSize.xs,\r\n fontWeight: tokens.typography.fontWeight.medium,\r\n color:\r\n timeSource === \"simulation\"\r\n ? tokens.colors.status.caution\r\n : tokens.colors.text.tertiary,\r\n textTransform: \"uppercase\",\r\n letterSpacing: tokens.typography.letterSpacing.wide,\r\n }}\r\n >\r\n {displayLabel}\r\n </span>\r\n )}\r\n </div>\r\n\r\n {/* AOS/LOS Timers */}\r\n {allTimers.length > 0 && (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n flexDirection: compact ? \"row\" : \"column\",\r\n gap: 8,\r\n }}\r\n >\r\n {allTimers.map((timer, index) => (\r\n <TimerDisplay\r\n key={`${timer.label}-${index}`}\r\n timer={timer}\r\n currentTime={time}\r\n tokens={tokens}\r\n compact={compact}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n});\r\n\r\n// ============================================================================\r\n// Convenience Components\r\n// ============================================================================\r\n\r\n/**\r\n * SimpleTimer - Standalone countdown/up timer\r\n */\r\nexport interface SimpleTimerProps {\r\n /** Timer label */\r\n label: string;\r\n /** Target/start timestamp */\r\n timestamp: Date;\r\n /** Timer direction */\r\n direction?: \"countdown\" | \"countup\";\r\n /** Status color */\r\n status?: \"normal\" | \"caution\" | \"critical\" | \"standby\";\r\n /** Show days */\r\n showDays?: boolean;\r\n /** Custom className */\r\n className?: string;\r\n}\r\n\r\nexport const SimpleTimer = memo(function SimpleTimer({\r\n label,\r\n timestamp,\r\n direction = \"countdown\",\r\n status,\r\n showDays = false,\r\n className = \"\",\r\n}: SimpleTimerProps): React.ReactElement {\r\n const { tokens } = useTheme();\r\n const [now, setNow] = useState(new Date());\r\n\r\n useEffect(() => {\r\n const interval = setInterval(() => setNow(new Date()), 1000);\r\n return () => clearInterval(interval);\r\n }, []);\r\n\r\n const timer: TimerConfig = { label, timestamp, direction, status, showDays };\r\n\r\n return (\r\n <div className={classNames(\"zendir-simple-timer\", className)}>\r\n <TimerDisplay timer={timer} currentTime={now} tokens={tokens} />\r\n </div>\r\n );\r\n});\r\n\r\n/**\r\n * MissionElapsedTime - Dedicated MET display\r\n */\r\nexport interface MissionElapsedTimeProps {\r\n /** Mission launch/start time */\r\n launchTime: Date | string;\r\n /** Show milliseconds */\r\n showMilliseconds?: boolean;\r\n /** Custom className */\r\n className?: string;\r\n /** Small variant */\r\n small?: boolean;\r\n}\r\n\r\nexport const MissionElapsedTime = memo(function MissionElapsedTime({\r\n launchTime,\r\n showMilliseconds = false,\r\n className = \"\",\r\n small = false,\r\n}: MissionElapsedTimeProps): React.ReactElement {\r\n return (\r\n <MissionClock\r\n format=\"met\"\r\n missionStart={launchTime}\r\n showMET\r\n showMilliseconds={showMilliseconds}\r\n className={className}\r\n small={small}\r\n timezone=\"\"\r\n />\r\n );\r\n});\r\n\r\n/**\r\n * SimulationClock - Clock driven by simulation time\r\n */\r\nexport interface SimulationClockProps {\r\n /** Simulation epoch */\r\n epoch: Date | string;\r\n /** Elapsed seconds from epoch */\r\n elapsedSeconds?: number;\r\n /** Time scale factor */\r\n timeScale?: number;\r\n /** Whether simulation is running */\r\n isRunning?: boolean;\r\n /** Show date */\r\n showDate?: boolean;\r\n /** Date format */\r\n dateFormat?: DateFormat;\r\n /** Custom className */\r\n className?: string;\r\n /** Small variant */\r\n small?: boolean;\r\n}\r\n\r\nexport const SimulationClock = memo(function SimulationClock({\r\n epoch,\r\n elapsedSeconds = 0,\r\n timeScale = 1,\r\n isRunning = true,\r\n showDate = true,\r\n dateFormat = \"julian\",\r\n className = \"\",\r\n small = false,\r\n}: SimulationClockProps): React.ReactElement {\r\n return (\r\n <MissionClock\r\n timeSource=\"simulation\"\r\n simulationConfig={{\r\n epoch,\r\n elapsedSeconds,\r\n timeScale,\r\n isRunning,\r\n }}\r\n showDate={showDate}\r\n dateFormat={dateFormat}\r\n className={className}\r\n small={small}\r\n />\r\n );\r\n});\r\n\r\nexport default MissionClock;\r\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"MonitoringIcon.js","names":[],"sources":["../../../src/react/astro/MonitoringIcon.tsx"],"sourcesContent":["/**\n * @zendir/ui - MonitoringIcon Component (Pure React)\n *\n * Status monitoring icon following Astro UX Design System patterns.\n * Displays a monitoring icon with status, label, and sub-label.\n *\n * Astro UX Compliance (https://www.astrouxds.com/components/icons-and-symbols/):\n * - Must include a label and status indicator\n * - Light theme requires border around status indicator\n * - Uses 6-level status color system\n *\n * Features:\n * - Status-based coloring with theme integration\n * - Notification badge\n * - Astro icon library support\n * - Light theme border support\n * - Tooltip support\n * - Keyboard accessible\n */\n\nimport React, { memo, useState } from \"react\";\nimport { useTheme } from \"../theme\";\nimport { classNames, type StatusLevel } from \"../utils\";\nimport { Icon, isValidIconName, type IconName } from \"../core/display/Icon\";\n\nexport type MonitoringStatus = StatusLevel;\n\nexport interface MonitoringIconProps {\n /** Current status of the monitored item */\n status: MonitoringStatus;\n /** Primary label (always visible) */\n label: string;\n /** Sub-label for dynamic info (optional) */\n sublabel?: string;\n /** Icon name or custom icon element */\n icon?: string | React.ReactNode;\n /** Notification count badge */\n notifications?: number;\n /** Show tooltip on hover */\n tooltip?: string;\n /** Custom className */\n className?: string;\n /** Click handler */\n onClick?: () => void;\n\n // === Percentage Arc Display (Astro UX) ===\n /**\n * Show percentage arc display instead of icon\n * When true, displays a circular arc showing the percentage value\n */\n showPercentage?: boolean;\n /** Percentage value (0-100) - displayed as arc when showPercentage is true */\n percentage?: number;\n /** Map percentage to status colors (e.g., low = critical, high = normal) */\n percentageToStatus?: \"ascending\" | \"descending\";\n /** Show percentage value as text inside the arc */\n showPercentageValue?: boolean;\n}\n\n/**\n * Astro UX Status Colors (Light Theme - Border)\n * Required for light backgrounds per Astro UX\n */\nconst STATUS_BORDER_COLORS: Record<StatusLevel, string> = {\n off: \"#3c3e42\",\n standby: \"#285766\",\n normal: \"#005a00\",\n caution: \"#645600\",\n serious: \"#664618\",\n critical: \"#661102\",\n};\n\n/**\n * Render Astro-compliant status shape for MonitoringIcon\n * Shapes per https://www.astrouxds.com/patterns/status-system/\n * - Off: Circle (grey)\n * - Standby: Ring (cyan)\n * - Normal: Circle (green)\n * - Caution: Square (yellow)\n * - Serious: Diamond (orange)\n * - Critical: Triangle pointing down (red)\n */\nconst renderStatusSymbol = (\n status: StatusLevel,\n size: number,\n fillColor: string,\n borderColor?: string,\n glow?: boolean,\n): React.ReactNode => {\n const hasBorder = !!borderColor;\n const strokeWidth = hasBorder ? 1 : 0;\n const glowFilter = glow ? `drop-shadow(0 0 3px ${fillColor})` : undefined;\n\n switch (status) {\n // Small filled circle: off\n case \"off\":\n return (\n <svg\n viewBox=\"0 0 12 12\"\n width={size}\n height={size}\n style={{ filter: glowFilter }}\n >\n <circle\n cx=\"6\"\n cy=\"6\"\n r={hasBorder ? 2.5 : 3}\n fill={fillColor}\n stroke={borderColor}\n strokeWidth={strokeWidth}\n />\n </svg>\n );\n\n // Ring (donut): standby\n case \"standby\":\n return (\n <svg\n viewBox=\"0 0 12 12\"\n width={size}\n height={size}\n style={{ filter: glowFilter }}\n >\n <circle\n cx=\"6\"\n cy=\"6\"\n r=\"3.5\"\n fill=\"none\"\n stroke={fillColor}\n strokeWidth=\"2\"\n />\n </svg>\n );\n\n // Filled circle: normal\n case \"normal\":\n return (\n <svg\n viewBox=\"0 0 12 12\"\n width={size}\n height={size}\n style={{ filter: glowFilter }}\n >\n <circle\n cx=\"6\"\n cy=\"6\"\n r={hasBorder ? 4.5 : 5}\n fill={fillColor}\n stroke={borderColor}\n strokeWidth={strokeWidth}\n />\n </svg>\n );\n\n // Square shape: caution\n case \"caution\":\n return (\n <svg\n viewBox=\"0 0 12 12\"\n width={size}\n height={size}\n style={{ filter: glowFilter }}\n >\n <rect\n x={hasBorder ? 1.5 : 1}\n y={hasBorder ? 1.5 : 1}\n width={hasBorder ? 9 : 10}\n height={hasBorder ? 9 : 10}\n fill={fillColor}\n stroke={borderColor}\n strokeWidth={strokeWidth}\n />\n </svg>\n );\n\n // Diamond shape: serious (rotated square)\n case \"serious\":\n return (\n <svg\n viewBox=\"0 0 12 12\"\n width={size}\n height={size}\n style={{ filter: glowFilter }}\n >\n <polygon\n points=\"6,1 11,6 6,11 1,6\"\n fill={fillColor}\n stroke={borderColor}\n strokeWidth={strokeWidth}\n />\n </svg>\n );\n\n // Triangle pointing down: critical\n case \"critical\":\n return (\n <svg\n viewBox=\"0 0 12 12\"\n width={size}\n height={size}\n style={{ filter: glowFilter }}\n >\n <polygon\n points=\"6,11 1,2 11,2\"\n fill={fillColor}\n stroke={borderColor}\n strokeWidth={strokeWidth}\n />\n </svg>\n );\n\n default:\n return null;\n }\n};\n\n/**\n * Astro UX Icon Library\n * Based on https://astro-components.netlify.app/?path=/story/components-icons--all-icons\n *\n * Categories: Astro (space/mission), Equipment, System\n */\nconst ICON_PATHS: Record<string, string> = {\n // Astro Icons (Space/Mission) - Paths from @astrouxds/astro-web-components\n thermal:\n \"M10.5 2C12.433 2 14 3.567 14 5.5L14.0005 12.2576C15.2217 13.2664 16 14.7923 16 16.5C16 19.5376 13.5376 22 10.5 22C7.46243 22 5 19.5376 5 16.5C5 14.7919 5.77868 13.2656 7.00044 12.2568L7 5.5C7 3.567 8.567 2 10.5 2ZM10.5 4C9.7203 4 9.07955 4.59489 9.00687 5.35543L9 5.49987L9.0005 13.199L8.27384 13.799C7.47135 14.4616 7 15.4402 7 16.5C7 18.433 8.567 20 10.5 20C12.433 20 14 18.433 14 16.5C14 15.5111 13.5896 14.593 12.8828 13.9362L12.7268 13.7995L12.0006 13.1997L12 5.5C12 4.7203 11.4051 4.07955 10.6445 4.00687L10.5 4ZM11 5.5C11 5.22386 10.7761 5 10.5 5C10.2239 5 10 5.22386 10 5.5L10.0006 14.0499C8.85917 14.2813 8 15.2903 8 16.5C8 17.8807 9.11929 19 10.5 19C11.8807 19 13 17.8807 13 16.5C13 15.2907 12.1413 14.2819 11.0004 14.0501L11 5.5ZM20 11C20.5523 11 21 11.4477 21 12C21 12.5523 20.5523 13 20 13H17C16.4477 13 16 12.5523 16 12C16 11.4477 16.4477 11 17 11H20ZM19 9C19 8.44772 18.5523 8 18 8H17C16.4477 8 16 8.44772 16 9C16 9.55228 16.4477 10 17 10H18C18.5523 10 19 9.55228 19 9ZM20 5C20.5523 5 21 5.44772 21 6C21 6.55228 20.5523 7 20 7H17C16.4477 7 16 6.55228 16 6C16 5.44772 16.4477 5 17 5H20ZM19 3C19 2.44772 18.5523 2 18 2H17C16.4477 2 16 2.44772 16 3C16 3.55228 16.4477 4 17 4H18C18.5523 4 19 3.55228 19 3Z\",\n \"propulsion-power\":\n \"M16 2C17.1046 2 18 2.89543 18 4V20C18 21.1046 17.1046 22 16 22H9C7.89543 22 7 21.1046 7 20V4C7 2.89543 7.89543 2 9 2H16ZM13.8115 5.69961C13.8115 5.00797 12.9835 4.75858 12.631 5.27555L12.5794 5.36359L9.0799 12.364C8.8597 12.8083 9.11904 13.3258 9.55954 13.3928L9.6566 13.4001H11.1901V18.3004C11.1901 18.992 12.0181 19.2414 12.3706 18.7245L12.4222 18.6364L15.9217 11.636C16.1419 11.1917 15.8711 10.6742 15.4398 10.6072L15.345 10.5999H13.8115V5.69961Z\",\n payload:\n \"M12.6802 2.24483L12.8418 2.31637L20.8418 6.31637C21.4305 6.6107 21.819 7.18871 21.8753 7.83667L21.8824 8V16C21.8824 16.6581 21.5391 17.2641 20.9848 17.6043L20.8418 17.6836L12.8418 21.6836C12.3649 21.9221 11.812 21.9459 11.3198 21.7552L11.1582 21.6836L3.15821 17.6836C2.56956 17.3893 2.18104 16.8113 2.12475 16.1633L2.11768 16V8C2.11768 7.34186 2.46091 6.73586 3.0153 6.39574L3.15821 6.31637L3.4276 6.17973C3.50773 6.12386 3.59511 6.0805 3.6866 6.05036L11.1582 2.31637C11.5822 2.1044 12.0662 2.062 12.5141 2.18919L12.6802 2.24483ZM3.99968 8.17865L4.00003 16L10.9997 19.4996V12.5536L3.99968 8.17865ZM12.9997 12.6176L19.9997 9.11765L20 16L12.9997 19.4996V12.6176ZM18.5 15C18.7762 15 19 15.2239 19 15.5C19 15.7761 18.7762 16 18.5 16C18.2239 16 18 15.7761 18 15.5C18 15.2239 18.2239 15 18.5 15ZM6.00003 15.5C6.00003 15.2239 5.77617 15 5.50003 15C5.22389 15 5.00003 15.2239 5.00003 15.5C5.00003 15.7761 5.22389 16 5.50003 16C5.77617 16 6.00003 15.7761 6.00003 15.5ZM16.5 14C16.7762 14 17 14.2239 17 14.5C17 14.7761 16.7762 15 16.5 15C16.2239 15 16 14.7761 16 14.5C16 14.2239 16.2239 14 16.5 14ZM8.00003 14.5C8.00003 14.2239 7.77617 14 7.50003 14C7.22389 14 7.00003 14.2239 7.00003 14.5C7.00003 14.7761 7.22389 15 7.50003 15C7.77617 15 8.00003 14.7761 8.00003 14.5ZM9.50003 13C9.77617 13 10 13.2239 10 13.5C10 13.7761 9.77617 14 9.50003 14C9.22389 14 9.00003 13.7761 9.00003 13.5C9.00003 13.2239 9.22389 13 9.50003 13ZM15 13.5C15 13.2239 14.7762 13 14.5 13C14.2239 13 14 13.2239 14 13.5C14 13.7761 14.2239 14 14.5 14C14.7762 14 15 13.7761 15 13.5ZM12 4L5.93668 7.03065L12.053 10.854L18.8807 7.44065L12 4ZM12.5 9.5C12.5 9.22386 12.2762 9 12 9C11.7239 9 11.5 9.22386 11.5 9.5C11.5 9.77614 11.7239 10 12 10C12.2762 10 12.5 9.77614 12.5 9.5ZM12 7C12.2762 7 12.5 7.22386 12.5 7.5C12.5 7.77614 12.2762 8 12 8C11.7239 8 11.5 7.77614 11.5 7.5C11.5 7.22386 11.7239 7 12 7ZM12.5 5.5C12.5 5.22386 12.2762 5 12 5C11.7239 5 11.5 5.22386 11.5 5.5C11.5 5.77614 11.7239 6 12 6C12.2762 6 12.5 5.77614 12.5 5.5Z\",\n netcom:\n \"M16 2C17.6569 2 19 3.34315 19 5C19 6.65685 17.6569 8 16 8C15.8259 8 15.6553 7.98518 15.4894 7.95672L14.8034 9.14676C15.3137 9.64825 15.6902 10.2856 15.874 11.0002L18.2676 10.9999C18.6134 10.4022 19.2597 10 20 10C21.1046 10 22 10.8954 22 12C22 13.1046 21.1046 14 20 14C19.2602 14 18.6142 13.5983 18.2682 13.0011L15.8738 13.0008C15.6717 13.7853 15.2375 14.4767 14.6488 14.9974L15.2128 16.1044C15.4637 16.0363 15.7276 16 16 16C17.6569 16 19 17.3431 19 19C19 20.6569 17.6569 22 16 22C14.3431 22 13 20.6569 13 19C13 18.3508 13.2062 17.7498 13.5567 17.2589L12.8669 15.9058C12.5878 15.9675 12.2977 16 12 16C11.2582 16 10.5635 15.7981 9.96801 15.4462L7.75736 17.6569L7.59355 17.4912C7.85196 17.9345 8 18.4499 8 19C8 20.6569 6.65685 22 5 22C3.34315 22 2 20.6569 2 19C2 17.3431 3.34315 16 5 16C5.55006 16 6.06555 16.148 6.50879 16.4065L6.34315 16.2426L8.55383 14.032C8.20193 13.4365 8 12.7418 8 12C8 9.79086 9.79086 8 12 8C12.3705 8 12.7293 8.05038 13.0698 8.14467L13.7446 6.97823C13.281 6.45014 13 5.75789 13 5C13 3.34315 14.3431 2 16 2ZM12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10Z\",\n antenna:\n \"M12.5 8C13.6506 8 14.5833 8.89543 14.5833 10C14.5833 10.7398 14.1649 11.3858 13.5428 11.7318L13.5416 22H11.4583L11.4582 11.7324C10.8356 11.3866 10.4166 10.7403 10.4166 10C10.4166 8.89543 11.3494 8 12.5 8ZM6.63099 2.32732C6.98124 2.70075 7.0016 3.27819 6.64763 3.65177C3.61283 6.82949 3.34936 11.6553 6.02151 15.1201C6.33286 15.5271 6.26451 16.1001 5.86774 16.4431C5.40872 16.8398 4.68582 16.775 4.3192 16.294C1.13831 12.1519 1.38131 6.45292 4.85709 2.56983L5.07393 2.33438L5.1678 2.24643C5.59314 1.89421 6.24722 1.91815 6.63099 2.32732ZM19.9142 2.24643L20.0081 2.33438C23.6894 6.21966 24.0087 12.0674 20.7628 16.294C20.3962 16.775 19.6733 16.8398 19.2143 16.4431C18.8175 16.1001 18.7492 15.5271 19.0605 15.1201C21.7327 11.6553 21.4692 6.82949 18.4344 3.65177C18.0804 3.27819 18.1008 2.70075 18.4511 2.32732C18.8348 1.91815 19.4889 1.89421 19.9142 2.24643ZM9.8013 5.34518C10.1466 5.71337 10.1537 6.26509 9.82646 6.65682C8.45162 8.33503 8.32337 10.6773 9.50741 12.4838C9.79011 12.9062 9.72281 13.4541 9.33916 13.7858C8.86156 14.1986 8.10517 14.1177 7.75278 13.6059C6.10277 11.1439 6.21558 7.93692 8.0237 5.58971L8.20397 5.3653L8.28854 5.2755C8.70418 4.88648 9.40006 4.91737 9.8013 5.34518ZM16.7935 5.2755L16.8781 5.3653C18.8573 7.72924 19.0325 11.0644 17.3292 13.6059C16.9769 14.1177 16.2205 14.1986 15.7429 13.7858C15.3592 13.4541 15.2919 12.9062 15.5746 12.4838C16.7586 10.6773 16.6304 8.33503 15.2556 6.65682C14.9283 6.26509 14.9354 5.71337 15.2807 5.34518C15.682 4.91737 16.3778 4.88648 16.7935 5.2755Z\",\n solar:\n \"M19.5385 4C20.3456 4 21 4.67008 21 5.49666V17.5033C21 18.3299 20.3456 19 19.5385 19H3.46154C2.65436 19 2 18.3299 2 17.5033V5.49666C2 4.67008 2.65436 4 3.46154 4H19.5385ZM7 6H4V11H7V6ZM11 6H8V11H11V6ZM15 6H12V11H15V6ZM19 6H16V11H19V6ZM7 12H4V17H7V12ZM11 12H8V17H11V12ZM15 12H12V17H15V12ZM19 12H16V17H19V12Z\",\n altitude:\n \"M12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2ZM12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4ZM14 18C14 17.4477 13.5523 17 13 17H11C10.4477 17 10 17.4477 10 18C10 18.5523 10.4477 19 11 19H13C13.5523 19 14 18.5523 14 18ZM14 14C14.5523 14 15 14.4477 15 15C15 15.5523 14.5523 16 14 16H10C9.44772 16 9 15.5523 9 15C9 14.4477 9.44772 14 10 14H14ZM16 12L19 14V10L16 12ZM5 10L8 12L5 14V10ZM14 12C14 11.4477 13.5523 11 13 11H11C10.4477 11 10 11.4477 10 12C10 12.5523 10.4477 13 11 13H13C13.5523 13 14 12.5523 14 12ZM14 8C14.5523 8 15 8.44772 15 9C15 9.55228 14.5523 10 14 10H10C9.44772 10 9 9.55228 9 9C9 8.44772 9.44772 8 10 8H14ZM14 6C14 5.44772 13.5523 5 13 5H11C10.4477 5 10 5.44772 10 6C10 6.55228 10.4477 7 11 7H13C13.5523 7 14 6.55228 14 6Z\",\n processor:\n \"M9 20V22H7V20H9ZM13 20V22H11V20H13ZM17 20V22H15V20H17ZM17 5C18.1046 5 19 5.89543 19 7V17C19 18.1046 18.1046 19 17 19H7C5.89543 19 5 18.1046 5 17V7C5 5.89543 5.89543 5 7 5H17ZM17 16C16.4477 16 16 16.4477 16 17C16 17.5523 16.4477 18 17 18C17.5523 18 18 17.5523 18 17C18 16.4477 17.5523 16 17 16ZM4 15V17H2V15H4ZM22 15V17H20V15H22ZM4 11V13H2V11H4ZM22 11V13H20V11H22ZM4 7V9H2V7H4ZM22 7V9H20V7H22ZM7 6C6.44772 6 6 6.44772 6 7C6 7.55228 6.44772 8 7 8C7.55228 8 8 7.55228 8 7C8 6.44772 7.55228 6 7 6ZM9 2V4H7V2H9ZM13 2V4H11V2H13ZM17 2V4H15V2H17Z\",\n mission:\n \"M12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2ZM12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4ZM18 12C18 8.68629 15.3137 6 12 6C8.68629 6 6 8.68629 6 12C6 15.3137 8.68629 18 12 18C15.3137 18 18 15.3137 18 12ZM12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8ZM14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12Z\",\n equipment:\n \"M22 5C22 3.89543 21.1046 3 20 3H4C2.89543 3 2 3.89543 2 5V9C2 10.1046 2.89543 11 4 11H20C21.1046 11 22 10.1046 22 9V5ZM22 15C22 13.8954 21.1046 13 20 13H4C2.89543 13 2 13.8954 2 15V19C2 20.1046 2.89543 21 4 21H20C21.1046 21 22 20.1046 22 19V15ZM4 15H20V19H4V15ZM7 16V18H5V16H7ZM10 18V16H8V18H10ZM13 16V18H11V16H13ZM20 5H4V9H20V5ZM7 8V6H5V8H7ZM10 6V8H8V6H10ZM13 8V6H11V8H13Z\",\n \"satellite-transmit\":\n \"M8.87871 8.87868C9.65976 8.09763 10.9261 8.09763 11.7071 8.87868L13.1213 10.2929C13.9024 11.0739 13.9024 12.3403 13.1213 13.1213C12.3403 13.9024 11.074 13.9024 10.2929 13.1213L8.87871 11.7071C8.09766 10.9261 8.09766 9.65973 8.87871 8.87868ZM4.05657 15.3702C4.09551 15.3313 4.13761 15.2956 4.18243 15.2636L8.1716 12.4142L9.58581 13.8284L6.73641 17.8176C6.4154 18.267 5.79085 18.3711 5.34144 18.0501C5.29662 18.0181 5.25452 17.9824 5.21557 17.9435L4.05657 16.7845C3.66604 16.3939 3.66604 15.7608 4.05657 15.3702ZM20.9898 11C21.5828 11 22.0551 11.5125 21.9948 12.1055C21.4823 17.3315 17.3416 21.4721 12.1156 21.9947C11.5226 22.055 11 21.5927 11 20.9998C11 20.4973 11.3719 20.0551 11.8744 20.0048C16.1658 19.5928 19.5828 16.1757 19.9949 11.8844C20.0451 11.3819 20.4773 11 20.9898 11ZM16.9776 11C17.5946 11 18.08 11.546 17.989 12.1527C17.5035 15.1355 15.1469 17.5015 12.1531 17.9868C11.5462 18.088 11 17.5925 11 16.9757C11 16.4803 11.3641 16.0657 11.8597 15.9848C13.8884 15.6338 15.5032 14.0794 15.9425 12.083L15.9864 11.8595C16.0673 11.364 16.482 11 16.9776 11ZM16.6903 3.97335L16.7845 4.05653L17.9435 5.21554C17.9824 5.25449 18.0181 5.29659 18.0501 5.34141C18.3464 5.75625 18.2805 6.32032 17.9152 6.65713L17.8176 6.73638L13.8285 9.58578L12.4142 8.17157L15.2636 4.1824C15.2957 4.13758 15.3313 4.09548 15.3703 4.05653C15.7308 3.69605 16.298 3.66832 16.6903 3.97335Z\",\n \"satellite-receive\":\n \"M5.53115 17.8387L6.58945 18.8268L8.92522 18.602L9.83101 20.4262C9.89964 20.5644 9.93535 20.7167 9.93535 20.871C9.93535 21.3838 9.54931 21.8065 9.05197 21.8642L8.93535 21.871H4.20497C3.9626 21.871 3.72849 21.7829 3.54616 21.6233C3.16263 21.2874 3.09746 20.7233 3.37588 20.3117L3.45266 20.2122L5.53115 17.8387ZM7.09757 10.0443C7.33377 10.0636 7.55543 10.1662 7.72301 10.3338L10.042 12.653L12 12L11.347 13.958L13.2146 15.8254C13.6051 16.2159 13.6051 16.8491 13.2146 17.2396C13.047 17.4072 12.8253 17.5098 12.5891 17.5291L7.30432 17.9622C7.01163 17.9862 6.7232 17.8803 6.51554 17.6726L5.87575 17.0328C5.66809 16.8252 5.56221 16.5368 5.58619 16.2441L6.01924 10.9593C6.06434 10.4088 6.54713 9.99916 7.09757 10.0443ZM14 9C14.5523 9 15 9.44772 15 10C15 10.5523 14.5523 11 14 11C13.4477 11 13 10.5523 13 10C13 9.44772 13.4477 9 14 9ZM16 7C16.5523 7 17 7.44772 17 8C17 8.55228 16.5523 9 16 9C15.4477 9 15 8.55228 15 8C15 7.44772 15.4477 7 16 7ZM18.5 4C19.3284 4 20 4.67157 20 5.5C20 6.32843 19.3284 7 18.5 7C17.6716 7 17 6.32843 17 5.5C17 4.67157 17.6716 4 18.5 4Z\",\n \"satellite-off\":\n \"M8.87867 11.7071C8.09762 10.9261 8.09762 9.65973 8.87867 8.87868C9.65972 8.09763 10.926 8.09763 11.7071 8.87868L13.1213 10.2929C13.9024 11.0739 13.9024 12.3403 13.1213 13.1213C12.3403 13.9024 11.0739 13.9024 10.2929 13.1213L8.87867 11.7071ZM4.05653 16.7845C3.61958 16.3475 3.67956 15.6228 4.1824 15.2636L8.17156 12.4142L9.58578 13.8284L6.73637 17.8176C6.3772 18.3204 5.65248 18.3804 5.21553 17.9435L4.05653 16.7845ZM15.2636 4.1824C15.6228 3.67956 16.3475 3.61958 16.7844 4.05653L17.9435 5.21554C18.3804 5.65249 18.3204 6.37721 17.8176 6.73638L13.8284 9.58578L12.4142 8.17157L15.2636 4.1824Z\",\n hardware:\n \"M4 17.8247V10.4692H20V17.8247H4ZM2 9.77297C2 9.05293 2.58371 8.46922 3.30375 8.46922H20.6962C21.4163 8.46922 22 9.05293 22 9.77298V18.5209C22 19.241 21.4163 19.8247 20.6962 19.8247H3.30375C2.58371 19.8247 2 19.241 2 18.5209V9.77297ZM8.99573 13.637H4.99573V11.637H8.99573V13.637ZM8.99573 16.642H4.99573V14.642H8.99573V16.642ZM10 13.637H14V11.637H10V13.637ZM14 16.642H10V14.642H14V16.642ZM14.9987 13.637H18.9987V11.637H14.9987V13.637ZM18.9987 16.6424H14.9987V14.6424H18.9987V16.6424Z\",\n release: \"M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8-8-8z\",\n // Legacy aliases\n satellite:\n \"M8.87867 11.7071C8.09762 10.9261 8.09762 9.65973 8.87867 8.87868C9.65972 8.09763 10.926 8.09763 11.7071 8.87868L13.1213 10.2929C13.9024 11.0739 13.9024 12.3403 13.1213 13.1213C12.3403 13.9024 11.0739 13.9024 10.2929 13.1213L8.87867 11.7071ZM4.05653 16.7845C3.61958 16.3475 3.67956 15.6228 4.1824 15.2636L8.17156 12.4142L9.58578 13.8284L6.73637 17.8176C6.3772 18.3204 5.65248 18.3804 5.21553 17.9435L4.05653 16.7845ZM15.2636 4.1824C15.6228 3.67956 16.3475 3.61958 16.7844 4.05653L17.9435 5.21554C18.3804 5.65249 18.3204 6.37721 17.8176 6.73638L13.8284 9.58578L12.4142 8.17157L15.2636 4.1824Z\",\n power:\n \"M16 2C17.1046 2 18 2.89543 18 4V20C18 21.1046 17.1046 22 16 22H9C7.89543 22 7 21.1046 7 20V4C7 2.89543 7.89543 2 9 2H16ZM13.8115 5.69961C13.8115 5.00797 12.9835 4.75858 12.631 5.27555L12.5794 5.36359L9.0799 12.364C8.8597 12.8083 9.11904 13.3258 9.55954 13.3928L9.6566 13.4001H11.1901V18.3004C11.1901 18.992 12.0181 19.2414 12.3706 18.7245L12.4222 18.6364L15.9217 11.636C16.1419 11.1917 15.8711 10.6742 15.4398 10.6072L15.345 10.5999H13.8115V5.69961Z\",\n comms:\n \"M16 2C17.6569 2 19 3.34315 19 5C19 6.65685 17.6569 8 16 8C15.8259 8 15.6553 7.98518 15.4894 7.95672L14.8034 9.14676C15.3137 9.64825 15.6902 10.2856 15.874 11.0002L18.2676 10.9999C18.6134 10.4022 19.2597 10 20 10C21.1046 10 22 10.8954 22 12C22 13.1046 21.1046 14 20 14C19.2602 14 18.6142 13.5983 18.2682 13.0011L15.8738 13.0008C15.6717 13.7853 15.2375 14.4767 14.6488 14.9974L15.2128 16.1044C15.4637 16.0363 15.7276 16 16 16C17.6569 16 19 17.3431 19 19C19 20.6569 17.6569 22 16 22C14.3431 22 13 20.6569 13 19C13 18.3508 13.2062 17.7498 13.5567 17.2589L12.8669 15.9058C12.5878 15.9675 12.2977 16 12 16C11.2582 16 10.5635 15.7981 9.96801 15.4462L7.75736 17.6569L7.59355 17.4912C7.85196 17.9345 8 18.4499 8 19C8 20.6569 6.65685 22 5 22C3.34315 22 2 20.6569 2 19C2 17.3431 3.34315 16 5 16C5.55006 16 6.06555 16.148 6.50879 16.4065L6.34315 16.2426L8.55383 14.032C8.20193 13.4365 8 12.7418 8 12C8 9.79086 9.79086 8 12 8C12.3705 8 12.7293 8.05038 13.0698 8.14467L13.7446 6.97823C13.281 6.45014 13 5.75789 13 5C13 3.34315 14.3431 2 16 2ZM12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10Z\",\n};\n\n/**\n * Render percentage arc display (Astro UX pattern)\n *\n * Displays a circular arc showing a percentage value 0-100.\n * The arc fills clockwise from the top, with status-colored fill.\n */\nconst renderPercentageArc = (\n percentage: number,\n statusColor: string,\n showValue: boolean = true,\n size: number = 48,\n): React.ReactNode => {\n // Clamp percentage to 0-100\n const pct = Math.max(0, Math.min(100, percentage));\n\n // Arc geometry\n const centerX = size / 2;\n const centerY = size / 2;\n const radius = size / 2 - 4; // Leave room for stroke\n const strokeWidth = 4;\n const innerRadius = radius - strokeWidth / 2;\n\n // Calculate arc path\n // Start at top (12 o'clock) and sweep clockwise\n const startAngle = -90; // Start at top\n const endAngle = startAngle + (pct / 100) * 360;\n\n // Convert to radians\n const startRad = (startAngle * Math.PI) / 180;\n const endRad = (endAngle * Math.PI) / 180;\n\n // Calculate start and end points\n const startX = centerX + innerRadius * Math.cos(startRad);\n const startY = centerY + innerRadius * Math.sin(startRad);\n const endX = centerX + innerRadius * Math.cos(endRad);\n const endY = centerY + innerRadius * Math.sin(endRad);\n\n // Determine if we need a large arc (> 180 degrees)\n const largeArcFlag = pct > 50 ? 1 : 0;\n\n // Create arc path\n const arcPath =\n pct > 0 && pct < 100\n ? `M ${startX} ${startY} A ${innerRadius} ${innerRadius} 0 ${largeArcFlag} 1 ${endX} ${endY}`\n : pct >= 100\n ? `M ${centerX} ${centerY - innerRadius} A ${innerRadius} ${innerRadius} 0 1 1 ${centerX - 0.001} ${centerY - innerRadius}` // Full circle\n : \"\"; // Empty when 0%\n\n return (\n <svg\n width={size}\n height={size}\n viewBox={`0 0 ${size} ${size}`}\n style={{ display: \"block\" }}\n >\n {/* Background circle (track) */}\n <circle\n cx={centerX}\n cy={centerY}\n r={innerRadius}\n fill=\"none\"\n stroke=\"rgba(255, 255, 255, 0.1)\"\n strokeWidth={strokeWidth}\n />\n\n {/* Progress arc */}\n {arcPath && (\n <path\n d={arcPath}\n fill=\"none\"\n stroke={statusColor}\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n style={{\n filter: `drop-shadow(0 0 4px ${statusColor}60)`,\n }}\n />\n )}\n\n {/* Center value text */}\n {showValue && (\n <text\n x={centerX}\n y={centerY}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n fill={statusColor}\n fontSize={size * 0.28}\n fontWeight={600}\n fontFamily=\"system-ui, -apple-system, sans-serif\"\n >\n {Math.round(pct)}\n </text>\n )}\n </svg>\n );\n};\n\n/**\n * Get status based on percentage value\n * - ascending: low values = critical, high values = normal\n * - descending: low values = normal, high values = critical\n */\nconst getStatusFromPercentage = (\n percentage: number,\n direction: \"ascending\" | \"descending\",\n): MonitoringStatus => {\n const pct = direction === \"descending\" ? 100 - percentage : percentage;\n\n if (pct >= 80) return \"normal\";\n if (pct >= 60) return \"standby\";\n if (pct >= 40) return \"caution\";\n if (pct >= 20) return \"serious\";\n return \"critical\";\n};\n\n/**\n * MonitoringIcon - Pure React monitoring icon component\n *\n * Displays system status with icon, label, and optional notification badge.\n * Fully Astro UX compliant with theme integration.\n *\n * @example\n * ```tsx\n * // Standard monitoring icon\n * <MonitoringIcon\n * status=\"normal\"\n * label=\"Power\"\n * sublabel=\"85%\"\n * icon=\"power\"\n * />\n *\n * // Percentage arc display\n * <MonitoringIcon\n * status=\"normal\"\n * label=\"Battery\"\n * showPercentage\n * percentage={75}\n * percentageToStatus=\"ascending\"\n * />\n * ```\n */\nexport const MonitoringIcon = memo(function MonitoringIcon({\n status,\n label,\n sublabel,\n icon = \"mission\",\n notifications,\n tooltip,\n className = \"\",\n onClick,\n showPercentage = false,\n percentage = 0,\n percentageToStatus,\n showPercentageValue = true,\n}: MonitoringIconProps): React.ReactElement {\n const { tokens, mode, theme } = useTheme();\n const isTransparentTheme =\n theme === \"transparent\" ||\n theme === \"transparent-bold\" ||\n theme === \"transparent-minimal\";\n const [showTooltip, setShowTooltip] = useState(false);\n\n // Calculate effective status when using percentage-to-status mapping\n const effectiveStatus = percentageToStatus\n ? getStatusFromPercentage(percentage, percentageToStatus)\n : status;\n\n // Get status color from theme\n const color = tokens.colors.status[effectiveStatus] || \"#a4abb6\";\n const isLightTheme = mode === \"light\";\n const borderColor = isLightTheme\n ? STATUS_BORDER_COLORS[effectiveStatus]\n : undefined;\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (onClick && (e.key === \"Enter\" || e.key === \" \")) {\n e.preventDefault();\n onClick();\n }\n };\n\n const renderIcon = () => {\n // Percentage arc display mode\n if (showPercentage) {\n return renderPercentageArc(percentage, color, showPercentageValue, 48);\n }\n\n // Custom React element\n if (React.isValidElement(icon)) {\n return icon;\n }\n\n // Use Icon component if valid icon name from core library\n if (typeof icon === \"string\" && isValidIconName(icon)) {\n return <Icon name={icon as IconName} size={24} color=\"currentColor\" />;\n }\n\n // Fallback to legacy ICON_PATHS for backward compatibility\n const iconPath = typeof icon === \"string\" ? ICON_PATHS[icon] : undefined;\n\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n style={{ width: 24, height: 24 }}\n aria-hidden=\"true\"\n >\n {iconPath ? (\n <path d={iconPath} fillRule=\"evenodd\" clipRule=\"evenodd\" />\n ) : (\n <path\n d=\"M12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2ZM12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4ZM18 12C18 8.68629 15.3137 6 12 6C8.68629 6 6 8.68629 6 12C6 15.3137 8.68629 18 12 18C15.3137 18 18 15.3137 18 12ZM12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8ZM14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12Z\"\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n />\n )}\n </svg>\n );\n };\n\n return (\n <div\n className={classNames(\"zendir-monitoring-icon\", className)}\n onClick={onClick}\n onKeyDown={onClick ? handleKeyDown : undefined}\n onMouseEnter={() => setShowTooltip(true)}\n onMouseLeave={() => setShowTooltip(false)}\n tabIndex={onClick ? 0 : undefined}\n role=\"status\"\n aria-label={`${label}: ${sublabel ?? status}`}\n style={{\n position: \"relative\",\n display: \"inline-flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: tokens.spacing.xs,\n padding: `${tokens.spacing.sm} ${tokens.spacing.md}`,\n minWidth: 72,\n backgroundColor: isTransparentTheme\n ? \"transparent\"\n : tokens.colors.background.surface,\n ...(isTransparentTheme && {\n backdropFilter: \"blur(12px)\",\n WebkitBackdropFilter: \"blur(12px)\" as const,\n }),\n ...(tokens.colors.border.cardStyle ?? {\n border: `1px solid ${tokens.colors.border.muted}`,\n }),\n borderRadius: tokens.borderRadius.md,\n cursor: onClick ? \"pointer\" : \"default\",\n outline: \"none\",\n transition: tokens.animation.fast,\n }}\n >\n {/* Icon with status indicator */}\n <div\n style={{\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color,\n // Explicit sizing for predictable layout\n width: showPercentage ? 48 : 24,\n height: showPercentage ? 48 : 24,\n }}\n >\n {renderIcon()}\n\n {/* Status symbol - shape based on status per Astro UX */}\n <span\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n transform: \"translate(-35%, -35%)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n {renderStatusSymbol(\n effectiveStatus,\n 9,\n color,\n borderColor,\n !isLightTheme,\n )}\n </span>\n\n {/* Notification badge */}\n {notifications !== undefined && notifications > 0 && (\n <span\n style={{\n position: \"absolute\",\n top: 0,\n right: 0,\n transform: \"translate(40%, -40%)\",\n minWidth: 16,\n height: 16,\n padding: \"0 4px\",\n borderRadius: tokens.borderRadius.full,\n backgroundColor: tokens.colors.status.critical,\n color: \"#ffffff\",\n fontSize: \"0.625rem\", // 10px in rem\n fontWeight: 700, // AstroUXDS bold for status values\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n {notifications > 99 ? \"99+\" : notifications}\n </span>\n )}\n </div>\n\n {/* Label - sentence case per Astro UX */}\n <span\n style={{\n fontSize: tokens.typography.fontSize.xs,\n fontWeight: tokens.typography.fontWeight.medium,\n color: tokens.colors.text.secondary,\n textTransform: \"none\", // Astro uses sentence case, not uppercase\n letterSpacing: tokens.typography.letterSpacing.normal,\n whiteSpace: \"nowrap\",\n }}\n >\n {label}\n </span>\n\n {/* Sublabel - dynamic value */}\n {sublabel && (\n <span\n style={{\n fontSize: tokens.typography.fontSize.sm,\n fontWeight: tokens.typography.fontWeight.semibold,\n fontVariantNumeric: \"tabular-nums\",\n color: tokens.colors.text.primary,\n }}\n >\n {sublabel}\n </span>\n )}\n\n {/* Tooltip */}\n {tooltip && showTooltip && (\n <div\n style={{\n position: \"absolute\",\n bottom: \"100%\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n marginBottom: 8,\n padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`,\n backgroundColor: tokens.colors.background.overlay,\n borderRadius: tokens.borderRadius.sm,\n fontSize: tokens.typography.fontSize.sm,\n color: tokens.colors.text.primary,\n whiteSpace: \"nowrap\",\n zIndex: 1000,\n pointerEvents: \"none\",\n boxShadow: tokens.shadows.md,\n }}\n >\n {tooltip}\n {/* Tooltip arrow */}\n <span\n style={{\n position: \"absolute\",\n top: \"100%\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n borderWidth: 4,\n borderStyle: \"solid\",\n borderColor: `${tokens.colors.background.overlay} transparent transparent transparent`,\n }}\n />\n </div>\n )}\n </div>\n );\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"MonitoringIcon.js","names":[],"sources":["../../../src/react/astro/MonitoringIcon.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - MonitoringIcon Component (Pure React)\r\n *\r\n * Status monitoring icon following Astro UX Design System patterns.\r\n * Displays a monitoring icon with status, label, and sub-label.\r\n *\r\n * Astro UX Compliance (https://www.astrouxds.com/components/icons-and-symbols/):\r\n * - Must include a label and status indicator\r\n * - Light theme requires border around status indicator\r\n * - Uses 6-level status color system\r\n *\r\n * Features:\r\n * - Status-based coloring with theme integration\r\n * - Notification badge\r\n * - Astro icon library support\r\n * - Light theme border support\r\n * - Tooltip support\r\n * - Keyboard accessible\r\n */\r\n\r\nimport React, { memo, useState } from \"react\";\r\nimport { useTheme } from \"../theme\";\r\nimport { classNames, type StatusLevel } from \"../utils\";\r\nimport { Icon, isValidIconName, type IconName } from \"../core/display/Icon\";\r\n\r\nexport type MonitoringStatus = StatusLevel;\r\n\r\nexport interface MonitoringIconProps {\r\n /** Current status of the monitored item */\r\n status: MonitoringStatus;\r\n /** Primary label (always visible) */\r\n label: string;\r\n /** Sub-label for dynamic info (optional) */\r\n sublabel?: string;\r\n /** Icon name or custom icon element */\r\n icon?: string | React.ReactNode;\r\n /** Notification count badge */\r\n notifications?: number;\r\n /** Show tooltip on hover */\r\n tooltip?: string;\r\n /** Custom className */\r\n className?: string;\r\n /** Click handler */\r\n onClick?: () => void;\r\n\r\n // === Percentage Arc Display (Astro UX) ===\r\n /**\r\n * Show percentage arc display instead of icon\r\n * When true, displays a circular arc showing the percentage value\r\n */\r\n showPercentage?: boolean;\r\n /** Percentage value (0-100) - displayed as arc when showPercentage is true */\r\n percentage?: number;\r\n /** Map percentage to status colors (e.g., low = critical, high = normal) */\r\n percentageToStatus?: \"ascending\" | \"descending\";\r\n /** Show percentage value as text inside the arc */\r\n showPercentageValue?: boolean;\r\n}\r\n\r\n/**\r\n * Astro UX Status Colors (Light Theme - Border)\r\n * Required for light backgrounds per Astro UX\r\n */\r\nconst STATUS_BORDER_COLORS: Record<StatusLevel, string> = {\r\n off: \"#3c3e42\",\r\n standby: \"#285766\",\r\n normal: \"#005a00\",\r\n caution: \"#645600\",\r\n serious: \"#664618\",\r\n critical: \"#661102\",\r\n};\r\n\r\n/**\r\n * Render Astro-compliant status shape for MonitoringIcon\r\n * Shapes per https://www.astrouxds.com/patterns/status-system/\r\n * - Off: Circle (grey)\r\n * - Standby: Ring (cyan)\r\n * - Normal: Circle (green)\r\n * - Caution: Square (yellow)\r\n * - Serious: Diamond (orange)\r\n * - Critical: Triangle pointing down (red)\r\n */\r\nconst renderStatusSymbol = (\r\n status: StatusLevel,\r\n size: number,\r\n fillColor: string,\r\n borderColor?: string,\r\n glow?: boolean,\r\n): React.ReactNode => {\r\n const hasBorder = !!borderColor;\r\n const strokeWidth = hasBorder ? 1 : 0;\r\n const glowFilter = glow ? `drop-shadow(0 0 3px ${fillColor})` : undefined;\r\n\r\n switch (status) {\r\n // Small filled circle: off\r\n case \"off\":\r\n return (\r\n <svg\r\n viewBox=\"0 0 12 12\"\r\n width={size}\r\n height={size}\r\n style={{ filter: glowFilter }}\r\n >\r\n <circle\r\n cx=\"6\"\r\n cy=\"6\"\r\n r={hasBorder ? 2.5 : 3}\r\n fill={fillColor}\r\n stroke={borderColor}\r\n strokeWidth={strokeWidth}\r\n />\r\n </svg>\r\n );\r\n\r\n // Ring (donut): standby\r\n case \"standby\":\r\n return (\r\n <svg\r\n viewBox=\"0 0 12 12\"\r\n width={size}\r\n height={size}\r\n style={{ filter: glowFilter }}\r\n >\r\n <circle\r\n cx=\"6\"\r\n cy=\"6\"\r\n r=\"3.5\"\r\n fill=\"none\"\r\n stroke={fillColor}\r\n strokeWidth=\"2\"\r\n />\r\n </svg>\r\n );\r\n\r\n // Filled circle: normal\r\n case \"normal\":\r\n return (\r\n <svg\r\n viewBox=\"0 0 12 12\"\r\n width={size}\r\n height={size}\r\n style={{ filter: glowFilter }}\r\n >\r\n <circle\r\n cx=\"6\"\r\n cy=\"6\"\r\n r={hasBorder ? 4.5 : 5}\r\n fill={fillColor}\r\n stroke={borderColor}\r\n strokeWidth={strokeWidth}\r\n />\r\n </svg>\r\n );\r\n\r\n // Square shape: caution\r\n case \"caution\":\r\n return (\r\n <svg\r\n viewBox=\"0 0 12 12\"\r\n width={size}\r\n height={size}\r\n style={{ filter: glowFilter }}\r\n >\r\n <rect\r\n x={hasBorder ? 1.5 : 1}\r\n y={hasBorder ? 1.5 : 1}\r\n width={hasBorder ? 9 : 10}\r\n height={hasBorder ? 9 : 10}\r\n fill={fillColor}\r\n stroke={borderColor}\r\n strokeWidth={strokeWidth}\r\n />\r\n </svg>\r\n );\r\n\r\n // Diamond shape: serious (rotated square)\r\n case \"serious\":\r\n return (\r\n <svg\r\n viewBox=\"0 0 12 12\"\r\n width={size}\r\n height={size}\r\n style={{ filter: glowFilter }}\r\n >\r\n <polygon\r\n points=\"6,1 11,6 6,11 1,6\"\r\n fill={fillColor}\r\n stroke={borderColor}\r\n strokeWidth={strokeWidth}\r\n />\r\n </svg>\r\n );\r\n\r\n // Triangle pointing down: critical\r\n case \"critical\":\r\n return (\r\n <svg\r\n viewBox=\"0 0 12 12\"\r\n width={size}\r\n height={size}\r\n style={{ filter: glowFilter }}\r\n >\r\n <polygon\r\n points=\"6,11 1,2 11,2\"\r\n fill={fillColor}\r\n stroke={borderColor}\r\n strokeWidth={strokeWidth}\r\n />\r\n </svg>\r\n );\r\n\r\n default:\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * Astro UX Icon Library\r\n * Based on https://astro-components.netlify.app/?path=/story/components-icons--all-icons\r\n *\r\n * Categories: Astro (space/mission), Equipment, System\r\n */\r\nconst ICON_PATHS: Record<string, string> = {\r\n // Astro Icons (Space/Mission) - Paths from @astrouxds/astro-web-components\r\n thermal:\r\n \"M10.5 2C12.433 2 14 3.567 14 5.5L14.0005 12.2576C15.2217 13.2664 16 14.7923 16 16.5C16 19.5376 13.5376 22 10.5 22C7.46243 22 5 19.5376 5 16.5C5 14.7919 5.77868 13.2656 7.00044 12.2568L7 5.5C7 3.567 8.567 2 10.5 2ZM10.5 4C9.7203 4 9.07955 4.59489 9.00687 5.35543L9 5.49987L9.0005 13.199L8.27384 13.799C7.47135 14.4616 7 15.4402 7 16.5C7 18.433 8.567 20 10.5 20C12.433 20 14 18.433 14 16.5C14 15.5111 13.5896 14.593 12.8828 13.9362L12.7268 13.7995L12.0006 13.1997L12 5.5C12 4.7203 11.4051 4.07955 10.6445 4.00687L10.5 4ZM11 5.5C11 5.22386 10.7761 5 10.5 5C10.2239 5 10 5.22386 10 5.5L10.0006 14.0499C8.85917 14.2813 8 15.2903 8 16.5C8 17.8807 9.11929 19 10.5 19C11.8807 19 13 17.8807 13 16.5C13 15.2907 12.1413 14.2819 11.0004 14.0501L11 5.5ZM20 11C20.5523 11 21 11.4477 21 12C21 12.5523 20.5523 13 20 13H17C16.4477 13 16 12.5523 16 12C16 11.4477 16.4477 11 17 11H20ZM19 9C19 8.44772 18.5523 8 18 8H17C16.4477 8 16 8.44772 16 9C16 9.55228 16.4477 10 17 10H18C18.5523 10 19 9.55228 19 9ZM20 5C20.5523 5 21 5.44772 21 6C21 6.55228 20.5523 7 20 7H17C16.4477 7 16 6.55228 16 6C16 5.44772 16.4477 5 17 5H20ZM19 3C19 2.44772 18.5523 2 18 2H17C16.4477 2 16 2.44772 16 3C16 3.55228 16.4477 4 17 4H18C18.5523 4 19 3.55228 19 3Z\",\r\n \"propulsion-power\":\r\n \"M16 2C17.1046 2 18 2.89543 18 4V20C18 21.1046 17.1046 22 16 22H9C7.89543 22 7 21.1046 7 20V4C7 2.89543 7.89543 2 9 2H16ZM13.8115 5.69961C13.8115 5.00797 12.9835 4.75858 12.631 5.27555L12.5794 5.36359L9.0799 12.364C8.8597 12.8083 9.11904 13.3258 9.55954 13.3928L9.6566 13.4001H11.1901V18.3004C11.1901 18.992 12.0181 19.2414 12.3706 18.7245L12.4222 18.6364L15.9217 11.636C16.1419 11.1917 15.8711 10.6742 15.4398 10.6072L15.345 10.5999H13.8115V5.69961Z\",\r\n payload:\r\n \"M12.6802 2.24483L12.8418 2.31637L20.8418 6.31637C21.4305 6.6107 21.819 7.18871 21.8753 7.83667L21.8824 8V16C21.8824 16.6581 21.5391 17.2641 20.9848 17.6043L20.8418 17.6836L12.8418 21.6836C12.3649 21.9221 11.812 21.9459 11.3198 21.7552L11.1582 21.6836L3.15821 17.6836C2.56956 17.3893 2.18104 16.8113 2.12475 16.1633L2.11768 16V8C2.11768 7.34186 2.46091 6.73586 3.0153 6.39574L3.15821 6.31637L3.4276 6.17973C3.50773 6.12386 3.59511 6.0805 3.6866 6.05036L11.1582 2.31637C11.5822 2.1044 12.0662 2.062 12.5141 2.18919L12.6802 2.24483ZM3.99968 8.17865L4.00003 16L10.9997 19.4996V12.5536L3.99968 8.17865ZM12.9997 12.6176L19.9997 9.11765L20 16L12.9997 19.4996V12.6176ZM18.5 15C18.7762 15 19 15.2239 19 15.5C19 15.7761 18.7762 16 18.5 16C18.2239 16 18 15.7761 18 15.5C18 15.2239 18.2239 15 18.5 15ZM6.00003 15.5C6.00003 15.2239 5.77617 15 5.50003 15C5.22389 15 5.00003 15.2239 5.00003 15.5C5.00003 15.7761 5.22389 16 5.50003 16C5.77617 16 6.00003 15.7761 6.00003 15.5ZM16.5 14C16.7762 14 17 14.2239 17 14.5C17 14.7761 16.7762 15 16.5 15C16.2239 15 16 14.7761 16 14.5C16 14.2239 16.2239 14 16.5 14ZM8.00003 14.5C8.00003 14.2239 7.77617 14 7.50003 14C7.22389 14 7.00003 14.2239 7.00003 14.5C7.00003 14.7761 7.22389 15 7.50003 15C7.77617 15 8.00003 14.7761 8.00003 14.5ZM9.50003 13C9.77617 13 10 13.2239 10 13.5C10 13.7761 9.77617 14 9.50003 14C9.22389 14 9.00003 13.7761 9.00003 13.5C9.00003 13.2239 9.22389 13 9.50003 13ZM15 13.5C15 13.2239 14.7762 13 14.5 13C14.2239 13 14 13.2239 14 13.5C14 13.7761 14.2239 14 14.5 14C14.7762 14 15 13.7761 15 13.5ZM12 4L5.93668 7.03065L12.053 10.854L18.8807 7.44065L12 4ZM12.5 9.5C12.5 9.22386 12.2762 9 12 9C11.7239 9 11.5 9.22386 11.5 9.5C11.5 9.77614 11.7239 10 12 10C12.2762 10 12.5 9.77614 12.5 9.5ZM12 7C12.2762 7 12.5 7.22386 12.5 7.5C12.5 7.77614 12.2762 8 12 8C11.7239 8 11.5 7.77614 11.5 7.5C11.5 7.22386 11.7239 7 12 7ZM12.5 5.5C12.5 5.22386 12.2762 5 12 5C11.7239 5 11.5 5.22386 11.5 5.5C11.5 5.77614 11.7239 6 12 6C12.2762 6 12.5 5.77614 12.5 5.5Z\",\r\n netcom:\r\n \"M16 2C17.6569 2 19 3.34315 19 5C19 6.65685 17.6569 8 16 8C15.8259 8 15.6553 7.98518 15.4894 7.95672L14.8034 9.14676C15.3137 9.64825 15.6902 10.2856 15.874 11.0002L18.2676 10.9999C18.6134 10.4022 19.2597 10 20 10C21.1046 10 22 10.8954 22 12C22 13.1046 21.1046 14 20 14C19.2602 14 18.6142 13.5983 18.2682 13.0011L15.8738 13.0008C15.6717 13.7853 15.2375 14.4767 14.6488 14.9974L15.2128 16.1044C15.4637 16.0363 15.7276 16 16 16C17.6569 16 19 17.3431 19 19C19 20.6569 17.6569 22 16 22C14.3431 22 13 20.6569 13 19C13 18.3508 13.2062 17.7498 13.5567 17.2589L12.8669 15.9058C12.5878 15.9675 12.2977 16 12 16C11.2582 16 10.5635 15.7981 9.96801 15.4462L7.75736 17.6569L7.59355 17.4912C7.85196 17.9345 8 18.4499 8 19C8 20.6569 6.65685 22 5 22C3.34315 22 2 20.6569 2 19C2 17.3431 3.34315 16 5 16C5.55006 16 6.06555 16.148 6.50879 16.4065L6.34315 16.2426L8.55383 14.032C8.20193 13.4365 8 12.7418 8 12C8 9.79086 9.79086 8 12 8C12.3705 8 12.7293 8.05038 13.0698 8.14467L13.7446 6.97823C13.281 6.45014 13 5.75789 13 5C13 3.34315 14.3431 2 16 2ZM12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10Z\",\r\n antenna:\r\n \"M12.5 8C13.6506 8 14.5833 8.89543 14.5833 10C14.5833 10.7398 14.1649 11.3858 13.5428 11.7318L13.5416 22H11.4583L11.4582 11.7324C10.8356 11.3866 10.4166 10.7403 10.4166 10C10.4166 8.89543 11.3494 8 12.5 8ZM6.63099 2.32732C6.98124 2.70075 7.0016 3.27819 6.64763 3.65177C3.61283 6.82949 3.34936 11.6553 6.02151 15.1201C6.33286 15.5271 6.26451 16.1001 5.86774 16.4431C5.40872 16.8398 4.68582 16.775 4.3192 16.294C1.13831 12.1519 1.38131 6.45292 4.85709 2.56983L5.07393 2.33438L5.1678 2.24643C5.59314 1.89421 6.24722 1.91815 6.63099 2.32732ZM19.9142 2.24643L20.0081 2.33438C23.6894 6.21966 24.0087 12.0674 20.7628 16.294C20.3962 16.775 19.6733 16.8398 19.2143 16.4431C18.8175 16.1001 18.7492 15.5271 19.0605 15.1201C21.7327 11.6553 21.4692 6.82949 18.4344 3.65177C18.0804 3.27819 18.1008 2.70075 18.4511 2.32732C18.8348 1.91815 19.4889 1.89421 19.9142 2.24643ZM9.8013 5.34518C10.1466 5.71337 10.1537 6.26509 9.82646 6.65682C8.45162 8.33503 8.32337 10.6773 9.50741 12.4838C9.79011 12.9062 9.72281 13.4541 9.33916 13.7858C8.86156 14.1986 8.10517 14.1177 7.75278 13.6059C6.10277 11.1439 6.21558 7.93692 8.0237 5.58971L8.20397 5.3653L8.28854 5.2755C8.70418 4.88648 9.40006 4.91737 9.8013 5.34518ZM16.7935 5.2755L16.8781 5.3653C18.8573 7.72924 19.0325 11.0644 17.3292 13.6059C16.9769 14.1177 16.2205 14.1986 15.7429 13.7858C15.3592 13.4541 15.2919 12.9062 15.5746 12.4838C16.7586 10.6773 16.6304 8.33503 15.2556 6.65682C14.9283 6.26509 14.9354 5.71337 15.2807 5.34518C15.682 4.91737 16.3778 4.88648 16.7935 5.2755Z\",\r\n solar:\r\n \"M19.5385 4C20.3456 4 21 4.67008 21 5.49666V17.5033C21 18.3299 20.3456 19 19.5385 19H3.46154C2.65436 19 2 18.3299 2 17.5033V5.49666C2 4.67008 2.65436 4 3.46154 4H19.5385ZM7 6H4V11H7V6ZM11 6H8V11H11V6ZM15 6H12V11H15V6ZM19 6H16V11H19V6ZM7 12H4V17H7V12ZM11 12H8V17H11V12ZM15 12H12V17H15V12ZM19 12H16V17H19V12Z\",\r\n altitude:\r\n \"M12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2ZM12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4ZM14 18C14 17.4477 13.5523 17 13 17H11C10.4477 17 10 17.4477 10 18C10 18.5523 10.4477 19 11 19H13C13.5523 19 14 18.5523 14 18ZM14 14C14.5523 14 15 14.4477 15 15C15 15.5523 14.5523 16 14 16H10C9.44772 16 9 15.5523 9 15C9 14.4477 9.44772 14 10 14H14ZM16 12L19 14V10L16 12ZM5 10L8 12L5 14V10ZM14 12C14 11.4477 13.5523 11 13 11H11C10.4477 11 10 11.4477 10 12C10 12.5523 10.4477 13 11 13H13C13.5523 13 14 12.5523 14 12ZM14 8C14.5523 8 15 8.44772 15 9C15 9.55228 14.5523 10 14 10H10C9.44772 10 9 9.55228 9 9C9 8.44772 9.44772 8 10 8H14ZM14 6C14 5.44772 13.5523 5 13 5H11C10.4477 5 10 5.44772 10 6C10 6.55228 10.4477 7 11 7H13C13.5523 7 14 6.55228 14 6Z\",\r\n processor:\r\n \"M9 20V22H7V20H9ZM13 20V22H11V20H13ZM17 20V22H15V20H17ZM17 5C18.1046 5 19 5.89543 19 7V17C19 18.1046 18.1046 19 17 19H7C5.89543 19 5 18.1046 5 17V7C5 5.89543 5.89543 5 7 5H17ZM17 16C16.4477 16 16 16.4477 16 17C16 17.5523 16.4477 18 17 18C17.5523 18 18 17.5523 18 17C18 16.4477 17.5523 16 17 16ZM4 15V17H2V15H4ZM22 15V17H20V15H22ZM4 11V13H2V11H4ZM22 11V13H20V11H22ZM4 7V9H2V7H4ZM22 7V9H20V7H22ZM7 6C6.44772 6 6 6.44772 6 7C6 7.55228 6.44772 8 7 8C7.55228 8 8 7.55228 8 7C8 6.44772 7.55228 6 7 6ZM9 2V4H7V2H9ZM13 2V4H11V2H13ZM17 2V4H15V2H17Z\",\r\n mission:\r\n \"M12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2ZM12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4ZM18 12C18 8.68629 15.3137 6 12 6C8.68629 6 6 8.68629 6 12C6 15.3137 8.68629 18 12 18C15.3137 18 18 15.3137 18 12ZM12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8ZM14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12Z\",\r\n equipment:\r\n \"M22 5C22 3.89543 21.1046 3 20 3H4C2.89543 3 2 3.89543 2 5V9C2 10.1046 2.89543 11 4 11H20C21.1046 11 22 10.1046 22 9V5ZM22 15C22 13.8954 21.1046 13 20 13H4C2.89543 13 2 13.8954 2 15V19C2 20.1046 2.89543 21 4 21H20C21.1046 21 22 20.1046 22 19V15ZM4 15H20V19H4V15ZM7 16V18H5V16H7ZM10 18V16H8V18H10ZM13 16V18H11V16H13ZM20 5H4V9H20V5ZM7 8V6H5V8H7ZM10 6V8H8V6H10ZM13 8V6H11V8H13Z\",\r\n \"satellite-transmit\":\r\n \"M8.87871 8.87868C9.65976 8.09763 10.9261 8.09763 11.7071 8.87868L13.1213 10.2929C13.9024 11.0739 13.9024 12.3403 13.1213 13.1213C12.3403 13.9024 11.074 13.9024 10.2929 13.1213L8.87871 11.7071C8.09766 10.9261 8.09766 9.65973 8.87871 8.87868ZM4.05657 15.3702C4.09551 15.3313 4.13761 15.2956 4.18243 15.2636L8.1716 12.4142L9.58581 13.8284L6.73641 17.8176C6.4154 18.267 5.79085 18.3711 5.34144 18.0501C5.29662 18.0181 5.25452 17.9824 5.21557 17.9435L4.05657 16.7845C3.66604 16.3939 3.66604 15.7608 4.05657 15.3702ZM20.9898 11C21.5828 11 22.0551 11.5125 21.9948 12.1055C21.4823 17.3315 17.3416 21.4721 12.1156 21.9947C11.5226 22.055 11 21.5927 11 20.9998C11 20.4973 11.3719 20.0551 11.8744 20.0048C16.1658 19.5928 19.5828 16.1757 19.9949 11.8844C20.0451 11.3819 20.4773 11 20.9898 11ZM16.9776 11C17.5946 11 18.08 11.546 17.989 12.1527C17.5035 15.1355 15.1469 17.5015 12.1531 17.9868C11.5462 18.088 11 17.5925 11 16.9757C11 16.4803 11.3641 16.0657 11.8597 15.9848C13.8884 15.6338 15.5032 14.0794 15.9425 12.083L15.9864 11.8595C16.0673 11.364 16.482 11 16.9776 11ZM16.6903 3.97335L16.7845 4.05653L17.9435 5.21554C17.9824 5.25449 18.0181 5.29659 18.0501 5.34141C18.3464 5.75625 18.2805 6.32032 17.9152 6.65713L17.8176 6.73638L13.8285 9.58578L12.4142 8.17157L15.2636 4.1824C15.2957 4.13758 15.3313 4.09548 15.3703 4.05653C15.7308 3.69605 16.298 3.66832 16.6903 3.97335Z\",\r\n \"satellite-receive\":\r\n \"M5.53115 17.8387L6.58945 18.8268L8.92522 18.602L9.83101 20.4262C9.89964 20.5644 9.93535 20.7167 9.93535 20.871C9.93535 21.3838 9.54931 21.8065 9.05197 21.8642L8.93535 21.871H4.20497C3.9626 21.871 3.72849 21.7829 3.54616 21.6233C3.16263 21.2874 3.09746 20.7233 3.37588 20.3117L3.45266 20.2122L5.53115 17.8387ZM7.09757 10.0443C7.33377 10.0636 7.55543 10.1662 7.72301 10.3338L10.042 12.653L12 12L11.347 13.958L13.2146 15.8254C13.6051 16.2159 13.6051 16.8491 13.2146 17.2396C13.047 17.4072 12.8253 17.5098 12.5891 17.5291L7.30432 17.9622C7.01163 17.9862 6.7232 17.8803 6.51554 17.6726L5.87575 17.0328C5.66809 16.8252 5.56221 16.5368 5.58619 16.2441L6.01924 10.9593C6.06434 10.4088 6.54713 9.99916 7.09757 10.0443ZM14 9C14.5523 9 15 9.44772 15 10C15 10.5523 14.5523 11 14 11C13.4477 11 13 10.5523 13 10C13 9.44772 13.4477 9 14 9ZM16 7C16.5523 7 17 7.44772 17 8C17 8.55228 16.5523 9 16 9C15.4477 9 15 8.55228 15 8C15 7.44772 15.4477 7 16 7ZM18.5 4C19.3284 4 20 4.67157 20 5.5C20 6.32843 19.3284 7 18.5 7C17.6716 7 17 6.32843 17 5.5C17 4.67157 17.6716 4 18.5 4Z\",\r\n \"satellite-off\":\r\n \"M8.87867 11.7071C8.09762 10.9261 8.09762 9.65973 8.87867 8.87868C9.65972 8.09763 10.926 8.09763 11.7071 8.87868L13.1213 10.2929C13.9024 11.0739 13.9024 12.3403 13.1213 13.1213C12.3403 13.9024 11.0739 13.9024 10.2929 13.1213L8.87867 11.7071ZM4.05653 16.7845C3.61958 16.3475 3.67956 15.6228 4.1824 15.2636L8.17156 12.4142L9.58578 13.8284L6.73637 17.8176C6.3772 18.3204 5.65248 18.3804 5.21553 17.9435L4.05653 16.7845ZM15.2636 4.1824C15.6228 3.67956 16.3475 3.61958 16.7844 4.05653L17.9435 5.21554C18.3804 5.65249 18.3204 6.37721 17.8176 6.73638L13.8284 9.58578L12.4142 8.17157L15.2636 4.1824Z\",\r\n hardware:\r\n \"M4 17.8247V10.4692H20V17.8247H4ZM2 9.77297C2 9.05293 2.58371 8.46922 3.30375 8.46922H20.6962C21.4163 8.46922 22 9.05293 22 9.77298V18.5209C22 19.241 21.4163 19.8247 20.6962 19.8247H3.30375C2.58371 19.8247 2 19.241 2 18.5209V9.77297ZM8.99573 13.637H4.99573V11.637H8.99573V13.637ZM8.99573 16.642H4.99573V14.642H8.99573V16.642ZM10 13.637H14V11.637H10V13.637ZM14 16.642H10V14.642H14V16.642ZM14.9987 13.637H18.9987V11.637H14.9987V13.637ZM18.9987 16.6424H14.9987V14.6424H18.9987V16.6424Z\",\r\n release: \"M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8-8-8z\",\r\n // Legacy aliases\r\n satellite:\r\n \"M8.87867 11.7071C8.09762 10.9261 8.09762 9.65973 8.87867 8.87868C9.65972 8.09763 10.926 8.09763 11.7071 8.87868L13.1213 10.2929C13.9024 11.0739 13.9024 12.3403 13.1213 13.1213C12.3403 13.9024 11.0739 13.9024 10.2929 13.1213L8.87867 11.7071ZM4.05653 16.7845C3.61958 16.3475 3.67956 15.6228 4.1824 15.2636L8.17156 12.4142L9.58578 13.8284L6.73637 17.8176C6.3772 18.3204 5.65248 18.3804 5.21553 17.9435L4.05653 16.7845ZM15.2636 4.1824C15.6228 3.67956 16.3475 3.61958 16.7844 4.05653L17.9435 5.21554C18.3804 5.65249 18.3204 6.37721 17.8176 6.73638L13.8284 9.58578L12.4142 8.17157L15.2636 4.1824Z\",\r\n power:\r\n \"M16 2C17.1046 2 18 2.89543 18 4V20C18 21.1046 17.1046 22 16 22H9C7.89543 22 7 21.1046 7 20V4C7 2.89543 7.89543 2 9 2H16ZM13.8115 5.69961C13.8115 5.00797 12.9835 4.75858 12.631 5.27555L12.5794 5.36359L9.0799 12.364C8.8597 12.8083 9.11904 13.3258 9.55954 13.3928L9.6566 13.4001H11.1901V18.3004C11.1901 18.992 12.0181 19.2414 12.3706 18.7245L12.4222 18.6364L15.9217 11.636C16.1419 11.1917 15.8711 10.6742 15.4398 10.6072L15.345 10.5999H13.8115V5.69961Z\",\r\n comms:\r\n \"M16 2C17.6569 2 19 3.34315 19 5C19 6.65685 17.6569 8 16 8C15.8259 8 15.6553 7.98518 15.4894 7.95672L14.8034 9.14676C15.3137 9.64825 15.6902 10.2856 15.874 11.0002L18.2676 10.9999C18.6134 10.4022 19.2597 10 20 10C21.1046 10 22 10.8954 22 12C22 13.1046 21.1046 14 20 14C19.2602 14 18.6142 13.5983 18.2682 13.0011L15.8738 13.0008C15.6717 13.7853 15.2375 14.4767 14.6488 14.9974L15.2128 16.1044C15.4637 16.0363 15.7276 16 16 16C17.6569 16 19 17.3431 19 19C19 20.6569 17.6569 22 16 22C14.3431 22 13 20.6569 13 19C13 18.3508 13.2062 17.7498 13.5567 17.2589L12.8669 15.9058C12.5878 15.9675 12.2977 16 12 16C11.2582 16 10.5635 15.7981 9.96801 15.4462L7.75736 17.6569L7.59355 17.4912C7.85196 17.9345 8 18.4499 8 19C8 20.6569 6.65685 22 5 22C3.34315 22 2 20.6569 2 19C2 17.3431 3.34315 16 5 16C5.55006 16 6.06555 16.148 6.50879 16.4065L6.34315 16.2426L8.55383 14.032C8.20193 13.4365 8 12.7418 8 12C8 9.79086 9.79086 8 12 8C12.3705 8 12.7293 8.05038 13.0698 8.14467L13.7446 6.97823C13.281 6.45014 13 5.75789 13 5C13 3.34315 14.3431 2 16 2ZM12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10Z\",\r\n};\r\n\r\n/**\r\n * Render percentage arc display (Astro UX pattern)\r\n *\r\n * Displays a circular arc showing a percentage value 0-100.\r\n * The arc fills clockwise from the top, with status-colored fill.\r\n */\r\nconst renderPercentageArc = (\r\n percentage: number,\r\n statusColor: string,\r\n showValue: boolean = true,\r\n size: number = 48,\r\n): React.ReactNode => {\r\n // Clamp percentage to 0-100\r\n const pct = Math.max(0, Math.min(100, percentage));\r\n\r\n // Arc geometry\r\n const centerX = size / 2;\r\n const centerY = size / 2;\r\n const radius = size / 2 - 4; // Leave room for stroke\r\n const strokeWidth = 4;\r\n const innerRadius = radius - strokeWidth / 2;\r\n\r\n // Calculate arc path\r\n // Start at top (12 o'clock) and sweep clockwise\r\n const startAngle = -90; // Start at top\r\n const endAngle = startAngle + (pct / 100) * 360;\r\n\r\n // Convert to radians\r\n const startRad = (startAngle * Math.PI) / 180;\r\n const endRad = (endAngle * Math.PI) / 180;\r\n\r\n // Calculate start and end points\r\n const startX = centerX + innerRadius * Math.cos(startRad);\r\n const startY = centerY + innerRadius * Math.sin(startRad);\r\n const endX = centerX + innerRadius * Math.cos(endRad);\r\n const endY = centerY + innerRadius * Math.sin(endRad);\r\n\r\n // Determine if we need a large arc (> 180 degrees)\r\n const largeArcFlag = pct > 50 ? 1 : 0;\r\n\r\n // Create arc path\r\n const arcPath =\r\n pct > 0 && pct < 100\r\n ? `M ${startX} ${startY} A ${innerRadius} ${innerRadius} 0 ${largeArcFlag} 1 ${endX} ${endY}`\r\n : pct >= 100\r\n ? `M ${centerX} ${centerY - innerRadius} A ${innerRadius} ${innerRadius} 0 1 1 ${centerX - 0.001} ${centerY - innerRadius}` // Full circle\r\n : \"\"; // Empty when 0%\r\n\r\n return (\r\n <svg\r\n width={size}\r\n height={size}\r\n viewBox={`0 0 ${size} ${size}`}\r\n style={{ display: \"block\" }}\r\n >\r\n {/* Background circle (track) */}\r\n <circle\r\n cx={centerX}\r\n cy={centerY}\r\n r={innerRadius}\r\n fill=\"none\"\r\n stroke=\"rgba(255, 255, 255, 0.1)\"\r\n strokeWidth={strokeWidth}\r\n />\r\n\r\n {/* Progress arc */}\r\n {arcPath && (\r\n <path\r\n d={arcPath}\r\n fill=\"none\"\r\n stroke={statusColor}\r\n strokeWidth={strokeWidth}\r\n strokeLinecap=\"round\"\r\n style={{\r\n filter: `drop-shadow(0 0 4px ${statusColor}60)`,\r\n }}\r\n />\r\n )}\r\n\r\n {/* Center value text */}\r\n {showValue && (\r\n <text\r\n x={centerX}\r\n y={centerY}\r\n textAnchor=\"middle\"\r\n dominantBaseline=\"central\"\r\n fill={statusColor}\r\n fontSize={size * 0.28}\r\n fontWeight={600}\r\n fontFamily=\"system-ui, -apple-system, sans-serif\"\r\n >\r\n {Math.round(pct)}\r\n </text>\r\n )}\r\n </svg>\r\n );\r\n};\r\n\r\n/**\r\n * Get status based on percentage value\r\n * - ascending: low values = critical, high values = normal\r\n * - descending: low values = normal, high values = critical\r\n */\r\nconst getStatusFromPercentage = (\r\n percentage: number,\r\n direction: \"ascending\" | \"descending\",\r\n): MonitoringStatus => {\r\n const pct = direction === \"descending\" ? 100 - percentage : percentage;\r\n\r\n if (pct >= 80) return \"normal\";\r\n if (pct >= 60) return \"standby\";\r\n if (pct >= 40) return \"caution\";\r\n if (pct >= 20) return \"serious\";\r\n return \"critical\";\r\n};\r\n\r\n/**\r\n * MonitoringIcon - Pure React monitoring icon component\r\n *\r\n * Displays system status with icon, label, and optional notification badge.\r\n * Fully Astro UX compliant with theme integration.\r\n *\r\n * @example\r\n * ```tsx\r\n * // Standard monitoring icon\r\n * <MonitoringIcon\r\n * status=\"normal\"\r\n * label=\"Power\"\r\n * sublabel=\"85%\"\r\n * icon=\"power\"\r\n * />\r\n *\r\n * // Percentage arc display\r\n * <MonitoringIcon\r\n * status=\"normal\"\r\n * label=\"Battery\"\r\n * showPercentage\r\n * percentage={75}\r\n * percentageToStatus=\"ascending\"\r\n * />\r\n * ```\r\n */\r\nexport const MonitoringIcon = memo(function MonitoringIcon({\r\n status,\r\n label,\r\n sublabel,\r\n icon = \"mission\",\r\n notifications,\r\n tooltip,\r\n className = \"\",\r\n onClick,\r\n showPercentage = false,\r\n percentage = 0,\r\n percentageToStatus,\r\n showPercentageValue = true,\r\n}: MonitoringIconProps): React.ReactElement {\r\n const { tokens, mode, theme } = useTheme();\r\n const isTransparentTheme =\r\n theme === \"transparent\" ||\r\n theme === \"transparent-bold\" ||\r\n theme === \"transparent-minimal\";\r\n const [showTooltip, setShowTooltip] = useState(false);\r\n\r\n // Calculate effective status when using percentage-to-status mapping\r\n const effectiveStatus = percentageToStatus\r\n ? getStatusFromPercentage(percentage, percentageToStatus)\r\n : status;\r\n\r\n // Get status color from theme\r\n const color = tokens.colors.status[effectiveStatus] || \"#a4abb6\";\r\n const isLightTheme = mode === \"light\";\r\n const borderColor = isLightTheme\r\n ? STATUS_BORDER_COLORS[effectiveStatus]\r\n : undefined;\r\n\r\n const handleKeyDown = (e: React.KeyboardEvent) => {\r\n if (onClick && (e.key === \"Enter\" || e.key === \" \")) {\r\n e.preventDefault();\r\n onClick();\r\n }\r\n };\r\n\r\n const renderIcon = () => {\r\n // Percentage arc display mode\r\n if (showPercentage) {\r\n return renderPercentageArc(percentage, color, showPercentageValue, 48);\r\n }\r\n\r\n // Custom React element\r\n if (React.isValidElement(icon)) {\r\n return icon;\r\n }\r\n\r\n // Use Icon component if valid icon name from core library\r\n if (typeof icon === \"string\" && isValidIconName(icon)) {\r\n return <Icon name={icon as IconName} size={24} color=\"currentColor\" />;\r\n }\r\n\r\n // Fallback to legacy ICON_PATHS for backward compatibility\r\n const iconPath = typeof icon === \"string\" ? ICON_PATHS[icon] : undefined;\r\n\r\n return (\r\n <svg\r\n viewBox=\"0 0 24 24\"\r\n fill=\"currentColor\"\r\n style={{ width: 24, height: 24 }}\r\n aria-hidden=\"true\"\r\n >\r\n {iconPath ? (\r\n <path d={iconPath} fillRule=\"evenodd\" clipRule=\"evenodd\" />\r\n ) : (\r\n <path\r\n d=\"M12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2ZM12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4ZM18 12C18 8.68629 15.3137 6 12 6C8.68629 6 6 8.68629 6 12C6 15.3137 8.68629 18 12 18C15.3137 18 18 15.3137 18 12ZM12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8ZM14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12Z\"\r\n fillRule=\"evenodd\"\r\n clipRule=\"evenodd\"\r\n />\r\n )}\r\n </svg>\r\n );\r\n };\r\n\r\n return (\r\n <div\r\n className={classNames(\"zendir-monitoring-icon\", className)}\r\n onClick={onClick}\r\n onKeyDown={onClick ? handleKeyDown : undefined}\r\n onMouseEnter={() => setShowTooltip(true)}\r\n onMouseLeave={() => setShowTooltip(false)}\r\n tabIndex={onClick ? 0 : undefined}\r\n role=\"status\"\r\n aria-label={`${label}: ${sublabel ?? status}`}\r\n style={{\r\n position: \"relative\",\r\n display: \"inline-flex\",\r\n flexDirection: \"column\",\r\n alignItems: \"center\",\r\n gap: tokens.spacing.xs,\r\n padding: `${tokens.spacing.sm} ${tokens.spacing.md}`,\r\n minWidth: 72,\r\n backgroundColor: isTransparentTheme\r\n ? \"transparent\"\r\n : tokens.colors.background.surface,\r\n ...(isTransparentTheme && {\r\n backdropFilter: \"blur(12px)\",\r\n WebkitBackdropFilter: \"blur(12px)\" as const,\r\n }),\r\n ...(tokens.colors.border.cardStyle ?? {\r\n border: `1px solid ${tokens.colors.border.muted}`,\r\n }),\r\n borderRadius: tokens.borderRadius.md,\r\n cursor: onClick ? \"pointer\" : \"default\",\r\n outline: \"none\",\r\n transition: tokens.animation.fast,\r\n }}\r\n >\r\n {/* Icon with status indicator */}\r\n <div\r\n style={{\r\n position: \"relative\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n color,\r\n // Explicit sizing for predictable layout\r\n width: showPercentage ? 48 : 24,\r\n height: showPercentage ? 48 : 24,\r\n }}\r\n >\r\n {renderIcon()}\r\n\r\n {/* Status symbol - shape based on status per Astro UX */}\r\n <span\r\n style={{\r\n position: \"absolute\",\r\n top: 0,\r\n left: 0,\r\n transform: \"translate(-35%, -35%)\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n }}\r\n >\r\n {renderStatusSymbol(\r\n effectiveStatus,\r\n 9,\r\n color,\r\n borderColor,\r\n !isLightTheme,\r\n )}\r\n </span>\r\n\r\n {/* Notification badge */}\r\n {notifications !== undefined && notifications > 0 && (\r\n <span\r\n style={{\r\n position: \"absolute\",\r\n top: 0,\r\n right: 0,\r\n transform: \"translate(40%, -40%)\",\r\n minWidth: 16,\r\n height: 16,\r\n padding: \"0 4px\",\r\n borderRadius: tokens.borderRadius.full,\r\n backgroundColor: tokens.colors.status.critical,\r\n color: \"#ffffff\",\r\n fontSize: \"0.625rem\", // 10px in rem\r\n fontWeight: 700, // AstroUXDS bold for status values\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n }}\r\n >\r\n {notifications > 99 ? \"99+\" : notifications}\r\n </span>\r\n )}\r\n </div>\r\n\r\n {/* Label - sentence case per Astro UX */}\r\n <span\r\n style={{\r\n fontSize: tokens.typography.fontSize.xs,\r\n fontWeight: tokens.typography.fontWeight.medium,\r\n color: tokens.colors.text.secondary,\r\n textTransform: \"none\", // Astro uses sentence case, not uppercase\r\n letterSpacing: tokens.typography.letterSpacing.normal,\r\n whiteSpace: \"nowrap\",\r\n }}\r\n >\r\n {label}\r\n </span>\r\n\r\n {/* Sublabel - dynamic value */}\r\n {sublabel && (\r\n <span\r\n style={{\r\n fontSize: tokens.typography.fontSize.sm,\r\n fontWeight: tokens.typography.fontWeight.semibold,\r\n fontVariantNumeric: \"tabular-nums\",\r\n color: tokens.colors.text.primary,\r\n }}\r\n >\r\n {sublabel}\r\n </span>\r\n )}\r\n\r\n {/* Tooltip */}\r\n {tooltip && showTooltip && (\r\n <div\r\n style={{\r\n position: \"absolute\",\r\n bottom: \"100%\",\r\n left: \"50%\",\r\n transform: \"translateX(-50%)\",\r\n marginBottom: 8,\r\n padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`,\r\n backgroundColor: tokens.colors.background.overlay,\r\n borderRadius: tokens.borderRadius.sm,\r\n fontSize: tokens.typography.fontSize.sm,\r\n color: tokens.colors.text.primary,\r\n whiteSpace: \"nowrap\",\r\n zIndex: 1000,\r\n pointerEvents: \"none\",\r\n boxShadow: tokens.shadows.md,\r\n }}\r\n >\r\n {tooltip}\r\n {/* Tooltip arrow */}\r\n <span\r\n style={{\r\n position: \"absolute\",\r\n top: \"100%\",\r\n left: \"50%\",\r\n transform: \"translateX(-50%)\",\r\n borderWidth: 4,\r\n borderStyle: \"solid\",\r\n borderColor: `${tokens.colors.background.overlay} transparent transparent transparent`,\r\n }}\r\n />\r\n </div>\r\n )}\r\n </div>\r\n );\r\n});\r\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Notification.js","names":[],"sources":["../../../src/react/astro/Notification.tsx"],"sourcesContent":["/**\n * @zendir/ui - Notification Component (Pure React)\n *\n * Toast notification following Astro UX Design System patterns.\n *\n * Features:\n * - Theme-integrated via useTheme()\n * - Status-based styling (standby, normal, caution, critical)\n * - Auto-dismiss support\n * - Close button\n * - Entrance/exit animations\n * - Accessible (live region for screen readers)\n */\n\nimport React, { memo, useEffect, useState, useCallback, useRef } from \"react\";\nimport { useTheme } from \"../theme\";\nimport { classNames } from \"../utils\";\n\nexport type NotificationStatus =\n | \"standby\"\n | \"normal\"\n | \"caution\"\n | \"serious\"\n | \"critical\";\n\nexport interface NotificationProps {\n /** Notification message */\n message: string;\n /** Status/severity of the notification */\n status?: NotificationStatus;\n /** Whether the notification is open/visible */\n open?: boolean;\n /** Auto-close after this many milliseconds */\n closeAfter?: number;\n /** Show close button */\n closeable?: boolean;\n /** Callback when notification is closed */\n onClose?: () => void;\n /** Custom className */\n className?: string;\n /** Child content (alternative to message prop) */\n children?: React.ReactNode;\n}\n\n/**\n * AstroUXDS Status Symbol Icons with Dual-Coding\n *\n * Each status has a unique shape for accessibility:\n * - standby: Ring (info)\n * - normal: Circle (checkmark)\n * - caution: Square (warning)\n * - serious: Diamond (warning)\n * - critical: Triangle (error)\n */\nconst STATUS_ICONS: Record<NotificationStatus, React.ReactNode> = {\n // Standby - Blue ring with info symbol\n standby: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" opacity=\"0.2\" />\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n />\n <path d=\"M11 11h2v6h-2v-6zm0-4h2v2h-2V7z\" />\n </svg>\n ),\n // Normal - Green Circle with checkmark\n normal: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path\n d=\"M9 12.5l2 2 4-4\"\n fill=\"none\"\n stroke=\"#fff\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n ),\n // Caution - Yellow Square with warning\n caution: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" />\n <path d=\"M11 7h2v6h-2V7zm0 8h2v2h-2v-2z\" fill=\"#000\" />\n </svg>\n ),\n // Serious - Orange Diamond with warning\n serious: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M12 2l10 10-10 10L2 12z\" />\n <path d=\"M11 8h2v6h-2V8zm0 8h2v2h-2v-2z\" fill=\"#000\" />\n </svg>\n ),\n // Critical - Red Triangle with exclamation\n critical: (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\n <path d=\"M12 2L2 20h20L12 2z\" />\n <path d=\"M11 9h2v6h-2V9zm0 8h2v2h-2v-2z\" fill=\"#fff\" />\n </svg>\n ),\n};\n\n/**\n * Notification - Pure React toast notification\n *\n * Displays alerts with status-based coloring and optional auto-dismiss.\n *\n * @example\n * ```tsx\n * <Notification\n * message=\"Telemetry received\"\n * status=\"normal\"\n * open={true}\n * />\n * <Notification\n * message=\"Link quality degraded\"\n * status=\"caution\"\n * closeAfter={5000}\n * onClose={() => {}}\n * />\n * ```\n */\nexport const Notification = memo(function Notification({\n message,\n status = \"standby\",\n open = true,\n closeAfter,\n closeable = true,\n onClose,\n className = \"\",\n children,\n}: NotificationProps): React.ReactElement | null {\n const { tokens, theme } = useTheme();\n const isTransparentTheme =\n theme === \"transparent\" ||\n theme === \"transparent-bold\" ||\n theme === \"transparent-minimal\";\n const [isVisible, setIsVisible] = useState(open);\n const [isExiting, setIsExiting] = useState(false);\n const closeTimeoutRef = useRef<ReturnType<typeof setTimeout>>();\n const color = tokens.colors.status[status] || tokens.colors.status.standby;\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n clearTimeout(closeTimeoutRef.current);\n };\n }, []);\n\n const handleClose = useCallback(() => {\n setIsExiting(true);\n closeTimeoutRef.current = setTimeout(() => {\n setIsVisible(false);\n onClose?.();\n }, 200);\n }, [onClose]);\n\n useEffect(() => {\n setIsVisible(open);\n setIsExiting(false);\n }, [open]);\n\n useEffect(() => {\n if (closeAfter && isVisible) {\n const timer = setTimeout(handleClose, closeAfter);\n return () => clearTimeout(timer);\n }\n }, [closeAfter, isVisible, handleClose]);\n\n if (!isVisible) return null;\n\n return (\n <div\n className={classNames(\"zendir-notification\", className)}\n role=\"alert\"\n aria-live=\"polite\"\n style={{\n display: \"flex\",\n alignItems: \"flex-start\",\n gap: tokens.spacing.md,\n padding: `${tokens.spacing.md} ${tokens.spacing.lg}`,\n backgroundColor: isTransparentTheme\n ? \"transparent\"\n : tokens.colors.background.surface,\n ...(isTransparentTheme && {\n backdropFilter: \"blur(12px)\",\n WebkitBackdropFilter: \"blur(12px)\" as const,\n }),\n borderLeft: `4px solid ${color}`,\n borderRadius: tokens.borderRadius.md,\n boxShadow: tokens.shadows.lg,\n maxWidth: 400,\n animation: isExiting\n ? \"notificationExit 200ms ease-out forwards\"\n : \"notificationEnter 200ms ease-out\",\n }}\n >\n {/* Status icon */}\n <span style={{ color, flexShrink: 0, marginTop: 2 }}>\n {STATUS_ICONS[status]}\n </span>\n\n {/* Content */}\n <div\n style={{\n flex: 1,\n fontSize: tokens.typography.fontSize.base,\n lineHeight: tokens.typography.lineHeight.normal,\n color: tokens.colors.text.primary,\n }}\n >\n {children ?? message}\n </div>\n\n {/* Close button */}\n {closeable && (\n <button\n onClick={handleClose}\n aria-label=\"Close notification\"\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 24,\n height: 24,\n padding: 0,\n background: \"transparent\",\n border: \"none\",\n borderRadius: tokens.borderRadius.sm,\n color: tokens.colors.text.secondary,\n cursor: \"pointer\",\n transition: tokens.animation.fast,\n flexShrink: 0,\n }}\n >\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"16\" height=\"16\">\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\" />\n </svg>\n </button>\n )}\n\n {/* Animations — respects prefers-reduced-motion (WCAG 2.3.3) */}\n <style>{`\n @keyframes notificationEnter {\n from {\n opacity: 0;\n transform: translateX(20px);\n }\n to {\n opacity: 1;\n transform: translateX(0);\n }\n }\n @keyframes notificationExit {\n from {\n opacity: 1;\n transform: translateX(0);\n }\n to {\n opacity: 0;\n transform: translateX(20px);\n }\n }\n @media (prefers-reduced-motion: reduce) {\n .zendir-notification {\n animation: none !important;\n }\n }\n `}</style>\n </div>\n );\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"Notification.js","names":[],"sources":["../../../src/react/astro/Notification.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - Notification Component (Pure React)\r\n *\r\n * Toast notification following Astro UX Design System patterns.\r\n *\r\n * Features:\r\n * - Theme-integrated via useTheme()\r\n * - Status-based styling (standby, normal, caution, critical)\r\n * - Auto-dismiss support\r\n * - Close button\r\n * - Entrance/exit animations\r\n * - Accessible (live region for screen readers)\r\n */\r\n\r\nimport React, { memo, useEffect, useState, useCallback, useRef } from \"react\";\r\nimport { useTheme } from \"../theme\";\r\nimport { classNames } from \"../utils\";\r\n\r\nexport type NotificationStatus =\r\n | \"standby\"\r\n | \"normal\"\r\n | \"caution\"\r\n | \"serious\"\r\n | \"critical\";\r\n\r\nexport interface NotificationProps {\r\n /** Notification message */\r\n message: string;\r\n /** Status/severity of the notification */\r\n status?: NotificationStatus;\r\n /** Whether the notification is open/visible */\r\n open?: boolean;\r\n /** Auto-close after this many milliseconds */\r\n closeAfter?: number;\r\n /** Show close button */\r\n closeable?: boolean;\r\n /** Callback when notification is closed */\r\n onClose?: () => void;\r\n /** Custom className */\r\n className?: string;\r\n /** Child content (alternative to message prop) */\r\n children?: React.ReactNode;\r\n}\r\n\r\n/**\r\n * AstroUXDS Status Symbol Icons with Dual-Coding\r\n *\r\n * Each status has a unique shape for accessibility:\r\n * - standby: Ring (info)\r\n * - normal: Circle (checkmark)\r\n * - caution: Square (warning)\r\n * - serious: Diamond (warning)\r\n * - critical: Triangle (error)\r\n */\r\nconst STATUS_ICONS: Record<NotificationStatus, React.ReactNode> = {\r\n // Standby - Blue ring with info symbol\r\n standby: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" opacity=\"0.2\" />\r\n <circle\r\n cx=\"12\"\r\n cy=\"12\"\r\n r=\"10\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n />\r\n <path d=\"M11 11h2v6h-2v-6zm0-4h2v2h-2V7z\" />\r\n </svg>\r\n ),\r\n // Normal - Green Circle with checkmark\r\n normal: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <path\r\n d=\"M9 12.5l2 2 4-4\"\r\n fill=\"none\"\r\n stroke=\"#fff\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n />\r\n </svg>\r\n ),\r\n // Caution - Yellow Square with warning\r\n caution: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" />\r\n <path d=\"M11 7h2v6h-2V7zm0 8h2v2h-2v-2z\" fill=\"#000\" />\r\n </svg>\r\n ),\r\n // Serious - Orange Diamond with warning\r\n serious: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M12 2l10 10-10 10L2 12z\" />\r\n <path d=\"M11 8h2v6h-2V8zm0 8h2v2h-2v-2z\" fill=\"#000\" />\r\n </svg>\r\n ),\r\n // Critical - Red Triangle with exclamation\r\n critical: (\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"20\" height=\"20\">\r\n <path d=\"M12 2L2 20h20L12 2z\" />\r\n <path d=\"M11 9h2v6h-2V9zm0 8h2v2h-2v-2z\" fill=\"#fff\" />\r\n </svg>\r\n ),\r\n};\r\n\r\n/**\r\n * Notification - Pure React toast notification\r\n *\r\n * Displays alerts with status-based coloring and optional auto-dismiss.\r\n *\r\n * @example\r\n * ```tsx\r\n * <Notification\r\n * message=\"Telemetry received\"\r\n * status=\"normal\"\r\n * open={true}\r\n * />\r\n * <Notification\r\n * message=\"Link quality degraded\"\r\n * status=\"caution\"\r\n * closeAfter={5000}\r\n * onClose={() => {}}\r\n * />\r\n * ```\r\n */\r\nexport const Notification = memo(function Notification({\r\n message,\r\n status = \"standby\",\r\n open = true,\r\n closeAfter,\r\n closeable = true,\r\n onClose,\r\n className = \"\",\r\n children,\r\n}: NotificationProps): React.ReactElement | null {\r\n const { tokens, theme } = useTheme();\r\n const isTransparentTheme =\r\n theme === \"transparent\" ||\r\n theme === \"transparent-bold\" ||\r\n theme === \"transparent-minimal\";\r\n const [isVisible, setIsVisible] = useState(open);\r\n const [isExiting, setIsExiting] = useState(false);\r\n const closeTimeoutRef = useRef<ReturnType<typeof setTimeout>>();\r\n const color = tokens.colors.status[status] || tokens.colors.status.standby;\r\n\r\n // Cleanup on unmount\r\n useEffect(() => {\r\n return () => {\r\n clearTimeout(closeTimeoutRef.current);\r\n };\r\n }, []);\r\n\r\n const handleClose = useCallback(() => {\r\n setIsExiting(true);\r\n closeTimeoutRef.current = setTimeout(() => {\r\n setIsVisible(false);\r\n onClose?.();\r\n }, 200);\r\n }, [onClose]);\r\n\r\n useEffect(() => {\r\n setIsVisible(open);\r\n setIsExiting(false);\r\n }, [open]);\r\n\r\n useEffect(() => {\r\n if (closeAfter && isVisible) {\r\n const timer = setTimeout(handleClose, closeAfter);\r\n return () => clearTimeout(timer);\r\n }\r\n }, [closeAfter, isVisible, handleClose]);\r\n\r\n if (!isVisible) return null;\r\n\r\n return (\r\n <div\r\n className={classNames(\"zendir-notification\", className)}\r\n role=\"alert\"\r\n aria-live=\"polite\"\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"flex-start\",\r\n gap: tokens.spacing.md,\r\n padding: `${tokens.spacing.md} ${tokens.spacing.lg}`,\r\n backgroundColor: isTransparentTheme\r\n ? \"transparent\"\r\n : tokens.colors.background.surface,\r\n ...(isTransparentTheme && {\r\n backdropFilter: \"blur(12px)\",\r\n WebkitBackdropFilter: \"blur(12px)\" as const,\r\n }),\r\n borderLeft: `4px solid ${color}`,\r\n borderRadius: tokens.borderRadius.md,\r\n boxShadow: tokens.shadows.lg,\r\n maxWidth: 400,\r\n animation: isExiting\r\n ? \"notificationExit 200ms ease-out forwards\"\r\n : \"notificationEnter 200ms ease-out\",\r\n }}\r\n >\r\n {/* Status icon */}\r\n <span style={{ color, flexShrink: 0, marginTop: 2 }}>\r\n {STATUS_ICONS[status]}\r\n </span>\r\n\r\n {/* Content */}\r\n <div\r\n style={{\r\n flex: 1,\r\n fontSize: tokens.typography.fontSize.base,\r\n lineHeight: tokens.typography.lineHeight.normal,\r\n color: tokens.colors.text.primary,\r\n }}\r\n >\r\n {children ?? message}\r\n </div>\r\n\r\n {/* Close button */}\r\n {closeable && (\r\n <button\r\n onClick={handleClose}\r\n aria-label=\"Close notification\"\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n width: 24,\r\n height: 24,\r\n padding: 0,\r\n background: \"transparent\",\r\n border: \"none\",\r\n borderRadius: tokens.borderRadius.sm,\r\n color: tokens.colors.text.secondary,\r\n cursor: \"pointer\",\r\n transition: tokens.animation.fast,\r\n flexShrink: 0,\r\n }}\r\n >\r\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" width=\"16\" height=\"16\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\" />\r\n </svg>\r\n </button>\r\n )}\r\n\r\n {/* Animations — respects prefers-reduced-motion (WCAG 2.3.3) */}\r\n <style>{`\r\n @keyframes notificationEnter {\r\n from {\r\n opacity: 0;\r\n transform: translateX(20px);\r\n }\r\n to {\r\n opacity: 1;\r\n transform: translateX(0);\r\n }\r\n }\r\n @keyframes notificationExit {\r\n from {\r\n opacity: 1;\r\n transform: translateX(0);\r\n }\r\n to {\r\n opacity: 0;\r\n transform: translateX(20px);\r\n }\r\n }\r\n @media (prefers-reduced-motion: reduce) {\r\n .zendir-notification {\r\n animation: none !important;\r\n }\r\n }\r\n `}</style>\r\n </div>\r\n );\r\n});\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,IAAM,eAA4D;CAEhE,SACE,qBAAC,OAAD;EAAK,SAAQ;EAAY,MAAK;EAAe,OAAM;EAAK,QAAO;YAA/D;GACE,oBAAC,UAAD;IAAQ,IAAG;IAAK,IAAG;IAAK,GAAE;IAAK,SAAQ;GAAO,CAAA;GAC9C,oBAAC,UAAD;IACE,IAAG;IACH,IAAG;IACH,GAAE;IACF,MAAK;IACL,QAAO;IACP,aAAY;GACb,CAAA;GACD,oBAAC,QAAD,EAAM,GAAE,kCAAmC,CAAA;EACxC;;CAGP,QACE,qBAAC,OAAD;EAAK,SAAQ;EAAY,MAAK;EAAe,OAAM;EAAK,QAAO;YAA/D,CACE,oBAAC,UAAD;GAAQ,IAAG;GAAK,IAAG;GAAK,GAAE;EAAM,CAAA,GAChC,oBAAC,QAAD;GACE,GAAE;GACF,MAAK;GACL,QAAO;GACP,aAAY;GACZ,eAAc;GACd,gBAAe;EAChB,CAAA,CACE;;CAGP,SACE,qBAAC,OAAD;EAAK,SAAQ;EAAY,MAAK;EAAe,OAAM;EAAK,QAAO;YAA/D,CACE,oBAAC,QAAD;GAAM,GAAE;GAAI,GAAE;GAAI,OAAM;GAAK,QAAO;GAAK,IAAG;EAAK,CAAA,GACjD,oBAAC,QAAD;GAAM,GAAE;GAAiC,MAAK;EAAQ,CAAA,CACnD;;CAGP,SACE,qBAAC,OAAD;EAAK,SAAQ;EAAY,MAAK;EAAe,OAAM;EAAK,QAAO;YAA/D,CACE,oBAAC,QAAD,EAAM,GAAE,0BAA2B,CAAA,GACnC,oBAAC,QAAD;GAAM,GAAE;GAAiC,MAAK;EAAQ,CAAA,CACnD;;CAGP,UACE,qBAAC,OAAD;EAAK,SAAQ;EAAY,MAAK;EAAe,OAAM;EAAK,QAAO;YAA/D,CACE,oBAAC,QAAD,EAAM,GAAE,sBAAuB,CAAA,GAC/B,oBAAC,QAAD;GAAM,GAAE;GAAiC,MAAK;EAAQ,CAAA,CACnD;;AAET;;;;;;;;;;;;;;;;;;;;;AAsBA,IAAa,eAAe,KAAK,SAAS,aAAa,EACrD,SACA,SAAS,WACT,OAAO,MACP,YACA,YAAY,MACZ,SACA,YAAY,IACZ,YAC+C;CAC/C,MAAM,EAAE,QAAQ,UAAU,SAAS;CACnC,MAAM,qBACJ,UAAU,iBACV,UAAU,sBACV,UAAU;CACZ,MAAM,CAAC,WAAW,gBAAgB,SAAS,IAAI;CAC/C,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,kBAAkB,OAAsC;CAC9D,MAAM,QAAQ,OAAO,OAAO,OAAO,WAAW,OAAO,OAAO,OAAO;CAGnE,gBAAgB;EACd,aAAa;GACX,aAAa,gBAAgB,OAAO;EACtC;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,cAAc,kBAAkB;EACpC,aAAa,IAAI;EACjB,gBAAgB,UAAU,iBAAiB;GACzC,aAAa,KAAK;GAClB,UAAU;EACZ,GAAG,GAAG;CACR,GAAG,CAAC,OAAO,CAAC;CAEZ,gBAAgB;EACd,aAAa,IAAI;EACjB,aAAa,KAAK;CACpB,GAAG,CAAC,IAAI,CAAC;CAET,gBAAgB;EACd,IAAI,cAAc,WAAW;GAC3B,MAAM,QAAQ,WAAW,aAAa,UAAU;GAChD,aAAa,aAAa,KAAK;EACjC;CACF,GAAG;EAAC;EAAY;EAAW;CAAW,CAAC;CAEvC,IAAI,CAAC,WAAW,OAAO;CAEvB,OACE,qBAAC,OAAD;EACE,WAAW,WAAW,uBAAuB,SAAS;EACtD,MAAK;EACL,aAAU;EACV,OAAO;GACL,SAAS;GACT,YAAY;GACZ,KAAK,OAAO,QAAQ;GACpB,SAAS,GAAG,OAAO,QAAQ,GAAG,GAAG,OAAO,QAAQ;GAChD,iBAAiB,qBACb,gBACA,OAAO,OAAO,WAAW;GAC7B,GAAI,sBAAsB;IACxB,gBAAgB;IAChB,sBAAsB;GACxB;GACA,YAAY,aAAa;GACzB,cAAc,OAAO,aAAa;GAClC,WAAW,OAAO,QAAQ;GAC1B,UAAU;GACV,WAAW,YACP,6CACA;EACN;YAvBF;GA0BE,oBAAC,QAAD;IAAM,OAAO;KAAE;KAAO,YAAY;KAAG,WAAW;IAAE;cAC/C,aAAa;GACV,CAAA;GAGN,oBAAC,OAAD;IACE,OAAO;KACL,MAAM;KACN,UAAU,OAAO,WAAW,SAAS;KACrC,YAAY,OAAO,WAAW,WAAW;KACzC,OAAO,OAAO,OAAO,KAAK;IAC5B;cAEC,YAAY;GACV,CAAA;GAGJ,aACC,oBAAC,UAAD;IACE,SAAS;IACT,cAAW;IACX,OAAO;KACL,SAAS;KACT,YAAY;KACZ,gBAAgB;KAChB,OAAO;KACP,QAAQ;KACR,SAAS;KACT,YAAY;KACZ,QAAQ;KACR,cAAc,OAAO,aAAa;KAClC,OAAO,OAAO,OAAO,KAAK;KAC1B,QAAQ;KACR,YAAY,OAAO,UAAU;KAC7B,YAAY;IACd;cAEA,oBAAC,OAAD;KAAK,SAAQ;KAAY,MAAK;KAAe,OAAM;KAAK,QAAO;eAC7D,oBAAC,QAAD,EAAM,GAAE,wGAAyG,CAAA;IAC9G,CAAA;GACC,CAAA;GAIV,oBAAC,SAAD,EAAA,UAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;QA0BC,CAAA;EACN;;AAET,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Progress.js","names":[],"sources":["../../../src/react/astro/Progress.tsx"],"sourcesContent":["/**\n * @zendir/ui - Progress Component (Pure React)\n *\n * Progress bar following Astro UX Design System patterns.\n *\n * Features:\n * - Theme-integrated via useTheme()\n * - Determinate and indeterminate modes\n * - Optional label and value display\n * - Status-based coloring\n * - Smooth animations\n * - Accessible (progress role with aria attributes)\n */\n\nimport React, { memo } from \"react\";\nimport { useTheme } from \"../theme\";\nimport { classNames, type StatusLevel, formatPercentage } from \"../utils\";\n\n/** Astro UX status shape per official spec: filled circle (normal), ring (standby), small circle (off), square (caution), diamond (serious), triangle (critical) */\nfunction ProgressStatusShape({\n status,\n color,\n size = 10,\n}: {\n status: StatusLevel;\n color: string;\n size?: number;\n}): React.ReactElement {\n const glow = `${color}50`;\n\n switch (status) {\n case \"caution\":\n return (\n <svg\n viewBox=\"0 0 12 12\"\n width={size}\n height={size}\n style={{ filter: `drop-shadow(0 0 3px ${glow})` }}\n >\n <rect x=\"1\" y=\"1\" width=\"10\" height=\"10\" fill={color} />\n </svg>\n );\n case \"serious\":\n return (\n <svg\n viewBox=\"0 0 12 12\"\n width={size}\n height={size}\n style={{ filter: `drop-shadow(0 0 3px ${glow})` }}\n >\n <polygon points=\"6,1 11,6 6,11 1,6\" fill={color} />\n </svg>\n );\n case \"critical\":\n return (\n <svg\n viewBox=\"0 0 12 12\"\n width={size}\n height={size}\n style={{ filter: `drop-shadow(0 0 3px ${glow})` }}\n >\n <polygon points=\"6,11 1,2 11,2\" fill={color} />\n </svg>\n );\n case \"standby\":\n return (\n <svg\n viewBox=\"0 0 12 12\"\n width={size}\n height={size}\n style={{ filter: `drop-shadow(0 0 3px ${glow})` }}\n >\n <circle\n cx=\"6\"\n cy=\"6\"\n r=\"3.5\"\n fill=\"none\"\n stroke={color}\n strokeWidth=\"2\"\n />\n </svg>\n );\n case \"off\":\n return (\n <svg\n viewBox=\"0 0 12 12\"\n width={size}\n height={size}\n style={{ filter: `drop-shadow(0 0 3px ${glow})` }}\n >\n <circle cx=\"6\" cy=\"6\" r=\"3\" fill={color} />\n </svg>\n );\n case \"normal\":\n default:\n return (\n <svg\n viewBox=\"0 0 12 12\"\n width={size}\n height={size}\n style={{ filter: `drop-shadow(0 0 3px ${glow})` }}\n >\n <circle cx=\"6\" cy=\"6\" r=\"5\" fill={color} />\n </svg>\n );\n }\n}\n\nexport interface ProgressProps {\n /** Current value (0-max) */\n value?: number;\n /** Maximum value (default: 100) */\n max?: number;\n /** Hide the percentage label */\n hideLabel?: boolean;\n /** Show value as label instead of percentage */\n showValue?: boolean;\n /** Status-based coloring (overrides default) */\n status?: StatusLevel;\n /** Indeterminate mode (animated, no value) */\n indeterminate?: boolean;\n /** Height of the progress bar */\n height?: number;\n /** Custom label */\n label?: string;\n /** Show Astro UX status shape icon beneath the bar at the fill position (default: true) */\n showStatusIcon?: boolean;\n /** Custom className */\n className?: string;\n}\n\n/**\n * Progress - Pure React progress bar component\n *\n * Displays progress with visual bar and optional label.\n *\n * @example\n * ```tsx\n * <Progress value={85} />\n * <Progress value={42} max={50} hideLabel />\n * <Progress indeterminate label=\"Loading...\" />\n * <Progress value={25} status=\"caution\" />\n * ```\n */\nexport const Progress = memo(function Progress({\n value,\n max = 100,\n hideLabel = false,\n showValue = false,\n status,\n indeterminate = false,\n height = 8,\n label,\n showStatusIcon = true,\n className = \"\",\n}: ProgressProps): React.ReactElement {\n const { tokens } = useTheme();\n const percentage =\n value !== undefined ? Math.min(100, Math.max(0, (value / max) * 100)) : 0;\n\n // Auto-determine status based on value if not provided\n const effectiveStatus: StatusLevel =\n status ??\n (percentage >= 75\n ? \"normal\"\n : percentage >= 50\n ? \"standby\"\n : percentage >= 25\n ? \"caution\"\n : percentage > 0\n ? \"serious\"\n : \"off\");\n\n // Get color from theme\n const color = tokens.colors.status[effectiveStatus];\n\n const displayLabel =\n label ??\n (showValue && value !== undefined\n ? `${value}/${max}`\n : formatPercentage(percentage, false, 0));\n\n const iconSize = Math.max(10, height + 2);\n\n return (\n <div\n className={classNames(\"zendir-progress\", className)}\n role=\"progressbar\"\n aria-valuenow={indeterminate ? undefined : value}\n aria-valuemin={0}\n aria-valuemax={max}\n aria-label={label ?? `Progress: ${percentage.toFixed(0)}%`}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: tokens.spacing.xs,\n width: \"100%\",\n }}\n >\n {/* Label row */}\n {!hideLabel && (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n fontSize: tokens.typography.fontSize.sm,\n fontWeight: tokens.typography.fontWeight.medium,\n color: tokens.colors.text.secondary,\n }}\n >\n {label && (\n <span style={{ color: tokens.colors.text.secondary }}>{label}</span>\n )}\n <span\n style={{\n marginLeft: \"auto\",\n fontVariantNumeric: \"tabular-nums\",\n color: tokens.colors.text.primary,\n }}\n >\n {!indeterminate && displayLabel}\n </span>\n </div>\n )}\n\n {/* Progress track (relative wrapper for icon positioning) */}\n <div style={{ position: \"relative\", width: \"100%\" }}>\n <div\n style={{\n position: \"relative\",\n width: \"100%\",\n height,\n backgroundColor: tokens.colors.border.muted,\n borderRadius: height / 2,\n overflow: \"hidden\",\n }}\n >\n {/* Progress fill */}\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n height: \"100%\",\n width: indeterminate ? \"30%\" : `${percentage}%`,\n backgroundColor: color,\n borderRadius: height / 2,\n transition: indeterminate ? \"none\" : \"width 300ms ease-out\",\n animation: indeterminate\n ? \"progressIndeterminate 1.5s ease-in-out infinite\"\n : \"none\",\n boxShadow: `0 0 ${height}px ${color}40`,\n }}\n />\n </div>\n\n {/* Status shape icon positioned beneath the fill edge */}\n {showStatusIcon && !indeterminate && (\n <div\n style={{\n position: \"absolute\",\n top: height + 4,\n left: `${percentage}%`,\n transform: \"translateX(-50%)\",\n lineHeight: 0,\n transition: \"left 300ms ease-out\",\n }}\n aria-hidden=\"true\"\n >\n <ProgressStatusShape\n status={effectiveStatus}\n color={color}\n size={iconSize}\n />\n </div>\n )}\n </div>\n\n {/* Reserve space for the icon so it doesn't overlap content below */}\n {showStatusIcon && !indeterminate && (\n <div style={{ height: iconSize + 2 }} />\n )}\n\n {/* Keyframe animation for indeterminate */}\n <style>{`\n @keyframes progressIndeterminate {\n 0% { left: -30%; }\n 100% { left: 100%; }\n }\n `}</style>\n </div>\n );\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"Progress.js","names":[],"sources":["../../../src/react/astro/Progress.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - Progress Component (Pure React)\r\n *\r\n * Progress bar following Astro UX Design System patterns.\r\n *\r\n * Features:\r\n * - Theme-integrated via useTheme()\r\n * - Determinate and indeterminate modes\r\n * - Optional label and value display\r\n * - Status-based coloring\r\n * - Smooth animations\r\n * - Accessible (progress role with aria attributes)\r\n */\r\n\r\nimport React, { memo } from \"react\";\r\nimport { useTheme } from \"../theme\";\r\nimport { classNames, type StatusLevel, formatPercentage } from \"../utils\";\r\n\r\n/** Astro UX status shape per official spec: filled circle (normal), ring (standby), small circle (off), square (caution), diamond (serious), triangle (critical) */\r\nfunction ProgressStatusShape({\r\n status,\r\n color,\r\n size = 10,\r\n}: {\r\n status: StatusLevel;\r\n color: string;\r\n size?: number;\r\n}): React.ReactElement {\r\n const glow = `${color}50`;\r\n\r\n switch (status) {\r\n case \"caution\":\r\n return (\r\n <svg\r\n viewBox=\"0 0 12 12\"\r\n width={size}\r\n height={size}\r\n style={{ filter: `drop-shadow(0 0 3px ${glow})` }}\r\n >\r\n <rect x=\"1\" y=\"1\" width=\"10\" height=\"10\" fill={color} />\r\n </svg>\r\n );\r\n case \"serious\":\r\n return (\r\n <svg\r\n viewBox=\"0 0 12 12\"\r\n width={size}\r\n height={size}\r\n style={{ filter: `drop-shadow(0 0 3px ${glow})` }}\r\n >\r\n <polygon points=\"6,1 11,6 6,11 1,6\" fill={color} />\r\n </svg>\r\n );\r\n case \"critical\":\r\n return (\r\n <svg\r\n viewBox=\"0 0 12 12\"\r\n width={size}\r\n height={size}\r\n style={{ filter: `drop-shadow(0 0 3px ${glow})` }}\r\n >\r\n <polygon points=\"6,11 1,2 11,2\" fill={color} />\r\n </svg>\r\n );\r\n case \"standby\":\r\n return (\r\n <svg\r\n viewBox=\"0 0 12 12\"\r\n width={size}\r\n height={size}\r\n style={{ filter: `drop-shadow(0 0 3px ${glow})` }}\r\n >\r\n <circle\r\n cx=\"6\"\r\n cy=\"6\"\r\n r=\"3.5\"\r\n fill=\"none\"\r\n stroke={color}\r\n strokeWidth=\"2\"\r\n />\r\n </svg>\r\n );\r\n case \"off\":\r\n return (\r\n <svg\r\n viewBox=\"0 0 12 12\"\r\n width={size}\r\n height={size}\r\n style={{ filter: `drop-shadow(0 0 3px ${glow})` }}\r\n >\r\n <circle cx=\"6\" cy=\"6\" r=\"3\" fill={color} />\r\n </svg>\r\n );\r\n case \"normal\":\r\n default:\r\n return (\r\n <svg\r\n viewBox=\"0 0 12 12\"\r\n width={size}\r\n height={size}\r\n style={{ filter: `drop-shadow(0 0 3px ${glow})` }}\r\n >\r\n <circle cx=\"6\" cy=\"6\" r=\"5\" fill={color} />\r\n </svg>\r\n );\r\n }\r\n}\r\n\r\nexport interface ProgressProps {\r\n /** Current value (0-max) */\r\n value?: number;\r\n /** Maximum value (default: 100) */\r\n max?: number;\r\n /** Hide the percentage label */\r\n hideLabel?: boolean;\r\n /** Show value as label instead of percentage */\r\n showValue?: boolean;\r\n /** Status-based coloring (overrides default) */\r\n status?: StatusLevel;\r\n /** Indeterminate mode (animated, no value) */\r\n indeterminate?: boolean;\r\n /** Height of the progress bar */\r\n height?: number;\r\n /** Custom label */\r\n label?: string;\r\n /** Show Astro UX status shape icon beneath the bar at the fill position (default: true) */\r\n showStatusIcon?: boolean;\r\n /** Custom className */\r\n className?: string;\r\n}\r\n\r\n/**\r\n * Progress - Pure React progress bar component\r\n *\r\n * Displays progress with visual bar and optional label.\r\n *\r\n * @example\r\n * ```tsx\r\n * <Progress value={85} />\r\n * <Progress value={42} max={50} hideLabel />\r\n * <Progress indeterminate label=\"Loading...\" />\r\n * <Progress value={25} status=\"caution\" />\r\n * ```\r\n */\r\nexport const Progress = memo(function Progress({\r\n value,\r\n max = 100,\r\n hideLabel = false,\r\n showValue = false,\r\n status,\r\n indeterminate = false,\r\n height = 8,\r\n label,\r\n showStatusIcon = true,\r\n className = \"\",\r\n}: ProgressProps): React.ReactElement {\r\n const { tokens } = useTheme();\r\n const percentage =\r\n value !== undefined ? Math.min(100, Math.max(0, (value / max) * 100)) : 0;\r\n\r\n // Auto-determine status based on value if not provided\r\n const effectiveStatus: StatusLevel =\r\n status ??\r\n (percentage >= 75\r\n ? \"normal\"\r\n : percentage >= 50\r\n ? \"standby\"\r\n : percentage >= 25\r\n ? \"caution\"\r\n : percentage > 0\r\n ? \"serious\"\r\n : \"off\");\r\n\r\n // Get color from theme\r\n const color = tokens.colors.status[effectiveStatus];\r\n\r\n const displayLabel =\r\n label ??\r\n (showValue && value !== undefined\r\n ? `${value}/${max}`\r\n : formatPercentage(percentage, false, 0));\r\n\r\n const iconSize = Math.max(10, height + 2);\r\n\r\n return (\r\n <div\r\n className={classNames(\"zendir-progress\", className)}\r\n role=\"progressbar\"\r\n aria-valuenow={indeterminate ? undefined : value}\r\n aria-valuemin={0}\r\n aria-valuemax={max}\r\n aria-label={label ?? `Progress: ${percentage.toFixed(0)}%`}\r\n style={{\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n gap: tokens.spacing.xs,\r\n width: \"100%\",\r\n }}\r\n >\r\n {/* Label row */}\r\n {!hideLabel && (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n justifyContent: \"space-between\",\r\n alignItems: \"center\",\r\n fontSize: tokens.typography.fontSize.sm,\r\n fontWeight: tokens.typography.fontWeight.medium,\r\n color: tokens.colors.text.secondary,\r\n }}\r\n >\r\n {label && (\r\n <span style={{ color: tokens.colors.text.secondary }}>{label}</span>\r\n )}\r\n <span\r\n style={{\r\n marginLeft: \"auto\",\r\n fontVariantNumeric: \"tabular-nums\",\r\n color: tokens.colors.text.primary,\r\n }}\r\n >\r\n {!indeterminate && displayLabel}\r\n </span>\r\n </div>\r\n )}\r\n\r\n {/* Progress track (relative wrapper for icon positioning) */}\r\n <div style={{ position: \"relative\", width: \"100%\" }}>\r\n <div\r\n style={{\r\n position: \"relative\",\r\n width: \"100%\",\r\n height,\r\n backgroundColor: tokens.colors.border.muted,\r\n borderRadius: height / 2,\r\n overflow: \"hidden\",\r\n }}\r\n >\r\n {/* Progress fill */}\r\n <div\r\n style={{\r\n position: \"absolute\",\r\n top: 0,\r\n left: 0,\r\n height: \"100%\",\r\n width: indeterminate ? \"30%\" : `${percentage}%`,\r\n backgroundColor: color,\r\n borderRadius: height / 2,\r\n transition: indeterminate ? \"none\" : \"width 300ms ease-out\",\r\n animation: indeterminate\r\n ? \"progressIndeterminate 1.5s ease-in-out infinite\"\r\n : \"none\",\r\n boxShadow: `0 0 ${height}px ${color}40`,\r\n }}\r\n />\r\n </div>\r\n\r\n {/* Status shape icon positioned beneath the fill edge */}\r\n {showStatusIcon && !indeterminate && (\r\n <div\r\n style={{\r\n position: \"absolute\",\r\n top: height + 4,\r\n left: `${percentage}%`,\r\n transform: \"translateX(-50%)\",\r\n lineHeight: 0,\r\n transition: \"left 300ms ease-out\",\r\n }}\r\n aria-hidden=\"true\"\r\n >\r\n <ProgressStatusShape\r\n status={effectiveStatus}\r\n color={color}\r\n size={iconSize}\r\n />\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Reserve space for the icon so it doesn't overlap content below */}\r\n {showStatusIcon && !indeterminate && (\r\n <div style={{ height: iconSize + 2 }} />\r\n )}\r\n\r\n {/* Keyframe animation for indeterminate */}\r\n <style>{`\r\n @keyframes progressIndeterminate {\r\n 0% { left: -30%; }\r\n 100% { left: 100%; }\r\n }\r\n `}</style>\r\n </div>\r\n );\r\n});\r\n"],"mappings":"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"}