@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.
- package/CHANGELOG.md +419 -406
- package/dist/react/3d/CesiumCaptureSource.js.map +1 -1
- package/dist/react/3d/ZenSpace3D.js.map +1 -1
- package/dist/react/3d/ZenSpace3DCesium.js.map +1 -1
- package/dist/react/3d/ZenSpace3DShaders.js.map +1 -1
- package/dist/react/3d/ZenSpace3DUtils.js.map +1 -1
- package/dist/react/3d/capturePngAnalysis.js.map +1 -1
- package/dist/react/3d/threeLoader.js.map +1 -1
- package/dist/react/astro/ClassificationBanner.js.map +1 -1
- package/dist/react/astro/GlobalStatusBar.js.map +1 -1
- package/dist/react/astro/MissionClock.js.map +1 -1
- package/dist/react/astro/MonitoringIcon.js.map +1 -1
- package/dist/react/astro/Notification.js.map +1 -1
- package/dist/react/astro/Progress.js.map +1 -1
- package/dist/react/astro/SimulationControls.js.map +1 -1
- package/dist/react/astro/StatusIndicator.js.map +1 -1
- package/dist/react/astro/UnifiedTimeline.js.map +1 -1
- package/dist/react/cards/AccessCard.js.map +1 -1
- package/dist/react/cards/OrbitCard.js.map +1 -1
- package/dist/react/cards/SpacecraftCard.js.map +1 -1
- package/dist/react/cards/TelemetryCard.js.map +1 -1
- package/dist/react/cards/TelemetryStreamCard.js.map +1 -1
- package/dist/react/charts/GroundTrackMap.js.map +1 -1
- package/dist/react/charts/GroundTrackMapLeaflet.js.map +1 -1
- package/dist/react/charts/groundTrackMapLeafletTiles.js.map +1 -1
- package/dist/react/charts/groundTrackMapLeafletUtils.js.map +1 -1
- package/dist/react/charts/unified/AstroChart.js.map +1 -1
- package/dist/react/charts/unified/PowerOverviewChart.js.map +1 -1
- package/dist/react/charts/unified/domain.js.map +1 -1
- package/dist/react/charts/unified/generators.js.map +1 -1
- package/dist/react/charts/unified/presets.js.map +1 -1
- package/dist/react/charts/unified/sync.js.map +1 -1
- package/dist/react/charts/unified/theme.js.map +1 -1
- package/dist/react/charts/unified/useChartStream.js.map +1 -1
- package/dist/react/chatgpt/index.js.map +1 -1
- package/dist/react/context/CategoryContext.js.map +1 -1
- package/dist/react/context/DisplaySettingsContext.js.map +1 -1
- package/dist/react/context/SpatialSelectionContext.js.map +1 -1
- package/dist/react/core/data/DataTable.js.map +1 -1
- package/dist/react/core/data/DataValue.js.map +1 -1
- package/dist/react/core/data/propertyConfig.js.map +1 -1
- package/dist/react/core/display/AstroIcon.js.map +1 -1
- package/dist/react/core/display/Badge.js.map +1 -1
- package/dist/react/core/display/CardHeader.js.map +1 -1
- package/dist/react/core/display/Container.js.map +1 -1
- package/dist/react/core/display/CopyButton.js.map +1 -1
- package/dist/react/core/display/GlassCard.js.map +1 -1
- package/dist/react/core/display/HeaderIconWithStatus.js.map +1 -1
- package/dist/react/core/display/Icon.js.map +1 -1
- package/dist/react/core/display/Typography.js.map +1 -1
- package/dist/react/core/feedback/ConfirmDialog.js.map +1 -1
- package/dist/react/core/feedback/Dialog.js.map +1 -1
- package/dist/react/core/feedback/Toast.js.map +1 -1
- package/dist/react/core/inputs/Button.js.map +1 -1
- package/dist/react/core/inputs/Checkbox.js.map +1 -1
- package/dist/react/core/inputs/Input.js.map +1 -1
- package/dist/react/core/inputs/LimitsBar.js.map +1 -1
- package/dist/react/core/inputs/NumberInput.js.map +1 -1
- package/dist/react/core/inputs/PinInput.js.map +1 -1
- package/dist/react/core/inputs/Select.js.map +1 -1
- package/dist/react/core/inputs/Toggle.js.map +1 -1
- package/dist/react/core/layout/Box.js.map +1 -1
- package/dist/react/core/layout/Center.js.map +1 -1
- package/dist/react/core/layout/Divider.js.map +1 -1
- package/dist/react/core/layout/Flex.js.map +1 -1
- package/dist/react/core/layout/Grid.js.map +1 -1
- package/dist/react/core/layout/Spacer.js.map +1 -1
- package/dist/react/core/layout/Stack.js.map +1 -1
- package/dist/react/core/layout/responsive.js.map +1 -1
- package/dist/react/core/layout/useBreakpoint.js.map +1 -1
- package/dist/react/core/navigation/AppBar.js.map +1 -1
- package/dist/react/core/navigation/Pagination.js.map +1 -1
- package/dist/react/core/navigation/SideNav.js.map +1 -1
- package/dist/react/core/navigation/Tabs.js.map +1 -1
- package/dist/react/core/overlays/Popover.js.map +1 -1
- package/dist/react/core/overlays/SidePanel.js.map +1 -1
- package/dist/react/core/overlays/Tooltip.js.map +1 -1
- package/dist/react/core/widgets/ActivityPlanner.js.map +1 -1
- package/dist/react/core/widgets/Capture.js.map +1 -1
- package/dist/react/core/widgets/ChatPanel.js.map +1 -1
- package/dist/react/core/widgets/ColorPickerPanel.js.map +1 -1
- package/dist/react/core/widgets/CommandBuilder.js.map +1 -1
- package/dist/react/core/widgets/ConnectionForm.js.map +1 -1
- package/dist/react/core/widgets/FileExplorer.js.map +1 -1
- package/dist/react/core/widgets/HexViewer.js.map +1 -1
- package/dist/react/core/widgets/ImageFrame.js.map +1 -1
- package/dist/react/core/widgets/ImageGallery.js.map +1 -1
- package/dist/react/core/widgets/ImagePanel.js.map +1 -1
- package/dist/react/core/widgets/LogViewer.js.map +1 -1
- package/dist/react/core/widgets/MessageStream.js.map +1 -1
- package/dist/react/core/widgets/MissionCalendar.js.map +1 -1
- package/dist/react/core/widgets/PacketViewer.js.map +1 -1
- package/dist/react/hooks/useCompactMode.js.map +1 -1
- package/dist/react/hooks/useSimulationScene.js.map +1 -1
- package/dist/react/panels/LayerControlPanel.js.map +1 -1
- package/dist/react/panels/ObjectInventoryPanel.js.map +1 -1
- package/dist/react/shared/ErrorBoundary.js.map +1 -1
- package/dist/react/shared/Skeleton.js.map +1 -1
- package/dist/react/theme/ThemeProvider.js +2 -1
- package/dist/react/theme/ThemeProvider.js.map +1 -1
- package/dist/react/theme/cardAccent.js.map +1 -1
- package/dist/react/theme/config.js.map +1 -1
- package/dist/react/theme/types.js.map +1 -1
- package/dist/react/types.js.map +1 -1
- package/dist/react/utils/categoryPalette.js.map +1 -1
- package/dist/react/utils/index.js.map +1 -1
- package/dist/style.css +216 -216
- package/dist/tokens/core.js.map +1 -1
- package/dist/tokens/index.js.map +1 -1
- package/dist/tokens/palettes/astro.js.map +1 -1
- package/dist/tokens/palettes/index.js.map +1 -1
- package/dist/tokens/palettes/tailwind.js.map +1 -1
- package/dist/tokens/palettes/zendir.js.map +1 -1
- package/dist/tokens/themes.js.map +1 -1
- package/dist/tokens/tokens.css +533 -533
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Container.js","names":[],"sources":["../../../../src/react/core/display/Container.tsx"],"sourcesContent":["/**\n * @zendir/ui - Container/Card Component\n *\n * Container/Card wrapper following Astro UX Design System.\n * Automatically switches to glassmorphic styling when transparent themes are active.\n *\n * Transparent themes (transparent, transparent-bold):\n * - Glassmorphic panels with blur effect\n * - Colored top border accent\n * - Hover glow effect (like GlassCard)\n * - transparent-bold has 2px top border\n *\n * @example\n * ```tsx\n * <Container>Simple container</Container>\n * <Container title=\"Spacecraft Status\" status=\"normal\">Content</Container>\n * <Container title=\"Power System\" icon=\"solar\" iconStatus=\"normal\">With status</Container>\n * <Container title=\"Custom Color\" icon=\"thermal\" iconColor=\"#FF6B6B\">Custom color</Container>\n * ```\n */\n\nimport React, { memo, useCallback } from \"react\";\nimport { useTheme } from \"../../theme\";\nimport { classNames, addAlpha, type StatusLevel } from \"../../utils\";\nimport { AstroIcon, type AstroIconName } from \"./AstroIcon\";\nimport { HeaderIconWithStatus } from \"./HeaderIconWithStatus\";\nimport { CardHeader } from \"./CardHeader\";\nimport { useBreakpoint } from \"../layout/useBreakpoint\";\n\nexport type ContainerVariant =\n | \"default\"\n | \"elevated\"\n | \"outlined\"\n | \"ghost\"\n | \"glass\"\n | \"glass-dark\"\n | \"glass-light\";\nexport type ContainerPadding = \"none\" | \"sm\" | \"md\" | \"lg\";\n\n/** Status descriptions for tooltips (default synonyms from AstroUXDS) */\nconst STATUS_DESCRIPTIONS: Record<StatusLevel, string> = {\n off: \"Off, unavailable, disabled\",\n standby: \"Standby, available, enabled\",\n normal: \"Normal, ok, satisfactory\",\n caution: \"Caution, warning, unstable\",\n serious: \"Serious, error, needs attention\",\n critical: \"Critical, emergency, urgent\",\n};\n\n/** Status symbol shapes following AstroUXDS guidelines */\ntype _StatusShape =\n | \"circle\"\n | \"square\"\n | \"diamond\"\n | \"triangle\"\n | \"circle-hollow\";\n\nexport interface ContainerProps {\n /** Visual variant */\n variant?: ContainerVariant;\n /** Padding size */\n padding?: ContainerPadding;\n /** Container title */\n title?: React.ReactNode;\n /** Subtitle or description */\n subtitle?: React.ReactNode;\n /** Status indicator (affects left border in non-glass mode) */\n status?: StatusLevel;\n /** Header actions (buttons, etc.) */\n actions?: React.ReactNode;\n /** Full height */\n fullHeight?: boolean;\n /**\n * Clip overflowing content area when fullHeight is enabled.\n * Keep false for form cards so wrapped rows can expand naturally.\n */\n clipContent?: boolean;\n /** Loading state */\n loading?: boolean;\n /** Children */\n children: React.ReactNode;\n /** Custom className */\n className?: string;\n /** Custom style */\n style?: React.CSSProperties;\n /** Click handler */\n onClick?: () => void;\n /** Disable auto-glass effect in transparent theme */\n disableAutoGlass?: boolean;\n /** Icon to display in header (Astro icon name) */\n icon?: AstroIconName;\n /** Icon status - shows status symbol and colors icon accordingly */\n iconStatus?: StatusLevel;\n /** Custom status message shown in tooltip (overrides default description) */\n statusMessage?: string;\n /** Custom icon color (overrides iconStatus and theme color) */\n iconColor?: string;\n /** Custom accent color for glass mode (title, line, etc.) */\n accentColor?: string;\n}\n\n/**\n * Icon wrapper with status tooltip - triggers tooltip on hover over entire icon area\n */\nfunction IconWithStatusTooltip({\n icon,\n iconColor,\n iconStatus,\n statusMessage,\n iconSize = 20,\n}: {\n icon: string;\n iconColor: string;\n iconStatus?: StatusLevel;\n statusMessage?: string;\n iconSize?: number;\n}): React.ReactElement {\n const [isHovered, setIsHovered] = React.useState(false);\n const { tokens } = useTheme();\n const color = iconStatus ? tokens.colors.status[iconStatus] : iconColor;\n const defaultMessage = iconStatus ? STATUS_DESCRIPTIONS[iconStatus] : \"\";\n const tooltipText = statusMessage || defaultMessage;\n const statusLabel = iconStatus\n ? iconStatus.charAt(0).toUpperCase() + iconStatus.slice(1)\n : \"\";\n\n return (\n <div\n style={{\n position: \"relative\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flexShrink: 0,\n cursor: iconStatus ? \"help\" : \"default\",\n }}\n onMouseEnter={() => iconStatus && setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n {/* Use HeaderIconWithStatus for consistent sizing with SpacecraftCard */}\n {iconStatus ? (\n <HeaderIconWithStatus\n icon={icon as AstroIconName}\n status={iconStatus}\n size={iconSize}\n statusColor={iconColor}\n />\n ) : (\n <AstroIcon name={icon} size={iconSize} color={iconColor} />\n )}\n {/* Tooltip popup - triggers on whole icon area hover */}\n {iconStatus && isHovered && (\n <div\n style={{\n position: \"absolute\",\n bottom: \"calc(100% + 12px)\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n padding: \"8px 12px\",\n backgroundColor: \"rgba(10, 15, 25, 0.95)\",\n border: `1px solid ${color}`,\n borderRadius: \"4px\",\n boxShadow: `0 0 12px ${color}40, 0 4px 12px rgba(0,0,0,0.4)`,\n zIndex: 1000,\n whiteSpace: \"nowrap\",\n pointerEvents: \"none\",\n minWidth: \"150px\",\n }}\n >\n {/* Status label */}\n <div\n style={{\n fontSize: \"0.6875rem\", // 11px in rem\n fontWeight: 500, // AstroUXDS medium for labels\n color: color,\n marginBottom: \"4px\",\n textTransform: \"uppercase\",\n letterSpacing: \"0.5px\",\n }}\n >\n {statusLabel}\n </div>\n {/* Status message */}\n <div\n style={{\n fontSize: \"0.75rem\", // 12px in rem\n color: \"rgba(255,255,255,0.9)\",\n lineHeight: 1.4,\n }}\n >\n {tooltipText}\n </div>\n {/* Arrow */}\n <div\n style={{\n position: \"absolute\",\n bottom: \"-6px\",\n left: \"50%\",\n transform: \"translateX(-50%) rotate(45deg)\",\n width: \"10px\",\n height: \"10px\",\n backgroundColor: \"rgba(10, 15, 25, 0.95)\",\n borderRight: `1px solid ${color}`,\n borderBottom: `1px solid ${color}`,\n }}\n />\n </div>\n )}\n </div>\n );\n}\n\n/**\n * Renders AstroUXDS-compliant status symbol with proper shape\n * Shapes: Critical=triangle, Serious=diamond, Caution=square, Normal=circle, Standby=ring, Off=small-circle\n */\nfunction StatusSymbol({\n status,\n size = 8,\n message,\n showTooltip = false,\n}: {\n status: StatusLevel;\n size?: number;\n message?: string;\n showTooltip?: boolean;\n}): React.ReactElement {\n const [isHovered, setIsHovered] = React.useState(false);\n const { tokens } = useTheme();\n const color = tokens.colors.status[status];\n const defaultMessage = STATUS_DESCRIPTIONS[status];\n const tooltipText = message || defaultMessage;\n const statusLabel = status.charAt(0).toUpperCase() + status.slice(1);\n\n // Shape rendering based on Astro UX dual-coded status levels\n const renderShape = () => {\n const h = size / 2;\n const glow = `drop-shadow(0 0 3px ${color})`;\n switch (status) {\n case \"critical\":\n // Triangle pointing down\n return (\n <svg\n width={size}\n height={size}\n viewBox={`0 0 ${size} ${size}`}\n style={{ filter: glow }}\n >\n <polygon points={`${h},${size} 0,0 ${size},0`} fill={color} />\n </svg>\n );\n case \"serious\":\n // Diamond (rotated square)\n return (\n <svg\n width={size}\n height={size}\n viewBox={`0 0 ${size} ${size}`}\n style={{ filter: glow }}\n >\n <polygon\n points={`${h},0 ${size},${h} ${h},${size} 0,${h}`}\n fill={color}\n />\n </svg>\n );\n case \"caution\":\n // Filled square\n return (\n <svg\n width={size}\n height={size}\n viewBox={`0 0 ${size} ${size}`}\n style={{ filter: glow }}\n >\n <rect width={size} height={size} fill={color} />\n </svg>\n );\n case \"normal\":\n // Filled circle\n return (\n <svg\n width={size}\n height={size}\n viewBox={`0 0 ${size} ${size}`}\n style={{ filter: glow }}\n >\n <circle cx={h} cy={h} r={h} fill={color} />\n </svg>\n );\n case \"standby\":\n // Ring (donut) — per official Astro UXDS\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 12 12\"\n style={{ filter: 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 default:\n // Small filled circle — per official Astro UXDS\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 12 12\"\n style={{ filter: glow }}\n >\n <circle cx=\"6\" cy=\"6\" r=\"3\" fill={color} />\n </svg>\n );\n }\n };\n\n return (\n <div\n style={{\n position: \"relative\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: showTooltip ? \"help\" : \"default\",\n }}\n onMouseEnter={() => showTooltip && setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n {renderShape()}\n {/* Custom tooltip popup */}\n {showTooltip && isHovered && (\n <div\n style={{\n position: \"absolute\",\n bottom: \"calc(100% + 8px)\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n padding: \"8px 12px\",\n backgroundColor: \"rgba(10, 15, 25, 0.95)\",\n border: `1px solid ${color}`,\n borderRadius: \"4px\",\n boxShadow: `0 0 12px ${color}40, 0 4px 12px rgba(0,0,0,0.4)`,\n zIndex: 1000,\n whiteSpace: \"nowrap\",\n pointerEvents: \"none\",\n minWidth: \"150px\",\n }}\n >\n {/* Status label */}\n <div\n style={{\n fontSize: \"0.6875rem\", // 11px in rem\n fontWeight: 500, // AstroUXDS medium for labels\n color: color,\n marginBottom: \"4px\",\n textTransform: \"uppercase\",\n letterSpacing: \"0.5px\",\n }}\n >\n {statusLabel}\n </div>\n {/* Status message */}\n <div\n style={{\n fontSize: \"0.75rem\", // 12px in rem\n color: \"rgba(255,255,255,0.9)\",\n lineHeight: 1.4,\n }}\n >\n {tooltipText}\n </div>\n {/* Arrow */}\n <div\n style={{\n position: \"absolute\",\n bottom: \"-6px\",\n left: \"50%\",\n transform: \"translateX(-50%) rotate(45deg)\",\n width: \"10px\",\n height: \"10px\",\n backgroundColor: \"rgba(10, 15, 25, 0.95)\",\n borderRight: `1px solid ${color}`,\n borderBottom: `1px solid ${color}`,\n }}\n />\n </div>\n )}\n </div>\n );\n}\n\n/**\n * StatusBadge - Compact status indicator for accent lines\n * Shows colored badge with status shape at end of accent line\n */\nfunction StatusBadge({\n status,\n tokens: _tokens,\n size = \"bold\",\n}: {\n status: StatusLevel;\n tokens: any;\n size?: \"bold\" | \"minimal\";\n}): React.ReactElement {\n const { tokens } = useTheme();\n const color = tokens.colors.status[status];\n const label = status.charAt(0).toUpperCase() + status.slice(1);\n const isBold = size === \"bold\";\n\n return (\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: isBold ? \"6px\" : \"4px\",\n padding: isBold ? \"3px 10px\" : \"2px 8px\",\n borderRadius: \"12px\",\n fontSize: isBold ? \"11px\" : \"10px\",\n fontWeight: 500,\n backgroundColor: `${color}20`,\n color: color,\n flexShrink: 0,\n textTransform: \"uppercase\",\n letterSpacing: \"0.3px\",\n }}\n >\n {/* Status shape */}\n <StatusSymbol status={status} size={isBold ? 6 : 5} />\n {label}\n </span>\n );\n}\n\nexport const Container = memo(function Container({\n variant = \"default\",\n padding = \"md\",\n title,\n subtitle,\n status,\n actions,\n fullHeight = false,\n clipContent = true,\n loading = false,\n children,\n className = \"\",\n style,\n onClick,\n disableAutoGlass = false,\n icon,\n iconStatus,\n statusMessage,\n iconColor,\n accentColor,\n}: ContainerProps): React.ReactElement {\n const { tokens, theme } = useTheme();\n const { isMobile } = useBreakpoint();\n\n // Theme detection\n const _isTransparentTheme =\n theme === \"transparent\" ||\n theme === \"transparent-bold\" ||\n theme === \"transparent-minimal\";\n const isBoldVariant = theme === \"transparent-bold\";\n const isMinimalVariant = theme === \"transparent-minimal\";\n\n // Glass mode with accent styling ONLY for bold/minimal themes\n // Normal \"transparent\" (Glass) theme uses simpler styling without accent borders\n const useGlassMode =\n (isBoldVariant || isMinimalVariant) &&\n !disableAutoGlass &&\n !variant.startsWith(\"glass\");\n\n // Simple glass mode for normal \"transparent\" theme (no accent borders)\n const useSimpleGlass =\n theme === \"transparent\" &&\n !disableAutoGlass &&\n !variant.startsWith(\"glass\");\n\n // Default accent color: bold/minimal themes use theme accent (Zendir purple)\n const defaultAccentColor = tokens.colors.accent.primary;\n const glassAccentColor = accentColor || defaultAccentColor;\n const glassAccentMuted = `${glassAccentColor}66`;\n const glassGradient = `linear-gradient(135deg, ${glassAccentColor}10 0%, ${glassAccentColor}03 100%)`;\n\n // Determine icon color: custom > status > accent\n const resolvedIconColor =\n iconColor ||\n (iconStatus ? tokens.colors.status[iconStatus] : glassAccentColor);\n const _iconColorMuted = `${resolvedIconColor}66`;\n\n const paddingConfig = {\n none: \"0\",\n sm: isMobile ? tokens.spacing.xs : tokens.spacing.sm,\n md: isMobile ? tokens.spacing.sm : tokens.spacing.md,\n lg: isMobile ? tokens.spacing.md : tokens.spacing.lg,\n };\n\n const headingConfig = tokens.layout?.card?.heading ?? {\n iconSize: 20,\n iconSizeCompact: 16,\n titleFontSize: \"1.125rem\",\n titleFontSizeChart: \"0.875rem\",\n titleFontWeight: 500,\n gap: 8,\n };\n\n const variantStyles: Record<ContainerVariant, React.CSSProperties> = {\n default: {\n backgroundColor: tokens.colors.background.surface,\n border: `1px solid ${tokens.colors.border.muted}`,\n boxShadow: \"none\",\n },\n elevated: {\n backgroundColor: tokens.colors.background.surface,\n border: \"none\",\n boxShadow: tokens.shadows.md,\n },\n outlined: {\n backgroundColor: \"transparent\",\n border: `1px solid ${tokens.colors.border.muted}`,\n boxShadow: \"none\",\n },\n ghost: {\n backgroundColor: \"transparent\",\n border: \"none\",\n boxShadow: \"none\",\n },\n // Glass variants - transparent with blur\n glass: {\n backgroundColor: \"rgba(15, 20, 35, 0.85)\",\n backdropFilter: \"blur(12px)\",\n WebkitBackdropFilter: \"blur(12px)\",\n border: \"1px solid rgba(0, 212, 255, 0.25)\",\n boxShadow: \"none\",\n } as React.CSSProperties,\n \"glass-dark\": {\n backgroundColor: \"rgba(0, 0, 0, 0.7)\",\n backdropFilter: \"blur(16px)\",\n WebkitBackdropFilter: \"blur(16px)\",\n border: \"1px solid rgba(100, 130, 160, 0.2)\",\n boxShadow: \"none\",\n } as React.CSSProperties,\n \"glass-light\": {\n backgroundColor: \"rgba(255, 255, 255, 0.15)\",\n backdropFilter: \"blur(12px)\",\n WebkitBackdropFilter: \"blur(12px)\",\n border: \"1px solid rgba(255, 255, 255, 0.25)\",\n boxShadow: \"none\",\n } as React.CSSProperties,\n };\n\n // Glow color for hover effect (like GlassCard)\n const glowColor = accentColor ? `${accentColor}66` : \"rgba(0, 212, 255, 0.4)\";\n\n // Glass mode overrides for BOLD/MINIMAL themes (Glassmorphic Panels with accent borders)\n const glassOverrides: React.CSSProperties = useGlassMode\n ? ({\n backgroundColor: \"rgba(10, 15, 25, 0.35)\",\n backdropFilter: \"blur(12px)\",\n WebkitBackdropFilter: \"blur(12px)\",\n border: `1px solid ${glassAccentMuted}`,\n borderTop: isBoldVariant\n ? `2px solid ${glassAccentColor}`\n : `1px solid ${glassAccentColor}`,\n transition: \"all 0.3s ease-out, box-shadow 0.3s ease-out\",\n } as React.CSSProperties)\n : {};\n\n // Simple glass overrides for normal \"transparent\" (Glass) theme — match top cards (ISS): transparent + blur\n const simpleGlassOverrides: React.CSSProperties = useSimpleGlass\n ? ({\n backgroundColor: \"transparent\",\n backdropFilter: \"blur(12px)\",\n WebkitBackdropFilter: \"blur(12px)\",\n border: `1px solid ${tokens.colors.border.muted}`,\n transition: \"all 0.3s ease-out\",\n } as React.CSSProperties)\n : {};\n\n // Hover handlers for glow effect (like GlassCard)\n const handleMouseEnter = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n if (useGlassMode) {\n e.currentTarget.style.boxShadow = `0 0 30px ${glowColor}, 0 4px 20px rgba(0,0,0,0.3)`;\n }\n },\n [useGlassMode, glowColor],\n );\n\n const handleMouseLeave = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n if (useGlassMode) {\n e.currentTarget.style.boxShadow = \"none\";\n }\n },\n [useGlassMode],\n );\n\n const statusColor = status ? tokens.colors.status[status] : undefined;\n const isInteractive = !!onClick;\n\n return (\n <div\n className={classNames(\n \"zendir-container\",\n `zendir-container--${variant}`,\n useGlassMode && \"zendir-container--auto-glass\",\n className,\n )}\n onClick={onClick}\n role={isInteractive ? \"button\" : undefined}\n tabIndex={isInteractive ? 0 : undefined}\n onKeyDown={\n onClick\n ? (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n }\n : undefined\n }\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n style={{\n borderRadius: tokens.borderRadius.lg,\n overflow: \"hidden\",\n position: \"relative\",\n height: fullHeight ? \"100%\" : \"auto\",\n display: \"flex\",\n flexDirection: \"column\",\n cursor: isInteractive ? \"pointer\" : \"default\",\n transition: \"all 0.3s ease-out\",\n borderLeft: statusColor ? `4px solid ${statusColor}` : undefined,\n ...variantStyles[variant],\n ...simpleGlassOverrides, // Normal Glass theme\n ...glassOverrides, // Bold/Minimal themes (overrides simpleGlass if both)\n ...style,\n }}\n >\n {/* Glass gradient overlay for bold/minimal transparent themes */}\n {useGlassMode && (\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n background: glassGradient,\n pointerEvents: \"none\",\n zIndex: 0,\n }}\n />\n )}\n\n {/* Loading overlay */}\n {loading && (\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n backgroundColor: addAlpha(tokens.colors.background.surface, 0.5),\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n zIndex: 10,\n }}\n >\n <svg\n width=\"32\"\n height=\"32\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{ animation: \"spin 1s linear infinite\" }}\n >\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke={tokens.colors.accent.primary}\n strokeWidth=\"3\"\n strokeDasharray=\"31.4 31.4\"\n strokeDashoffset=\"10\"\n />\n </svg>\n <style>\n {`@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`}\n </style>\n </div>\n )}\n\n {/* Header - Glass mode BOLD variant (matching GlassCard style exactly) */}\n {(title || actions) && useGlassMode && isBoldVariant && (\n <div\n style={{\n position: \"relative\",\n zIndex: 1,\n }}\n >\n {/* Title row */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n padding: `16px ${paddingConfig[padding]} 0`,\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: headingConfig.gap,\n }}\n >\n {/* Icon with optional status symbol - full area triggers tooltip */}\n {icon && (\n <IconWithStatusTooltip\n icon={icon}\n iconColor={resolvedIconColor}\n iconStatus={iconStatus}\n statusMessage={statusMessage}\n iconSize={headingConfig.iconSize}\n />\n )}\n <h3\n style={{\n margin: 0,\n fontSize: headingConfig.titleFontSize,\n fontWeight: headingConfig.titleFontWeight,\n color: glassAccentColor,\n letterSpacing: \"0.5px\",\n textShadow: `0 0 20px ${glassAccentMuted}`,\n }}\n >\n {title}\n </h3>\n </div>\n {actions && (\n <div style={{ display: \"flex\", gap: tokens.spacing.xs }}>\n {actions}\n </div>\n )}\n </div>\n\n {subtitle && (\n <p\n style={{\n margin: 0,\n padding: `${tokens.spacing.xs} ${paddingConfig[padding]} 0`,\n fontSize: tokens.typography.fontSize.sm,\n color: tokens.colors.text.secondary,\n }}\n >\n {subtitle}\n </p>\n )}\n\n {/* Accent line with optional status badge */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: tokens.spacing.sm,\n padding: `12px ${paddingConfig[padding]} 0`,\n marginBottom: tokens.spacing.sm,\n }}\n >\n {/* Main accent line with gradient */}\n <div\n style={{\n flex: 1,\n height: \"2px\",\n background: `linear-gradient(90deg, ${glassAccentColor} 0%, ${glassAccentMuted} 70%, ${glassAccentMuted}20 100%)`,\n boxShadow: `0 0 8px ${glassAccentMuted}`,\n }}\n />\n {/* Status badge at the end if status is set */}\n {iconStatus && iconStatus !== \"off\" && (\n <StatusBadge status={iconStatus} tokens={tokens} size=\"bold\" />\n )}\n </div>\n </div>\n )}\n\n {/* Header - Glass mode MINIMAL variant (inline thin line) */}\n {(title || actions) && useGlassMode && !isBoldVariant && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n padding: `${tokens.spacing.sm} ${paddingConfig[padding]} 0`,\n marginBottom: tokens.spacing.sm,\n position: \"relative\",\n zIndex: 1,\n }}\n >\n {/* Icon with optional status symbol - full area triggers tooltip */}\n {icon && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n marginRight: tokens.spacing.sm,\n }}\n >\n <IconWithStatusTooltip\n icon={icon}\n iconColor={resolvedIconColor}\n iconStatus={iconStatus}\n statusMessage={statusMessage}\n iconSize={headingConfig.iconSizeCompact}\n />\n </div>\n )}\n\n {/* Title — card heading system */}\n {title && (\n <h3\n style={{\n margin: 0,\n fontSize: headingConfig.titleFontSize,\n fontWeight: headingConfig.titleFontWeight,\n color: glassAccentColor,\n textShadow: `0 0 16px ${glassAccentMuted}`,\n letterSpacing: \"0.02em\",\n whiteSpace: \"nowrap\",\n marginRight: \"12px\",\n }}\n >\n {title}\n </h3>\n )}\n\n {/* Accent line - inline after title with optional status badge */}\n <div\n style={{\n flex: 1,\n display: \"flex\",\n alignItems: \"center\",\n gap: tokens.spacing.sm,\n minWidth: 40,\n }}\n >\n {/* Main gradient line */}\n <div\n style={{\n flex: 1,\n height: \"1px\",\n background: `linear-gradient(90deg, ${glassAccentColor} 0%, ${glassAccentMuted} 70%, ${glassAccentMuted}20 100%)`,\n }}\n />\n {/* Status badge at the end if status is set */}\n {iconStatus && iconStatus !== \"off\" && (\n <StatusBadge status={iconStatus} tokens={tokens} size=\"minimal\" />\n )}\n </div>\n\n {actions && (\n <div\n style={{\n display: \"flex\",\n gap: tokens.spacing.xs,\n flexShrink: 0,\n marginLeft: \"12px\",\n }}\n >\n {actions}\n </div>\n )}\n </div>\n )}\n\n {/* Subtitle for glass mode MINIMAL - separate row */}\n {subtitle && useGlassMode && !isBoldVariant && (\n <p\n style={{\n margin: 0,\n padding: `0 ${paddingConfig[padding]}`,\n marginBottom: tokens.spacing.sm,\n fontSize: tokens.typography.fontSize.sm,\n color: tokens.colors.text.secondary,\n position: \"relative\",\n zIndex: 1,\n }}\n >\n {subtitle}\n </p>\n )}\n\n {/* Header - Regular mode (non-glass) - Uses shared CardHeader for consistency */}\n {(title || actions) && !useGlassMode && (\n <div\n style={{\n padding: `${paddingConfig[padding]} ${paddingConfig[padding]} 0`,\n position: \"relative\",\n zIndex: 1,\n }}\n >\n <CardHeader\n icon={icon || (iconStatus ? \"mission\" : \"\")}\n title={typeof title === \"string\" ? title : String(title || \"\")}\n subtitle={typeof subtitle === \"string\" ? subtitle : undefined}\n status={iconStatus || status}\n iconColor={iconColor}\n iconSize={headingConfig.iconSize}\n hideStatusIndicator={!icon && !iconStatus && !status}\n rightSlot={actions}\n style={{ marginBottom: tokens.spacing.sm }}\n />\n {/* Render non-string subtitles (React elements) below the CardHeader */}\n {subtitle && typeof subtitle !== \"string\" && (\n <div\n style={{\n fontSize: tokens.typography.fontSize.sm,\n color: tokens.colors.text.secondary,\n marginTop: -parseInt(tokens.spacing.xs || \"4\", 10) || -4,\n marginBottom: parseInt(tokens.spacing.sm || \"8\", 10) || 8,\n }}\n >\n {subtitle}\n </div>\n )}\n </div>\n )}\n\n {/* Content */}\n <div\n style={{\n flex: 1,\n minHeight: fullHeight ? 0 : undefined,\n overflow: fullHeight && clipContent ? \"hidden\" : undefined,\n // When fullHeight, become a flex column so any child using flex:1 or height:100%\n // gets a properly bounded height and scroll containers can work.\n display: fullHeight ? \"flex\" : undefined,\n flexDirection: fullHeight ? \"column\" : undefined,\n padding: fullHeight\n ? `${tokens.spacing.xs} 0 0 0`\n : title\n ? `${tokens.spacing.xs} ${paddingConfig[padding]} ${paddingConfig[padding]}`\n : paddingConfig[padding],\n position: \"relative\",\n zIndex: 1,\n }}\n >\n {children}\n </div>\n </div>\n );\n});\n\nexport default Container;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Container.js","names":[],"sources":["../../../../src/react/core/display/Container.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - Container/Card Component\r\n *\r\n * Container/Card wrapper following Astro UX Design System.\r\n * Automatically switches to glassmorphic styling when transparent themes are active.\r\n *\r\n * Transparent themes (transparent, transparent-bold):\r\n * - Glassmorphic panels with blur effect\r\n * - Colored top border accent\r\n * - Hover glow effect (like GlassCard)\r\n * - transparent-bold has 2px top border\r\n *\r\n * @example\r\n * ```tsx\r\n * <Container>Simple container</Container>\r\n * <Container title=\"Spacecraft Status\" status=\"normal\">Content</Container>\r\n * <Container title=\"Power System\" icon=\"solar\" iconStatus=\"normal\">With status</Container>\r\n * <Container title=\"Custom Color\" icon=\"thermal\" iconColor=\"#FF6B6B\">Custom color</Container>\r\n * ```\r\n */\r\n\r\nimport React, { memo, useCallback } from \"react\";\r\nimport { useTheme } from \"../../theme\";\r\nimport { classNames, addAlpha, type StatusLevel } from \"../../utils\";\r\nimport { AstroIcon, type AstroIconName } from \"./AstroIcon\";\r\nimport { HeaderIconWithStatus } from \"./HeaderIconWithStatus\";\r\nimport { CardHeader } from \"./CardHeader\";\r\nimport { useBreakpoint } from \"../layout/useBreakpoint\";\r\n\r\nexport type ContainerVariant =\r\n | \"default\"\r\n | \"elevated\"\r\n | \"outlined\"\r\n | \"ghost\"\r\n | \"glass\"\r\n | \"glass-dark\"\r\n | \"glass-light\";\r\nexport type ContainerPadding = \"none\" | \"sm\" | \"md\" | \"lg\";\r\n\r\n/** Status descriptions for tooltips (default synonyms from AstroUXDS) */\r\nconst STATUS_DESCRIPTIONS: Record<StatusLevel, string> = {\r\n off: \"Off, unavailable, disabled\",\r\n standby: \"Standby, available, enabled\",\r\n normal: \"Normal, ok, satisfactory\",\r\n caution: \"Caution, warning, unstable\",\r\n serious: \"Serious, error, needs attention\",\r\n critical: \"Critical, emergency, urgent\",\r\n};\r\n\r\n/** Status symbol shapes following AstroUXDS guidelines */\r\ntype _StatusShape =\r\n | \"circle\"\r\n | \"square\"\r\n | \"diamond\"\r\n | \"triangle\"\r\n | \"circle-hollow\";\r\n\r\nexport interface ContainerProps {\r\n /** Visual variant */\r\n variant?: ContainerVariant;\r\n /** Padding size */\r\n padding?: ContainerPadding;\r\n /** Container title */\r\n title?: React.ReactNode;\r\n /** Subtitle or description */\r\n subtitle?: React.ReactNode;\r\n /** Status indicator (affects left border in non-glass mode) */\r\n status?: StatusLevel;\r\n /** Header actions (buttons, etc.) */\r\n actions?: React.ReactNode;\r\n /** Full height */\r\n fullHeight?: boolean;\r\n /**\r\n * Clip overflowing content area when fullHeight is enabled.\r\n * Keep false for form cards so wrapped rows can expand naturally.\r\n */\r\n clipContent?: boolean;\r\n /** Loading state */\r\n loading?: boolean;\r\n /** Children */\r\n children: React.ReactNode;\r\n /** Custom className */\r\n className?: string;\r\n /** Custom style */\r\n style?: React.CSSProperties;\r\n /** Click handler */\r\n onClick?: () => void;\r\n /** Disable auto-glass effect in transparent theme */\r\n disableAutoGlass?: boolean;\r\n /** Icon to display in header (Astro icon name) */\r\n icon?: AstroIconName;\r\n /** Icon status - shows status symbol and colors icon accordingly */\r\n iconStatus?: StatusLevel;\r\n /** Custom status message shown in tooltip (overrides default description) */\r\n statusMessage?: string;\r\n /** Custom icon color (overrides iconStatus and theme color) */\r\n iconColor?: string;\r\n /** Custom accent color for glass mode (title, line, etc.) */\r\n accentColor?: string;\r\n}\r\n\r\n/**\r\n * Icon wrapper with status tooltip - triggers tooltip on hover over entire icon area\r\n */\r\nfunction IconWithStatusTooltip({\r\n icon,\r\n iconColor,\r\n iconStatus,\r\n statusMessage,\r\n iconSize = 20,\r\n}: {\r\n icon: string;\r\n iconColor: string;\r\n iconStatus?: StatusLevel;\r\n statusMessage?: string;\r\n iconSize?: number;\r\n}): React.ReactElement {\r\n const [isHovered, setIsHovered] = React.useState(false);\r\n const { tokens } = useTheme();\r\n const color = iconStatus ? tokens.colors.status[iconStatus] : iconColor;\r\n const defaultMessage = iconStatus ? STATUS_DESCRIPTIONS[iconStatus] : \"\";\r\n const tooltipText = statusMessage || defaultMessage;\r\n const statusLabel = iconStatus\r\n ? iconStatus.charAt(0).toUpperCase() + iconStatus.slice(1)\r\n : \"\";\r\n\r\n return (\r\n <div\r\n style={{\r\n position: \"relative\",\r\n display: \"inline-flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n flexShrink: 0,\r\n cursor: iconStatus ? \"help\" : \"default\",\r\n }}\r\n onMouseEnter={() => iconStatus && setIsHovered(true)}\r\n onMouseLeave={() => setIsHovered(false)}\r\n >\r\n {/* Use HeaderIconWithStatus for consistent sizing with SpacecraftCard */}\r\n {iconStatus ? (\r\n <HeaderIconWithStatus\r\n icon={icon as AstroIconName}\r\n status={iconStatus}\r\n size={iconSize}\r\n statusColor={iconColor}\r\n />\r\n ) : (\r\n <AstroIcon name={icon} size={iconSize} color={iconColor} />\r\n )}\r\n {/* Tooltip popup - triggers on whole icon area hover */}\r\n {iconStatus && isHovered && (\r\n <div\r\n style={{\r\n position: \"absolute\",\r\n bottom: \"calc(100% + 12px)\",\r\n left: \"50%\",\r\n transform: \"translateX(-50%)\",\r\n padding: \"8px 12px\",\r\n backgroundColor: \"rgba(10, 15, 25, 0.95)\",\r\n border: `1px solid ${color}`,\r\n borderRadius: \"4px\",\r\n boxShadow: `0 0 12px ${color}40, 0 4px 12px rgba(0,0,0,0.4)`,\r\n zIndex: 1000,\r\n whiteSpace: \"nowrap\",\r\n pointerEvents: \"none\",\r\n minWidth: \"150px\",\r\n }}\r\n >\r\n {/* Status label */}\r\n <div\r\n style={{\r\n fontSize: \"0.6875rem\", // 11px in rem\r\n fontWeight: 500, // AstroUXDS medium for labels\r\n color: color,\r\n marginBottom: \"4px\",\r\n textTransform: \"uppercase\",\r\n letterSpacing: \"0.5px\",\r\n }}\r\n >\r\n {statusLabel}\r\n </div>\r\n {/* Status message */}\r\n <div\r\n style={{\r\n fontSize: \"0.75rem\", // 12px in rem\r\n color: \"rgba(255,255,255,0.9)\",\r\n lineHeight: 1.4,\r\n }}\r\n >\r\n {tooltipText}\r\n </div>\r\n {/* Arrow */}\r\n <div\r\n style={{\r\n position: \"absolute\",\r\n bottom: \"-6px\",\r\n left: \"50%\",\r\n transform: \"translateX(-50%) rotate(45deg)\",\r\n width: \"10px\",\r\n height: \"10px\",\r\n backgroundColor: \"rgba(10, 15, 25, 0.95)\",\r\n borderRight: `1px solid ${color}`,\r\n borderBottom: `1px solid ${color}`,\r\n }}\r\n />\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n/**\r\n * Renders AstroUXDS-compliant status symbol with proper shape\r\n * Shapes: Critical=triangle, Serious=diamond, Caution=square, Normal=circle, Standby=ring, Off=small-circle\r\n */\r\nfunction StatusSymbol({\r\n status,\r\n size = 8,\r\n message,\r\n showTooltip = false,\r\n}: {\r\n status: StatusLevel;\r\n size?: number;\r\n message?: string;\r\n showTooltip?: boolean;\r\n}): React.ReactElement {\r\n const [isHovered, setIsHovered] = React.useState(false);\r\n const { tokens } = useTheme();\r\n const color = tokens.colors.status[status];\r\n const defaultMessage = STATUS_DESCRIPTIONS[status];\r\n const tooltipText = message || defaultMessage;\r\n const statusLabel = status.charAt(0).toUpperCase() + status.slice(1);\r\n\r\n // Shape rendering based on Astro UX dual-coded status levels\r\n const renderShape = () => {\r\n const h = size / 2;\r\n const glow = `drop-shadow(0 0 3px ${color})`;\r\n switch (status) {\r\n case \"critical\":\r\n // Triangle pointing down\r\n return (\r\n <svg\r\n width={size}\r\n height={size}\r\n viewBox={`0 0 ${size} ${size}`}\r\n style={{ filter: glow }}\r\n >\r\n <polygon points={`${h},${size} 0,0 ${size},0`} fill={color} />\r\n </svg>\r\n );\r\n case \"serious\":\r\n // Diamond (rotated square)\r\n return (\r\n <svg\r\n width={size}\r\n height={size}\r\n viewBox={`0 0 ${size} ${size}`}\r\n style={{ filter: glow }}\r\n >\r\n <polygon\r\n points={`${h},0 ${size},${h} ${h},${size} 0,${h}`}\r\n fill={color}\r\n />\r\n </svg>\r\n );\r\n case \"caution\":\r\n // Filled square\r\n return (\r\n <svg\r\n width={size}\r\n height={size}\r\n viewBox={`0 0 ${size} ${size}`}\r\n style={{ filter: glow }}\r\n >\r\n <rect width={size} height={size} fill={color} />\r\n </svg>\r\n );\r\n case \"normal\":\r\n // Filled circle\r\n return (\r\n <svg\r\n width={size}\r\n height={size}\r\n viewBox={`0 0 ${size} ${size}`}\r\n style={{ filter: glow }}\r\n >\r\n <circle cx={h} cy={h} r={h} fill={color} />\r\n </svg>\r\n );\r\n case \"standby\":\r\n // Ring (donut) — per official Astro UXDS\r\n return (\r\n <svg\r\n width={size}\r\n height={size}\r\n viewBox=\"0 0 12 12\"\r\n style={{ filter: 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 default:\r\n // Small filled circle — per official Astro UXDS\r\n return (\r\n <svg\r\n width={size}\r\n height={size}\r\n viewBox=\"0 0 12 12\"\r\n style={{ filter: glow }}\r\n >\r\n <circle cx=\"6\" cy=\"6\" r=\"3\" fill={color} />\r\n </svg>\r\n );\r\n }\r\n };\r\n\r\n return (\r\n <div\r\n style={{\r\n position: \"relative\",\r\n display: \"inline-flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n cursor: showTooltip ? \"help\" : \"default\",\r\n }}\r\n onMouseEnter={() => showTooltip && setIsHovered(true)}\r\n onMouseLeave={() => setIsHovered(false)}\r\n >\r\n {renderShape()}\r\n {/* Custom tooltip popup */}\r\n {showTooltip && isHovered && (\r\n <div\r\n style={{\r\n position: \"absolute\",\r\n bottom: \"calc(100% + 8px)\",\r\n left: \"50%\",\r\n transform: \"translateX(-50%)\",\r\n padding: \"8px 12px\",\r\n backgroundColor: \"rgba(10, 15, 25, 0.95)\",\r\n border: `1px solid ${color}`,\r\n borderRadius: \"4px\",\r\n boxShadow: `0 0 12px ${color}40, 0 4px 12px rgba(0,0,0,0.4)`,\r\n zIndex: 1000,\r\n whiteSpace: \"nowrap\",\r\n pointerEvents: \"none\",\r\n minWidth: \"150px\",\r\n }}\r\n >\r\n {/* Status label */}\r\n <div\r\n style={{\r\n fontSize: \"0.6875rem\", // 11px in rem\r\n fontWeight: 500, // AstroUXDS medium for labels\r\n color: color,\r\n marginBottom: \"4px\",\r\n textTransform: \"uppercase\",\r\n letterSpacing: \"0.5px\",\r\n }}\r\n >\r\n {statusLabel}\r\n </div>\r\n {/* Status message */}\r\n <div\r\n style={{\r\n fontSize: \"0.75rem\", // 12px in rem\r\n color: \"rgba(255,255,255,0.9)\",\r\n lineHeight: 1.4,\r\n }}\r\n >\r\n {tooltipText}\r\n </div>\r\n {/* Arrow */}\r\n <div\r\n style={{\r\n position: \"absolute\",\r\n bottom: \"-6px\",\r\n left: \"50%\",\r\n transform: \"translateX(-50%) rotate(45deg)\",\r\n width: \"10px\",\r\n height: \"10px\",\r\n backgroundColor: \"rgba(10, 15, 25, 0.95)\",\r\n borderRight: `1px solid ${color}`,\r\n borderBottom: `1px solid ${color}`,\r\n }}\r\n />\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n/**\r\n * StatusBadge - Compact status indicator for accent lines\r\n * Shows colored badge with status shape at end of accent line\r\n */\r\nfunction StatusBadge({\r\n status,\r\n tokens: _tokens,\r\n size = \"bold\",\r\n}: {\r\n status: StatusLevel;\r\n tokens: any;\r\n size?: \"bold\" | \"minimal\";\r\n}): React.ReactElement {\r\n const { tokens } = useTheme();\r\n const color = tokens.colors.status[status];\r\n const label = status.charAt(0).toUpperCase() + status.slice(1);\r\n const isBold = size === \"bold\";\r\n\r\n return (\r\n <span\r\n style={{\r\n display: \"inline-flex\",\r\n alignItems: \"center\",\r\n gap: isBold ? \"6px\" : \"4px\",\r\n padding: isBold ? \"3px 10px\" : \"2px 8px\",\r\n borderRadius: \"12px\",\r\n fontSize: isBold ? \"11px\" : \"10px\",\r\n fontWeight: 500,\r\n backgroundColor: `${color}20`,\r\n color: color,\r\n flexShrink: 0,\r\n textTransform: \"uppercase\",\r\n letterSpacing: \"0.3px\",\r\n }}\r\n >\r\n {/* Status shape */}\r\n <StatusSymbol status={status} size={isBold ? 6 : 5} />\r\n {label}\r\n </span>\r\n );\r\n}\r\n\r\nexport const Container = memo(function Container({\r\n variant = \"default\",\r\n padding = \"md\",\r\n title,\r\n subtitle,\r\n status,\r\n actions,\r\n fullHeight = false,\r\n clipContent = true,\r\n loading = false,\r\n children,\r\n className = \"\",\r\n style,\r\n onClick,\r\n disableAutoGlass = false,\r\n icon,\r\n iconStatus,\r\n statusMessage,\r\n iconColor,\r\n accentColor,\r\n}: ContainerProps): React.ReactElement {\r\n const { tokens, theme } = useTheme();\r\n const { isMobile } = useBreakpoint();\r\n\r\n // Theme detection\r\n const _isTransparentTheme =\r\n theme === \"transparent\" ||\r\n theme === \"transparent-bold\" ||\r\n theme === \"transparent-minimal\";\r\n const isBoldVariant = theme === \"transparent-bold\";\r\n const isMinimalVariant = theme === \"transparent-minimal\";\r\n\r\n // Glass mode with accent styling ONLY for bold/minimal themes\r\n // Normal \"transparent\" (Glass) theme uses simpler styling without accent borders\r\n const useGlassMode =\r\n (isBoldVariant || isMinimalVariant) &&\r\n !disableAutoGlass &&\r\n !variant.startsWith(\"glass\");\r\n\r\n // Simple glass mode for normal \"transparent\" theme (no accent borders)\r\n const useSimpleGlass =\r\n theme === \"transparent\" &&\r\n !disableAutoGlass &&\r\n !variant.startsWith(\"glass\");\r\n\r\n // Default accent color: bold/minimal themes use theme accent (Zendir purple)\r\n const defaultAccentColor = tokens.colors.accent.primary;\r\n const glassAccentColor = accentColor || defaultAccentColor;\r\n const glassAccentMuted = `${glassAccentColor}66`;\r\n const glassGradient = `linear-gradient(135deg, ${glassAccentColor}10 0%, ${glassAccentColor}03 100%)`;\r\n\r\n // Determine icon color: custom > status > accent\r\n const resolvedIconColor =\r\n iconColor ||\r\n (iconStatus ? tokens.colors.status[iconStatus] : glassAccentColor);\r\n const _iconColorMuted = `${resolvedIconColor}66`;\r\n\r\n const paddingConfig = {\r\n none: \"0\",\r\n sm: isMobile ? tokens.spacing.xs : tokens.spacing.sm,\r\n md: isMobile ? tokens.spacing.sm : tokens.spacing.md,\r\n lg: isMobile ? tokens.spacing.md : tokens.spacing.lg,\r\n };\r\n\r\n const headingConfig = tokens.layout?.card?.heading ?? {\r\n iconSize: 20,\r\n iconSizeCompact: 16,\r\n titleFontSize: \"1.125rem\",\r\n titleFontSizeChart: \"0.875rem\",\r\n titleFontWeight: 500,\r\n gap: 8,\r\n };\r\n\r\n const variantStyles: Record<ContainerVariant, React.CSSProperties> = {\r\n default: {\r\n backgroundColor: tokens.colors.background.surface,\r\n border: `1px solid ${tokens.colors.border.muted}`,\r\n boxShadow: \"none\",\r\n },\r\n elevated: {\r\n backgroundColor: tokens.colors.background.surface,\r\n border: \"none\",\r\n boxShadow: tokens.shadows.md,\r\n },\r\n outlined: {\r\n backgroundColor: \"transparent\",\r\n border: `1px solid ${tokens.colors.border.muted}`,\r\n boxShadow: \"none\",\r\n },\r\n ghost: {\r\n backgroundColor: \"transparent\",\r\n border: \"none\",\r\n boxShadow: \"none\",\r\n },\r\n // Glass variants - transparent with blur\r\n glass: {\r\n backgroundColor: \"rgba(15, 20, 35, 0.85)\",\r\n backdropFilter: \"blur(12px)\",\r\n WebkitBackdropFilter: \"blur(12px)\",\r\n border: \"1px solid rgba(0, 212, 255, 0.25)\",\r\n boxShadow: \"none\",\r\n } as React.CSSProperties,\r\n \"glass-dark\": {\r\n backgroundColor: \"rgba(0, 0, 0, 0.7)\",\r\n backdropFilter: \"blur(16px)\",\r\n WebkitBackdropFilter: \"blur(16px)\",\r\n border: \"1px solid rgba(100, 130, 160, 0.2)\",\r\n boxShadow: \"none\",\r\n } as React.CSSProperties,\r\n \"glass-light\": {\r\n backgroundColor: \"rgba(255, 255, 255, 0.15)\",\r\n backdropFilter: \"blur(12px)\",\r\n WebkitBackdropFilter: \"blur(12px)\",\r\n border: \"1px solid rgba(255, 255, 255, 0.25)\",\r\n boxShadow: \"none\",\r\n } as React.CSSProperties,\r\n };\r\n\r\n // Glow color for hover effect (like GlassCard)\r\n const glowColor = accentColor ? `${accentColor}66` : \"rgba(0, 212, 255, 0.4)\";\r\n\r\n // Glass mode overrides for BOLD/MINIMAL themes (Glassmorphic Panels with accent borders)\r\n const glassOverrides: React.CSSProperties = useGlassMode\r\n ? ({\r\n backgroundColor: \"rgba(10, 15, 25, 0.35)\",\r\n backdropFilter: \"blur(12px)\",\r\n WebkitBackdropFilter: \"blur(12px)\",\r\n border: `1px solid ${glassAccentMuted}`,\r\n borderTop: isBoldVariant\r\n ? `2px solid ${glassAccentColor}`\r\n : `1px solid ${glassAccentColor}`,\r\n transition: \"all 0.3s ease-out, box-shadow 0.3s ease-out\",\r\n } as React.CSSProperties)\r\n : {};\r\n\r\n // Simple glass overrides for normal \"transparent\" (Glass) theme — match top cards (ISS): transparent + blur\r\n const simpleGlassOverrides: React.CSSProperties = useSimpleGlass\r\n ? ({\r\n backgroundColor: \"transparent\",\r\n backdropFilter: \"blur(12px)\",\r\n WebkitBackdropFilter: \"blur(12px)\",\r\n border: `1px solid ${tokens.colors.border.muted}`,\r\n transition: \"all 0.3s ease-out\",\r\n } as React.CSSProperties)\r\n : {};\r\n\r\n // Hover handlers for glow effect (like GlassCard)\r\n const handleMouseEnter = useCallback(\r\n (e: React.MouseEvent<HTMLDivElement>) => {\r\n if (useGlassMode) {\r\n e.currentTarget.style.boxShadow = `0 0 30px ${glowColor}, 0 4px 20px rgba(0,0,0,0.3)`;\r\n }\r\n },\r\n [useGlassMode, glowColor],\r\n );\r\n\r\n const handleMouseLeave = useCallback(\r\n (e: React.MouseEvent<HTMLDivElement>) => {\r\n if (useGlassMode) {\r\n e.currentTarget.style.boxShadow = \"none\";\r\n }\r\n },\r\n [useGlassMode],\r\n );\r\n\r\n const statusColor = status ? tokens.colors.status[status] : undefined;\r\n const isInteractive = !!onClick;\r\n\r\n return (\r\n <div\r\n className={classNames(\r\n \"zendir-container\",\r\n `zendir-container--${variant}`,\r\n useGlassMode && \"zendir-container--auto-glass\",\r\n className,\r\n )}\r\n onClick={onClick}\r\n role={isInteractive ? \"button\" : undefined}\r\n tabIndex={isInteractive ? 0 : undefined}\r\n onKeyDown={\r\n onClick\r\n ? (e: React.KeyboardEvent) => {\r\n if (e.key === \"Enter\" || e.key === \" \") {\r\n e.preventDefault();\r\n onClick();\r\n }\r\n }\r\n : undefined\r\n }\r\n onMouseEnter={handleMouseEnter}\r\n onMouseLeave={handleMouseLeave}\r\n style={{\r\n borderRadius: tokens.borderRadius.lg,\r\n overflow: \"hidden\",\r\n position: \"relative\",\r\n height: fullHeight ? \"100%\" : \"auto\",\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n cursor: isInteractive ? \"pointer\" : \"default\",\r\n transition: \"all 0.3s ease-out\",\r\n borderLeft: statusColor ? `4px solid ${statusColor}` : undefined,\r\n ...variantStyles[variant],\r\n ...simpleGlassOverrides, // Normal Glass theme\r\n ...glassOverrides, // Bold/Minimal themes (overrides simpleGlass if both)\r\n ...style,\r\n }}\r\n >\r\n {/* Glass gradient overlay for bold/minimal transparent themes */}\r\n {useGlassMode && (\r\n <div\r\n style={{\r\n position: \"absolute\",\r\n inset: 0,\r\n background: glassGradient,\r\n pointerEvents: \"none\",\r\n zIndex: 0,\r\n }}\r\n />\r\n )}\r\n\r\n {/* Loading overlay */}\r\n {loading && (\r\n <div\r\n style={{\r\n position: \"absolute\",\r\n inset: 0,\r\n backgroundColor: addAlpha(tokens.colors.background.surface, 0.5),\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n zIndex: 10,\r\n }}\r\n >\r\n <svg\r\n width=\"32\"\r\n height=\"32\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n style={{ animation: \"spin 1s linear infinite\" }}\r\n >\r\n <circle\r\n cx=\"12\"\r\n cy=\"12\"\r\n r=\"10\"\r\n stroke={tokens.colors.accent.primary}\r\n strokeWidth=\"3\"\r\n strokeDasharray=\"31.4 31.4\"\r\n strokeDashoffset=\"10\"\r\n />\r\n </svg>\r\n <style>\r\n {`@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`}\r\n </style>\r\n </div>\r\n )}\r\n\r\n {/* Header - Glass mode BOLD variant (matching GlassCard style exactly) */}\r\n {(title || actions) && useGlassMode && isBoldVariant && (\r\n <div\r\n style={{\r\n position: \"relative\",\r\n zIndex: 1,\r\n }}\r\n >\r\n {/* Title row */}\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"space-between\",\r\n padding: `16px ${paddingConfig[padding]} 0`,\r\n }}\r\n >\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: headingConfig.gap,\r\n }}\r\n >\r\n {/* Icon with optional status symbol - full area triggers tooltip */}\r\n {icon && (\r\n <IconWithStatusTooltip\r\n icon={icon}\r\n iconColor={resolvedIconColor}\r\n iconStatus={iconStatus}\r\n statusMessage={statusMessage}\r\n iconSize={headingConfig.iconSize}\r\n />\r\n )}\r\n <h3\r\n style={{\r\n margin: 0,\r\n fontSize: headingConfig.titleFontSize,\r\n fontWeight: headingConfig.titleFontWeight,\r\n color: glassAccentColor,\r\n letterSpacing: \"0.5px\",\r\n textShadow: `0 0 20px ${glassAccentMuted}`,\r\n }}\r\n >\r\n {title}\r\n </h3>\r\n </div>\r\n {actions && (\r\n <div style={{ display: \"flex\", gap: tokens.spacing.xs }}>\r\n {actions}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {subtitle && (\r\n <p\r\n style={{\r\n margin: 0,\r\n padding: `${tokens.spacing.xs} ${paddingConfig[padding]} 0`,\r\n fontSize: tokens.typography.fontSize.sm,\r\n color: tokens.colors.text.secondary,\r\n }}\r\n >\r\n {subtitle}\r\n </p>\r\n )}\r\n\r\n {/* Accent line with optional status badge */}\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: tokens.spacing.sm,\r\n padding: `12px ${paddingConfig[padding]} 0`,\r\n marginBottom: tokens.spacing.sm,\r\n }}\r\n >\r\n {/* Main accent line with gradient */}\r\n <div\r\n style={{\r\n flex: 1,\r\n height: \"2px\",\r\n background: `linear-gradient(90deg, ${glassAccentColor} 0%, ${glassAccentMuted} 70%, ${glassAccentMuted}20 100%)`,\r\n boxShadow: `0 0 8px ${glassAccentMuted}`,\r\n }}\r\n />\r\n {/* Status badge at the end if status is set */}\r\n {iconStatus && iconStatus !== \"off\" && (\r\n <StatusBadge status={iconStatus} tokens={tokens} size=\"bold\" />\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Header - Glass mode MINIMAL variant (inline thin line) */}\r\n {(title || actions) && useGlassMode && !isBoldVariant && (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n padding: `${tokens.spacing.sm} ${paddingConfig[padding]} 0`,\r\n marginBottom: tokens.spacing.sm,\r\n position: \"relative\",\r\n zIndex: 1,\r\n }}\r\n >\r\n {/* Icon with optional status symbol - full area triggers tooltip */}\r\n {icon && (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n marginRight: tokens.spacing.sm,\r\n }}\r\n >\r\n <IconWithStatusTooltip\r\n icon={icon}\r\n iconColor={resolvedIconColor}\r\n iconStatus={iconStatus}\r\n statusMessage={statusMessage}\r\n iconSize={headingConfig.iconSizeCompact}\r\n />\r\n </div>\r\n )}\r\n\r\n {/* Title — card heading system */}\r\n {title && (\r\n <h3\r\n style={{\r\n margin: 0,\r\n fontSize: headingConfig.titleFontSize,\r\n fontWeight: headingConfig.titleFontWeight,\r\n color: glassAccentColor,\r\n textShadow: `0 0 16px ${glassAccentMuted}`,\r\n letterSpacing: \"0.02em\",\r\n whiteSpace: \"nowrap\",\r\n marginRight: \"12px\",\r\n }}\r\n >\r\n {title}\r\n </h3>\r\n )}\r\n\r\n {/* Accent line - inline after title with optional status badge */}\r\n <div\r\n style={{\r\n flex: 1,\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: tokens.spacing.sm,\r\n minWidth: 40,\r\n }}\r\n >\r\n {/* Main gradient line */}\r\n <div\r\n style={{\r\n flex: 1,\r\n height: \"1px\",\r\n background: `linear-gradient(90deg, ${glassAccentColor} 0%, ${glassAccentMuted} 70%, ${glassAccentMuted}20 100%)`,\r\n }}\r\n />\r\n {/* Status badge at the end if status is set */}\r\n {iconStatus && iconStatus !== \"off\" && (\r\n <StatusBadge status={iconStatus} tokens={tokens} size=\"minimal\" />\r\n )}\r\n </div>\r\n\r\n {actions && (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n gap: tokens.spacing.xs,\r\n flexShrink: 0,\r\n marginLeft: \"12px\",\r\n }}\r\n >\r\n {actions}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* Subtitle for glass mode MINIMAL - separate row */}\r\n {subtitle && useGlassMode && !isBoldVariant && (\r\n <p\r\n style={{\r\n margin: 0,\r\n padding: `0 ${paddingConfig[padding]}`,\r\n marginBottom: tokens.spacing.sm,\r\n fontSize: tokens.typography.fontSize.sm,\r\n color: tokens.colors.text.secondary,\r\n position: \"relative\",\r\n zIndex: 1,\r\n }}\r\n >\r\n {subtitle}\r\n </p>\r\n )}\r\n\r\n {/* Header - Regular mode (non-glass) - Uses shared CardHeader for consistency */}\r\n {(title || actions) && !useGlassMode && (\r\n <div\r\n style={{\r\n padding: `${paddingConfig[padding]} ${paddingConfig[padding]} 0`,\r\n position: \"relative\",\r\n zIndex: 1,\r\n }}\r\n >\r\n <CardHeader\r\n icon={icon || (iconStatus ? \"mission\" : \"\")}\r\n title={typeof title === \"string\" ? title : String(title || \"\")}\r\n subtitle={typeof subtitle === \"string\" ? subtitle : undefined}\r\n status={iconStatus || status}\r\n iconColor={iconColor}\r\n iconSize={headingConfig.iconSize}\r\n hideStatusIndicator={!icon && !iconStatus && !status}\r\n rightSlot={actions}\r\n style={{ marginBottom: tokens.spacing.sm }}\r\n />\r\n {/* Render non-string subtitles (React elements) below the CardHeader */}\r\n {subtitle && typeof subtitle !== \"string\" && (\r\n <div\r\n style={{\r\n fontSize: tokens.typography.fontSize.sm,\r\n color: tokens.colors.text.secondary,\r\n marginTop: -parseInt(tokens.spacing.xs || \"4\", 10) || -4,\r\n marginBottom: parseInt(tokens.spacing.sm || \"8\", 10) || 8,\r\n }}\r\n >\r\n {subtitle}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* Content */}\r\n <div\r\n style={{\r\n flex: 1,\r\n minHeight: fullHeight ? 0 : undefined,\r\n overflow: fullHeight && clipContent ? \"hidden\" : undefined,\r\n // When fullHeight, become a flex column so any child using flex:1 or height:100%\r\n // gets a properly bounded height and scroll containers can work.\r\n display: fullHeight ? \"flex\" : undefined,\r\n flexDirection: fullHeight ? \"column\" : undefined,\r\n padding: fullHeight\r\n ? `${tokens.spacing.xs} 0 0 0`\r\n : title\r\n ? `${tokens.spacing.xs} ${paddingConfig[padding]} ${paddingConfig[padding]}`\r\n : paddingConfig[padding],\r\n position: \"relative\",\r\n zIndex: 1,\r\n }}\r\n >\r\n {children}\r\n </div>\r\n </div>\r\n );\r\n});\r\n\r\nexport default Container;\r\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CopyButton.js","names":[],"sources":["../../../../src/react/core/display/CopyButton.tsx"],"sourcesContent":["/**\n * @zendir/ui - Clipboard Utilities\n *\n * Copy-to-clipboard hook and button component. Used universally in operator\n * dashboards for sharing configuration URLs, copying telemetry values,\n * exporting command IDs.\n *\n * @example\n * ```tsx\n * // Hook\n * const { copy, copied } = useCopyToClipboard();\n * <Button onClick={() => copy(configUrl)}>\n * {copied ? 'Copied!' : 'Copy URL'}\n * </Button>\n *\n * // Component\n * <CopyButton value={telemetryValue} label=\"Copy Value\" />\n * <CopyButton value={shareUrl} size=\"small\" />\n * ```\n */\n\nimport React, { memo, useState, useCallback, useRef, useEffect } from \"react\";\nimport { useTheme } from \"../../theme\";\n\n// ─── Hook ────────────────────────────────────────────────────────────────────\n\nexport interface UseCopyToClipboardReturn {\n /** Copy text to clipboard */\n copy: (text: string) => Promise<boolean>;\n /** True for brief period after successful copy */\n copied: boolean;\n /** Error if copy failed */\n error: string | null;\n}\n\n/**\n * Hook for clipboard operations.\n *\n * @param resetDelay - Time in ms before `copied` resets to false (default 2000)\n *\n * @example\n * ```tsx\n * const { copy, copied } = useCopyToClipboard();\n * ```\n */\nexport function useCopyToClipboard(\n resetDelay = 2000,\n): UseCopyToClipboardReturn {\n const [copied, setCopied] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const timeoutRef = useRef<ReturnType<typeof setTimeout>>();\n\n const copy = useCallback(\n async (text: string): Promise<boolean> => {\n try {\n if (navigator.clipboard && navigator.clipboard.writeText) {\n await navigator.clipboard.writeText(text);\n } else {\n // Fallback for older browsers / non-HTTPS\n const textarea = document.createElement(\"textarea\");\n textarea.value = text;\n textarea.style.cssText =\n \"position:fixed;left:-9999px;top:-9999px;opacity:0\";\n document.body.appendChild(textarea);\n textarea.select();\n document.execCommand(\"copy\");\n document.body.removeChild(textarea);\n }\n\n setCopied(true);\n setError(null);\n clearTimeout(timeoutRef.current);\n timeoutRef.current = setTimeout(() => setCopied(false), resetDelay);\n return true;\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Copy failed\";\n setError(message);\n setCopied(false);\n return false;\n }\n },\n [resetDelay],\n );\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n clearTimeout(timeoutRef.current);\n };\n }, []);\n\n return { copy, copied, error };\n}\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\nexport interface CopyButtonProps {\n /** Text to copy */\n value: string;\n /** Button label (default: shows icon only) */\n label?: string;\n /** Label shown briefly after copy (default: \"Copied!\") */\n copiedLabel?: string;\n /** Size */\n size?: \"small\" | \"medium\" | \"large\";\n /** Tooltip text */\n tooltip?: string;\n /** Disabled */\n disabled?: boolean;\n /** Custom style */\n style?: React.CSSProperties;\n}\n\nexport const CopyButton = memo(function CopyButton({\n value,\n label,\n copiedLabel = \"Copied!\",\n size = \"medium\",\n tooltip = \"Copy to clipboard\",\n disabled = false,\n style,\n}: CopyButtonProps): React.ReactElement {\n const { tokens } = useTheme();\n const { copy, copied } = useCopyToClipboard();\n const [isHovered, setIsHovered] = useState(false);\n\n const sizeConfig = {\n small: {\n height: 28,\n padding: \"4px 8px\",\n fontSize: \"0.75rem\",\n iconSize: 14,\n },\n medium: {\n height: 36,\n padding: \"6px 12px\",\n fontSize: \"0.875rem\",\n iconSize: 16,\n },\n large: { height: 44, padding: \"8px 16px\", fontSize: \"1rem\", iconSize: 18 },\n };\n const config = sizeConfig[size];\n\n // Copy icon (two overlapping rectangles)\n const copyIcon = (\n <svg\n width={config.iconSize}\n height={config.iconSize}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n );\n\n // Checkmark icon\n const checkIcon = (\n <svg\n width={config.iconSize}\n height={config.iconSize}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke={tokens.colors.status.normal}\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n );\n\n return (\n <button\n type=\"button\"\n onClick={() => !disabled && copy(value)}\n disabled={disabled}\n title={copied ? copiedLabel : tooltip}\n aria-label={!label ? (copied ? copiedLabel : tooltip) : undefined}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: \"6px\",\n height: config.height,\n padding: label\n ? config.padding\n : `0 ${Math.round(parseInt(config.padding) * 0.6)}px`,\n fontSize: config.fontSize,\n fontWeight: 500,\n fontFamily: tokens.typography.fontFamily.primary,\n color: copied\n ? tokens.colors.status.normal\n : tokens.colors.text.secondary,\n backgroundColor:\n isHovered && !disabled\n ? `${tokens.colors.accent.primary}12`\n : \"transparent\",\n border: `1px solid ${copied ? `${tokens.colors.status.normal}40` : tokens.colors.border.muted}`,\n borderRadius: tokens.borderRadius.md,\n cursor: disabled ? \"not-allowed\" : \"pointer\",\n transition: tokens.animation.fast,\n opacity: disabled ? 0.5 : 1,\n outline: \"none\",\n whiteSpace: \"nowrap\",\n ...style,\n }}\n >\n {copied ? checkIcon : copyIcon}\n {label && <span>{copied ? copiedLabel : label}</span>}\n </button>\n );\n});\n\nexport default CopyButton;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CopyButton.js","names":[],"sources":["../../../../src/react/core/display/CopyButton.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - Clipboard Utilities\r\n *\r\n * Copy-to-clipboard hook and button component. Used universally in operator\r\n * dashboards for sharing configuration URLs, copying telemetry values,\r\n * exporting command IDs.\r\n *\r\n * @example\r\n * ```tsx\r\n * // Hook\r\n * const { copy, copied } = useCopyToClipboard();\r\n * <Button onClick={() => copy(configUrl)}>\r\n * {copied ? 'Copied!' : 'Copy URL'}\r\n * </Button>\r\n *\r\n * // Component\r\n * <CopyButton value={telemetryValue} label=\"Copy Value\" />\r\n * <CopyButton value={shareUrl} size=\"small\" />\r\n * ```\r\n */\r\n\r\nimport React, { memo, useState, useCallback, useRef, useEffect } from \"react\";\r\nimport { useTheme } from \"../../theme\";\r\n\r\n// ─── Hook ────────────────────────────────────────────────────────────────────\r\n\r\nexport interface UseCopyToClipboardReturn {\r\n /** Copy text to clipboard */\r\n copy: (text: string) => Promise<boolean>;\r\n /** True for brief period after successful copy */\r\n copied: boolean;\r\n /** Error if copy failed */\r\n error: string | null;\r\n}\r\n\r\n/**\r\n * Hook for clipboard operations.\r\n *\r\n * @param resetDelay - Time in ms before `copied` resets to false (default 2000)\r\n *\r\n * @example\r\n * ```tsx\r\n * const { copy, copied } = useCopyToClipboard();\r\n * ```\r\n */\r\nexport function useCopyToClipboard(\r\n resetDelay = 2000,\r\n): UseCopyToClipboardReturn {\r\n const [copied, setCopied] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const timeoutRef = useRef<ReturnType<typeof setTimeout>>();\r\n\r\n const copy = useCallback(\r\n async (text: string): Promise<boolean> => {\r\n try {\r\n if (navigator.clipboard && navigator.clipboard.writeText) {\r\n await navigator.clipboard.writeText(text);\r\n } else {\r\n // Fallback for older browsers / non-HTTPS\r\n const textarea = document.createElement(\"textarea\");\r\n textarea.value = text;\r\n textarea.style.cssText =\r\n \"position:fixed;left:-9999px;top:-9999px;opacity:0\";\r\n document.body.appendChild(textarea);\r\n textarea.select();\r\n document.execCommand(\"copy\");\r\n document.body.removeChild(textarea);\r\n }\r\n\r\n setCopied(true);\r\n setError(null);\r\n clearTimeout(timeoutRef.current);\r\n timeoutRef.current = setTimeout(() => setCopied(false), resetDelay);\r\n return true;\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : \"Copy failed\";\r\n setError(message);\r\n setCopied(false);\r\n return false;\r\n }\r\n },\r\n [resetDelay],\r\n );\r\n\r\n // Cleanup on unmount\r\n useEffect(() => {\r\n return () => {\r\n clearTimeout(timeoutRef.current);\r\n };\r\n }, []);\r\n\r\n return { copy, copied, error };\r\n}\r\n\r\n// ─── Component ───────────────────────────────────────────────────────────────\r\n\r\nexport interface CopyButtonProps {\r\n /** Text to copy */\r\n value: string;\r\n /** Button label (default: shows icon only) */\r\n label?: string;\r\n /** Label shown briefly after copy (default: \"Copied!\") */\r\n copiedLabel?: string;\r\n /** Size */\r\n size?: \"small\" | \"medium\" | \"large\";\r\n /** Tooltip text */\r\n tooltip?: string;\r\n /** Disabled */\r\n disabled?: boolean;\r\n /** Custom style */\r\n style?: React.CSSProperties;\r\n}\r\n\r\nexport const CopyButton = memo(function CopyButton({\r\n value,\r\n label,\r\n copiedLabel = \"Copied!\",\r\n size = \"medium\",\r\n tooltip = \"Copy to clipboard\",\r\n disabled = false,\r\n style,\r\n}: CopyButtonProps): React.ReactElement {\r\n const { tokens } = useTheme();\r\n const { copy, copied } = useCopyToClipboard();\r\n const [isHovered, setIsHovered] = useState(false);\r\n\r\n const sizeConfig = {\r\n small: {\r\n height: 28,\r\n padding: \"4px 8px\",\r\n fontSize: \"0.75rem\",\r\n iconSize: 14,\r\n },\r\n medium: {\r\n height: 36,\r\n padding: \"6px 12px\",\r\n fontSize: \"0.875rem\",\r\n iconSize: 16,\r\n },\r\n large: { height: 44, padding: \"8px 16px\", fontSize: \"1rem\", iconSize: 18 },\r\n };\r\n const config = sizeConfig[size];\r\n\r\n // Copy icon (two overlapping rectangles)\r\n const copyIcon = (\r\n <svg\r\n width={config.iconSize}\r\n height={config.iconSize}\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n >\r\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\r\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\r\n </svg>\r\n );\r\n\r\n // Checkmark icon\r\n const checkIcon = (\r\n <svg\r\n width={config.iconSize}\r\n height={config.iconSize}\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke={tokens.colors.status.normal}\r\n strokeWidth=\"2.5\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n >\r\n <polyline points=\"20 6 9 17 4 12\" />\r\n </svg>\r\n );\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n onClick={() => !disabled && copy(value)}\r\n disabled={disabled}\r\n title={copied ? copiedLabel : tooltip}\r\n aria-label={!label ? (copied ? copiedLabel : tooltip) : undefined}\r\n onMouseEnter={() => setIsHovered(true)}\r\n onMouseLeave={() => setIsHovered(false)}\r\n style={{\r\n display: \"inline-flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n gap: \"6px\",\r\n height: config.height,\r\n padding: label\r\n ? config.padding\r\n : `0 ${Math.round(parseInt(config.padding) * 0.6)}px`,\r\n fontSize: config.fontSize,\r\n fontWeight: 500,\r\n fontFamily: tokens.typography.fontFamily.primary,\r\n color: copied\r\n ? tokens.colors.status.normal\r\n : tokens.colors.text.secondary,\r\n backgroundColor:\r\n isHovered && !disabled\r\n ? `${tokens.colors.accent.primary}12`\r\n : \"transparent\",\r\n border: `1px solid ${copied ? `${tokens.colors.status.normal}40` : tokens.colors.border.muted}`,\r\n borderRadius: tokens.borderRadius.md,\r\n cursor: disabled ? \"not-allowed\" : \"pointer\",\r\n transition: tokens.animation.fast,\r\n opacity: disabled ? 0.5 : 1,\r\n outline: \"none\",\r\n whiteSpace: \"nowrap\",\r\n ...style,\r\n }}\r\n >\r\n {copied ? checkIcon : copyIcon}\r\n {label && <span>{copied ? copiedLabel : label}</span>}\r\n </button>\r\n );\r\n});\r\n\r\nexport default CopyButton;\r\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlassCard.js","names":[],"sources":["../../../../src/react/core/display/GlassCard.tsx"],"sourcesContent":["/**\n * @zendir/ui - GlassCard Component\n *\n * Glassmorphic card component with transparent blur backgrounds,\n * gradient overlays, and Zendir brand color accent system.\n *\n * Inspired by AstroUXDS radar chart styling with modern glassmorphism.\n *\n * @example\n * ```tsx\n * <GlassCard title=\"Radar Chart 001\" colorOverlay=\"electric\">\n * <RadarChart data={data} />\n * </GlassCard>\n *\n * <GlassCard title=\"System Status\" colorOverlay=\"purple\" accentPosition=\"top\">\n * <StatusContent />\n * </GlassCard>\n * ```\n */\n\nimport React, { memo } from \"react\";\nimport { useTheme } from \"../../theme\";\nimport { classNames, type StatusLevel } from \"../../utils\";\n\n// =============================================================================\n// Zendir Brand Color Palette for Glass Overlays\n// =============================================================================\n\nexport const GLASS_COLOR_OVERLAYS = {\n // Core brand colors\n electric: {\n gradient:\n \"linear-gradient(135deg, rgba(62, 60, 255, 0.15) 0%, rgba(62, 60, 255, 0.05) 100%)\",\n accent: \"#3E3CFF\",\n border: \"rgba(62, 60, 255, 0.3)\",\n glow: \"rgba(62, 60, 255, 0.4)\",\n },\n purple: {\n gradient:\n \"linear-gradient(135deg, rgba(157, 112, 255, 0.15) 0%, rgba(157, 112, 255, 0.05) 100%)\",\n accent: \"#9D70FF\",\n border: \"rgba(157, 112, 255, 0.3)\",\n glow: \"rgba(157, 112, 255, 0.4)\",\n },\n prussianBlue: {\n gradient:\n \"linear-gradient(135deg, rgba(27, 45, 160, 0.2) 0%, rgba(27, 45, 160, 0.08) 100%)\",\n accent: \"#1B2DA0\",\n border: \"rgba(27, 45, 160, 0.4)\",\n glow: \"rgba(27, 45, 160, 0.5)\",\n },\n\n // Cyan/Teal (matching the reference image style)\n cyan: {\n gradient:\n \"linear-gradient(135deg, rgba(0, 212, 255, 0.12) 0%, rgba(0, 180, 220, 0.04) 100%)\",\n accent: \"#00D4FF\",\n border: \"rgba(0, 212, 255, 0.35)\",\n glow: \"rgba(0, 212, 255, 0.5)\",\n },\n teal: {\n gradient:\n \"linear-gradient(135deg, rgba(45, 204, 255, 0.12) 0%, rgba(45, 204, 255, 0.04) 100%)\",\n accent: \"#2DCCFF\",\n border: \"rgba(45, 204, 255, 0.35)\",\n glow: \"rgba(45, 204, 255, 0.5)\",\n },\n\n // Neutral options\n dark: {\n gradient:\n \"linear-gradient(135deg, rgba(0, 0, 0, 0.4) 0%, rgba(0, 0, 0, 0.2) 100%)\",\n accent: \"#1a1a2e\",\n border: \"rgba(255, 255, 255, 0.1)\",\n glow: \"rgba(0, 0, 0, 0.3)\",\n },\n light: {\n gradient:\n \"linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0.05) 100%)\",\n accent: \"#ffffff\",\n border: \"rgba(255, 255, 255, 0.25)\",\n glow: \"rgba(255, 255, 255, 0.3)\",\n },\n white: {\n gradient:\n \"linear-gradient(135deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0.08) 100%)\",\n accent: \"#ffffff\",\n border: \"rgba(255, 255, 255, 0.3)\",\n glow: \"rgba(255, 255, 255, 0.4)\",\n },\n\n // Additional shades\n electricLight: {\n gradient:\n \"linear-gradient(135deg, rgba(107, 105, 255, 0.15) 0%, rgba(107, 105, 255, 0.05) 100%)\",\n accent: \"#6B69FF\",\n border: \"rgba(107, 105, 255, 0.3)\",\n glow: \"rgba(107, 105, 255, 0.4)\",\n },\n purpleLight: {\n gradient:\n \"linear-gradient(135deg, rgba(180, 141, 255, 0.15) 0%, rgba(180, 141, 255, 0.05) 100%)\",\n accent: \"#B48DFF\",\n border: \"rgba(180, 141, 255, 0.3)\",\n glow: \"rgba(180, 141, 255, 0.4)\",\n },\n\n // No overlay (transparent)\n none: {\n gradient: \"none\",\n accent: \"transparent\",\n border: \"rgba(255, 255, 255, 0.1)\",\n glow: \"transparent\",\n },\n} as const;\n\nexport type GlassColorOverlay = keyof typeof GLASS_COLOR_OVERLAYS;\n\nexport type GlassAccentPosition = \"top\" | \"left\" | \"right\" | \"bottom\" | \"none\";\n\nexport interface GlassCardProps {\n /** Card title with optional icon */\n title?: React.ReactNode;\n /** Subtitle text */\n subtitle?: React.ReactNode;\n /** Color overlay from Zendir brand palette */\n colorOverlay?: GlassColorOverlay;\n /** Custom color overlay (hex or rgba) */\n customOverlay?: {\n gradient: string;\n accent: string;\n border: string;\n glow?: string;\n };\n /**\n * Accent color (hex) - auto-generates overlay from this color\n * Overrides colorOverlay if provided\n * Can be used with CardAccentProvider: accentColor={getAccentColor(title)}\n */\n accentColor?: string;\n /** Position of the accent line/glow */\n accentPosition?: GlassAccentPosition;\n /** Accent line style */\n accentStyle?: \"solid\" | \"gradient\" | \"glow\" | \"dots\";\n /** Header icon (rendered before title) */\n icon?: React.ReactNode;\n /** Header right actions (legend, buttons, etc.) */\n actions?: React.ReactNode;\n /** Legend items to display in header */\n legend?: Array<{ label: string; color: string }>;\n /** Status indicator */\n status?: StatusLevel;\n /** Blur intensity (0-20) */\n blur?: number;\n /** Background opacity (0-1) */\n backgroundOpacity?: number;\n /** Enable glow effect on hover */\n glowOnHover?: boolean;\n /** Children content */\n children: React.ReactNode;\n /** Custom className */\n className?: string;\n /** Custom style */\n style?: React.CSSProperties;\n /** Click handler */\n onClick?: () => void;\n /** Full height mode */\n fullHeight?: boolean;\n /** Padding size */\n padding?: \"none\" | \"sm\" | \"md\" | \"lg\";\n}\n\n/**\n * GlassCard - Glassmorphic card with Zendir brand styling\n *\n * Features:\n * - Transparent blur background\n * - Gradient color overlays\n * - Accent lines with glow effects\n * - Legend support for charts\n * - Customizable via props or custom overlay object\n */\n/**\n * Create overlay from accent color hex\n */\nfunction createOverlayFromColor(color: string) {\n // Extract RGB from hex\n const hex = color.replace(\"#\", \"\");\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n\n return {\n gradient: `linear-gradient(135deg, rgba(${r}, ${g}, ${b}, 0.15) 0%, rgba(${r}, ${g}, ${b}, 0.05) 100%)`,\n accent: color,\n border: `rgba(${r}, ${g}, ${b}, 0.35)`,\n glow: `rgba(${r}, ${g}, ${b}, 0.5)`,\n };\n}\n\nexport const GlassCard = memo(function GlassCard({\n title,\n subtitle,\n colorOverlay = \"cyan\",\n customOverlay,\n accentColor,\n accentPosition = \"top\",\n accentStyle = \"gradient\",\n icon,\n actions,\n legend,\n status,\n blur = 12,\n backgroundOpacity = 0.85,\n glowOnHover = true,\n children,\n className = \"\",\n style,\n onClick,\n fullHeight = false,\n padding = \"md\",\n}: GlassCardProps): React.ReactElement {\n const { tokens, mode, theme } = useTheme();\n const isDark = mode === \"dark\";\n const isTransparent =\n theme === \"transparent\" ||\n theme === \"transparent-bold\" ||\n theme === \"transparent-minimal\";\n const isBoldVariant = theme === \"transparent-bold\";\n const isMinimalVariant = theme === \"transparent-minimal\";\n\n // Accent styling only for Bold/Minimal themes (or when position explicitly set for non-transparent)\n const showAccentStyling = isBoldVariant || isMinimalVariant || !isTransparent;\n\n // For all transparent themes, default to purple (Zendir accent) instead of cyan\n const effectiveColorOverlay =\n isTransparent && colorOverlay === \"cyan\" ? \"purple\" : colorOverlay;\n\n // Get overlay colors (priority: accentColor > customOverlay > colorOverlay)\n const overlay = accentColor\n ? createOverlayFromColor(accentColor)\n : customOverlay || GLASS_COLOR_OVERLAYS[effectiveColorOverlay];\n\n // Auto-switch to light token for 'white' overlay in light mode\n const effectiveOverlay =\n mode === \"light\" &&\n colorOverlay === \"white\" &&\n !accentColor &&\n !customOverlay\n ? GLASS_COLOR_OVERLAYS.dark\n : overlay;\n\n // Theme-aware background colors\n const cardBackground = isDark\n ? `rgba(15, 20, 35, ${backgroundOpacity})`\n : `rgba(255, 255, 255, ${backgroundOpacity})`;\n\n // Theme-aware border colors\n const baseBorderColor = isDark\n ? effectiveOverlay.border\n : `rgba(100, 116, 139, 0.25)`;\n\n const paddingConfig = {\n none: \"0\",\n sm: tokens.spacing.sm,\n md: tokens.spacing.md,\n lg: tokens.spacing.lg,\n };\n\n const isInteractive = !!onClick;\n\n // Accent line styles based on position and style\n // Only show accent styling for Bold/Minimal themes (or non-transparent themes)\n const getAccentStyles = (): React.CSSProperties => {\n // For normal Glass theme, use subtle muted border instead of colored accent\n if (isTransparent && !showAccentStyling) {\n return {};\n }\n\n if (accentPosition === \"none\") return {};\n\n const accentColorValue = effectiveOverlay.accent;\n const glowColor = effectiveOverlay.glow || accentColorValue;\n\n const baseAccentStyle: React.CSSProperties = {};\n\n // Position-based border\n const positions: Record<GlassAccentPosition, string> = {\n top: \"borderTop\",\n left: \"borderLeft\",\n right: \"borderRight\",\n bottom: \"borderBottom\",\n none: \"\",\n };\n\n const borderProp = positions[accentPosition] as keyof React.CSSProperties;\n\n if (accentStyle === \"solid\") {\n (baseAccentStyle as any)[borderProp] = `2px solid ${accentColorValue}`;\n } else if (accentStyle === \"gradient\" || accentStyle === \"glow\") {\n // Using pseudo-element for gradient, so just set position indicator\n (baseAccentStyle as any)[borderProp] = `2px solid ${accentColorValue}`;\n if (accentStyle === \"glow\") {\n baseAccentStyle.boxShadow = `0 -2px 20px ${glowColor}, 0 -1px 8px ${glowColor}`;\n }\n } else if (accentStyle === \"dots\") {\n (baseAccentStyle as any)[borderProp] = `2px dotted ${accentColorValue}`;\n }\n\n return baseAccentStyle;\n };\n\n // Status color\n const statusColor = status ? tokens.colors.status[status] : undefined;\n\n return (\n <div\n className={classNames(\n \"zendir-glass-card\",\n `zendir-glass-card--${colorOverlay}`,\n className,\n )}\n onClick={onClick}\n role={isInteractive ? \"button\" : undefined}\n tabIndex={isInteractive ? 0 : undefined}\n onKeyDown={\n onClick\n ? (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n }\n : undefined\n }\n style={{\n position: \"relative\",\n borderRadius: tokens.borderRadius.lg,\n overflow: \"hidden\",\n height: fullHeight ? \"100%\" : \"auto\",\n display: \"flex\",\n flexDirection: \"column\",\n cursor: isInteractive ? \"pointer\" : \"default\",\n\n // Glassmorphic base (theme-aware)\n background: cardBackground,\n backdropFilter: isTransparent ? `blur(${blur}px)` : \"none\",\n WebkitBackdropFilter: isTransparent ? `blur(${blur}px)` : \"none\",\n\n // Border with color tint (theme-aware)\n border: `1px solid ${baseBorderColor}`,\n\n // Accent positioning\n ...getAccentStyles(),\n\n // Hover glow effect\n transition: \"all 0.3s ease-out\",\n boxShadow: glowOnHover ? \"none\" : undefined,\n\n ...style,\n }}\n onMouseEnter={(e) => {\n if (glowOnHover && effectiveOverlay.glow) {\n e.currentTarget.style.boxShadow = `0 0 30px ${effectiveOverlay.glow}, 0 4px 20px rgba(0,0,0,0.3)`;\n }\n }}\n onMouseLeave={(e) => {\n if (glowOnHover) {\n e.currentTarget.style.boxShadow = \"none\";\n }\n }}\n >\n {/* Gradient overlay layer */}\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n background: effectiveOverlay.gradient,\n pointerEvents: \"none\",\n zIndex: 0,\n }}\n />\n\n {/* Accent glow line (top) - only for Bold/Minimal themes */}\n {showAccentStyling &&\n accentPosition === \"top\" &&\n accentStyle === \"glow\" && (\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: \"10%\",\n right: \"10%\",\n height: \"2px\",\n background: `linear-gradient(90deg, transparent, ${effectiveOverlay.accent}, transparent)`,\n boxShadow: `0 0 15px ${effectiveOverlay.glow}, 0 0 30px ${effectiveOverlay.glow}`,\n zIndex: 1,\n }}\n />\n )}\n\n {/* Content wrapper */}\n <div\n style={{\n position: \"relative\",\n zIndex: 1,\n display: \"flex\",\n flexDirection: \"column\",\n flex: 1,\n }}\n >\n {/* Header */}\n {(title || actions || legend) && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: tokens.spacing.md,\n padding: `${paddingConfig[padding]} ${paddingConfig[padding]} 0`,\n marginBottom: tokens.spacing.sm,\n }}\n >\n {/* Title section */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: tokens.spacing.sm,\n }}\n >\n {/* Icon */}\n {icon && (\n <span\n style={{\n color: effectiveOverlay.accent,\n display: \"flex\",\n alignItems: \"center\",\n }}\n >\n {icon}\n </span>\n )}\n\n {/* Status shape — Astro UX dual-coded */}\n {status &&\n statusColor &&\n (() => {\n const s = 10;\n const h = s / 2;\n const glow = `drop-shadow(0 0 4px ${statusColor})`;\n switch (status) {\n case \"critical\":\n return (\n <svg\n width={s}\n height={s}\n viewBox={`0 0 ${s} ${s}`}\n style={{ flexShrink: 0, filter: glow }}\n >\n <polygon\n points={`${h},${s} 0,0 ${s},0`}\n fill={statusColor}\n />\n </svg>\n );\n case \"serious\":\n return (\n <svg\n width={s}\n height={s}\n viewBox={`0 0 ${s} ${s}`}\n style={{ flexShrink: 0, filter: glow }}\n >\n <polygon\n points={`${h},0 ${s},${h} ${h},${s} 0,${h}`}\n fill={statusColor}\n />\n </svg>\n );\n case \"caution\":\n return (\n <svg\n width={s}\n height={s}\n viewBox={`0 0 ${s} ${s}`}\n style={{ flexShrink: 0, filter: glow }}\n >\n <rect width={s} height={s} fill={statusColor} />\n </svg>\n );\n case \"standby\":\n return (\n <svg\n width={s}\n height={s}\n viewBox=\"0 0 12 12\"\n style={{ flexShrink: 0, filter: glow }}\n >\n <circle\n cx=\"6\"\n cy=\"6\"\n r=\"3.5\"\n fill=\"none\"\n stroke={statusColor}\n strokeWidth=\"2\"\n />\n </svg>\n );\n case \"off\":\n return (\n <svg\n width={s}\n height={s}\n viewBox=\"0 0 12 12\"\n style={{ flexShrink: 0, filter: glow }}\n >\n <circle cx=\"6\" cy=\"6\" r=\"3\" fill={statusColor} />\n </svg>\n );\n default: // normal\n return (\n <svg\n width={s}\n height={s}\n viewBox={`0 0 ${s} ${s}`}\n style={{ flexShrink: 0, filter: glow }}\n >\n <circle cx={h} cy={h} r={h} fill={statusColor} />\n </svg>\n );\n }\n })()}\n\n {/* Title text — card heading system */}\n <div>\n {title && (\n <h3\n style={{\n margin: 0,\n fontSize:\n tokens.layout?.card?.heading?.titleFontSize ??\n \"1.125rem\",\n fontWeight:\n tokens.layout?.card?.heading?.titleFontWeight ?? 500,\n color: effectiveOverlay.accent,\n letterSpacing: \"0.5px\",\n textShadow: `0 0 20px ${effectiveOverlay.glow}`,\n }}\n >\n {title}\n </h3>\n )}\n {subtitle && (\n <p\n style={{\n margin: `${tokens.spacing.xs} 0 0`,\n fontSize: tokens.typography.body[3].fontSize,\n color: tokens.colors.text.secondary,\n }}\n >\n {subtitle}\n </p>\n )}\n </div>\n </div>\n\n {/* Right section: legend + actions */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: tokens.spacing.md,\n }}\n >\n {/* Legend items */}\n {legend && legend.length > 0 && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: tokens.spacing.md,\n }}\n >\n {legend.map((item, idx) => (\n <div\n key={idx}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: tokens.spacing.xs,\n }}\n >\n <span\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"2px\",\n backgroundColor: item.color,\n }}\n />\n <span\n style={{\n fontSize: tokens.typography.body[3].fontSize,\n color: tokens.colors.text.secondary,\n }}\n >\n {item.label}\n </span>\n </div>\n ))}\n </div>\n )}\n\n {/* Actions */}\n {actions && (\n <div style={{ display: \"flex\", gap: tokens.spacing.xs }}>\n {actions}\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* Accent line - only for Bold/Minimal themes (no decorative dashes) */}\n {showAccentStyling && accentPosition === \"top\" && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n padding: `0 ${paddingConfig[padding]}`,\n marginBottom: tokens.spacing.sm,\n }}\n >\n {/* Clean accent line with smooth gradient */}\n <div\n style={{\n flex: 1,\n height: \"2px\",\n background: `linear-gradient(90deg, ${effectiveOverlay.accent} 0%, ${effectiveOverlay.accent}60 70%, ${effectiveOverlay.accent}20 100%)`,\n boxShadow: `0 0 6px ${effectiveOverlay.accent}40`,\n }}\n />\n </div>\n )}\n\n {/* Content */}\n <div\n style={{\n flex: 1,\n padding: title\n ? `0 ${paddingConfig[padding]} ${paddingConfig[padding]}`\n : paddingConfig[padding],\n }}\n >\n {children}\n </div>\n </div>\n </div>\n );\n});\n\nexport default GlassCard;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GlassCard.js","names":[],"sources":["../../../../src/react/core/display/GlassCard.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - GlassCard Component\r\n *\r\n * Glassmorphic card component with transparent blur backgrounds,\r\n * gradient overlays, and Zendir brand color accent system.\r\n *\r\n * Inspired by AstroUXDS radar chart styling with modern glassmorphism.\r\n *\r\n * @example\r\n * ```tsx\r\n * <GlassCard title=\"Radar Chart 001\" colorOverlay=\"electric\">\r\n * <RadarChart data={data} />\r\n * </GlassCard>\r\n *\r\n * <GlassCard title=\"System Status\" colorOverlay=\"purple\" accentPosition=\"top\">\r\n * <StatusContent />\r\n * </GlassCard>\r\n * ```\r\n */\r\n\r\nimport React, { memo } from \"react\";\r\nimport { useTheme } from \"../../theme\";\r\nimport { classNames, type StatusLevel } from \"../../utils\";\r\n\r\n// =============================================================================\r\n// Zendir Brand Color Palette for Glass Overlays\r\n// =============================================================================\r\n\r\nexport const GLASS_COLOR_OVERLAYS = {\r\n // Core brand colors\r\n electric: {\r\n gradient:\r\n \"linear-gradient(135deg, rgba(62, 60, 255, 0.15) 0%, rgba(62, 60, 255, 0.05) 100%)\",\r\n accent: \"#3E3CFF\",\r\n border: \"rgba(62, 60, 255, 0.3)\",\r\n glow: \"rgba(62, 60, 255, 0.4)\",\r\n },\r\n purple: {\r\n gradient:\r\n \"linear-gradient(135deg, rgba(157, 112, 255, 0.15) 0%, rgba(157, 112, 255, 0.05) 100%)\",\r\n accent: \"#9D70FF\",\r\n border: \"rgba(157, 112, 255, 0.3)\",\r\n glow: \"rgba(157, 112, 255, 0.4)\",\r\n },\r\n prussianBlue: {\r\n gradient:\r\n \"linear-gradient(135deg, rgba(27, 45, 160, 0.2) 0%, rgba(27, 45, 160, 0.08) 100%)\",\r\n accent: \"#1B2DA0\",\r\n border: \"rgba(27, 45, 160, 0.4)\",\r\n glow: \"rgba(27, 45, 160, 0.5)\",\r\n },\r\n\r\n // Cyan/Teal (matching the reference image style)\r\n cyan: {\r\n gradient:\r\n \"linear-gradient(135deg, rgba(0, 212, 255, 0.12) 0%, rgba(0, 180, 220, 0.04) 100%)\",\r\n accent: \"#00D4FF\",\r\n border: \"rgba(0, 212, 255, 0.35)\",\r\n glow: \"rgba(0, 212, 255, 0.5)\",\r\n },\r\n teal: {\r\n gradient:\r\n \"linear-gradient(135deg, rgba(45, 204, 255, 0.12) 0%, rgba(45, 204, 255, 0.04) 100%)\",\r\n accent: \"#2DCCFF\",\r\n border: \"rgba(45, 204, 255, 0.35)\",\r\n glow: \"rgba(45, 204, 255, 0.5)\",\r\n },\r\n\r\n // Neutral options\r\n dark: {\r\n gradient:\r\n \"linear-gradient(135deg, rgba(0, 0, 0, 0.4) 0%, rgba(0, 0, 0, 0.2) 100%)\",\r\n accent: \"#1a1a2e\",\r\n border: \"rgba(255, 255, 255, 0.1)\",\r\n glow: \"rgba(0, 0, 0, 0.3)\",\r\n },\r\n light: {\r\n gradient:\r\n \"linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0.05) 100%)\",\r\n accent: \"#ffffff\",\r\n border: \"rgba(255, 255, 255, 0.25)\",\r\n glow: \"rgba(255, 255, 255, 0.3)\",\r\n },\r\n white: {\r\n gradient:\r\n \"linear-gradient(135deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0.08) 100%)\",\r\n accent: \"#ffffff\",\r\n border: \"rgba(255, 255, 255, 0.3)\",\r\n glow: \"rgba(255, 255, 255, 0.4)\",\r\n },\r\n\r\n // Additional shades\r\n electricLight: {\r\n gradient:\r\n \"linear-gradient(135deg, rgba(107, 105, 255, 0.15) 0%, rgba(107, 105, 255, 0.05) 100%)\",\r\n accent: \"#6B69FF\",\r\n border: \"rgba(107, 105, 255, 0.3)\",\r\n glow: \"rgba(107, 105, 255, 0.4)\",\r\n },\r\n purpleLight: {\r\n gradient:\r\n \"linear-gradient(135deg, rgba(180, 141, 255, 0.15) 0%, rgba(180, 141, 255, 0.05) 100%)\",\r\n accent: \"#B48DFF\",\r\n border: \"rgba(180, 141, 255, 0.3)\",\r\n glow: \"rgba(180, 141, 255, 0.4)\",\r\n },\r\n\r\n // No overlay (transparent)\r\n none: {\r\n gradient: \"none\",\r\n accent: \"transparent\",\r\n border: \"rgba(255, 255, 255, 0.1)\",\r\n glow: \"transparent\",\r\n },\r\n} as const;\r\n\r\nexport type GlassColorOverlay = keyof typeof GLASS_COLOR_OVERLAYS;\r\n\r\nexport type GlassAccentPosition = \"top\" | \"left\" | \"right\" | \"bottom\" | \"none\";\r\n\r\nexport interface GlassCardProps {\r\n /** Card title with optional icon */\r\n title?: React.ReactNode;\r\n /** Subtitle text */\r\n subtitle?: React.ReactNode;\r\n /** Color overlay from Zendir brand palette */\r\n colorOverlay?: GlassColorOverlay;\r\n /** Custom color overlay (hex or rgba) */\r\n customOverlay?: {\r\n gradient: string;\r\n accent: string;\r\n border: string;\r\n glow?: string;\r\n };\r\n /**\r\n * Accent color (hex) - auto-generates overlay from this color\r\n * Overrides colorOverlay if provided\r\n * Can be used with CardAccentProvider: accentColor={getAccentColor(title)}\r\n */\r\n accentColor?: string;\r\n /** Position of the accent line/glow */\r\n accentPosition?: GlassAccentPosition;\r\n /** Accent line style */\r\n accentStyle?: \"solid\" | \"gradient\" | \"glow\" | \"dots\";\r\n /** Header icon (rendered before title) */\r\n icon?: React.ReactNode;\r\n /** Header right actions (legend, buttons, etc.) */\r\n actions?: React.ReactNode;\r\n /** Legend items to display in header */\r\n legend?: Array<{ label: string; color: string }>;\r\n /** Status indicator */\r\n status?: StatusLevel;\r\n /** Blur intensity (0-20) */\r\n blur?: number;\r\n /** Background opacity (0-1) */\r\n backgroundOpacity?: number;\r\n /** Enable glow effect on hover */\r\n glowOnHover?: boolean;\r\n /** Children content */\r\n children: React.ReactNode;\r\n /** Custom className */\r\n className?: string;\r\n /** Custom style */\r\n style?: React.CSSProperties;\r\n /** Click handler */\r\n onClick?: () => void;\r\n /** Full height mode */\r\n fullHeight?: boolean;\r\n /** Padding size */\r\n padding?: \"none\" | \"sm\" | \"md\" | \"lg\";\r\n}\r\n\r\n/**\r\n * GlassCard - Glassmorphic card with Zendir brand styling\r\n *\r\n * Features:\r\n * - Transparent blur background\r\n * - Gradient color overlays\r\n * - Accent lines with glow effects\r\n * - Legend support for charts\r\n * - Customizable via props or custom overlay object\r\n */\r\n/**\r\n * Create overlay from accent color hex\r\n */\r\nfunction createOverlayFromColor(color: string) {\r\n // Extract RGB from hex\r\n const hex = color.replace(\"#\", \"\");\r\n const r = parseInt(hex.substring(0, 2), 16);\r\n const g = parseInt(hex.substring(2, 4), 16);\r\n const b = parseInt(hex.substring(4, 6), 16);\r\n\r\n return {\r\n gradient: `linear-gradient(135deg, rgba(${r}, ${g}, ${b}, 0.15) 0%, rgba(${r}, ${g}, ${b}, 0.05) 100%)`,\r\n accent: color,\r\n border: `rgba(${r}, ${g}, ${b}, 0.35)`,\r\n glow: `rgba(${r}, ${g}, ${b}, 0.5)`,\r\n };\r\n}\r\n\r\nexport const GlassCard = memo(function GlassCard({\r\n title,\r\n subtitle,\r\n colorOverlay = \"cyan\",\r\n customOverlay,\r\n accentColor,\r\n accentPosition = \"top\",\r\n accentStyle = \"gradient\",\r\n icon,\r\n actions,\r\n legend,\r\n status,\r\n blur = 12,\r\n backgroundOpacity = 0.85,\r\n glowOnHover = true,\r\n children,\r\n className = \"\",\r\n style,\r\n onClick,\r\n fullHeight = false,\r\n padding = \"md\",\r\n}: GlassCardProps): React.ReactElement {\r\n const { tokens, mode, theme } = useTheme();\r\n const isDark = mode === \"dark\";\r\n const isTransparent =\r\n theme === \"transparent\" ||\r\n theme === \"transparent-bold\" ||\r\n theme === \"transparent-minimal\";\r\n const isBoldVariant = theme === \"transparent-bold\";\r\n const isMinimalVariant = theme === \"transparent-minimal\";\r\n\r\n // Accent styling only for Bold/Minimal themes (or when position explicitly set for non-transparent)\r\n const showAccentStyling = isBoldVariant || isMinimalVariant || !isTransparent;\r\n\r\n // For all transparent themes, default to purple (Zendir accent) instead of cyan\r\n const effectiveColorOverlay =\r\n isTransparent && colorOverlay === \"cyan\" ? \"purple\" : colorOverlay;\r\n\r\n // Get overlay colors (priority: accentColor > customOverlay > colorOverlay)\r\n const overlay = accentColor\r\n ? createOverlayFromColor(accentColor)\r\n : customOverlay || GLASS_COLOR_OVERLAYS[effectiveColorOverlay];\r\n\r\n // Auto-switch to light token for 'white' overlay in light mode\r\n const effectiveOverlay =\r\n mode === \"light\" &&\r\n colorOverlay === \"white\" &&\r\n !accentColor &&\r\n !customOverlay\r\n ? GLASS_COLOR_OVERLAYS.dark\r\n : overlay;\r\n\r\n // Theme-aware background colors\r\n const cardBackground = isDark\r\n ? `rgba(15, 20, 35, ${backgroundOpacity})`\r\n : `rgba(255, 255, 255, ${backgroundOpacity})`;\r\n\r\n // Theme-aware border colors\r\n const baseBorderColor = isDark\r\n ? effectiveOverlay.border\r\n : `rgba(100, 116, 139, 0.25)`;\r\n\r\n const paddingConfig = {\r\n none: \"0\",\r\n sm: tokens.spacing.sm,\r\n md: tokens.spacing.md,\r\n lg: tokens.spacing.lg,\r\n };\r\n\r\n const isInteractive = !!onClick;\r\n\r\n // Accent line styles based on position and style\r\n // Only show accent styling for Bold/Minimal themes (or non-transparent themes)\r\n const getAccentStyles = (): React.CSSProperties => {\r\n // For normal Glass theme, use subtle muted border instead of colored accent\r\n if (isTransparent && !showAccentStyling) {\r\n return {};\r\n }\r\n\r\n if (accentPosition === \"none\") return {};\r\n\r\n const accentColorValue = effectiveOverlay.accent;\r\n const glowColor = effectiveOverlay.glow || accentColorValue;\r\n\r\n const baseAccentStyle: React.CSSProperties = {};\r\n\r\n // Position-based border\r\n const positions: Record<GlassAccentPosition, string> = {\r\n top: \"borderTop\",\r\n left: \"borderLeft\",\r\n right: \"borderRight\",\r\n bottom: \"borderBottom\",\r\n none: \"\",\r\n };\r\n\r\n const borderProp = positions[accentPosition] as keyof React.CSSProperties;\r\n\r\n if (accentStyle === \"solid\") {\r\n (baseAccentStyle as any)[borderProp] = `2px solid ${accentColorValue}`;\r\n } else if (accentStyle === \"gradient\" || accentStyle === \"glow\") {\r\n // Using pseudo-element for gradient, so just set position indicator\r\n (baseAccentStyle as any)[borderProp] = `2px solid ${accentColorValue}`;\r\n if (accentStyle === \"glow\") {\r\n baseAccentStyle.boxShadow = `0 -2px 20px ${glowColor}, 0 -1px 8px ${glowColor}`;\r\n }\r\n } else if (accentStyle === \"dots\") {\r\n (baseAccentStyle as any)[borderProp] = `2px dotted ${accentColorValue}`;\r\n }\r\n\r\n return baseAccentStyle;\r\n };\r\n\r\n // Status color\r\n const statusColor = status ? tokens.colors.status[status] : undefined;\r\n\r\n return (\r\n <div\r\n className={classNames(\r\n \"zendir-glass-card\",\r\n `zendir-glass-card--${colorOverlay}`,\r\n className,\r\n )}\r\n onClick={onClick}\r\n role={isInteractive ? \"button\" : undefined}\r\n tabIndex={isInteractive ? 0 : undefined}\r\n onKeyDown={\r\n onClick\r\n ? (e: React.KeyboardEvent) => {\r\n if (e.key === \"Enter\" || e.key === \" \") {\r\n e.preventDefault();\r\n onClick();\r\n }\r\n }\r\n : undefined\r\n }\r\n style={{\r\n position: \"relative\",\r\n borderRadius: tokens.borderRadius.lg,\r\n overflow: \"hidden\",\r\n height: fullHeight ? \"100%\" : \"auto\",\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n cursor: isInteractive ? \"pointer\" : \"default\",\r\n\r\n // Glassmorphic base (theme-aware)\r\n background: cardBackground,\r\n backdropFilter: isTransparent ? `blur(${blur}px)` : \"none\",\r\n WebkitBackdropFilter: isTransparent ? `blur(${blur}px)` : \"none\",\r\n\r\n // Border with color tint (theme-aware)\r\n border: `1px solid ${baseBorderColor}`,\r\n\r\n // Accent positioning\r\n ...getAccentStyles(),\r\n\r\n // Hover glow effect\r\n transition: \"all 0.3s ease-out\",\r\n boxShadow: glowOnHover ? \"none\" : undefined,\r\n\r\n ...style,\r\n }}\r\n onMouseEnter={(e) => {\r\n if (glowOnHover && effectiveOverlay.glow) {\r\n e.currentTarget.style.boxShadow = `0 0 30px ${effectiveOverlay.glow}, 0 4px 20px rgba(0,0,0,0.3)`;\r\n }\r\n }}\r\n onMouseLeave={(e) => {\r\n if (glowOnHover) {\r\n e.currentTarget.style.boxShadow = \"none\";\r\n }\r\n }}\r\n >\r\n {/* Gradient overlay layer */}\r\n <div\r\n style={{\r\n position: \"absolute\",\r\n inset: 0,\r\n background: effectiveOverlay.gradient,\r\n pointerEvents: \"none\",\r\n zIndex: 0,\r\n }}\r\n />\r\n\r\n {/* Accent glow line (top) - only for Bold/Minimal themes */}\r\n {showAccentStyling &&\r\n accentPosition === \"top\" &&\r\n accentStyle === \"glow\" && (\r\n <div\r\n style={{\r\n position: \"absolute\",\r\n top: 0,\r\n left: \"10%\",\r\n right: \"10%\",\r\n height: \"2px\",\r\n background: `linear-gradient(90deg, transparent, ${effectiveOverlay.accent}, transparent)`,\r\n boxShadow: `0 0 15px ${effectiveOverlay.glow}, 0 0 30px ${effectiveOverlay.glow}`,\r\n zIndex: 1,\r\n }}\r\n />\r\n )}\r\n\r\n {/* Content wrapper */}\r\n <div\r\n style={{\r\n position: \"relative\",\r\n zIndex: 1,\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n flex: 1,\r\n }}\r\n >\r\n {/* Header */}\r\n {(title || actions || legend) && (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"space-between\",\r\n gap: tokens.spacing.md,\r\n padding: `${paddingConfig[padding]} ${paddingConfig[padding]} 0`,\r\n marginBottom: tokens.spacing.sm,\r\n }}\r\n >\r\n {/* Title section */}\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: tokens.spacing.sm,\r\n }}\r\n >\r\n {/* Icon */}\r\n {icon && (\r\n <span\r\n style={{\r\n color: effectiveOverlay.accent,\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n }}\r\n >\r\n {icon}\r\n </span>\r\n )}\r\n\r\n {/* Status shape — Astro UX dual-coded */}\r\n {status &&\r\n statusColor &&\r\n (() => {\r\n const s = 10;\r\n const h = s / 2;\r\n const glow = `drop-shadow(0 0 4px ${statusColor})`;\r\n switch (status) {\r\n case \"critical\":\r\n return (\r\n <svg\r\n width={s}\r\n height={s}\r\n viewBox={`0 0 ${s} ${s}`}\r\n style={{ flexShrink: 0, filter: glow }}\r\n >\r\n <polygon\r\n points={`${h},${s} 0,0 ${s},0`}\r\n fill={statusColor}\r\n />\r\n </svg>\r\n );\r\n case \"serious\":\r\n return (\r\n <svg\r\n width={s}\r\n height={s}\r\n viewBox={`0 0 ${s} ${s}`}\r\n style={{ flexShrink: 0, filter: glow }}\r\n >\r\n <polygon\r\n points={`${h},0 ${s},${h} ${h},${s} 0,${h}`}\r\n fill={statusColor}\r\n />\r\n </svg>\r\n );\r\n case \"caution\":\r\n return (\r\n <svg\r\n width={s}\r\n height={s}\r\n viewBox={`0 0 ${s} ${s}`}\r\n style={{ flexShrink: 0, filter: glow }}\r\n >\r\n <rect width={s} height={s} fill={statusColor} />\r\n </svg>\r\n );\r\n case \"standby\":\r\n return (\r\n <svg\r\n width={s}\r\n height={s}\r\n viewBox=\"0 0 12 12\"\r\n style={{ flexShrink: 0, filter: 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={statusColor}\r\n strokeWidth=\"2\"\r\n />\r\n </svg>\r\n );\r\n case \"off\":\r\n return (\r\n <svg\r\n width={s}\r\n height={s}\r\n viewBox=\"0 0 12 12\"\r\n style={{ flexShrink: 0, filter: glow }}\r\n >\r\n <circle cx=\"6\" cy=\"6\" r=\"3\" fill={statusColor} />\r\n </svg>\r\n );\r\n default: // normal\r\n return (\r\n <svg\r\n width={s}\r\n height={s}\r\n viewBox={`0 0 ${s} ${s}`}\r\n style={{ flexShrink: 0, filter: glow }}\r\n >\r\n <circle cx={h} cy={h} r={h} fill={statusColor} />\r\n </svg>\r\n );\r\n }\r\n })()}\r\n\r\n {/* Title text — card heading system */}\r\n <div>\r\n {title && (\r\n <h3\r\n style={{\r\n margin: 0,\r\n fontSize:\r\n tokens.layout?.card?.heading?.titleFontSize ??\r\n \"1.125rem\",\r\n fontWeight:\r\n tokens.layout?.card?.heading?.titleFontWeight ?? 500,\r\n color: effectiveOverlay.accent,\r\n letterSpacing: \"0.5px\",\r\n textShadow: `0 0 20px ${effectiveOverlay.glow}`,\r\n }}\r\n >\r\n {title}\r\n </h3>\r\n )}\r\n {subtitle && (\r\n <p\r\n style={{\r\n margin: `${tokens.spacing.xs} 0 0`,\r\n fontSize: tokens.typography.body[3].fontSize,\r\n color: tokens.colors.text.secondary,\r\n }}\r\n >\r\n {subtitle}\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Right section: legend + actions */}\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: tokens.spacing.md,\r\n }}\r\n >\r\n {/* Legend items */}\r\n {legend && legend.length > 0 && (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: tokens.spacing.md,\r\n }}\r\n >\r\n {legend.map((item, idx) => (\r\n <div\r\n key={idx}\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: tokens.spacing.xs,\r\n }}\r\n >\r\n <span\r\n style={{\r\n width: \"8px\",\r\n height: \"8px\",\r\n borderRadius: \"2px\",\r\n backgroundColor: item.color,\r\n }}\r\n />\r\n <span\r\n style={{\r\n fontSize: tokens.typography.body[3].fontSize,\r\n color: tokens.colors.text.secondary,\r\n }}\r\n >\r\n {item.label}\r\n </span>\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Actions */}\r\n {actions && (\r\n <div style={{ display: \"flex\", gap: tokens.spacing.xs }}>\r\n {actions}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Accent line - only for Bold/Minimal themes (no decorative dashes) */}\r\n {showAccentStyling && accentPosition === \"top\" && (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n padding: `0 ${paddingConfig[padding]}`,\r\n marginBottom: tokens.spacing.sm,\r\n }}\r\n >\r\n {/* Clean accent line with smooth gradient */}\r\n <div\r\n style={{\r\n flex: 1,\r\n height: \"2px\",\r\n background: `linear-gradient(90deg, ${effectiveOverlay.accent} 0%, ${effectiveOverlay.accent}60 70%, ${effectiveOverlay.accent}20 100%)`,\r\n boxShadow: `0 0 6px ${effectiveOverlay.accent}40`,\r\n }}\r\n />\r\n </div>\r\n )}\r\n\r\n {/* Content */}\r\n <div\r\n style={{\r\n flex: 1,\r\n padding: title\r\n ? `0 ${paddingConfig[padding]} ${paddingConfig[padding]}`\r\n : paddingConfig[padding],\r\n }}\r\n >\r\n {children}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n});\r\n\r\nexport default GlassCard;\r\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HeaderIconWithStatus.js","names":[],"sources":["../../../../src/react/core/display/HeaderIconWithStatus.tsx"],"sourcesContent":["/**\n * @zendir/ui - HeaderIconWithStatus Component\n *\n * Shared component for card/chart header icons with status indicator.\n * Follows MonitoringIcon pattern for Astro UX compliance.\n *\n * Features:\n * - Status indicator positioned at top-left with transform offset\n * - Glow effect in dark mode for visibility\n * - Border in light mode for WCAG AA compliance\n * - Theme-aware colors\n * - Consistent sizing across all usages\n */\n\nimport React, { memo } from \"react\";\nimport { useTheme } from \"../../theme\";\nimport { type StatusLevel } from \"../../utils\";\nimport { AstroIcon, type AstroIconName } from \"./AstroIcon\";\n\n// =============================================================================\n// Astro UX Status Border Colors - Required for light theme WCAG compliance\n// https://www.astrouxds.com/patterns/status-system/\n// =============================================================================\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// Status Shape SVG - Matches MonitoringIcon exactly\n// =============================================================================\n\ninterface StatusShapeProps {\n status: StatusLevel;\n size: number;\n color: string;\n borderColor?: string;\n glow?: boolean;\n}\n\nconst StatusShape = ({\n status,\n size,\n color,\n borderColor,\n glow = true,\n}: StatusShapeProps) => {\n const hasBorder = !!borderColor;\n const strokeWidth = hasBorder ? 1 : 0;\n const glowFilter =\n glow && !hasBorder ? `drop-shadow(0 0 3px ${color})` : undefined;\n\n const renderShape = () => {\n switch (status) {\n case \"off\":\n return (\n <circle\n cx=\"6\"\n cy=\"6\"\n r={hasBorder ? 2.5 : 3}\n fill={color}\n stroke={borderColor}\n strokeWidth={strokeWidth}\n />\n );\n case \"standby\":\n return (\n <circle\n cx=\"6\"\n cy=\"6\"\n r=\"3.5\"\n fill=\"none\"\n stroke={color}\n strokeWidth=\"2\"\n />\n );\n case \"normal\":\n return (\n <circle\n cx=\"6\"\n cy=\"6\"\n r={hasBorder ? 4.5 : 5}\n fill={color}\n stroke={borderColor}\n strokeWidth={strokeWidth}\n />\n );\n case \"caution\":\n return (\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={color}\n stroke={borderColor}\n strokeWidth={strokeWidth}\n />\n );\n case \"serious\":\n return (\n <polygon\n points=\"6,1 11,6 6,11 1,6\"\n fill={color}\n stroke={borderColor}\n strokeWidth={strokeWidth}\n />\n );\n case \"critical\":\n return (\n <polygon\n points=\"6,11 1,2 11,2\"\n fill={color}\n stroke={borderColor}\n strokeWidth={strokeWidth}\n />\n );\n default:\n return null;\n }\n };\n\n return (\n <svg\n viewBox=\"0 0 12 12\"\n width={size}\n height={size}\n style={{ filter: glowFilter }}\n >\n {renderShape()}\n </svg>\n );\n};\n\n// =============================================================================\n// HeaderIconWithStatus Component\n// =============================================================================\n\nexport interface HeaderIconWithStatusProps {\n /** Astro icon name */\n icon: AstroIconName | string;\n /** Icon size in pixels */\n size?: number;\n /** Status level */\n status: StatusLevel;\n /** Custom status color (optional - defaults to theme status color) */\n statusColor?: string;\n /** Override light theme detection */\n isLightTheme?: boolean;\n /** Additional CSS class */\n className?: string;\n /** Additional inline styles */\n style?: React.CSSProperties;\n}\n\n/**\n * HeaderIconWithStatus - Card/Chart header icon with status indicator\n *\n * Follows MonitoringIcon pattern exactly:\n * - Icon colored by status\n * - Status symbol at top-left with transform offset\n * - Glow in dark mode, border in light mode\n *\n * @example\n * ```tsx\n * <HeaderIconWithStatus\n * icon=\"satellite-transmit\"\n * status=\"normal\"\n * size={24}\n * />\n * ```\n */\nexport const HeaderIconWithStatus = memo(function HeaderIconWithStatus({\n icon,\n size = 24,\n status,\n statusColor: statusColorProp,\n isLightTheme: isLightThemeProp,\n className,\n style,\n}: HeaderIconWithStatusProps) {\n const { tokens, mode } = useTheme();\n\n // Theme detection\n const isLightTheme = isLightThemeProp ?? mode === \"light\";\n\n // Status color from theme or prop\n const statusColor =\n statusColorProp ?? tokens.colors.status[status] ?? \"#a4abb6\";\n\n // Border color for light theme (WCAG compliance)\n const borderColor = isLightTheme ? STATUS_BORDER_COLORS[status] : undefined;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // SIZING CONTROLS - Adjust these to match MonitoringIcon proportions\n // ═══════════════════════════════════════════════════════════════════════════\n // Badge size: ~35% of icon size (same ratio as MonitoringIcon's 9px badge on 24px icon)\n const badgeSize = Math.max(7, Math.min(12, Math.round(size * 0.38)));\n\n // Transform offset: translate(-35%, -35%) matches MonitoringIcon exactly\n const transformOffset = \"translate(-35%, -35%)\";\n\n return (\n <div\n role=\"img\"\n aria-label={`${icon} — status: ${status}`}\n className={className}\n style={{\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: size,\n height: size,\n flexShrink: 0,\n color: statusColor,\n ...style,\n }}\n >\n {/* Icon - colored by status */}\n <AstroIcon\n name={icon as AstroIconName}\n size={size}\n color={statusColor}\n aria-hidden=\"true\"\n />\n\n {/* Status symbol - top-left corner with transform offset */}\n <span\n aria-hidden=\"true\"\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n transform: transformOffset,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <StatusShape\n status={status}\n size={badgeSize}\n color={statusColor}\n borderColor={borderColor}\n glow={!isLightTheme}\n />\n </span>\n </div>\n );\n});\n\nexport default HeaderIconWithStatus;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAwBA,IAAM,uBAAoD;CACxD,KAAK;CACL,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,UAAU;AACZ;AAcA,IAAM,eAAe,EACnB,QACA,MACA,OACA,aACA,OAAO,WACe;CACtB,MAAM,YAAY,CAAC,CAAC;CACpB,MAAM,cAAc,YAAY,IAAI;CACpC,MAAM,aACJ,QAAQ,CAAC,YAAY,uBAAuB,MAAM,KAAK,KAAA;CAEzD,MAAM,oBAAoB;EACxB,QAAQ,QAAR;GACE,KAAK,OACH,OACE,oBAAC,UAAD;IACE,IAAG;IACH,IAAG;IACH,GAAG,YAAY,MAAM;IACrB,MAAM;IACN,QAAQ;IACK;GACd,CAAA;GAEL,KAAK,WACH,OACE,oBAAC,UAAD;IACE,IAAG;IACH,IAAG;IACH,GAAE;IACF,MAAK;IACL,QAAQ;IACR,aAAY;GACb,CAAA;GAEL,KAAK,UACH,OACE,oBAAC,UAAD;IACE,IAAG;IACH,IAAG;IACH,GAAG,YAAY,MAAM;IACrB,MAAM;IACN,QAAQ;IACK;GACd,CAAA;GAEL,KAAK,WACH,OACE,oBAAC,QAAD;IACE,GAAG,YAAY,MAAM;IACrB,GAAG,YAAY,MAAM;IACrB,OAAO,YAAY,IAAI;IACvB,QAAQ,YAAY,IAAI;IACxB,MAAM;IACN,QAAQ;IACK;GACd,CAAA;GAEL,KAAK,WACH,OACE,oBAAC,WAAD;IACE,QAAO;IACP,MAAM;IACN,QAAQ;IACK;GACd,CAAA;GAEL,KAAK,YACH,OACE,oBAAC,WAAD;IACE,QAAO;IACP,MAAM;IACN,QAAQ;IACK;GACd,CAAA;GAEL,SACE,OAAO;EACX;CACF;CAEA,OACE,oBAAC,OAAD;EACE,SAAQ;EACR,OAAO;EACP,QAAQ;EACR,OAAO,EAAE,QAAQ,WAAW;YAE3B,YAAY;CACV,CAAA;AAET;;;;;;;;;;;;;;;;;;AAwCA,IAAa,uBAAuB,KAAK,SAAS,qBAAqB,EACrE,MACA,OAAO,IACP,QACA,aAAa,iBACb,cAAc,kBACd,WACA,SAC4B;CAC5B,MAAM,EAAE,QAAQ,SAAS,SAAS;CAGlC,MAAM,eAAe,oBAAoB,SAAS;CAGlD,MAAM,cACJ,mBAAmB,OAAO,OAAO,OAAO,WAAW;CAGrD,MAAM,cAAc,eAAe,qBAAqB,UAAU,KAAA;CAMlE,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,OAAO,GAAI,CAAC,CAAC;CAGnE,MAAM,kBAAkB;CAExB,OACE,qBAAC,OAAD;EACE,MAAK;EACL,cAAY,GAAG,KAAK,aAAa;EACtB;EACX,OAAO;GACL,UAAU;GACV,SAAS;GACT,YAAY;GACZ,gBAAgB;GAChB,OAAO;GACP,QAAQ;GACR,YAAY;GACZ,OAAO;GACP,GAAG;EACL;YAdF,CAiBE,oBAAC,WAAD;GACE,MAAM;GACA;GACN,OAAO;GACP,eAAY;EACb,CAAA,GAGD,oBAAC,QAAD;GACE,eAAY;GACZ,OAAO;IACL,UAAU;IACV,KAAK;IACL,MAAM;IACN,WAAW;IACX,SAAS;IACT,YAAY;IACZ,gBAAgB;GAClB;aAEA,oBAAC,aAAD;IACU;IACR,MAAM;IACN,OAAO;IACM;IACb,MAAM,CAAC;GACR,CAAA;EACG,CAAA,CACH;;AAET,CAAC"}
|
|
1
|
+
{"version":3,"file":"HeaderIconWithStatus.js","names":[],"sources":["../../../../src/react/core/display/HeaderIconWithStatus.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - HeaderIconWithStatus Component\r\n *\r\n * Shared component for card/chart header icons with status indicator.\r\n * Follows MonitoringIcon pattern for Astro UX compliance.\r\n *\r\n * Features:\r\n * - Status indicator positioned at top-left with transform offset\r\n * - Glow effect in dark mode for visibility\r\n * - Border in light mode for WCAG AA compliance\r\n * - Theme-aware colors\r\n * - Consistent sizing across all usages\r\n */\r\n\r\nimport React, { memo } from \"react\";\r\nimport { useTheme } from \"../../theme\";\r\nimport { type StatusLevel } from \"../../utils\";\r\nimport { AstroIcon, type AstroIconName } from \"./AstroIcon\";\r\n\r\n// =============================================================================\r\n// Astro UX Status Border Colors - Required for light theme WCAG compliance\r\n// https://www.astrouxds.com/patterns/status-system/\r\n// =============================================================================\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// Status Shape SVG - Matches MonitoringIcon exactly\r\n// =============================================================================\r\n\r\ninterface StatusShapeProps {\r\n status: StatusLevel;\r\n size: number;\r\n color: string;\r\n borderColor?: string;\r\n glow?: boolean;\r\n}\r\n\r\nconst StatusShape = ({\r\n status,\r\n size,\r\n color,\r\n borderColor,\r\n glow = true,\r\n}: StatusShapeProps) => {\r\n const hasBorder = !!borderColor;\r\n const strokeWidth = hasBorder ? 1 : 0;\r\n const glowFilter =\r\n glow && !hasBorder ? `drop-shadow(0 0 3px ${color})` : undefined;\r\n\r\n const renderShape = () => {\r\n switch (status) {\r\n case \"off\":\r\n return (\r\n <circle\r\n cx=\"6\"\r\n cy=\"6\"\r\n r={hasBorder ? 2.5 : 3}\r\n fill={color}\r\n stroke={borderColor}\r\n strokeWidth={strokeWidth}\r\n />\r\n );\r\n case \"standby\":\r\n return (\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 );\r\n case \"normal\":\r\n return (\r\n <circle\r\n cx=\"6\"\r\n cy=\"6\"\r\n r={hasBorder ? 4.5 : 5}\r\n fill={color}\r\n stroke={borderColor}\r\n strokeWidth={strokeWidth}\r\n />\r\n );\r\n case \"caution\":\r\n return (\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={color}\r\n stroke={borderColor}\r\n strokeWidth={strokeWidth}\r\n />\r\n );\r\n case \"serious\":\r\n return (\r\n <polygon\r\n points=\"6,1 11,6 6,11 1,6\"\r\n fill={color}\r\n stroke={borderColor}\r\n strokeWidth={strokeWidth}\r\n />\r\n );\r\n case \"critical\":\r\n return (\r\n <polygon\r\n points=\"6,11 1,2 11,2\"\r\n fill={color}\r\n stroke={borderColor}\r\n strokeWidth={strokeWidth}\r\n />\r\n );\r\n default:\r\n return null;\r\n }\r\n };\r\n\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 {renderShape()}\r\n </svg>\r\n );\r\n};\r\n\r\n// =============================================================================\r\n// HeaderIconWithStatus Component\r\n// =============================================================================\r\n\r\nexport interface HeaderIconWithStatusProps {\r\n /** Astro icon name */\r\n icon: AstroIconName | string;\r\n /** Icon size in pixels */\r\n size?: number;\r\n /** Status level */\r\n status: StatusLevel;\r\n /** Custom status color (optional - defaults to theme status color) */\r\n statusColor?: string;\r\n /** Override light theme detection */\r\n isLightTheme?: boolean;\r\n /** Additional CSS class */\r\n className?: string;\r\n /** Additional inline styles */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/**\r\n * HeaderIconWithStatus - Card/Chart header icon with status indicator\r\n *\r\n * Follows MonitoringIcon pattern exactly:\r\n * - Icon colored by status\r\n * - Status symbol at top-left with transform offset\r\n * - Glow in dark mode, border in light mode\r\n *\r\n * @example\r\n * ```tsx\r\n * <HeaderIconWithStatus\r\n * icon=\"satellite-transmit\"\r\n * status=\"normal\"\r\n * size={24}\r\n * />\r\n * ```\r\n */\r\nexport const HeaderIconWithStatus = memo(function HeaderIconWithStatus({\r\n icon,\r\n size = 24,\r\n status,\r\n statusColor: statusColorProp,\r\n isLightTheme: isLightThemeProp,\r\n className,\r\n style,\r\n}: HeaderIconWithStatusProps) {\r\n const { tokens, mode } = useTheme();\r\n\r\n // Theme detection\r\n const isLightTheme = isLightThemeProp ?? mode === \"light\";\r\n\r\n // Status color from theme or prop\r\n const statusColor =\r\n statusColorProp ?? tokens.colors.status[status] ?? \"#a4abb6\";\r\n\r\n // Border color for light theme (WCAG compliance)\r\n const borderColor = isLightTheme ? STATUS_BORDER_COLORS[status] : undefined;\r\n\r\n // ═══════════════════════════════════════════════════════════════════════════\r\n // SIZING CONTROLS - Adjust these to match MonitoringIcon proportions\r\n // ═══════════════════════════════════════════════════════════════════════════\r\n // Badge size: ~35% of icon size (same ratio as MonitoringIcon's 9px badge on 24px icon)\r\n const badgeSize = Math.max(7, Math.min(12, Math.round(size * 0.38)));\r\n\r\n // Transform offset: translate(-35%, -35%) matches MonitoringIcon exactly\r\n const transformOffset = \"translate(-35%, -35%)\";\r\n\r\n return (\r\n <div\r\n role=\"img\"\r\n aria-label={`${icon} — status: ${status}`}\r\n className={className}\r\n style={{\r\n position: \"relative\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n width: size,\r\n height: size,\r\n flexShrink: 0,\r\n color: statusColor,\r\n ...style,\r\n }}\r\n >\r\n {/* Icon - colored by status */}\r\n <AstroIcon\r\n name={icon as AstroIconName}\r\n size={size}\r\n color={statusColor}\r\n aria-hidden=\"true\"\r\n />\r\n\r\n {/* Status symbol - top-left corner with transform offset */}\r\n <span\r\n aria-hidden=\"true\"\r\n style={{\r\n position: \"absolute\",\r\n top: 0,\r\n left: 0,\r\n transform: transformOffset,\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n }}\r\n >\r\n <StatusShape\r\n status={status}\r\n size={badgeSize}\r\n color={statusColor}\r\n borderColor={borderColor}\r\n glow={!isLightTheme}\r\n />\r\n </span>\r\n </div>\r\n );\r\n});\r\n\r\nexport default HeaderIconWithStatus;\r\n"],"mappings":";;;;;;;;;;;;;;;;;;AAwBA,IAAM,uBAAoD;CACxD,KAAK;CACL,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,UAAU;AACZ;AAcA,IAAM,eAAe,EACnB,QACA,MACA,OACA,aACA,OAAO,WACe;CACtB,MAAM,YAAY,CAAC,CAAC;CACpB,MAAM,cAAc,YAAY,IAAI;CACpC,MAAM,aACJ,QAAQ,CAAC,YAAY,uBAAuB,MAAM,KAAK,KAAA;CAEzD,MAAM,oBAAoB;EACxB,QAAQ,QAAR;GACE,KAAK,OACH,OACE,oBAAC,UAAD;IACE,IAAG;IACH,IAAG;IACH,GAAG,YAAY,MAAM;IACrB,MAAM;IACN,QAAQ;IACK;GACd,CAAA;GAEL,KAAK,WACH,OACE,oBAAC,UAAD;IACE,IAAG;IACH,IAAG;IACH,GAAE;IACF,MAAK;IACL,QAAQ;IACR,aAAY;GACb,CAAA;GAEL,KAAK,UACH,OACE,oBAAC,UAAD;IACE,IAAG;IACH,IAAG;IACH,GAAG,YAAY,MAAM;IACrB,MAAM;IACN,QAAQ;IACK;GACd,CAAA;GAEL,KAAK,WACH,OACE,oBAAC,QAAD;IACE,GAAG,YAAY,MAAM;IACrB,GAAG,YAAY,MAAM;IACrB,OAAO,YAAY,IAAI;IACvB,QAAQ,YAAY,IAAI;IACxB,MAAM;IACN,QAAQ;IACK;GACd,CAAA;GAEL,KAAK,WACH,OACE,oBAAC,WAAD;IACE,QAAO;IACP,MAAM;IACN,QAAQ;IACK;GACd,CAAA;GAEL,KAAK,YACH,OACE,oBAAC,WAAD;IACE,QAAO;IACP,MAAM;IACN,QAAQ;IACK;GACd,CAAA;GAEL,SACE,OAAO;EACX;CACF;CAEA,OACE,oBAAC,OAAD;EACE,SAAQ;EACR,OAAO;EACP,QAAQ;EACR,OAAO,EAAE,QAAQ,WAAW;YAE3B,YAAY;CACV,CAAA;AAET;;;;;;;;;;;;;;;;;;AAwCA,IAAa,uBAAuB,KAAK,SAAS,qBAAqB,EACrE,MACA,OAAO,IACP,QACA,aAAa,iBACb,cAAc,kBACd,WACA,SAC4B;CAC5B,MAAM,EAAE,QAAQ,SAAS,SAAS;CAGlC,MAAM,eAAe,oBAAoB,SAAS;CAGlD,MAAM,cACJ,mBAAmB,OAAO,OAAO,OAAO,WAAW;CAGrD,MAAM,cAAc,eAAe,qBAAqB,UAAU,KAAA;CAMlE,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,OAAO,GAAI,CAAC,CAAC;CAGnE,MAAM,kBAAkB;CAExB,OACE,qBAAC,OAAD;EACE,MAAK;EACL,cAAY,GAAG,KAAK,aAAa;EACtB;EACX,OAAO;GACL,UAAU;GACV,SAAS;GACT,YAAY;GACZ,gBAAgB;GAChB,OAAO;GACP,QAAQ;GACR,YAAY;GACZ,OAAO;GACP,GAAG;EACL;YAdF,CAiBE,oBAAC,WAAD;GACE,MAAM;GACA;GACN,OAAO;GACP,eAAY;EACb,CAAA,GAGD,oBAAC,QAAD;GACE,eAAY;GACZ,OAAO;IACL,UAAU;IACV,KAAK;IACL,MAAM;IACN,WAAW;IACX,SAAS;IACT,YAAY;IACZ,gBAAgB;GAClB;aAEA,oBAAC,aAAD;IACU;IACR,MAAM;IACN,OAAO;IACM;IACb,MAAM,CAAC;GACR,CAAA;EACG,CAAA,CACH;;AAET,CAAC"}
|