@zendir/ui 0.2.21 → 0.3.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 +183 -1
- package/README.md +70 -28
- package/dist/index.d.ts +1 -1
- package/dist/index.js +51 -42
- package/dist/index.js.map +1 -1
- package/dist/react/3d/CesiumCaptureSource.d.ts +1 -1
- package/dist/react/3d/CesiumCaptureSource.js +1 -1
- package/dist/react/3d/CesiumCaptureSource.js.map +1 -1
- package/dist/react/3d/ZenSpace3D.js +1253 -0
- package/dist/react/3d/ZenSpace3D.js.map +1 -0
- package/dist/react/3d/ZenSpace3DCesium.js +579 -0
- package/dist/react/3d/ZenSpace3DCesium.js.map +1 -0
- package/dist/react/3d/ZenSpace3DTypes.d.ts +28 -1
- package/dist/react/3d/ZenSpace3DUtils.d.ts +17 -173
- package/dist/react/3d/ZenSpace3DUtils.js +20 -1
- package/dist/react/3d/ZenSpace3DUtils.js.map +1 -1
- package/dist/react/3d/index.d.ts +6 -12
- package/dist/react/3d/threeLoader.js +18 -0
- package/dist/react/3d/threeLoader.js.map +1 -0
- package/dist/react/astro/MonitoringIcon.js +1 -1
- package/dist/react/astro/MonitoringIcon.js.map +1 -1
- package/dist/react/astro/SimulationControls.js +2 -2
- package/dist/react/astro/SimulationControls.js.map +1 -1
- package/dist/react/astro/UnifiedTimeline.js +4 -4
- package/dist/react/astro/UnifiedTimeline.js.map +1 -1
- package/dist/react/charts/GroundTrackMap.d.ts +2 -15
- package/dist/react/charts/GroundTrackMap.js +1 -1
- package/dist/react/charts/GroundTrackMap.js.map +1 -1
- package/dist/react/charts/unified/AstroChart.js +34 -13
- package/dist/react/charts/unified/AstroChart.js.map +1 -1
- package/dist/react/chatgpt/AppCard.d.ts +0 -4
- package/dist/react/chatgpt/index.d.ts +0 -19
- package/dist/react/context/SpatialSelectionContext.d.ts +40 -0
- package/dist/react/context/SpatialSelectionContext.js +10 -0
- package/dist/react/context/SpatialSelectionContext.js.map +1 -0
- package/dist/react/context/index.d.ts +2 -0
- package/dist/react/core/{DataTable.d.ts → data/DataTable.d.ts} +1 -1
- package/dist/react/core/{DataTable.js → data/DataTable.js} +4 -4
- package/dist/react/core/data/DataTable.js.map +1 -0
- package/dist/react/core/{DataValue.d.ts → data/DataValue.d.ts} +2 -2
- package/dist/react/core/{DataValue.js → data/DataValue.js} +2 -2
- package/dist/react/core/data/DataValue.js.map +1 -0
- package/dist/react/core/{propertyConfig.d.ts → data/propertyConfig.d.ts} +2 -2
- package/dist/react/core/data/propertyConfig.js.map +1 -0
- package/dist/react/core/{AstroIcon.js → display/AstroIcon.js} +1 -1
- package/dist/react/core/display/AstroIcon.js.map +1 -0
- package/dist/react/core/{Badge.d.ts → display/Badge.d.ts} +1 -1
- package/dist/react/core/{Badge.js → display/Badge.js} +2 -2
- package/dist/react/core/display/Badge.js.map +1 -0
- package/dist/react/core/{CardHeader.d.ts → display/CardHeader.d.ts} +1 -1
- package/dist/react/core/{CardHeader.js → display/CardHeader.js} +2 -2
- package/dist/react/core/display/CardHeader.js.map +1 -0
- package/dist/react/core/{Container.d.ts → display/Container.d.ts} +1 -1
- package/dist/react/core/{Container.js → display/Container.js} +3 -3
- package/dist/react/core/display/Container.js.map +1 -0
- package/dist/react/core/{CopyButton.js → display/CopyButton.js} +1 -1
- package/dist/react/core/display/CopyButton.js.map +1 -0
- package/dist/react/core/{GlassCard.d.ts → display/GlassCard.d.ts} +1 -1
- package/dist/react/core/{GlassCard.js → display/GlassCard.js} +2 -2
- package/dist/react/core/display/GlassCard.js.map +1 -0
- package/dist/react/core/{HeaderIconWithStatus.d.ts → display/HeaderIconWithStatus.d.ts} +1 -1
- package/dist/react/core/{HeaderIconWithStatus.js → display/HeaderIconWithStatus.js} +1 -1
- package/dist/react/core/display/HeaderIconWithStatus.js.map +1 -0
- package/dist/react/core/{Icon.d.ts → display/Icon.d.ts} +1 -1
- package/dist/react/core/{Icon.js → display/Icon.js} +1 -1
- package/dist/react/core/display/Icon.js.map +1 -0
- package/dist/react/core/{Typography.d.ts → display/Typography.d.ts} +13 -4
- package/dist/react/core/{Typography.js → display/Typography.js} +1 -1
- package/dist/react/core/display/Typography.js.map +1 -0
- package/dist/react/core/{ConfirmDialog.js → feedback/ConfirmDialog.js} +1 -1
- package/dist/react/core/feedback/ConfirmDialog.js.map +1 -0
- package/dist/react/core/{Dialog.js → feedback/Dialog.js} +2 -2
- package/dist/react/core/feedback/Dialog.js.map +1 -0
- package/dist/react/core/{Toast.js → feedback/Toast.js} +3 -3
- package/dist/react/core/feedback/Toast.js.map +1 -0
- package/dist/react/core/index.d.ts +85 -85
- package/dist/react/core/{Button.js → inputs/Button.js} +2 -2
- package/dist/react/core/inputs/Button.js.map +1 -0
- package/dist/react/core/{Checkbox.js → inputs/Checkbox.js} +2 -2
- package/dist/react/core/inputs/Checkbox.js.map +1 -0
- package/dist/react/core/{Input.d.ts → inputs/Input.d.ts} +1 -1
- package/dist/react/core/{Input.js → inputs/Input.js} +3 -3
- package/dist/react/core/inputs/Input.js.map +1 -0
- package/dist/react/core/{LimitsBar.js → inputs/LimitsBar.js} +1 -1
- package/dist/react/core/inputs/LimitsBar.js.map +1 -0
- package/dist/react/core/{NumberInput.d.ts → inputs/NumberInput.d.ts} +2 -2
- package/dist/react/core/{NumberInput.js → inputs/NumberInput.js} +3 -3
- package/dist/react/core/inputs/NumberInput.js.map +1 -0
- package/dist/react/core/{PinInput.js → inputs/PinInput.js} +2 -2
- package/dist/react/core/inputs/PinInput.js.map +1 -0
- package/dist/react/core/{Select.js → inputs/Select.js} +3 -3
- package/dist/react/core/inputs/Select.js.map +1 -0
- package/dist/react/core/{Toggle.js → inputs/Toggle.js} +2 -2
- package/dist/react/core/inputs/Toggle.js.map +1 -0
- package/dist/react/core/{AppBar.d.ts → navigation/AppBar.d.ts} +1 -1
- package/dist/react/core/{AppBar.js → navigation/AppBar.js} +7 -7
- package/dist/react/core/navigation/AppBar.js.map +1 -0
- package/dist/react/core/{Pagination.js → navigation/Pagination.js} +2 -2
- package/dist/react/core/navigation/Pagination.js.map +1 -0
- package/dist/react/core/{SideNav.d.ts → navigation/SideNav.d.ts} +1 -1
- package/dist/react/core/{SideNav.js → navigation/SideNav.js} +3 -3
- package/dist/react/core/navigation/SideNav.js.map +1 -0
- package/dist/react/core/{Tabs.js → navigation/Tabs.js} +2 -2
- package/dist/react/core/navigation/Tabs.js.map +1 -0
- package/dist/react/core/{Popover.js → overlays/Popover.js} +1 -1
- package/dist/react/core/overlays/Popover.js.map +1 -0
- package/dist/react/core/{SidePanel.js → overlays/SidePanel.js} +3 -3
- package/dist/react/core/overlays/SidePanel.js.map +1 -0
- package/dist/react/core/{Tooltip.js → overlays/Tooltip.js} +2 -2
- package/dist/react/core/overlays/Tooltip.js.map +1 -0
- package/dist/react/core/{ActivityPlanner.js → widgets/ActivityPlanner.js} +1 -1
- package/dist/react/core/widgets/ActivityPlanner.js.map +1 -0
- package/dist/react/core/{Capture.js → widgets/Capture.js} +3 -3
- package/dist/react/core/widgets/Capture.js.map +1 -0
- package/dist/react/core/{ChatPanel.d.ts → widgets/ChatPanel.d.ts} +1 -1
- package/dist/react/core/{ChatPanel.js → widgets/ChatPanel.js} +2 -2
- package/dist/react/core/widgets/ChatPanel.js.map +1 -0
- package/dist/react/core/{ColorPickerPanel.d.ts → widgets/ColorPickerPanel.d.ts} +1 -1
- package/dist/react/core/{ColorPickerPanel.js → widgets/ColorPickerPanel.js} +3 -3
- package/dist/react/core/widgets/ColorPickerPanel.js.map +1 -0
- package/dist/react/core/{CommandBuilder.js → widgets/CommandBuilder.js} +1 -1
- package/dist/react/core/widgets/CommandBuilder.js.map +1 -0
- package/dist/react/core/{ConnectionForm.d.ts → widgets/ConnectionForm.d.ts} +1 -1
- package/dist/react/core/{ConnectionForm.js → widgets/ConnectionForm.js} +2 -2
- package/dist/react/core/widgets/ConnectionForm.js.map +1 -0
- package/dist/react/core/{FileExplorer.js → widgets/FileExplorer.js} +2 -2
- package/dist/react/core/widgets/FileExplorer.js.map +1 -0
- package/dist/react/core/{HexViewer.js → widgets/HexViewer.js} +1 -1
- package/dist/react/core/widgets/HexViewer.js.map +1 -0
- package/dist/react/core/{ImageGallery.d.ts → widgets/ImageGallery.d.ts} +1 -1
- package/dist/react/core/{ImageGallery.js → widgets/ImageGallery.js} +3 -3
- package/dist/react/core/widgets/ImageGallery.js.map +1 -0
- package/dist/react/core/{LogViewer.d.ts → widgets/LogViewer.d.ts} +13 -3
- package/dist/react/core/{LogViewer.js → widgets/LogViewer.js} +28 -8
- package/dist/react/core/widgets/LogViewer.js.map +1 -0
- package/dist/react/core/{MessageStream.d.ts → widgets/MessageStream.d.ts} +2 -2
- package/dist/react/core/{MessageStream.js → widgets/MessageStream.js} +4 -4
- package/dist/react/core/widgets/MessageStream.js.map +1 -0
- package/dist/react/core/{MissionCalendar.js → widgets/MissionCalendar.js} +2 -2
- package/dist/react/core/widgets/MissionCalendar.js.map +1 -0
- package/dist/react/core/{PacketViewer.js → widgets/PacketViewer.js} +1 -1
- package/dist/react/core/widgets/PacketViewer.js.map +1 -0
- package/dist/react/core/widgets/capture-placeholder.png.js.map +1 -0
- package/dist/react/hooks/index.d.ts +9 -11
- package/dist/react/hooks/useAccessWindows.d.ts +15 -19
- package/dist/react/hooks/useGroundTrackHistory.d.ts +34 -0
- package/dist/react/hooks/useSimulationScene.d.ts +141 -0
- package/dist/react/hooks/useSimulationScene.js +401 -0
- package/dist/react/hooks/useSimulationScene.js.map +1 -0
- package/dist/react/hooks/useZendirSession.d.ts +44 -69
- package/dist/react/index.d.ts +7 -3
- package/dist/react/panels/LayerControlPanel.d.ts +54 -0
- package/dist/react/panels/LayerControlPanel.js +184 -0
- package/dist/react/panels/LayerControlPanel.js.map +1 -0
- package/dist/react/panels/ObjectInventoryPanel.d.ts +57 -0
- package/dist/react/panels/ObjectInventoryPanel.js +261 -0
- package/dist/react/panels/ObjectInventoryPanel.js.map +1 -0
- package/dist/react/panels/index.d.ts +15 -0
- package/dist/react/theme/ThemeProvider.d.ts +2 -0
- package/dist/react/theme/ThemeProvider.js +50 -72
- package/dist/react/theme/ThemeProvider.js.map +1 -1
- package/dist/react/types.d.ts +32 -3
- package/dist/react/types.js.map +1 -1
- package/dist/react.js +51 -42
- package/dist/react.js.map +1 -1
- package/dist/shaders/atmosphere.frag.js +5 -0
- package/dist/shaders/atmosphere.frag.js.map +1 -0
- package/dist/shaders/atmosphere.vert.js +5 -0
- package/dist/shaders/atmosphere.vert.js.map +1 -0
- package/dist/shaders/stars.frag.js +5 -0
- package/dist/shaders/stars.frag.js.map +1 -0
- package/dist/shaders/stars.vert.js +5 -0
- package/dist/shaders/stars.vert.js.map +1 -0
- package/dist/style.css +6 -4
- package/dist/tokens/css-vars.d.ts +91 -0
- package/dist/tokens/css-vars.js +228 -0
- package/dist/tokens/css-vars.js.map +1 -0
- package/dist/tokens/index.d.ts +71 -18
- package/dist/tokens/index.js +206 -97
- package/dist/tokens/index.js.map +1 -1
- package/dist/tokens/tokens.css +50 -50
- package/package.json +26 -22
- package/sdk-stub.js +10 -5
- package/dist/react/3d/EarthViewer.d.ts +0 -46
- package/dist/react/3d/SolarSystemViewer.d.ts +0 -43
- package/dist/react/chatgpt/ChatGPTCard.d.ts +0 -6
- package/dist/react/core/ActivityPlanner.js.map +0 -1
- package/dist/react/core/AppBar.js.map +0 -1
- package/dist/react/core/AstroIcon.js.map +0 -1
- package/dist/react/core/Badge.js.map +0 -1
- package/dist/react/core/Button.js.map +0 -1
- package/dist/react/core/Capture.js.map +0 -1
- package/dist/react/core/CardHeader.js.map +0 -1
- package/dist/react/core/ChatPanel.js.map +0 -1
- package/dist/react/core/Checkbox.js.map +0 -1
- package/dist/react/core/ColorPickerPanel.js.map +0 -1
- package/dist/react/core/CommandBuilder.js.map +0 -1
- package/dist/react/core/ConfirmDialog.js.map +0 -1
- package/dist/react/core/ConnectionForm.js.map +0 -1
- package/dist/react/core/Container.js.map +0 -1
- package/dist/react/core/CopyButton.js.map +0 -1
- package/dist/react/core/DataTable.js.map +0 -1
- package/dist/react/core/DataValue.js.map +0 -1
- package/dist/react/core/Dialog.js.map +0 -1
- package/dist/react/core/FileExplorer.js.map +0 -1
- package/dist/react/core/GlassCard.js.map +0 -1
- package/dist/react/core/HeaderIconWithStatus.js.map +0 -1
- package/dist/react/core/HexViewer.js.map +0 -1
- package/dist/react/core/Icon.js.map +0 -1
- package/dist/react/core/ImageGallery.js.map +0 -1
- package/dist/react/core/Input.js.map +0 -1
- package/dist/react/core/LimitsBar.js.map +0 -1
- package/dist/react/core/LogViewer.js.map +0 -1
- package/dist/react/core/MessageStream.js.map +0 -1
- package/dist/react/core/MissionCalendar.js.map +0 -1
- package/dist/react/core/NumberInput.js.map +0 -1
- package/dist/react/core/PacketViewer.js.map +0 -1
- package/dist/react/core/Pagination.js.map +0 -1
- package/dist/react/core/PinInput.js.map +0 -1
- package/dist/react/core/Popover.js.map +0 -1
- package/dist/react/core/Select.js.map +0 -1
- package/dist/react/core/SideNav.js.map +0 -1
- package/dist/react/core/SidePanel.js.map +0 -1
- package/dist/react/core/Tabs.js.map +0 -1
- package/dist/react/core/Toast.js.map +0 -1
- package/dist/react/core/Toggle.js.map +0 -1
- package/dist/react/core/Tooltip.js.map +0 -1
- package/dist/react/core/Typography.js.map +0 -1
- package/dist/react/core/capture-placeholder.png.js.map +0 -1
- package/dist/react/core/propertyConfig.js.map +0 -1
- package/dist/react/hooks/useSimulationTime.d.ts +0 -61
- package/dist/react/hooks/useSpacecraftPosition.d.ts +0 -50
- package/dist/react/hooks/useTelemetry.d.ts +0 -55
- package/dist/types.d.ts +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- /package/dist/react/core/{propertyConfig.js → data/propertyConfig.js} +0 -0
- /package/dist/react/core/{AstroIcon.d.ts → display/AstroIcon.d.ts} +0 -0
- /package/dist/react/core/{CopyButton.d.ts → display/CopyButton.d.ts} +0 -0
- /package/dist/react/core/{ConfirmDialog.d.ts → feedback/ConfirmDialog.d.ts} +0 -0
- /package/dist/react/core/{Dialog.d.ts → feedback/Dialog.d.ts} +0 -0
- /package/dist/react/core/{Toast.d.ts → feedback/Toast.d.ts} +0 -0
- /package/dist/react/core/{Button.d.ts → inputs/Button.d.ts} +0 -0
- /package/dist/react/core/{Checkbox.d.ts → inputs/Checkbox.d.ts} +0 -0
- /package/dist/react/core/{LimitsBar.d.ts → inputs/LimitsBar.d.ts} +0 -0
- /package/dist/react/core/{PinInput.d.ts → inputs/PinInput.d.ts} +0 -0
- /package/dist/react/core/{Select.d.ts → inputs/Select.d.ts} +0 -0
- /package/dist/react/core/{Toggle.d.ts → inputs/Toggle.d.ts} +0 -0
- /package/dist/react/core/{Pagination.d.ts → navigation/Pagination.d.ts} +0 -0
- /package/dist/react/core/{Tabs.d.ts → navigation/Tabs.d.ts} +0 -0
- /package/dist/react/core/{Popover.d.ts → overlays/Popover.d.ts} +0 -0
- /package/dist/react/core/{SidePanel.d.ts → overlays/SidePanel.d.ts} +0 -0
- /package/dist/react/core/{Tooltip.d.ts → overlays/Tooltip.d.ts} +0 -0
- /package/dist/react/core/{ActivityPlanner.d.ts → widgets/ActivityPlanner.d.ts} +0 -0
- /package/dist/react/core/{Capture.d.ts → widgets/Capture.d.ts} +0 -0
- /package/dist/react/core/{CommandBuilder.d.ts → widgets/CommandBuilder.d.ts} +0 -0
- /package/dist/react/core/{FileExplorer.d.ts → widgets/FileExplorer.d.ts} +0 -0
- /package/dist/react/core/{HexViewer.d.ts → widgets/HexViewer.d.ts} +0 -0
- /package/dist/react/core/{MissionCalendar.d.ts → widgets/MissionCalendar.d.ts} +0 -0
- /package/dist/react/core/{PacketViewer.d.ts → widgets/PacketViewer.d.ts} +0 -0
- /package/dist/react/core/{capture-placeholder.png.js → widgets/capture-placeholder.png.js} +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface SpatialSelectionContextValue {
|
|
4
|
+
/** ID of the currently selected object, or null if nothing is selected. */
|
|
5
|
+
selectedId: string | null;
|
|
6
|
+
/** Set the selection (or clear with `null`). */
|
|
7
|
+
setSelectedId: (id: string | null) => void;
|
|
8
|
+
/** Toggle selection: select the id if it isn't selected, clear otherwise. */
|
|
9
|
+
toggleSelection: (id: string) => void;
|
|
10
|
+
/** Convenience: clear any current selection. */
|
|
11
|
+
clearSelection: () => void;
|
|
12
|
+
}
|
|
13
|
+
export interface SpatialSelectionProviderProps {
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
/** Initial selected id. Default null (nothing selected). */
|
|
16
|
+
defaultSelectedId?: string | null;
|
|
17
|
+
/** Controlled mode: when set, the provider mirrors this value instead
|
|
18
|
+
* of owning state. Pair with `onSelectionChange`. */
|
|
19
|
+
selectedId?: string | null;
|
|
20
|
+
/** Called whenever the selection changes (uncontrolled or controlled). */
|
|
21
|
+
onSelectionChange?: (id: string | null) => void;
|
|
22
|
+
}
|
|
23
|
+
export declare function SpatialSelectionProvider({ children, defaultSelectedId, selectedId: controlledId, onSelectionChange, }: SpatialSelectionProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
/**
|
|
25
|
+
* Read the spatial-selection context. Returns `null` when used outside
|
|
26
|
+
* a `<SpatialSelectionProvider>` — components MUST handle that case so
|
|
27
|
+
* they stay standalone-usable. Treat the provider as a progressive
|
|
28
|
+
* enhancement, never a hard dependency.
|
|
29
|
+
*
|
|
30
|
+
* const ctx = useSpatialSelection();
|
|
31
|
+
* const selectedId = ctx?.selectedId ?? null; // safe outside provider
|
|
32
|
+
* const onSelect = ctx?.setSelectedId ?? noop; // safe outside provider
|
|
33
|
+
*/
|
|
34
|
+
export declare function useSpatialSelection(): SpatialSelectionContextValue | null;
|
|
35
|
+
/**
|
|
36
|
+
* Strict variant — throws if used outside a provider. Useful in the
|
|
37
|
+
* provider's own children when the dependency is intentional.
|
|
38
|
+
*/
|
|
39
|
+
export declare function useSpatialSelectionStrict(): SpatialSelectionContextValue;
|
|
40
|
+
export default SpatialSelectionProvider;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import "react/jsx-runtime";
|
|
2
|
+
import { useContext, createContext } from "react";
|
|
3
|
+
const SpatialSelectionContextInternal = createContext(null);
|
|
4
|
+
function useSpatialSelection() {
|
|
5
|
+
return useContext(SpatialSelectionContextInternal);
|
|
6
|
+
}
|
|
7
|
+
export {
|
|
8
|
+
useSpatialSelection
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=SpatialSelectionContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpatialSelectionContext.js","sources":["../../../src/react/context/SpatialSelectionContext.tsx"],"sourcesContent":["/**\n * @zendir/ui - SpatialSelectionContext\n *\n * Optional shared selection state for spatial dashboards. Wrap a tree\n * containing `<ZenSpace3D />`, `<GroundTrackMap />`,\n * `<ObjectInventoryPanel />`, etc. — they cross-talk via the context\n * and stay synchronised without prop-drilling:\n *\n * <SpatialSelectionProvider>\n * <ObjectInventoryPanel objects={scene.objects} /> // writes selection\n * <ZenSpace3D satellites={...} /> // reads selection\n * <GroundTrackMap satellites={tracks} /> // reads selection\n * </SpatialSelectionProvider>\n *\n * The provider is **opt-in**. Components that consume the context use\n * `useSpatialSelection()` which returns `null` outside a provider —\n * that's how every component stays standalone-usable. No coupling.\n */\n\nimport { createContext, useCallback, useContext, useMemo, useState } from 'react';\nimport type { ReactNode } from 'react';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface SpatialSelectionContextValue {\n /** ID of the currently selected object, or null if nothing is selected. */\n selectedId: string | null;\n /** Set the selection (or clear with `null`). */\n setSelectedId: (id: string | null) => void;\n /** Toggle selection: select the id if it isn't selected, clear otherwise. */\n toggleSelection: (id: string) => void;\n /** Convenience: clear any current selection. */\n clearSelection: () => void;\n}\n\nconst SpatialSelectionContextInternal = createContext<SpatialSelectionContextValue | null>(null);\n\n// ─── Provider ─────────────────────────────────────────────────────────────────\n\nexport interface SpatialSelectionProviderProps {\n children: ReactNode;\n /** Initial selected id. Default null (nothing selected). */\n defaultSelectedId?: string | null;\n /** Controlled mode: when set, the provider mirrors this value instead\n * of owning state. Pair with `onSelectionChange`. */\n selectedId?: string | null;\n /** Called whenever the selection changes (uncontrolled or controlled). */\n onSelectionChange?: (id: string | null) => void;\n}\n\nexport function SpatialSelectionProvider({\n children,\n defaultSelectedId = null,\n selectedId: controlledId,\n onSelectionChange,\n}: SpatialSelectionProviderProps) {\n const [internalId, setInternalId] = useState<string | null>(defaultSelectedId);\n const isControlled = controlledId !== undefined;\n const selectedId = isControlled ? controlledId : internalId;\n\n const setSelectedId = useCallback(\n (id: string | null) => {\n if (!isControlled) setInternalId(id);\n onSelectionChange?.(id);\n },\n [isControlled, onSelectionChange],\n );\n\n const toggleSelection = useCallback(\n (id: string) => {\n const next = selectedId === id ? null : id;\n if (!isControlled) setInternalId(next);\n onSelectionChange?.(next);\n },\n [selectedId, isControlled, onSelectionChange],\n );\n\n const clearSelection = useCallback(() => {\n if (!isControlled) setInternalId(null);\n onSelectionChange?.(null);\n }, [isControlled, onSelectionChange]);\n\n const value = useMemo<SpatialSelectionContextValue>(\n () => ({ selectedId, setSelectedId, toggleSelection, clearSelection }),\n [selectedId, setSelectedId, toggleSelection, clearSelection],\n );\n\n return (\n <SpatialSelectionContextInternal.Provider value={value}>\n {children}\n </SpatialSelectionContextInternal.Provider>\n );\n}\n\n// ─── Hooks ────────────────────────────────────────────────────────────────────\n\n/**\n * Read the spatial-selection context. Returns `null` when used outside\n * a `<SpatialSelectionProvider>` — components MUST handle that case so\n * they stay standalone-usable. Treat the provider as a progressive\n * enhancement, never a hard dependency.\n *\n * const ctx = useSpatialSelection();\n * const selectedId = ctx?.selectedId ?? null; // safe outside provider\n * const onSelect = ctx?.setSelectedId ?? noop; // safe outside provider\n */\nexport function useSpatialSelection(): SpatialSelectionContextValue | null {\n return useContext(SpatialSelectionContextInternal);\n}\n\n/**\n * Strict variant — throws if used outside a provider. Useful in the\n * provider's own children when the dependency is intentional.\n */\nexport function useSpatialSelectionStrict(): SpatialSelectionContextValue {\n const ctx = useContext(SpatialSelectionContextInternal);\n if (!ctx) {\n throw new Error(\n 'useSpatialSelectionStrict() called outside <SpatialSelectionProvider>. ' +\n 'Wrap the tree, or use useSpatialSelection() (returns null) for opt-in usage.',\n );\n }\n return ctx;\n}\n\nexport default SpatialSelectionProvider;\n"],"names":[],"mappings":";;AAmCA,MAAM,kCAAkC,cAAmD,IAAI;AAuExF,SAAS,sBAA2D;AACzE,SAAO,WAAW,+BAA+B;AACnD;"}
|
|
@@ -5,3 +5,5 @@ export { DisplaySettingsProvider, useDisplaySettings, useDisplaySettingsOptional
|
|
|
5
5
|
export type { DisplaySettings, DisplaySettingsContextValue, DisplaySettingsProviderProps, ColorTarget, PresetColorKey, GlassTintKey, } from './DisplaySettingsContext';
|
|
6
6
|
export { CategoryProvider, useCategoryPalette, useCategoryPaletteRequired, } from './CategoryContext';
|
|
7
7
|
export type { CategoryContextValue, CategoryProviderProps, } from './CategoryContext';
|
|
8
|
+
export { SpatialSelectionProvider, useSpatialSelection, useSpatialSelectionStrict, } from './SpatialSelectionContext';
|
|
9
|
+
export type { SpatialSelectionContextValue, SpatialSelectionProviderProps, } from './SpatialSelectionContext';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React, { memo, useMemo, useState, useCallback } from "react";
|
|
3
|
-
import { useBreakpoint } from "
|
|
4
|
-
import { Tooltip } from "
|
|
5
|
-
import { addAlpha } from "
|
|
6
|
-
import { useTheme } from "
|
|
3
|
+
import { useBreakpoint } from "../layout/useBreakpoint.js";
|
|
4
|
+
import { Tooltip } from "../overlays/Tooltip.js";
|
|
5
|
+
import { addAlpha } from "../../utils/index.js";
|
|
6
|
+
import { useTheme } from "../../theme/ThemeProvider.js";
|
|
7
7
|
const STATUS_DOT_COLORS = {
|
|
8
8
|
normal: "#56F000",
|
|
9
9
|
caution: "#FCE83A",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataTable.js","sources":["../../../../src/react/core/data/DataTable.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - DataTable Component\r\n * \r\n * Structured data display with expandable groups, responsive columns,\r\n * and theme-aware styling. Designed for telemetry parameter grids,\r\n * link budget displays, spacecraft information panels.\r\n * \r\n * Astro UX Compliance:\r\n * - Tabular monospace numbers for value columns\r\n * - Status-based row coloring\r\n * - Compact mode support\r\n * - Accessible table semantics\r\n * \r\n * Enhanced Tooltip System:\r\n * - Row-level tooltips (string or rich ReactNode via rowTooltipContent)\r\n * - Cell-level tooltips per column definition\r\n * - Header tooltips for column descriptions\r\n * - Built-in DataTableRowDetail component for structured detail views\r\n * - Portal-rendered, WCAG-compliant, animated tooltips\r\n * \r\n * @example\r\n * ```tsx\r\n * <DataTable\r\n * columns={[\r\n * { key: 'label', header: 'Parameter', width: '40%', headerTooltip: 'Telemetry parameter name' },\r\n * { key: 'value', header: 'Value', align: 'right', mono: true, cellTooltip: (v, row) => `Raw: ${v}` },\r\n * { key: 'unit', header: 'Unit', width: 80 },\r\n * ]}\r\n * data={[\r\n * { label: 'Frequency', value: '437.500', unit: 'MHz' },\r\n * { label: 'Bandwidth', value: '25.000', unit: 'kHz' },\r\n * ]}\r\n * rowTooltipContent={(row) => (\r\n * <DataTableRowDetail\r\n * title={row.label}\r\n * fields={[\r\n * { label: 'Value', value: `${row.value} ${row.unit}` },\r\n * ]}\r\n * />\r\n * )}\r\n * />\r\n * ```\r\n */\r\n\r\nimport React, { memo, useState, useCallback, useMemo } from 'react';\r\nimport { useTheme } from '../../theme';\r\nimport { useBreakpoint } from '../layout/useBreakpoint';\r\nimport { Tooltip } from '../overlays/Tooltip';\r\nimport type { TooltipPlacement } from '../overlays/Tooltip';\r\nimport { addAlpha } from '../../utils';\r\n\r\n// ─── Types ───────────────────────────────────────────────────────────────────\r\n\r\nexport interface DataTableColumn<T = Record<string, unknown>> {\r\n /** Key in data object */\r\n key: string;\r\n /** Column header text */\r\n header: string;\r\n /** Column width (CSS value or number for px) */\r\n width?: string | number;\r\n /** Text alignment */\r\n align?: 'left' | 'center' | 'right';\r\n /** Use monospace font (good for numbers) */\r\n mono?: boolean;\r\n /** Custom cell renderer */\r\n render?: (value: unknown, row: T, index: number) => React.ReactNode;\r\n /** Hide column on mobile */\r\n hideOnMobile?: boolean;\r\n /** Tooltip for the column header (explains what this column represents) */\r\n headerTooltip?: string;\r\n /** Per-cell tooltip — return string or ReactNode, or undefined to skip */\r\n cellTooltip?: (value: unknown, row: T, index: number) => React.ReactNode | undefined;\r\n}\r\n\r\nexport interface DataTableProps<T = Record<string, unknown>> {\r\n /** Column definitions */\r\n columns: DataTableColumn<T>[];\r\n /** Data rows */\r\n data: T[];\r\n /** Key field for React keys (default: index) */\r\n keyField?: string;\r\n /** Group rows by this field */\r\n groupBy?: string;\r\n /** Allow expanding/collapsing groups */\r\n expandable?: boolean;\r\n /** Default expanded state for groups */\r\n defaultExpanded?: boolean;\r\n /** Striped rows */\r\n striped?: boolean;\r\n /** Compact row padding */\r\n compact?: boolean;\r\n /** Show header row */\r\n showHeader?: boolean;\r\n /** Empty state message */\r\n emptyMessage?: string;\r\n /** Row click handler */\r\n onRowClick?: (row: T, index: number) => void;\r\n /** Simple string tooltip for each row (legacy — uses native title) */\r\n rowTooltip?: (row: T) => string | undefined;\r\n /** Rich tooltip content for each row — renders in a portal-based Tooltip */\r\n rowTooltipContent?: (row: T, index: number) => React.ReactNode | undefined;\r\n /** Placement for row and cell tooltips (default: 'top') */\r\n tooltipPlacement?: TooltipPlacement;\r\n /** Delay before tooltips appear in ms (default: 300) */\r\n tooltipDelay?: number;\r\n /** Max height with scroll */\r\n maxHeight?: string | number;\r\n /** Color for boolean ✓/✗ values (e.g. '#fff' for white). Defaults to text.primary or row status. */\r\n booleanColor?: string;\r\n /** Optional row status key or getter — boolean cells use this row's status color when set (matches white/status design). */\r\n getRowStatus?: (row: T, index: number) => 'normal' | 'caution' | 'serious' | 'critical' | 'standby' | 'off' | undefined;\r\n /** Custom style */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n// ─── DataTableRowDetail ──────────────────────────────────────────────────────\r\n\r\nexport interface DataTableRowDetailField {\r\n /** Field label */\r\n label: string;\r\n /** Field value (string, number, or ReactNode for custom rendering) */\r\n value: React.ReactNode;\r\n /** Optional status color for the value */\r\n status?: 'normal' | 'caution' | 'serious' | 'critical' | 'standby' | 'off';\r\n /** Use monospace font for this value */\r\n mono?: boolean;\r\n}\r\n\r\nexport interface DataTableRowDetailProps {\r\n /** Title shown at the top of the tooltip */\r\n title?: React.ReactNode;\r\n /** Optional subtitle / secondary info */\r\n subtitle?: React.ReactNode;\r\n /** Structured key-value fields to display */\r\n fields?: DataTableRowDetailField[];\r\n /** Optional footer content (timestamps, actions, etc.) */\r\n footer?: React.ReactNode;\r\n /** Optional icon or status indicator beside the title */\r\n icon?: React.ReactNode;\r\n /** Maximum width of the tooltip (default: 320) */\r\n maxWidth?: number;\r\n}\r\n\r\nconst STATUS_DOT_COLORS: Record<string, string> = {\r\n normal: '#56F000',\r\n caution: '#FCE83A',\r\n serious: '#FFB302',\r\n critical: '#FF3838',\r\n standby: '#2DCCFF',\r\n off: '#9EA7AD',\r\n};\r\n\r\n/**\r\n * Pre-built tooltip content renderer for DataTable rows.\r\n * Provides a structured layout: title, key-value fields, and optional footer.\r\n * \r\n * @example\r\n * ```tsx\r\n * <DataTable\r\n * columns={columns}\r\n * data={data}\r\n * rowTooltipContent={(row) => (\r\n * <DataTableRowDetail\r\n * title={row.parameter}\r\n * subtitle={row.category}\r\n * fields={[\r\n * { label: 'Value', value: row.value, mono: true },\r\n * { label: 'Status', value: row.status, status: row.status },\r\n * ]}\r\n * footer={`Last updated: ${row.timestamp}`}\r\n * />\r\n * )}\r\n * />\r\n * ```\r\n */\r\nexport const DataTableRowDetail = memo(function DataTableRowDetail({\r\n title,\r\n subtitle,\r\n fields,\r\n footer,\r\n icon,\r\n maxWidth = 320,\r\n}: DataTableRowDetailProps): React.ReactElement {\r\n const { tokens } = useTheme();\r\n\r\n return (\r\n <div style={{ maxWidth, minWidth: 180 }}>\r\n {/* Header */}\r\n {(title || icon) && (\r\n <div style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: tokens.spacing.sm,\r\n marginBottom: fields?.length || subtitle ? tokens.spacing.sm : 0,\r\n }}>\r\n {icon}\r\n <div style={{ flex: 1, minWidth: 0 }}>\r\n {title && (\r\n <div style={{\r\n fontWeight: tokens.typography.fontWeight.semibold,\r\n fontSize: tokens.typography.fontSize.sm,\r\n color: tokens.colors.text.primary,\r\n lineHeight: 1.3,\r\n overflow: 'hidden',\r\n textOverflow: 'ellipsis',\r\n }}>\r\n {title}\r\n </div>\r\n )}\r\n {subtitle && (\r\n <div style={{\r\n fontSize: tokens.typography.fontSize.xxs,\r\n color: tokens.colors.text.tertiary,\r\n marginTop: 2,\r\n }}>\r\n {subtitle}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Fields */}\r\n {fields && fields.length > 0 && (\r\n <div style={{\r\n display: 'grid',\r\n gridTemplateColumns: 'auto 1fr',\r\n gap: `${tokens.spacing.xs} ${tokens.spacing.md}`,\r\n fontSize: tokens.typography.fontSize.xs,\r\n lineHeight: 1.5,\r\n }}>\r\n {fields.map((field, i) => (\r\n <React.Fragment key={i}>\r\n <span style={{\r\n color: tokens.colors.text.tertiary,\r\n whiteSpace: 'nowrap',\r\n }}>\r\n {field.label}\r\n </span>\r\n <span style={{\r\n color: field.status\r\n ? STATUS_DOT_COLORS[field.status] || tokens.colors.text.primary\r\n : tokens.colors.text.primary,\r\n fontFamily: field.mono ? tokens.typography.fontFamily.mono : 'inherit',\r\n fontVariantNumeric: field.mono ? 'tabular-nums' : 'normal',\r\n textAlign: 'right',\r\n overflow: 'hidden',\r\n textOverflow: 'ellipsis',\r\n whiteSpace: 'nowrap',\r\n }}>\r\n {field.value}\r\n </span>\r\n </React.Fragment>\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Footer */}\r\n {footer && (\r\n <div style={{\r\n marginTop: tokens.spacing.sm,\r\n paddingTop: tokens.spacing.xs,\r\n borderTop: `1px solid ${addAlpha(tokens.colors.border.muted, 0.19)}`,\r\n fontSize: tokens.typography.fontSize.xxs,\r\n color: tokens.colors.text.tertiary,\r\n }}>\r\n {footer}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n});\r\n\r\n// ─── Cell Tooltip Wrapper ────────────────────────────────────────────────────\r\n\r\ninterface CellTooltipWrapperProps {\r\n content: React.ReactNode;\r\n placement: TooltipPlacement;\r\n delay: number;\r\n children: React.ReactElement;\r\n}\r\n\r\nconst CellTooltipWrapper = memo(function CellTooltipWrapper({\r\n content,\r\n placement,\r\n delay,\r\n children,\r\n}: CellTooltipWrapperProps): React.ReactElement {\r\n if (!content) return children;\r\n return (\r\n <Tooltip content={content} placement={placement} delay={delay}>\r\n {children}\r\n </Tooltip>\r\n );\r\n});\r\n\r\n// ─── DataTable ───────────────────────────────────────────────────────────────\r\n\r\nexport const DataTable = memo(function DataTable<T extends Record<string, unknown>>({\r\n columns,\r\n data,\r\n keyField,\r\n groupBy,\r\n expandable = false,\r\n defaultExpanded = true,\r\n striped = false,\r\n compact = false,\r\n showHeader = true,\r\n emptyMessage = 'No data available',\r\n onRowClick,\r\n rowTooltip,\r\n rowTooltipContent,\r\n tooltipPlacement = 'top',\r\n tooltipDelay = 300,\r\n maxHeight,\r\n booleanColor,\r\n getRowStatus,\r\n style,\r\n}: DataTableProps<T>): React.ReactElement {\r\n const { tokens } = useTheme();\r\n const { isMobile: isMobileView } = useBreakpoint();\r\n const statusColorMap = useMemo(() => ({\r\n normal: tokens.colors.status.normal,\r\n caution: tokens.colors.status.caution,\r\n serious: tokens.colors.status.serious,\r\n critical: tokens.colors.status.critical,\r\n standby: tokens.colors.status.standby,\r\n off: tokens.colors.status.off,\r\n }), [tokens.colors.status]);\r\n const visibleColumns = isMobileView ? columns.filter(col => !col.hideOnMobile) : columns;\r\n \r\n const [expandedGroups, setExpandedGroups] = useState<Set<string>>(\r\n defaultExpanded ? new Set(['__all__']) : new Set()\r\n );\r\n const [hoveredRow, setHoveredRow] = useState<number | null>(null);\r\n const visibleColumnCount = Math.max(1, visibleColumns.length);\r\n \r\n const cellPadding = compact ? `${tokens.spacing.xs} ${tokens.spacing.sm}` : `${tokens.spacing.sm} ${tokens.spacing.md}`;\r\n \r\n const toggleGroup = useCallback((group: string) => {\r\n setExpandedGroups(prev => {\r\n const next = new Set(prev);\r\n if (next.has(group)) next.delete(group);\r\n else next.add(group);\r\n return next;\r\n });\r\n }, []);\r\n \r\n const isGroupExpanded = useCallback((group: string) => {\r\n return expandedGroups.has('__all__') || expandedGroups.has(group);\r\n }, [expandedGroups]);\r\n \r\n const groups = useMemo(() => {\r\n if (!groupBy) return [{ key: '__default__', label: '', rows: data }];\r\n \r\n const map = new Map<string, T[]>();\r\n data.forEach(row => {\r\n const key = String((row as Record<string, unknown>)[groupBy] ?? 'Other');\r\n if (!map.has(key)) map.set(key, []);\r\n map.get(key)!.push(row);\r\n });\r\n \r\n return Array.from(map.entries()).map(([key, rows]) => ({\r\n key,\r\n label: key,\r\n rows,\r\n }));\r\n }, [data, groupBy]);\r\n \r\n const resolveWidth = (w: string | number | undefined): string | undefined => {\r\n if (w === undefined) return undefined;\r\n if (typeof w === 'number') return `${w}px`;\r\n return w;\r\n };\r\n \r\n const renderCell = (col: DataTableColumn<T>, row: T, rowIndex: number) => {\r\n const value = row[col.key];\r\n if (col.render) return col.render(value, row, rowIndex);\r\n if (value === null || value === undefined) return '—';\r\n if (typeof value === 'boolean') {\r\n const label = value ? '✓' : '✗';\r\n const color = booleanColor\r\n ?? (getRowStatus ? (() => { const s = getRowStatus(row, rowIndex); return s ? statusColorMap[s] : undefined; })() : undefined)\r\n ?? tokens.colors.text.primary;\r\n return <span style={{ color }}>{label}</span>;\r\n }\r\n return String(value);\r\n };\r\n\r\n const renderCellWithTooltip = (col: DataTableColumn<T>, row: T, rowIndex: number) => {\r\n const cellContent = renderCell(col, row, rowIndex);\r\n if (!col.cellTooltip) return cellContent;\r\n\r\n const tooltipContent = col.cellTooltip(row[col.key], row, rowIndex);\r\n if (!tooltipContent) return cellContent;\r\n\r\n return (\r\n <CellTooltipWrapper\r\n content={tooltipContent}\r\n placement={tooltipPlacement}\r\n delay={tooltipDelay}\r\n >\r\n <span style={{ cursor: 'help' }}>{cellContent}</span>\r\n </CellTooltipWrapper>\r\n );\r\n };\r\n\r\n const renderHeaderCell = (col: DataTableColumn<T>) => {\r\n const headerContent = (\r\n <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}>\r\n {col.header}\r\n {col.headerTooltip && (\r\n <svg\r\n width=\"12\" height=\"12\" viewBox=\"0 0 16 16\" fill=\"none\"\r\n style={{ opacity: 0.5, flexShrink: 0 }}\r\n >\r\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\r\n <path d=\"M8 7v4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\r\n <circle cx=\"8\" cy=\"5\" r=\"0.75\" fill=\"currentColor\" />\r\n </svg>\r\n )}\r\n </span>\r\n );\r\n \r\n if (!col.headerTooltip) return headerContent;\r\n \r\n return (\r\n <Tooltip content={col.headerTooltip} placement=\"bottom\" delay={tooltipDelay}>\r\n {headerContent}\r\n </Tooltip>\r\n );\r\n };\r\n \r\n const chevron = (expanded: boolean) => (\r\n <svg\r\n width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\"\r\n style={{\r\n transition: tokens.animation.fast,\r\n transform: expanded ? 'rotate(90deg)' : 'rotate(0deg)',\r\n flexShrink: 0,\r\n }}\r\n >\r\n <polyline points=\"9 18 15 12 9 6\" />\r\n </svg>\r\n );\r\n\r\n const hasRichRowTooltip = !!rowTooltipContent;\r\n \r\n const renderRowContent = (row: T, rowIdx: number, localIndex: number) => {\r\n const isHovered = hoveredRow === rowIdx;\r\n const rowKey = keyField ? String(row[keyField]) : rowIdx;\r\n const useNativeTitle = !hasRichRowTooltip && rowTooltip;\r\n\r\n const tr = (\r\n <tr\r\n key={rowKey}\r\n tabIndex={onRowClick ? 0 : undefined}\r\n onClick={onRowClick ? () => onRowClick(row, rowIdx) : undefined}\r\n onKeyDown={onRowClick ? (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onRowClick(row, rowIdx); } } : undefined}\r\n onMouseEnter={() => setHoveredRow(rowIdx)}\r\n onMouseLeave={() => setHoveredRow(null)}\r\n title={useNativeTitle ? rowTooltip(row) : undefined}\r\n style={{\r\n cursor: onRowClick ? 'pointer' : 'default',\r\n backgroundColor: isHovered\r\n ? addAlpha(tokens.colors.accent.primary, 0.08)\r\n : striped && localIndex % 2 === 1\r\n ? addAlpha(tokens.colors.background.surface, 0.5)\r\n : 'transparent',\r\n transition: 'background-color 150ms ease',\r\n }}\r\n >\r\n {visibleColumns.map(col => (\r\n <td\r\n key={col.key}\r\n style={{\r\n padding: cellPadding,\r\n textAlign: col.align || 'left',\r\n color: tokens.colors.text.primary,\r\n borderBottom: `1px solid ${addAlpha(tokens.colors.border.muted, 0.08)}`,\r\n fontFamily: col.mono ? tokens.typography.fontFamily.mono : 'inherit',\r\n fontVariantNumeric: col.mono ? 'tabular-nums' : 'normal',\r\n whiteSpace: 'nowrap',\r\n overflow: 'hidden',\r\n textOverflow: 'ellipsis',\r\n maxWidth: resolveWidth(col.width) || '300px',\r\n }}\r\n >\r\n {renderCellWithTooltip(col, row, rowIdx)}\r\n </td>\r\n ))}\r\n </tr>\r\n );\r\n\r\n if (hasRichRowTooltip) {\r\n const tooltipContent = rowTooltipContent(row, rowIdx);\r\n if (tooltipContent) {\r\n return (\r\n <Tooltip\r\n key={rowKey}\r\n content={tooltipContent}\r\n placement={tooltipPlacement}\r\n delay={tooltipDelay}\r\n >\r\n {tr}\r\n </Tooltip>\r\n );\r\n }\r\n }\r\n\r\n return tr;\r\n };\r\n \r\n let globalRowIndex = 0;\r\n \r\n return (\r\n <div\r\n style={{\r\n fontFamily: tokens.typography.fontFamily.primary,\r\n overflow: 'auto',\r\n WebkitOverflowScrolling: 'touch',\r\n maxHeight: typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight,\r\n borderRadius: tokens.borderRadius.md,\r\n border: tokens.borders.divider,\r\n ...style,\r\n }}\r\n >\r\n <table\r\n style={{\r\n width: '100%',\r\n borderCollapse: 'collapse',\r\n fontSize: compact ? tokens.typography.fontSize.xs : tokens.typography.fontSize.sm,\r\n }}\r\n >\r\n {showHeader && (\r\n <thead>\r\n <tr>\r\n {visibleColumns.map(col => (\r\n <th\r\n key={col.key}\r\n style={{\r\n padding: cellPadding,\r\n textAlign: col.align || 'left',\r\n fontSize: tokens.typography.fontSize.xxs,\r\n fontWeight: tokens.typography.fontWeight.bold,\r\n color: tokens.colors.text.tertiary,\r\n textTransform: 'uppercase',\r\n letterSpacing: '0.06em',\r\n backgroundColor: tokens.colors.background.surface,\r\n borderBottom: tokens.borders.divider,\r\n width: resolveWidth(col.width),\r\n position: 'sticky',\r\n top: 0,\r\n zIndex: 1,\r\n whiteSpace: 'nowrap',\r\n }}\r\n >\r\n {renderHeaderCell(col)}\r\n </th>\r\n ))}\r\n </tr>\r\n </thead>\r\n )}\r\n \r\n <tbody>\r\n {data.length === 0 && (\r\n <tr>\r\n <td\r\n colSpan={visibleColumnCount}\r\n style={{\r\n padding: tokens.spacing.xl,\r\n textAlign: 'center',\r\n color: tokens.colors.text.tertiary,\r\n fontSize: tokens.typography.fontSize.sm,\r\n }}\r\n >\r\n {emptyMessage}\r\n </td>\r\n </tr>\r\n )}\r\n \r\n {groups.map(group => {\r\n const isExpanded = !groupBy || isGroupExpanded(group.key);\r\n \r\n return (\r\n <React.Fragment key={group.key}>\r\n {groupBy && group.label && (\r\n <tr\r\n style={{\r\n backgroundColor: addAlpha(tokens.colors.accent.primary, 0.08),\r\n }}\r\n >\r\n <td\r\n colSpan={visibleColumnCount}\r\n style={{\r\n padding: 0,\r\n borderBottom: tokens.borders.divider,\r\n }}\r\n >\r\n {expandable ? (\r\n <button\r\n type=\"button\"\r\n aria-expanded={isExpanded}\r\n onClick={() => toggleGroup(group.key)}\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: tokens.spacing.xs,\r\n width: '100%',\r\n padding: cellPadding,\r\n margin: 0,\r\n border: 'none',\r\n background: 'none',\r\n cursor: 'pointer',\r\n fontWeight: tokens.typography.fontWeight.semibold,\r\n color: tokens.colors.text.primary,\r\n fontSize: compact ? tokens.typography.fontSize.xs : tokens.typography.fontSize.sm,\r\n fontFamily: 'inherit',\r\n textAlign: 'left',\r\n }}\r\n >\r\n {chevron(isExpanded)}\r\n {group.label}\r\n <span style={{\r\n fontSize: tokens.typography.fontSize.xxs,\r\n color: tokens.colors.text.tertiary,\r\n fontWeight: tokens.typography.fontWeight.normal,\r\n }}>\r\n ({group.rows.length})\r\n </span>\r\n </button>\r\n ) : (\r\n <div\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: tokens.spacing.xs,\r\n padding: cellPadding,\r\n fontWeight: tokens.typography.fontWeight.semibold,\r\n color: tokens.colors.text.primary,\r\n fontSize: compact ? tokens.typography.fontSize.xs : tokens.typography.fontSize.sm,\r\n }}\r\n >\r\n {group.label}\r\n <span style={{\r\n fontSize: tokens.typography.fontSize.xxs,\r\n color: tokens.colors.text.tertiary,\r\n fontWeight: tokens.typography.fontWeight.normal,\r\n }}>\r\n ({group.rows.length})\r\n </span>\r\n </div>\r\n )}\r\n </td>\r\n </tr>\r\n )}\r\n \r\n {isExpanded && group.rows.map((row, localIndex) => {\r\n const rowIdx = globalRowIndex++;\r\n return renderRowContent(row, rowIdx, localIndex);\r\n })}\r\n </React.Fragment>\r\n );\r\n })}\r\n </tbody>\r\n </table>\r\n </div>\r\n );\r\n}) as <T extends Record<string, unknown>>(props: DataTableProps<T>) => React.ReactElement;\r\n\r\nexport default DataTable;\r\n"],"names":["DataTableRowDetail","CellTooltipWrapper","DataTable"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { AstroIconName } from '
|
|
2
|
+
import { AstroIconName } from '../display/AstroIcon';
|
|
3
3
|
import { PropertyKey, StatusThresholds } from './propertyConfig';
|
|
4
|
-
import { StatusLevel } from '
|
|
4
|
+
import { StatusLevel } from '../../utils';
|
|
5
5
|
|
|
6
6
|
export type DataValueVariant = 'stacked' | 'inline' | 'compact' | 'minimal' | 'card' | 'banner';
|
|
7
7
|
export type DataValueSize = 'sm' | 'md' | 'lg';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { memo, useMemo } from "react";
|
|
3
|
-
import { AstroIcon } from "
|
|
3
|
+
import { AstroIcon } from "../display/AstroIcon.js";
|
|
4
4
|
import { getPropertyConfig, deriveStatus, formatPropertyValue } from "./propertyConfig.js";
|
|
5
|
-
import { useTheme } from "
|
|
5
|
+
import { useTheme } from "../../theme/ThemeProvider.js";
|
|
6
6
|
const STATUS_BORDER_COLORS = {
|
|
7
7
|
off: "#3c3e42",
|
|
8
8
|
standby: "#285766",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataValue.js","sources":["../../../../src/react/core/data/DataValue.tsx"],"sourcesContent":["/**\n * @zendir/ui - DataValue Component\n * \n * Enterprise-grade data value display with icon, label, value, and status.\n * The building block for telemetry displays, dashboards, and monitoring UIs.\n * \n * AstroUXDS Compliance:\n * - Status colors per AstroUXDS status system\n * - Dual-coding (color + shape) for accessibility via StatusIndicator\n * - Tabular numbers for alignment\n * - Sentence-case labels\n * \n * Features:\n * - Auto-derive status from value + thresholds\n * - Contextual icons from property presets\n * - Multiple layout variants (stacked, inline, compact)\n * - Theme-aware styling\n * \n * @example\n * ```tsx\n * import { DataValue } from '@zendir/ui';\n * \n * // Simple usage with property preset\n * <DataValue property=\"temperature\" value={72.5} />\n * \n * // Custom configuration\n * <DataValue \n * label=\"Battery\"\n * value={85}\n * unit=\"%\"\n * icon=\"battery-full\"\n * thresholds={{ critical: 10, caution: 30 }}\n * />\n * \n * // Inline layout\n * <DataValue property=\"voltage\" value={28.4} variant=\"inline\" />\n * ```\n */\n\nimport React, { memo, useMemo } from 'react';\nimport { useTheme } from '../../theme';\nimport { AstroIcon, type AstroIconName } from '../display/AstroIcon';\nimport { \n getPropertyConfig, \n deriveStatus, \n formatPropertyValue,\n type PropertyKey,\n type StatusThresholds,\n type PropertyConfig,\n} from './propertyConfig';\nimport type { StatusLevel } from '../../utils';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type DataValueVariant = 'stacked' | 'inline' | 'compact' | 'minimal' | 'card' | 'banner';\nexport type DataValueSize = 'sm' | 'md' | 'lg';\n\nexport interface DataValueProps {\n /** Property key for auto-configuration (e.g., 'temperature', 'battery') */\n property?: PropertyKey;\n /** Display label (overrides property preset) */\n label?: string;\n /** Current value */\n value: number | string | undefined | null;\n /** Unit of measurement (overrides property preset) */\n unit?: string;\n /** Icon name (overrides property preset) */\n icon?: AstroIconName;\n /** Show icon */\n showIcon?: boolean;\n /** Status thresholds for auto-derivation (overrides property preset) */\n thresholds?: StatusThresholds;\n /** Override status (bypasses auto-derivation) */\n status?: StatusLevel;\n /** Show status indicator */\n showStatus?: boolean;\n /** Precision for number formatting (overrides property preset) */\n precision?: number;\n /** Layout variant */\n variant?: DataValueVariant;\n /** Size */\n size?: DataValueSize;\n /** Custom value color (overrides status color) */\n color?: string;\n /** Additional CSS class */\n className?: string;\n /** Custom inline styles */\n style?: React.CSSProperties;\n /** Click handler */\n onClick?: () => void;\n /** Tooltip text */\n tooltip?: string;\n}\n\n// =============================================================================\n// Astro UX Status Border Colors - Required for light theme WCAG compliance\n// https://www.astrouxds.com/patterns/status-system/\n// =============================================================================\n\nconst STATUS_BORDER_COLORS: Record<StatusLevel, string> = {\n off: '#3c3e42',\n standby: '#285766',\n normal: '#005a00',\n caution: '#645600',\n serious: '#664618',\n critical: '#661102',\n};\n\n// =============================================================================\n// Status Shape SVG - Matches MonitoringIcon exactly\n// - Glow effect in dark mode for visibility\n// - Border in light mode for WCAG AA compliance\n// =============================================================================\n\ninterface StatusShapeProps {\n status: StatusLevel;\n size: number;\n color: string;\n borderColor?: string;\n glow?: boolean;\n}\n\nconst StatusShape = ({ status, size, color, borderColor, glow = true }: StatusShapeProps) => {\n const hasBorder = !!borderColor;\n const strokeWidth = hasBorder ? 1 : 0;\n const glowFilter = glow && !hasBorder ? `drop-shadow(0 0 3px ${color})` : undefined;\n \n const renderShape = () => {\n switch (status) {\n case 'off':\n return <circle cx=\"6\" cy=\"6\" r={hasBorder ? 2.5 : 3} fill={color} stroke={borderColor} strokeWidth={strokeWidth} />;\n case 'standby':\n return <circle cx=\"6\" cy=\"6\" r=\"3.5\" fill=\"none\" stroke={color} strokeWidth=\"2\" />;\n case 'normal':\n return (\n <circle\n cx=\"6\"\n cy=\"6\"\n r={hasBorder ? 4.5 : 5}\n fill={color}\n stroke={borderColor}\n strokeWidth={strokeWidth}\n />\n );\n case 'caution':\n return (\n <rect\n x={hasBorder ? 1.5 : 1}\n y={hasBorder ? 1.5 : 1}\n width={hasBorder ? 9 : 10}\n height={hasBorder ? 9 : 10}\n fill={color}\n stroke={borderColor}\n strokeWidth={strokeWidth}\n />\n );\n case 'serious':\n return (\n <polygon\n points=\"6,1 11,6 6,11 1,6\"\n fill={color}\n stroke={borderColor}\n strokeWidth={strokeWidth}\n />\n );\n case 'critical':\n return (\n <polygon\n points=\"6,11 1,2 11,2\"\n fill={color}\n stroke={borderColor}\n strokeWidth={strokeWidth}\n />\n );\n default:\n return null;\n }\n };\n \n return (\n <svg \n viewBox=\"0 0 12 12\" \n width={size} \n height={size}\n style={{ filter: glowFilter }}\n >\n {renderShape()}\n </svg>\n );\n};\n\n// =============================================================================\n// Icon with Status Badge - Enterprise-grade alignment\n// \n// Design System Principles (Apple HIG / Google Material / AstroUXDS):\n// - 4px-based spacing grid for visual harmony\n// - Explicit container sizing prevents layout shift\n// - Status badge positioned at corner, not extending beyond container bounds\n// - Proportional badge sizing: ~35% of icon size for optimal visibility\n// =============================================================================\n\ninterface IconWithBadgeProps {\n icon: AstroIconName;\n iconSize: number;\n iconColor: string;\n showBadge: boolean;\n status: StatusLevel;\n statusColor: string;\n isLightTheme?: boolean;\n}\n\nconst IconWithBadge = memo(function IconWithBadge({ \n icon, iconSize, iconColor, showBadge, status, statusColor, isLightTheme = false \n}: IconWithBadgeProps) {\n // ═══════════════════════════════════════════════════════════════════════════\n // STATUS BADGE CONTROLS\n // ═══════════════════════════════════════════════════════════════════════════\n // BADGE SIZE: Percentage of icon size (0.25 = 25%)\n const badgeSizeRatio = 0.30;\n const badgeSize = Math.max(7, Math.min(14, Math.round(iconSize * badgeSizeRatio)));\n \n // BADGE POSITION: Offset from top-left corner (negative = away from icon)\n const badgeOffsetX = -2; // px (negative = left, positive = right)\n const badgeOffsetY = -2; // px (negative = up, positive = down)\n \n // ═══════════════════════════════════════════════════════════════════════════\n const borderColor = isLightTheme ? STATUS_BORDER_COLORS[status] : undefined;\n const containerSize = iconSize;\n \n return (\n <div style={{\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n width: containerSize,\n height: containerSize,\n }}>\n <AstroIcon name={icon} size={iconSize} color={iconColor} />\n {showBadge && (\n <span style={{\n position: 'absolute',\n top: badgeOffsetY,\n left: badgeOffsetX,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}>\n <StatusShape \n status={status} \n size={badgeSize} \n color={statusColor} \n borderColor={borderColor}\n glow={!isLightTheme} \n />\n </span>\n )}\n </div>\n );\n});\n\n// =============================================================================\n// DataValue Component\n// =============================================================================\n\nexport const DataValue = memo(function DataValue({\n property,\n label: labelProp,\n value,\n unit: unitProp,\n icon: iconProp,\n showIcon = true,\n thresholds: thresholdsProp,\n status: statusProp,\n showStatus = true,\n precision: precisionProp,\n variant = 'stacked',\n size = 'md',\n color: colorProp,\n className = '',\n style,\n onClick,\n tooltip,\n}: DataValueProps): React.ReactElement {\n const { tokens, mode } = useTheme();\n const isLightTheme = mode === 'light';\n\n // Merge property preset with explicit props\n const config = useMemo((): PropertyConfig => {\n const preset = property ? getPropertyConfig(property) : {\n label: labelProp || 'Value',\n icon: iconProp || 'info',\n unit: unitProp,\n precision: precisionProp,\n thresholds: thresholdsProp,\n };\n\n return {\n ...preset,\n ...(labelProp !== undefined && { label: labelProp }),\n ...(iconProp !== undefined && { icon: iconProp }),\n ...(unitProp !== undefined && { unit: unitProp }),\n ...(precisionProp !== undefined && { precision: precisionProp }),\n ...(thresholdsProp !== undefined && { thresholds: thresholdsProp }),\n };\n }, [property, labelProp, iconProp, unitProp, precisionProp, thresholdsProp]);\n\n // Derive or use explicit status\n const status = useMemo((): StatusLevel => {\n if (statusProp) return statusProp;\n if (typeof value === 'number') {\n return deriveStatus(value, config.thresholds);\n }\n return 'normal';\n }, [statusProp, value, config.thresholds]);\n\n // Format the value\n const formattedValue = useMemo((): string => {\n if (value === undefined || value === null) return '--';\n if (typeof value === 'string') return value;\n return formatPropertyValue(value, config);\n }, [value, config]);\n\n // Get status color\n const statusColor = tokens.colors.status[status] || tokens.colors.status.off;\n const valueColor = colorProp || (showStatus && status !== 'normal' ? statusColor : tokens.colors.text.primary);\n\n // ==========================================================================\n // Size Configuration - Uses theme tokens for consistency with other cards\n // ==========================================================================\n // Typography uses theme tokens to match SpacecraftCard's DataCell\n // fontSize.xs = 10px (0.625rem), fontSize.sm = 12px (0.75rem)\n const sizeConfig = {\n sm: { \n iconSize: 16, \n labelSize: tokens.typography.fontSize.xs, // 10px - matches DataCell\n valueSize: tokens.typography.fontSize.sm, // 12px - matches DataCell\n lineHeight: 1.4,\n gap: 6, // Increased from 4px to 6px for better icon separation with larger icons\n rowGap: 2, // 2px between label and value\n },\n md: { \n iconSize: 20, \n labelSize: tokens.typography.fontSize.xs, // 10px\n valueSize: tokens.typography.fontSize.base, // 14px\n lineHeight: 1.4,\n gap: 10, // Increased from 8px to 10px\n rowGap: 2, // 2px between label and value\n },\n lg: { \n iconSize: 24, \n labelSize: tokens.typography.fontSize.sm, // 12px\n valueSize: tokens.typography.fontSize.md, // 14px\n lineHeight: 1.4,\n gap: 14, // Increased from 12px to 14px\n rowGap: 4, // 4px between label and value\n },\n }[size];\n\n // ==========================================================================\n // Render Based on Variant\n // \n // Layout principles:\n // - Baseline alignment for inline text\n // - Consistent icon-to-text spacing\n // - Symmetrical padding\n // - Tabular numbers for value alignment in grids\n // ==========================================================================\n const renderContent = () => {\n // Determine if status indicator should show\n const hasStatus = showStatus && status !== 'normal' && status !== 'off';\n \n switch (variant) {\n // ======================================================================\n // INLINE: Icon + Label ... Value (space-between)\n // Best for: Key-value pairs in tables or lists\n // ======================================================================\n case 'inline': {\n return (\n <div style={{ \n display: 'flex', \n alignItems: 'center', \n justifyContent: 'space-between', \n gap: sizeConfig.gap * 2,\n minHeight: sizeConfig.iconSize, // Ensure consistent row height\n }}>\n <div style={{ \n display: 'flex', \n alignItems: 'center', \n gap: sizeConfig.gap,\n }}>\n {showIcon && config.icon && (\n <IconWithBadge\n icon={config.icon}\n iconSize={sizeConfig.iconSize}\n iconColor={hasStatus ? statusColor : tokens.colors.text.tertiary}\n showBadge={hasStatus}\n status={status}\n statusColor={statusColor}\n isLightTheme={isLightTheme}\n />\n )}\n <span style={{\n fontSize: sizeConfig.labelSize,\n lineHeight: sizeConfig.lineHeight,\n color: tokens.colors.text.secondary,\n fontWeight: 500,\n fontFamily: tokens.typography.fontFamily.primary,\n }}>\n {config.label}\n </span>\n </div>\n <span style={{\n fontSize: sizeConfig.valueSize,\n lineHeight: sizeConfig.lineHeight,\n fontWeight: 500, // Match SpacecraftCard DataCell\n fontFamily: tokens.typography.fontFamily.mono,\n fontVariantNumeric: 'tabular-nums',\n color: valueColor,\n }}>\n {formattedValue}\n </span>\n </div>\n );\n }\n\n // ======================================================================\n // COMPACT: Icon + Value (horizontal, no label)\n // Best for: Dense displays, status bars, compact dashboards\n // ======================================================================\n case 'compact': {\n return (\n <div style={{ \n display: 'flex', \n alignItems: 'center', \n gap: sizeConfig.gap,\n minHeight: sizeConfig.iconSize,\n }}>\n {showIcon && config.icon && (\n <IconWithBadge\n icon={config.icon}\n iconSize={sizeConfig.iconSize}\n iconColor={hasStatus ? statusColor : tokens.colors.text.tertiary}\n showBadge={hasStatus}\n status={status}\n statusColor={statusColor}\n isLightTheme={isLightTheme}\n />\n )}\n <span style={{\n fontSize: sizeConfig.valueSize,\n lineHeight: sizeConfig.lineHeight,\n fontWeight: 500, // Match SpacecraftCard DataCell\n fontFamily: tokens.typography.fontFamily.mono,\n fontVariantNumeric: 'tabular-nums',\n color: valueColor,\n }}>\n {formattedValue}\n </span>\n </div>\n );\n }\n\n // ======================================================================\n // MINIMAL: Value only (no icon, no label)\n // Best for: Inline values, table cells\n // ======================================================================\n case 'minimal':\n return (\n <span style={{\n fontSize: sizeConfig.valueSize,\n lineHeight: sizeConfig.lineHeight,\n fontWeight: 500, // Match SpacecraftCard DataCell\n fontFamily: tokens.typography.fontFamily.mono,\n fontVariantNumeric: 'tabular-nums',\n color: valueColor,\n }}>\n {formattedValue}\n </span>\n );\n\n // ======================================================================\n // CARD: Icon EXACTLY matches 2-row text height\n // Best for: Dashboard tiles, prominent metrics\n // ======================================================================\n case 'card': {\n // ═══════════════════════════════════════════════════════════════════════════\n // 2-ROW LAYOUT CONTROLS (card variant)\n // ═══════════════════════════════════════════════════════════════════════════\n // ICON MULTIPLIER: Scale factor (0.5 = half, 1.0 = match text height, 1.5 = 150%)\n const iconMultiplier = 0.7;\n \n // GAP: Pixels between icon and text column\n const iconToTextGap = 4; // px\n \n // ═══════════════════════════════════════════════════════════════════════════\n const baseSize = { sm: 26, md: 32, lg: 40 }[size];\n const iconSize = Math.round(baseSize * iconMultiplier);\n \n return (\n <div style={{ \n display: 'flex', \n alignItems: 'center',\n gap: iconToTextGap,\n }}>\n {showIcon && config.icon && (\n <IconWithBadge\n icon={config.icon}\n iconSize={iconSize}\n iconColor={hasStatus ? statusColor : tokens.colors.text.tertiary}\n showBadge={hasStatus}\n status={status}\n statusColor={statusColor}\n isLightTheme={isLightTheme}\n />\n )}\n <div style={{ \n display: 'flex', \n flexDirection: 'column', \n justifyContent: 'space-between', // Distribute label/value to edges\n gap: sizeConfig.rowGap, \n minWidth: 0,\n }}>\n <span style={{\n fontSize: sizeConfig.labelSize,\n lineHeight: sizeConfig.lineHeight,\n color: tokens.colors.text.secondary,\n fontWeight: 500,\n fontFamily: tokens.typography.fontFamily.primary,\n }}>\n {config.label}\n </span>\n <span style={{\n fontSize: sizeConfig.valueSize,\n lineHeight: sizeConfig.lineHeight,\n fontWeight: 500, // Match SpacecraftCard DataCell\n fontFamily: tokens.typography.fontFamily.mono,\n fontVariantNumeric: 'tabular-nums',\n color: valueColor,\n }}>\n {formattedValue}\n </span>\n </div>\n </div>\n );\n }\n\n // ======================================================================\n // BANNER: Label on top, icon left-aligned + value right-aligned below\n // Best for: TopBar metrics, KPI tiles where heading spans full width\n // ======================================================================\n case 'banner': {\n const bannerIconSize = { sm: 18, md: 22, lg: 28 }[size];\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: sizeConfig.rowGap, minWidth: 0, width: '100%' }}>\n <span style={{\n fontSize: sizeConfig.labelSize,\n lineHeight: sizeConfig.lineHeight,\n color: tokens.colors.text.secondary,\n fontWeight: 500,\n fontFamily: tokens.typography.fontFamily.primary,\n textTransform: 'uppercase' as const,\n letterSpacing: '0.5px',\n }}>\n {config.label}\n </span>\n <div style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'flex-start',\n width: '100%',\n gap: 6,\n minWidth: 0,\n }}>\n {showIcon && config.icon && (\n <IconWithBadge\n icon={config.icon}\n iconSize={bannerIconSize}\n iconColor={hasStatus ? statusColor : tokens.colors.text.tertiary}\n showBadge={hasStatus}\n status={status}\n statusColor={statusColor}\n isLightTheme={isLightTheme}\n />\n )}\n <span style={{\n fontSize: sizeConfig.valueSize,\n lineHeight: sizeConfig.lineHeight,\n fontWeight: 600,\n fontFamily: tokens.typography.fontFamily.mono,\n fontVariantNumeric: 'tabular-nums',\n color: valueColor,\n textAlign: 'left',\n }}>\n {formattedValue}\n </span>\n </div>\n </div>\n );\n }\n\n // ======================================================================\n // STACKED (default): Icon EXACTLY matches 2-row text height\n // Best for: General telemetry displays, standard data values\n // ======================================================================\n case 'stacked':\n default: {\n // ═══════════════════════════════════════════════════════════════════════════\n // 2-ROW LAYOUT CONTROLS (stacked variant)\n // ═══════════════════════════════════════════════════════════════════════════\n // ICON MULTIPLIER: Scale factor (0.5 = half, 1.0 = match text height, 1.5 = 150%)\n const iconMultiplier = 0.7;\n \n // GAP: Pixels between icon and text column\n const iconToTextGap = 4; // px\n \n // ═══════════════════════════════════════════════════════════════════════════\n const baseSize = { sm: 26, md: 32, lg: 40 }[size];\n const iconSize = Math.round(baseSize * iconMultiplier);\n \n return (\n <div style={{ \n display: 'flex', \n alignItems: 'center',\n gap: iconToTextGap,\n }}>\n {showIcon && config.icon && (\n <IconWithBadge\n icon={config.icon}\n iconSize={iconSize}\n iconColor={hasStatus ? statusColor : tokens.colors.text.tertiary}\n showBadge={hasStatus}\n status={status}\n statusColor={statusColor}\n isLightTheme={isLightTheme}\n />\n )}\n <div style={{ \n display: 'flex', \n flexDirection: 'column', \n justifyContent: 'space-between', // Distribute label/value to edges\n gap: sizeConfig.rowGap, \n minWidth: 0,\n }}>\n <span style={{\n fontSize: sizeConfig.labelSize,\n lineHeight: sizeConfig.lineHeight,\n color: tokens.colors.text.secondary,\n fontWeight: 500,\n fontFamily: tokens.typography.fontFamily.primary,\n }}>\n {config.label}\n </span>\n <span style={{\n fontSize: sizeConfig.valueSize,\n lineHeight: sizeConfig.lineHeight,\n fontWeight: 500, // Match SpacecraftCard DataCell\n fontFamily: tokens.typography.fontFamily.mono,\n fontVariantNumeric: 'tabular-nums',\n color: valueColor,\n }}>\n {formattedValue}\n </span>\n </div>\n </div>\n );\n }\n }\n };\n\n return (\n <div\n className={`zendir-data-value zendir-data-value--${variant} zendir-data-value--${size} ${className}`}\n style={{\n cursor: onClick ? 'pointer' : 'default',\n ...(variant === 'banner' ? { flex: 1, minWidth: 0 } : {}),\n ...style,\n }}\n onClick={onClick}\n title={tooltip || config.description}\n role={onClick ? 'button' : undefined}\n tabIndex={onClick ? 0 : undefined}\n onKeyDown={onClick ? (e) => e.key === 'Enter' && onClick() : undefined}\n >\n {renderContent()}\n </div>\n );\n});\n\n// =============================================================================\n// DataValueGroup Component\n// =============================================================================\n\nexport interface DataValueGroupProps {\n /** Title for the group */\n title?: string;\n /** Icon for the title */\n icon?: AstroIconName;\n /** Layout direction */\n direction?: 'row' | 'column' | 'grid';\n /** Number of columns for grid layout */\n columns?: number;\n /** Gap between items */\n gap?: 'sm' | 'md' | 'lg';\n /** Children DataValue components */\n children: React.ReactNode;\n /** Additional CSS class */\n className?: string;\n /** Custom inline styles */\n style?: React.CSSProperties;\n}\n\nexport const DataValueGroup = memo(function DataValueGroup({\n title,\n icon,\n direction = 'grid',\n columns = 2,\n gap = 'md',\n children,\n className = '',\n style,\n}: DataValueGroupProps): React.ReactElement {\n const { tokens } = useTheme();\n\n // Gap sizing on 4px grid\n const gapSize = {\n sm: 8, // 2 × 4px\n md: 16, // 4 × 4px\n lg: 24, // 6 × 4px\n }[gap];\n\n const layoutStyles: Record<typeof direction, React.CSSProperties> = {\n row: { \n display: 'flex', \n flexDirection: 'row' as const, \n flexWrap: 'wrap' as const, \n gap: gapSize,\n alignItems: 'flex-start',\n },\n column: { \n display: 'flex', \n flexDirection: 'column' as const, \n gap: gapSize,\n },\n grid: { \n display: 'grid', \n gridTemplateColumns: `repeat(${columns}, 1fr)`, \n gap: gapSize,\n alignItems: 'start',\n },\n };\n const layoutStyle = layoutStyles[direction];\n\n return (\n <div className={`zendir-data-value-group ${className}`} style={style}>\n {title && (\n <div style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6, // 6px gap for tight header\n marginBottom: 12, // 3 × 4px\n paddingBottom: 8, // 2 × 4px\n borderBottom: `1px solid ${tokens.colors.border.muted}`,\n }}>\n {icon && (\n <AstroIcon \n name={icon} \n size={14} \n color={tokens.colors.text.tertiary}\n style={{ flexShrink: 0 }}\n />\n )}\n <span style={{\n fontSize: '12px',\n fontWeight: 500,\n color: tokens.colors.text.secondary,\n textTransform: 'uppercase',\n letterSpacing: '0.5px',\n }}>\n {title}\n </span>\n </div>\n )}\n <div style={layoutStyle}>\n {children}\n </div>\n </div>\n );\n});\n\nexport default DataValue;\n"],"names":["IconWithBadge","DataValue","DataValueGroup"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propertyConfig.js","sources":["../../../../src/react/core/data/propertyConfig.ts"],"sourcesContent":["/**\n * @zendir/ui - Property Configuration System\n * \n * Enterprise-grade property-to-icon/status/unit mapping system.\n * Provides automatic icon, status, and formatting for common telemetry properties.\n * \n * AstroUXDS Compliance:\n * - Uses official Astro icon names\n * - Status colors per AstroUXDS status system\n * - Dual-coding (color + shape) for accessibility\n * \n * Features:\n * - Auto-derive status from value + thresholds\n * - Contextual icons for space operations properties\n * - Unit formatting with SI prefixes\n * - Extensible configuration\n * \n * @example\n * ```tsx\n * import { getPropertyConfig, deriveStatus, PROPERTY_PRESETS } from '@zendir/ui';\n * \n * // Get config for a known property\n * const tempConfig = getPropertyConfig('temperature');\n * // { icon: 'thermal', unit: '°C', thresholds: { caution: 60, critical: 80 }, ... }\n * \n * // Derive status from value\n * const status = deriveStatus(75, tempConfig.thresholds);\n * // 'caution'\n * ```\n */\n\nimport type { StatusLevel } from '../../utils';\nimport type { AstroIconName } from '../display/AstroIcon';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Threshold configuration for automatic status derivation\n * Values are compared: value >= threshold triggers that status (high thresholds)\n * or value <= threshold triggers that status (low thresholds)\n */\nexport interface StatusThresholds {\n /** Value at or above which status becomes 'critical' (high is bad) */\n critical?: number;\n /** Value at or above which status becomes 'serious' (high is bad) */\n serious?: number;\n /** Value at or above which status becomes 'caution' (high is bad) */\n caution?: number;\n /** Value at or below which status becomes 'caution' (low is bad) */\n cautionLow?: number;\n /** Value at or below which status becomes 'serious' (low is bad) */\n seriousLow?: number;\n /** Value at or below which status becomes 'critical' (low is bad) */\n criticalLow?: number;\n}\n\n/**\n * Complete property configuration\n */\nexport interface PropertyConfig {\n /** Display name (sentence case per AstroUXDS) */\n label: string;\n /** Astro icon name */\n icon: AstroIconName;\n /** Unit of measurement */\n unit?: string;\n /** Precision for number formatting */\n precision?: number;\n /** Status thresholds for auto-derivation */\n thresholds?: StatusThresholds;\n /** Category for grouping */\n category?: PropertyCategory;\n /** Description for tooltips */\n description?: string;\n /** Format function override */\n format?: (value: number) => string;\n}\n\n/**\n * Property categories for organization\n */\nexport type PropertyCategory = \n | 'power'\n | 'thermal'\n | 'attitude'\n | 'communications'\n | 'propulsion'\n | 'navigation'\n | 'payload'\n | 'health'\n | 'orbital'\n | 'general';\n\n/**\n * Property key - either a preset name or custom string\n */\nexport type PropertyKey = keyof typeof PROPERTY_PRESETS | (string & {});\n\n// =============================================================================\n// Property Presets\n// =============================================================================\n\n/**\n * Predefined property configurations for common space operations telemetry\n * \n * These provide sensible defaults that can be overridden per-use.\n */\nexport const PROPERTY_PRESETS = {\n // === Power System ===\n battery: {\n label: 'Battery',\n icon: 'battery-full' as AstroIconName,\n unit: '%',\n precision: 1,\n category: 'power' as PropertyCategory,\n // Low values are bad for battery (use *Low thresholds)\n thresholds: { criticalLow: 10, seriousLow: 20, cautionLow: 30 },\n description: 'Battery state of charge',\n },\n voltage: {\n label: 'Voltage',\n icon: 'propulsion-power' as AstroIconName,\n unit: 'V',\n precision: 2,\n category: 'power' as PropertyCategory,\n thresholds: { criticalLow: 24, cautionLow: 26 },\n description: 'Bus voltage',\n },\n current: {\n label: 'Current',\n icon: 'propulsion-power' as AstroIconName,\n unit: 'A',\n precision: 2,\n category: 'power' as PropertyCategory,\n description: 'Current draw',\n },\n power: {\n label: 'Power',\n icon: 'propulsion-power' as AstroIconName,\n unit: 'W',\n precision: 1,\n category: 'power' as PropertyCategory,\n description: 'Power consumption or generation',\n },\n solarPower: {\n label: 'Solar',\n icon: 'solar' as AstroIconName,\n unit: 'W',\n precision: 1,\n category: 'power' as PropertyCategory,\n description: 'Solar array output',\n },\n load: {\n label: 'Load',\n icon: 'propulsion-power' as AstroIconName,\n unit: 'W',\n precision: 1,\n category: 'power' as PropertyCategory,\n description: 'Power load',\n },\n\n // === Thermal ===\n temperature: {\n label: 'Temperature',\n icon: 'thermal' as AstroIconName,\n unit: '°C',\n precision: 1,\n category: 'thermal' as PropertyCategory,\n thresholds: { critical: 80, serious: 70, caution: 60, cautionLow: -20, criticalLow: -40 },\n description: 'Component temperature',\n },\n heater: {\n label: 'Heater',\n icon: 'thermal' as AstroIconName,\n unit: '',\n category: 'thermal' as PropertyCategory,\n description: 'Heater status',\n },\n\n // === Attitude ===\n roll: {\n label: 'Roll',\n icon: 'explore' as AstroIconName,\n unit: '°',\n precision: 2,\n category: 'attitude' as PropertyCategory,\n thresholds: { critical: 45, caution: 30 },\n description: 'Roll angle',\n },\n pitch: {\n label: 'Pitch',\n icon: 'explore' as AstroIconName,\n unit: '°',\n precision: 2,\n category: 'attitude' as PropertyCategory,\n thresholds: { critical: 45, caution: 30 },\n description: 'Pitch angle',\n },\n yaw: {\n label: 'Yaw',\n icon: 'explore' as AstroIconName,\n unit: '°',\n precision: 2,\n category: 'attitude' as PropertyCategory,\n thresholds: { critical: 45, caution: 30 },\n description: 'Yaw angle',\n },\n pointingError: {\n label: 'Pointing error',\n icon: 'explore' as AstroIconName,\n unit: '°',\n precision: 3,\n category: 'attitude' as PropertyCategory,\n thresholds: { critical: 1.0, serious: 0.5, caution: 0.1 },\n description: 'Attitude pointing error',\n },\n angularVelocity: {\n label: 'Angular velocity',\n icon: 'explore' as AstroIconName,\n unit: '°/s',\n precision: 3,\n category: 'attitude' as PropertyCategory,\n thresholds: { critical: 5.0, caution: 2.0 },\n description: 'Rotation rate',\n },\n\n // === Communications ===\n signalStrength: {\n label: 'Signal',\n icon: 'antenna-receive' as AstroIconName,\n unit: 'dBm',\n precision: 1,\n category: 'communications' as PropertyCategory,\n thresholds: { criticalLow: -100, cautionLow: -85 },\n description: 'Received signal strength',\n },\n dataRate: {\n label: 'Data rate',\n icon: 'antenna-transmit' as AstroIconName,\n unit: 'Mbps',\n precision: 2,\n category: 'communications' as PropertyCategory,\n description: 'Communication data rate',\n },\n packetLoss: {\n label: 'Packet loss',\n icon: 'netcom' as AstroIconName,\n unit: '%',\n precision: 2,\n category: 'communications' as PropertyCategory,\n thresholds: { critical: 10, serious: 5, caution: 1 },\n description: 'Communication packet loss rate',\n },\n snr: {\n label: 'SNR',\n icon: 'antenna' as AstroIconName,\n unit: 'dB',\n precision: 1,\n category: 'communications' as PropertyCategory,\n thresholds: { criticalLow: 5, cautionLow: 10 },\n description: 'Signal-to-noise ratio',\n },\n queue: {\n label: 'Queue',\n icon: 'netcom' as AstroIconName,\n unit: 'pkts',\n precision: 0,\n category: 'communications' as PropertyCategory,\n thresholds: { critical: 1000, caution: 500 },\n description: 'Packet queue depth',\n },\n\n // === Propulsion ===\n fuelLevel: {\n label: 'Fuel',\n icon: 'propulsion-power' as AstroIconName,\n unit: '%',\n precision: 1,\n category: 'propulsion' as PropertyCategory,\n thresholds: { critical: 5, serious: 10, caution: 20 },\n description: 'Propellant remaining',\n },\n deltaV: {\n label: 'Delta-V',\n icon: 'propulsion-power' as AstroIconName,\n unit: 'm/s',\n precision: 1,\n category: 'propulsion' as PropertyCategory,\n description: 'Available delta-V budget',\n },\n thrustLevel: {\n label: 'Thrust',\n icon: 'propulsion-power' as AstroIconName,\n unit: 'N',\n precision: 2,\n category: 'propulsion' as PropertyCategory,\n description: 'Current thrust output',\n },\n\n // === Navigation ===\n altitude: {\n label: 'Altitude',\n icon: 'altitude' as AstroIconName,\n unit: 'km',\n precision: 1,\n category: 'orbital' as PropertyCategory,\n thresholds: { criticalLow: 200, cautionLow: 250 },\n description: 'Orbital altitude',\n },\n velocity: {\n label: 'Velocity',\n icon: 'altitude' as AstroIconName,\n unit: 'km/s',\n precision: 3,\n category: 'orbital' as PropertyCategory,\n description: 'Orbital velocity',\n },\n inclination: {\n label: 'Inclination',\n icon: 'altitude' as AstroIconName,\n unit: '°',\n precision: 2,\n category: 'orbital' as PropertyCategory,\n description: 'Orbital inclination',\n },\n eccentricity: {\n label: 'Eccentricity',\n icon: 'altitude' as AstroIconName,\n unit: '',\n precision: 6,\n category: 'orbital' as PropertyCategory,\n description: 'Orbital eccentricity',\n },\n\n // === Payload ===\n payloadStatus: {\n label: 'Payload',\n icon: 'payload' as AstroIconName,\n unit: '',\n category: 'payload' as PropertyCategory,\n description: 'Payload operational status',\n },\n storageUsed: {\n label: 'Storage',\n icon: 'hardware' as AstroIconName,\n unit: '%',\n precision: 1,\n category: 'payload' as PropertyCategory,\n thresholds: { critical: 95, serious: 90, caution: 80 },\n description: 'Onboard storage usage',\n },\n\n // === Health ===\n cpuUsage: {\n label: 'CPU',\n icon: 'processor' as AstroIconName,\n unit: '%',\n precision: 1,\n category: 'health' as PropertyCategory,\n thresholds: { critical: 95, serious: 85, caution: 75 },\n description: 'Processor utilization',\n },\n memoryUsage: {\n label: 'Memory',\n icon: 'processor' as AstroIconName,\n unit: '%',\n precision: 1,\n category: 'health' as PropertyCategory,\n thresholds: { critical: 95, serious: 85, caution: 75 },\n description: 'Memory utilization',\n },\n uptime: {\n label: 'Uptime',\n icon: 'mission' as AstroIconName,\n unit: 's',\n precision: 0,\n category: 'health' as PropertyCategory,\n description: 'System uptime',\n },\n\n // === General ===\n count: {\n label: 'Count',\n icon: 'list' as AstroIconName,\n unit: '',\n precision: 0,\n category: 'general' as PropertyCategory,\n description: 'Item count',\n },\n percentage: {\n label: 'Percentage',\n icon: 'info' as AstroIconName,\n unit: '%',\n precision: 1,\n category: 'general' as PropertyCategory,\n description: 'Percentage value',\n },\n duration: {\n label: 'Duration',\n icon: 'schedule' as AstroIconName,\n unit: 's',\n precision: 0,\n category: 'general' as PropertyCategory,\n description: 'Time duration',\n },\n} as const satisfies Record<string, PropertyConfig>;\n\n// =============================================================================\n// Category Icons (for section headers)\n// =============================================================================\n\nexport const CATEGORY_ICONS: Record<PropertyCategory, AstroIconName> = {\n power: 'propulsion-power',\n thermal: 'thermal',\n attitude: 'explore',\n communications: 'antenna',\n propulsion: 'propulsion-power',\n navigation: 'gps-fixed',\n payload: 'payload',\n health: 'favorite',\n orbital: 'altitude',\n general: 'info',\n};\n\nexport const CATEGORY_LABELS: Record<PropertyCategory, string> = {\n power: 'Power',\n thermal: 'Thermal',\n attitude: 'Attitude',\n communications: 'Communications',\n propulsion: 'Propulsion',\n navigation: 'Navigation',\n payload: 'Payload',\n health: 'Health',\n orbital: 'Orbital',\n general: 'General',\n};\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Get property configuration by key\n * Returns preset config or a default config for unknown properties\n */\nexport function getPropertyConfig(key: PropertyKey): PropertyConfig {\n const preset = PROPERTY_PRESETS[key as keyof typeof PROPERTY_PRESETS];\n if (preset) {\n return preset;\n }\n\n // Return default config for unknown properties\n return {\n label: formatPropertyLabel(key),\n icon: 'info',\n unit: '',\n precision: 2,\n category: 'general',\n description: key,\n };\n}\n\n/**\n * Format a property key into a display label (sentence case)\n */\nexport function formatPropertyLabel(key: string): string {\n // Handle camelCase → Sentence case\n const words = key\n .replace(/([A-Z])/g, ' $1')\n .replace(/[_-]/g, ' ')\n .trim()\n .toLowerCase();\n return words.charAt(0).toUpperCase() + words.slice(1);\n}\n\n/**\n * Derive status level from a value and thresholds\n * \n * @param value - Current value\n * @param thresholds - Status thresholds\n * @returns StatusLevel\n * \n * @example\n * ```tsx\n * deriveStatus(75, { caution: 60, critical: 80 }) // 'caution'\n * deriveStatus(25, { criticalLow: 10, cautionLow: 30 }) // 'caution'\n * deriveStatus(50, { caution: 60, critical: 80 }) // 'normal'\n * ```\n */\nexport function deriveStatus(\n value: number | undefined | null,\n thresholds?: StatusThresholds\n): StatusLevel {\n if (value === undefined || value === null || !Number.isFinite(value)) {\n return 'off';\n }\n\n if (!thresholds) {\n return 'normal';\n }\n\n // Check high thresholds (value >= threshold is bad)\n if (thresholds.critical !== undefined && value >= thresholds.critical) {\n return 'critical';\n }\n if (thresholds.serious !== undefined && value >= thresholds.serious) {\n return 'serious';\n }\n if (thresholds.caution !== undefined && value >= thresholds.caution) {\n return 'caution';\n }\n\n // Check low thresholds (value <= threshold is bad)\n if (thresholds.criticalLow !== undefined && value <= thresholds.criticalLow) {\n return 'critical';\n }\n if (thresholds.seriousLow !== undefined && value <= thresholds.seriousLow) {\n return 'serious';\n }\n if (thresholds.cautionLow !== undefined && value <= thresholds.cautionLow) {\n return 'caution';\n }\n\n return 'normal';\n}\n\n/**\n * Derive status for battery specifically (low is bad)\n */\nexport function deriveBatteryStatus(level: number | undefined): StatusLevel {\n if (level === undefined || level === null) return 'off';\n if (level <= 10) return 'critical';\n if (level <= 20) return 'serious';\n if (level <= 30) return 'caution';\n return 'normal';\n}\n\n/**\n * Format a value with its property config\n */\nexport function formatPropertyValue(\n value: number | undefined | null,\n config: PropertyConfig\n): string {\n if (value === undefined || value === null || !Number.isFinite(value)) {\n return '--';\n }\n\n if (config.format) {\n return config.format(value);\n }\n\n const precision = config.precision ?? 2;\n const formatted = value.toFixed(precision);\n const unit = config.unit ?? '';\n \n return unit ? `${formatted}${unit.startsWith('°') || unit.startsWith('%') ? '' : ' '}${unit}` : formatted;\n}\n\n/**\n * Create a custom property config by merging with a preset\n */\nexport function createPropertyConfig(\n baseKey: PropertyKey,\n overrides: Partial<PropertyConfig>\n): PropertyConfig {\n const base = getPropertyConfig(baseKey);\n return { ...base, ...overrides };\n}\n\n/**\n * Get all properties in a category\n */\nexport function getPropertiesByCategory(category: PropertyCategory): Array<{ key: string; config: PropertyConfig }> {\n return Object.entries(PROPERTY_PRESETS)\n .filter(([_, config]) => config.category === category)\n .map(([key, config]) => ({ key, config }));\n}\n"],"names":[],"mappings":"AA6GO,MAAM,mBAAmB;AAAA;AAAA,EAE9B,SAAS;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA;AAAA,IAEV,YAAY,EAAE,aAAa,IAAI,YAAY,IAAI,YAAY,GAAA;AAAA,IAC3D,aAAa;AAAA,EAAA;AAAA,EAEf,SAAS;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,aAAa,IAAI,YAAY,GAAA;AAAA,IAC3C,aAAa;AAAA,EAAA;AAAA,EAEf,SAAS;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA,EAEf,OAAO;AAAA,IACL,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA,EAEf,YAAY;AAAA,IACV,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA,EAEf,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA;AAAA,EAIf,aAAa;AAAA,IACX,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,UAAU,IAAI,SAAS,IAAI,SAAS,IAAI,YAAY,KAAK,aAAa,IAAA;AAAA,IACpF,aAAa;AAAA,EAAA;AAAA,EAEf,QAAQ;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA;AAAA,EAIf,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,UAAU,IAAI,SAAS,GAAA;AAAA,IACrC,aAAa;AAAA,EAAA;AAAA,EAEf,OAAO;AAAA,IACL,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,UAAU,IAAI,SAAS,GAAA;AAAA,IACrC,aAAa;AAAA,EAAA;AAAA,EAEf,KAAK;AAAA,IACH,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,UAAU,IAAI,SAAS,GAAA;AAAA,IACrC,aAAa;AAAA,EAAA;AAAA,EAEf,eAAe;AAAA,IACb,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,UAAU,GAAK,SAAS,KAAK,SAAS,IAAA;AAAA,IACpD,aAAa;AAAA,EAAA;AAAA,EAEf,iBAAiB;AAAA,IACf,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,UAAU,GAAK,SAAS,EAAA;AAAA,IACtC,aAAa;AAAA,EAAA;AAAA;AAAA,EAIf,gBAAgB;AAAA,IACd,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,aAAa,MAAM,YAAY,IAAA;AAAA,IAC7C,aAAa;AAAA,EAAA;AAAA,EAEf,UAAU;AAAA,IACR,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA,EAEf,YAAY;AAAA,IACV,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,UAAU,IAAI,SAAS,GAAG,SAAS,EAAA;AAAA,IACjD,aAAa;AAAA,EAAA;AAAA,EAEf,KAAK;AAAA,IACH,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,aAAa,GAAG,YAAY,GAAA;AAAA,IAC1C,aAAa;AAAA,EAAA;AAAA,EAEf,OAAO;AAAA,IACL,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,UAAU,KAAM,SAAS,IAAA;AAAA,IACvC,aAAa;AAAA,EAAA;AAAA;AAAA,EAIf,WAAW;AAAA,IACT,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,UAAU,GAAG,SAAS,IAAI,SAAS,GAAA;AAAA,IACjD,aAAa;AAAA,EAAA;AAAA,EAEf,QAAQ;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA,EAEf,aAAa;AAAA,IACX,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA;AAAA,EAIf,UAAU;AAAA,IACR,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,aAAa,KAAK,YAAY,IAAA;AAAA,IAC5C,aAAa;AAAA,EAAA;AAAA,EAEf,UAAU;AAAA,IACR,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA,EAEf,aAAa;AAAA,IACX,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA,EAEf,cAAc;AAAA,IACZ,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA;AAAA,EAIf,eAAe;AAAA,IACb,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA,EAEf,aAAa;AAAA,IACX,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,UAAU,IAAI,SAAS,IAAI,SAAS,GAAA;AAAA,IAClD,aAAa;AAAA,EAAA;AAAA;AAAA,EAIf,UAAU;AAAA,IACR,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,UAAU,IAAI,SAAS,IAAI,SAAS,GAAA;AAAA,IAClD,aAAa;AAAA,EAAA;AAAA,EAEf,aAAa;AAAA,IACX,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY,EAAE,UAAU,IAAI,SAAS,IAAI,SAAS,GAAA;AAAA,IAClD,aAAa;AAAA,EAAA;AAAA,EAEf,QAAQ;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA;AAAA,EAIf,OAAO;AAAA,IACL,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA,EAEf,YAAY;AAAA,IACV,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAAA,EAEf,UAAU;AAAA,IACR,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAEjB;AAMO,MAAM,iBAA0D;AAAA,EACrE,OAAO;AAAA,EACP,SAAS;AAAA,EACT,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AACX;AAEO,MAAM,kBAAoD;AAAA,EAC/D,OAAO;AAAA,EACP,SAAS;AAAA,EACT,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AACX;AAUO,SAAS,kBAAkB,KAAkC;AAClE,QAAM,SAAS,iBAAiB,GAAoC;AACpE,MAAI,QAAQ;AACV,WAAO;AAAA,EACT;AAGA,SAAO;AAAA,IACL,OAAO,oBAAoB,GAAG;AAAA,IAC9B,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,aAAa;AAAA,EAAA;AAEjB;AAKO,SAAS,oBAAoB,KAAqB;AAEvD,QAAM,QAAQ,IACX,QAAQ,YAAY,KAAK,EACzB,QAAQ,SAAS,GAAG,EACpB,KAAA,EACA,YAAA;AACH,SAAO,MAAM,OAAO,CAAC,EAAE,gBAAgB,MAAM,MAAM,CAAC;AACtD;AAgBO,SAAS,aACd,OACA,YACa;AACb,MAAI,UAAU,UAAa,UAAU,QAAQ,CAAC,OAAO,SAAS,KAAK,GAAG;AACpE,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAGA,MAAI,WAAW,aAAa,UAAa,SAAS,WAAW,UAAU;AACrE,WAAO;AAAA,EACT;AACA,MAAI,WAAW,YAAY,UAAa,SAAS,WAAW,SAAS;AACnE,WAAO;AAAA,EACT;AACA,MAAI,WAAW,YAAY,UAAa,SAAS,WAAW,SAAS;AACnE,WAAO;AAAA,EACT;AAGA,MAAI,WAAW,gBAAgB,UAAa,SAAS,WAAW,aAAa;AAC3E,WAAO;AAAA,EACT;AACA,MAAI,WAAW,eAAe,UAAa,SAAS,WAAW,YAAY;AACzE,WAAO;AAAA,EACT;AACA,MAAI,WAAW,eAAe,UAAa,SAAS,WAAW,YAAY;AACzE,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKO,SAAS,oBAAoB,OAAwC;AAC1E,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,SAAS,GAAI,QAAO;AACxB,MAAI,SAAS,GAAI,QAAO;AACxB,MAAI,SAAS,GAAI,QAAO;AACxB,SAAO;AACT;AAKO,SAAS,oBACd,OACA,QACQ;AACR,MAAI,UAAU,UAAa,UAAU,QAAQ,CAAC,OAAO,SAAS,KAAK,GAAG;AACpE,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,QAAQ;AACjB,WAAO,OAAO,OAAO,KAAK;AAAA,EAC5B;AAEA,QAAM,YAAY,OAAO,aAAa;AACtC,QAAM,YAAY,MAAM,QAAQ,SAAS;AACzC,QAAM,OAAO,OAAO,QAAQ;AAE5B,SAAO,OAAO,GAAG,SAAS,GAAG,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,IAAI,KAAK,GAAG,GAAG,IAAI,KAAK;AAClG;AAKO,SAAS,qBACd,SACA,WACgB;AAChB,QAAM,OAAO,kBAAkB,OAAO;AACtC,SAAO,EAAE,GAAG,MAAM,GAAG,UAAA;AACvB;AAKO,SAAS,wBAAwB,UAA4E;AAClH,SAAO,OAAO,QAAQ,gBAAgB,EACnC,OAAO,CAAC,CAAC,GAAG,MAAM,MAAM,OAAO,aAAa,QAAQ,EACpD,IAAI,CAAC,CAAC,KAAK,MAAM,OAAO,EAAE,KAAK,OAAA,EAAS;AAC7C;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { memo, useState, useRef, useEffect } from "react";
|
|
3
3
|
import { isValidIconName, Icon } from "./Icon.js";
|
|
4
|
-
import { useTheme } from "
|
|
4
|
+
import { useTheme } from "../../theme/ThemeProvider.js";
|
|
5
5
|
const SIZE_MAP = {
|
|
6
6
|
"extra-small": 16,
|
|
7
7
|
"small": 24,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AstroIcon.js","sources":["../../../../src/react/core/display/AstroIcon.tsx"],"sourcesContent":["/**\n * @zendir/ui - AstroIcon Component\n * \n * Wrapper around official @astrouxds/react RuxIcon component.\n * Provides all 400+ official Astro UXD icons with consistent API.\n * \n * SECURITY: Uses dynamic import with proper error handling.\n * FLEXIBILITY: Works with or without @astrouxds/react installed.\n * \n * @see https://www.astrouxds.com/components/icon-library/\n * \n * @example\n * ```tsx\n * import { AstroIcon } from '@zendir/ui/react';\n * \n * <AstroIcon name=\"satellite\" />\n * <AstroIcon name=\"antenna\" size=\"large\" />\n * <AstroIcon name=\"thermal\" color=\"#ff0000\" />\n * ```\n */\n\nimport React, { memo, useState, useEffect, useRef } from 'react';\nimport { useTheme } from '../../theme';\nimport { Icon, isValidIconName } from './Icon';\n\n/**\n * All official Astro UXD icon names\n * @see https://www.astrouxds.com/components/icon-library/\n */\nexport type AstroIconName =\n // === Astro Space/Mission Icons (Custom by Rocket Communications) ===\n | 'altitude'\n | 'antenna'\n | 'antenna-off'\n | 'antenna-receive'\n | 'antenna-transmit'\n | 'equipment'\n | 'hardware'\n | 'mission'\n | 'netcom'\n | 'payload'\n | 'processor'\n | 'processor-alt'\n | 'propulsion-power'\n | 'satellite-off'\n | 'satellite-receive'\n | 'satellite-transmit'\n | 'solar'\n | 'thermal'\n // === Actions ===\n | 'settings'\n | 'search'\n | 'home'\n | 'info'\n | 'help'\n | 'delete'\n | 'edit'\n | 'lock'\n | 'lock-open'\n | 'visibility'\n | 'visibility-off'\n | 'refresh'\n | 'sync'\n | 'download'\n | 'upload'\n | 'fullscreen'\n | 'fullscreen-exit'\n | 'zoom-in'\n | 'zoom-out'\n | 'schedule'\n | 'timeline'\n | 'today'\n | 'event'\n | 'bookmark'\n | 'favorite'\n | 'star'\n | 'check-circle'\n | 'done'\n | 'done-all'\n | 'print'\n | 'open-in-new'\n | 'launch'\n | 'power-settings-new'\n | 'history'\n | 'cached'\n | 'build'\n | 'code'\n | 'dns'\n | 'language'\n | 'input'\n | 'label'\n | 'list'\n | 'track-changes'\n | 'verified-user'\n | 'work'\n // === Alerts ===\n | 'add-alert'\n | 'error'\n | 'error-outline'\n | 'notification-important'\n | 'warning'\n // === AV ===\n | 'play-arrow'\n | 'pause'\n | 'stop'\n | 'skip-next'\n | 'skip-previous'\n | 'fast-forward'\n | 'fast-rewind'\n | 'replay'\n | 'loop'\n | 'shuffle'\n | 'volume-up'\n | 'volume-down'\n | 'volume-off'\n | 'volume-mute'\n | 'mic'\n | 'mic-off'\n | 'videocam'\n | 'videocam-off'\n | 'movie'\n | 'music-note'\n | 'equalizer'\n | 'library-music'\n | 'queue-music'\n | 'subscriptions'\n | 'fiber-new'\n | 'fiber-manual-record'\n | 'fiber-smart-record'\n // === Communication ===\n | 'call'\n | 'call-end'\n | 'call-made'\n | 'call-received'\n | 'call-missed'\n | 'call-split'\n | 'chat'\n | 'chat-bubble'\n | 'comment'\n | 'contacts'\n | 'dialer-sip'\n | 'email'\n | 'forum'\n | 'import-export'\n | 'live-help'\n | 'location-off'\n | 'location-on'\n | 'message'\n | 'phone'\n | 'phonelink-erase'\n | 'phonelink-lock'\n | 'phonelink-ring'\n | 'portable-wifi-off'\n | 'present-to-all'\n | 'ring-volume'\n | 'screen-share'\n | 'speaker-phone'\n | 'stay-primary-landscape'\n | 'stay-primary-portrait'\n | 'stop-screen-share'\n | 'swap-calls'\n | 'textsms'\n | 'voicemail'\n | 'vpn-key'\n // === Content ===\n | 'add'\n | 'add-box'\n | 'add-circle'\n | 'add-circle-outline'\n | 'archive'\n | 'backspace'\n | 'block'\n | 'clear'\n | 'content-copy'\n | 'content-cut'\n | 'content-paste'\n | 'create'\n | 'drafts'\n | 'filter-list'\n | 'flag'\n | 'forward'\n | 'gesture'\n | 'inbox'\n | 'link'\n | 'link-off'\n | 'low-priority'\n | 'mail'\n | 'markunread'\n | 'move-to-inbox'\n | 'next-week'\n | 'redo'\n | 'remove'\n | 'remove-circle'\n | 'remove-circle-outline'\n | 'reply'\n | 'reply-all'\n | 'report'\n | 'save'\n | 'select-all'\n | 'send'\n | 'sort'\n | 'text-format'\n | 'unarchive'\n | 'undo'\n | 'weekend'\n // === Device ===\n | 'access-alarm'\n | 'access-alarms'\n | 'access-time'\n | 'add-alarm'\n | 'airplanemode-active'\n | 'airplanemode-inactive'\n | 'battery-20'\n | 'battery-30'\n | 'battery-50'\n | 'battery-60'\n | 'battery-80'\n | 'battery-90'\n | 'battery-alert'\n | 'battery-charging-20'\n | 'battery-charging-30'\n | 'battery-charging-50'\n | 'battery-charging-60'\n | 'battery-charging-80'\n | 'battery-charging-90'\n | 'battery-charging-full'\n | 'battery-full'\n | 'battery-std'\n | 'battery-unknown'\n | 'bluetooth'\n | 'bluetooth-connected'\n | 'bluetooth-disabled'\n | 'bluetooth-searching'\n | 'brightness-auto'\n | 'brightness-high'\n | 'brightness-low'\n | 'brightness-medium'\n | 'data-usage'\n | 'developer-mode'\n | 'devices'\n | 'dvr'\n | 'gps-fixed'\n | 'gps-not-fixed'\n | 'gps-off'\n | 'graphic-eq'\n | 'location-disabled'\n | 'location-searching'\n | 'network-cell'\n | 'network-wifi'\n | 'nfc'\n | 'screen-lock-landscape'\n | 'screen-lock-portrait'\n | 'screen-lock-rotation'\n | 'screen-rotation'\n | 'sd-storage'\n | 'settings-system-daydream'\n | 'signal-cellular-0-bar'\n | 'signal-cellular-1-bar'\n | 'signal-cellular-2-bar'\n | 'signal-cellular-3-bar'\n | 'signal-cellular-4-bar'\n | 'signal-cellular-connected-no-internet-0-bar'\n | 'signal-cellular-connected-no-internet-1-bar'\n | 'signal-cellular-connected-no-internet-2-bar'\n | 'signal-cellular-connected-no-internet-3-bar'\n | 'signal-cellular-connected-no-internet-4-bar'\n | 'signal-cellular-no-sim'\n | 'signal-cellular-null'\n | 'signal-cellular-off'\n | 'signal-wifi-0-bar'\n | 'signal-wifi-1-bar'\n | 'signal-wifi-1-bar-lock'\n | 'signal-wifi-2-bar'\n | 'signal-wifi-2-bar-lock'\n | 'signal-wifi-3-bar'\n | 'signal-wifi-3-bar-lock'\n | 'signal-wifi-4-bar'\n | 'signal-wifi-4-bar-lock'\n | 'signal-wifi-off'\n | 'storage'\n | 'usb'\n | 'wallpaper'\n | 'widgets'\n | 'wifi-lock'\n | 'wifi-tethering'\n // === Editor ===\n | 'attach-file'\n | 'attach-money'\n | 'border-all'\n | 'border-bottom'\n | 'border-clear'\n | 'border-color'\n | 'border-horizontal'\n | 'border-inner'\n | 'border-left'\n | 'border-outer'\n | 'border-right'\n | 'border-style'\n | 'border-top'\n | 'border-vertical'\n | 'bubble-chart'\n | 'drag-handle'\n | 'format-align-center'\n | 'format-align-justify'\n | 'format-align-left'\n | 'format-align-right'\n | 'format-bold'\n | 'format-clear'\n | 'format-color-fill'\n | 'format-color-reset'\n | 'format-color-text'\n | 'format-indent-decrease'\n | 'format-indent-increase'\n | 'format-italic'\n | 'format-line-spacing'\n | 'format-list-bulleted'\n | 'format-list-numbered'\n | 'format-paint'\n | 'format-quote'\n | 'format-shapes'\n | 'format-size'\n | 'format-strikethrough'\n | 'format-textdirection-l-to-r'\n | 'format-textdirection-r-to-l'\n | 'format-underlined'\n | 'functions'\n | 'highlight'\n | 'insert-chart'\n | 'insert-comment'\n | 'insert-drive-file'\n | 'insert-emoticon'\n | 'insert-invitation'\n | 'insert-link'\n | 'insert-photo'\n | 'linear-scale'\n | 'merge-type'\n | 'mode-comment'\n | 'mode-edit'\n | 'monetization-on'\n | 'money-off'\n | 'multiline-chart'\n | 'pie-chart'\n | 'pie-chart-outlined'\n | 'publish'\n | 'short-text'\n | 'show-chart'\n | 'space-bar'\n | 'strikethrough-s'\n | 'table-chart'\n | 'text-fields'\n | 'title'\n | 'vertical-align-bottom'\n | 'vertical-align-center'\n | 'vertical-align-top'\n | 'wrap-text'\n // === File ===\n | 'attachment'\n | 'cloud'\n | 'cloud-circle'\n | 'cloud-done'\n | 'cloud-download'\n | 'cloud-off'\n | 'cloud-queue'\n | 'cloud-upload'\n | 'create-new-folder'\n | 'file-download'\n | 'file-upload'\n | 'folder'\n | 'folder-open'\n | 'folder-shared'\n // === Hardware ===\n | 'cast'\n | 'cast-connected'\n | 'computer'\n | 'desktop-mac'\n | 'desktop-windows'\n | 'developer-board'\n | 'device-hub'\n | 'devices-other'\n | 'dock'\n | 'gamepad'\n | 'headset'\n | 'headset-mic'\n | 'keyboard'\n | 'keyboard-arrow-down'\n | 'keyboard-arrow-left'\n | 'keyboard-arrow-right'\n | 'keyboard-arrow-up'\n | 'keyboard-backspace'\n | 'keyboard-capslock'\n | 'keyboard-hide'\n | 'keyboard-return'\n | 'keyboard-tab'\n | 'keyboard-voice'\n | 'laptop'\n | 'laptop-chromebook'\n | 'laptop-mac'\n | 'laptop-windows'\n | 'memory'\n | 'mouse'\n | 'phone-android'\n | 'phone-iphone'\n | 'phonelink'\n | 'phonelink-off'\n | 'power-input'\n | 'router'\n | 'scanner'\n | 'security'\n | 'sim-card'\n | 'smartphone'\n | 'speaker'\n | 'speaker-group'\n | 'tablet'\n | 'tablet-android'\n | 'tablet-mac'\n | 'toys'\n | 'tv'\n | 'videogame-asset'\n | 'watch'\n // === Image ===\n | 'add-a-photo'\n | 'add-to-photos'\n | 'adjust'\n | 'assistant'\n | 'assistant-photo'\n | 'audiotrack'\n | 'blur-circular'\n | 'blur-linear'\n | 'blur-off'\n | 'blur-on'\n | 'brightness-1'\n | 'brightness-2'\n | 'brightness-3'\n | 'brightness-4'\n | 'brightness-5'\n | 'brightness-6'\n | 'brightness-7'\n | 'broken-image'\n | 'brush'\n | 'burst-mode'\n | 'camera'\n | 'camera-alt'\n | 'camera-front'\n | 'camera-rear'\n | 'camera-roll'\n | 'center-focus-strong'\n | 'center-focus-weak'\n | 'collections'\n | 'collections-bookmark'\n | 'color-lens'\n | 'colorize'\n | 'compare'\n | 'control-point'\n | 'control-point-duplicate'\n | 'crop'\n | 'crop-16-9'\n | 'crop-3-2'\n | 'crop-5-4'\n | 'crop-7-5'\n | 'crop-din'\n | 'crop-free'\n | 'crop-landscape'\n | 'crop-original'\n | 'crop-portrait'\n | 'crop-rotate'\n | 'crop-square'\n | 'dehaze'\n | 'details'\n | 'edit'\n | 'exposure'\n | 'exposure-neg-1'\n | 'exposure-neg-2'\n | 'exposure-plus-1'\n | 'exposure-plus-2'\n | 'exposure-zero'\n | 'filter'\n | 'filter-1'\n | 'filter-2'\n | 'filter-3'\n | 'filter-4'\n | 'filter-5'\n | 'filter-6'\n | 'filter-7'\n | 'filter-8'\n | 'filter-9'\n | 'filter-9-plus'\n | 'filter-b-and-w'\n | 'filter-center-focus'\n | 'filter-drama'\n | 'filter-frames'\n | 'filter-hdr'\n | 'filter-none'\n | 'filter-tilt-shift'\n | 'filter-vintage'\n | 'flare'\n | 'flash-auto'\n | 'flash-off'\n | 'flash-on'\n | 'flip'\n | 'gradient'\n | 'grain'\n | 'grid-off'\n | 'grid-on'\n | 'hdr-off'\n | 'hdr-on'\n | 'hdr-strong'\n | 'hdr-weak'\n | 'healing'\n | 'image'\n | 'image-aspect-ratio'\n | 'iso'\n | 'landscape'\n | 'leak-add'\n | 'leak-remove'\n | 'lens'\n | 'linked-camera'\n | 'looks'\n | 'looks-3'\n | 'looks-4'\n | 'looks-5'\n | 'looks-6'\n | 'looks-one'\n | 'looks-two'\n | 'loupe'\n | 'monochrome-photos'\n | 'movie-creation'\n | 'movie-filter'\n | 'music-note'\n | 'nature'\n | 'nature-people'\n | 'navigate-before'\n | 'navigate-next'\n | 'palette'\n | 'panorama'\n | 'panorama-fish-eye'\n | 'panorama-horizontal'\n | 'panorama-vertical'\n | 'panorama-wide-angle'\n | 'photo'\n | 'photo-album'\n | 'photo-camera'\n | 'photo-filter'\n | 'photo-library'\n | 'photo-size-select-actual'\n | 'photo-size-select-large'\n | 'photo-size-select-small'\n | 'picture-as-pdf'\n | 'portrait'\n | 'remove-red-eye'\n | 'rotate-90-degrees-ccw'\n | 'rotate-left'\n | 'rotate-right'\n | 'slideshow'\n | 'straighten'\n | 'style'\n | 'switch-camera'\n | 'switch-video'\n | 'tag-faces'\n | 'texture'\n | 'timelapse'\n | 'timer'\n | 'timer-10'\n | 'timer-3'\n | 'timer-off'\n | 'tonality'\n | 'transform'\n | 'tune'\n | 'view-comfy'\n | 'view-compact'\n | 'vignette'\n | 'wb-auto'\n | 'wb-cloudy'\n | 'wb-incandescent'\n | 'wb-iridescent'\n | 'wb-sunny'\n // === Maps ===\n | 'add-location'\n | 'beenhere'\n | 'directions'\n | 'directions-bike'\n | 'directions-boat'\n | 'directions-bus'\n | 'directions-car'\n | 'directions-railway'\n | 'directions-run'\n | 'directions-subway'\n | 'directions-transit'\n | 'directions-walk'\n | 'edit-location'\n | 'ev-station'\n | 'explore'\n | 'flight'\n | 'hotel'\n | 'layers'\n | 'layers-clear'\n | 'local-activity'\n | 'local-airport'\n | 'local-atm'\n | 'local-bar'\n | 'local-cafe'\n | 'local-car-wash'\n | 'local-convenience-store'\n | 'local-dining'\n | 'local-drink'\n | 'local-florist'\n | 'local-gas-station'\n | 'local-grocery-store'\n | 'local-hospital'\n | 'local-hotel'\n | 'local-laundry-service'\n | 'local-library'\n | 'local-mall'\n | 'local-movies'\n | 'local-offer'\n | 'local-parking'\n | 'local-pharmacy'\n | 'local-phone'\n | 'local-pizza'\n | 'local-play'\n | 'local-post-office'\n | 'local-printshop'\n | 'local-see'\n | 'local-shipping'\n | 'local-taxi'\n | 'map'\n | 'my-location'\n | 'navigation'\n | 'near-me'\n | 'person-pin'\n | 'person-pin-circle'\n | 'pin-drop'\n | 'place'\n | 'rate-review'\n | 'restaurant'\n | 'restaurant-menu'\n | 'satellite'\n | 'store-mall-directory'\n | 'streetview'\n | 'subway'\n | 'terrain'\n | 'traffic'\n | 'train'\n | 'tram'\n | 'transfer-within-a-station'\n | 'zoom-out-map'\n // === Navigation ===\n | 'apps'\n | 'arrow-back'\n | 'arrow-downward'\n | 'arrow-drop-down'\n | 'arrow-drop-down-circle'\n | 'arrow-drop-up'\n | 'arrow-forward'\n | 'arrow-upward'\n | 'cancel'\n | 'check'\n | 'chevron-left'\n | 'chevron-right'\n | 'close'\n | 'expand-less'\n | 'expand-more'\n | 'first-page'\n | 'fullscreen'\n | 'fullscreen-exit'\n | 'last-page'\n | 'menu'\n | 'more-horiz'\n | 'more-vert'\n | 'refresh'\n | 'subdirectory-arrow-left'\n | 'subdirectory-arrow-right'\n | 'unfold-less'\n | 'unfold-more'\n // === Notification ===\n | 'adb'\n | 'airline-seat-flat'\n | 'airline-seat-flat-angled'\n | 'airline-seat-individual-suite'\n | 'airline-seat-legroom-extra'\n | 'airline-seat-legroom-normal'\n | 'airline-seat-legroom-reduced'\n | 'airline-seat-recline-extra'\n | 'airline-seat-recline-normal'\n | 'bluetooth-audio'\n | 'confirmation-number'\n | 'disc-full'\n | 'do-not-disturb'\n | 'do-not-disturb-alt'\n | 'do-not-disturb-off'\n | 'do-not-disturb-on'\n | 'drive-eta'\n | 'enhanced-encryption'\n | 'event-available'\n | 'event-busy'\n | 'event-note'\n | 'folder-special'\n | 'live-tv'\n | 'mms'\n | 'more'\n | 'network-check'\n | 'network-locked'\n | 'no-encryption'\n | 'ondemand-video'\n | 'personal-video'\n | 'phone-bluetooth-speaker'\n | 'phone-forwarded'\n | 'phone-in-talk'\n | 'phone-locked'\n | 'phone-missed'\n | 'phone-paused'\n | 'power'\n | 'power-off'\n | 'priority-high'\n | 'sd-card'\n | 'sim-card-alert'\n | 'sms'\n | 'sms-failed'\n | 'sync'\n | 'sync-disabled'\n | 'sync-problem'\n | 'system-update'\n | 'tap-and-play'\n | 'time-to-leave'\n | 'vibration'\n | 'voice-chat'\n | 'vpn-lock'\n | 'wc'\n | 'wifi'\n | 'wifi-off'\n // === Places ===\n | 'ac-unit'\n | 'airport-shuttle'\n | 'all-inclusive'\n | 'beach-access'\n | 'business-center'\n | 'casino'\n | 'child-care'\n | 'child-friendly'\n | 'fitness-center'\n | 'free-breakfast'\n | 'golf-course'\n | 'hot-tub'\n | 'kitchen'\n | 'pool'\n | 'room-service'\n | 'rv-hookup'\n | 'smoke-free'\n | 'smoking-rooms'\n | 'spa'\n // === Social ===\n | 'cake'\n | 'domain'\n | 'group'\n | 'group-add'\n | 'location-city'\n | 'mood'\n | 'mood-bad'\n | 'notifications'\n | 'notifications-active'\n | 'notifications-none'\n | 'notifications-off'\n | 'notifications-paused'\n | 'pages'\n | 'party-mode'\n | 'people'\n | 'people-outline'\n | 'person'\n | 'person-add'\n | 'person-outline'\n | 'plus-one'\n | 'poll'\n | 'public'\n | 'school'\n | 'sentiment-dissatisfied'\n | 'sentiment-neutral'\n | 'sentiment-satisfied'\n | 'sentiment-very-dissatisfied'\n | 'sentiment-very-satisfied'\n | 'share'\n | 'whatshot'\n // === Toggle ===\n | 'check-box'\n | 'check-box-outline-blank'\n | 'indeterminate-check-box'\n | 'radio-button-checked'\n | 'radio-button-unchecked'\n | 'star'\n | 'star-border'\n | 'star-half'\n // === Space Operations Aliases (mapped to existing icons) ===\n // Orbit & Trajectory\n | 'orbit' | 'trajectory' | 'orbital'\n // Ground Operations\n | 'ground-station' | 'ground-control' | 'dish' | 'tracking-station'\n // Communication\n | 'uplink' | 'downlink' | 'command' | 'telemetry' | 'comms' | 'rf' | 'link' | 'signal' | 'data-link'\n // Satellite States\n | 'satellite' | 'spacecraft' | 'vehicle' | 'sat' | 'sc'\n // Power Systems\n | 'power' | 'battery' | 'energy' | 'solar-array' | 'solar-panel' | 'photovoltaic'\n // Propulsion\n | 'thruster' | 'engine' | 'burn' | 'maneuver' | 'delta-v' | 'rcs'\n // Thermal\n | 'temperature' | 'heat' | 'cooling' | 'heater'\n // Attitude & Control\n | 'attitude' | 'pointing' | 'orientation' | 'adcs' | 'gyro' | 'gyroscope'\n // Navigation\n | 'gps' | 'gnss' | 'position' | 'location' | 'ephemeris'\n // Status & Health\n | 'health' | 'status' | 'nominal' | 'anomaly' | 'fault' | 'safe-mode' | 'emergency' | 'critical' | 'caution'\n // Time & Scheduling\n | 'pass' | 'contact' | 'access' | 'window' | 'aos' | 'los' | 'eclipse' | 'sunlight' | 'shadow'\n // Subsystems\n | 'subsystem' | 'computer' | 'obc' | 'cdh' | 'flight-computer' | 'sensor' | 'instrument'\n // Launch & Deployment\n | 'launch' | 'rocket' | 'liftoff' | 'deployment' | 'deploy' | 'separation'\n // Operations\n | 'ops' | 'operations' | 'control' | 'automation' | 'sequence' | 'procedure'\n // Data & Storage\n | 'storage' | 'memory' | 'recorder' | 'playback' | 'record'\n // Monitoring\n | 'monitor' | 'dashboard' | 'console' | 'display'\n // Crew\n | 'astronaut' | 'crew' | 'eva'\n // Catch-all for any other icon (flexibility)\n | (string & {});\n\nexport type AstroIconSize = 'extra-small' | 'small' | 'normal' | 'large';\n\nexport interface AstroIconProps {\n /** Icon name from Astro UXD library */\n name: AstroIconName;\n /** Icon size preset or custom pixel value */\n size?: AstroIconSize | number;\n /** Custom color (hex, rgb, or CSS color) */\n color?: string;\n /** Accessibility label (required for screen readers) */\n label?: string;\n /** Additional CSS class */\n className?: string;\n /** Additional inline styles */\n style?: React.CSSProperties;\n /** Click handler */\n onClick?: () => void;\n /** Test ID for testing */\n 'data-testid'?: string;\n}\n\n// Size mapping for fallback mode\nconst SIZE_MAP: Record<AstroIconSize, number> = {\n 'extra-small': 16,\n 'small': 24,\n 'normal': 32,\n 'large': 48,\n};\n\n/**\n * Space Operations Icon Aliases\n * Maps common space terminology to existing Astro icons.\n * Provides better developer experience with intuitive naming.\n */\nconst ICON_ALIASES: Record<string, string> = {\n // === Orbit & Trajectory ===\n 'orbit': '360', // Orbital path\n 'trajectory': '360', // Flight path\n 'orbital': '360', // Orbital mechanics\n \n // === Ground Operations ===\n 'ground-station': 'antenna', // Ground station\n 'ground-control': 'antenna', // Mission control\n 'dish': 'antenna', // Antenna dish\n 'tracking-station': 'antenna', // Tracking facility\n \n // === Communication ===\n 'uplink': 'antenna-transmit', // Command upload\n 'downlink': 'antenna-receive', // Data download\n 'command': 'antenna-transmit', // Send command\n 'telemetry': 'antenna-receive', // Receive telemetry\n 'comms': 'netcom', // Communications\n 'rf': 'antenna', // Radio frequency\n 'link': 'netcom', // Communication link\n 'signal': 'antenna-transmit', // Signal transmission\n 'data-link': 'netcom', // Data link\n \n // === Satellite States ===\n 'satellite': 'satellite-transmit', // Default satellite (active)\n 'spacecraft': 'satellite-transmit', // Spacecraft\n 'vehicle': 'satellite-transmit', // Space vehicle\n 'sat': 'satellite-transmit', // Abbreviation\n 'sc': 'satellite-transmit', // Spacecraft abbreviation\n \n // === Power Systems ===\n 'power': 'propulsion-power', // Power system\n 'battery': 'battery-full', // Battery status\n 'energy': 'propulsion-power', // Energy management\n 'solar-array': 'solar', // Solar arrays\n 'solar-panel': 'solar', // Solar panels\n 'photovoltaic': 'solar', // PV system\n \n // === Propulsion ===\n 'thruster': 'propulsion-power', // Thruster\n 'engine': 'propulsion-power', // Engine\n 'burn': 'propulsion-power', // Burn/maneuver\n 'maneuver': 'propulsion-power', // Orbital maneuver\n 'delta-v': 'propulsion-power', // Delta-V\n 'rcs': 'propulsion-power', // Reaction control system\n \n // === Thermal ===\n 'temperature': 'thermal', // Temperature\n 'heat': 'thermal', // Heat management\n 'cooling': 'thermal', // Cooling system\n 'heater': 'thermal', // Heater\n \n // === Attitude & Control ===\n 'attitude': 'explore', // Attitude control\n 'pointing': 'explore', // Pointing direction\n 'orientation': 'explore', // Spacecraft orientation\n 'adcs': 'explore', // Attitude determination & control\n 'gyro': 'explore', // Gyroscope\n 'gyroscope': 'explore', // Gyroscope\n \n // === Navigation ===\n 'gps': 'gps-fixed', // GPS/GNSS\n 'gnss': 'gps-fixed', // Global navigation\n 'position': 'gps-fixed', // Position\n 'location': 'place', // Location\n 'ephemeris': 'timeline', // Ephemeris data\n \n // === Status & Health ===\n 'health': 'favorite', // System health\n 'status': 'info', // Status indicator\n 'nominal': 'check-circle', // Nominal/OK\n 'anomaly': 'error', // Anomaly detected\n 'fault': 'error', // Fault condition\n 'safe-mode': 'warning', // Safe mode\n 'emergency': 'warning', // Emergency\n 'critical': 'error', // Critical status\n 'caution': 'warning', // Caution\n \n // === Time & Scheduling ===\n 'pass': 'schedule', // Satellite pass\n 'contact': 'schedule', // Ground contact\n 'access': 'schedule', // Access window\n 'window': 'schedule', // Time window\n 'aos': 'schedule', // Acquisition of signal\n 'los': 'schedule', // Loss of signal\n 'eclipse': 'brightness-3', // Eclipse period\n 'sunlight': 'wb-sunny', // In sunlight\n 'shadow': 'brightness-3', // In shadow\n \n // === Subsystems ===\n 'subsystem': 'developer-board', // Generic subsystem\n 'computer': 'memory', // Onboard computer\n 'obc': 'memory', // Onboard computer\n 'cdh': 'memory', // Command & data handling\n 'flight-computer': 'memory', // Flight computer\n 'sensor': 'settings-input-component', // Sensor\n 'instrument': 'settings-input-component', // Instrument\n \n // === Launch & Deployment ===\n 'launch': 'flight-takeoff', // Launch\n 'rocket': 'flight-takeoff', // Rocket\n 'liftoff': 'flight-takeoff', // Liftoff\n 'deployment': 'open-in-new', // Deployment\n 'deploy': 'open-in-new', // Deploy\n 'separation': 'call-split', // Stage separation\n \n // === Operations ===\n 'ops': 'build', // Operations\n 'operations': 'build', // Operations\n 'control': 'tune', // Control\n 'automation': 'autorenew', // Automation\n 'sequence': 'playlist-play', // Command sequence\n 'procedure': 'list', // Procedure\n \n // === Data & Storage ===\n 'storage': 'sd-storage', // Data storage\n 'memory': 'memory', // Memory\n 'recorder': 'fiber-dvr', // Data recorder\n 'playback': 'play-arrow', // Playback\n 'record': 'fiber-manual-record', // Recording\n \n // === Monitoring ===\n 'monitor': 'desktop-mac', // Monitoring\n 'dashboard': 'dashboard', // Dashboard\n 'console': 'desktop-windows', // Console\n 'display': 'tv', // Display\n \n // === Crew (if applicable) ===\n 'astronaut': 'person', // Astronaut\n 'crew': 'group', // Crew\n 'eva': 'directions-walk', // Extra-vehicular activity\n};\n\n/**\n * Resolve icon alias to actual Astro icon name\n */\nfunction resolveIconAlias(name: string): string {\n return ICON_ALIASES[name] || name;\n}\n\n/**\n * Get all available icon aliases\n */\nexport function getIconAliases(): Record<string, string> {\n return { ...ICON_ALIASES };\n}\n\n/**\n * Check if an icon name is an alias\n */\nexport function isIconAlias(name: string): boolean {\n return name in ICON_ALIASES;\n}\n\n/**\n * All available Astro UXD icon names (official icons, not aliases)\n * This is the comprehensive list from the Astro UXD icon library\n */\nexport const ASTRO_ICON_NAMES: readonly string[] = [\n // === Astro Space/Mission Icons (Custom by Rocket Communications) ===\n 'altitude', 'antenna', 'antenna-off', 'antenna-receive', 'antenna-transmit',\n 'equipment', 'hardware', 'mission', 'netcom', 'payload',\n 'processor', 'processor-alt', 'propulsion-power', 'satellite-off',\n 'satellite-receive', 'satellite-transmit', 'solar', 'thermal',\n // === Actions ===\n 'settings', 'search', 'home', 'info', 'help', 'delete', 'edit',\n 'lock', 'lock-open', 'visibility', 'visibility-off', 'refresh', 'sync',\n 'download', 'upload', 'fullscreen', 'fullscreen-exit', 'zoom-in', 'zoom-out',\n 'schedule', 'timeline', 'today', 'event', 'bookmark', 'favorite', 'star',\n 'check-circle', 'done', 'done-all', 'print', 'open-in-new', 'launch',\n 'power-settings-new', 'history', 'cached', 'build', 'code', 'dns',\n 'language', 'input', 'label', 'list', 'track-changes', 'verified-user', 'work',\n // === Alerts ===\n 'add-alert', 'error', 'error-outline', 'notification-important', 'warning',\n // === AV ===\n 'play-arrow', 'pause', 'stop', 'skip-next', 'skip-previous',\n 'fast-forward', 'fast-rewind', 'replay', 'loop', 'shuffle',\n 'volume-up', 'volume-down', 'volume-off', 'volume-mute',\n 'mic', 'mic-off', 'videocam', 'videocam-off', 'movie',\n 'music-note', 'equalizer', 'library-music', 'queue-music',\n // === Communication ===\n 'call', 'call-end', 'chat', 'chat-bubble', 'chat-bubble-outline',\n 'comment', 'contacts', 'email', 'mail-outline', 'message',\n 'phone', 'voicemail', 'vpn-key', 'forum', 'live-help',\n 'location-on', 'location-off', 'business', 'import-contacts',\n // === Content ===\n 'add', 'remove', 'add-circle', 'add-circle-outline', 'remove-circle',\n 'remove-circle-outline', 'clear', 'content-copy', 'content-cut', 'content-paste',\n 'create', 'flag', 'forward', 'reply', 'reply-all',\n 'save', 'save-alt', 'select-all', 'send', 'undo', 'redo',\n 'filter-list', 'sort', 'drafts', 'link', 'link-off',\n // === Device ===\n 'battery-full', 'battery-charging-full', 'battery-alert', 'battery-unknown',\n 'bluetooth', 'bluetooth-disabled', 'bluetooth-connected', 'bluetooth-searching',\n 'brightness-1', 'brightness-2', 'brightness-3', 'brightness-4',\n 'brightness-5', 'brightness-6', 'brightness-7', 'brightness-auto',\n 'brightness-high', 'brightness-low', 'brightness-medium',\n 'gps-fixed', 'gps-not-fixed', 'gps-off', 'graphic-eq',\n 'network-cell', 'network-wifi', 'nfc', 'screen-rotation',\n 'sd-storage', 'settings-system-daydream', 'signal-cellular-4-bar',\n 'signal-cellular-connected-no-internet-4-bar', 'signal-cellular-no-sim',\n 'signal-cellular-null', 'signal-cellular-off', 'signal-wifi-4-bar',\n 'signal-wifi-4-bar-lock', 'signal-wifi-off', 'storage',\n 'usb', 'wifi', 'wifi-lock', 'wifi-off', 'wifi-tethering',\n // === Editor ===\n 'attach-file', 'attach-money', 'border-all', 'border-bottom',\n 'border-clear', 'border-color', 'border-horizontal', 'border-inner',\n 'border-left', 'border-outer', 'border-right', 'border-style',\n 'border-top', 'border-vertical', 'format-align-center', 'format-align-justify',\n 'format-align-left', 'format-align-right', 'format-bold', 'format-clear',\n 'format-color-fill', 'format-color-reset', 'format-color-text',\n 'format-indent-decrease', 'format-indent-increase', 'format-italic',\n 'format-line-spacing', 'format-list-bulleted', 'format-list-numbered',\n 'format-paint', 'format-quote', 'format-size', 'format-strikethrough',\n 'format-textdirection-l-to-r', 'format-textdirection-r-to-l',\n 'format-underlined', 'functions', 'insert-chart', 'insert-comment',\n 'insert-drive-file', 'insert-emoticon', 'insert-invitation', 'insert-link',\n 'insert-photo', 'merge-type', 'mode-comment', 'mode-edit',\n 'publish', 'short-text', 'space-bar', 'strikethrough-s',\n 'text-fields', 'title', 'vertical-align-bottom', 'vertical-align-center',\n 'vertical-align-top', 'wrap-text',\n // === File ===\n 'attachment', 'cloud', 'cloud-circle', 'cloud-done', 'cloud-download',\n 'cloud-off', 'cloud-queue', 'cloud-upload', 'create-new-folder',\n 'file-download', 'file-upload', 'folder', 'folder-open', 'folder-shared',\n // === Hardware ===\n 'cast', 'cast-connected', 'computer', 'desktop-mac', 'desktop-windows',\n 'developer-board', 'device-hub', 'devices-other', 'dock', 'gamepad',\n 'headset', 'headset-mic', 'keyboard', 'keyboard-arrow-down',\n 'keyboard-arrow-left', 'keyboard-arrow-right', 'keyboard-arrow-up',\n 'keyboard-backspace', 'keyboard-capslock', 'keyboard-hide',\n 'keyboard-return', 'keyboard-tab', 'keyboard-voice', 'laptop',\n 'laptop-chromebook', 'laptop-mac', 'laptop-windows', 'memory',\n 'mouse', 'phone-android', 'phone-iphone', 'phonelink', 'phonelink-off',\n 'power-input', 'router', 'scanner', 'security', 'sim-card',\n 'smartphone', 'speaker', 'speaker-group', 'tablet', 'tablet-android',\n 'tablet-mac', 'toys', 'tv', 'watch',\n // === Image ===\n 'add-a-photo', 'add-photo-alternate', 'add-to-photos', 'adjust',\n 'brightness-1', 'broken-image', 'brush', 'burst-mode', 'camera',\n 'camera-alt', 'camera-front', 'camera-rear', 'camera-roll',\n 'center-focus-strong', 'center-focus-weak', 'collections',\n 'collections-bookmark', 'color-lens', 'colorize', 'compare',\n 'control-point', 'control-point-duplicate', 'crop', 'crop-16-9',\n 'crop-3-2', 'crop-5-4', 'crop-7-5', 'crop-din', 'crop-free',\n 'crop-landscape', 'crop-original', 'crop-portrait', 'crop-rotate',\n 'crop-square', 'dehaze', 'details', 'edit', 'exposure',\n 'exposure-neg-1', 'exposure-neg-2', 'exposure-plus-1', 'exposure-plus-2',\n 'exposure-zero', 'filter', 'filter-1', 'filter-2', 'filter-3',\n 'filter-4', 'filter-5', 'filter-6', 'filter-7', 'filter-8', 'filter-9',\n 'filter-9-plus', 'filter-b-and-w', 'filter-center-focus', 'filter-drama',\n 'filter-frames', 'filter-hdr', 'filter-none', 'filter-tilt-shift',\n 'filter-vintage', 'flare', 'flash-auto', 'flash-off', 'flash-on',\n 'flip', 'gradient', 'grain', 'grid-off', 'grid-on', 'hdr-off',\n 'hdr-on', 'hdr-strong', 'hdr-weak', 'healing', 'image',\n 'image-aspect-ratio', 'image-search', 'iso', 'landscape', 'leak-add',\n 'leak-remove', 'lens', 'linked-camera', 'looks', 'looks-3',\n 'looks-4', 'looks-5', 'looks-6', 'looks-one', 'looks-two', 'loupe',\n 'monochrome-photos', 'movie-creation', 'movie-filter', 'music-off',\n 'music-on', 'navigate-before', 'navigate-next', 'nature', 'nature-people',\n 'palette', 'panorama', 'panorama-fish-eye', 'panorama-horizontal',\n 'panorama-vertical', 'panorama-wide-angle', 'photo', 'photo-album',\n 'photo-camera', 'photo-filter', 'photo-library', 'photo-size-select-actual',\n 'photo-size-select-large', 'photo-size-select-small', 'picture-as-pdf',\n 'portrait', 'remove-red-eye', 'rotate-90-degrees-ccw', 'rotate-left',\n 'rotate-right', 'slideshow', 'straighten', 'style', 'switch-camera',\n 'switch-video', 'tag-faces', 'texture', 'timelapse', 'timer',\n 'timer-10', 'timer-3', 'timer-off', 'tonality', 'transform', 'tune',\n 'view-comfy', 'view-compact', 'vignette', 'wb-auto', 'wb-cloudy',\n 'wb-incandescent', 'wb-iridescent', 'wb-sunny',\n // === Maps ===\n 'add-location', 'beenhere', 'directions', 'directions-bike',\n 'directions-boat', 'directions-bus', 'directions-car',\n 'directions-railway', 'directions-run', 'directions-subway',\n 'directions-transit', 'directions-walk', 'edit-location', 'ev-station',\n 'flight', 'hotel', 'layers', 'layers-clear', 'local-activity',\n 'local-airport', 'local-atm', 'local-bar', 'local-cafe', 'local-car-wash',\n 'local-convenience-store', 'local-dining', 'local-drink', 'local-florist',\n 'local-gas-station', 'local-grocery-store', 'local-hospital',\n 'local-hotel', 'local-laundry-service', 'local-library', 'local-mall',\n 'local-movies', 'local-offer', 'local-parking', 'local-pharmacy',\n 'local-phone', 'local-pizza', 'local-play', 'local-post-office',\n 'local-printshop', 'local-see', 'local-shipping', 'local-taxi', 'map',\n 'my-location', 'navigation', 'near-me', 'person-pin', 'person-pin-circle',\n 'pin-drop', 'place', 'rate-review', 'restaurant', 'restaurant-menu',\n 'satellite', 'store-mall-directory', 'streetview', 'subway', 'terrain',\n 'traffic', 'train', 'tram', 'transfer-within-a-station', 'zoom-out-map',\n // === Navigation ===\n 'apps', 'arrow-back', 'arrow-downward', 'arrow-drop-down',\n 'arrow-drop-down-circle', 'arrow-drop-up', 'arrow-forward', 'arrow-upward',\n 'cancel', 'check', 'chevron-left', 'chevron-right', 'close',\n 'expand-less', 'expand-more', 'first-page', 'last-page', 'menu',\n 'more-horiz', 'more-vert', 'subdirectory-arrow-left',\n 'subdirectory-arrow-right', 'unfold-less', 'unfold-more',\n // === Notification ===\n 'adb', 'airline-seat-flat', 'airline-seat-flat-angled',\n 'airline-seat-individual-suite', 'airline-seat-legroom-extra',\n 'airline-seat-legroom-normal', 'airline-seat-legroom-reduced',\n 'airline-seat-recline-extra', 'airline-seat-recline-normal',\n 'bluetooth-audio', 'confirmation-number', 'disc-full', 'do-not-disturb',\n 'do-not-disturb-alt', 'do-not-disturb-off', 'do-not-disturb-on',\n 'drive-eta', 'enhanced-encryption', 'event-available', 'event-busy',\n 'event-note', 'folder-special', 'live-tv', 'mms', 'more',\n 'network-check', 'network-locked', 'no-encryption', 'ondemand-video',\n 'personal-video', 'phone-bluetooth-speaker', 'phone-callback',\n 'phone-forwarded', 'phone-in-talk', 'phone-locked', 'phone-missed',\n 'phone-paused', 'power', 'power-off', 'priority-high', 'sd-card',\n 'sim-card-alert', 'sms', 'sms-failed', 'sync-disabled', 'sync-problem',\n 'system-update', 'tap-and-play', 'time-to-leave', 'vibration',\n 'voice-chat', 'vpn-lock', 'wc', 'wifi', 'notifications', 'notifications-active',\n 'notifications-none', 'notifications-off', 'notifications-paused',\n // === Places ===\n 'ac-unit', 'airport-shuttle', 'all-inclusive', 'beach-access',\n 'business-center', 'casino', 'child-care', 'child-friendly',\n 'fitness-center', 'free-breakfast', 'golf-course', 'hot-tub',\n 'kitchen', 'meeting-room', 'no-meeting-room', 'pool', 'room-service',\n 'rv-hookup', 'smoke-free', 'smoking-rooms', 'spa',\n // === Social ===\n 'cake', 'domain', 'group', 'group-add', 'location-city', 'mood',\n 'mood-bad', 'notifications', 'pages', 'party-mode', 'people',\n 'people-outline', 'person', 'person-add', 'person-outline',\n 'plus-one', 'poll', 'public', 'school', 'sentiment-dissatisfied',\n 'sentiment-neutral', 'sentiment-satisfied', 'sentiment-very-dissatisfied',\n 'sentiment-very-satisfied', 'share', 'thumb-down', 'thumb-up',\n 'whatshot',\n // === Toggle ===\n 'check-box', 'check-box-outline-blank', 'indeterminate-check-box',\n 'radio-button-checked', 'radio-button-unchecked', 'star', 'star-border', 'star-half',\n // === Additional common icons ===\n '360', 'autorenew', 'call-split', 'explore', 'extension', 'face',\n 'feedback', 'fiber-dvr', 'fiber-manual-record', 'fiber-new', 'fiber-pin',\n 'fiber-smart-record', 'get-app', 'grade', 'highlight-off', 'http',\n 'https', 'important-devices', 'lightbulb', 'lightbulb-outline',\n 'perm-camera-mic', 'perm-contact-calendar', 'perm-data-setting',\n 'perm-device-information', 'perm-identity', 'perm-media', 'perm-phone-msg',\n 'perm-scan-wifi', 'pets', 'playlist-add', 'playlist-add-check', 'playlist-play',\n 'pregnant-woman', 'query-builder', 'question-answer', 'receipt', 'record-voice-over',\n 'redeem', 'report-problem', 'restore', 'restore-page', 'room', 'rounded-corner',\n 'rowing', 'settings-applications', 'settings-backup-restore', 'settings-bluetooth',\n 'settings-brightness', 'settings-cell', 'settings-ethernet', 'settings-input-antenna',\n 'settings-input-component', 'settings-input-composite', 'settings-input-hdmi',\n 'settings-input-svideo', 'settings-overscan', 'settings-phone', 'settings-power',\n 'settings-remote', 'settings-voice', 'shop', 'shop-two', 'shopping-basket',\n 'shopping-cart', 'speaker-notes', 'speaker-notes-off', 'spellcheck', 'stars',\n 'subject', 'supervisor-account', 'swap-horiz', 'swap-vert', 'swap-vertical-circle',\n 'system-update-alt', 'tab', 'tab-unselected', 'theaters', 'thumb-down',\n 'thumb-up', 'thumbs-up-down', 'toc', 'toll', 'touch-app', 'translate',\n 'trending-down', 'trending-flat', 'trending-up', 'turned-in', 'turned-in-not',\n 'update', 'view-agenda', 'view-array', 'view-carousel', 'view-column',\n 'view-day', 'view-headline', 'view-list', 'view-module', 'view-quilt',\n 'view-stream', 'view-week', 'visibility', 'visibility-off', 'watch-later',\n 'youtube-searched-for', 'aspect-ratio', 'assignment', 'assignment-ind',\n 'assignment-late', 'assignment-return', 'assignment-returned', 'assignment-turned-in',\n 'backup', 'book', 'flight-takeoff', 'flight-land',\n] as const;\n\n/**\n * Get all available Astro icon names\n */\nexport function getAstroIconNames(): readonly string[] {\n return ASTRO_ICON_NAMES;\n}\n\n/**\n * Get all available icon names including aliases\n */\nexport function getAllIconNames(): { icons: readonly string[]; aliases: Record<string, string> } {\n return {\n icons: ASTRO_ICON_NAMES,\n aliases: ICON_ALIASES,\n };\n}\n\n// Global state for RuxIcon loading with subscription pattern\ntype LoadState = 'pending' | 'loading' | 'loaded' | 'failed';\nlet loadState: LoadState = 'pending';\nlet RuxIconComponent: React.ComponentType<any> | null = null;\nconst subscribers = new Set<() => void>();\n\nfunction subscribe(callback: () => void) {\n subscribers.add(callback);\n return () => subscribers.delete(callback);\n}\n\nfunction notifySubscribers() {\n subscribers.forEach(cb => cb());\n}\n\n/**\n * Safely load RuxIcon from @astrouxds/react\n * Returns null if not available\n */\nasync function loadRuxIcon(): Promise<React.ComponentType<any> | null> {\n if (loadState === 'loaded') {\n return RuxIconComponent;\n }\n \n if (loadState === 'failed') {\n return null;\n }\n \n if (loadState === 'loading') {\n // Wait for the existing load to complete\n return new Promise(resolve => {\n const unsub = subscribe(() => {\n unsub();\n resolve(RuxIconComponent);\n });\n });\n }\n \n loadState = 'loading';\n \n try {\n // Dynamic import for tree-shaking and optional dependency\n const astroModule = await import('@astrouxds/react');\n RuxIconComponent = astroModule.RuxIcon;\n loadState = 'loaded';\n notifySubscribers();\n return RuxIconComponent;\n } catch (err) {\n loadState = 'failed';\n notifySubscribers();\n return null;\n }\n}\n\n/**\n * Fallback icon component when @astrouxds/react is not installed.\n * Uses built-in Icon SVGs when the name matches, otherwise shows a generic placeholder.\n */\nfunction FallbackIcon({\n name,\n size,\n color,\n label,\n className,\n style,\n onClick,\n 'data-testid': testId,\n}: AstroIconProps) {\n const { tokens } = useTheme();\n const actualSize = typeof size === 'number' ? size : SIZE_MAP[size || 'normal'];\n\n if (isValidIconName(name)) {\n return (\n <Icon\n name={name}\n size={actualSize}\n color={color}\n className={className}\n aria-label={label || name}\n onClick={onClick}\n style={style}\n />\n );\n }\n\n return (\n <span\n role=\"img\"\n aria-label={label || name}\n className={className}\n data-testid={testId}\n onClick={onClick}\n tabIndex={onClick ? 0 : undefined}\n onKeyDown={onClick ? (e) => e.key === 'Enter' && onClick() : undefined}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: actualSize,\n height: actualSize,\n fontSize: actualSize * 0.4,\n fontFamily: tokens.typography.fontFamily.mono,\n fontWeight: 700,\n color: color || tokens.colors.status.off,\n backgroundColor: tokens.colors.background.surface,\n border: `1px solid ${tokens.colors.border.default}`,\n borderRadius: 4,\n cursor: onClick ? 'pointer' : 'default',\n userSelect: 'none',\n ...style,\n }}\n title={`Icon: ${name} (install @astrouxds/react for official icons)`}\n >\n <svg\n width={actualSize * 0.6}\n height={actualSize * 0.6}\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <circle cx=\"12\" cy=\"12\" r=\"2\" fill=\"currentColor\" />\n </svg>\n </span>\n );\n}\n\n/**\n * AstroIcon - Official Astro UXD Icons\n * \n * Displays icons from the official Astro UX Design System.\n * Automatically uses @astrouxds/react if installed, otherwise shows fallback.\n * \n * @example\n * ```tsx\n * // Basic usage\n * <AstroIcon name=\"satellite\" />\n * \n * // With size\n * <AstroIcon name=\"antenna\" size=\"large\" />\n * <AstroIcon name=\"thermal\" size={48} />\n * \n * // With color\n * <AstroIcon name=\"warning\" color=\"var(--color-status-caution)\" />\n * \n * // With click handler\n * <AstroIcon name=\"settings\" onClick={() => openSettings()} />\n * ```\n */\nexport const AstroIcon = memo(function AstroIcon(props: AstroIconProps) {\n const {\n name,\n size = 'normal',\n color,\n label,\n className,\n style,\n onClick,\n 'data-testid': testId,\n } = props;\n \n const [, forceUpdate] = useState(0);\n const [currentState, setCurrentState] = useState(loadState);\n const mountedRef = useRef(true);\n \n // Subscribe to load state changes and trigger loading\n useEffect(() => {\n mountedRef.current = true;\n \n // Subscribe to state changes\n const unsubscribe = subscribe(() => {\n if (mountedRef.current) {\n setCurrentState(loadState);\n forceUpdate(n => n + 1);\n }\n });\n \n // Trigger load if not yet started\n if (loadState === 'pending') {\n loadRuxIcon();\n }\n \n return () => {\n mountedRef.current = false;\n unsubscribe();\n };\n }, []);\n \n // If still loading, show a subtle placeholder\n if (currentState === 'pending' || currentState === 'loading') {\n const actualSize = typeof size === 'number' ? size : SIZE_MAP[size];\n return (\n <span\n style={{\n display: 'inline-block',\n width: actualSize,\n height: actualSize,\n ...style,\n }}\n className={className}\n aria-hidden=\"true\"\n />\n );\n }\n \n // Resolve icon alias to actual Astro icon name\n const resolvedName = resolveIconAlias(name);\n \n // If @astrouxds/react is available, use official RuxIcon\n if (RuxIconComponent) {\n const RuxIcon = RuxIconComponent;\n const pixelSize = typeof size === 'number' ? size : SIZE_MAP[size];\n \n // Map numeric size to closest Astro size preset for RuxIcon\n // This helps RuxIcon render at approximately the right size before CSS kicks in\n const getClosestAstroSize = (px: number): AstroIconSize => {\n if (px <= 18) return 'extra-small'; // 16px\n if (px <= 28) return 'small'; // 24px\n if (px <= 40) return 'normal'; // 32px\n return 'large'; // 48px\n };\n const astroSize = typeof size === 'number' ? getClosestAstroSize(size) : size;\n \n // Default to off/grey color if no color specified\n const iconColor = color || 'var(--color-status-off, #a4abb6)';\n \n return (\n <span\n role=\"img\"\n aria-label={label || name}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: pixelSize,\n height: pixelSize,\n minWidth: pixelSize,\n minHeight: pixelSize,\n flexShrink: 0,\n // Don't use overflow:hidden - it clips the icon SVG\n ...style,\n }}\n className={className}\n >\n <RuxIcon\n icon={resolvedName}\n size={astroSize}\n label={label || name}\n data-testid={testId}\n onClick={onClick}\n style={{\n // Force the RuxIcon to respect our exact pixel size\n '--iconDefaultSize': `${pixelSize}px`,\n '--iconSize': `${pixelSize}px`,\n '--size': `${pixelSize}px`,\n color: iconColor,\n width: `${pixelSize}px`,\n height: `${pixelSize}px`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n ...(onClick && { cursor: 'pointer' }),\n } as React.CSSProperties}\n />\n </span>\n );\n }\n \n // Fallback when @astrouxds/react is not installed\n return <FallbackIcon {...props} name={resolvedName} />;\n});\n\n/**\n * Check if @astrouxds/react is available\n * Useful for conditional rendering or feature detection\n */\nexport function isAstroIconsAvailable(): boolean {\n return loadState === 'loaded' && RuxIconComponent !== null;\n}\n\n/**\n * Preload the Astro icons module\n * Call this early in your app to ensure icons are ready\n */\nexport async function preloadAstroIcons(): Promise<boolean> {\n const component = await loadRuxIcon();\n return component !== null;\n}\n\nexport default AstroIcon;\n"],"names":["AstroIcon"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { memo } from "react";
|
|
3
|
-
import { classNames } from "
|
|
4
|
-
import { useTheme } from "
|
|
3
|
+
import { classNames } from "../../utils/index.js";
|
|
4
|
+
import { useTheme } from "../../theme/ThemeProvider.js";
|
|
5
5
|
const Badge = memo(function Badge2({
|
|
6
6
|
variant = "filled",
|
|
7
7
|
size = "small",
|