@zendir/ui 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.md +419 -406
  2. package/dist/react/3d/CesiumCaptureSource.js.map +1 -1
  3. package/dist/react/3d/ZenSpace3D.js.map +1 -1
  4. package/dist/react/3d/ZenSpace3DCesium.js.map +1 -1
  5. package/dist/react/3d/ZenSpace3DShaders.js.map +1 -1
  6. package/dist/react/3d/ZenSpace3DUtils.js.map +1 -1
  7. package/dist/react/3d/capturePngAnalysis.js.map +1 -1
  8. package/dist/react/3d/threeLoader.js.map +1 -1
  9. package/dist/react/astro/ClassificationBanner.js.map +1 -1
  10. package/dist/react/astro/GlobalStatusBar.js.map +1 -1
  11. package/dist/react/astro/MissionClock.js.map +1 -1
  12. package/dist/react/astro/MonitoringIcon.js.map +1 -1
  13. package/dist/react/astro/Notification.js.map +1 -1
  14. package/dist/react/astro/Progress.js.map +1 -1
  15. package/dist/react/astro/SimulationControls.js.map +1 -1
  16. package/dist/react/astro/StatusIndicator.js.map +1 -1
  17. package/dist/react/astro/UnifiedTimeline.js.map +1 -1
  18. package/dist/react/cards/AccessCard.js.map +1 -1
  19. package/dist/react/cards/OrbitCard.js.map +1 -1
  20. package/dist/react/cards/SpacecraftCard.js.map +1 -1
  21. package/dist/react/cards/TelemetryCard.js.map +1 -1
  22. package/dist/react/cards/TelemetryStreamCard.js.map +1 -1
  23. package/dist/react/charts/GroundTrackMap.js.map +1 -1
  24. package/dist/react/charts/GroundTrackMapLeaflet.js.map +1 -1
  25. package/dist/react/charts/groundTrackMapLeafletTiles.js.map +1 -1
  26. package/dist/react/charts/groundTrackMapLeafletUtils.js.map +1 -1
  27. package/dist/react/charts/unified/AstroChart.js.map +1 -1
  28. package/dist/react/charts/unified/PowerOverviewChart.js.map +1 -1
  29. package/dist/react/charts/unified/domain.js.map +1 -1
  30. package/dist/react/charts/unified/generators.js.map +1 -1
  31. package/dist/react/charts/unified/presets.js.map +1 -1
  32. package/dist/react/charts/unified/sync.js.map +1 -1
  33. package/dist/react/charts/unified/theme.js.map +1 -1
  34. package/dist/react/charts/unified/useChartStream.js.map +1 -1
  35. package/dist/react/chatgpt/index.js.map +1 -1
  36. package/dist/react/context/CategoryContext.js.map +1 -1
  37. package/dist/react/context/DisplaySettingsContext.js.map +1 -1
  38. package/dist/react/context/SpatialSelectionContext.js.map +1 -1
  39. package/dist/react/core/data/DataTable.js.map +1 -1
  40. package/dist/react/core/data/DataValue.js.map +1 -1
  41. package/dist/react/core/data/propertyConfig.js.map +1 -1
  42. package/dist/react/core/display/AstroIcon.js.map +1 -1
  43. package/dist/react/core/display/Badge.js.map +1 -1
  44. package/dist/react/core/display/CardHeader.js.map +1 -1
  45. package/dist/react/core/display/Container.js.map +1 -1
  46. package/dist/react/core/display/CopyButton.js.map +1 -1
  47. package/dist/react/core/display/GlassCard.js.map +1 -1
  48. package/dist/react/core/display/HeaderIconWithStatus.js.map +1 -1
  49. package/dist/react/core/display/Icon.js.map +1 -1
  50. package/dist/react/core/display/Typography.js.map +1 -1
  51. package/dist/react/core/feedback/ConfirmDialog.js.map +1 -1
  52. package/dist/react/core/feedback/Dialog.js.map +1 -1
  53. package/dist/react/core/feedback/Toast.js.map +1 -1
  54. package/dist/react/core/inputs/Button.js.map +1 -1
  55. package/dist/react/core/inputs/Checkbox.js.map +1 -1
  56. package/dist/react/core/inputs/Input.js.map +1 -1
  57. package/dist/react/core/inputs/LimitsBar.js.map +1 -1
  58. package/dist/react/core/inputs/NumberInput.js.map +1 -1
  59. package/dist/react/core/inputs/PinInput.js.map +1 -1
  60. package/dist/react/core/inputs/Select.js.map +1 -1
  61. package/dist/react/core/inputs/Toggle.js.map +1 -1
  62. package/dist/react/core/layout/Box.js.map +1 -1
  63. package/dist/react/core/layout/Center.js.map +1 -1
  64. package/dist/react/core/layout/Divider.js.map +1 -1
  65. package/dist/react/core/layout/Flex.js.map +1 -1
  66. package/dist/react/core/layout/Grid.js.map +1 -1
  67. package/dist/react/core/layout/Spacer.js.map +1 -1
  68. package/dist/react/core/layout/Stack.js.map +1 -1
  69. package/dist/react/core/layout/responsive.js.map +1 -1
  70. package/dist/react/core/layout/useBreakpoint.js.map +1 -1
  71. package/dist/react/core/navigation/AppBar.js.map +1 -1
  72. package/dist/react/core/navigation/Pagination.js.map +1 -1
  73. package/dist/react/core/navigation/SideNav.js.map +1 -1
  74. package/dist/react/core/navigation/Tabs.js.map +1 -1
  75. package/dist/react/core/overlays/Popover.js.map +1 -1
  76. package/dist/react/core/overlays/SidePanel.js.map +1 -1
  77. package/dist/react/core/overlays/Tooltip.js.map +1 -1
  78. package/dist/react/core/widgets/ActivityPlanner.js.map +1 -1
  79. package/dist/react/core/widgets/Capture.js.map +1 -1
  80. package/dist/react/core/widgets/ChatPanel.js.map +1 -1
  81. package/dist/react/core/widgets/ColorPickerPanel.js.map +1 -1
  82. package/dist/react/core/widgets/CommandBuilder.js.map +1 -1
  83. package/dist/react/core/widgets/ConnectionForm.js.map +1 -1
  84. package/dist/react/core/widgets/FileExplorer.js.map +1 -1
  85. package/dist/react/core/widgets/HexViewer.js.map +1 -1
  86. package/dist/react/core/widgets/ImageFrame.js.map +1 -1
  87. package/dist/react/core/widgets/ImageGallery.js.map +1 -1
  88. package/dist/react/core/widgets/ImagePanel.js.map +1 -1
  89. package/dist/react/core/widgets/LogViewer.js.map +1 -1
  90. package/dist/react/core/widgets/MessageStream.js.map +1 -1
  91. package/dist/react/core/widgets/MissionCalendar.js.map +1 -1
  92. package/dist/react/core/widgets/PacketViewer.js.map +1 -1
  93. package/dist/react/hooks/useCompactMode.js.map +1 -1
  94. package/dist/react/hooks/useSimulationScene.js.map +1 -1
  95. package/dist/react/panels/LayerControlPanel.js.map +1 -1
  96. package/dist/react/panels/ObjectInventoryPanel.js.map +1 -1
  97. package/dist/react/shared/ErrorBoundary.js.map +1 -1
  98. package/dist/react/shared/Skeleton.js.map +1 -1
  99. package/dist/react/theme/ThemeProvider.js +2 -1
  100. package/dist/react/theme/ThemeProvider.js.map +1 -1
  101. package/dist/react/theme/cardAccent.js.map +1 -1
  102. package/dist/react/theme/config.js.map +1 -1
  103. package/dist/react/theme/types.js.map +1 -1
  104. package/dist/react/types.js.map +1 -1
  105. package/dist/react/utils/categoryPalette.js.map +1 -1
  106. package/dist/react/utils/index.js.map +1 -1
  107. package/dist/style.css +216 -216
  108. package/dist/tokens/core.js.map +1 -1
  109. package/dist/tokens/index.js.map +1 -1
  110. package/dist/tokens/palettes/astro.js.map +1 -1
  111. package/dist/tokens/palettes/index.js.map +1 -1
  112. package/dist/tokens/palettes/tailwind.js.map +1 -1
  113. package/dist/tokens/palettes/zendir.js.map +1 -1
  114. package/dist/tokens/themes.js.map +1 -1
  115. package/dist/tokens/tokens.css +533 -533
  116. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"DataTable.js","names":[],"sources":["../../../../src/react/core/data/DataTable.tsx"],"sourcesContent":["/**\n * @zendir/ui - DataTable Component\n *\n * Structured data display with expandable groups, responsive columns,\n * and theme-aware styling. Designed for telemetry parameter grids,\n * link budget displays, spacecraft information panels.\n *\n * Astro UX Compliance:\n * - Tabular monospace numbers for value columns\n * - Status-based row coloring\n * - Compact mode support\n * - Accessible table semantics\n *\n * Enhanced Tooltip System:\n * - Row-level tooltips (string or rich ReactNode via rowTooltipContent)\n * - Cell-level tooltips per column definition\n * - Header tooltips for column descriptions\n * - Built-in DataTableRowDetail component for structured detail views\n * - Portal-rendered, WCAG-compliant, animated tooltips\n *\n * @example\n * ```tsx\n * <DataTable\n * columns={[\n * { key: 'label', header: 'Parameter', width: '40%', headerTooltip: 'Telemetry parameter name' },\n * { key: 'value', header: 'Value', align: 'right', mono: true, cellTooltip: (v, row) => `Raw: ${v}` },\n * { key: 'unit', header: 'Unit', width: 80 },\n * ]}\n * data={[\n * { label: 'Frequency', value: '437.500', unit: 'MHz' },\n * { label: 'Bandwidth', value: '25.000', unit: 'kHz' },\n * ]}\n * rowTooltipContent={(row) => (\n * <DataTableRowDetail\n * title={row.label}\n * fields={[\n * { label: 'Value', value: `${row.value} ${row.unit}` },\n * ]}\n * />\n * )}\n * />\n * ```\n */\n\nimport React, { memo, useState, useCallback, useMemo } from \"react\";\nimport { useTheme } from \"../../theme\";\nimport { useBreakpoint } from \"../layout/useBreakpoint\";\nimport { Tooltip } from \"../overlays/Tooltip\";\nimport type { TooltipPlacement } from \"../overlays/Tooltip\";\nimport { addAlpha } from \"../../utils\";\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport interface DataTableColumn<T = Record<string, unknown>> {\n /** Key in data object */\n key: string;\n /** Column header text */\n header: string;\n /** Column width (CSS value or number for px) */\n width?: string | number;\n /** Text alignment */\n align?: \"left\" | \"center\" | \"right\";\n /** Use monospace font (good for numbers) */\n mono?: boolean;\n /** Custom cell renderer */\n render?: (value: unknown, row: T, index: number) => React.ReactNode;\n /** Hide column on mobile */\n hideOnMobile?: boolean;\n /** Tooltip for the column header (explains what this column represents) */\n headerTooltip?: string;\n /** Per-cell tooltip — return string or ReactNode, or undefined to skip */\n cellTooltip?: (\n value: unknown,\n row: T,\n index: number,\n ) => React.ReactNode | undefined;\n}\n\nexport interface DataTableProps<T = Record<string, unknown>> {\n /** Column definitions */\n columns: DataTableColumn<T>[];\n /** Data rows */\n data: T[];\n /** Key field for React keys (default: index) */\n keyField?: string;\n /** Group rows by this field */\n groupBy?: string;\n /** Allow expanding/collapsing groups */\n expandable?: boolean;\n /** Default expanded state for groups */\n defaultExpanded?: boolean;\n /** Striped rows */\n striped?: boolean;\n /** Compact row padding */\n compact?: boolean;\n /** Show header row */\n showHeader?: boolean;\n /** Empty state message */\n emptyMessage?: string;\n /** Row click handler */\n onRowClick?: (row: T, index: number) => void;\n /** Simple string tooltip for each row (legacy — uses native title) */\n rowTooltip?: (row: T) => string | undefined;\n /** Rich tooltip content for each row — renders in a portal-based Tooltip */\n rowTooltipContent?: (row: T, index: number) => React.ReactNode | undefined;\n /** Placement for row and cell tooltips (default: 'top') */\n tooltipPlacement?: TooltipPlacement;\n /** Delay before tooltips appear in ms (default: 300) */\n tooltipDelay?: number;\n /** Max height with scroll */\n maxHeight?: string | number;\n /** Color for boolean ✓/✗ values (e.g. '#fff' for white). Defaults to text.primary or row status. */\n booleanColor?: string;\n /** Optional row status key or getter — boolean cells use this row's status color when set (matches white/status design). */\n getRowStatus?: (\n row: T,\n index: number,\n ) =>\n | \"normal\"\n | \"caution\"\n | \"serious\"\n | \"critical\"\n | \"standby\"\n | \"off\"\n | undefined;\n /** Custom style */\n style?: React.CSSProperties;\n}\n\n// ─── DataTableRowDetail ──────────────────────────────────────────────────────\n\nexport interface DataTableRowDetailField {\n /** Field label */\n label: string;\n /** Field value (string, number, or ReactNode for custom rendering) */\n value: React.ReactNode;\n /** Optional status color for the value */\n status?: \"normal\" | \"caution\" | \"serious\" | \"critical\" | \"standby\" | \"off\";\n /** Use monospace font for this value */\n mono?: boolean;\n}\n\nexport interface DataTableRowDetailProps {\n /** Title shown at the top of the tooltip */\n title?: React.ReactNode;\n /** Optional subtitle / secondary info */\n subtitle?: React.ReactNode;\n /** Structured key-value fields to display */\n fields?: DataTableRowDetailField[];\n /** Optional footer content (timestamps, actions, etc.) */\n footer?: React.ReactNode;\n /** Optional icon or status indicator beside the title */\n icon?: React.ReactNode;\n /** Maximum width of the tooltip (default: 320) */\n maxWidth?: number;\n}\n\n/**\n * Pre-built tooltip content renderer for DataTable rows.\n * Provides a structured layout: title, key-value fields, and optional footer.\n *\n * @example\n * ```tsx\n * <DataTable\n * columns={columns}\n * data={data}\n * rowTooltipContent={(row) => (\n * <DataTableRowDetail\n * title={row.parameter}\n * subtitle={row.category}\n * fields={[\n * { label: 'Value', value: row.value, mono: true },\n * { label: 'Status', value: row.status, status: row.status },\n * ]}\n * footer={`Last updated: ${row.timestamp}`}\n * />\n * )}\n * />\n * ```\n */\nexport const DataTableRowDetail = memo(function DataTableRowDetail({\n title,\n subtitle,\n fields,\n footer,\n icon,\n maxWidth = 320,\n}: DataTableRowDetailProps): React.ReactElement {\n const { tokens } = useTheme();\n\n return (\n <div style={{ maxWidth, minWidth: 180 }}>\n {/* Header */}\n {(title || icon) && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: tokens.spacing.sm,\n marginBottom: fields?.length || subtitle ? tokens.spacing.sm : 0,\n }}\n >\n {icon}\n <div style={{ flex: 1, minWidth: 0 }}>\n {title && (\n <div\n style={{\n fontWeight: tokens.typography.fontWeight.semibold,\n fontSize: tokens.typography.fontSize.sm,\n color: tokens.colors.text.primary,\n lineHeight: 1.3,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {title}\n </div>\n )}\n {subtitle && (\n <div\n style={{\n fontSize: tokens.typography.fontSize.xxs,\n color: tokens.colors.text.tertiary,\n marginTop: 2,\n }}\n >\n {subtitle}\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* Fields */}\n {fields && fields.length > 0 && (\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: \"auto 1fr\",\n gap: `${tokens.spacing.xs} ${tokens.spacing.md}`,\n fontSize: tokens.typography.fontSize.xs,\n lineHeight: 1.5,\n }}\n >\n {fields.map((field, i) => (\n <React.Fragment key={i}>\n <span\n style={{\n color: tokens.colors.text.tertiary,\n whiteSpace: \"nowrap\",\n }}\n >\n {field.label}\n </span>\n <span\n style={{\n color: field.status\n ? tokens.colors.status[field.status] ||\n tokens.colors.text.primary\n : tokens.colors.text.primary,\n fontFamily: field.mono\n ? tokens.typography.fontFamily.mono\n : \"inherit\",\n fontVariantNumeric: field.mono ? \"tabular-nums\" : \"normal\",\n textAlign: \"right\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {field.value}\n </span>\n </React.Fragment>\n ))}\n </div>\n )}\n\n {/* Footer */}\n {footer && (\n <div\n style={{\n marginTop: tokens.spacing.sm,\n paddingTop: tokens.spacing.xs,\n borderTop: `1px solid ${addAlpha(tokens.colors.border.muted, 0.19)}`,\n fontSize: tokens.typography.fontSize.xxs,\n color: tokens.colors.text.tertiary,\n }}\n >\n {footer}\n </div>\n )}\n </div>\n );\n});\n\n// ─── Cell Tooltip Wrapper ────────────────────────────────────────────────────\n\ninterface CellTooltipWrapperProps {\n content: React.ReactNode;\n placement: TooltipPlacement;\n delay: number;\n children: React.ReactElement;\n}\n\nconst CellTooltipWrapper = memo(function CellTooltipWrapper({\n content,\n placement,\n delay,\n children,\n}: CellTooltipWrapperProps): React.ReactElement {\n if (!content) return children;\n return (\n <Tooltip content={content} placement={placement} delay={delay}>\n {children}\n </Tooltip>\n );\n});\n\n// ─── DataTable ───────────────────────────────────────────────────────────────\n\nexport const DataTable = memo(function DataTable<\n T extends Record<string, unknown>,\n>({\n columns,\n data,\n keyField,\n groupBy,\n expandable = false,\n defaultExpanded = true,\n striped = false,\n compact = false,\n showHeader = true,\n emptyMessage = \"No data available\",\n onRowClick,\n rowTooltip,\n rowTooltipContent,\n tooltipPlacement = \"top\",\n tooltipDelay = 300,\n maxHeight,\n booleanColor,\n getRowStatus,\n style,\n}: DataTableProps<T>): React.ReactElement {\n const { tokens } = useTheme();\n const { isMobile: isMobileView } = useBreakpoint();\n const statusColorMap = useMemo(\n () => ({\n normal: tokens.colors.status.normal,\n caution: tokens.colors.status.caution,\n serious: tokens.colors.status.serious,\n critical: tokens.colors.status.critical,\n standby: tokens.colors.status.standby,\n off: tokens.colors.status.off,\n }),\n [tokens.colors.status],\n );\n const visibleColumns = isMobileView\n ? columns.filter((col) => !col.hideOnMobile)\n : columns;\n\n const [expandedGroups, setExpandedGroups] = useState<Set<string>>(\n defaultExpanded ? new Set([\"__all__\"]) : new Set(),\n );\n const [hoveredRow, setHoveredRow] = useState<number | null>(null);\n const visibleColumnCount = Math.max(1, visibleColumns.length);\n\n const cellPadding = compact\n ? `${tokens.spacing.xs} ${tokens.spacing.sm}`\n : `${tokens.spacing.sm} ${tokens.spacing.md}`;\n\n const toggleGroup = useCallback((group: string) => {\n setExpandedGroups((prev) => {\n const next = new Set(prev);\n if (next.has(group)) next.delete(group);\n else next.add(group);\n return next;\n });\n }, []);\n\n const isGroupExpanded = useCallback(\n (group: string) => {\n return expandedGroups.has(\"__all__\") || expandedGroups.has(group);\n },\n [expandedGroups],\n );\n\n const groups = useMemo(() => {\n if (!groupBy) return [{ key: \"__default__\", label: \"\", rows: data }];\n\n const map = new Map<string, T[]>();\n data.forEach((row) => {\n const key = String((row as Record<string, unknown>)[groupBy] ?? \"Other\");\n if (!map.has(key)) map.set(key, []);\n map.get(key)!.push(row);\n });\n\n return Array.from(map.entries()).map(([key, rows]) => ({\n key,\n label: key,\n rows,\n }));\n }, [data, groupBy]);\n\n const resolveWidth = (w: string | number | undefined): string | undefined => {\n if (w === undefined) return undefined;\n if (typeof w === \"number\") return `${w}px`;\n return w;\n };\n\n const renderCell = (col: DataTableColumn<T>, row: T, rowIndex: number) => {\n const value = row[col.key];\n if (col.render) return col.render(value, row, rowIndex);\n if (value === null || value === undefined) return \"—\";\n if (typeof value === \"boolean\") {\n const label = value ? \"✓\" : \"✗\";\n const color =\n booleanColor ??\n (getRowStatus\n ? (() => {\n const s = getRowStatus(row, rowIndex);\n return s ? statusColorMap[s] : undefined;\n })()\n : undefined) ??\n tokens.colors.text.primary;\n return <span style={{ color }}>{label}</span>;\n }\n return String(value);\n };\n\n const renderCellWithTooltip = (\n col: DataTableColumn<T>,\n row: T,\n rowIndex: number,\n ) => {\n const cellContent = renderCell(col, row, rowIndex);\n if (!col.cellTooltip) return cellContent;\n\n const tooltipContent = col.cellTooltip(row[col.key], row, rowIndex);\n if (!tooltipContent) return cellContent;\n\n return (\n <CellTooltipWrapper\n content={tooltipContent}\n placement={tooltipPlacement}\n delay={tooltipDelay}\n >\n <span style={{ cursor: \"help\" }}>{cellContent}</span>\n </CellTooltipWrapper>\n );\n };\n\n const renderHeaderCell = (col: DataTableColumn<T>) => {\n const headerContent = (\n <span style={{ display: \"inline-flex\", alignItems: \"center\", gap: 4 }}>\n {col.header}\n {col.headerTooltip && (\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n style={{ opacity: 0.5, flexShrink: 0 }}\n >\n <circle\n cx=\"8\"\n cy=\"8\"\n r=\"7\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M8 7v4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <circle cx=\"8\" cy=\"5\" r=\"0.75\" fill=\"currentColor\" />\n </svg>\n )}\n </span>\n );\n\n if (!col.headerTooltip) return headerContent;\n\n return (\n <Tooltip\n content={col.headerTooltip}\n placement=\"bottom\"\n delay={tooltipDelay}\n >\n {headerContent}\n </Tooltip>\n );\n };\n\n const chevron = (expanded: boolean) => (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n style={{\n transition: tokens.animation.fast,\n transform: expanded ? \"rotate(90deg)\" : \"rotate(0deg)\",\n flexShrink: 0,\n }}\n >\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n );\n\n const hasRichRowTooltip = !!rowTooltipContent;\n\n const renderRowContent = (row: T, rowIdx: number, localIndex: number) => {\n const isHovered = hoveredRow === rowIdx;\n const rowKey = keyField ? String(row[keyField]) : rowIdx;\n const useNativeTitle = !hasRichRowTooltip && rowTooltip;\n\n const tr = (\n <tr\n key={rowKey}\n tabIndex={onRowClick ? 0 : undefined}\n onClick={onRowClick ? () => onRowClick(row, rowIdx) : undefined}\n onKeyDown={\n onRowClick\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onRowClick(row, rowIdx);\n }\n }\n : undefined\n }\n onMouseEnter={() => setHoveredRow(rowIdx)}\n onMouseLeave={() => setHoveredRow(null)}\n title={useNativeTitle ? rowTooltip(row) : undefined}\n style={{\n cursor: onRowClick ? \"pointer\" : \"default\",\n backgroundColor: isHovered\n ? addAlpha(tokens.colors.accent.primary, 0.08)\n : striped && localIndex % 2 === 1\n ? addAlpha(tokens.colors.background.surface, 0.5)\n : \"transparent\",\n transition: \"background-color 150ms ease\",\n }}\n >\n {visibleColumns.map((col) => (\n <td\n key={col.key}\n style={{\n padding: cellPadding,\n textAlign: col.align || \"left\",\n color: tokens.colors.text.primary,\n borderBottom: `1px solid ${addAlpha(tokens.colors.border.muted, 0.08)}`,\n fontFamily: col.mono\n ? tokens.typography.fontFamily.mono\n : \"inherit\",\n fontVariantNumeric: col.mono ? \"tabular-nums\" : \"normal\",\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: resolveWidth(col.width) || \"300px\",\n }}\n >\n {renderCellWithTooltip(col, row, rowIdx)}\n </td>\n ))}\n </tr>\n );\n\n if (hasRichRowTooltip) {\n const tooltipContent = rowTooltipContent(row, rowIdx);\n if (tooltipContent) {\n return (\n <Tooltip\n key={rowKey}\n content={tooltipContent}\n placement={tooltipPlacement}\n delay={tooltipDelay}\n >\n {tr}\n </Tooltip>\n );\n }\n }\n\n return tr;\n };\n\n let globalRowIndex = 0;\n\n return (\n <div\n style={{\n fontFamily: tokens.typography.fontFamily.primary,\n overflow: \"auto\",\n WebkitOverflowScrolling: \"touch\",\n maxHeight: typeof maxHeight === \"number\" ? `${maxHeight}px` : maxHeight,\n borderRadius: tokens.borderRadius.md,\n border: tokens.borders.divider,\n ...style,\n }}\n >\n <table\n style={{\n width: \"100%\",\n borderCollapse: \"collapse\",\n fontSize: compact\n ? tokens.typography.fontSize.xs\n : tokens.typography.fontSize.sm,\n }}\n >\n {showHeader && (\n <thead>\n <tr>\n {visibleColumns.map((col) => (\n <th\n key={col.key}\n style={{\n padding: cellPadding,\n textAlign: col.align || \"left\",\n fontSize: tokens.typography.fontSize.xxs,\n fontWeight: tokens.typography.fontWeight.bold,\n color: tokens.colors.text.tertiary,\n textTransform: \"uppercase\",\n letterSpacing: \"0.06em\",\n backgroundColor: tokens.colors.background.surface,\n borderBottom: tokens.borders.divider,\n width: resolveWidth(col.width),\n position: \"sticky\",\n top: 0,\n zIndex: 1,\n whiteSpace: \"nowrap\",\n }}\n >\n {renderHeaderCell(col)}\n </th>\n ))}\n </tr>\n </thead>\n )}\n\n <tbody>\n {data.length === 0 && (\n <tr>\n <td\n colSpan={visibleColumnCount}\n style={{\n padding: tokens.spacing.xl,\n textAlign: \"center\",\n color: tokens.colors.text.tertiary,\n fontSize: tokens.typography.fontSize.sm,\n }}\n >\n {emptyMessage}\n </td>\n </tr>\n )}\n\n {groups.map((group) => {\n const isExpanded = !groupBy || isGroupExpanded(group.key);\n\n return (\n <React.Fragment key={group.key}>\n {groupBy && group.label && (\n <tr\n style={{\n backgroundColor: addAlpha(\n tokens.colors.accent.primary,\n 0.08,\n ),\n }}\n >\n <td\n colSpan={visibleColumnCount}\n style={{\n padding: 0,\n borderBottom: tokens.borders.divider,\n }}\n >\n {expandable ? (\n <button\n type=\"button\"\n aria-expanded={isExpanded}\n onClick={() => toggleGroup(group.key)}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: tokens.spacing.xs,\n width: \"100%\",\n padding: cellPadding,\n margin: 0,\n border: \"none\",\n background: \"none\",\n cursor: \"pointer\",\n fontWeight: tokens.typography.fontWeight.semibold,\n color: tokens.colors.text.primary,\n fontSize: compact\n ? tokens.typography.fontSize.xs\n : tokens.typography.fontSize.sm,\n fontFamily: \"inherit\",\n textAlign: \"left\",\n }}\n >\n {chevron(isExpanded)}\n {group.label}\n <span\n style={{\n fontSize: tokens.typography.fontSize.xxs,\n color: tokens.colors.text.tertiary,\n fontWeight: tokens.typography.fontWeight.normal,\n }}\n >\n ({group.rows.length})\n </span>\n </button>\n ) : (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: tokens.spacing.xs,\n padding: cellPadding,\n fontWeight: tokens.typography.fontWeight.semibold,\n color: tokens.colors.text.primary,\n fontSize: compact\n ? tokens.typography.fontSize.xs\n : tokens.typography.fontSize.sm,\n }}\n >\n {group.label}\n <span\n style={{\n fontSize: tokens.typography.fontSize.xxs,\n color: tokens.colors.text.tertiary,\n fontWeight: tokens.typography.fontWeight.normal,\n }}\n >\n ({group.rows.length})\n </span>\n </div>\n )}\n </td>\n </tr>\n )}\n\n {isExpanded &&\n group.rows.map((row, localIndex) => {\n const rowIdx = globalRowIndex++;\n return renderRowContent(row, rowIdx, localIndex);\n })}\n </React.Fragment>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n}) as <T extends Record<string, unknown>>(\n props: DataTableProps<T>,\n) => React.ReactElement;\n\nexport default DataTable;\n"],"mappings":"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"}
1
+ {"version":3,"file":"DataTable.js","names":[],"sources":["../../../../src/react/core/data/DataTable.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - DataTable Component\r\n *\r\n * Structured data display with expandable groups, responsive columns,\r\n * and theme-aware styling. Designed for telemetry parameter grids,\r\n * link budget displays, spacecraft information panels.\r\n *\r\n * Astro UX Compliance:\r\n * - Tabular monospace numbers for value columns\r\n * - Status-based row coloring\r\n * - Compact mode support\r\n * - Accessible table semantics\r\n *\r\n * Enhanced Tooltip System:\r\n * - Row-level tooltips (string or rich ReactNode via rowTooltipContent)\r\n * - Cell-level tooltips per column definition\r\n * - Header tooltips for column descriptions\r\n * - Built-in DataTableRowDetail component for structured detail views\r\n * - Portal-rendered, WCAG-compliant, animated tooltips\r\n *\r\n * @example\r\n * ```tsx\r\n * <DataTable\r\n * columns={[\r\n * { key: 'label', header: 'Parameter', width: '40%', headerTooltip: 'Telemetry parameter name' },\r\n * { key: 'value', header: 'Value', align: 'right', mono: true, cellTooltip: (v, row) => `Raw: ${v}` },\r\n * { key: 'unit', header: 'Unit', width: 80 },\r\n * ]}\r\n * data={[\r\n * { label: 'Frequency', value: '437.500', unit: 'MHz' },\r\n * { label: 'Bandwidth', value: '25.000', unit: 'kHz' },\r\n * ]}\r\n * rowTooltipContent={(row) => (\r\n * <DataTableRowDetail\r\n * title={row.label}\r\n * fields={[\r\n * { label: 'Value', value: `${row.value} ${row.unit}` },\r\n * ]}\r\n * />\r\n * )}\r\n * />\r\n * ```\r\n */\r\n\r\nimport React, { memo, useState, useCallback, useMemo } from \"react\";\r\nimport { useTheme } from \"../../theme\";\r\nimport { useBreakpoint } from \"../layout/useBreakpoint\";\r\nimport { Tooltip } from \"../overlays/Tooltip\";\r\nimport type { TooltipPlacement } from \"../overlays/Tooltip\";\r\nimport { addAlpha } from \"../../utils\";\r\n\r\n// ─── Types ───────────────────────────────────────────────────────────────────\r\n\r\nexport interface DataTableColumn<T = Record<string, unknown>> {\r\n /** Key in data object */\r\n key: string;\r\n /** Column header text */\r\n header: string;\r\n /** Column width (CSS value or number for px) */\r\n width?: string | number;\r\n /** Text alignment */\r\n align?: \"left\" | \"center\" | \"right\";\r\n /** Use monospace font (good for numbers) */\r\n mono?: boolean;\r\n /** Custom cell renderer */\r\n render?: (value: unknown, row: T, index: number) => React.ReactNode;\r\n /** Hide column on mobile */\r\n hideOnMobile?: boolean;\r\n /** Tooltip for the column header (explains what this column represents) */\r\n headerTooltip?: string;\r\n /** Per-cell tooltip — return string or ReactNode, or undefined to skip */\r\n cellTooltip?: (\r\n value: unknown,\r\n row: T,\r\n index: number,\r\n ) => React.ReactNode | undefined;\r\n}\r\n\r\nexport interface DataTableProps<T = Record<string, unknown>> {\r\n /** Column definitions */\r\n columns: DataTableColumn<T>[];\r\n /** Data rows */\r\n data: T[];\r\n /** Key field for React keys (default: index) */\r\n keyField?: string;\r\n /** Group rows by this field */\r\n groupBy?: string;\r\n /** Allow expanding/collapsing groups */\r\n expandable?: boolean;\r\n /** Default expanded state for groups */\r\n defaultExpanded?: boolean;\r\n /** Striped rows */\r\n striped?: boolean;\r\n /** Compact row padding */\r\n compact?: boolean;\r\n /** Show header row */\r\n showHeader?: boolean;\r\n /** Empty state message */\r\n emptyMessage?: string;\r\n /** Row click handler */\r\n onRowClick?: (row: T, index: number) => void;\r\n /** Simple string tooltip for each row (legacy — uses native title) */\r\n rowTooltip?: (row: T) => string | undefined;\r\n /** Rich tooltip content for each row — renders in a portal-based Tooltip */\r\n rowTooltipContent?: (row: T, index: number) => React.ReactNode | undefined;\r\n /** Placement for row and cell tooltips (default: 'top') */\r\n tooltipPlacement?: TooltipPlacement;\r\n /** Delay before tooltips appear in ms (default: 300) */\r\n tooltipDelay?: number;\r\n /** Max height with scroll */\r\n maxHeight?: string | number;\r\n /** Color for boolean ✓/✗ values (e.g. '#fff' for white). Defaults to text.primary or row status. */\r\n booleanColor?: string;\r\n /** Optional row status key or getter — boolean cells use this row's status color when set (matches white/status design). */\r\n getRowStatus?: (\r\n row: T,\r\n index: number,\r\n ) =>\r\n | \"normal\"\r\n | \"caution\"\r\n | \"serious\"\r\n | \"critical\"\r\n | \"standby\"\r\n | \"off\"\r\n | undefined;\r\n /** Custom style */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n// ─── DataTableRowDetail ──────────────────────────────────────────────────────\r\n\r\nexport interface DataTableRowDetailField {\r\n /** Field label */\r\n label: string;\r\n /** Field value (string, number, or ReactNode for custom rendering) */\r\n value: React.ReactNode;\r\n /** Optional status color for the value */\r\n status?: \"normal\" | \"caution\" | \"serious\" | \"critical\" | \"standby\" | \"off\";\r\n /** Use monospace font for this value */\r\n mono?: boolean;\r\n}\r\n\r\nexport interface DataTableRowDetailProps {\r\n /** Title shown at the top of the tooltip */\r\n title?: React.ReactNode;\r\n /** Optional subtitle / secondary info */\r\n subtitle?: React.ReactNode;\r\n /** Structured key-value fields to display */\r\n fields?: DataTableRowDetailField[];\r\n /** Optional footer content (timestamps, actions, etc.) */\r\n footer?: React.ReactNode;\r\n /** Optional icon or status indicator beside the title */\r\n icon?: React.ReactNode;\r\n /** Maximum width of the tooltip (default: 320) */\r\n maxWidth?: number;\r\n}\r\n\r\n/**\r\n * Pre-built tooltip content renderer for DataTable rows.\r\n * Provides a structured layout: title, key-value fields, and optional footer.\r\n *\r\n * @example\r\n * ```tsx\r\n * <DataTable\r\n * columns={columns}\r\n * data={data}\r\n * rowTooltipContent={(row) => (\r\n * <DataTableRowDetail\r\n * title={row.parameter}\r\n * subtitle={row.category}\r\n * fields={[\r\n * { label: 'Value', value: row.value, mono: true },\r\n * { label: 'Status', value: row.status, status: row.status },\r\n * ]}\r\n * footer={`Last updated: ${row.timestamp}`}\r\n * />\r\n * )}\r\n * />\r\n * ```\r\n */\r\nexport const DataTableRowDetail = memo(function DataTableRowDetail({\r\n title,\r\n subtitle,\r\n fields,\r\n footer,\r\n icon,\r\n maxWidth = 320,\r\n}: DataTableRowDetailProps): React.ReactElement {\r\n const { tokens } = useTheme();\r\n\r\n return (\r\n <div style={{ maxWidth, minWidth: 180 }}>\r\n {/* Header */}\r\n {(title || icon) && (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: tokens.spacing.sm,\r\n marginBottom: fields?.length || subtitle ? tokens.spacing.sm : 0,\r\n }}\r\n >\r\n {icon}\r\n <div style={{ flex: 1, minWidth: 0 }}>\r\n {title && (\r\n <div\r\n style={{\r\n fontWeight: tokens.typography.fontWeight.semibold,\r\n fontSize: tokens.typography.fontSize.sm,\r\n color: tokens.colors.text.primary,\r\n lineHeight: 1.3,\r\n overflow: \"hidden\",\r\n textOverflow: \"ellipsis\",\r\n }}\r\n >\r\n {title}\r\n </div>\r\n )}\r\n {subtitle && (\r\n <div\r\n style={{\r\n fontSize: tokens.typography.fontSize.xxs,\r\n color: tokens.colors.text.tertiary,\r\n marginTop: 2,\r\n }}\r\n >\r\n {subtitle}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Fields */}\r\n {fields && fields.length > 0 && (\r\n <div\r\n style={{\r\n display: \"grid\",\r\n gridTemplateColumns: \"auto 1fr\",\r\n gap: `${tokens.spacing.xs} ${tokens.spacing.md}`,\r\n fontSize: tokens.typography.fontSize.xs,\r\n lineHeight: 1.5,\r\n }}\r\n >\r\n {fields.map((field, i) => (\r\n <React.Fragment key={i}>\r\n <span\r\n style={{\r\n color: tokens.colors.text.tertiary,\r\n whiteSpace: \"nowrap\",\r\n }}\r\n >\r\n {field.label}\r\n </span>\r\n <span\r\n style={{\r\n color: field.status\r\n ? tokens.colors.status[field.status] ||\r\n tokens.colors.text.primary\r\n : tokens.colors.text.primary,\r\n fontFamily: field.mono\r\n ? tokens.typography.fontFamily.mono\r\n : \"inherit\",\r\n fontVariantNumeric: field.mono ? \"tabular-nums\" : \"normal\",\r\n textAlign: \"right\",\r\n overflow: \"hidden\",\r\n textOverflow: \"ellipsis\",\r\n whiteSpace: \"nowrap\",\r\n }}\r\n >\r\n {field.value}\r\n </span>\r\n </React.Fragment>\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Footer */}\r\n {footer && (\r\n <div\r\n style={{\r\n marginTop: tokens.spacing.sm,\r\n paddingTop: tokens.spacing.xs,\r\n borderTop: `1px solid ${addAlpha(tokens.colors.border.muted, 0.19)}`,\r\n fontSize: tokens.typography.fontSize.xxs,\r\n color: tokens.colors.text.tertiary,\r\n }}\r\n >\r\n {footer}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n});\r\n\r\n// ─── Cell Tooltip Wrapper ────────────────────────────────────────────────────\r\n\r\ninterface CellTooltipWrapperProps {\r\n content: React.ReactNode;\r\n placement: TooltipPlacement;\r\n delay: number;\r\n children: React.ReactElement;\r\n}\r\n\r\nconst CellTooltipWrapper = memo(function CellTooltipWrapper({\r\n content,\r\n placement,\r\n delay,\r\n children,\r\n}: CellTooltipWrapperProps): React.ReactElement {\r\n if (!content) return children;\r\n return (\r\n <Tooltip content={content} placement={placement} delay={delay}>\r\n {children}\r\n </Tooltip>\r\n );\r\n});\r\n\r\n// ─── DataTable ───────────────────────────────────────────────────────────────\r\n\r\nexport const DataTable = memo(function DataTable<\r\n T extends Record<string, unknown>,\r\n>({\r\n columns,\r\n data,\r\n keyField,\r\n groupBy,\r\n expandable = false,\r\n defaultExpanded = true,\r\n striped = false,\r\n compact = false,\r\n showHeader = true,\r\n emptyMessage = \"No data available\",\r\n onRowClick,\r\n rowTooltip,\r\n rowTooltipContent,\r\n tooltipPlacement = \"top\",\r\n tooltipDelay = 300,\r\n maxHeight,\r\n booleanColor,\r\n getRowStatus,\r\n style,\r\n}: DataTableProps<T>): React.ReactElement {\r\n const { tokens } = useTheme();\r\n const { isMobile: isMobileView } = useBreakpoint();\r\n const statusColorMap = useMemo(\r\n () => ({\r\n normal: tokens.colors.status.normal,\r\n caution: tokens.colors.status.caution,\r\n serious: tokens.colors.status.serious,\r\n critical: tokens.colors.status.critical,\r\n standby: tokens.colors.status.standby,\r\n off: tokens.colors.status.off,\r\n }),\r\n [tokens.colors.status],\r\n );\r\n const visibleColumns = isMobileView\r\n ? columns.filter((col) => !col.hideOnMobile)\r\n : columns;\r\n\r\n const [expandedGroups, setExpandedGroups] = useState<Set<string>>(\r\n defaultExpanded ? new Set([\"__all__\"]) : new Set(),\r\n );\r\n const [hoveredRow, setHoveredRow] = useState<number | null>(null);\r\n const visibleColumnCount = Math.max(1, visibleColumns.length);\r\n\r\n const cellPadding = compact\r\n ? `${tokens.spacing.xs} ${tokens.spacing.sm}`\r\n : `${tokens.spacing.sm} ${tokens.spacing.md}`;\r\n\r\n const toggleGroup = useCallback((group: string) => {\r\n setExpandedGroups((prev) => {\r\n const next = new Set(prev);\r\n if (next.has(group)) next.delete(group);\r\n else next.add(group);\r\n return next;\r\n });\r\n }, []);\r\n\r\n const isGroupExpanded = useCallback(\r\n (group: string) => {\r\n return expandedGroups.has(\"__all__\") || expandedGroups.has(group);\r\n },\r\n [expandedGroups],\r\n );\r\n\r\n const groups = useMemo(() => {\r\n if (!groupBy) return [{ key: \"__default__\", label: \"\", rows: data }];\r\n\r\n const map = new Map<string, T[]>();\r\n data.forEach((row) => {\r\n const key = String((row as Record<string, unknown>)[groupBy] ?? \"Other\");\r\n if (!map.has(key)) map.set(key, []);\r\n map.get(key)!.push(row);\r\n });\r\n\r\n return Array.from(map.entries()).map(([key, rows]) => ({\r\n key,\r\n label: key,\r\n rows,\r\n }));\r\n }, [data, groupBy]);\r\n\r\n const resolveWidth = (w: string | number | undefined): string | undefined => {\r\n if (w === undefined) return undefined;\r\n if (typeof w === \"number\") return `${w}px`;\r\n return w;\r\n };\r\n\r\n const renderCell = (col: DataTableColumn<T>, row: T, rowIndex: number) => {\r\n const value = row[col.key];\r\n if (col.render) return col.render(value, row, rowIndex);\r\n if (value === null || value === undefined) return \"—\";\r\n if (typeof value === \"boolean\") {\r\n const label = value ? \"✓\" : \"✗\";\r\n const color =\r\n booleanColor ??\r\n (getRowStatus\r\n ? (() => {\r\n const s = getRowStatus(row, rowIndex);\r\n return s ? statusColorMap[s] : undefined;\r\n })()\r\n : undefined) ??\r\n tokens.colors.text.primary;\r\n return <span style={{ color }}>{label}</span>;\r\n }\r\n return String(value);\r\n };\r\n\r\n const renderCellWithTooltip = (\r\n col: DataTableColumn<T>,\r\n row: T,\r\n rowIndex: number,\r\n ) => {\r\n const cellContent = renderCell(col, row, rowIndex);\r\n if (!col.cellTooltip) return cellContent;\r\n\r\n const tooltipContent = col.cellTooltip(row[col.key], row, rowIndex);\r\n if (!tooltipContent) return cellContent;\r\n\r\n return (\r\n <CellTooltipWrapper\r\n content={tooltipContent}\r\n placement={tooltipPlacement}\r\n delay={tooltipDelay}\r\n >\r\n <span style={{ cursor: \"help\" }}>{cellContent}</span>\r\n </CellTooltipWrapper>\r\n );\r\n };\r\n\r\n const renderHeaderCell = (col: DataTableColumn<T>) => {\r\n const headerContent = (\r\n <span style={{ display: \"inline-flex\", alignItems: \"center\", gap: 4 }}>\r\n {col.header}\r\n {col.headerTooltip && (\r\n <svg\r\n width=\"12\"\r\n height=\"12\"\r\n viewBox=\"0 0 16 16\"\r\n fill=\"none\"\r\n style={{ opacity: 0.5, flexShrink: 0 }}\r\n >\r\n <circle\r\n cx=\"8\"\r\n cy=\"8\"\r\n r=\"7\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"1.5\"\r\n />\r\n <path\r\n d=\"M8 7v4\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"1.5\"\r\n strokeLinecap=\"round\"\r\n />\r\n <circle cx=\"8\" cy=\"5\" r=\"0.75\" fill=\"currentColor\" />\r\n </svg>\r\n )}\r\n </span>\r\n );\r\n\r\n if (!col.headerTooltip) return headerContent;\r\n\r\n return (\r\n <Tooltip\r\n content={col.headerTooltip}\r\n placement=\"bottom\"\r\n delay={tooltipDelay}\r\n >\r\n {headerContent}\r\n </Tooltip>\r\n );\r\n };\r\n\r\n const chevron = (expanded: boolean) => (\r\n <svg\r\n width=\"14\"\r\n height=\"14\"\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 style={{\r\n transition: tokens.animation.fast,\r\n transform: expanded ? \"rotate(90deg)\" : \"rotate(0deg)\",\r\n flexShrink: 0,\r\n }}\r\n >\r\n <polyline points=\"9 18 15 12 9 6\" />\r\n </svg>\r\n );\r\n\r\n const hasRichRowTooltip = !!rowTooltipContent;\r\n\r\n const renderRowContent = (row: T, rowIdx: number, localIndex: number) => {\r\n const isHovered = hoveredRow === rowIdx;\r\n const rowKey = keyField ? String(row[keyField]) : rowIdx;\r\n const useNativeTitle = !hasRichRowTooltip && rowTooltip;\r\n\r\n const tr = (\r\n <tr\r\n key={rowKey}\r\n tabIndex={onRowClick ? 0 : undefined}\r\n onClick={onRowClick ? () => onRowClick(row, rowIdx) : undefined}\r\n onKeyDown={\r\n onRowClick\r\n ? (e) => {\r\n if (e.key === \"Enter\" || e.key === \" \") {\r\n e.preventDefault();\r\n onRowClick(row, rowIdx);\r\n }\r\n }\r\n : undefined\r\n }\r\n onMouseEnter={() => setHoveredRow(rowIdx)}\r\n onMouseLeave={() => setHoveredRow(null)}\r\n title={useNativeTitle ? rowTooltip(row) : undefined}\r\n style={{\r\n cursor: onRowClick ? \"pointer\" : \"default\",\r\n backgroundColor: isHovered\r\n ? addAlpha(tokens.colors.accent.primary, 0.08)\r\n : striped && localIndex % 2 === 1\r\n ? addAlpha(tokens.colors.background.surface, 0.5)\r\n : \"transparent\",\r\n transition: \"background-color 150ms ease\",\r\n }}\r\n >\r\n {visibleColumns.map((col) => (\r\n <td\r\n key={col.key}\r\n style={{\r\n padding: cellPadding,\r\n textAlign: col.align || \"left\",\r\n color: tokens.colors.text.primary,\r\n borderBottom: `1px solid ${addAlpha(tokens.colors.border.muted, 0.08)}`,\r\n fontFamily: col.mono\r\n ? tokens.typography.fontFamily.mono\r\n : \"inherit\",\r\n fontVariantNumeric: col.mono ? \"tabular-nums\" : \"normal\",\r\n whiteSpace: \"nowrap\",\r\n overflow: \"hidden\",\r\n textOverflow: \"ellipsis\",\r\n maxWidth: resolveWidth(col.width) || \"300px\",\r\n }}\r\n >\r\n {renderCellWithTooltip(col, row, rowIdx)}\r\n </td>\r\n ))}\r\n </tr>\r\n );\r\n\r\n if (hasRichRowTooltip) {\r\n const tooltipContent = rowTooltipContent(row, rowIdx);\r\n if (tooltipContent) {\r\n return (\r\n <Tooltip\r\n key={rowKey}\r\n content={tooltipContent}\r\n placement={tooltipPlacement}\r\n delay={tooltipDelay}\r\n >\r\n {tr}\r\n </Tooltip>\r\n );\r\n }\r\n }\r\n\r\n return tr;\r\n };\r\n\r\n let globalRowIndex = 0;\r\n\r\n return (\r\n <div\r\n style={{\r\n fontFamily: tokens.typography.fontFamily.primary,\r\n overflow: \"auto\",\r\n WebkitOverflowScrolling: \"touch\",\r\n maxHeight: typeof maxHeight === \"number\" ? `${maxHeight}px` : maxHeight,\r\n borderRadius: tokens.borderRadius.md,\r\n border: tokens.borders.divider,\r\n ...style,\r\n }}\r\n >\r\n <table\r\n style={{\r\n width: \"100%\",\r\n borderCollapse: \"collapse\",\r\n fontSize: compact\r\n ? tokens.typography.fontSize.xs\r\n : tokens.typography.fontSize.sm,\r\n }}\r\n >\r\n {showHeader && (\r\n <thead>\r\n <tr>\r\n {visibleColumns.map((col) => (\r\n <th\r\n key={col.key}\r\n style={{\r\n padding: cellPadding,\r\n textAlign: col.align || \"left\",\r\n fontSize: tokens.typography.fontSize.xxs,\r\n fontWeight: tokens.typography.fontWeight.bold,\r\n color: tokens.colors.text.tertiary,\r\n textTransform: \"uppercase\",\r\n letterSpacing: \"0.06em\",\r\n backgroundColor: tokens.colors.background.surface,\r\n borderBottom: tokens.borders.divider,\r\n width: resolveWidth(col.width),\r\n position: \"sticky\",\r\n top: 0,\r\n zIndex: 1,\r\n whiteSpace: \"nowrap\",\r\n }}\r\n >\r\n {renderHeaderCell(col)}\r\n </th>\r\n ))}\r\n </tr>\r\n </thead>\r\n )}\r\n\r\n <tbody>\r\n {data.length === 0 && (\r\n <tr>\r\n <td\r\n colSpan={visibleColumnCount}\r\n style={{\r\n padding: tokens.spacing.xl,\r\n textAlign: \"center\",\r\n color: tokens.colors.text.tertiary,\r\n fontSize: tokens.typography.fontSize.sm,\r\n }}\r\n >\r\n {emptyMessage}\r\n </td>\r\n </tr>\r\n )}\r\n\r\n {groups.map((group) => {\r\n const isExpanded = !groupBy || isGroupExpanded(group.key);\r\n\r\n return (\r\n <React.Fragment key={group.key}>\r\n {groupBy && group.label && (\r\n <tr\r\n style={{\r\n backgroundColor: addAlpha(\r\n tokens.colors.accent.primary,\r\n 0.08,\r\n ),\r\n }}\r\n >\r\n <td\r\n colSpan={visibleColumnCount}\r\n style={{\r\n padding: 0,\r\n borderBottom: tokens.borders.divider,\r\n }}\r\n >\r\n {expandable ? (\r\n <button\r\n type=\"button\"\r\n aria-expanded={isExpanded}\r\n onClick={() => toggleGroup(group.key)}\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: tokens.spacing.xs,\r\n width: \"100%\",\r\n padding: cellPadding,\r\n margin: 0,\r\n border: \"none\",\r\n background: \"none\",\r\n cursor: \"pointer\",\r\n fontWeight: tokens.typography.fontWeight.semibold,\r\n color: tokens.colors.text.primary,\r\n fontSize: compact\r\n ? tokens.typography.fontSize.xs\r\n : tokens.typography.fontSize.sm,\r\n fontFamily: \"inherit\",\r\n textAlign: \"left\",\r\n }}\r\n >\r\n {chevron(isExpanded)}\r\n {group.label}\r\n <span\r\n style={{\r\n fontSize: tokens.typography.fontSize.xxs,\r\n color: tokens.colors.text.tertiary,\r\n fontWeight: tokens.typography.fontWeight.normal,\r\n }}\r\n >\r\n ({group.rows.length})\r\n </span>\r\n </button>\r\n ) : (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: tokens.spacing.xs,\r\n padding: cellPadding,\r\n fontWeight: tokens.typography.fontWeight.semibold,\r\n color: tokens.colors.text.primary,\r\n fontSize: compact\r\n ? tokens.typography.fontSize.xs\r\n : tokens.typography.fontSize.sm,\r\n }}\r\n >\r\n {group.label}\r\n <span\r\n style={{\r\n fontSize: tokens.typography.fontSize.xxs,\r\n color: tokens.colors.text.tertiary,\r\n fontWeight: tokens.typography.fontWeight.normal,\r\n }}\r\n >\r\n ({group.rows.length})\r\n </span>\r\n </div>\r\n )}\r\n </td>\r\n </tr>\r\n )}\r\n\r\n {isExpanded &&\r\n group.rows.map((row, localIndex) => {\r\n const rowIdx = globalRowIndex++;\r\n return renderRowContent(row, rowIdx, localIndex);\r\n })}\r\n </React.Fragment>\r\n );\r\n })}\r\n </tbody>\r\n </table>\r\n </div>\r\n );\r\n}) as <T extends Record<string, unknown>>(\r\n props: DataTableProps<T>,\r\n) => React.ReactElement;\r\n\r\nexport default DataTable;\r\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"DataValue.js","names":[],"sources":["../../../../src/react/core/data/DataValue.tsx"],"sourcesContent":["/**\n * @zendir/ui - DataValue Component\n *\n * Enterprise-grade data value display with icon, label, value, and status.\n * The building block for telemetry displays, dashboards, and monitoring UIs.\n *\n * AstroUXDS Compliance:\n * - Status colors per AstroUXDS status system\n * - Dual-coding (color + shape) for accessibility via StatusIndicator\n * - Tabular numbers for alignment\n * - Sentence-case labels\n *\n * Features:\n * - Auto-derive status from value + thresholds\n * - Contextual icons from property presets\n * - Multiple layout variants (stacked, inline, compact)\n * - Theme-aware styling\n *\n * @example\n * ```tsx\n * import { DataValue } from '@zendir/ui';\n *\n * // Simple usage with property preset\n * <DataValue property=\"temperature\" value={72.5} />\n *\n * // Custom configuration\n * <DataValue\n * label=\"Battery\"\n * value={85}\n * unit=\"%\"\n * icon=\"battery-full\"\n * thresholds={{ critical: 10, caution: 30 }}\n * />\n *\n * // Inline layout\n * <DataValue property=\"voltage\" value={28.4} variant=\"inline\" />\n * ```\n */\n\nimport React, { memo, useMemo } from \"react\";\nimport { useTheme } from \"../../theme\";\nimport { AstroIcon, type AstroIconName } from \"../display/AstroIcon\";\nimport {\n getPropertyConfig,\n deriveStatus,\n formatPropertyValue,\n type PropertyKey,\n type StatusThresholds,\n type PropertyConfig,\n} from \"./propertyConfig\";\nimport type { StatusLevel } from \"../../utils\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type DataValueVariant =\n | \"stacked\"\n | \"inline\"\n | \"compact\"\n | \"minimal\"\n | \"card\"\n | \"banner\"\n | \"stat\";\nexport type DataValueSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface DataValueProps {\n /** Property key for auto-configuration (e.g., 'temperature', 'battery') */\n property?: PropertyKey;\n /** Display label (overrides property preset) */\n label?: string;\n /** Current value */\n value: number | string | undefined | null;\n /** Unit of measurement (overrides property preset) */\n unit?: string;\n /** Icon name (overrides property preset) */\n icon?: AstroIconName;\n /** Show icon */\n showIcon?: boolean;\n /** Status thresholds for auto-derivation (overrides property preset) */\n thresholds?: StatusThresholds;\n /** Override status (bypasses auto-derivation) */\n status?: StatusLevel;\n /** Show status indicator */\n showStatus?: boolean;\n /** Precision for number formatting (overrides property preset) */\n precision?: number;\n /** Layout variant */\n variant?: DataValueVariant;\n /** Size */\n size?: DataValueSize;\n /** Custom value color (overrides status color) */\n color?: string;\n /** Additional CSS class */\n className?: string;\n /** Custom inline styles */\n style?: React.CSSProperties;\n /** Click handler */\n onClick?: () => void;\n /** Tooltip text */\n tooltip?: string;\n}\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// - Glow effect in dark mode for visibility\n// - Border in light mode for WCAG AA compliance\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// Icon with Status Badge - Enterprise-grade alignment\n//\n// Design System Principles (Apple HIG / Google Material / AstroUXDS):\n// - 4px-based spacing grid for visual harmony\n// - Explicit container sizing prevents layout shift\n// - Status badge positioned at corner, not extending beyond container bounds\n// - Proportional badge sizing: ~35% of icon size for optimal visibility\n// =============================================================================\n\ninterface IconWithBadgeProps {\n icon: AstroIconName;\n iconSize: number;\n iconColor: string;\n showBadge: boolean;\n status: StatusLevel;\n statusColor: string;\n isLightTheme?: boolean;\n}\n\nconst IconWithBadge = memo(function IconWithBadge({\n icon,\n iconSize,\n iconColor,\n showBadge,\n status,\n statusColor,\n isLightTheme = false,\n}: IconWithBadgeProps) {\n // ═══════════════════════════════════════════════════════════════════════════\n // STATUS BADGE CONTROLS\n // ═══════════════════════════════════════════════════════════════════════════\n // BADGE SIZE: Percentage of icon size (0.25 = 25%)\n const badgeSizeRatio = 0.3;\n const badgeSize = Math.max(\n 7,\n Math.min(14, Math.round(iconSize * badgeSizeRatio)),\n );\n\n // BADGE POSITION: Offset from top-left corner (negative = away from icon)\n const badgeOffsetX = -2; // px (negative = left, positive = right)\n const badgeOffsetY = -2; // px (negative = up, positive = down)\n\n // ═══════════════════════════════════════════════════════════════════════════\n const borderColor = isLightTheme ? STATUS_BORDER_COLORS[status] : undefined;\n const containerSize = iconSize;\n\n return (\n <div\n style={{\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flexShrink: 0,\n width: containerSize,\n height: containerSize,\n }}\n >\n <AstroIcon name={icon} size={iconSize} color={iconColor} />\n {showBadge && (\n <span\n style={{\n position: \"absolute\",\n top: badgeOffsetY,\n left: badgeOffsetX,\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 )}\n </div>\n );\n});\n\n// =============================================================================\n// DataValue Component\n// =============================================================================\n\nexport const DataValue = memo(function DataValue({\n property,\n label: labelProp,\n value,\n unit: unitProp,\n icon: iconProp,\n showIcon = true,\n thresholds: thresholdsProp,\n status: statusProp,\n showStatus = true,\n precision: precisionProp,\n variant = \"stacked\",\n size = \"md\",\n color: colorProp,\n className = \"\",\n style,\n onClick,\n tooltip,\n}: DataValueProps): React.ReactElement {\n const { tokens, mode } = useTheme();\n const isLightTheme = mode === \"light\";\n\n // Merge property preset with explicit props\n const config = useMemo((): PropertyConfig => {\n const preset = property\n ? getPropertyConfig(property)\n : {\n label: labelProp || \"Value\",\n icon: iconProp || \"info\",\n unit: unitProp,\n precision: precisionProp,\n thresholds: thresholdsProp,\n };\n\n return {\n ...preset,\n ...(labelProp !== undefined && { label: labelProp }),\n ...(iconProp !== undefined && { icon: iconProp }),\n ...(unitProp !== undefined && { unit: unitProp }),\n ...(precisionProp !== undefined && { precision: precisionProp }),\n ...(thresholdsProp !== undefined && { thresholds: thresholdsProp }),\n };\n }, [property, labelProp, iconProp, unitProp, precisionProp, thresholdsProp]);\n\n // Derive or use explicit status\n const status = useMemo((): StatusLevel => {\n if (statusProp) return statusProp;\n if (typeof value === \"number\") {\n return deriveStatus(value, config.thresholds);\n }\n return \"normal\";\n }, [statusProp, value, config.thresholds]);\n\n // Format the value\n const formattedValue = useMemo((): string => {\n if (value === undefined || value === null) return \"--\";\n if (typeof value === \"string\") return value;\n return formatPropertyValue(value, config);\n }, [value, config]);\n\n // Get status color\n const statusColor = tokens.colors.status[status] || tokens.colors.status.off;\n const valueColor =\n colorProp ||\n (showStatus && status !== \"normal\"\n ? statusColor\n : tokens.colors.text.primary);\n\n // ==========================================================================\n // Size Configuration - Uses theme tokens for consistency with other cards\n // ==========================================================================\n // Typography uses theme tokens to match SpacecraftCard's DataCell\n // fontSize.xs = 10px (0.625rem), fontSize.sm = 12px (0.75rem)\n const sizeConfig = {\n sm: {\n iconSize: 16,\n labelSize: tokens.typography.fontSize.xs, // 10px - matches DataCell\n valueSize: tokens.typography.fontSize.sm, // 12px - matches DataCell\n lineHeight: 1.4,\n gap: 6, // Increased from 4px to 6px for better icon separation with larger icons\n rowGap: 2, // 2px between label and value\n },\n md: {\n iconSize: 20,\n labelSize: tokens.typography.fontSize.xs, // 10px\n valueSize: tokens.typography.fontSize.base, // 14px\n lineHeight: 1.4,\n gap: 10, // Increased from 8px to 10px\n rowGap: 2, // 2px between label and value\n },\n lg: {\n iconSize: 24,\n labelSize: tokens.typography.fontSize.sm, // 12px\n valueSize: tokens.typography.fontSize.md, // 14px\n lineHeight: 1.4,\n gap: 14, // Increased from 12px to 14px\n rowGap: 4, // 4px between label and value\n },\n }[size];\n\n // ==========================================================================\n // Render Based on Variant\n //\n // Layout principles:\n // - Baseline alignment for inline text\n // - Consistent icon-to-text spacing\n // - Symmetrical padding\n // - Tabular numbers for value alignment in grids\n // ==========================================================================\n const renderContent = () => {\n // Determine if status indicator should show\n const hasStatus = showStatus && status !== \"normal\" && status !== \"off\";\n\n switch (variant) {\n // ======================================================================\n // INLINE: Icon + Label ... Value (space-between)\n // Best for: Key-value pairs in tables or lists\n // ======================================================================\n case \"inline\": {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: sizeConfig.gap * 2,\n minHeight: sizeConfig.iconSize, // Ensure consistent row height\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: sizeConfig.gap,\n }}\n >\n {showIcon && config.icon && (\n <IconWithBadge\n icon={config.icon}\n iconSize={sizeConfig.iconSize}\n iconColor={\n hasStatus ? statusColor : tokens.colors.text.tertiary\n }\n showBadge={hasStatus}\n status={status}\n statusColor={statusColor}\n isLightTheme={isLightTheme}\n />\n )}\n <span\n style={{\n fontSize: sizeConfig.labelSize,\n lineHeight: sizeConfig.lineHeight,\n color: tokens.colors.text.secondary,\n fontWeight: 500,\n fontFamily: tokens.typography.fontFamily.primary,\n }}\n >\n {config.label}\n </span>\n </div>\n <span\n style={{\n fontSize: sizeConfig.valueSize,\n lineHeight: sizeConfig.lineHeight,\n fontWeight: 500, // Match SpacecraftCard DataCell\n fontFamily: tokens.typography.fontFamily.mono,\n fontVariantNumeric: \"tabular-nums\",\n color: valueColor,\n }}\n >\n {formattedValue}\n </span>\n </div>\n );\n }\n\n // ======================================================================\n // COMPACT: Icon + Value (horizontal, no label)\n // Best for: Dense displays, status bars, compact dashboards\n // ======================================================================\n case \"compact\": {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: sizeConfig.gap,\n minHeight: sizeConfig.iconSize,\n }}\n >\n {showIcon && config.icon && (\n <IconWithBadge\n icon={config.icon}\n iconSize={sizeConfig.iconSize}\n iconColor={\n hasStatus ? statusColor : tokens.colors.text.tertiary\n }\n showBadge={hasStatus}\n status={status}\n statusColor={statusColor}\n isLightTheme={isLightTheme}\n />\n )}\n <span\n style={{\n fontSize: sizeConfig.valueSize,\n lineHeight: sizeConfig.lineHeight,\n fontWeight: 500, // Match SpacecraftCard DataCell\n fontFamily: tokens.typography.fontFamily.mono,\n fontVariantNumeric: \"tabular-nums\",\n color: valueColor,\n }}\n >\n {formattedValue}\n </span>\n </div>\n );\n }\n\n // ======================================================================\n // MINIMAL: Value only (no icon, no label)\n // Best for: Inline values, table cells\n // ======================================================================\n case \"minimal\":\n return (\n <span\n style={{\n fontSize: sizeConfig.valueSize,\n lineHeight: sizeConfig.lineHeight,\n fontWeight: 500, // Match SpacecraftCard DataCell\n fontFamily: tokens.typography.fontFamily.mono,\n fontVariantNumeric: \"tabular-nums\",\n color: valueColor,\n }}\n >\n {formattedValue}\n </span>\n );\n\n // ======================================================================\n // CARD: Icon EXACTLY matches 2-row text height\n // Best for: Dashboard tiles, prominent metrics\n // ======================================================================\n case \"card\": {\n // ═══════════════════════════════════════════════════════════════════════════\n // 2-ROW LAYOUT CONTROLS (card variant)\n // ═══════════════════════════════════════════════════════════════════════════\n // ICON MULTIPLIER: Scale factor (0.5 = half, 1.0 = match text height, 1.5 = 150%)\n const iconMultiplier = 0.7;\n\n // GAP: Pixels between icon and text column\n const iconToTextGap = 4; // px\n\n // ═══════════════════════════════════════════════════════════════════════════\n const baseSize = { sm: 26, md: 32, lg: 40 }[size];\n const iconSize = Math.round(baseSize * iconMultiplier);\n\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: iconToTextGap,\n }}\n >\n {showIcon && config.icon && (\n <IconWithBadge\n icon={config.icon}\n iconSize={iconSize}\n iconColor={\n hasStatus ? statusColor : tokens.colors.text.tertiary\n }\n showBadge={hasStatus}\n status={status}\n statusColor={statusColor}\n isLightTheme={isLightTheme}\n />\n )}\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"space-between\", // Distribute label/value to edges\n gap: sizeConfig.rowGap,\n minWidth: 0,\n }}\n >\n <span\n style={{\n fontSize: sizeConfig.labelSize,\n lineHeight: sizeConfig.lineHeight,\n color: tokens.colors.text.secondary,\n fontWeight: 500,\n fontFamily: tokens.typography.fontFamily.primary,\n }}\n >\n {config.label}\n </span>\n <span\n style={{\n fontSize: sizeConfig.valueSize,\n lineHeight: sizeConfig.lineHeight,\n fontWeight: 500, // Match SpacecraftCard DataCell\n fontFamily: tokens.typography.fontFamily.mono,\n fontVariantNumeric: \"tabular-nums\",\n color: valueColor,\n }}\n >\n {formattedValue}\n </span>\n </div>\n </div>\n );\n }\n\n // ======================================================================\n // BANNER: Label on top, icon left-aligned + value right-aligned below\n // Best for: TopBar metrics, KPI tiles where heading spans full width\n // ======================================================================\n case \"banner\": {\n const bannerIconSize = { sm: 18, md: 22, lg: 28 }[size];\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: sizeConfig.rowGap,\n minWidth: 0,\n width: \"100%\",\n }}\n >\n <span\n style={{\n fontSize: sizeConfig.labelSize,\n lineHeight: sizeConfig.lineHeight,\n color: tokens.colors.text.secondary,\n fontWeight: 500,\n fontFamily: tokens.typography.fontFamily.primary,\n textTransform: \"uppercase\" as const,\n letterSpacing: \"0.5px\",\n }}\n >\n {config.label}\n </span>\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"flex-start\",\n width: \"100%\",\n gap: 6,\n minWidth: 0,\n }}\n >\n {showIcon && config.icon && (\n <IconWithBadge\n icon={config.icon}\n iconSize={bannerIconSize}\n iconColor={\n hasStatus ? statusColor : tokens.colors.text.tertiary\n }\n showBadge={hasStatus}\n status={status}\n statusColor={statusColor}\n isLightTheme={isLightTheme}\n />\n )}\n <span\n style={{\n fontSize: sizeConfig.valueSize,\n lineHeight: sizeConfig.lineHeight,\n fontWeight: 600,\n fontFamily: tokens.typography.fontFamily.mono,\n fontVariantNumeric: \"tabular-nums\",\n color: valueColor,\n textAlign: \"left\",\n }}\n >\n {formattedValue}\n </span>\n </div>\n </div>\n );\n }\n\n // ======================================================================\n // STAT: icon + value (status-coloured) on top, uppercase mono label below\n // Best for: status-header / top-bar telemetry chips (Asset, Link,\n // Battery, Storage, Ground). Unlike the other variants, the value AND\n // icon take the status colour even when `normal` — a nominal chip\n // renders green — matching the SpaceRange status-header spec.\n // ======================================================================\n case \"stat\": {\n const statSize = {\n sm: { icon: 13, value: 13, label: 9.5 },\n md: { icon: 15, value: 14, label: 10 },\n lg: { icon: 18, value: 16, label: 11 },\n }[size];\n // colorProp wins; otherwise the status colour drives value + icon\n // (including `normal`, so nominal telemetry reads green per spec).\n const statColor = colorProp || statusColor;\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"flex-start\",\n gap: 2,\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n fontFamily: tokens.typography.fontFamily.mono,\n fontSize: statSize.value,\n fontWeight: 600,\n color: statColor,\n fontVariantNumeric: \"tabular-nums\",\n letterSpacing: \"0.02em\",\n lineHeight: 1.1,\n }}\n >\n {showIcon && config.icon && (\n <AstroIcon\n name={config.icon}\n size={statSize.icon}\n color={statColor}\n />\n )}\n <span>{formattedValue}</span>\n </div>\n <span\n style={{\n fontFamily: tokens.typography.fontFamily.mono,\n fontSize: statSize.label,\n letterSpacing: \"0.06em\",\n textTransform: \"uppercase\",\n color: tokens.colors.text.tertiary,\n lineHeight: 1.1,\n }}\n >\n {config.label}\n </span>\n </div>\n );\n }\n\n // ======================================================================\n // STACKED (default): Icon EXACTLY matches 2-row text height\n // Best for: General telemetry displays, standard data values\n // ======================================================================\n case \"stacked\":\n default: {\n // ═══════════════════════════════════════════════════════════════════════════\n // 2-ROW LAYOUT CONTROLS (stacked variant)\n // ═══════════════════════════════════════════════════════════════════════════\n // ICON MULTIPLIER: Scale factor (0.5 = half, 1.0 = match text height, 1.5 = 150%)\n const iconMultiplier = 0.7;\n\n // GAP: Pixels between icon and text column\n const iconToTextGap = 4; // px\n\n // ═══════════════════════════════════════════════════════════════════════════\n const baseSize = { sm: 26, md: 32, lg: 40 }[size];\n const iconSize = Math.round(baseSize * iconMultiplier);\n\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: iconToTextGap,\n }}\n >\n {showIcon && config.icon && (\n <IconWithBadge\n icon={config.icon}\n iconSize={iconSize}\n iconColor={\n hasStatus ? statusColor : tokens.colors.text.tertiary\n }\n showBadge={hasStatus}\n status={status}\n statusColor={statusColor}\n isLightTheme={isLightTheme}\n />\n )}\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"space-between\", // Distribute label/value to edges\n gap: sizeConfig.rowGap,\n minWidth: 0,\n }}\n >\n <span\n style={{\n fontSize: sizeConfig.labelSize,\n lineHeight: sizeConfig.lineHeight,\n color: tokens.colors.text.secondary,\n fontWeight: 500,\n fontFamily: tokens.typography.fontFamily.primary,\n }}\n >\n {config.label}\n </span>\n <span\n style={{\n fontSize: sizeConfig.valueSize,\n lineHeight: sizeConfig.lineHeight,\n fontWeight: 500, // Match SpacecraftCard DataCell\n fontFamily: tokens.typography.fontFamily.mono,\n fontVariantNumeric: \"tabular-nums\",\n color: valueColor,\n }}\n >\n {formattedValue}\n </span>\n </div>\n </div>\n );\n }\n }\n };\n\n return (\n <div\n className={`zendir-data-value zendir-data-value--${variant} zendir-data-value--${size} ${className}`}\n style={{\n cursor: onClick ? \"pointer\" : \"default\",\n ...(variant === \"banner\" ? { flex: 1, minWidth: 0 } : {}),\n ...style,\n }}\n onClick={onClick}\n title={tooltip || config.description}\n role={onClick ? \"button\" : undefined}\n tabIndex={onClick ? 0 : undefined}\n onKeyDown={onClick ? (e) => e.key === \"Enter\" && onClick() : undefined}\n >\n {renderContent()}\n </div>\n );\n});\n\n// =============================================================================\n// DataValueGroup Component\n// =============================================================================\n\nexport interface DataValueGroupProps {\n /** Title for the group */\n title?: string;\n /** Icon for the title */\n icon?: AstroIconName;\n /** Layout direction */\n direction?: \"row\" | \"column\" | \"grid\";\n /** Number of columns for grid layout */\n columns?: number;\n /** Gap between items */\n gap?: \"sm\" | \"md\" | \"lg\";\n /** Children DataValue components */\n children: React.ReactNode;\n /** Additional CSS class */\n className?: string;\n /** Custom inline styles */\n style?: React.CSSProperties;\n}\n\nexport const DataValueGroup = memo(function DataValueGroup({\n title,\n icon,\n direction = \"grid\",\n columns = 2,\n gap = \"md\",\n children,\n className = \"\",\n style,\n}: DataValueGroupProps): React.ReactElement {\n const { tokens } = useTheme();\n\n // Gap sizing on 4px grid\n const gapSize = {\n sm: 8, // 2 × 4px\n md: 16, // 4 × 4px\n lg: 24, // 6 × 4px\n }[gap];\n\n const layoutStyles: Record<typeof direction, React.CSSProperties> = {\n row: {\n display: \"flex\",\n flexDirection: \"row\" as const,\n flexWrap: \"wrap\" as const,\n gap: gapSize,\n alignItems: \"flex-start\",\n },\n column: {\n display: \"flex\",\n flexDirection: \"column\" as const,\n gap: gapSize,\n },\n grid: {\n display: \"grid\",\n gridTemplateColumns: `repeat(${columns}, 1fr)`,\n gap: gapSize,\n alignItems: \"start\",\n },\n };\n const layoutStyle = layoutStyles[direction];\n\n return (\n <div className={`zendir-data-value-group ${className}`} style={style}>\n {title && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6, // 6px gap for tight header\n marginBottom: 12, // 3 × 4px\n paddingBottom: 8, // 2 × 4px\n borderBottom: `1px solid ${tokens.colors.border.muted}`,\n }}\n >\n {icon && (\n <AstroIcon\n name={icon}\n size={14}\n color={tokens.colors.text.tertiary}\n style={{ flexShrink: 0 }}\n />\n )}\n <span\n style={{\n fontSize: \"12px\",\n fontWeight: 500,\n color: tokens.colors.text.secondary,\n textTransform: \"uppercase\",\n letterSpacing: \"0.5px\",\n }}\n >\n {title}\n </span>\n </div>\n )}\n <div style={layoutStyle}>{children}</div>\n </div>\n );\n});\n\nexport default DataValue;\n"],"mappings":"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"}
1
+ {"version":3,"file":"DataValue.js","names":[],"sources":["../../../../src/react/core/data/DataValue.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - DataValue Component\r\n *\r\n * Enterprise-grade data value display with icon, label, value, and status.\r\n * The building block for telemetry displays, dashboards, and monitoring UIs.\r\n *\r\n * AstroUXDS Compliance:\r\n * - Status colors per AstroUXDS status system\r\n * - Dual-coding (color + shape) for accessibility via StatusIndicator\r\n * - Tabular numbers for alignment\r\n * - Sentence-case labels\r\n *\r\n * Features:\r\n * - Auto-derive status from value + thresholds\r\n * - Contextual icons from property presets\r\n * - Multiple layout variants (stacked, inline, compact)\r\n * - Theme-aware styling\r\n *\r\n * @example\r\n * ```tsx\r\n * import { DataValue } from '@zendir/ui';\r\n *\r\n * // Simple usage with property preset\r\n * <DataValue property=\"temperature\" value={72.5} />\r\n *\r\n * // Custom configuration\r\n * <DataValue\r\n * label=\"Battery\"\r\n * value={85}\r\n * unit=\"%\"\r\n * icon=\"battery-full\"\r\n * thresholds={{ critical: 10, caution: 30 }}\r\n * />\r\n *\r\n * // Inline layout\r\n * <DataValue property=\"voltage\" value={28.4} variant=\"inline\" />\r\n * ```\r\n */\r\n\r\nimport React, { memo, useMemo } from \"react\";\r\nimport { useTheme } from \"../../theme\";\r\nimport { AstroIcon, type AstroIconName } from \"../display/AstroIcon\";\r\nimport {\r\n getPropertyConfig,\r\n deriveStatus,\r\n formatPropertyValue,\r\n type PropertyKey,\r\n type StatusThresholds,\r\n type PropertyConfig,\r\n} from \"./propertyConfig\";\r\nimport type { StatusLevel } from \"../../utils\";\r\n\r\n// =============================================================================\r\n// Types\r\n// =============================================================================\r\n\r\nexport type DataValueVariant =\r\n | \"stacked\"\r\n | \"inline\"\r\n | \"compact\"\r\n | \"minimal\"\r\n | \"card\"\r\n | \"banner\"\r\n | \"stat\";\r\nexport type DataValueSize = \"sm\" | \"md\" | \"lg\";\r\n\r\nexport interface DataValueProps {\r\n /** Property key for auto-configuration (e.g., 'temperature', 'battery') */\r\n property?: PropertyKey;\r\n /** Display label (overrides property preset) */\r\n label?: string;\r\n /** Current value */\r\n value: number | string | undefined | null;\r\n /** Unit of measurement (overrides property preset) */\r\n unit?: string;\r\n /** Icon name (overrides property preset) */\r\n icon?: AstroIconName;\r\n /** Show icon */\r\n showIcon?: boolean;\r\n /** Status thresholds for auto-derivation (overrides property preset) */\r\n thresholds?: StatusThresholds;\r\n /** Override status (bypasses auto-derivation) */\r\n status?: StatusLevel;\r\n /** Show status indicator */\r\n showStatus?: boolean;\r\n /** Precision for number formatting (overrides property preset) */\r\n precision?: number;\r\n /** Layout variant */\r\n variant?: DataValueVariant;\r\n /** Size */\r\n size?: DataValueSize;\r\n /** Custom value color (overrides status color) */\r\n color?: string;\r\n /** Additional CSS class */\r\n className?: string;\r\n /** Custom inline styles */\r\n style?: React.CSSProperties;\r\n /** Click handler */\r\n onClick?: () => void;\r\n /** Tooltip text */\r\n tooltip?: string;\r\n}\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// - Glow effect in dark mode for visibility\r\n// - Border in light mode for WCAG AA compliance\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// Icon with Status Badge - Enterprise-grade alignment\r\n//\r\n// Design System Principles (Apple HIG / Google Material / AstroUXDS):\r\n// - 4px-based spacing grid for visual harmony\r\n// - Explicit container sizing prevents layout shift\r\n// - Status badge positioned at corner, not extending beyond container bounds\r\n// - Proportional badge sizing: ~35% of icon size for optimal visibility\r\n// =============================================================================\r\n\r\ninterface IconWithBadgeProps {\r\n icon: AstroIconName;\r\n iconSize: number;\r\n iconColor: string;\r\n showBadge: boolean;\r\n status: StatusLevel;\r\n statusColor: string;\r\n isLightTheme?: boolean;\r\n}\r\n\r\nconst IconWithBadge = memo(function IconWithBadge({\r\n icon,\r\n iconSize,\r\n iconColor,\r\n showBadge,\r\n status,\r\n statusColor,\r\n isLightTheme = false,\r\n}: IconWithBadgeProps) {\r\n // ═══════════════════════════════════════════════════════════════════════════\r\n // STATUS BADGE CONTROLS\r\n // ═══════════════════════════════════════════════════════════════════════════\r\n // BADGE SIZE: Percentage of icon size (0.25 = 25%)\r\n const badgeSizeRatio = 0.3;\r\n const badgeSize = Math.max(\r\n 7,\r\n Math.min(14, Math.round(iconSize * badgeSizeRatio)),\r\n );\r\n\r\n // BADGE POSITION: Offset from top-left corner (negative = away from icon)\r\n const badgeOffsetX = -2; // px (negative = left, positive = right)\r\n const badgeOffsetY = -2; // px (negative = up, positive = down)\r\n\r\n // ═══════════════════════════════════════════════════════════════════════════\r\n const borderColor = isLightTheme ? STATUS_BORDER_COLORS[status] : undefined;\r\n const containerSize = iconSize;\r\n\r\n return (\r\n <div\r\n style={{\r\n position: \"relative\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n flexShrink: 0,\r\n width: containerSize,\r\n height: containerSize,\r\n }}\r\n >\r\n <AstroIcon name={icon} size={iconSize} color={iconColor} />\r\n {showBadge && (\r\n <span\r\n style={{\r\n position: \"absolute\",\r\n top: badgeOffsetY,\r\n left: badgeOffsetX,\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 )}\r\n </div>\r\n );\r\n});\r\n\r\n// =============================================================================\r\n// DataValue Component\r\n// =============================================================================\r\n\r\nexport const DataValue = memo(function DataValue({\r\n property,\r\n label: labelProp,\r\n value,\r\n unit: unitProp,\r\n icon: iconProp,\r\n showIcon = true,\r\n thresholds: thresholdsProp,\r\n status: statusProp,\r\n showStatus = true,\r\n precision: precisionProp,\r\n variant = \"stacked\",\r\n size = \"md\",\r\n color: colorProp,\r\n className = \"\",\r\n style,\r\n onClick,\r\n tooltip,\r\n}: DataValueProps): React.ReactElement {\r\n const { tokens, mode } = useTheme();\r\n const isLightTheme = mode === \"light\";\r\n\r\n // Merge property preset with explicit props\r\n const config = useMemo((): PropertyConfig => {\r\n const preset = property\r\n ? getPropertyConfig(property)\r\n : {\r\n label: labelProp || \"Value\",\r\n icon: iconProp || \"info\",\r\n unit: unitProp,\r\n precision: precisionProp,\r\n thresholds: thresholdsProp,\r\n };\r\n\r\n return {\r\n ...preset,\r\n ...(labelProp !== undefined && { label: labelProp }),\r\n ...(iconProp !== undefined && { icon: iconProp }),\r\n ...(unitProp !== undefined && { unit: unitProp }),\r\n ...(precisionProp !== undefined && { precision: precisionProp }),\r\n ...(thresholdsProp !== undefined && { thresholds: thresholdsProp }),\r\n };\r\n }, [property, labelProp, iconProp, unitProp, precisionProp, thresholdsProp]);\r\n\r\n // Derive or use explicit status\r\n const status = useMemo((): StatusLevel => {\r\n if (statusProp) return statusProp;\r\n if (typeof value === \"number\") {\r\n return deriveStatus(value, config.thresholds);\r\n }\r\n return \"normal\";\r\n }, [statusProp, value, config.thresholds]);\r\n\r\n // Format the value\r\n const formattedValue = useMemo((): string => {\r\n if (value === undefined || value === null) return \"--\";\r\n if (typeof value === \"string\") return value;\r\n return formatPropertyValue(value, config);\r\n }, [value, config]);\r\n\r\n // Get status color\r\n const statusColor = tokens.colors.status[status] || tokens.colors.status.off;\r\n const valueColor =\r\n colorProp ||\r\n (showStatus && status !== \"normal\"\r\n ? statusColor\r\n : tokens.colors.text.primary);\r\n\r\n // ==========================================================================\r\n // Size Configuration - Uses theme tokens for consistency with other cards\r\n // ==========================================================================\r\n // Typography uses theme tokens to match SpacecraftCard's DataCell\r\n // fontSize.xs = 10px (0.625rem), fontSize.sm = 12px (0.75rem)\r\n const sizeConfig = {\r\n sm: {\r\n iconSize: 16,\r\n labelSize: tokens.typography.fontSize.xs, // 10px - matches DataCell\r\n valueSize: tokens.typography.fontSize.sm, // 12px - matches DataCell\r\n lineHeight: 1.4,\r\n gap: 6, // Increased from 4px to 6px for better icon separation with larger icons\r\n rowGap: 2, // 2px between label and value\r\n },\r\n md: {\r\n iconSize: 20,\r\n labelSize: tokens.typography.fontSize.xs, // 10px\r\n valueSize: tokens.typography.fontSize.base, // 14px\r\n lineHeight: 1.4,\r\n gap: 10, // Increased from 8px to 10px\r\n rowGap: 2, // 2px between label and value\r\n },\r\n lg: {\r\n iconSize: 24,\r\n labelSize: tokens.typography.fontSize.sm, // 12px\r\n valueSize: tokens.typography.fontSize.md, // 14px\r\n lineHeight: 1.4,\r\n gap: 14, // Increased from 12px to 14px\r\n rowGap: 4, // 4px between label and value\r\n },\r\n }[size];\r\n\r\n // ==========================================================================\r\n // Render Based on Variant\r\n //\r\n // Layout principles:\r\n // - Baseline alignment for inline text\r\n // - Consistent icon-to-text spacing\r\n // - Symmetrical padding\r\n // - Tabular numbers for value alignment in grids\r\n // ==========================================================================\r\n const renderContent = () => {\r\n // Determine if status indicator should show\r\n const hasStatus = showStatus && status !== \"normal\" && status !== \"off\";\r\n\r\n switch (variant) {\r\n // ======================================================================\r\n // INLINE: Icon + Label ... Value (space-between)\r\n // Best for: Key-value pairs in tables or lists\r\n // ======================================================================\r\n case \"inline\": {\r\n return (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"space-between\",\r\n gap: sizeConfig.gap * 2,\r\n minHeight: sizeConfig.iconSize, // Ensure consistent row height\r\n }}\r\n >\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: sizeConfig.gap,\r\n }}\r\n >\r\n {showIcon && config.icon && (\r\n <IconWithBadge\r\n icon={config.icon}\r\n iconSize={sizeConfig.iconSize}\r\n iconColor={\r\n hasStatus ? statusColor : tokens.colors.text.tertiary\r\n }\r\n showBadge={hasStatus}\r\n status={status}\r\n statusColor={statusColor}\r\n isLightTheme={isLightTheme}\r\n />\r\n )}\r\n <span\r\n style={{\r\n fontSize: sizeConfig.labelSize,\r\n lineHeight: sizeConfig.lineHeight,\r\n color: tokens.colors.text.secondary,\r\n fontWeight: 500,\r\n fontFamily: tokens.typography.fontFamily.primary,\r\n }}\r\n >\r\n {config.label}\r\n </span>\r\n </div>\r\n <span\r\n style={{\r\n fontSize: sizeConfig.valueSize,\r\n lineHeight: sizeConfig.lineHeight,\r\n fontWeight: 500, // Match SpacecraftCard DataCell\r\n fontFamily: tokens.typography.fontFamily.mono,\r\n fontVariantNumeric: \"tabular-nums\",\r\n color: valueColor,\r\n }}\r\n >\r\n {formattedValue}\r\n </span>\r\n </div>\r\n );\r\n }\r\n\r\n // ======================================================================\r\n // COMPACT: Icon + Value (horizontal, no label)\r\n // Best for: Dense displays, status bars, compact dashboards\r\n // ======================================================================\r\n case \"compact\": {\r\n return (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: sizeConfig.gap,\r\n minHeight: sizeConfig.iconSize,\r\n }}\r\n >\r\n {showIcon && config.icon && (\r\n <IconWithBadge\r\n icon={config.icon}\r\n iconSize={sizeConfig.iconSize}\r\n iconColor={\r\n hasStatus ? statusColor : tokens.colors.text.tertiary\r\n }\r\n showBadge={hasStatus}\r\n status={status}\r\n statusColor={statusColor}\r\n isLightTheme={isLightTheme}\r\n />\r\n )}\r\n <span\r\n style={{\r\n fontSize: sizeConfig.valueSize,\r\n lineHeight: sizeConfig.lineHeight,\r\n fontWeight: 500, // Match SpacecraftCard DataCell\r\n fontFamily: tokens.typography.fontFamily.mono,\r\n fontVariantNumeric: \"tabular-nums\",\r\n color: valueColor,\r\n }}\r\n >\r\n {formattedValue}\r\n </span>\r\n </div>\r\n );\r\n }\r\n\r\n // ======================================================================\r\n // MINIMAL: Value only (no icon, no label)\r\n // Best for: Inline values, table cells\r\n // ======================================================================\r\n case \"minimal\":\r\n return (\r\n <span\r\n style={{\r\n fontSize: sizeConfig.valueSize,\r\n lineHeight: sizeConfig.lineHeight,\r\n fontWeight: 500, // Match SpacecraftCard DataCell\r\n fontFamily: tokens.typography.fontFamily.mono,\r\n fontVariantNumeric: \"tabular-nums\",\r\n color: valueColor,\r\n }}\r\n >\r\n {formattedValue}\r\n </span>\r\n );\r\n\r\n // ======================================================================\r\n // CARD: Icon EXACTLY matches 2-row text height\r\n // Best for: Dashboard tiles, prominent metrics\r\n // ======================================================================\r\n case \"card\": {\r\n // ═══════════════════════════════════════════════════════════════════════════\r\n // 2-ROW LAYOUT CONTROLS (card variant)\r\n // ═══════════════════════════════════════════════════════════════════════════\r\n // ICON MULTIPLIER: Scale factor (0.5 = half, 1.0 = match text height, 1.5 = 150%)\r\n const iconMultiplier = 0.7;\r\n\r\n // GAP: Pixels between icon and text column\r\n const iconToTextGap = 4; // px\r\n\r\n // ═══════════════════════════════════════════════════════════════════════════\r\n const baseSize = { sm: 26, md: 32, lg: 40 }[size];\r\n const iconSize = Math.round(baseSize * iconMultiplier);\r\n\r\n return (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: iconToTextGap,\r\n }}\r\n >\r\n {showIcon && config.icon && (\r\n <IconWithBadge\r\n icon={config.icon}\r\n iconSize={iconSize}\r\n iconColor={\r\n hasStatus ? statusColor : tokens.colors.text.tertiary\r\n }\r\n showBadge={hasStatus}\r\n status={status}\r\n statusColor={statusColor}\r\n isLightTheme={isLightTheme}\r\n />\r\n )}\r\n <div\r\n style={{\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n justifyContent: \"space-between\", // Distribute label/value to edges\r\n gap: sizeConfig.rowGap,\r\n minWidth: 0,\r\n }}\r\n >\r\n <span\r\n style={{\r\n fontSize: sizeConfig.labelSize,\r\n lineHeight: sizeConfig.lineHeight,\r\n color: tokens.colors.text.secondary,\r\n fontWeight: 500,\r\n fontFamily: tokens.typography.fontFamily.primary,\r\n }}\r\n >\r\n {config.label}\r\n </span>\r\n <span\r\n style={{\r\n fontSize: sizeConfig.valueSize,\r\n lineHeight: sizeConfig.lineHeight,\r\n fontWeight: 500, // Match SpacecraftCard DataCell\r\n fontFamily: tokens.typography.fontFamily.mono,\r\n fontVariantNumeric: \"tabular-nums\",\r\n color: valueColor,\r\n }}\r\n >\r\n {formattedValue}\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n // ======================================================================\r\n // BANNER: Label on top, icon left-aligned + value right-aligned below\r\n // Best for: TopBar metrics, KPI tiles where heading spans full width\r\n // ======================================================================\r\n case \"banner\": {\r\n const bannerIconSize = { sm: 18, md: 22, lg: 28 }[size];\r\n return (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n gap: sizeConfig.rowGap,\r\n minWidth: 0,\r\n width: \"100%\",\r\n }}\r\n >\r\n <span\r\n style={{\r\n fontSize: sizeConfig.labelSize,\r\n lineHeight: sizeConfig.lineHeight,\r\n color: tokens.colors.text.secondary,\r\n fontWeight: 500,\r\n fontFamily: tokens.typography.fontFamily.primary,\r\n textTransform: \"uppercase\" as const,\r\n letterSpacing: \"0.5px\",\r\n }}\r\n >\r\n {config.label}\r\n </span>\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"flex-start\",\r\n width: \"100%\",\r\n gap: 6,\r\n minWidth: 0,\r\n }}\r\n >\r\n {showIcon && config.icon && (\r\n <IconWithBadge\r\n icon={config.icon}\r\n iconSize={bannerIconSize}\r\n iconColor={\r\n hasStatus ? statusColor : tokens.colors.text.tertiary\r\n }\r\n showBadge={hasStatus}\r\n status={status}\r\n statusColor={statusColor}\r\n isLightTheme={isLightTheme}\r\n />\r\n )}\r\n <span\r\n style={{\r\n fontSize: sizeConfig.valueSize,\r\n lineHeight: sizeConfig.lineHeight,\r\n fontWeight: 600,\r\n fontFamily: tokens.typography.fontFamily.mono,\r\n fontVariantNumeric: \"tabular-nums\",\r\n color: valueColor,\r\n textAlign: \"left\",\r\n }}\r\n >\r\n {formattedValue}\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n // ======================================================================\r\n // STAT: icon + value (status-coloured) on top, uppercase mono label below\r\n // Best for: status-header / top-bar telemetry chips (Asset, Link,\r\n // Battery, Storage, Ground). Unlike the other variants, the value AND\r\n // icon take the status colour even when `normal` — a nominal chip\r\n // renders green — matching the SpaceRange status-header spec.\r\n // ======================================================================\r\n case \"stat\": {\r\n const statSize = {\r\n sm: { icon: 13, value: 13, label: 9.5 },\r\n md: { icon: 15, value: 14, label: 10 },\r\n lg: { icon: 18, value: 16, label: 11 },\r\n }[size];\r\n // colorProp wins; otherwise the status colour drives value + icon\r\n // (including `normal`, so nominal telemetry reads green per spec).\r\n const statColor = colorProp || statusColor;\r\n return (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n alignItems: \"flex-start\",\r\n gap: 2,\r\n }}\r\n >\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: 6,\r\n fontFamily: tokens.typography.fontFamily.mono,\r\n fontSize: statSize.value,\r\n fontWeight: 600,\r\n color: statColor,\r\n fontVariantNumeric: \"tabular-nums\",\r\n letterSpacing: \"0.02em\",\r\n lineHeight: 1.1,\r\n }}\r\n >\r\n {showIcon && config.icon && (\r\n <AstroIcon\r\n name={config.icon}\r\n size={statSize.icon}\r\n color={statColor}\r\n />\r\n )}\r\n <span>{formattedValue}</span>\r\n </div>\r\n <span\r\n style={{\r\n fontFamily: tokens.typography.fontFamily.mono,\r\n fontSize: statSize.label,\r\n letterSpacing: \"0.06em\",\r\n textTransform: \"uppercase\",\r\n color: tokens.colors.text.tertiary,\r\n lineHeight: 1.1,\r\n }}\r\n >\r\n {config.label}\r\n </span>\r\n </div>\r\n );\r\n }\r\n\r\n // ======================================================================\r\n // STACKED (default): Icon EXACTLY matches 2-row text height\r\n // Best for: General telemetry displays, standard data values\r\n // ======================================================================\r\n case \"stacked\":\r\n default: {\r\n // ═══════════════════════════════════════════════════════════════════════════\r\n // 2-ROW LAYOUT CONTROLS (stacked variant)\r\n // ═══════════════════════════════════════════════════════════════════════════\r\n // ICON MULTIPLIER: Scale factor (0.5 = half, 1.0 = match text height, 1.5 = 150%)\r\n const iconMultiplier = 0.7;\r\n\r\n // GAP: Pixels between icon and text column\r\n const iconToTextGap = 4; // px\r\n\r\n // ═══════════════════════════════════════════════════════════════════════════\r\n const baseSize = { sm: 26, md: 32, lg: 40 }[size];\r\n const iconSize = Math.round(baseSize * iconMultiplier);\r\n\r\n return (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: iconToTextGap,\r\n }}\r\n >\r\n {showIcon && config.icon && (\r\n <IconWithBadge\r\n icon={config.icon}\r\n iconSize={iconSize}\r\n iconColor={\r\n hasStatus ? statusColor : tokens.colors.text.tertiary\r\n }\r\n showBadge={hasStatus}\r\n status={status}\r\n statusColor={statusColor}\r\n isLightTheme={isLightTheme}\r\n />\r\n )}\r\n <div\r\n style={{\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n justifyContent: \"space-between\", // Distribute label/value to edges\r\n gap: sizeConfig.rowGap,\r\n minWidth: 0,\r\n }}\r\n >\r\n <span\r\n style={{\r\n fontSize: sizeConfig.labelSize,\r\n lineHeight: sizeConfig.lineHeight,\r\n color: tokens.colors.text.secondary,\r\n fontWeight: 500,\r\n fontFamily: tokens.typography.fontFamily.primary,\r\n }}\r\n >\r\n {config.label}\r\n </span>\r\n <span\r\n style={{\r\n fontSize: sizeConfig.valueSize,\r\n lineHeight: sizeConfig.lineHeight,\r\n fontWeight: 500, // Match SpacecraftCard DataCell\r\n fontFamily: tokens.typography.fontFamily.mono,\r\n fontVariantNumeric: \"tabular-nums\",\r\n color: valueColor,\r\n }}\r\n >\r\n {formattedValue}\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n }\r\n }\r\n };\r\n\r\n return (\r\n <div\r\n className={`zendir-data-value zendir-data-value--${variant} zendir-data-value--${size} ${className}`}\r\n style={{\r\n cursor: onClick ? \"pointer\" : \"default\",\r\n ...(variant === \"banner\" ? { flex: 1, minWidth: 0 } : {}),\r\n ...style,\r\n }}\r\n onClick={onClick}\r\n title={tooltip || config.description}\r\n role={onClick ? \"button\" : undefined}\r\n tabIndex={onClick ? 0 : undefined}\r\n onKeyDown={onClick ? (e) => e.key === \"Enter\" && onClick() : undefined}\r\n >\r\n {renderContent()}\r\n </div>\r\n );\r\n});\r\n\r\n// =============================================================================\r\n// DataValueGroup Component\r\n// =============================================================================\r\n\r\nexport interface DataValueGroupProps {\r\n /** Title for the group */\r\n title?: string;\r\n /** Icon for the title */\r\n icon?: AstroIconName;\r\n /** Layout direction */\r\n direction?: \"row\" | \"column\" | \"grid\";\r\n /** Number of columns for grid layout */\r\n columns?: number;\r\n /** Gap between items */\r\n gap?: \"sm\" | \"md\" | \"lg\";\r\n /** Children DataValue components */\r\n children: React.ReactNode;\r\n /** Additional CSS class */\r\n className?: string;\r\n /** Custom inline styles */\r\n style?: React.CSSProperties;\r\n}\r\n\r\nexport const DataValueGroup = memo(function DataValueGroup({\r\n title,\r\n icon,\r\n direction = \"grid\",\r\n columns = 2,\r\n gap = \"md\",\r\n children,\r\n className = \"\",\r\n style,\r\n}: DataValueGroupProps): React.ReactElement {\r\n const { tokens } = useTheme();\r\n\r\n // Gap sizing on 4px grid\r\n const gapSize = {\r\n sm: 8, // 2 × 4px\r\n md: 16, // 4 × 4px\r\n lg: 24, // 6 × 4px\r\n }[gap];\r\n\r\n const layoutStyles: Record<typeof direction, React.CSSProperties> = {\r\n row: {\r\n display: \"flex\",\r\n flexDirection: \"row\" as const,\r\n flexWrap: \"wrap\" as const,\r\n gap: gapSize,\r\n alignItems: \"flex-start\",\r\n },\r\n column: {\r\n display: \"flex\",\r\n flexDirection: \"column\" as const,\r\n gap: gapSize,\r\n },\r\n grid: {\r\n display: \"grid\",\r\n gridTemplateColumns: `repeat(${columns}, 1fr)`,\r\n gap: gapSize,\r\n alignItems: \"start\",\r\n },\r\n };\r\n const layoutStyle = layoutStyles[direction];\r\n\r\n return (\r\n <div className={`zendir-data-value-group ${className}`} style={style}>\r\n {title && (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: 6, // 6px gap for tight header\r\n marginBottom: 12, // 3 × 4px\r\n paddingBottom: 8, // 2 × 4px\r\n borderBottom: `1px solid ${tokens.colors.border.muted}`,\r\n }}\r\n >\r\n {icon && (\r\n <AstroIcon\r\n name={icon}\r\n size={14}\r\n color={tokens.colors.text.tertiary}\r\n style={{ flexShrink: 0 }}\r\n />\r\n )}\r\n <span\r\n style={{\r\n fontSize: \"12px\",\r\n fontWeight: 500,\r\n color: tokens.colors.text.secondary,\r\n textTransform: \"uppercase\",\r\n letterSpacing: \"0.5px\",\r\n }}\r\n >\r\n {title}\r\n </span>\r\n </div>\r\n )}\r\n <div style={layoutStyle}>{children}</div>\r\n </div>\r\n );\r\n});\r\n\r\nexport default DataValue;\r\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"propertyConfig.js","names":[],"sources":["../../../../src/react/core/data/propertyConfig.ts"],"sourcesContent":["/**\n * @zendir/ui - Property Configuration System\n *\n * Enterprise-grade property-to-icon/status/unit mapping system.\n * Provides automatic icon, status, and formatting for common telemetry properties.\n *\n * AstroUXDS Compliance:\n * - Uses official Astro icon names\n * - Status colors per AstroUXDS status system\n * - Dual-coding (color + shape) for accessibility\n *\n * Features:\n * - Auto-derive status from value + thresholds\n * - Contextual icons for space operations properties\n * - Unit formatting with SI prefixes\n * - Extensible configuration\n *\n * @example\n * ```tsx\n * import { getPropertyConfig, deriveStatus, PROPERTY_PRESETS } from '@zendir/ui';\n *\n * // Get config for a known property\n * const tempConfig = getPropertyConfig('temperature');\n * // { icon: 'thermal', unit: '°C', thresholds: { caution: 60, critical: 80 }, ... }\n *\n * // Derive status from value\n * const status = deriveStatus(75, tempConfig.thresholds);\n * // 'caution'\n * ```\n */\n\nimport type { StatusLevel } from \"../../utils\";\nimport type { AstroIconName } from \"../display/AstroIcon\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Threshold configuration for automatic status derivation\n * Values are compared: value >= threshold triggers that status (high thresholds)\n * or value <= threshold triggers that status (low thresholds)\n */\nexport interface StatusThresholds {\n /** Value at or above which status becomes 'critical' (high is bad) */\n critical?: number;\n /** Value at or above which status becomes 'serious' (high is bad) */\n serious?: number;\n /** Value at or above which status becomes 'caution' (high is bad) */\n caution?: number;\n /** Value at or below which status becomes 'caution' (low is bad) */\n cautionLow?: number;\n /** Value at or below which status becomes 'serious' (low is bad) */\n seriousLow?: number;\n /** Value at or below which status becomes 'critical' (low is bad) */\n criticalLow?: number;\n}\n\n/**\n * Complete property configuration\n */\nexport interface PropertyConfig {\n /** Display name (sentence case per AstroUXDS) */\n label: string;\n /** Astro icon name */\n icon: AstroIconName;\n /** Unit of measurement */\n unit?: string;\n /** Precision for number formatting */\n precision?: number;\n /** Status thresholds for auto-derivation */\n thresholds?: StatusThresholds;\n /** Category for grouping */\n category?: PropertyCategory;\n /** Description for tooltips */\n description?: string;\n /** Format function override */\n format?: (value: number) => string;\n}\n\n/**\n * Property categories for organization\n */\nexport type PropertyCategory =\n | \"power\"\n | \"thermal\"\n | \"attitude\"\n | \"communications\"\n | \"propulsion\"\n | \"navigation\"\n | \"payload\"\n | \"health\"\n | \"orbital\"\n | \"general\";\n\n/**\n * Property key - either a preset name or custom string\n */\nexport type PropertyKey = keyof typeof PROPERTY_PRESETS | (string & {});\n\n// =============================================================================\n// Property Presets\n// =============================================================================\n\n/**\n * Predefined property configurations for common space operations telemetry\n *\n * These provide sensible defaults that can be overridden per-use.\n */\nexport const PROPERTY_PRESETS = {\n // === Power System ===\n battery: {\n label: \"Battery\",\n icon: \"battery-full\" as AstroIconName,\n unit: \"%\",\n precision: 1,\n category: \"power\" as PropertyCategory,\n // Low values are bad for battery (use *Low thresholds)\n thresholds: { criticalLow: 10, seriousLow: 20, cautionLow: 30 },\n description: \"Battery state of charge\",\n },\n voltage: {\n label: \"Voltage\",\n icon: \"propulsion-power\" as AstroIconName,\n unit: \"V\",\n precision: 2,\n category: \"power\" as PropertyCategory,\n thresholds: { criticalLow: 24, cautionLow: 26 },\n description: \"Bus voltage\",\n },\n current: {\n label: \"Current\",\n icon: \"propulsion-power\" as AstroIconName,\n unit: \"A\",\n precision: 2,\n category: \"power\" as PropertyCategory,\n description: \"Current draw\",\n },\n power: {\n label: \"Power\",\n icon: \"propulsion-power\" as AstroIconName,\n unit: \"W\",\n precision: 1,\n category: \"power\" as PropertyCategory,\n description: \"Power consumption or generation\",\n },\n solarPower: {\n label: \"Solar\",\n icon: \"solar\" as AstroIconName,\n unit: \"W\",\n precision: 1,\n category: \"power\" as PropertyCategory,\n description: \"Solar array output\",\n },\n load: {\n label: \"Load\",\n icon: \"propulsion-power\" as AstroIconName,\n unit: \"W\",\n precision: 1,\n category: \"power\" as PropertyCategory,\n description: \"Power load\",\n },\n\n // === Thermal ===\n temperature: {\n label: \"Temperature\",\n icon: \"thermal\" as AstroIconName,\n unit: \"°C\",\n precision: 1,\n category: \"thermal\" as PropertyCategory,\n thresholds: {\n critical: 80,\n serious: 70,\n caution: 60,\n cautionLow: -20,\n criticalLow: -40,\n },\n description: \"Component temperature\",\n },\n heater: {\n label: \"Heater\",\n icon: \"thermal\" as AstroIconName,\n unit: \"\",\n category: \"thermal\" as PropertyCategory,\n description: \"Heater status\",\n },\n\n // === Attitude ===\n roll: {\n label: \"Roll\",\n icon: \"explore\" as AstroIconName,\n unit: \"°\",\n precision: 2,\n category: \"attitude\" as PropertyCategory,\n thresholds: { critical: 45, caution: 30 },\n description: \"Roll angle\",\n },\n pitch: {\n label: \"Pitch\",\n icon: \"explore\" as AstroIconName,\n unit: \"°\",\n precision: 2,\n category: \"attitude\" as PropertyCategory,\n thresholds: { critical: 45, caution: 30 },\n description: \"Pitch angle\",\n },\n yaw: {\n label: \"Yaw\",\n icon: \"explore\" as AstroIconName,\n unit: \"°\",\n precision: 2,\n category: \"attitude\" as PropertyCategory,\n thresholds: { critical: 45, caution: 30 },\n description: \"Yaw angle\",\n },\n pointingError: {\n label: \"Pointing error\",\n icon: \"explore\" as AstroIconName,\n unit: \"°\",\n precision: 3,\n category: \"attitude\" as PropertyCategory,\n thresholds: { critical: 1.0, serious: 0.5, caution: 0.1 },\n description: \"Attitude pointing error\",\n },\n angularVelocity: {\n label: \"Angular velocity\",\n icon: \"explore\" as AstroIconName,\n unit: \"°/s\",\n precision: 3,\n category: \"attitude\" as PropertyCategory,\n thresholds: { critical: 5.0, caution: 2.0 },\n description: \"Rotation rate\",\n },\n\n // === Communications ===\n signalStrength: {\n label: \"Signal\",\n icon: \"antenna-receive\" as AstroIconName,\n unit: \"dBm\",\n precision: 1,\n category: \"communications\" as PropertyCategory,\n thresholds: { criticalLow: -100, cautionLow: -85 },\n description: \"Received signal strength\",\n },\n dataRate: {\n label: \"Data rate\",\n icon: \"antenna-transmit\" as AstroIconName,\n unit: \"Mbps\",\n precision: 2,\n category: \"communications\" as PropertyCategory,\n description: \"Communication data rate\",\n },\n packetLoss: {\n label: \"Packet loss\",\n icon: \"netcom\" as AstroIconName,\n unit: \"%\",\n precision: 2,\n category: \"communications\" as PropertyCategory,\n thresholds: { critical: 10, serious: 5, caution: 1 },\n description: \"Communication packet loss rate\",\n },\n snr: {\n label: \"SNR\",\n icon: \"antenna\" as AstroIconName,\n unit: \"dB\",\n precision: 1,\n category: \"communications\" as PropertyCategory,\n thresholds: { criticalLow: 5, cautionLow: 10 },\n description: \"Signal-to-noise ratio\",\n },\n queue: {\n label: \"Queue\",\n icon: \"netcom\" as AstroIconName,\n unit: \"pkts\",\n precision: 0,\n category: \"communications\" as PropertyCategory,\n thresholds: { critical: 1000, caution: 500 },\n description: \"Packet queue depth\",\n },\n\n // === Propulsion ===\n fuelLevel: {\n label: \"Fuel\",\n icon: \"propulsion-power\" as AstroIconName,\n unit: \"%\",\n precision: 1,\n category: \"propulsion\" as PropertyCategory,\n thresholds: { critical: 5, serious: 10, caution: 20 },\n description: \"Propellant remaining\",\n },\n deltaV: {\n label: \"Delta-V\",\n icon: \"propulsion-power\" as AstroIconName,\n unit: \"m/s\",\n precision: 1,\n category: \"propulsion\" as PropertyCategory,\n description: \"Available delta-V budget\",\n },\n thrustLevel: {\n label: \"Thrust\",\n icon: \"propulsion-power\" as AstroIconName,\n unit: \"N\",\n precision: 2,\n category: \"propulsion\" as PropertyCategory,\n description: \"Current thrust output\",\n },\n\n // === Navigation ===\n altitude: {\n label: \"Altitude\",\n icon: \"altitude\" as AstroIconName,\n unit: \"km\",\n precision: 1,\n category: \"orbital\" as PropertyCategory,\n thresholds: { criticalLow: 200, cautionLow: 250 },\n description: \"Orbital altitude\",\n },\n velocity: {\n label: \"Velocity\",\n icon: \"altitude\" as AstroIconName,\n unit: \"km/s\",\n precision: 3,\n category: \"orbital\" as PropertyCategory,\n description: \"Orbital velocity\",\n },\n inclination: {\n label: \"Inclination\",\n icon: \"altitude\" as AstroIconName,\n unit: \"°\",\n precision: 2,\n category: \"orbital\" as PropertyCategory,\n description: \"Orbital inclination\",\n },\n eccentricity: {\n label: \"Eccentricity\",\n icon: \"altitude\" as AstroIconName,\n unit: \"\",\n precision: 6,\n category: \"orbital\" as PropertyCategory,\n description: \"Orbital eccentricity\",\n },\n\n // === Payload ===\n payloadStatus: {\n label: \"Payload\",\n icon: \"payload\" as AstroIconName,\n unit: \"\",\n category: \"payload\" as PropertyCategory,\n description: \"Payload operational status\",\n },\n storageUsed: {\n label: \"Storage\",\n icon: \"hardware\" as AstroIconName,\n unit: \"%\",\n precision: 1,\n category: \"payload\" as PropertyCategory,\n thresholds: { critical: 95, serious: 90, caution: 80 },\n description: \"Onboard storage usage\",\n },\n\n // === Health ===\n cpuUsage: {\n label: \"CPU\",\n icon: \"processor\" as AstroIconName,\n unit: \"%\",\n precision: 1,\n category: \"health\" as PropertyCategory,\n thresholds: { critical: 95, serious: 85, caution: 75 },\n description: \"Processor utilization\",\n },\n memoryUsage: {\n label: \"Memory\",\n icon: \"processor\" as AstroIconName,\n unit: \"%\",\n precision: 1,\n category: \"health\" as PropertyCategory,\n thresholds: { critical: 95, serious: 85, caution: 75 },\n description: \"Memory utilization\",\n },\n uptime: {\n label: \"Uptime\",\n icon: \"mission\" as AstroIconName,\n unit: \"s\",\n precision: 0,\n category: \"health\" as PropertyCategory,\n description: \"System uptime\",\n },\n\n // === General ===\n count: {\n label: \"Count\",\n icon: \"list\" as AstroIconName,\n unit: \"\",\n precision: 0,\n category: \"general\" as PropertyCategory,\n description: \"Item count\",\n },\n percentage: {\n label: \"Percentage\",\n icon: \"info\" as AstroIconName,\n unit: \"%\",\n precision: 1,\n category: \"general\" as PropertyCategory,\n description: \"Percentage value\",\n },\n duration: {\n label: \"Duration\",\n icon: \"schedule\" as AstroIconName,\n unit: \"s\",\n precision: 0,\n category: \"general\" as PropertyCategory,\n description: \"Time duration\",\n },\n} as const satisfies Record<string, PropertyConfig>;\n\n// =============================================================================\n// Category Icons (for section headers)\n// =============================================================================\n\nexport const CATEGORY_ICONS: Record<PropertyCategory, AstroIconName> = {\n power: \"propulsion-power\",\n thermal: \"thermal\",\n attitude: \"explore\",\n communications: \"antenna\",\n propulsion: \"propulsion-power\",\n navigation: \"gps-fixed\",\n payload: \"payload\",\n health: \"favorite\",\n orbital: \"altitude\",\n general: \"info\",\n};\n\nexport const CATEGORY_LABELS: Record<PropertyCategory, string> = {\n power: \"Power\",\n thermal: \"Thermal\",\n attitude: \"Attitude\",\n communications: \"Communications\",\n propulsion: \"Propulsion\",\n navigation: \"Navigation\",\n payload: \"Payload\",\n health: \"Health\",\n orbital: \"Orbital\",\n general: \"General\",\n};\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Get property configuration by key\n * Returns preset config or a default config for unknown properties\n */\nexport function getPropertyConfig(key: PropertyKey): PropertyConfig {\n const preset = PROPERTY_PRESETS[key as keyof typeof PROPERTY_PRESETS];\n if (preset) {\n return preset;\n }\n\n // Return default config for unknown properties\n return {\n label: formatPropertyLabel(key),\n icon: \"info\",\n unit: \"\",\n precision: 2,\n category: \"general\",\n description: key,\n };\n}\n\n/**\n * Format a property key into a display label (sentence case)\n */\nexport function formatPropertyLabel(key: string): string {\n // Handle camelCase → Sentence case\n const words = key\n .replace(/([A-Z])/g, \" $1\")\n .replace(/[_-]/g, \" \")\n .trim()\n .toLowerCase();\n return words.charAt(0).toUpperCase() + words.slice(1);\n}\n\n/**\n * Derive status level from a value and thresholds\n *\n * @param value - Current value\n * @param thresholds - Status thresholds\n * @returns StatusLevel\n *\n * @example\n * ```tsx\n * deriveStatus(75, { caution: 60, critical: 80 }) // 'caution'\n * deriveStatus(25, { criticalLow: 10, cautionLow: 30 }) // 'caution'\n * deriveStatus(50, { caution: 60, critical: 80 }) // 'normal'\n * ```\n */\nexport function deriveStatus(\n value: number | undefined | null,\n thresholds?: StatusThresholds,\n): StatusLevel {\n if (value === undefined || value === null || !Number.isFinite(value)) {\n return \"off\";\n }\n\n if (!thresholds) {\n return \"normal\";\n }\n\n // Check high thresholds (value >= threshold is bad)\n if (thresholds.critical !== undefined && value >= thresholds.critical) {\n return \"critical\";\n }\n if (thresholds.serious !== undefined && value >= thresholds.serious) {\n return \"serious\";\n }\n if (thresholds.caution !== undefined && value >= thresholds.caution) {\n return \"caution\";\n }\n\n // Check low thresholds (value <= threshold is bad)\n if (thresholds.criticalLow !== undefined && value <= thresholds.criticalLow) {\n return \"critical\";\n }\n if (thresholds.seriousLow !== undefined && value <= thresholds.seriousLow) {\n return \"serious\";\n }\n if (thresholds.cautionLow !== undefined && value <= thresholds.cautionLow) {\n return \"caution\";\n }\n\n return \"normal\";\n}\n\n/**\n * Derive status for battery specifically (low is bad)\n */\nexport function deriveBatteryStatus(level: number | undefined): StatusLevel {\n if (level === undefined || level === null) return \"off\";\n if (level <= 10) return \"critical\";\n if (level <= 20) return \"serious\";\n if (level <= 30) return \"caution\";\n return \"normal\";\n}\n\n/**\n * Format a value with its property config\n */\nexport function formatPropertyValue(\n value: number | undefined | null,\n config: PropertyConfig,\n): string {\n if (value === undefined || value === null || !Number.isFinite(value)) {\n return \"--\";\n }\n\n if (config.format) {\n return config.format(value);\n }\n\n const precision = config.precision ?? 2;\n const formatted = value.toFixed(precision);\n const unit = config.unit ?? \"\";\n\n return unit\n ? `${formatted}${unit.startsWith(\"°\") || unit.startsWith(\"%\") ? \"\" : \" \"}${unit}`\n : formatted;\n}\n\n/**\n * Create a custom property config by merging with a preset\n */\nexport function createPropertyConfig(\n baseKey: PropertyKey,\n overrides: Partial<PropertyConfig>,\n): PropertyConfig {\n const base = getPropertyConfig(baseKey);\n return { ...base, ...overrides };\n}\n\n/**\n * Get all properties in a category\n */\nexport function getPropertiesByCategory(\n category: PropertyCategory,\n): Array<{ key: string; config: PropertyConfig }> {\n return Object.entries(PROPERTY_PRESETS)\n .filter(([_, config]) => config.category === category)\n .map(([key, config]) => ({ key, config }));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"propertyConfig.js","names":[],"sources":["../../../../src/react/core/data/propertyConfig.ts"],"sourcesContent":["/**\r\n * @zendir/ui - Property Configuration System\r\n *\r\n * Enterprise-grade property-to-icon/status/unit mapping system.\r\n * Provides automatic icon, status, and formatting for common telemetry properties.\r\n *\r\n * AstroUXDS Compliance:\r\n * - Uses official Astro icon names\r\n * - Status colors per AstroUXDS status system\r\n * - Dual-coding (color + shape) for accessibility\r\n *\r\n * Features:\r\n * - Auto-derive status from value + thresholds\r\n * - Contextual icons for space operations properties\r\n * - Unit formatting with SI prefixes\r\n * - Extensible configuration\r\n *\r\n * @example\r\n * ```tsx\r\n * import { getPropertyConfig, deriveStatus, PROPERTY_PRESETS } from '@zendir/ui';\r\n *\r\n * // Get config for a known property\r\n * const tempConfig = getPropertyConfig('temperature');\r\n * // { icon: 'thermal', unit: '°C', thresholds: { caution: 60, critical: 80 }, ... }\r\n *\r\n * // Derive status from value\r\n * const status = deriveStatus(75, tempConfig.thresholds);\r\n * // 'caution'\r\n * ```\r\n */\r\n\r\nimport type { StatusLevel } from \"../../utils\";\r\nimport type { AstroIconName } from \"../display/AstroIcon\";\r\n\r\n// =============================================================================\r\n// Types\r\n// =============================================================================\r\n\r\n/**\r\n * Threshold configuration for automatic status derivation\r\n * Values are compared: value >= threshold triggers that status (high thresholds)\r\n * or value <= threshold triggers that status (low thresholds)\r\n */\r\nexport interface StatusThresholds {\r\n /** Value at or above which status becomes 'critical' (high is bad) */\r\n critical?: number;\r\n /** Value at or above which status becomes 'serious' (high is bad) */\r\n serious?: number;\r\n /** Value at or above which status becomes 'caution' (high is bad) */\r\n caution?: number;\r\n /** Value at or below which status becomes 'caution' (low is bad) */\r\n cautionLow?: number;\r\n /** Value at or below which status becomes 'serious' (low is bad) */\r\n seriousLow?: number;\r\n /** Value at or below which status becomes 'critical' (low is bad) */\r\n criticalLow?: number;\r\n}\r\n\r\n/**\r\n * Complete property configuration\r\n */\r\nexport interface PropertyConfig {\r\n /** Display name (sentence case per AstroUXDS) */\r\n label: string;\r\n /** Astro icon name */\r\n icon: AstroIconName;\r\n /** Unit of measurement */\r\n unit?: string;\r\n /** Precision for number formatting */\r\n precision?: number;\r\n /** Status thresholds for auto-derivation */\r\n thresholds?: StatusThresholds;\r\n /** Category for grouping */\r\n category?: PropertyCategory;\r\n /** Description for tooltips */\r\n description?: string;\r\n /** Format function override */\r\n format?: (value: number) => string;\r\n}\r\n\r\n/**\r\n * Property categories for organization\r\n */\r\nexport type PropertyCategory =\r\n | \"power\"\r\n | \"thermal\"\r\n | \"attitude\"\r\n | \"communications\"\r\n | \"propulsion\"\r\n | \"navigation\"\r\n | \"payload\"\r\n | \"health\"\r\n | \"orbital\"\r\n | \"general\";\r\n\r\n/**\r\n * Property key - either a preset name or custom string\r\n */\r\nexport type PropertyKey = keyof typeof PROPERTY_PRESETS | (string & {});\r\n\r\n// =============================================================================\r\n// Property Presets\r\n// =============================================================================\r\n\r\n/**\r\n * Predefined property configurations for common space operations telemetry\r\n *\r\n * These provide sensible defaults that can be overridden per-use.\r\n */\r\nexport const PROPERTY_PRESETS = {\r\n // === Power System ===\r\n battery: {\r\n label: \"Battery\",\r\n icon: \"battery-full\" as AstroIconName,\r\n unit: \"%\",\r\n precision: 1,\r\n category: \"power\" as PropertyCategory,\r\n // Low values are bad for battery (use *Low thresholds)\r\n thresholds: { criticalLow: 10, seriousLow: 20, cautionLow: 30 },\r\n description: \"Battery state of charge\",\r\n },\r\n voltage: {\r\n label: \"Voltage\",\r\n icon: \"propulsion-power\" as AstroIconName,\r\n unit: \"V\",\r\n precision: 2,\r\n category: \"power\" as PropertyCategory,\r\n thresholds: { criticalLow: 24, cautionLow: 26 },\r\n description: \"Bus voltage\",\r\n },\r\n current: {\r\n label: \"Current\",\r\n icon: \"propulsion-power\" as AstroIconName,\r\n unit: \"A\",\r\n precision: 2,\r\n category: \"power\" as PropertyCategory,\r\n description: \"Current draw\",\r\n },\r\n power: {\r\n label: \"Power\",\r\n icon: \"propulsion-power\" as AstroIconName,\r\n unit: \"W\",\r\n precision: 1,\r\n category: \"power\" as PropertyCategory,\r\n description: \"Power consumption or generation\",\r\n },\r\n solarPower: {\r\n label: \"Solar\",\r\n icon: \"solar\" as AstroIconName,\r\n unit: \"W\",\r\n precision: 1,\r\n category: \"power\" as PropertyCategory,\r\n description: \"Solar array output\",\r\n },\r\n load: {\r\n label: \"Load\",\r\n icon: \"propulsion-power\" as AstroIconName,\r\n unit: \"W\",\r\n precision: 1,\r\n category: \"power\" as PropertyCategory,\r\n description: \"Power load\",\r\n },\r\n\r\n // === Thermal ===\r\n temperature: {\r\n label: \"Temperature\",\r\n icon: \"thermal\" as AstroIconName,\r\n unit: \"°C\",\r\n precision: 1,\r\n category: \"thermal\" as PropertyCategory,\r\n thresholds: {\r\n critical: 80,\r\n serious: 70,\r\n caution: 60,\r\n cautionLow: -20,\r\n criticalLow: -40,\r\n },\r\n description: \"Component temperature\",\r\n },\r\n heater: {\r\n label: \"Heater\",\r\n icon: \"thermal\" as AstroIconName,\r\n unit: \"\",\r\n category: \"thermal\" as PropertyCategory,\r\n description: \"Heater status\",\r\n },\r\n\r\n // === Attitude ===\r\n roll: {\r\n label: \"Roll\",\r\n icon: \"explore\" as AstroIconName,\r\n unit: \"°\",\r\n precision: 2,\r\n category: \"attitude\" as PropertyCategory,\r\n thresholds: { critical: 45, caution: 30 },\r\n description: \"Roll angle\",\r\n },\r\n pitch: {\r\n label: \"Pitch\",\r\n icon: \"explore\" as AstroIconName,\r\n unit: \"°\",\r\n precision: 2,\r\n category: \"attitude\" as PropertyCategory,\r\n thresholds: { critical: 45, caution: 30 },\r\n description: \"Pitch angle\",\r\n },\r\n yaw: {\r\n label: \"Yaw\",\r\n icon: \"explore\" as AstroIconName,\r\n unit: \"°\",\r\n precision: 2,\r\n category: \"attitude\" as PropertyCategory,\r\n thresholds: { critical: 45, caution: 30 },\r\n description: \"Yaw angle\",\r\n },\r\n pointingError: {\r\n label: \"Pointing error\",\r\n icon: \"explore\" as AstroIconName,\r\n unit: \"°\",\r\n precision: 3,\r\n category: \"attitude\" as PropertyCategory,\r\n thresholds: { critical: 1.0, serious: 0.5, caution: 0.1 },\r\n description: \"Attitude pointing error\",\r\n },\r\n angularVelocity: {\r\n label: \"Angular velocity\",\r\n icon: \"explore\" as AstroIconName,\r\n unit: \"°/s\",\r\n precision: 3,\r\n category: \"attitude\" as PropertyCategory,\r\n thresholds: { critical: 5.0, caution: 2.0 },\r\n description: \"Rotation rate\",\r\n },\r\n\r\n // === Communications ===\r\n signalStrength: {\r\n label: \"Signal\",\r\n icon: \"antenna-receive\" as AstroIconName,\r\n unit: \"dBm\",\r\n precision: 1,\r\n category: \"communications\" as PropertyCategory,\r\n thresholds: { criticalLow: -100, cautionLow: -85 },\r\n description: \"Received signal strength\",\r\n },\r\n dataRate: {\r\n label: \"Data rate\",\r\n icon: \"antenna-transmit\" as AstroIconName,\r\n unit: \"Mbps\",\r\n precision: 2,\r\n category: \"communications\" as PropertyCategory,\r\n description: \"Communication data rate\",\r\n },\r\n packetLoss: {\r\n label: \"Packet loss\",\r\n icon: \"netcom\" as AstroIconName,\r\n unit: \"%\",\r\n precision: 2,\r\n category: \"communications\" as PropertyCategory,\r\n thresholds: { critical: 10, serious: 5, caution: 1 },\r\n description: \"Communication packet loss rate\",\r\n },\r\n snr: {\r\n label: \"SNR\",\r\n icon: \"antenna\" as AstroIconName,\r\n unit: \"dB\",\r\n precision: 1,\r\n category: \"communications\" as PropertyCategory,\r\n thresholds: { criticalLow: 5, cautionLow: 10 },\r\n description: \"Signal-to-noise ratio\",\r\n },\r\n queue: {\r\n label: \"Queue\",\r\n icon: \"netcom\" as AstroIconName,\r\n unit: \"pkts\",\r\n precision: 0,\r\n category: \"communications\" as PropertyCategory,\r\n thresholds: { critical: 1000, caution: 500 },\r\n description: \"Packet queue depth\",\r\n },\r\n\r\n // === Propulsion ===\r\n fuelLevel: {\r\n label: \"Fuel\",\r\n icon: \"propulsion-power\" as AstroIconName,\r\n unit: \"%\",\r\n precision: 1,\r\n category: \"propulsion\" as PropertyCategory,\r\n thresholds: { critical: 5, serious: 10, caution: 20 },\r\n description: \"Propellant remaining\",\r\n },\r\n deltaV: {\r\n label: \"Delta-V\",\r\n icon: \"propulsion-power\" as AstroIconName,\r\n unit: \"m/s\",\r\n precision: 1,\r\n category: \"propulsion\" as PropertyCategory,\r\n description: \"Available delta-V budget\",\r\n },\r\n thrustLevel: {\r\n label: \"Thrust\",\r\n icon: \"propulsion-power\" as AstroIconName,\r\n unit: \"N\",\r\n precision: 2,\r\n category: \"propulsion\" as PropertyCategory,\r\n description: \"Current thrust output\",\r\n },\r\n\r\n // === Navigation ===\r\n altitude: {\r\n label: \"Altitude\",\r\n icon: \"altitude\" as AstroIconName,\r\n unit: \"km\",\r\n precision: 1,\r\n category: \"orbital\" as PropertyCategory,\r\n thresholds: { criticalLow: 200, cautionLow: 250 },\r\n description: \"Orbital altitude\",\r\n },\r\n velocity: {\r\n label: \"Velocity\",\r\n icon: \"altitude\" as AstroIconName,\r\n unit: \"km/s\",\r\n precision: 3,\r\n category: \"orbital\" as PropertyCategory,\r\n description: \"Orbital velocity\",\r\n },\r\n inclination: {\r\n label: \"Inclination\",\r\n icon: \"altitude\" as AstroIconName,\r\n unit: \"°\",\r\n precision: 2,\r\n category: \"orbital\" as PropertyCategory,\r\n description: \"Orbital inclination\",\r\n },\r\n eccentricity: {\r\n label: \"Eccentricity\",\r\n icon: \"altitude\" as AstroIconName,\r\n unit: \"\",\r\n precision: 6,\r\n category: \"orbital\" as PropertyCategory,\r\n description: \"Orbital eccentricity\",\r\n },\r\n\r\n // === Payload ===\r\n payloadStatus: {\r\n label: \"Payload\",\r\n icon: \"payload\" as AstroIconName,\r\n unit: \"\",\r\n category: \"payload\" as PropertyCategory,\r\n description: \"Payload operational status\",\r\n },\r\n storageUsed: {\r\n label: \"Storage\",\r\n icon: \"hardware\" as AstroIconName,\r\n unit: \"%\",\r\n precision: 1,\r\n category: \"payload\" as PropertyCategory,\r\n thresholds: { critical: 95, serious: 90, caution: 80 },\r\n description: \"Onboard storage usage\",\r\n },\r\n\r\n // === Health ===\r\n cpuUsage: {\r\n label: \"CPU\",\r\n icon: \"processor\" as AstroIconName,\r\n unit: \"%\",\r\n precision: 1,\r\n category: \"health\" as PropertyCategory,\r\n thresholds: { critical: 95, serious: 85, caution: 75 },\r\n description: \"Processor utilization\",\r\n },\r\n memoryUsage: {\r\n label: \"Memory\",\r\n icon: \"processor\" as AstroIconName,\r\n unit: \"%\",\r\n precision: 1,\r\n category: \"health\" as PropertyCategory,\r\n thresholds: { critical: 95, serious: 85, caution: 75 },\r\n description: \"Memory utilization\",\r\n },\r\n uptime: {\r\n label: \"Uptime\",\r\n icon: \"mission\" as AstroIconName,\r\n unit: \"s\",\r\n precision: 0,\r\n category: \"health\" as PropertyCategory,\r\n description: \"System uptime\",\r\n },\r\n\r\n // === General ===\r\n count: {\r\n label: \"Count\",\r\n icon: \"list\" as AstroIconName,\r\n unit: \"\",\r\n precision: 0,\r\n category: \"general\" as PropertyCategory,\r\n description: \"Item count\",\r\n },\r\n percentage: {\r\n label: \"Percentage\",\r\n icon: \"info\" as AstroIconName,\r\n unit: \"%\",\r\n precision: 1,\r\n category: \"general\" as PropertyCategory,\r\n description: \"Percentage value\",\r\n },\r\n duration: {\r\n label: \"Duration\",\r\n icon: \"schedule\" as AstroIconName,\r\n unit: \"s\",\r\n precision: 0,\r\n category: \"general\" as PropertyCategory,\r\n description: \"Time duration\",\r\n },\r\n} as const satisfies Record<string, PropertyConfig>;\r\n\r\n// =============================================================================\r\n// Category Icons (for section headers)\r\n// =============================================================================\r\n\r\nexport const CATEGORY_ICONS: Record<PropertyCategory, AstroIconName> = {\r\n power: \"propulsion-power\",\r\n thermal: \"thermal\",\r\n attitude: \"explore\",\r\n communications: \"antenna\",\r\n propulsion: \"propulsion-power\",\r\n navigation: \"gps-fixed\",\r\n payload: \"payload\",\r\n health: \"favorite\",\r\n orbital: \"altitude\",\r\n general: \"info\",\r\n};\r\n\r\nexport const CATEGORY_LABELS: Record<PropertyCategory, string> = {\r\n power: \"Power\",\r\n thermal: \"Thermal\",\r\n attitude: \"Attitude\",\r\n communications: \"Communications\",\r\n propulsion: \"Propulsion\",\r\n navigation: \"Navigation\",\r\n payload: \"Payload\",\r\n health: \"Health\",\r\n orbital: \"Orbital\",\r\n general: \"General\",\r\n};\r\n\r\n// =============================================================================\r\n// Utility Functions\r\n// =============================================================================\r\n\r\n/**\r\n * Get property configuration by key\r\n * Returns preset config or a default config for unknown properties\r\n */\r\nexport function getPropertyConfig(key: PropertyKey): PropertyConfig {\r\n const preset = PROPERTY_PRESETS[key as keyof typeof PROPERTY_PRESETS];\r\n if (preset) {\r\n return preset;\r\n }\r\n\r\n // Return default config for unknown properties\r\n return {\r\n label: formatPropertyLabel(key),\r\n icon: \"info\",\r\n unit: \"\",\r\n precision: 2,\r\n category: \"general\",\r\n description: key,\r\n };\r\n}\r\n\r\n/**\r\n * Format a property key into a display label (sentence case)\r\n */\r\nexport function formatPropertyLabel(key: string): string {\r\n // Handle camelCase → Sentence case\r\n const words = key\r\n .replace(/([A-Z])/g, \" $1\")\r\n .replace(/[_-]/g, \" \")\r\n .trim()\r\n .toLowerCase();\r\n return words.charAt(0).toUpperCase() + words.slice(1);\r\n}\r\n\r\n/**\r\n * Derive status level from a value and thresholds\r\n *\r\n * @param value - Current value\r\n * @param thresholds - Status thresholds\r\n * @returns StatusLevel\r\n *\r\n * @example\r\n * ```tsx\r\n * deriveStatus(75, { caution: 60, critical: 80 }) // 'caution'\r\n * deriveStatus(25, { criticalLow: 10, cautionLow: 30 }) // 'caution'\r\n * deriveStatus(50, { caution: 60, critical: 80 }) // 'normal'\r\n * ```\r\n */\r\nexport function deriveStatus(\r\n value: number | undefined | null,\r\n thresholds?: StatusThresholds,\r\n): StatusLevel {\r\n if (value === undefined || value === null || !Number.isFinite(value)) {\r\n return \"off\";\r\n }\r\n\r\n if (!thresholds) {\r\n return \"normal\";\r\n }\r\n\r\n // Check high thresholds (value >= threshold is bad)\r\n if (thresholds.critical !== undefined && value >= thresholds.critical) {\r\n return \"critical\";\r\n }\r\n if (thresholds.serious !== undefined && value >= thresholds.serious) {\r\n return \"serious\";\r\n }\r\n if (thresholds.caution !== undefined && value >= thresholds.caution) {\r\n return \"caution\";\r\n }\r\n\r\n // Check low thresholds (value <= threshold is bad)\r\n if (thresholds.criticalLow !== undefined && value <= thresholds.criticalLow) {\r\n return \"critical\";\r\n }\r\n if (thresholds.seriousLow !== undefined && value <= thresholds.seriousLow) {\r\n return \"serious\";\r\n }\r\n if (thresholds.cautionLow !== undefined && value <= thresholds.cautionLow) {\r\n return \"caution\";\r\n }\r\n\r\n return \"normal\";\r\n}\r\n\r\n/**\r\n * Derive status for battery specifically (low is bad)\r\n */\r\nexport function deriveBatteryStatus(level: number | undefined): StatusLevel {\r\n if (level === undefined || level === null) return \"off\";\r\n if (level <= 10) return \"critical\";\r\n if (level <= 20) return \"serious\";\r\n if (level <= 30) return \"caution\";\r\n return \"normal\";\r\n}\r\n\r\n/**\r\n * Format a value with its property config\r\n */\r\nexport function formatPropertyValue(\r\n value: number | undefined | null,\r\n config: PropertyConfig,\r\n): string {\r\n if (value === undefined || value === null || !Number.isFinite(value)) {\r\n return \"--\";\r\n }\r\n\r\n if (config.format) {\r\n return config.format(value);\r\n }\r\n\r\n const precision = config.precision ?? 2;\r\n const formatted = value.toFixed(precision);\r\n const unit = config.unit ?? \"\";\r\n\r\n return unit\r\n ? `${formatted}${unit.startsWith(\"°\") || unit.startsWith(\"%\") ? \"\" : \" \"}${unit}`\r\n : formatted;\r\n}\r\n\r\n/**\r\n * Create a custom property config by merging with a preset\r\n */\r\nexport function createPropertyConfig(\r\n baseKey: PropertyKey,\r\n overrides: Partial<PropertyConfig>,\r\n): PropertyConfig {\r\n const base = getPropertyConfig(baseKey);\r\n return { ...base, ...overrides };\r\n}\r\n\r\n/**\r\n * Get all properties in a category\r\n */\r\nexport function getPropertiesByCategory(\r\n category: PropertyCategory,\r\n): Array<{ key: string; config: PropertyConfig }> {\r\n return Object.entries(PROPERTY_PRESETS)\r\n .filter(([_, config]) => config.category === category)\r\n .map(([key, config]) => ({ key, config }));\r\n}\r\n"],"mappings":"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"}