@zendir/ui 0.1.14 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/react/astro/SimulationControls.js +3 -3
- package/dist/react/astro/SimulationControls.js.map +1 -1
- package/dist/react/astro/UnifiedTimeline.d.ts +70 -8
- package/dist/react/astro/UnifiedTimeline.js +886 -260
- package/dist/react/astro/UnifiedTimeline.js.map +1 -1
- package/dist/react/astro/index.d.ts +2 -1
- package/dist/react/charts/GroundTrackMap.d.ts +40 -1
- package/dist/react/charts/GroundTrackMap.js +98 -47
- package/dist/react/charts/GroundTrackMap.js.map +1 -1
- package/dist/react/charts/GroundTrackMapLeaflet.d.ts +11 -2
- package/dist/react/charts/GroundTrackMapLeaflet.js +128 -15
- package/dist/react/charts/GroundTrackMapLeaflet.js.map +1 -1
- package/dist/react/charts/index.d.ts +1 -1
- package/dist/react/charts/unified/theme.d.ts +7 -7
- package/dist/react/context/CategoryContext.d.ts +51 -0
- package/dist/react/context/CategoryContext.js +36 -0
- package/dist/react/context/CategoryContext.js.map +1 -0
- package/dist/react/context/index.d.ts +2 -0
- package/dist/react/index.d.ts +6 -4
- package/dist/react/types.d.ts +26 -0
- package/dist/react/types.js.map +1 -1
- package/dist/react/utils/categoryPalette.d.ts +43 -0
- package/dist/react/utils/categoryPalette.js +104 -0
- package/dist/react/utils/categoryPalette.js.map +1 -0
- package/dist/react/utils/index.d.ts +1 -0
- package/dist/react/utils/index.js.map +1 -1
- package/dist/react.js +6 -0
- package/dist/react.js.map +1 -1
- package/dist/style.css +49 -0
- package/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useContext, createContext } from "react";
|
|
3
|
+
import { CategoryPalette } from "../utils/categoryPalette.js";
|
|
4
|
+
const CategoryContext = createContext(null);
|
|
5
|
+
CategoryContext.displayName = "CategoryContext";
|
|
6
|
+
function CategoryProvider({
|
|
7
|
+
categories,
|
|
8
|
+
categoryLabel = "Categories",
|
|
9
|
+
fallbackPalette,
|
|
10
|
+
children
|
|
11
|
+
}) {
|
|
12
|
+
const value = useMemo(() => ({
|
|
13
|
+
palette: new CategoryPalette(categories, fallbackPalette),
|
|
14
|
+
categories,
|
|
15
|
+
categoryLabel
|
|
16
|
+
}), [categories, categoryLabel, fallbackPalette]);
|
|
17
|
+
return /* @__PURE__ */ jsx(CategoryContext.Provider, { value, children });
|
|
18
|
+
}
|
|
19
|
+
function useCategoryPalette() {
|
|
20
|
+
return useContext(CategoryContext);
|
|
21
|
+
}
|
|
22
|
+
function useCategoryPaletteRequired() {
|
|
23
|
+
const ctx = useContext(CategoryContext);
|
|
24
|
+
if (!ctx) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
"useCategoryPaletteRequired() was called outside of a <CategoryProvider>. Wrap a parent component with <CategoryProvider categories={[...]}> or use useCategoryPalette() for graceful null handling."
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
return ctx;
|
|
30
|
+
}
|
|
31
|
+
export {
|
|
32
|
+
CategoryProvider,
|
|
33
|
+
useCategoryPalette,
|
|
34
|
+
useCategoryPaletteRequired
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=CategoryContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CategoryContext.js","sources":["../../../src/react/context/CategoryContext.tsx"],"sourcesContent":["/**\r\n * @zendir/ui — CategoryProvider\r\n *\r\n * Optional React context for sharing a `CategoryPalette` and display label\r\n * across sibling components in a dashboard layout. Components that are\r\n * \"category-aware\" (Timeline, GroundTrackMap, AstroChart, DataTable) can\r\n * read from this context to resolve colors/labels without each needing\r\n * explicit palette props.\r\n *\r\n * **This context is fully opt-in.** Components continue to work standalone\r\n * — explicit `color` / `team` props always take precedence over context.\r\n *\r\n * @example\r\n * ```tsx\r\n * import { CategoryProvider, useCategoryPalette } from '@zendir/ui';\r\n *\r\n * const categories = [\r\n * { id: 'alpha', label: 'Team Alpha', color: '#2dccff' },\r\n * { id: 'bravo', label: 'Team Bravo', color: '#fce83a' },\r\n * ];\r\n *\r\n * // Wrap a section of your dashboard\r\n * <CategoryProvider categories={categories} categoryLabel=\"Squads\">\r\n * <Timeline events={events} />\r\n * <GroundTrackMap pins={pins} />\r\n * </CategoryProvider>\r\n *\r\n * // Inside any component\r\n * function MyWidget() {\r\n * const ctx = useCategoryPalette();\r\n * if (!ctx) return null; // graceful when no provider\r\n * const color = ctx.palette.getColor('alpha');\r\n * const label = ctx.categoryLabel; // \"Squads\"\r\n * }\r\n * ```\r\n */\r\n\r\nimport React, { createContext, useContext, useMemo, type ReactNode } from 'react';\r\nimport { CategoryPalette } from '../utils/categoryPalette';\r\nimport type { CategoryDef } from '../types';\r\n\r\n// =============================================================================\r\n// Context value\r\n// =============================================================================\r\n\r\nexport interface CategoryContextValue {\r\n /** Palette instance built from the provided categories. */\r\n palette: CategoryPalette;\r\n /** All registered category definitions. */\r\n categories: CategoryDef[];\r\n /**\r\n * Human-readable label for the grouping dimension.\r\n * Defaults to `\"Categories\"`. Components that support a label override\r\n * (e.g. Timeline's `teamLabel`) should fall back to this when no\r\n * explicit prop is provided.\r\n */\r\n categoryLabel: string;\r\n}\r\n\r\nconst CategoryContext = createContext<CategoryContextValue | null>(null);\r\nCategoryContext.displayName = 'CategoryContext';\r\n\r\n// =============================================================================\r\n// Provider\r\n// =============================================================================\r\n\r\nexport interface CategoryProviderProps {\r\n /** Category definitions — each must have `id`, `label`, and `color`. */\r\n categories: CategoryDef[];\r\n /**\r\n * Display label for the grouping dimension, e.g. `\"Teams\"`, `\"Squads\"`,\r\n * `\"Subsystems\"`. Defaults to `\"Categories\"`.\r\n */\r\n categoryLabel?: string;\r\n /**\r\n * Optional custom fallback palette for auto-assigned unknown ids.\r\n * Defaults to the Astro data-viz palette built into `CategoryPalette`.\r\n */\r\n fallbackPalette?: string[];\r\n children: ReactNode;\r\n}\r\n\r\n/**\r\n * Provides a shared `CategoryPalette` to descendant components.\r\n *\r\n * Wrap a dashboard section (not the entire app) so sibling components\r\n * like Timeline + Map + Charts resolve the same colors for the same ids.\r\n */\r\nexport function CategoryProvider({\r\n categories,\r\n categoryLabel = 'Categories',\r\n fallbackPalette,\r\n children,\r\n}: CategoryProviderProps): React.ReactElement {\r\n const value = useMemo<CategoryContextValue>(() => ({\r\n palette: new CategoryPalette(categories, fallbackPalette),\r\n categories,\r\n categoryLabel,\r\n }), [categories, categoryLabel, fallbackPalette]);\r\n\r\n return (\r\n <CategoryContext.Provider value={value}>\r\n {children}\r\n </CategoryContext.Provider>\r\n );\r\n}\r\n\r\n// =============================================================================\r\n// Hooks\r\n// =============================================================================\r\n\r\n/**\r\n * Access the nearest `CategoryProvider`'s palette and label.\r\n *\r\n * Returns `null` when no provider is present — components should treat\r\n * this as \"standalone mode\" and fall back to explicit props / defaults.\r\n */\r\nexport function useCategoryPalette(): CategoryContextValue | null {\r\n return useContext(CategoryContext);\r\n}\r\n\r\n/**\r\n * Like `useCategoryPalette()` but throws if no provider is found.\r\n * Use only when you know a provider is always present.\r\n */\r\nexport function useCategoryPaletteRequired(): CategoryContextValue {\r\n const ctx = useContext(CategoryContext);\r\n if (!ctx) {\r\n throw new Error(\r\n 'useCategoryPaletteRequired() was called outside of a <CategoryProvider>. ' +\r\n 'Wrap a parent component with <CategoryProvider categories={[...]}> or ' +\r\n 'use useCategoryPalette() for graceful null handling.',\r\n );\r\n }\r\n return ctx;\r\n}\r\n"],"names":[],"mappings":";;;AA2DA,MAAM,kBAAkB,cAA2C,IAAI;AACvE,gBAAgB,cAAc;AA4BvB,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AACF,GAA8C;AAC5C,QAAM,QAAQ,QAA8B,OAAO;AAAA,IACjD,SAAS,IAAI,gBAAgB,YAAY,eAAe;AAAA,IACxD;AAAA,IACA;AAAA,EAAA,IACE,CAAC,YAAY,eAAe,eAAe,CAAC;AAEhD,SACE,oBAAC,gBAAgB,UAAhB,EAAyB,OACvB,SAAA,CACH;AAEJ;AAYO,SAAS,qBAAkD;AAChE,SAAO,WAAW,eAAe;AACnC;AAMO,SAAS,6BAAmD;AACjE,QAAM,MAAM,WAAW,eAAe;AACtC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAIJ;AACA,SAAO;AACT;"}
|
|
@@ -3,3 +3,5 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export { DisplaySettingsProvider, useDisplaySettings, useDisplaySettingsOptional, getEffectiveCompactMode, PRESET_COLORS, GLASS_TINTS, } from './DisplaySettingsContext';
|
|
5
5
|
export type { DisplaySettings, DisplaySettingsContextValue, DisplaySettingsProviderProps, ColorTarget, PresetColorKey, GlassTintKey, } from './DisplaySettingsContext';
|
|
6
|
+
export { CategoryProvider, useCategoryPalette, useCategoryPaletteRequired, } from './CategoryContext';
|
|
7
|
+
export type { CategoryContextValue, CategoryProviderProps, } from './CategoryContext';
|
package/dist/react/index.d.ts
CHANGED
|
@@ -20,19 +20,21 @@ export { ThemeProvider, useTheme, useThemeTokens, useScrollbarStyles, CardAccent
|
|
|
20
20
|
export type { ThemeProviderProps, ThemeContextValue, ThemeVariant, ThemeMode, ThemeTokens, ThemeColors, ThemeAnimation, ThemeFocus, LayoutTokens, BorderTokens, CardAccentKey, CardAccentColor, CardAccentContextValue, CardAccentProviderProps, } from './theme';
|
|
21
21
|
export { DisplaySettingsProvider, useDisplaySettings, useDisplaySettingsOptional, getEffectiveCompactMode, PRESET_COLORS, GLASS_TINTS, } from './context';
|
|
22
22
|
export type { DisplaySettings, DisplaySettingsContextValue, DisplaySettingsProviderProps, ColorTarget, PresetColorKey, GlassTintKey, } from './context';
|
|
23
|
+
export { CategoryProvider, useCategoryPalette, useCategoryPaletteRequired, } from './context';
|
|
24
|
+
export type { CategoryContextValue, CategoryProviderProps, } from './context';
|
|
23
25
|
export { ErrorBoundary, withErrorBoundary } from './shared/ErrorBoundary';
|
|
24
26
|
export type { ErrorBoundaryProps } from './shared/ErrorBoundary';
|
|
25
27
|
export { SkeletonText, SkeletonBox, SkeletonCircle, SkeletonCard, SkeletonChart, Skeleton3D, } from './shared/Skeleton';
|
|
26
28
|
export type { SkeletonTextProps, SkeletonBoxProps, SkeletonCircleProps, SkeletonCardProps, SkeletonChartProps, Skeleton3DProps, } from './shared/Skeleton';
|
|
27
|
-
export { withNullSafety, safeNumber, isValidNumber, formatNumber, formatTabular, formatTemperature, formatDataRate, formatDistance, formatAltitude, formatVelocity, formatPercentage, formatPower, formatFrequency, formatDuration, formatCountdown, formatUTC, formatTime, formatCoordinate, formatLatLon, formatDegrees, formatDecibels, clamp, lerp, mapRange, STATUS_COLORS, getStatusColor, getStatusFromValue, normalizeStatus, isStatusLevel, getStatusSeverity, getWorstStatus, classNames, tabularNumsStyle, transitions, focusRingStyle, addAlpha, safeAccentText, } from './utils';
|
|
29
|
+
export { withNullSafety, safeNumber, isValidNumber, formatNumber, formatTabular, formatTemperature, formatDataRate, formatDistance, formatAltitude, formatVelocity, formatPercentage, formatPower, formatFrequency, formatDuration, formatCountdown, formatUTC, formatTime, formatCoordinate, formatLatLon, formatDegrees, formatDecibels, clamp, lerp, mapRange, STATUS_COLORS, getStatusColor, getStatusFromValue, normalizeStatus, isStatusLevel, getStatusSeverity, getWorstStatus, classNames, tabularNumsStyle, transitions, focusRingStyle, addAlpha, safeAccentText, CategoryPalette, } from './utils';
|
|
28
30
|
export type { StatusLevel, FormatNumberOptions } from './utils';
|
|
29
31
|
export { StatusIndicator, ClassificationBanner, GlobalStatusBar, MissionClock, MonitoringIcon, Progress, Notification, Timeline, SimulationControls, MiniSimulationControls, SimulationControlsWithClock, } from './astro';
|
|
30
|
-
export type { StatusIndicatorProps, StatusVariant, ClassificationBannerProps, ClassificationLevel, GlobalStatusBarProps, MissionClockProps, MonitoringIconProps, MonitoringStatus, ProgressProps, NotificationProps, NotificationStatus, TimelineProps, TimelineEvent, TimelineTrackDef, TimelineViewMode, TimeFormat, TimelineFilter, AstroStatus, AstroClassification, SimulationControlsProps, MiniSimulationControlsProps, SimulationControlsWithClockProps, } from './astro';
|
|
32
|
+
export type { StatusIndicatorProps, StatusVariant, ClassificationBannerProps, ClassificationLevel, GlobalStatusBarProps, MissionClockProps, MonitoringIconProps, MonitoringStatus, ProgressProps, NotificationProps, NotificationStatus, TimelineProps, TimelineEvent, TimelineTeam, TimelineTrackDef, TimelineViewMode, TimeFormat, TimelineFilter, AstroStatus, AstroClassification, SimulationControlsProps, MiniSimulationControlsProps, SimulationControlsWithClockProps, } from './astro';
|
|
31
33
|
export { AstroChart } from './charts';
|
|
32
34
|
export type { AstroChartProps, AstroChartHandle } from './charts';
|
|
33
35
|
export { GroundTrackMap } from './charts';
|
|
34
|
-
export type { GroundTrackMapProps } from './charts';
|
|
36
|
+
export type { GroundTrackMapProps, MapPin } from './charts';
|
|
35
37
|
export { useCompactMode } from './hooks/useCompactMode';
|
|
36
38
|
export type { UseCompactModeOptions, UseCompactModeResult } from './hooks/useCompactMode';
|
|
37
|
-
export type { SpacecraftPosition, Spacecraft, GroundStation, GroundTrackPoint, AccessData, AccessWindow, TelemetryData, OrbitalElements, Quaternion, EulerAngles, AngularVelocity, AttitudeData, PointingMode, EclipseInfo, DetailedLinkBudget, ThermalZone, ThermalData, ThrusterStatus, PropulsionSummary, ReactionWheelData, LVLHVector, LVLHState, ThrusterFireEvent, PlanetId, PlanetInfo, } from './types';
|
|
39
|
+
export type { SpacecraftPosition, Spacecraft, GroundStation, GroundTrackPoint, AccessData, AccessWindow, TelemetryData, OrbitalElements, Quaternion, EulerAngles, AngularVelocity, AttitudeData, PointingMode, EclipseInfo, DetailedLinkBudget, ThermalZone, ThermalData, ThrusterStatus, PropulsionSummary, ReactionWheelData, LVLHVector, LVLHState, ThrusterFireEvent, PlanetId, PlanetInfo, CategoryDef, } from './types';
|
|
38
40
|
export { estimateOrbitalPeriod, estimateOrbitalVelocity, auToKm, normalizePlanetName, getPlanet, PLANETS, } from './types';
|
package/dist/react/types.d.ts
CHANGED
|
@@ -6,6 +6,32 @@
|
|
|
6
6
|
*
|
|
7
7
|
* All types here mirror the @zendir/sdk interfaces.
|
|
8
8
|
*/
|
|
9
|
+
/**
|
|
10
|
+
* A named, colored data category — the SDK's shared concept for any secondary
|
|
11
|
+
* grouping dimension (teams, squads, subsystems, mission phases, etc.).
|
|
12
|
+
*
|
|
13
|
+
* Components that support category-aware coloring accept `CategoryDef` arrays
|
|
14
|
+
* and/or a `categoryId` field on individual data items. The `CategoryPalette`
|
|
15
|
+
* utility resolves ids → colors/labels consistently across an entire dashboard.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* const categories: CategoryDef[] = [
|
|
19
|
+
* { id: 'alpha', label: 'Team Alpha', color: '#2dccff' },
|
|
20
|
+
* { id: 'bravo', label: 'Team Bravo', color: '#fce83a' },
|
|
21
|
+
* ];
|
|
22
|
+
*/
|
|
23
|
+
export interface CategoryDef {
|
|
24
|
+
/** Stable unique identifier (string or numeric) */
|
|
25
|
+
id: string | number;
|
|
26
|
+
/** Human-readable display name */
|
|
27
|
+
label: string;
|
|
28
|
+
/** CSS color used for visual accents (stripes, rings, swatches, series lines) */
|
|
29
|
+
color: string;
|
|
30
|
+
/** Optional icon name from the Astro icon set */
|
|
31
|
+
icon?: string;
|
|
32
|
+
/** Arbitrary metadata for app-specific needs */
|
|
33
|
+
meta?: Record<string, unknown>;
|
|
34
|
+
}
|
|
9
35
|
export interface SpacecraftPosition {
|
|
10
36
|
/** Optional spacecraft id (when combined with Spacecraft) */
|
|
11
37
|
id?: string;
|
package/dist/react/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sources":["../../src/react/types.ts"],"sourcesContent":["/**\n * @zendir/ui - Local Type Definitions\n * \n * These types are provided so the UI library can be used without @zendir/sdk.\n * If you have @zendir/sdk installed, those types will be used instead.\n * \n * All types here mirror the @zendir/sdk interfaces.\n */\n\n// =============================================================================\n// Spacecraft Types\n// =============================================================================\n\nexport interface SpacecraftPosition {\n /** Optional spacecraft id (when combined with Spacecraft) */\n id?: string;\n /** Optional display name */\n name?: string;\n /** Latitude in degrees (-90 to 90) */\n latitude: number;\n /** Longitude in degrees (-180 to 180) */\n longitude: number;\n /** Altitude in kilometers */\n altitude: number;\n /** Velocity in km/s */\n velocity?: number;\n /** Heading in degrees */\n heading?: number;\n /** Timestamp */\n timestamp?: string;\n /** Orbit type (e.g. LEO, GEO) */\n orbitType?: string;\n /** Orbital inclination in degrees */\n inclination?: number;\n /** Health/operational status using AstroUXDS 6-level system */\n status?: 'off' | 'standby' | 'normal' | 'caution' | 'serious' | 'critical';\n}\n\nexport interface Spacecraft {\n id: string;\n name: string;\n noradId?: number;\n type?: string;\n /** Status using AstroUXDS 6-level system */\n status?: 'off' | 'standby' | 'normal' | 'caution' | 'serious' | 'critical';\n}\n\n// =============================================================================\n// Ground Station Types\n// =============================================================================\n\nexport interface GroundStation {\n id: string;\n name: string;\n latitude: number;\n longitude: number;\n elevation?: number;\n /** Minimum elevation angle for visibility (degrees) */\n minElevation?: number;\n network?: string;\n}\n\nexport interface GroundTrackPoint {\n latitude: number;\n longitude: number;\n altitude: number;\n timestamp: string;\n}\n\n// =============================================================================\n// Access / Contact Types\n// =============================================================================\n\nexport interface AccessData {\n stationId: string;\n stationName: string;\n spacecraftId: string;\n aos: string; // Acquisition of Signal - ISO timestamp\n los: string; // Loss of Signal - ISO timestamp\n maxElevation: number;\n azimuthAos?: number;\n azimuthLos?: number;\n /** Whether link is currently accessible */\n isAccessible?: boolean;\n /** Current elevation angle (degrees) */\n elevation?: number;\n /** Current azimuth (degrees) */\n azimuth?: number;\n /** Slant range in km */\n slantRange?: number;\n /** Signal strength 0-100 */\n signalStrength?: number;\n /** Link budget details */\n linkBudget?: {\n receivedPower?: number;\n snr?: number;\n dataRate?: number;\n };\n}\n\nexport interface AccessWindow {\n aos: string;\n los: string;\n maxElevation: number;\n stationId: string;\n /** Start time (ISO or ms) */\n startTime?: string | number;\n /** Duration in seconds */\n duration?: number;\n}\n\n// =============================================================================\n// Telemetry Types\n// =============================================================================\n\nexport interface TelemetryData {\n timestamp: string;\n subsystems: {\n power?: {\n status: string;\n batteryLevel?: number;\n solarArrayOutput?: number;\n voltage?: number;\n solarGeneration?: number;\n consumption?: number;\n };\n thermal?: {\n status: string;\n cpuTemp?: number;\n batteryTemp?: number;\n };\n comms?: {\n status: string;\n signalStrength?: number;\n dataRate?: number;\n downlinkRate?: number;\n transmitterStatus?: string;\n packetsQueued?: number;\n bytesTransmitted?: number;\n packetsTransmitted?: number;\n };\n attitude?: {\n status: string;\n pointingError?: number;\n eulerAngles?: EulerAngles;\n targetMode?: string;\n };\n };\n /** Health status (convenience alias / extended) */\n health?: {\n status?: string;\n anomalies?: Array<{ id: string; message: string; severity?: string }>;\n };\n /** Power (convenience alias for subsystems.power / extended) */\n power?: {\n status?: string;\n batteryLevel?: number;\n solarArrayOutput?: number;\n voltage?: number;\n solarGeneration?: number;\n consumption?: number;\n };\n /** Attitude (convenience alias / extended) */\n attitude?: {\n status?: string;\n eulerAngles?: EulerAngles;\n targetMode?: string;\n pointingError?: number;\n };\n /** Communications (convenience alias / extended) */\n communications?: {\n status?: string;\n signalStrength?: number;\n dataRate?: number;\n downlinkRate?: number;\n transmitterStatus?: string;\n packetsQueued?: number;\n bytesTransmitted?: number;\n packetsTransmitted?: number;\n };\n alerts?: Array<{\n id: string;\n severity: string;\n message: string;\n timestamp: string;\n }>;\n}\n\n// =============================================================================\n// Orbital Types\n// =============================================================================\n\nexport interface OrbitalElements {\n semiMajorAxis: number;\n eccentricity: number;\n inclination: number;\n raan: number; // Right Ascension of Ascending Node\n argumentOfPerigee: number;\n trueAnomaly: number;\n period?: number;\n epoch?: string;\n}\n\n// =============================================================================\n// Attitude Types\n// =============================================================================\n\nexport interface Quaternion {\n x: number;\n y: number;\n z: number;\n w: number;\n}\n\nexport interface EulerAngles {\n roll: number;\n pitch: number;\n yaw: number;\n}\n\nexport interface AngularVelocity {\n x: number;\n y: number;\n z: number;\n}\n\nexport interface AttitudeData {\n quaternion: Quaternion;\n eulerAngles: EulerAngles;\n angularVelocity: AngularVelocity;\n targetMode?: string;\n /** Pointing error in degrees */\n pointingError?: number;\n /** Target direction vector [x, y, z] */\n targetDirection?: [number, number, number];\n}\n\nexport type PointingMode = 'nadir' | 'sun' | 'target' | 'inertial' | 'velocity';\n\n// =============================================================================\n// Eclipse Types\n// =============================================================================\n\nexport interface EclipseInfo {\n inEclipse: boolean;\n timeToEclipse: number; // seconds\n eclipseDuration: number; // seconds\n sunlightDuration: number; // seconds\n /** Umbra duration in seconds */\n umbraDuration?: number;\n /** Penumbra duration in seconds */\n penumbraDuration?: number;\n /** Seconds until sunlight (when in eclipse) */\n timeToSunlight?: number;\n}\n\n// =============================================================================\n// Link Budget Types\n// =============================================================================\n\nexport interface DetailedLinkBudget {\n spacecraftId: string;\n groundStationId: string;\n frequency: number;\n eirp: number;\n pathLoss: number;\n atmosphericLoss: number;\n receiverGain: number;\n systemNoiseTemp: number;\n cnoRequired: number;\n cnoActual: number;\n margin: number;\n dataRate: number;\n}\n\n// =============================================================================\n// Thermal Types\n// =============================================================================\n\nexport interface ThermalZone {\n id: string;\n name: string;\n temperature: number;\n minLimit: number;\n maxLimit: number;\n}\n\nexport interface ThermalData {\n timestamp: string;\n zones: ThermalZone[];\n averageTemp: number;\n hottest: { zone: string; temp: number };\n coldest: { zone: string; temp: number };\n}\n\n// =============================================================================\n// Propulsion Types\n// =============================================================================\n\nexport interface ThrusterStatus {\n id: string;\n name: string;\n status: 'ready' | 'firing' | 'disabled' | 'error';\n fuelFlow?: number;\n}\n\nexport interface PropulsionSummary {\n fuelRemaining: number;\n fuelCapacity: number;\n thrusterStatus: ThrusterStatus[];\n deltaVRemaining: number;\n deltaVUsed: number;\n lastManeuver?: string;\n}\n\n// =============================================================================\n// Reaction Wheel / Momentum Types\n// =============================================================================\n\nexport interface ReactionWheelData {\n /** Unique wheel identifier */\n id: string;\n /** Display name (e.g. \"RW-X\", \"RW-1\") */\n name: string;\n /** Mounted axis */\n axis: 'X' | 'Y' | 'Z' | 'skew';\n /** Current stored angular momentum in N·m·s */\n momentumNms: number;\n /** Maximum momentum capacity in N·m·s */\n maxMomentumNms: number;\n /** Current wheel speed in RPM */\n speedRpm: number;\n /** Maximum wheel speed in RPM */\n maxSpeedRpm: number;\n /** Operational status */\n status: 'nominal' | 'saturated' | 'desaturating' | 'off' | 'error';\n /** Power consumption in Watts */\n powerW?: number;\n /** Bearing temperature in °C */\n temperatureC?: number;\n}\n\n/** LVLH (Local Vertical Local Horizontal) frame vector */\nexport interface LVLHVector {\n /** Radial component (local vertical, positive away from Earth) */\n radial: number;\n /** In-track component (along velocity vector) */\n inTrack: number;\n /** Cross-track component (normal to orbital plane) */\n crossTrack: number;\n}\n\n/** Time-stamped LVLH state for trajectory plotting */\nexport interface LVLHState {\n /** Timestamp in milliseconds */\n time: number;\n /** Position in LVLH frame (km) */\n position: LVLHVector;\n /** Velocity in LVLH frame (km/s) */\n velocity: LVLHVector;\n}\n\n/** Thruster firing event */\nexport interface ThrusterFireEvent {\n /** Event timestamp in milliseconds */\n time: number;\n /** Thruster ID */\n thrusterId: string;\n /** Display name */\n name: string;\n /** Delta-V magnitude in m/s */\n deltaVMs: number;\n /** Delta-V direction in LVLH frame (unit vector) */\n deltaVDirection?: LVLHVector;\n /** Burn duration in seconds */\n durationSeconds: number;\n /** Event type */\n type: 'impulsive' | 'finite' | 'continuous';\n}\n\n// =============================================================================\n// Planet Types\n// =============================================================================\n\nexport type PlanetId = \n | 'sun' \n | 'mercury' \n | 'venus' \n | 'earth' \n | 'moon' \n | 'mars' \n | 'jupiter' \n | 'saturn' \n | 'uranus' \n | 'neptune' \n | 'pluto';\n\nexport interface PlanetInfo {\n id: PlanetId;\n name: string;\n radius: number; // km\n /** @deprecated Use radius */\n radiusKm?: number;\n mass: number; // kg\n semiMajorAxis: number; // AU\n /** Distance from Sun in AU (alias for semiMajorAxis) */\n distanceFromSunAU?: number;\n orbitalPeriod: number; // Earth days\n color: string;\n}\n\n// =============================================================================\n// Utility Functions (fallbacks when SDK not available)\n// =============================================================================\n\n/**\n * Estimate orbital period from altitude (simplified)\n */\nexport function estimateOrbitalPeriod(altitudeKm: number): number {\n const earthRadiusKm = 6371;\n const mu = 398600.4418; // km³/s² - Earth's gravitational parameter\n const semiMajorAxis = earthRadiusKm + altitudeKm;\n const period = 2 * Math.PI * Math.sqrt(Math.pow(semiMajorAxis, 3) / mu);\n return period / 60; // Return in minutes\n}\n\n/**\n * Estimate orbital velocity from altitude (simplified)\n */\nexport function estimateOrbitalVelocity(altitudeKm: number): number {\n const earthRadiusKm = 6371;\n const mu = 398600.4418; // km³/s²\n const radius = earthRadiusKm + altitudeKm;\n return Math.sqrt(mu / radius); // km/s\n}\n\n/**\n * Convert AU to kilometers\n */\nexport function auToKm(au: number): number {\n return au * 149597870.7;\n}\n\n/**\n * Normalize planet name to PlanetId\n */\nexport function normalizePlanetName(name: string): PlanetId | null {\n const normalized = name.toLowerCase().trim();\n const validPlanets: PlanetId[] = [\n 'sun', 'mercury', 'venus', 'earth', 'moon', \n 'mars', 'jupiter', 'saturn', 'uranus', 'neptune', 'pluto'\n ];\n return validPlanets.includes(normalized as PlanetId) \n ? (normalized as PlanetId) \n : null;\n}\n\n/**\n * Get planet info by ID\n */\nexport function getPlanet(id: PlanetId): PlanetInfo | undefined {\n return PLANETS.find(p => p.id === id);\n}\n\n/**\n * Planet data (simplified)\n */\nexport const PLANETS: PlanetInfo[] = [\n { id: 'sun', name: 'Sun', radius: 696340, mass: 1.989e30, semiMajorAxis: 0, orbitalPeriod: 0, color: '#ffcc00' },\n { id: 'mercury', name: 'Mercury', radius: 2439.7, mass: 3.3011e23, semiMajorAxis: 0.387, orbitalPeriod: 88, color: '#b5b5b5' },\n { id: 'venus', name: 'Venus', radius: 6051.8, mass: 4.8675e24, semiMajorAxis: 0.723, orbitalPeriod: 225, color: '#e6c87a' },\n { id: 'earth', name: 'Earth', radius: 6371, mass: 5.972e24, semiMajorAxis: 1.0, orbitalPeriod: 365, color: '#4da6ff' },\n { id: 'moon', name: 'Moon', radius: 1737.4, mass: 7.342e22, semiMajorAxis: 0.00257, orbitalPeriod: 27.3, color: '#c0c0c0' },\n { id: 'mars', name: 'Mars', radius: 3389.5, mass: 6.4171e23, semiMajorAxis: 1.524, orbitalPeriod: 687, color: '#e07b4a' },\n { id: 'jupiter', name: 'Jupiter', radius: 69911, mass: 1.8982e27, semiMajorAxis: 5.203, orbitalPeriod: 4333, color: '#d8ca9d' },\n { id: 'saturn', name: 'Saturn', radius: 58232, mass: 5.6834e26, semiMajorAxis: 9.537, orbitalPeriod: 10759, color: '#f4d59e' },\n { id: 'uranus', name: 'Uranus', radius: 25362, mass: 8.6810e25, semiMajorAxis: 19.19, orbitalPeriod: 30687, color: '#b3e0e6' },\n { id: 'neptune', name: 'Neptune', radius: 24622, mass: 1.02413e26, semiMajorAxis: 30.07, orbitalPeriod: 60190, color: '#5b7fff' },\n { id: 'pluto', name: 'Pluto', radius: 1188.3, mass: 1.303e22, semiMajorAxis: 39.48, orbitalPeriod: 90560, color: '#c9b79c' },\n];\n"],"names":[],"mappings":"AAkaO,SAAS,sBAAsB,YAA4B;AAChE,QAAM,gBAAgB;AACtB,QAAM,KAAK;AACX,QAAM,gBAAgB,gBAAgB;AACtC,QAAM,SAAS,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI,eAAe,CAAC,IAAI,EAAE;AACtE,SAAO,SAAS;AAClB;AAKO,SAAS,wBAAwB,YAA4B;AAClE,QAAM,gBAAgB;AACtB,QAAM,KAAK;AACX,QAAM,SAAS,gBAAgB;AAC/B,SAAO,KAAK,KAAK,KAAK,MAAM;AAC9B;AAKO,SAAS,OAAO,IAAoB;AACzC,SAAO,KAAK;AACd;AAKO,SAAS,oBAAoB,MAA+B;AACjE,QAAM,aAAa,KAAK,YAAA,EAAc,KAAA;AACtC,QAAM,eAA2B;AAAA,IAC/B;AAAA,IAAO;AAAA,IAAW;AAAA,IAAS;AAAA,IAAS;AAAA,IACpC;AAAA,IAAQ;AAAA,IAAW;AAAA,IAAU;AAAA,IAAU;AAAA,IAAW;AAAA,EAAA;AAEpD,SAAO,aAAa,SAAS,UAAsB,IAC9C,aACD;AACN;AAKO,SAAS,UAAU,IAAsC;AAC9D,SAAO,QAAQ,KAAK,CAAA,MAAK,EAAE,OAAO,EAAE;AACtC;AAKO,MAAM,UAAwB;AAAA,EACnC,EAAE,IAAI,OAAO,MAAM,OAAO,QAAQ,QAAQ,MAAM,SAAU,eAAe,GAAG,eAAe,GAAG,OAAO,UAAA;AAAA,EACrG,EAAE,IAAI,WAAW,MAAM,WAAW,QAAQ,QAAQ,MAAM,UAAW,eAAe,OAAO,eAAe,IAAI,OAAO,UAAA;AAAA,EACnH,EAAE,IAAI,SAAS,MAAM,SAAS,QAAQ,QAAQ,MAAM,UAAW,eAAe,OAAO,eAAe,KAAK,OAAO,UAAA;AAAA,EAChH,EAAE,IAAI,SAAS,MAAM,SAAS,QAAQ,MAAM,MAAM,SAAU,eAAe,GAAK,eAAe,KAAK,OAAO,UAAA;AAAA,EAC3G,EAAE,IAAI,QAAQ,MAAM,QAAQ,QAAQ,QAAQ,MAAM,SAAU,eAAe,QAAS,eAAe,MAAM,OAAO,UAAA;AAAA,EAChH,EAAE,IAAI,QAAQ,MAAM,QAAQ,QAAQ,QAAQ,MAAM,UAAW,eAAe,OAAO,eAAe,KAAK,OAAO,UAAA;AAAA,EAC9G,EAAE,IAAI,WAAW,MAAM,WAAW,QAAQ,OAAO,MAAM,UAAW,eAAe,OAAO,eAAe,MAAM,OAAO,UAAA;AAAA,EACpH,EAAE,IAAI,UAAU,MAAM,UAAU,QAAQ,OAAO,MAAM,UAAW,eAAe,OAAO,eAAe,OAAO,OAAO,UAAA;AAAA,EACnH,EAAE,IAAI,UAAU,MAAM,UAAU,QAAQ,OAAO,MAAM,SAAW,eAAe,OAAO,eAAe,OAAO,OAAO,UAAA;AAAA,EACnH,EAAE,IAAI,WAAW,MAAM,WAAW,QAAQ,OAAO,MAAM,WAAY,eAAe,OAAO,eAAe,OAAO,OAAO,UAAA;AAAA,EACtH,EAAE,IAAI,SAAS,MAAM,SAAS,QAAQ,QAAQ,MAAM,SAAU,eAAe,OAAO,eAAe,OAAO,OAAO,UAAA;AACnH;"}
|
|
1
|
+
{"version":3,"file":"types.js","sources":["../../src/react/types.ts"],"sourcesContent":["/**\n * @zendir/ui - Local Type Definitions\n * \n * These types are provided so the UI library can be used without @zendir/sdk.\n * If you have @zendir/sdk installed, those types will be used instead.\n * \n * All types here mirror the @zendir/sdk interfaces.\n */\n\n// =============================================================================\n// Category / Group Primitive\n// =============================================================================\n\n/**\n * A named, colored data category — the SDK's shared concept for any secondary\n * grouping dimension (teams, squads, subsystems, mission phases, etc.).\n *\n * Components that support category-aware coloring accept `CategoryDef` arrays\n * and/or a `categoryId` field on individual data items. The `CategoryPalette`\n * utility resolves ids → colors/labels consistently across an entire dashboard.\n *\n * @example\n * const categories: CategoryDef[] = [\n * { id: 'alpha', label: 'Team Alpha', color: '#2dccff' },\n * { id: 'bravo', label: 'Team Bravo', color: '#fce83a' },\n * ];\n */\nexport interface CategoryDef {\n /** Stable unique identifier (string or numeric) */\n id: string | number;\n /** Human-readable display name */\n label: string;\n /** CSS color used for visual accents (stripes, rings, swatches, series lines) */\n color: string;\n /** Optional icon name from the Astro icon set */\n icon?: string;\n /** Arbitrary metadata for app-specific needs */\n meta?: Record<string, unknown>;\n}\n\n// =============================================================================\n// Spacecraft Types\n// =============================================================================\n\nexport interface SpacecraftPosition {\n /** Optional spacecraft id (when combined with Spacecraft) */\n id?: string;\n /** Optional display name */\n name?: string;\n /** Latitude in degrees (-90 to 90) */\n latitude: number;\n /** Longitude in degrees (-180 to 180) */\n longitude: number;\n /** Altitude in kilometers */\n altitude: number;\n /** Velocity in km/s */\n velocity?: number;\n /** Heading in degrees */\n heading?: number;\n /** Timestamp */\n timestamp?: string;\n /** Orbit type (e.g. LEO, GEO) */\n orbitType?: string;\n /** Orbital inclination in degrees */\n inclination?: number;\n /** Health/operational status using AstroUXDS 6-level system */\n status?: 'off' | 'standby' | 'normal' | 'caution' | 'serious' | 'critical';\n}\n\nexport interface Spacecraft {\n id: string;\n name: string;\n noradId?: number;\n type?: string;\n /** Status using AstroUXDS 6-level system */\n status?: 'off' | 'standby' | 'normal' | 'caution' | 'serious' | 'critical';\n}\n\n// =============================================================================\n// Ground Station Types\n// =============================================================================\n\nexport interface GroundStation {\n id: string;\n name: string;\n latitude: number;\n longitude: number;\n elevation?: number;\n /** Minimum elevation angle for visibility (degrees) */\n minElevation?: number;\n network?: string;\n}\n\nexport interface GroundTrackPoint {\n latitude: number;\n longitude: number;\n altitude: number;\n timestamp: string;\n}\n\n// =============================================================================\n// Access / Contact Types\n// =============================================================================\n\nexport interface AccessData {\n stationId: string;\n stationName: string;\n spacecraftId: string;\n aos: string; // Acquisition of Signal - ISO timestamp\n los: string; // Loss of Signal - ISO timestamp\n maxElevation: number;\n azimuthAos?: number;\n azimuthLos?: number;\n /** Whether link is currently accessible */\n isAccessible?: boolean;\n /** Current elevation angle (degrees) */\n elevation?: number;\n /** Current azimuth (degrees) */\n azimuth?: number;\n /** Slant range in km */\n slantRange?: number;\n /** Signal strength 0-100 */\n signalStrength?: number;\n /** Link budget details */\n linkBudget?: {\n receivedPower?: number;\n snr?: number;\n dataRate?: number;\n };\n}\n\nexport interface AccessWindow {\n aos: string;\n los: string;\n maxElevation: number;\n stationId: string;\n /** Start time (ISO or ms) */\n startTime?: string | number;\n /** Duration in seconds */\n duration?: number;\n}\n\n// =============================================================================\n// Telemetry Types\n// =============================================================================\n\nexport interface TelemetryData {\n timestamp: string;\n subsystems: {\n power?: {\n status: string;\n batteryLevel?: number;\n solarArrayOutput?: number;\n voltage?: number;\n solarGeneration?: number;\n consumption?: number;\n };\n thermal?: {\n status: string;\n cpuTemp?: number;\n batteryTemp?: number;\n };\n comms?: {\n status: string;\n signalStrength?: number;\n dataRate?: number;\n downlinkRate?: number;\n transmitterStatus?: string;\n packetsQueued?: number;\n bytesTransmitted?: number;\n packetsTransmitted?: number;\n };\n attitude?: {\n status: string;\n pointingError?: number;\n eulerAngles?: EulerAngles;\n targetMode?: string;\n };\n };\n /** Health status (convenience alias / extended) */\n health?: {\n status?: string;\n anomalies?: Array<{ id: string; message: string; severity?: string }>;\n };\n /** Power (convenience alias for subsystems.power / extended) */\n power?: {\n status?: string;\n batteryLevel?: number;\n solarArrayOutput?: number;\n voltage?: number;\n solarGeneration?: number;\n consumption?: number;\n };\n /** Attitude (convenience alias / extended) */\n attitude?: {\n status?: string;\n eulerAngles?: EulerAngles;\n targetMode?: string;\n pointingError?: number;\n };\n /** Communications (convenience alias / extended) */\n communications?: {\n status?: string;\n signalStrength?: number;\n dataRate?: number;\n downlinkRate?: number;\n transmitterStatus?: string;\n packetsQueued?: number;\n bytesTransmitted?: number;\n packetsTransmitted?: number;\n };\n alerts?: Array<{\n id: string;\n severity: string;\n message: string;\n timestamp: string;\n }>;\n}\n\n// =============================================================================\n// Orbital Types\n// =============================================================================\n\nexport interface OrbitalElements {\n semiMajorAxis: number;\n eccentricity: number;\n inclination: number;\n raan: number; // Right Ascension of Ascending Node\n argumentOfPerigee: number;\n trueAnomaly: number;\n period?: number;\n epoch?: string;\n}\n\n// =============================================================================\n// Attitude Types\n// =============================================================================\n\nexport interface Quaternion {\n x: number;\n y: number;\n z: number;\n w: number;\n}\n\nexport interface EulerAngles {\n roll: number;\n pitch: number;\n yaw: number;\n}\n\nexport interface AngularVelocity {\n x: number;\n y: number;\n z: number;\n}\n\nexport interface AttitudeData {\n quaternion: Quaternion;\n eulerAngles: EulerAngles;\n angularVelocity: AngularVelocity;\n targetMode?: string;\n /** Pointing error in degrees */\n pointingError?: number;\n /** Target direction vector [x, y, z] */\n targetDirection?: [number, number, number];\n}\n\nexport type PointingMode = 'nadir' | 'sun' | 'target' | 'inertial' | 'velocity';\n\n// =============================================================================\n// Eclipse Types\n// =============================================================================\n\nexport interface EclipseInfo {\n inEclipse: boolean;\n timeToEclipse: number; // seconds\n eclipseDuration: number; // seconds\n sunlightDuration: number; // seconds\n /** Umbra duration in seconds */\n umbraDuration?: number;\n /** Penumbra duration in seconds */\n penumbraDuration?: number;\n /** Seconds until sunlight (when in eclipse) */\n timeToSunlight?: number;\n}\n\n// =============================================================================\n// Link Budget Types\n// =============================================================================\n\nexport interface DetailedLinkBudget {\n spacecraftId: string;\n groundStationId: string;\n frequency: number;\n eirp: number;\n pathLoss: number;\n atmosphericLoss: number;\n receiverGain: number;\n systemNoiseTemp: number;\n cnoRequired: number;\n cnoActual: number;\n margin: number;\n dataRate: number;\n}\n\n// =============================================================================\n// Thermal Types\n// =============================================================================\n\nexport interface ThermalZone {\n id: string;\n name: string;\n temperature: number;\n minLimit: number;\n maxLimit: number;\n}\n\nexport interface ThermalData {\n timestamp: string;\n zones: ThermalZone[];\n averageTemp: number;\n hottest: { zone: string; temp: number };\n coldest: { zone: string; temp: number };\n}\n\n// =============================================================================\n// Propulsion Types\n// =============================================================================\n\nexport interface ThrusterStatus {\n id: string;\n name: string;\n status: 'ready' | 'firing' | 'disabled' | 'error';\n fuelFlow?: number;\n}\n\nexport interface PropulsionSummary {\n fuelRemaining: number;\n fuelCapacity: number;\n thrusterStatus: ThrusterStatus[];\n deltaVRemaining: number;\n deltaVUsed: number;\n lastManeuver?: string;\n}\n\n// =============================================================================\n// Reaction Wheel / Momentum Types\n// =============================================================================\n\nexport interface ReactionWheelData {\n /** Unique wheel identifier */\n id: string;\n /** Display name (e.g. \"RW-X\", \"RW-1\") */\n name: string;\n /** Mounted axis */\n axis: 'X' | 'Y' | 'Z' | 'skew';\n /** Current stored angular momentum in N·m·s */\n momentumNms: number;\n /** Maximum momentum capacity in N·m·s */\n maxMomentumNms: number;\n /** Current wheel speed in RPM */\n speedRpm: number;\n /** Maximum wheel speed in RPM */\n maxSpeedRpm: number;\n /** Operational status */\n status: 'nominal' | 'saturated' | 'desaturating' | 'off' | 'error';\n /** Power consumption in Watts */\n powerW?: number;\n /** Bearing temperature in °C */\n temperatureC?: number;\n}\n\n/** LVLH (Local Vertical Local Horizontal) frame vector */\nexport interface LVLHVector {\n /** Radial component (local vertical, positive away from Earth) */\n radial: number;\n /** In-track component (along velocity vector) */\n inTrack: number;\n /** Cross-track component (normal to orbital plane) */\n crossTrack: number;\n}\n\n/** Time-stamped LVLH state for trajectory plotting */\nexport interface LVLHState {\n /** Timestamp in milliseconds */\n time: number;\n /** Position in LVLH frame (km) */\n position: LVLHVector;\n /** Velocity in LVLH frame (km/s) */\n velocity: LVLHVector;\n}\n\n/** Thruster firing event */\nexport interface ThrusterFireEvent {\n /** Event timestamp in milliseconds */\n time: number;\n /** Thruster ID */\n thrusterId: string;\n /** Display name */\n name: string;\n /** Delta-V magnitude in m/s */\n deltaVMs: number;\n /** Delta-V direction in LVLH frame (unit vector) */\n deltaVDirection?: LVLHVector;\n /** Burn duration in seconds */\n durationSeconds: number;\n /** Event type */\n type: 'impulsive' | 'finite' | 'continuous';\n}\n\n// =============================================================================\n// Planet Types\n// =============================================================================\n\nexport type PlanetId = \n | 'sun' \n | 'mercury' \n | 'venus' \n | 'earth' \n | 'moon' \n | 'mars' \n | 'jupiter' \n | 'saturn' \n | 'uranus' \n | 'neptune' \n | 'pluto';\n\nexport interface PlanetInfo {\n id: PlanetId;\n name: string;\n radius: number; // km\n /** @deprecated Use radius */\n radiusKm?: number;\n mass: number; // kg\n semiMajorAxis: number; // AU\n /** Distance from Sun in AU (alias for semiMajorAxis) */\n distanceFromSunAU?: number;\n orbitalPeriod: number; // Earth days\n color: string;\n}\n\n// =============================================================================\n// Utility Functions (fallbacks when SDK not available)\n// =============================================================================\n\n/**\n * Estimate orbital period from altitude (simplified)\n */\nexport function estimateOrbitalPeriod(altitudeKm: number): number {\n const earthRadiusKm = 6371;\n const mu = 398600.4418; // km³/s² - Earth's gravitational parameter\n const semiMajorAxis = earthRadiusKm + altitudeKm;\n const period = 2 * Math.PI * Math.sqrt(Math.pow(semiMajorAxis, 3) / mu);\n return period / 60; // Return in minutes\n}\n\n/**\n * Estimate orbital velocity from altitude (simplified)\n */\nexport function estimateOrbitalVelocity(altitudeKm: number): number {\n const earthRadiusKm = 6371;\n const mu = 398600.4418; // km³/s²\n const radius = earthRadiusKm + altitudeKm;\n return Math.sqrt(mu / radius); // km/s\n}\n\n/**\n * Convert AU to kilometers\n */\nexport function auToKm(au: number): number {\n return au * 149597870.7;\n}\n\n/**\n * Normalize planet name to PlanetId\n */\nexport function normalizePlanetName(name: string): PlanetId | null {\n const normalized = name.toLowerCase().trim();\n const validPlanets: PlanetId[] = [\n 'sun', 'mercury', 'venus', 'earth', 'moon', \n 'mars', 'jupiter', 'saturn', 'uranus', 'neptune', 'pluto'\n ];\n return validPlanets.includes(normalized as PlanetId) \n ? (normalized as PlanetId) \n : null;\n}\n\n/**\n * Get planet info by ID\n */\nexport function getPlanet(id: PlanetId): PlanetInfo | undefined {\n return PLANETS.find(p => p.id === id);\n}\n\n/**\n * Planet data (simplified)\n */\nexport const PLANETS: PlanetInfo[] = [\n { id: 'sun', name: 'Sun', radius: 696340, mass: 1.989e30, semiMajorAxis: 0, orbitalPeriod: 0, color: '#ffcc00' },\n { id: 'mercury', name: 'Mercury', radius: 2439.7, mass: 3.3011e23, semiMajorAxis: 0.387, orbitalPeriod: 88, color: '#b5b5b5' },\n { id: 'venus', name: 'Venus', radius: 6051.8, mass: 4.8675e24, semiMajorAxis: 0.723, orbitalPeriod: 225, color: '#e6c87a' },\n { id: 'earth', name: 'Earth', radius: 6371, mass: 5.972e24, semiMajorAxis: 1.0, orbitalPeriod: 365, color: '#4da6ff' },\n { id: 'moon', name: 'Moon', radius: 1737.4, mass: 7.342e22, semiMajorAxis: 0.00257, orbitalPeriod: 27.3, color: '#c0c0c0' },\n { id: 'mars', name: 'Mars', radius: 3389.5, mass: 6.4171e23, semiMajorAxis: 1.524, orbitalPeriod: 687, color: '#e07b4a' },\n { id: 'jupiter', name: 'Jupiter', radius: 69911, mass: 1.8982e27, semiMajorAxis: 5.203, orbitalPeriod: 4333, color: '#d8ca9d' },\n { id: 'saturn', name: 'Saturn', radius: 58232, mass: 5.6834e26, semiMajorAxis: 9.537, orbitalPeriod: 10759, color: '#f4d59e' },\n { id: 'uranus', name: 'Uranus', radius: 25362, mass: 8.6810e25, semiMajorAxis: 19.19, orbitalPeriod: 30687, color: '#b3e0e6' },\n { id: 'neptune', name: 'Neptune', radius: 24622, mass: 1.02413e26, semiMajorAxis: 30.07, orbitalPeriod: 60190, color: '#5b7fff' },\n { id: 'pluto', name: 'Pluto', radius: 1188.3, mass: 1.303e22, semiMajorAxis: 39.48, orbitalPeriod: 90560, color: '#c9b79c' },\n];\n"],"names":[],"mappings":"AAicO,SAAS,sBAAsB,YAA4B;AAChE,QAAM,gBAAgB;AACtB,QAAM,KAAK;AACX,QAAM,gBAAgB,gBAAgB;AACtC,QAAM,SAAS,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI,eAAe,CAAC,IAAI,EAAE;AACtE,SAAO,SAAS;AAClB;AAKO,SAAS,wBAAwB,YAA4B;AAClE,QAAM,gBAAgB;AACtB,QAAM,KAAK;AACX,QAAM,SAAS,gBAAgB;AAC/B,SAAO,KAAK,KAAK,KAAK,MAAM;AAC9B;AAKO,SAAS,OAAO,IAAoB;AACzC,SAAO,KAAK;AACd;AAKO,SAAS,oBAAoB,MAA+B;AACjE,QAAM,aAAa,KAAK,YAAA,EAAc,KAAA;AACtC,QAAM,eAA2B;AAAA,IAC/B;AAAA,IAAO;AAAA,IAAW;AAAA,IAAS;AAAA,IAAS;AAAA,IACpC;AAAA,IAAQ;AAAA,IAAW;AAAA,IAAU;AAAA,IAAU;AAAA,IAAW;AAAA,EAAA;AAEpD,SAAO,aAAa,SAAS,UAAsB,IAC9C,aACD;AACN;AAKO,SAAS,UAAU,IAAsC;AAC9D,SAAO,QAAQ,KAAK,CAAA,MAAK,EAAE,OAAO,EAAE;AACtC;AAKO,MAAM,UAAwB;AAAA,EACnC,EAAE,IAAI,OAAO,MAAM,OAAO,QAAQ,QAAQ,MAAM,SAAU,eAAe,GAAG,eAAe,GAAG,OAAO,UAAA;AAAA,EACrG,EAAE,IAAI,WAAW,MAAM,WAAW,QAAQ,QAAQ,MAAM,UAAW,eAAe,OAAO,eAAe,IAAI,OAAO,UAAA;AAAA,EACnH,EAAE,IAAI,SAAS,MAAM,SAAS,QAAQ,QAAQ,MAAM,UAAW,eAAe,OAAO,eAAe,KAAK,OAAO,UAAA;AAAA,EAChH,EAAE,IAAI,SAAS,MAAM,SAAS,QAAQ,MAAM,MAAM,SAAU,eAAe,GAAK,eAAe,KAAK,OAAO,UAAA;AAAA,EAC3G,EAAE,IAAI,QAAQ,MAAM,QAAQ,QAAQ,QAAQ,MAAM,SAAU,eAAe,QAAS,eAAe,MAAM,OAAO,UAAA;AAAA,EAChH,EAAE,IAAI,QAAQ,MAAM,QAAQ,QAAQ,QAAQ,MAAM,UAAW,eAAe,OAAO,eAAe,KAAK,OAAO,UAAA;AAAA,EAC9G,EAAE,IAAI,WAAW,MAAM,WAAW,QAAQ,OAAO,MAAM,UAAW,eAAe,OAAO,eAAe,MAAM,OAAO,UAAA;AAAA,EACpH,EAAE,IAAI,UAAU,MAAM,UAAU,QAAQ,OAAO,MAAM,UAAW,eAAe,OAAO,eAAe,OAAO,OAAO,UAAA;AAAA,EACnH,EAAE,IAAI,UAAU,MAAM,UAAU,QAAQ,OAAO,MAAM,SAAW,eAAe,OAAO,eAAe,OAAO,OAAO,UAAA;AAAA,EACnH,EAAE,IAAI,WAAW,MAAM,WAAW,QAAQ,OAAO,MAAM,WAAY,eAAe,OAAO,eAAe,OAAO,OAAO,UAAA;AAAA,EACtH,EAAE,IAAI,SAAS,MAAM,SAAS,QAAQ,QAAQ,MAAM,SAAU,eAAe,OAAO,eAAe,OAAO,OAAO,UAAA;AACnH;"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { CategoryDef } from '../types';
|
|
2
|
+
|
|
3
|
+
export declare class CategoryPalette {
|
|
4
|
+
/** Registered categories (insertion order) */
|
|
5
|
+
private readonly _defs;
|
|
6
|
+
/** Auto-assigned colors for ids not in the initial set */
|
|
7
|
+
private readonly _autoColors;
|
|
8
|
+
/** Fallback palette used for auto-assignment */
|
|
9
|
+
private readonly _fallback;
|
|
10
|
+
/** Counter for round-robin auto-assignment */
|
|
11
|
+
private _autoIndex;
|
|
12
|
+
/**
|
|
13
|
+
* @param categories - Initial category definitions (id, label, color).
|
|
14
|
+
* @param fallbackPalette - Optional custom palette for auto-assigned unknowns.
|
|
15
|
+
* Defaults to the Astro UXDS–compliant Zendir data-viz palette.
|
|
16
|
+
*/
|
|
17
|
+
constructor(categories?: CategoryDef[], fallbackPalette?: string[]);
|
|
18
|
+
/** All registered categories (in insertion order). */
|
|
19
|
+
get all(): CategoryDef[];
|
|
20
|
+
/** Number of registered categories. */
|
|
21
|
+
get size(): number;
|
|
22
|
+
/** Returns the full definition for a registered id, or `undefined`. */
|
|
23
|
+
getCategory(id: string | number): CategoryDef | undefined;
|
|
24
|
+
/** Returns `true` if the id was registered in the constructor. */
|
|
25
|
+
has(id: string | number): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a color for any id.
|
|
28
|
+
* - Registered ids → their explicit `color`.
|
|
29
|
+
* - Unknown ids → stable auto-assigned color from the fallback palette
|
|
30
|
+
* (same id always gets the same color within this palette instance).
|
|
31
|
+
*/
|
|
32
|
+
getColor(id: string | number): string;
|
|
33
|
+
/**
|
|
34
|
+
* Resolve a label for any id.
|
|
35
|
+
* Registered ids → their `label`; unknown ids → the stringified id.
|
|
36
|
+
*/
|
|
37
|
+
getLabel(id: string | number): string;
|
|
38
|
+
/**
|
|
39
|
+
* Convert a `CategoryDef` array to a palette instance.
|
|
40
|
+
* Convenience factory — identical to `new CategoryPalette(defs)`.
|
|
41
|
+
*/
|
|
42
|
+
static from(defs: CategoryDef[], fallbackPalette?: string[]): CategoryPalette;
|
|
43
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
const DEFAULT_FALLBACK_PALETTE = [
|
|
5
|
+
"#3E3CFF",
|
|
6
|
+
// Zendir Electric
|
|
7
|
+
"#9D70FF",
|
|
8
|
+
// Zendir Purple
|
|
9
|
+
"#6B69FF",
|
|
10
|
+
// Electric 20 % lighter
|
|
11
|
+
"#B48DFF",
|
|
12
|
+
// Purple 20 % lighter
|
|
13
|
+
"#3548C0",
|
|
14
|
+
// Prussian Blue lighter
|
|
15
|
+
"#9997FF",
|
|
16
|
+
// Electric 35 % lighter
|
|
17
|
+
"#C9A8FF",
|
|
18
|
+
// Purple 35 % lighter
|
|
19
|
+
"#1B2DA0",
|
|
20
|
+
// Prussian Blue
|
|
21
|
+
"#3230CC",
|
|
22
|
+
// Electric 20 % darker
|
|
23
|
+
"#7E5ACC",
|
|
24
|
+
// Purple 20 % darker
|
|
25
|
+
"#4A5FD6"
|
|
26
|
+
// Prussian Blue lightest
|
|
27
|
+
];
|
|
28
|
+
class CategoryPalette {
|
|
29
|
+
/**
|
|
30
|
+
* @param categories - Initial category definitions (id, label, color).
|
|
31
|
+
* @param fallbackPalette - Optional custom palette for auto-assigned unknowns.
|
|
32
|
+
* Defaults to the Astro UXDS–compliant Zendir data-viz palette.
|
|
33
|
+
*/
|
|
34
|
+
constructor(categories = [], fallbackPalette) {
|
|
35
|
+
/** Registered categories (insertion order) */
|
|
36
|
+
__publicField(this, "_defs");
|
|
37
|
+
/** Auto-assigned colors for ids not in the initial set */
|
|
38
|
+
__publicField(this, "_autoColors");
|
|
39
|
+
/** Fallback palette used for auto-assignment */
|
|
40
|
+
__publicField(this, "_fallback");
|
|
41
|
+
/** Counter for round-robin auto-assignment */
|
|
42
|
+
__publicField(this, "_autoIndex");
|
|
43
|
+
this._defs = /* @__PURE__ */ new Map();
|
|
44
|
+
this._autoColors = /* @__PURE__ */ new Map();
|
|
45
|
+
this._fallback = fallbackPalette ?? DEFAULT_FALLBACK_PALETTE;
|
|
46
|
+
this._autoIndex = 0;
|
|
47
|
+
for (const cat of categories) {
|
|
48
|
+
this._defs.set(String(cat.id), cat);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** All registered categories (in insertion order). */
|
|
52
|
+
get all() {
|
|
53
|
+
return [...this._defs.values()];
|
|
54
|
+
}
|
|
55
|
+
/** Number of registered categories. */
|
|
56
|
+
get size() {
|
|
57
|
+
return this._defs.size;
|
|
58
|
+
}
|
|
59
|
+
/** Returns the full definition for a registered id, or `undefined`. */
|
|
60
|
+
getCategory(id) {
|
|
61
|
+
return this._defs.get(String(id));
|
|
62
|
+
}
|
|
63
|
+
/** Returns `true` if the id was registered in the constructor. */
|
|
64
|
+
has(id) {
|
|
65
|
+
return this._defs.has(String(id));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Resolve a color for any id.
|
|
69
|
+
* - Registered ids → their explicit `color`.
|
|
70
|
+
* - Unknown ids → stable auto-assigned color from the fallback palette
|
|
71
|
+
* (same id always gets the same color within this palette instance).
|
|
72
|
+
*/
|
|
73
|
+
getColor(id) {
|
|
74
|
+
const key = String(id);
|
|
75
|
+
const def = this._defs.get(key);
|
|
76
|
+
if (def) return def.color;
|
|
77
|
+
let auto = this._autoColors.get(key);
|
|
78
|
+
if (!auto) {
|
|
79
|
+
auto = this._fallback[this._autoIndex % this._fallback.length];
|
|
80
|
+
this._autoColors.set(key, auto);
|
|
81
|
+
this._autoIndex++;
|
|
82
|
+
}
|
|
83
|
+
return auto;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Resolve a label for any id.
|
|
87
|
+
* Registered ids → their `label`; unknown ids → the stringified id.
|
|
88
|
+
*/
|
|
89
|
+
getLabel(id) {
|
|
90
|
+
var _a;
|
|
91
|
+
return ((_a = this._defs.get(String(id))) == null ? void 0 : _a.label) ?? String(id);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Convert a `CategoryDef` array to a palette instance.
|
|
95
|
+
* Convenience factory — identical to `new CategoryPalette(defs)`.
|
|
96
|
+
*/
|
|
97
|
+
static from(defs, fallbackPalette) {
|
|
98
|
+
return new CategoryPalette(defs, fallbackPalette);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
CategoryPalette
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=categoryPalette.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"categoryPalette.js","sources":["../../../src/react/utils/categoryPalette.ts"],"sourcesContent":["/**\r\n * @zendir/ui — CategoryPalette\r\n *\r\n * A lightweight utility that maps category ids to stable colors and labels.\r\n * Designed for dashboards where multiple components (Timeline, Map, Charts,\r\n * DataTable) should share a consistent visual identity for the same\r\n * grouping dimension — teams, squads, subsystems, mission phases, etc.\r\n *\r\n * @example\r\n * ```ts\r\n * import { CategoryPalette } from '@zendir/ui';\r\n *\r\n * const palette = new CategoryPalette([\r\n * { id: 'alpha', label: 'Team Alpha', color: '#2dccff' },\r\n * { id: 'bravo', label: 'Team Bravo', color: '#fce83a' },\r\n * ]);\r\n *\r\n * palette.getColor('alpha'); // '#2dccff'\r\n * palette.getLabel('alpha'); // 'Team Alpha'\r\n * palette.getColor('unknown-id'); // auto-assigned from fallback palette\r\n * ```\r\n */\r\n\r\nimport type { CategoryDef } from '../types';\r\n\r\n/**\r\n * Default fallback palette — Astro-compliant data-viz colors.\r\n * Used when a category has no explicit color or when an unknown id is\r\n * encountered at runtime (auto-assignment by insertion order).\r\n */\r\nconst DEFAULT_FALLBACK_PALETTE: readonly string[] = [\r\n '#3E3CFF', // Zendir Electric\r\n '#9D70FF', // Zendir Purple\r\n '#6B69FF', // Electric 20 % lighter\r\n '#B48DFF', // Purple 20 % lighter\r\n '#3548C0', // Prussian Blue lighter\r\n '#9997FF', // Electric 35 % lighter\r\n '#C9A8FF', // Purple 35 % lighter\r\n '#1B2DA0', // Prussian Blue\r\n '#3230CC', // Electric 20 % darker\r\n '#7E5ACC', // Purple 20 % darker\r\n '#4A5FD6', // Prussian Blue lightest\r\n];\r\n\r\nexport class CategoryPalette {\r\n /** Registered categories (insertion order) */\r\n private readonly _defs: Map<string, CategoryDef>;\r\n /** Auto-assigned colors for ids not in the initial set */\r\n private readonly _autoColors: Map<string, string>;\r\n /** Fallback palette used for auto-assignment */\r\n private readonly _fallback: readonly string[];\r\n /** Counter for round-robin auto-assignment */\r\n private _autoIndex: number;\r\n\r\n /**\r\n * @param categories - Initial category definitions (id, label, color).\r\n * @param fallbackPalette - Optional custom palette for auto-assigned unknowns.\r\n * Defaults to the Astro UXDS–compliant Zendir data-viz palette.\r\n */\r\n constructor(\r\n categories: CategoryDef[] = [],\r\n fallbackPalette?: string[],\r\n ) {\r\n this._defs = new Map();\r\n this._autoColors = new Map();\r\n this._fallback = fallbackPalette ?? DEFAULT_FALLBACK_PALETTE;\r\n this._autoIndex = 0;\r\n\r\n for (const cat of categories) {\r\n this._defs.set(String(cat.id), cat);\r\n }\r\n }\r\n\r\n /** All registered categories (in insertion order). */\r\n get all(): CategoryDef[] {\r\n return [...this._defs.values()];\r\n }\r\n\r\n /** Number of registered categories. */\r\n get size(): number {\r\n return this._defs.size;\r\n }\r\n\r\n /** Returns the full definition for a registered id, or `undefined`. */\r\n getCategory(id: string | number): CategoryDef | undefined {\r\n return this._defs.get(String(id));\r\n }\r\n\r\n /** Returns `true` if the id was registered in the constructor. */\r\n has(id: string | number): boolean {\r\n return this._defs.has(String(id));\r\n }\r\n\r\n /**\r\n * Resolve a color for any id.\r\n * - Registered ids → their explicit `color`.\r\n * - Unknown ids → stable auto-assigned color from the fallback palette\r\n * (same id always gets the same color within this palette instance).\r\n */\r\n getColor(id: string | number): string {\r\n const key = String(id);\r\n const def = this._defs.get(key);\r\n if (def) return def.color;\r\n\r\n let auto = this._autoColors.get(key);\r\n if (!auto) {\r\n auto = this._fallback[this._autoIndex % this._fallback.length];\r\n this._autoColors.set(key, auto);\r\n this._autoIndex++;\r\n }\r\n return auto;\r\n }\r\n\r\n /**\r\n * Resolve a label for any id.\r\n * Registered ids → their `label`; unknown ids → the stringified id.\r\n */\r\n getLabel(id: string | number): string {\r\n return this._defs.get(String(id))?.label ?? String(id);\r\n }\r\n\r\n /**\r\n * Convert a `CategoryDef` array to a palette instance.\r\n * Convenience factory — identical to `new CategoryPalette(defs)`.\r\n */\r\n static from(defs: CategoryDef[], fallbackPalette?: string[]): CategoryPalette {\r\n return new CategoryPalette(defs, fallbackPalette);\r\n }\r\n}\r\n"],"names":[],"mappings":";;;AA8BA,MAAM,2BAA8C;AAAA,EAClD;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACF;AAEO,MAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAe3B,YACE,aAA4B,CAAA,GAC5B,iBACA;AAhBe;AAAA;AAEA;AAAA;AAEA;AAAA;AAET;AAAA;AAWN,SAAK,4BAAY,IAAA;AACjB,SAAK,kCAAkB,IAAA;AACvB,SAAK,YAAY,mBAAmB;AACpC,SAAK,aAAa;AAElB,eAAW,OAAO,YAAY;AAC5B,WAAK,MAAM,IAAI,OAAO,IAAI,EAAE,GAAG,GAAG;AAAA,IACpC;AAAA,EACF;AAAA;AAAA,EAGA,IAAI,MAAqB;AACvB,WAAO,CAAC,GAAG,KAAK,MAAM,QAAQ;AAAA,EAChC;AAAA;AAAA,EAGA,IAAI,OAAe;AACjB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA,EAGA,YAAY,IAA8C;AACxD,WAAO,KAAK,MAAM,IAAI,OAAO,EAAE,CAAC;AAAA,EAClC;AAAA;AAAA,EAGA,IAAI,IAA8B;AAChC,WAAO,KAAK,MAAM,IAAI,OAAO,EAAE,CAAC;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,IAA6B;AACpC,UAAM,MAAM,OAAO,EAAE;AACrB,UAAM,MAAM,KAAK,MAAM,IAAI,GAAG;AAC9B,QAAI,YAAY,IAAI;AAEpB,QAAI,OAAO,KAAK,YAAY,IAAI,GAAG;AACnC,QAAI,CAAC,MAAM;AACT,aAAO,KAAK,UAAU,KAAK,aAAa,KAAK,UAAU,MAAM;AAC7D,WAAK,YAAY,IAAI,KAAK,IAAI;AAC9B,WAAK;AAAA,IACP;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,IAA6B;AAvFxC;AAwFI,aAAO,UAAK,MAAM,IAAI,OAAO,EAAE,CAAC,MAAzB,mBAA4B,UAAS,OAAO,EAAE;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,KAAK,MAAqB,iBAA6C;AAC5E,WAAO,IAAI,gBAAgB,MAAM,eAAe;AAAA,EAClD;AACF;"}
|
|
@@ -245,3 +245,4 @@ export declare const focusRingStyle: React.CSSProperties;
|
|
|
245
245
|
* @example safeAccentText('#8b5cf6') // '#a885f8' — lightened to pass 4.5:1
|
|
246
246
|
*/
|
|
247
247
|
export declare function safeAccentText(accent: string): string;
|
|
248
|
+
export { CategoryPalette } from './categoryPalette';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/react/utils/index.ts"],"sourcesContent":["/**\n * @zendir/ui - Enterprise Utility Functions\n * \n * Shared utilities for null-safety, formatting, and defensive coding.\n * These utilities ensure components never crash due to undefined data.\n */\n\n// ============================================================================\n// NULL SAFETY UTILITIES\n// ============================================================================\n\n/**\n * Safely access a value with a fallback for null/undefined\n * @example withNullSafety(data?.temperature, 0) // Returns 0 if undefined\n */\nexport function withNullSafety<T>(value: T | null | undefined, fallback: T): T {\n return value ?? fallback;\n}\n\n/**\n * Safely format a number, returning '--' if undefined\n * @example safeNumber(data?.value, 2) // \"123.45\" or \"--\"\n */\nexport function safeNumber(\n value: number | null | undefined,\n decimals: number = 2,\n fallback: string = '--'\n): string {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return fallback;\n }\n return value.toFixed(decimals);\n}\n\n/**\n * Check if value is a valid finite number\n */\nexport function isValidNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\n// ============================================================================\n// NUMBER FORMATTING\n// ============================================================================\n\nexport interface FormatNumberOptions {\n decimals?: number;\n locale?: string;\n notation?: 'standard' | 'scientific' | 'engineering' | 'compact';\n unit?: string;\n signDisplay?: 'auto' | 'never' | 'always' | 'exceptZero';\n}\n\n/**\n * Format a number with locale-aware formatting and optional unit\n * @example formatNumber(1234567, { notation: 'compact' }) // \"1.2M\"\n */\nexport function formatNumber(\n value: number | null | undefined,\n options: FormatNumberOptions = {}\n): string {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return '--';\n }\n\n const {\n decimals = 2,\n locale = 'en-US',\n notation = 'standard',\n unit,\n signDisplay = 'auto',\n } = options;\n\n try {\n const formatted = new Intl.NumberFormat(locale, {\n notation,\n minimumFractionDigits: notation === 'compact' ? 0 : decimals,\n maximumFractionDigits: decimals,\n signDisplay,\n }).format(value);\n\n return unit ? `${formatted} ${unit}` : formatted;\n } catch {\n return value.toFixed(decimals);\n }\n}\n\n/**\n * Format a number with tabular (monospace) digits for alignment\n * Uses font-feature-settings: 'tnum' 1\n */\nexport function formatTabular(\n value: number | null | undefined,\n decimals: number = 2\n): string {\n return safeNumber(value, decimals);\n}\n\n// ============================================================================\n// UNIT-AWARE FORMATTING\n// ============================================================================\n\n/**\n * Format temperature with unit conversion\n * @example formatTemperature(25) // \"25.0°C\"\n * @example formatTemperature(25, 'fahrenheit') // \"77.0°F\"\n */\nexport function formatTemperature(\n celsius: number | null | undefined,\n unit: 'celsius' | 'fahrenheit' | 'kelvin' = 'celsius',\n decimals: number = 1\n): string {\n if (celsius === null || celsius === undefined || !Number.isFinite(celsius)) {\n return '--°C';\n }\n\n switch (unit) {\n case 'fahrenheit':\n return `${((celsius * 9) / 5 + 32).toFixed(decimals)}°F`;\n case 'kelvin':\n return `${(celsius + 273.15).toFixed(decimals)}K`;\n default:\n return `${celsius.toFixed(decimals)}°C`;\n }\n}\n\n/**\n * Format data rate with automatic unit scaling\n * @example formatDataRate(1500000) // \"1.50 Mbps\"\n */\nexport function formatDataRate(bitsPerSecond: number | null | undefined): string {\n if (bitsPerSecond === null || bitsPerSecond === undefined || !Number.isFinite(bitsPerSecond)) {\n return '-- bps';\n }\n\n const units = ['bps', 'Kbps', 'Mbps', 'Gbps', 'Tbps'];\n let unitIndex = 0;\n let value = bitsPerSecond;\n\n while (value >= 1000 && unitIndex < units.length - 1) {\n value /= 1000;\n unitIndex++;\n }\n\n return `${value.toFixed(2)} ${units[unitIndex]}`;\n}\n\n/**\n * Format distance with automatic unit scaling\n * @example formatDistance(1500) // \"1.50 km\"\n */\nexport function formatDistance(meters: number | null | undefined): string {\n if (meters === null || meters === undefined || !Number.isFinite(meters)) {\n return '-- m';\n }\n\n if (meters >= 1_000_000) {\n return `${(meters / 1_000_000).toFixed(2)} Mm`;\n } else if (meters >= 1_000) {\n return `${(meters / 1_000).toFixed(2)} km`;\n } else if (meters < 1) {\n return `${(meters * 100).toFixed(1)} cm`;\n }\n return `${meters.toFixed(1)} m`;\n}\n\n/**\n * Format altitude (always in km for space ops)\n * @example formatAltitude(418.2) // \"418.2 km\"\n */\nexport function formatAltitude(km: number | null | undefined): string {\n if (km === null || km === undefined || !Number.isFinite(km)) {\n return '-- km';\n }\n return `${km.toFixed(1)} km`;\n}\n\n/**\n * Format velocity\n * @example formatVelocity(7.66) // \"7.66 km/s\"\n */\nexport function formatVelocity(kmPerSec: number | null | undefined): string {\n if (kmPerSec === null || kmPerSec === undefined || !Number.isFinite(kmPerSec)) {\n return '-- km/s';\n }\n return `${kmPerSec.toFixed(2)} km/s`;\n}\n\n/**\n * Format percentage with bounds checking\n * @example formatPercentage(0.856) // \"85.6%\"\n * @example formatPercentage(85.6, false) // \"85.6%\" (already percentage)\n */\nexport function formatPercentage(\n value: number | null | undefined,\n isDecimal: boolean = false,\n decimals: number = 1\n): string {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return '--%';\n }\n\n const percentage = isDecimal ? value * 100 : value;\n return `${percentage.toFixed(decimals)}%`;\n}\n\n/**\n * Format power (watts) with auto-scaling\n * @example formatPower(1500) // \"1.50 kW\"\n */\nexport function formatPower(watts: number | null | undefined): string {\n if (watts === null || watts === undefined || !Number.isFinite(watts)) {\n return '-- W';\n }\n\n if (Math.abs(watts) >= 1_000_000) {\n return `${(watts / 1_000_000).toFixed(2)} MW`;\n } else if (Math.abs(watts) >= 1_000) {\n return `${(watts / 1_000).toFixed(2)} kW`;\n } else if (Math.abs(watts) < 1) {\n return `${(watts * 1000).toFixed(1)} mW`;\n }\n return `${watts.toFixed(1)} W`;\n}\n\n/**\n * Format frequency (Hz) with auto-scaling\n * @example formatFrequency(2400000000) // \"2.40 GHz\"\n */\nexport function formatFrequency(hz: number | null | undefined): string {\n if (hz === null || hz === undefined || !Number.isFinite(hz)) {\n return '-- Hz';\n }\n\n if (hz >= 1_000_000_000) {\n return `${(hz / 1_000_000_000).toFixed(2)} GHz`;\n } else if (hz >= 1_000_000) {\n return `${(hz / 1_000_000).toFixed(2)} MHz`;\n } else if (hz >= 1_000) {\n return `${(hz / 1_000).toFixed(2)} kHz`;\n }\n return `${hz.toFixed(0)} Hz`;\n}\n\n// ============================================================================\n// TIME FORMATTING\n// ============================================================================\n\n/**\n * Format duration in human-readable form\n * @example formatDuration(3661) // \"1h 1m 1s\"\n */\nexport function formatDuration(seconds: number | null | undefined): string {\n if (seconds === null || seconds === undefined || !Number.isFinite(seconds)) {\n return '--:--';\n }\n\n const absSeconds = Math.abs(seconds);\n const sign = seconds < 0 ? '-' : '';\n\n if (absSeconds < 60) {\n return `${sign}${absSeconds.toFixed(0)}s`;\n } else if (absSeconds < 3600) {\n const mins = Math.floor(absSeconds / 60);\n const secs = Math.floor(absSeconds % 60);\n return `${sign}${mins}m ${secs}s`;\n } else if (absSeconds < 86400) {\n const hours = Math.floor(absSeconds / 3600);\n const mins = Math.floor((absSeconds % 3600) / 60);\n return `${sign}${hours}h ${mins}m`;\n } else {\n const days = Math.floor(absSeconds / 86400);\n const hours = Math.floor((absSeconds % 86400) / 3600);\n return `${sign}${days}d ${hours}h`;\n }\n}\n\n/**\n * Format countdown timer (supports negative values for past events)\n * @example formatCountdown(125) // \"T-02:05\"\n * @example formatCountdown(-60) // \"T+01:00\"\n */\nexport function formatCountdown(seconds: number | null | undefined): string {\n if (seconds === null || seconds === undefined || !Number.isFinite(seconds)) {\n return 'T--:--';\n }\n\n const prefix = seconds >= 0 ? 'T-' : 'T+';\n const absSeconds = Math.abs(seconds);\n\n if (absSeconds >= 3600) {\n const hours = Math.floor(absSeconds / 3600);\n const mins = Math.floor((absSeconds % 3600) / 60);\n const secs = Math.floor(absSeconds % 60);\n return `${prefix}${hours}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;\n }\n\n const mins = Math.floor(absSeconds / 60);\n const secs = Math.floor(absSeconds % 60);\n return `${prefix}${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;\n}\n\n/**\n * Format UTC timestamp\n * @example formatUTC(new Date()) // \"2026-01-27 14:30:00Z\"\n */\nexport function formatUTC(date: Date | string | null | undefined): string {\n if (!date) return '--:--:-- UTC';\n\n try {\n const d = typeof date === 'string' ? new Date(date) : date;\n if (isNaN(d.getTime())) return '--:--:-- UTC';\n\n return d.toISOString().replace('T', ' ').slice(0, 19) + 'Z';\n } catch {\n return '--:--:-- UTC';\n }\n}\n\n/**\n * Format time only (HH:MM:SS)\n * @example formatTime(new Date()) // \"14:30:00\"\n */\nexport function formatTime(date: Date | string | null | undefined, includeSeconds = true): string {\n if (!date) return includeSeconds ? '--:--:--' : '--:--';\n\n try {\n const d = typeof date === 'string' ? new Date(date) : date;\n if (isNaN(d.getTime())) return includeSeconds ? '--:--:--' : '--:--';\n\n const hours = d.getUTCHours().toString().padStart(2, '0');\n const mins = d.getUTCMinutes().toString().padStart(2, '0');\n const secs = d.getUTCSeconds().toString().padStart(2, '0');\n\n return includeSeconds ? `${hours}:${mins}:${secs}` : `${hours}:${mins}`;\n } catch {\n return includeSeconds ? '--:--:--' : '--:--';\n }\n}\n\n// ============================================================================\n// COORDINATE FORMATTING\n// ============================================================================\n\n/**\n * Format latitude/longitude\n * @example formatCoordinate(32.4, 'lat') // \"32.40° N\"\n * @example formatCoordinate(-117.2, 'lon') // \"117.20° W\"\n */\nexport function formatCoordinate(\n value: number | null | undefined,\n type: 'lat' | 'lon'\n): string {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return '--°';\n }\n\n const absValue = Math.abs(value);\n let direction: string;\n\n if (type === 'lat') {\n direction = value >= 0 ? 'N' : 'S';\n } else {\n direction = value >= 0 ? 'E' : 'W';\n }\n\n return `${absValue.toFixed(2)}° ${direction}`;\n}\n\n/**\n * Format lat/lon pair\n * @example formatLatLon(32.4, -117.2) // \"32.40° N, 117.20° W\"\n */\nexport function formatLatLon(\n lat: number | null | undefined,\n lon: number | null | undefined\n): string {\n return `${formatCoordinate(lat, 'lat')}, ${formatCoordinate(lon, 'lon')}`;\n}\n\n// ============================================================================\n// ANGLE FORMATTING\n// ============================================================================\n\n/**\n * Format angle in degrees\n * @example formatDegrees(45.5) // \"45.5°\"\n */\nexport function formatDegrees(\n value: number | null | undefined,\n decimals: number = 1\n): string {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return '--°';\n }\n return `${value.toFixed(decimals)}°`;\n}\n\n/**\n * Format decibels\n * @example formatDecibels(3.5) // \"3.5 dB\"\n */\nexport function formatDecibels(\n value: number | null | undefined,\n decimals: number = 1\n): string {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return '-- dB';\n }\n return `${value.toFixed(decimals)} dB`;\n}\n\n// ============================================================================\n// VALUE UTILITIES\n// ============================================================================\n\n/**\n * Clamp a value between min and max\n * @example clamp(150, 0, 100) // 100\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\n/**\n * Linear interpolation\n * @example lerp(0, 100, 0.5) // 50\n */\nexport function lerp(start: number, end: number, t: number): number {\n return start + (end - start) * clamp(t, 0, 1);\n}\n\n/**\n * Map a value from one range to another\n * @example mapRange(50, 0, 100, 0, 1) // 0.5\n */\nexport function mapRange(\n value: number,\n inMin: number,\n inMax: number,\n outMin: number,\n outMax: number\n): number {\n const t = (value - inMin) / (inMax - inMin);\n return lerp(outMin, outMax, t);\n}\n\n// ============================================================================\n// STATUS UTILITIES\n// ============================================================================\n\nexport type StatusLevel = 'off' | 'standby' | 'normal' | 'caution' | 'serious' | 'critical';\n\n/**\n * Astro UX Design System status colors\n * These match the official Astro status semantics\n */\nexport const STATUS_COLORS: Record<StatusLevel, string> = {\n off: '#a4abb6',\n standby: '#2dccff',\n normal: '#56f000',\n caution: '#fce83a',\n serious: '#ffb302',\n critical: '#ff3838',\n};\n\n/**\n * Get status color from level\n * @example getStatusColor('normal') // '#56f000'\n */\nexport function getStatusColor(status: StatusLevel | null | undefined): string {\n return STATUS_COLORS[status ?? 'off'];\n}\n\n/**\n * Derive status for battery specifically (low is bad)\n * @example deriveBatteryStatus(25) // 'caution'\n */\nexport function deriveBatteryStatus(level: number | undefined | null): 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 * Determine status level from a value and thresholds\n * @example getStatusFromValue(85, { critical: 20, serious: 40, caution: 60, normal: 80 }) // 'normal'\n */\nexport function getStatusFromValue(\n value: number | null | undefined,\n thresholds: {\n critical?: number;\n serious?: number;\n caution?: number;\n normal?: number;\n },\n higherIsBetter: boolean = true\n): StatusLevel {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return 'off';\n }\n\n const { critical = 10, serious = 25, caution = 50, normal = 75 } = thresholds;\n\n if (higherIsBetter) {\n if (value <= critical) return 'critical';\n if (value <= serious) return 'serious';\n if (value <= caution) return 'caution';\n if (value <= normal) return 'standby';\n return 'normal';\n } else {\n if (value >= critical) return 'critical';\n if (value >= serious) return 'serious';\n if (value >= caution) return 'caution';\n if (value >= normal) return 'standby';\n return 'normal';\n }\n}\n\n// ============================================================================\n// STATUS NORMALIZATION\n// ============================================================================\n\n/**\n * Domain status terms that map to UI StatusLevel\n * This handles common backend/sensor terminology\n */\nconst STATUS_MAPPING: Record<string, StatusLevel> = {\n // → 'off'\n 'off': 'off',\n 'disabled': 'off',\n 'inactive': 'off',\n 'offline': 'off',\n 'unknown': 'off',\n 'null': 'off',\n 'none': 'off',\n \n // → 'standby'\n 'standby': 'standby',\n 'idle': 'standby',\n 'waiting': 'standby',\n 'ready': 'standby',\n 'pending': 'standby',\n 'queued': 'standby',\n \n // → 'normal'\n 'normal': 'normal',\n 'nominal': 'normal',\n 'healthy': 'normal',\n 'ok': 'normal',\n 'good': 'normal',\n 'success': 'normal',\n 'operational': 'normal',\n 'active': 'normal',\n 'online': 'normal',\n 'connected': 'normal',\n 'stable': 'normal',\n 'transmitting': 'normal',\n 'receiving': 'normal',\n \n // → 'caution'\n 'caution': 'caution',\n 'warning': 'caution',\n 'degraded': 'caution',\n 'elevated': 'caution',\n 'alert': 'caution',\n 'attention': 'caution',\n 'limited': 'caution',\n \n // → 'serious'\n 'serious': 'serious',\n 'unstable': 'serious',\n 'danger': 'serious',\n 'severe': 'serious',\n \n // → 'critical'\n 'critical': 'critical',\n 'error': 'critical',\n 'failed': 'critical',\n 'failure': 'critical',\n 'emergency': 'critical',\n 'fault': 'critical',\n 'alarm': 'critical',\n};\n\n/**\n * Normalize any status string to the 6-level StatusLevel system\n * \n * @param status - Any status string from domain/backend\n * @param defaultStatus - Fallback if status is not recognized (default: 'off')\n * @returns StatusLevel\n * \n * @example\n * ```typescript\n * normalizeStatus('degraded') // 'caution'\n * normalizeStatus('nominal') // 'normal'\n * normalizeStatus('transmitting') // 'normal'\n * normalizeStatus('warning') // 'caution'\n * normalizeStatus('error') // 'critical'\n * normalizeStatus(undefined) // 'off'\n * ```\n */\nexport function normalizeStatus(\n status: string | undefined | null,\n defaultStatus: StatusLevel = 'off'\n): StatusLevel {\n if (!status) return defaultStatus;\n \n const normalized = status.toLowerCase().trim();\n return STATUS_MAPPING[normalized] ?? defaultStatus;\n}\n\n/**\n * Check if a string is a valid StatusLevel\n */\nexport function isStatusLevel(value: string): value is StatusLevel {\n return ['off', 'standby', 'normal', 'caution', 'serious', 'critical'].includes(value);\n}\n\n/**\n * Get the severity order of a status (higher = more severe)\n * Useful for sorting or finding worst status\n */\nexport function getStatusSeverity(status: StatusLevel): number {\n const order: Record<StatusLevel, number> = {\n off: 0,\n standby: 1,\n normal: 2,\n caution: 3,\n serious: 4,\n critical: 5,\n };\n return order[status];\n}\n\n/**\n * Get the worst (most severe) status from an array\n * \n * @example\n * ```typescript\n * getWorstStatus(['normal', 'caution', 'normal']) // 'caution'\n * getWorstStatus(['normal', 'critical', 'caution']) // 'critical'\n * ```\n */\nexport function getWorstStatus(statuses: StatusLevel[]): StatusLevel {\n if (statuses.length === 0) return 'off';\n return statuses.reduce((worst, current) => \n getStatusSeverity(current) > getStatusSeverity(worst) ? current : worst\n );\n}\n\n// ============================================================================\n// COLOR UTILITIES\n// ============================================================================\n\n/**\n * Safely add alpha to any CSS color string.\n * Handles hex (#RRGGBB → #RRGGBBAA), rgb(), and rgba() formats.\n *\n * Avoids the common bug of appending a hex alpha string to an rgba() color,\n * which produces invalid CSS (e.g. \"rgba(15, 20, 35, 0.85)80\").\n *\n * @param color - CSS color string (hex, rgb, or rgba)\n * @param alpha - Alpha value 0–1\n * @returns Valid CSS color string with alpha applied\n *\n * @example\n * addAlpha('#1b2d3e', 0.5) // '#1b2d3e80'\n * addAlpha('rgba(15, 20, 35, 0.85)', 0.5) // 'rgba(15, 20, 35, 0.5)'\n * addAlpha('rgb(15, 20, 35)', 0.031) // 'rgba(15, 20, 35, 0.031)'\n */\nexport function addAlpha(color: string, alpha: number): string {\n if (!color) return color;\n const a = Math.max(0, Math.min(1, alpha));\n if (color.startsWith('rgba(')) {\n return color.replace(/,\\s*[\\d.]+\\)\\s*$/, `, ${a})`);\n }\n if (color.startsWith('rgb(')) {\n return color.replace(/^rgb\\(/, 'rgba(').replace(/\\)\\s*$/, `, ${a})`);\n }\n if (color.startsWith('#')) {\n const hexA = Math.round(a * 255).toString(16).padStart(2, '0');\n return `${color}${hexA}`;\n }\n return color;\n}\n\n// ============================================================================\n// COMPONENT STYLE UTILITIES\n// ============================================================================\n\n/**\n * Merge class names, filtering out falsy values\n * @example classNames('base', isActive && 'active', className) // \"base active custom\"\n */\nexport function classNames(...classes: (string | boolean | undefined | null)[]): string {\n return classes.filter(Boolean).join(' ');\n}\n\n/**\n * Generate CSS for tabular numbers (monospace digits)\n */\nexport const tabularNumsStyle: React.CSSProperties = {\n fontVariantNumeric: 'tabular-nums',\n fontFeatureSettings: '\"tnum\" 1',\n};\n\n/**\n * CSS transition presets\n */\nexport const transitions = {\n fast: 'all 150ms ease-out',\n normal: 'all 250ms ease-out',\n slow: 'all 400ms ease-out',\n spring: 'all 300ms cubic-bezier(0.34, 1.56, 0.64, 1)',\n} as const;\n\n/**\n * Focus ring styles for accessibility\n */\nexport const focusRingStyle: React.CSSProperties = {\n outline: '2px solid #4dc3ff',\n outlineOffset: '2px',\n};\n\n/**\n * Compute a WCAG AA safe version of an accent color for use as foreground text\n * on dark backgrounds. If the accent already passes 4.5:1 contrast on typical\n * dark surfaces (L ≈ 0.01), returns it unchanged. Otherwise lightens toward\n * white until the minimum contrast is met.\n *\n * @example safeAccentText('#8b5cf6') // '#a885f8' — lightened to pass 4.5:1\n */\nexport function safeAccentText(accent: string): string {\n const hex = accent.replace('#', '');\n if (hex.length < 6) return accent;\n\n const r = parseInt(hex.slice(0, 2), 16) / 255;\n const g = parseInt(hex.slice(2, 4), 16) / 255;\n const b = parseInt(hex.slice(4, 6), 16) / 255;\n const toLinear = (c: number) =>\n c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n const L = 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n\n // Threshold: on a dark surface with L≈0.01 we need text L ≥ 0.22 for 4.5:1\n if (L >= 0.22) return accent;\n\n // Lighten by mixing 25% toward white — reaches ~5.5:1 on typical dark bgs\n const mix = 0.25;\n const lr = Math.min(255, Math.round((r + (1 - r) * mix) * 255));\n const lg = Math.min(255, Math.round((g + (1 - g) * mix) * 255));\n const lb = Math.min(255, Math.round((b + (1 - b) * mix) * 255));\n return `#${lr.toString(16).padStart(2, '0')}${lg.toString(16).padStart(2, '0')}${lb.toString(16).padStart(2, '0')}`;\n}\n"],"names":["mins","secs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/react/utils/index.ts"],"sourcesContent":["/**\n * @zendir/ui - Enterprise Utility Functions\n * \n * Shared utilities for null-safety, formatting, and defensive coding.\n * These utilities ensure components never crash due to undefined data.\n */\n\n// ============================================================================\n// NULL SAFETY UTILITIES\n// ============================================================================\n\n/**\n * Safely access a value with a fallback for null/undefined\n * @example withNullSafety(data?.temperature, 0) // Returns 0 if undefined\n */\nexport function withNullSafety<T>(value: T | null | undefined, fallback: T): T {\n return value ?? fallback;\n}\n\n/**\n * Safely format a number, returning '--' if undefined\n * @example safeNumber(data?.value, 2) // \"123.45\" or \"--\"\n */\nexport function safeNumber(\n value: number | null | undefined,\n decimals: number = 2,\n fallback: string = '--'\n): string {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return fallback;\n }\n return value.toFixed(decimals);\n}\n\n/**\n * Check if value is a valid finite number\n */\nexport function isValidNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\n// ============================================================================\n// NUMBER FORMATTING\n// ============================================================================\n\nexport interface FormatNumberOptions {\n decimals?: number;\n locale?: string;\n notation?: 'standard' | 'scientific' | 'engineering' | 'compact';\n unit?: string;\n signDisplay?: 'auto' | 'never' | 'always' | 'exceptZero';\n}\n\n/**\n * Format a number with locale-aware formatting and optional unit\n * @example formatNumber(1234567, { notation: 'compact' }) // \"1.2M\"\n */\nexport function formatNumber(\n value: number | null | undefined,\n options: FormatNumberOptions = {}\n): string {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return '--';\n }\n\n const {\n decimals = 2,\n locale = 'en-US',\n notation = 'standard',\n unit,\n signDisplay = 'auto',\n } = options;\n\n try {\n const formatted = new Intl.NumberFormat(locale, {\n notation,\n minimumFractionDigits: notation === 'compact' ? 0 : decimals,\n maximumFractionDigits: decimals,\n signDisplay,\n }).format(value);\n\n return unit ? `${formatted} ${unit}` : formatted;\n } catch {\n return value.toFixed(decimals);\n }\n}\n\n/**\n * Format a number with tabular (monospace) digits for alignment\n * Uses font-feature-settings: 'tnum' 1\n */\nexport function formatTabular(\n value: number | null | undefined,\n decimals: number = 2\n): string {\n return safeNumber(value, decimals);\n}\n\n// ============================================================================\n// UNIT-AWARE FORMATTING\n// ============================================================================\n\n/**\n * Format temperature with unit conversion\n * @example formatTemperature(25) // \"25.0°C\"\n * @example formatTemperature(25, 'fahrenheit') // \"77.0°F\"\n */\nexport function formatTemperature(\n celsius: number | null | undefined,\n unit: 'celsius' | 'fahrenheit' | 'kelvin' = 'celsius',\n decimals: number = 1\n): string {\n if (celsius === null || celsius === undefined || !Number.isFinite(celsius)) {\n return '--°C';\n }\n\n switch (unit) {\n case 'fahrenheit':\n return `${((celsius * 9) / 5 + 32).toFixed(decimals)}°F`;\n case 'kelvin':\n return `${(celsius + 273.15).toFixed(decimals)}K`;\n default:\n return `${celsius.toFixed(decimals)}°C`;\n }\n}\n\n/**\n * Format data rate with automatic unit scaling\n * @example formatDataRate(1500000) // \"1.50 Mbps\"\n */\nexport function formatDataRate(bitsPerSecond: number | null | undefined): string {\n if (bitsPerSecond === null || bitsPerSecond === undefined || !Number.isFinite(bitsPerSecond)) {\n return '-- bps';\n }\n\n const units = ['bps', 'Kbps', 'Mbps', 'Gbps', 'Tbps'];\n let unitIndex = 0;\n let value = bitsPerSecond;\n\n while (value >= 1000 && unitIndex < units.length - 1) {\n value /= 1000;\n unitIndex++;\n }\n\n return `${value.toFixed(2)} ${units[unitIndex]}`;\n}\n\n/**\n * Format distance with automatic unit scaling\n * @example formatDistance(1500) // \"1.50 km\"\n */\nexport function formatDistance(meters: number | null | undefined): string {\n if (meters === null || meters === undefined || !Number.isFinite(meters)) {\n return '-- m';\n }\n\n if (meters >= 1_000_000) {\n return `${(meters / 1_000_000).toFixed(2)} Mm`;\n } else if (meters >= 1_000) {\n return `${(meters / 1_000).toFixed(2)} km`;\n } else if (meters < 1) {\n return `${(meters * 100).toFixed(1)} cm`;\n }\n return `${meters.toFixed(1)} m`;\n}\n\n/**\n * Format altitude (always in km for space ops)\n * @example formatAltitude(418.2) // \"418.2 km\"\n */\nexport function formatAltitude(km: number | null | undefined): string {\n if (km === null || km === undefined || !Number.isFinite(km)) {\n return '-- km';\n }\n return `${km.toFixed(1)} km`;\n}\n\n/**\n * Format velocity\n * @example formatVelocity(7.66) // \"7.66 km/s\"\n */\nexport function formatVelocity(kmPerSec: number | null | undefined): string {\n if (kmPerSec === null || kmPerSec === undefined || !Number.isFinite(kmPerSec)) {\n return '-- km/s';\n }\n return `${kmPerSec.toFixed(2)} km/s`;\n}\n\n/**\n * Format percentage with bounds checking\n * @example formatPercentage(0.856) // \"85.6%\"\n * @example formatPercentage(85.6, false) // \"85.6%\" (already percentage)\n */\nexport function formatPercentage(\n value: number | null | undefined,\n isDecimal: boolean = false,\n decimals: number = 1\n): string {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return '--%';\n }\n\n const percentage = isDecimal ? value * 100 : value;\n return `${percentage.toFixed(decimals)}%`;\n}\n\n/**\n * Format power (watts) with auto-scaling\n * @example formatPower(1500) // \"1.50 kW\"\n */\nexport function formatPower(watts: number | null | undefined): string {\n if (watts === null || watts === undefined || !Number.isFinite(watts)) {\n return '-- W';\n }\n\n if (Math.abs(watts) >= 1_000_000) {\n return `${(watts / 1_000_000).toFixed(2)} MW`;\n } else if (Math.abs(watts) >= 1_000) {\n return `${(watts / 1_000).toFixed(2)} kW`;\n } else if (Math.abs(watts) < 1) {\n return `${(watts * 1000).toFixed(1)} mW`;\n }\n return `${watts.toFixed(1)} W`;\n}\n\n/**\n * Format frequency (Hz) with auto-scaling\n * @example formatFrequency(2400000000) // \"2.40 GHz\"\n */\nexport function formatFrequency(hz: number | null | undefined): string {\n if (hz === null || hz === undefined || !Number.isFinite(hz)) {\n return '-- Hz';\n }\n\n if (hz >= 1_000_000_000) {\n return `${(hz / 1_000_000_000).toFixed(2)} GHz`;\n } else if (hz >= 1_000_000) {\n return `${(hz / 1_000_000).toFixed(2)} MHz`;\n } else if (hz >= 1_000) {\n return `${(hz / 1_000).toFixed(2)} kHz`;\n }\n return `${hz.toFixed(0)} Hz`;\n}\n\n// ============================================================================\n// TIME FORMATTING\n// ============================================================================\n\n/**\n * Format duration in human-readable form\n * @example formatDuration(3661) // \"1h 1m 1s\"\n */\nexport function formatDuration(seconds: number | null | undefined): string {\n if (seconds === null || seconds === undefined || !Number.isFinite(seconds)) {\n return '--:--';\n }\n\n const absSeconds = Math.abs(seconds);\n const sign = seconds < 0 ? '-' : '';\n\n if (absSeconds < 60) {\n return `${sign}${absSeconds.toFixed(0)}s`;\n } else if (absSeconds < 3600) {\n const mins = Math.floor(absSeconds / 60);\n const secs = Math.floor(absSeconds % 60);\n return `${sign}${mins}m ${secs}s`;\n } else if (absSeconds < 86400) {\n const hours = Math.floor(absSeconds / 3600);\n const mins = Math.floor((absSeconds % 3600) / 60);\n return `${sign}${hours}h ${mins}m`;\n } else {\n const days = Math.floor(absSeconds / 86400);\n const hours = Math.floor((absSeconds % 86400) / 3600);\n return `${sign}${days}d ${hours}h`;\n }\n}\n\n/**\n * Format countdown timer (supports negative values for past events)\n * @example formatCountdown(125) // \"T-02:05\"\n * @example formatCountdown(-60) // \"T+01:00\"\n */\nexport function formatCountdown(seconds: number | null | undefined): string {\n if (seconds === null || seconds === undefined || !Number.isFinite(seconds)) {\n return 'T--:--';\n }\n\n const prefix = seconds >= 0 ? 'T-' : 'T+';\n const absSeconds = Math.abs(seconds);\n\n if (absSeconds >= 3600) {\n const hours = Math.floor(absSeconds / 3600);\n const mins = Math.floor((absSeconds % 3600) / 60);\n const secs = Math.floor(absSeconds % 60);\n return `${prefix}${hours}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;\n }\n\n const mins = Math.floor(absSeconds / 60);\n const secs = Math.floor(absSeconds % 60);\n return `${prefix}${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;\n}\n\n/**\n * Format UTC timestamp\n * @example formatUTC(new Date()) // \"2026-01-27 14:30:00Z\"\n */\nexport function formatUTC(date: Date | string | null | undefined): string {\n if (!date) return '--:--:-- UTC';\n\n try {\n const d = typeof date === 'string' ? new Date(date) : date;\n if (isNaN(d.getTime())) return '--:--:-- UTC';\n\n return d.toISOString().replace('T', ' ').slice(0, 19) + 'Z';\n } catch {\n return '--:--:-- UTC';\n }\n}\n\n/**\n * Format time only (HH:MM:SS)\n * @example formatTime(new Date()) // \"14:30:00\"\n */\nexport function formatTime(date: Date | string | null | undefined, includeSeconds = true): string {\n if (!date) return includeSeconds ? '--:--:--' : '--:--';\n\n try {\n const d = typeof date === 'string' ? new Date(date) : date;\n if (isNaN(d.getTime())) return includeSeconds ? '--:--:--' : '--:--';\n\n const hours = d.getUTCHours().toString().padStart(2, '0');\n const mins = d.getUTCMinutes().toString().padStart(2, '0');\n const secs = d.getUTCSeconds().toString().padStart(2, '0');\n\n return includeSeconds ? `${hours}:${mins}:${secs}` : `${hours}:${mins}`;\n } catch {\n return includeSeconds ? '--:--:--' : '--:--';\n }\n}\n\n// ============================================================================\n// COORDINATE FORMATTING\n// ============================================================================\n\n/**\n * Format latitude/longitude\n * @example formatCoordinate(32.4, 'lat') // \"32.40° N\"\n * @example formatCoordinate(-117.2, 'lon') // \"117.20° W\"\n */\nexport function formatCoordinate(\n value: number | null | undefined,\n type: 'lat' | 'lon'\n): string {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return '--°';\n }\n\n const absValue = Math.abs(value);\n let direction: string;\n\n if (type === 'lat') {\n direction = value >= 0 ? 'N' : 'S';\n } else {\n direction = value >= 0 ? 'E' : 'W';\n }\n\n return `${absValue.toFixed(2)}° ${direction}`;\n}\n\n/**\n * Format lat/lon pair\n * @example formatLatLon(32.4, -117.2) // \"32.40° N, 117.20° W\"\n */\nexport function formatLatLon(\n lat: number | null | undefined,\n lon: number | null | undefined\n): string {\n return `${formatCoordinate(lat, 'lat')}, ${formatCoordinate(lon, 'lon')}`;\n}\n\n// ============================================================================\n// ANGLE FORMATTING\n// ============================================================================\n\n/**\n * Format angle in degrees\n * @example formatDegrees(45.5) // \"45.5°\"\n */\nexport function formatDegrees(\n value: number | null | undefined,\n decimals: number = 1\n): string {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return '--°';\n }\n return `${value.toFixed(decimals)}°`;\n}\n\n/**\n * Format decibels\n * @example formatDecibels(3.5) // \"3.5 dB\"\n */\nexport function formatDecibels(\n value: number | null | undefined,\n decimals: number = 1\n): string {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return '-- dB';\n }\n return `${value.toFixed(decimals)} dB`;\n}\n\n// ============================================================================\n// VALUE UTILITIES\n// ============================================================================\n\n/**\n * Clamp a value between min and max\n * @example clamp(150, 0, 100) // 100\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\n/**\n * Linear interpolation\n * @example lerp(0, 100, 0.5) // 50\n */\nexport function lerp(start: number, end: number, t: number): number {\n return start + (end - start) * clamp(t, 0, 1);\n}\n\n/**\n * Map a value from one range to another\n * @example mapRange(50, 0, 100, 0, 1) // 0.5\n */\nexport function mapRange(\n value: number,\n inMin: number,\n inMax: number,\n outMin: number,\n outMax: number\n): number {\n const t = (value - inMin) / (inMax - inMin);\n return lerp(outMin, outMax, t);\n}\n\n// ============================================================================\n// STATUS UTILITIES\n// ============================================================================\n\nexport type StatusLevel = 'off' | 'standby' | 'normal' | 'caution' | 'serious' | 'critical';\n\n/**\n * Astro UX Design System status colors\n * These match the official Astro status semantics\n */\nexport const STATUS_COLORS: Record<StatusLevel, string> = {\n off: '#a4abb6',\n standby: '#2dccff',\n normal: '#56f000',\n caution: '#fce83a',\n serious: '#ffb302',\n critical: '#ff3838',\n};\n\n/**\n * Get status color from level\n * @example getStatusColor('normal') // '#56f000'\n */\nexport function getStatusColor(status: StatusLevel | null | undefined): string {\n return STATUS_COLORS[status ?? 'off'];\n}\n\n/**\n * Derive status for battery specifically (low is bad)\n * @example deriveBatteryStatus(25) // 'caution'\n */\nexport function deriveBatteryStatus(level: number | undefined | null): 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 * Determine status level from a value and thresholds\n * @example getStatusFromValue(85, { critical: 20, serious: 40, caution: 60, normal: 80 }) // 'normal'\n */\nexport function getStatusFromValue(\n value: number | null | undefined,\n thresholds: {\n critical?: number;\n serious?: number;\n caution?: number;\n normal?: number;\n },\n higherIsBetter: boolean = true\n): StatusLevel {\n if (value === null || value === undefined || !Number.isFinite(value)) {\n return 'off';\n }\n\n const { critical = 10, serious = 25, caution = 50, normal = 75 } = thresholds;\n\n if (higherIsBetter) {\n if (value <= critical) return 'critical';\n if (value <= serious) return 'serious';\n if (value <= caution) return 'caution';\n if (value <= normal) return 'standby';\n return 'normal';\n } else {\n if (value >= critical) return 'critical';\n if (value >= serious) return 'serious';\n if (value >= caution) return 'caution';\n if (value >= normal) return 'standby';\n return 'normal';\n }\n}\n\n// ============================================================================\n// STATUS NORMALIZATION\n// ============================================================================\n\n/**\n * Domain status terms that map to UI StatusLevel\n * This handles common backend/sensor terminology\n */\nconst STATUS_MAPPING: Record<string, StatusLevel> = {\n // → 'off'\n 'off': 'off',\n 'disabled': 'off',\n 'inactive': 'off',\n 'offline': 'off',\n 'unknown': 'off',\n 'null': 'off',\n 'none': 'off',\n \n // → 'standby'\n 'standby': 'standby',\n 'idle': 'standby',\n 'waiting': 'standby',\n 'ready': 'standby',\n 'pending': 'standby',\n 'queued': 'standby',\n \n // → 'normal'\n 'normal': 'normal',\n 'nominal': 'normal',\n 'healthy': 'normal',\n 'ok': 'normal',\n 'good': 'normal',\n 'success': 'normal',\n 'operational': 'normal',\n 'active': 'normal',\n 'online': 'normal',\n 'connected': 'normal',\n 'stable': 'normal',\n 'transmitting': 'normal',\n 'receiving': 'normal',\n \n // → 'caution'\n 'caution': 'caution',\n 'warning': 'caution',\n 'degraded': 'caution',\n 'elevated': 'caution',\n 'alert': 'caution',\n 'attention': 'caution',\n 'limited': 'caution',\n \n // → 'serious'\n 'serious': 'serious',\n 'unstable': 'serious',\n 'danger': 'serious',\n 'severe': 'serious',\n \n // → 'critical'\n 'critical': 'critical',\n 'error': 'critical',\n 'failed': 'critical',\n 'failure': 'critical',\n 'emergency': 'critical',\n 'fault': 'critical',\n 'alarm': 'critical',\n};\n\n/**\n * Normalize any status string to the 6-level StatusLevel system\n * \n * @param status - Any status string from domain/backend\n * @param defaultStatus - Fallback if status is not recognized (default: 'off')\n * @returns StatusLevel\n * \n * @example\n * ```typescript\n * normalizeStatus('degraded') // 'caution'\n * normalizeStatus('nominal') // 'normal'\n * normalizeStatus('transmitting') // 'normal'\n * normalizeStatus('warning') // 'caution'\n * normalizeStatus('error') // 'critical'\n * normalizeStatus(undefined) // 'off'\n * ```\n */\nexport function normalizeStatus(\n status: string | undefined | null,\n defaultStatus: StatusLevel = 'off'\n): StatusLevel {\n if (!status) return defaultStatus;\n \n const normalized = status.toLowerCase().trim();\n return STATUS_MAPPING[normalized] ?? defaultStatus;\n}\n\n/**\n * Check if a string is a valid StatusLevel\n */\nexport function isStatusLevel(value: string): value is StatusLevel {\n return ['off', 'standby', 'normal', 'caution', 'serious', 'critical'].includes(value);\n}\n\n/**\n * Get the severity order of a status (higher = more severe)\n * Useful for sorting or finding worst status\n */\nexport function getStatusSeverity(status: StatusLevel): number {\n const order: Record<StatusLevel, number> = {\n off: 0,\n standby: 1,\n normal: 2,\n caution: 3,\n serious: 4,\n critical: 5,\n };\n return order[status];\n}\n\n/**\n * Get the worst (most severe) status from an array\n * \n * @example\n * ```typescript\n * getWorstStatus(['normal', 'caution', 'normal']) // 'caution'\n * getWorstStatus(['normal', 'critical', 'caution']) // 'critical'\n * ```\n */\nexport function getWorstStatus(statuses: StatusLevel[]): StatusLevel {\n if (statuses.length === 0) return 'off';\n return statuses.reduce((worst, current) => \n getStatusSeverity(current) > getStatusSeverity(worst) ? current : worst\n );\n}\n\n// ============================================================================\n// COLOR UTILITIES\n// ============================================================================\n\n/**\n * Safely add alpha to any CSS color string.\n * Handles hex (#RRGGBB → #RRGGBBAA), rgb(), and rgba() formats.\n *\n * Avoids the common bug of appending a hex alpha string to an rgba() color,\n * which produces invalid CSS (e.g. \"rgba(15, 20, 35, 0.85)80\").\n *\n * @param color - CSS color string (hex, rgb, or rgba)\n * @param alpha - Alpha value 0–1\n * @returns Valid CSS color string with alpha applied\n *\n * @example\n * addAlpha('#1b2d3e', 0.5) // '#1b2d3e80'\n * addAlpha('rgba(15, 20, 35, 0.85)', 0.5) // 'rgba(15, 20, 35, 0.5)'\n * addAlpha('rgb(15, 20, 35)', 0.031) // 'rgba(15, 20, 35, 0.031)'\n */\nexport function addAlpha(color: string, alpha: number): string {\n if (!color) return color;\n const a = Math.max(0, Math.min(1, alpha));\n if (color.startsWith('rgba(')) {\n return color.replace(/,\\s*[\\d.]+\\)\\s*$/, `, ${a})`);\n }\n if (color.startsWith('rgb(')) {\n return color.replace(/^rgb\\(/, 'rgba(').replace(/\\)\\s*$/, `, ${a})`);\n }\n if (color.startsWith('#')) {\n const hexA = Math.round(a * 255).toString(16).padStart(2, '0');\n return `${color}${hexA}`;\n }\n return color;\n}\n\n// ============================================================================\n// COMPONENT STYLE UTILITIES\n// ============================================================================\n\n/**\n * Merge class names, filtering out falsy values\n * @example classNames('base', isActive && 'active', className) // \"base active custom\"\n */\nexport function classNames(...classes: (string | boolean | undefined | null)[]): string {\n return classes.filter(Boolean).join(' ');\n}\n\n/**\n * Generate CSS for tabular numbers (monospace digits)\n */\nexport const tabularNumsStyle: React.CSSProperties = {\n fontVariantNumeric: 'tabular-nums',\n fontFeatureSettings: '\"tnum\" 1',\n};\n\n/**\n * CSS transition presets\n */\nexport const transitions = {\n fast: 'all 150ms ease-out',\n normal: 'all 250ms ease-out',\n slow: 'all 400ms ease-out',\n spring: 'all 300ms cubic-bezier(0.34, 1.56, 0.64, 1)',\n} as const;\n\n/**\n * Focus ring styles for accessibility\n */\nexport const focusRingStyle: React.CSSProperties = {\n outline: '2px solid #4dc3ff',\n outlineOffset: '2px',\n};\n\n/**\n * Compute a WCAG AA safe version of an accent color for use as foreground text\n * on dark backgrounds. If the accent already passes 4.5:1 contrast on typical\n * dark surfaces (L ≈ 0.01), returns it unchanged. Otherwise lightens toward\n * white until the minimum contrast is met.\n *\n * @example safeAccentText('#8b5cf6') // '#a885f8' — lightened to pass 4.5:1\n */\nexport function safeAccentText(accent: string): string {\n const hex = accent.replace('#', '');\n if (hex.length < 6) return accent;\n\n const r = parseInt(hex.slice(0, 2), 16) / 255;\n const g = parseInt(hex.slice(2, 4), 16) / 255;\n const b = parseInt(hex.slice(4, 6), 16) / 255;\n const toLinear = (c: number) =>\n c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n const L = 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n\n // Threshold: on a dark surface with L≈0.01 we need text L ≥ 0.22 for 4.5:1\n if (L >= 0.22) return accent;\n\n // Lighten by mixing 25% toward white — reaches ~5.5:1 on typical dark bgs\n const mix = 0.25;\n const lr = Math.min(255, Math.round((r + (1 - r) * mix) * 255));\n const lg = Math.min(255, Math.round((g + (1 - g) * mix) * 255));\n const lb = Math.min(255, Math.round((b + (1 - b) * mix) * 255));\n return `#${lr.toString(16).padStart(2, '0')}${lg.toString(16).padStart(2, '0')}${lb.toString(16).padStart(2, '0')}`;\n}\n\n// =============================================================================\n// Category Palette\n// =============================================================================\n\nexport { CategoryPalette } from './categoryPalette';\n"],"names":["mins","secs"],"mappings":"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"}
|
package/dist/react.js
CHANGED
|
@@ -15,6 +15,8 @@ import { CARD_ACCENT_COLORS, CardAccentProvider, SPACE_SYSTEM_COLORS, getAccentC
|
|
|
15
15
|
import { CATEGORY_ICONS, CATEGORY_LABELS, PROPERTY_PRESETS, createPropertyConfig, deriveBatteryStatus, deriveStatus, formatPropertyLabel, formatPropertyValue, getPropertiesByCategory, getPropertyConfig } from "./react/core/propertyConfig.js";
|
|
16
16
|
import { CHAT_RESPONSE_JSON_PROMPT, CHAT_RESPONSE_MCP_TOOL, CHAT_RESPONSE_TOOL_SCHEMA, CHAT_RESPONSE_YAML_PROMPT, CHAT_STATUS_RULES_PROMPT, ChatPanel, createChatResponseParser, parseChatResponse, parseMcpToolResult } from "./react/core/ChatPanel.js";
|
|
17
17
|
import { CardHeader } from "./react/core/CardHeader.js";
|
|
18
|
+
import { CategoryPalette } from "./react/utils/categoryPalette.js";
|
|
19
|
+
import { CategoryProvider, useCategoryPalette, useCategoryPaletteRequired } from "./react/context/CategoryContext.js";
|
|
18
20
|
import { Center } from "./react/core/layout/Center.js";
|
|
19
21
|
import { Checkbox } from "./react/core/Checkbox.js";
|
|
20
22
|
import { ClassificationBanner } from "./react/astro/ClassificationBanner.js";
|
|
@@ -88,6 +90,8 @@ export {
|
|
|
88
90
|
CHAT_STATUS_RULES_PROMPT,
|
|
89
91
|
CardAccentProvider,
|
|
90
92
|
CardHeader,
|
|
93
|
+
CategoryPalette,
|
|
94
|
+
CategoryProvider,
|
|
91
95
|
Center,
|
|
92
96
|
ChatPanel,
|
|
93
97
|
Checkbox,
|
|
@@ -241,6 +245,8 @@ export {
|
|
|
241
245
|
transitions,
|
|
242
246
|
useBreakpoint,
|
|
243
247
|
useCardAccent,
|
|
248
|
+
useCategoryPalette,
|
|
249
|
+
useCategoryPaletteRequired,
|
|
244
250
|
useCompactMode,
|
|
245
251
|
useConfirm,
|
|
246
252
|
useCopyToClipboard,
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"react.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|