@zendir/ui 0.1.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 +19 -0
- package/LICENSE +21 -0
- package/README.md +589 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +421 -0
- package/dist/index.js.map +1 -0
- package/dist/react/3d/EarthViewer.d.ts +46 -0
- package/dist/react/3d/EarthViewer.js +836 -0
- package/dist/react/3d/EarthViewer.js.map +1 -0
- package/dist/react/3d/SolarSystemViewer.d.ts +43 -0
- package/dist/react/3d/SolarSystemViewer.js +372 -0
- package/dist/react/3d/SolarSystemViewer.js.map +1 -0
- package/dist/react/3d/ZenSpace3D.d.ts +16 -0
- package/dist/react/3d/ZenSpace3D.js +1253 -0
- package/dist/react/3d/ZenSpace3D.js.map +1 -0
- package/dist/react/3d/ZenSpace3DCesium.d.ts +9 -0
- package/dist/react/3d/ZenSpace3DCesium.js +186 -0
- package/dist/react/3d/ZenSpace3DCesium.js.map +1 -0
- package/dist/react/3d/ZenSpace3DShaders.d.ts +78 -0
- package/dist/react/3d/ZenSpace3DShaders.js +94 -0
- package/dist/react/3d/ZenSpace3DShaders.js.map +1 -0
- package/dist/react/3d/ZenSpace3DTypes.d.ts +614 -0
- package/dist/react/3d/ZenSpace3DUtils.d.ts +183 -0
- package/dist/react/3d/ZenSpace3DUtils.js +213 -0
- package/dist/react/3d/ZenSpace3DUtils.js.map +1 -0
- package/dist/react/3d/index.d.ts +23 -0
- package/dist/react/3d/threeLoader.d.ts +22 -0
- package/dist/react/3d/threeLoader.js +18 -0
- package/dist/react/3d/threeLoader.js.map +1 -0
- package/dist/react/astro/ClassificationBanner.d.ts +25 -0
- package/dist/react/astro/ClassificationBanner.js +83 -0
- package/dist/react/astro/ClassificationBanner.js.map +1 -0
- package/dist/react/astro/GlobalStatusBar.d.ts +42 -0
- package/dist/react/astro/GlobalStatusBar.js +165 -0
- package/dist/react/astro/GlobalStatusBar.js.map +1 -0
- package/dist/react/astro/MissionClock.d.ts +169 -0
- package/dist/react/astro/MissionClock.js +411 -0
- package/dist/react/astro/MissionClock.js.map +1 -0
- package/dist/react/astro/MonitoringIcon.d.ts +60 -0
- package/dist/react/astro/MonitoringIcon.js +369 -0
- package/dist/react/astro/MonitoringIcon.js.map +1 -0
- package/dist/react/astro/Notification.d.ts +42 -0
- package/dist/react/astro/Notification.js +156 -0
- package/dist/react/astro/Notification.js.map +1 -0
- package/dist/react/astro/Progress.d.ts +39 -0
- package/dist/react/astro/Progress.js +149 -0
- package/dist/react/astro/Progress.js.map +1 -0
- package/dist/react/astro/SimulationControls.d.ts +136 -0
- package/dist/react/astro/SimulationControls.js +668 -0
- package/dist/react/astro/SimulationControls.js.map +1 -0
- package/dist/react/astro/StatusIndicator.d.ts +34 -0
- package/dist/react/astro/StatusIndicator.js +189 -0
- package/dist/react/astro/StatusIndicator.js.map +1 -0
- package/dist/react/astro/UnifiedTimeline.d.ts +106 -0
- package/dist/react/astro/UnifiedTimeline.js +1768 -0
- package/dist/react/astro/UnifiedTimeline.js.map +1 -0
- package/dist/react/astro/index.d.ts +63 -0
- package/dist/react/cards/AccessCard.d.ts +37 -0
- package/dist/react/cards/AccessCard.js +410 -0
- package/dist/react/cards/AccessCard.js.map +1 -0
- package/dist/react/cards/OrbitCard.d.ts +31 -0
- package/dist/react/cards/OrbitCard.js +372 -0
- package/dist/react/cards/OrbitCard.js.map +1 -0
- package/dist/react/cards/SpacecraftCard.d.ts +54 -0
- package/dist/react/cards/SpacecraftCard.js +941 -0
- package/dist/react/cards/SpacecraftCard.js.map +1 -0
- package/dist/react/cards/TelemetryCard.d.ts +40 -0
- package/dist/react/cards/TelemetryCard.js +742 -0
- package/dist/react/cards/TelemetryCard.js.map +1 -0
- package/dist/react/cards/TelemetryStreamCard.d.ts +59 -0
- package/dist/react/cards/TelemetryStreamCard.js +309 -0
- package/dist/react/cards/TelemetryStreamCard.js.map +1 -0
- package/dist/react/cards/index.d.ts +13 -0
- package/dist/react/charts/GroundTrackMap.d.ts +112 -0
- package/dist/react/charts/GroundTrackMap.js +1123 -0
- package/dist/react/charts/GroundTrackMap.js.map +1 -0
- package/dist/react/charts/GroundTrackMapLeaflet.d.ts +26 -0
- package/dist/react/charts/GroundTrackMapLeaflet.js +571 -0
- package/dist/react/charts/GroundTrackMapLeaflet.js.map +1 -0
- package/dist/react/charts/groundTrackMapLeafletTiles.d.ts +22 -0
- package/dist/react/charts/groundTrackMapLeafletTiles.js +11 -0
- package/dist/react/charts/groundTrackMapLeafletTiles.js.map +1 -0
- package/dist/react/charts/groundTrackMapLeafletUtils.d.ts +24 -0
- package/dist/react/charts/groundTrackMapLeafletUtils.js +109 -0
- package/dist/react/charts/groundTrackMapLeafletUtils.js.map +1 -0
- package/dist/react/charts/index.d.ts +10 -0
- package/dist/react/charts/unified/AstroChart.d.ts +24 -0
- package/dist/react/charts/unified/AstroChart.js +1405 -0
- package/dist/react/charts/unified/AstroChart.js.map +1 -0
- package/dist/react/charts/unified/PowerOverviewChart.d.ts +73 -0
- package/dist/react/charts/unified/PowerOverviewChart.js +488 -0
- package/dist/react/charts/unified/PowerOverviewChart.js.map +1 -0
- package/dist/react/charts/unified/domain.d.ts +845 -0
- package/dist/react/charts/unified/domain.js +3168 -0
- package/dist/react/charts/unified/domain.js.map +1 -0
- package/dist/react/charts/unified/generators.d.ts +276 -0
- package/dist/react/charts/unified/generators.js +518 -0
- package/dist/react/charts/unified/generators.js.map +1 -0
- package/dist/react/charts/unified/index.d.ts +55 -0
- package/dist/react/charts/unified/presets.d.ts +290 -0
- package/dist/react/charts/unified/presets.js +999 -0
- package/dist/react/charts/unified/presets.js.map +1 -0
- package/dist/react/charts/unified/sync.d.ts +69 -0
- package/dist/react/charts/unified/sync.js +219 -0
- package/dist/react/charts/unified/sync.js.map +1 -0
- package/dist/react/charts/unified/theme.d.ts +447 -0
- package/dist/react/charts/unified/theme.js +562 -0
- package/dist/react/charts/unified/theme.js.map +1 -0
- package/dist/react/charts/unified/types.d.ts +826 -0
- package/dist/react/charts/unified/useChartStream.d.ts +58 -0
- package/dist/react/charts/unified/useChartStream.js +226 -0
- package/dist/react/charts/unified/useChartStream.js.map +1 -0
- package/dist/react/chatgpt/AppCard.d.ts +59 -0
- package/dist/react/chatgpt/AppCard.js +306 -0
- package/dist/react/chatgpt/AppCard.js.map +1 -0
- package/dist/react/chatgpt/ChatGPTCard.d.ts +6 -0
- package/dist/react/chatgpt/index.d.ts +167 -0
- package/dist/react/chatgpt/index.js +166 -0
- package/dist/react/chatgpt/index.js.map +1 -0
- package/dist/react/context/DisplaySettingsContext.d.ts +107 -0
- package/dist/react/context/DisplaySettingsContext.js +169 -0
- package/dist/react/context/DisplaySettingsContext.js.map +1 -0
- package/dist/react/context/index.d.ts +5 -0
- package/dist/react/core/ActivityPlanner.d.ts +45 -0
- package/dist/react/core/ActivityPlanner.js +532 -0
- package/dist/react/core/ActivityPlanner.js.map +1 -0
- package/dist/react/core/AppBar.d.ts +71 -0
- package/dist/react/core/AppBar.js +817 -0
- package/dist/react/core/AppBar.js.map +1 -0
- package/dist/react/core/AstroIcon.d.ts +84 -0
- package/dist/react/core/AstroIcon.js +1243 -0
- package/dist/react/core/AstroIcon.js.map +1 -0
- package/dist/react/core/Badge.d.ts +27 -0
- package/dist/react/core/Badge.js +134 -0
- package/dist/react/core/Badge.js.map +1 -0
- package/dist/react/core/Button.d.ts +26 -0
- package/dist/react/core/Button.js +306 -0
- package/dist/react/core/Button.js.map +1 -0
- package/dist/react/core/CardHeader.d.ts +34 -0
- package/dist/react/core/CardHeader.js +316 -0
- package/dist/react/core/CardHeader.js.map +1 -0
- package/dist/react/core/ChatPanel.d.ts +627 -0
- package/dist/react/core/ChatPanel.js +1144 -0
- package/dist/react/core/ChatPanel.js.map +1 -0
- package/dist/react/core/Checkbox.d.ts +26 -0
- package/dist/react/core/Checkbox.js +130 -0
- package/dist/react/core/Checkbox.js.map +1 -0
- package/dist/react/core/ColorPickerPanel.d.ts +25 -0
- package/dist/react/core/ColorPickerPanel.js +293 -0
- package/dist/react/core/ColorPickerPanel.js.map +1 -0
- package/dist/react/core/CommandBuilder.d.ts +74 -0
- package/dist/react/core/CommandBuilder.js +518 -0
- package/dist/react/core/CommandBuilder.js.map +1 -0
- package/dist/react/core/ConfirmDialog.d.ts +45 -0
- package/dist/react/core/ConfirmDialog.js +315 -0
- package/dist/react/core/ConfirmDialog.js.map +1 -0
- package/dist/react/core/ConnectionForm.d.ts +57 -0
- package/dist/react/core/ConnectionForm.js +496 -0
- package/dist/react/core/ConnectionForm.js.map +1 -0
- package/dist/react/core/Container.d.ts +51 -0
- package/dist/react/core/Container.js +670 -0
- package/dist/react/core/Container.js.map +1 -0
- package/dist/react/core/CopyButton.d.ts +39 -0
- package/dist/react/core/CopyButton.js +105 -0
- package/dist/react/core/CopyButton.js.map +1 -0
- package/dist/react/core/DataTable.d.ts +113 -0
- package/dist/react/core/DataTable.js +446 -0
- package/dist/react/core/DataTable.js.map +1 -0
- package/dist/react/core/DataValue.d.ts +64 -0
- package/dist/react/core/DataValue.js +545 -0
- package/dist/react/core/DataValue.js.map +1 -0
- package/dist/react/core/Dialog.d.ts +32 -0
- package/dist/react/core/Dialog.js +201 -0
- package/dist/react/core/Dialog.js.map +1 -0
- package/dist/react/core/FileExplorer.d.ts +65 -0
- package/dist/react/core/FileExplorer.js +520 -0
- package/dist/react/core/FileExplorer.js.map +1 -0
- package/dist/react/core/GlassCard.d.ts +129 -0
- package/dist/react/core/GlassCard.js +375 -0
- package/dist/react/core/GlassCard.js.map +1 -0
- package/dist/react/core/HeaderIconWithStatus.d.ts +39 -0
- package/dist/react/core/HeaderIconWithStatus.js +157 -0
- package/dist/react/core/HeaderIconWithStatus.js.map +1 -0
- package/dist/react/core/HexViewer.d.ts +143 -0
- package/dist/react/core/HexViewer.js +1106 -0
- package/dist/react/core/HexViewer.js.map +1 -0
- package/dist/react/core/Icon.d.ts +32 -0
- package/dist/react/core/Icon.js +142 -0
- package/dist/react/core/Icon.js.map +1 -0
- package/dist/react/core/ImageGallery.d.ts +41 -0
- package/dist/react/core/ImageGallery.js +320 -0
- package/dist/react/core/ImageGallery.js.map +1 -0
- package/dist/react/core/Input.d.ts +38 -0
- package/dist/react/core/Input.js +288 -0
- package/dist/react/core/Input.js.map +1 -0
- package/dist/react/core/LimitsBar.d.ts +51 -0
- package/dist/react/core/LimitsBar.js +200 -0
- package/dist/react/core/LimitsBar.js.map +1 -0
- package/dist/react/core/LogViewer.d.ts +61 -0
- package/dist/react/core/LogViewer.js +599 -0
- package/dist/react/core/LogViewer.js.map +1 -0
- package/dist/react/core/MessageStream.d.ts +58 -0
- package/dist/react/core/MessageStream.js +455 -0
- package/dist/react/core/MessageStream.js.map +1 -0
- package/dist/react/core/MissionCalendar.d.ts +81 -0
- package/dist/react/core/MissionCalendar.js +1049 -0
- package/dist/react/core/MissionCalendar.js.map +1 -0
- package/dist/react/core/NumberInput.d.ts +85 -0
- package/dist/react/core/NumberInput.js +507 -0
- package/dist/react/core/NumberInput.js.map +1 -0
- package/dist/react/core/PacketViewer.d.ts +73 -0
- package/dist/react/core/PacketViewer.js +431 -0
- package/dist/react/core/PacketViewer.js.map +1 -0
- package/dist/react/core/Pagination.d.ts +30 -0
- package/dist/react/core/Pagination.js +190 -0
- package/dist/react/core/Pagination.js.map +1 -0
- package/dist/react/core/PinInput.d.ts +41 -0
- package/dist/react/core/PinInput.js +210 -0
- package/dist/react/core/PinInput.js.map +1 -0
- package/dist/react/core/Popover.d.ts +55 -0
- package/dist/react/core/Popover.js +288 -0
- package/dist/react/core/Popover.js.map +1 -0
- package/dist/react/core/Select.d.ts +42 -0
- package/dist/react/core/Select.js +303 -0
- package/dist/react/core/Select.js.map +1 -0
- package/dist/react/core/SideNav.d.ts +103 -0
- package/dist/react/core/SideNav.js +551 -0
- package/dist/react/core/SideNav.js.map +1 -0
- package/dist/react/core/SidePanel.d.ts +33 -0
- package/dist/react/core/SidePanel.js +199 -0
- package/dist/react/core/SidePanel.js.map +1 -0
- package/dist/react/core/Tabs.d.ts +47 -0
- package/dist/react/core/Tabs.js +129 -0
- package/dist/react/core/Tabs.js.map +1 -0
- package/dist/react/core/Toast.d.ts +56 -0
- package/dist/react/core/Toast.js +229 -0
- package/dist/react/core/Toast.js.map +1 -0
- package/dist/react/core/Toggle.d.ts +22 -0
- package/dist/react/core/Toggle.js +151 -0
- package/dist/react/core/Toggle.js.map +1 -0
- package/dist/react/core/Tooltip.d.ts +19 -0
- package/dist/react/core/Tooltip.js +179 -0
- package/dist/react/core/Tooltip.js.map +1 -0
- package/dist/react/core/Typography.d.ts +127 -0
- package/dist/react/core/Typography.js +187 -0
- package/dist/react/core/Typography.js.map +1 -0
- package/dist/react/core/index.d.ts +108 -0
- package/dist/react/core/layout/Box.d.ts +77 -0
- package/dist/react/core/layout/Box.js +126 -0
- package/dist/react/core/layout/Box.js.map +1 -0
- package/dist/react/core/layout/Center.d.ts +20 -0
- package/dist/react/core/layout/Center.js +34 -0
- package/dist/react/core/layout/Center.js.map +1 -0
- package/dist/react/core/layout/Divider.d.ts +16 -0
- package/dist/react/core/layout/Divider.js +108 -0
- package/dist/react/core/layout/Divider.js.map +1 -0
- package/dist/react/core/layout/Flex.d.ts +30 -0
- package/dist/react/core/layout/Flex.js +128 -0
- package/dist/react/core/layout/Flex.js.map +1 -0
- package/dist/react/core/layout/Grid.d.ts +36 -0
- package/dist/react/core/layout/Grid.js +142 -0
- package/dist/react/core/layout/Grid.js.map +1 -0
- package/dist/react/core/layout/Spacer.d.ts +8 -0
- package/dist/react/core/layout/Spacer.js +31 -0
- package/dist/react/core/layout/Spacer.js.map +1 -0
- package/dist/react/core/layout/Stack.d.ts +54 -0
- package/dist/react/core/layout/Stack.js +74 -0
- package/dist/react/core/layout/Stack.js.map +1 -0
- package/dist/react/core/layout/index.d.ts +38 -0
- package/dist/react/core/layout/responsive.d.ts +23 -0
- package/dist/react/core/layout/responsive.js +26 -0
- package/dist/react/core/layout/responsive.js.map +1 -0
- package/dist/react/core/layout/useBreakpoint.d.ts +77 -0
- package/dist/react/core/layout/useBreakpoint.js +73 -0
- package/dist/react/core/layout/useBreakpoint.js.map +1 -0
- package/dist/react/core/propertyConfig.d.ts +443 -0
- package/dist/react/core/propertyConfig.js +399 -0
- package/dist/react/core/propertyConfig.js.map +1 -0
- package/dist/react/hooks/index.d.ts +21 -0
- package/dist/react/hooks/useAccessWindows.d.ts +66 -0
- package/dist/react/hooks/useCompactMode.d.ts +82 -0
- package/dist/react/hooks/useCompactMode.js +62 -0
- package/dist/react/hooks/useCompactMode.js.map +1 -0
- package/dist/react/hooks/useLiveSelection.d.ts +57 -0
- package/dist/react/hooks/useSimulationPlayback.d.ts +97 -0
- package/dist/react/hooks/useSimulationTime.d.ts +61 -0
- package/dist/react/hooks/useSpacecraftPosition.d.ts +50 -0
- package/dist/react/hooks/useSpacecraftPosition.js +89 -0
- package/dist/react/hooks/useSpacecraftPosition.js.map +1 -0
- package/dist/react/hooks/useTelemetry.d.ts +55 -0
- package/dist/react/hooks/useTelemetry.js +73 -0
- package/dist/react/hooks/useTelemetry.js.map +1 -0
- package/dist/react/hooks/useZendirSession.d.ts +109 -0
- package/dist/react/hooks/useZendirSession.js +148 -0
- package/dist/react/hooks/useZendirSession.js.map +1 -0
- package/dist/react/index.d.ts +74 -0
- package/dist/react/shared/ErrorBoundary.d.ts +63 -0
- package/dist/react/shared/ErrorBoundary.js +142 -0
- package/dist/react/shared/ErrorBoundary.js.map +1 -0
- package/dist/react/shared/Skeleton.d.ts +110 -0
- package/dist/react/shared/Skeleton.js +324 -0
- package/dist/react/shared/Skeleton.js.map +1 -0
- package/dist/react/shared/index.d.ts +12 -0
- package/dist/react/theme/ThemeProvider.d.ts +385 -0
- package/dist/react/theme/ThemeProvider.js +1096 -0
- package/dist/react/theme/ThemeProvider.js.map +1 -0
- package/dist/react/theme/astro-tokens.d.ts +153 -0
- package/dist/react/theme/cardAccent.d.ts +75 -0
- package/dist/react/theme/cardAccent.js +137 -0
- package/dist/react/theme/cardAccent.js.map +1 -0
- package/dist/react/theme/config.d.ts +39 -0
- package/dist/react/theme/index.d.ts +9 -0
- package/dist/react/types.d.ts +360 -0
- package/dist/react/types.js +58 -0
- package/dist/react/types.js.map +1 -0
- package/dist/react/utils/index.d.ts +247 -0
- package/dist/react/utils/index.js +423 -0
- package/dist/react/utils/index.js.map +1 -0
- package/dist/react/visualizations/EclipseTimerCard.d.ts +17 -0
- package/dist/react/visualizations/EclipseTimerCard.js +250 -0
- package/dist/react/visualizations/EclipseTimerCard.js.map +1 -0
- package/dist/react/visualizations/LinkBudgetCard.d.ts +50 -0
- package/dist/react/visualizations/LinkBudgetCard.js +444 -0
- package/dist/react/visualizations/LinkBudgetCard.js.map +1 -0
- package/dist/react/visualizations/NavBallCard.d.ts +17 -0
- package/dist/react/visualizations/NavBallCard.js +243 -0
- package/dist/react/visualizations/NavBallCard.js.map +1 -0
- package/dist/react/visualizations/PropulsionCard.d.ts +37 -0
- package/dist/react/visualizations/PropulsionCard.js +298 -0
- package/dist/react/visualizations/PropulsionCard.js.map +1 -0
- package/dist/react/visualizations/SensorFootprintCard.d.ts +33 -0
- package/dist/react/visualizations/SensorFootprintCard.js +326 -0
- package/dist/react/visualizations/SensorFootprintCard.js.map +1 -0
- package/dist/react/visualizations/ThermalHeatmapCard.d.ts +38 -0
- package/dist/react/visualizations/ThermalHeatmapCard.js +372 -0
- package/dist/react/visualizations/ThermalHeatmapCard.js.map +1 -0
- package/dist/react/visualizations/index.d.ts +17 -0
- package/dist/react.d.ts +1 -0
- package/dist/react.js +421 -0
- package/dist/react.js.map +1 -0
- 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 +143 -0
- package/dist/tokens/index.d.ts +296 -0
- package/dist/tokens/index.js +263 -0
- package/dist/tokens/index.js.map +1 -0
- package/dist/tokens/tokens.css +155 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +220 -0
- package/sdk-stub.js +22 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Component, useRef } from "react";
|
|
3
|
+
import { useChatGPTTheme, useDisplayMode, useMaxHeight, isInChatGPT } from "./index.js";
|
|
4
|
+
import { FONT_FAMILY_PRIMARY } from "../core/Typography.js";
|
|
5
|
+
const STATUS_COLORS_INTERNAL = {
|
|
6
|
+
off: "#a4abb6",
|
|
7
|
+
standby: "#2dccff",
|
|
8
|
+
normal: "#56f000",
|
|
9
|
+
caution: "#fce83a",
|
|
10
|
+
serious: "#ffb302",
|
|
11
|
+
critical: "#ff3838"
|
|
12
|
+
};
|
|
13
|
+
function StatusShape({ status, size = 10 }) {
|
|
14
|
+
const color = STATUS_COLORS_INTERNAL[status] ?? STATUS_COLORS_INTERNAL.off;
|
|
15
|
+
const glow = `${color}50`;
|
|
16
|
+
switch (status) {
|
|
17
|
+
case "caution":
|
|
18
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", width: size, height: size, style: { filter: `drop-shadow(0 0 3px ${glow})` }, "aria-hidden": "true", children: /* @__PURE__ */ jsx("rect", { x: "1", y: "1", width: "10", height: "10", fill: color }) });
|
|
19
|
+
case "serious":
|
|
20
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", width: size, height: size, style: { filter: `drop-shadow(0 0 3px ${glow})` }, "aria-hidden": "true", children: /* @__PURE__ */ jsx("polygon", { points: "6,1 11,6 6,11 1,6", fill: color }) });
|
|
21
|
+
case "critical":
|
|
22
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", width: size, height: size, style: { filter: `drop-shadow(0 0 3px ${glow})` }, "aria-hidden": "true", children: /* @__PURE__ */ jsx("polygon", { points: "6,11 1,2 11,2", fill: color }) });
|
|
23
|
+
case "standby":
|
|
24
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", width: size, height: size, style: { filter: `drop-shadow(0 0 3px ${glow})` }, "aria-hidden": "true", children: /* @__PURE__ */ jsx("circle", { cx: "6", cy: "6", r: "3.5", fill: "none", stroke: color, strokeWidth: "2" }) });
|
|
25
|
+
case "off":
|
|
26
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", width: size, height: size, style: { filter: `drop-shadow(0 0 3px ${glow})` }, "aria-hidden": "true", children: /* @__PURE__ */ jsx("circle", { cx: "6", cy: "6", r: "3", fill: color }) });
|
|
27
|
+
default:
|
|
28
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", width: size, height: size, style: { filter: `drop-shadow(0 0 3px ${glow})` }, "aria-hidden": "true", children: /* @__PURE__ */ jsx("circle", { cx: "6", cy: "6", r: "5", fill: color }) });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const LEGACY_VARIANT_MAP = {
|
|
32
|
+
success: "normal",
|
|
33
|
+
warning: "caution",
|
|
34
|
+
error: "critical",
|
|
35
|
+
info: "standby",
|
|
36
|
+
neutral: "off"
|
|
37
|
+
};
|
|
38
|
+
function resolveStatusLevel(input) {
|
|
39
|
+
if (["off", "standby", "normal", "caution", "serious", "critical"].includes(input)) {
|
|
40
|
+
return input;
|
|
41
|
+
}
|
|
42
|
+
return LEGACY_VARIANT_MAP[input] ?? "off";
|
|
43
|
+
}
|
|
44
|
+
class CardErrorBoundary extends Component {
|
|
45
|
+
constructor(props) {
|
|
46
|
+
super(props);
|
|
47
|
+
this.state = { hasError: false };
|
|
48
|
+
}
|
|
49
|
+
static getDerivedStateFromError(error) {
|
|
50
|
+
return { hasError: true, error };
|
|
51
|
+
}
|
|
52
|
+
render() {
|
|
53
|
+
var _a;
|
|
54
|
+
if (this.state.hasError) {
|
|
55
|
+
return /* @__PURE__ */ jsxs(
|
|
56
|
+
"div",
|
|
57
|
+
{
|
|
58
|
+
style: {
|
|
59
|
+
padding: "16px",
|
|
60
|
+
borderRadius: "12px",
|
|
61
|
+
background: "rgba(255, 56, 56, 0.08)",
|
|
62
|
+
border: "1px solid rgba(255, 56, 56, 0.3)",
|
|
63
|
+
fontFamily: FONT_FAMILY_PRIMARY,
|
|
64
|
+
color: "#ff8a8a"
|
|
65
|
+
// WCAG AA: lighter red for readable text on dark error background
|
|
66
|
+
},
|
|
67
|
+
role: "alert",
|
|
68
|
+
children: [
|
|
69
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "8px" }, children: [
|
|
70
|
+
/* @__PURE__ */ jsx(StatusShape, { status: "critical", size: 12 }),
|
|
71
|
+
/* @__PURE__ */ jsxs("strong", { style: { fontSize: "0.875rem" }, children: [
|
|
72
|
+
this.props.componentName ?? "Widget",
|
|
73
|
+
" Error"
|
|
74
|
+
] })
|
|
75
|
+
] }),
|
|
76
|
+
/* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: "0.75rem", opacity: 0.8 }, children: ((_a = this.state.error) == null ? void 0 : _a.message) ?? "An unexpected error occurred." })
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return this.props.children;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function LoadingSkeleton({ compact, isDark }) {
|
|
85
|
+
const bar = (w, h = 12) => ({
|
|
86
|
+
width: w,
|
|
87
|
+
height: h,
|
|
88
|
+
borderRadius: 4,
|
|
89
|
+
background: isDark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)",
|
|
90
|
+
animation: "chatgpt-card-pulse 1.5s ease-in-out infinite"
|
|
91
|
+
});
|
|
92
|
+
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: compact ? 8 : 12 }, "aria-label": "Loading...", role: "status", children: [
|
|
93
|
+
/* @__PURE__ */ jsx("div", { style: bar("70%", 14) }),
|
|
94
|
+
/* @__PURE__ */ jsx("div", { style: bar("100%") }),
|
|
95
|
+
/* @__PURE__ */ jsx("div", { style: bar("85%") }),
|
|
96
|
+
/* @__PURE__ */ jsx("div", { style: bar("60%") }),
|
|
97
|
+
/* @__PURE__ */ jsx("style", { children: `@keyframes chatgpt-card-pulse { 0%,100% { opacity: 0.4 } 50% { opacity: 1 } }` })
|
|
98
|
+
] });
|
|
99
|
+
}
|
|
100
|
+
function ErrorDisplay({ error, onRetry, isDark }) {
|
|
101
|
+
const message = typeof error === "string" ? error : error.message;
|
|
102
|
+
return /* @__PURE__ */ jsxs(
|
|
103
|
+
"div",
|
|
104
|
+
{
|
|
105
|
+
role: "alert",
|
|
106
|
+
style: {
|
|
107
|
+
display: "flex",
|
|
108
|
+
flexDirection: "column",
|
|
109
|
+
gap: 8,
|
|
110
|
+
padding: "12px",
|
|
111
|
+
borderRadius: 8,
|
|
112
|
+
background: "rgba(255, 56, 56, 0.08)",
|
|
113
|
+
border: "1px solid rgba(255, 56, 56, 0.2)"
|
|
114
|
+
},
|
|
115
|
+
children: [
|
|
116
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
117
|
+
/* @__PURE__ */ jsx(StatusShape, { status: "critical", size: 12 }),
|
|
118
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: "0.75rem", fontWeight: 500, color: "#ff8a8a" }, children: message })
|
|
119
|
+
] }),
|
|
120
|
+
onRetry && /* @__PURE__ */ jsx(
|
|
121
|
+
"button",
|
|
122
|
+
{
|
|
123
|
+
onClick: onRetry,
|
|
124
|
+
style: {
|
|
125
|
+
alignSelf: "flex-start",
|
|
126
|
+
padding: "4px 12px",
|
|
127
|
+
borderRadius: 4,
|
|
128
|
+
border: `1px solid ${isDark ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`,
|
|
129
|
+
background: "transparent",
|
|
130
|
+
color: isDark ? "#a1a1aa" : "#636370",
|
|
131
|
+
// WCAG AA compliant on light backgrounds
|
|
132
|
+
cursor: "pointer",
|
|
133
|
+
fontSize: "0.6875rem",
|
|
134
|
+
fontFamily: FONT_FAMILY_PRIMARY
|
|
135
|
+
},
|
|
136
|
+
"aria-label": "Retry loading widget",
|
|
137
|
+
children: "Retry"
|
|
138
|
+
}
|
|
139
|
+
)
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
const AppCardInner = ({
|
|
145
|
+
children,
|
|
146
|
+
title,
|
|
147
|
+
subtitle,
|
|
148
|
+
status,
|
|
149
|
+
allowFullscreen = false,
|
|
150
|
+
onFullscreenChange,
|
|
151
|
+
className = "",
|
|
152
|
+
compact = false,
|
|
153
|
+
icon,
|
|
154
|
+
footer,
|
|
155
|
+
actions,
|
|
156
|
+
loading = false,
|
|
157
|
+
error,
|
|
158
|
+
onRetry,
|
|
159
|
+
style
|
|
160
|
+
}) => {
|
|
161
|
+
const containerRef = useRef(null);
|
|
162
|
+
const { isDark, colors } = useChatGPTTheme();
|
|
163
|
+
const { mode, requestMode } = useDisplayMode();
|
|
164
|
+
const maxHeight = useMaxHeight();
|
|
165
|
+
const resolvedStatus = status ? resolveStatusLevel(status.level ?? status.variant ?? "off") : void 0;
|
|
166
|
+
const statusColor = resolvedStatus ? STATUS_COLORS_INTERNAL[resolvedStatus] : void 0;
|
|
167
|
+
const toggleFullscreen = async () => {
|
|
168
|
+
const newMode = mode === "fullscreen" ? "inline" : "fullscreen";
|
|
169
|
+
await requestMode(newMode);
|
|
170
|
+
onFullscreenChange == null ? void 0 : onFullscreenChange(newMode === "fullscreen");
|
|
171
|
+
};
|
|
172
|
+
return /* @__PURE__ */ jsxs(
|
|
173
|
+
"div",
|
|
174
|
+
{
|
|
175
|
+
ref: containerRef,
|
|
176
|
+
className: `chatgpt-card ${className}`,
|
|
177
|
+
role: "region",
|
|
178
|
+
"aria-label": title ?? "Widget",
|
|
179
|
+
style: {
|
|
180
|
+
background: colors.surface,
|
|
181
|
+
border: `1px solid ${colors.border}`,
|
|
182
|
+
borderRadius: "12px",
|
|
183
|
+
padding: compact ? "12px" : "16px",
|
|
184
|
+
fontFamily: FONT_FAMILY_PRIMARY,
|
|
185
|
+
color: colors.text,
|
|
186
|
+
transition: "all 0.2s ease",
|
|
187
|
+
...maxHeight ? { maxHeight, overflow: "auto" } : {},
|
|
188
|
+
...style
|
|
189
|
+
},
|
|
190
|
+
children: [
|
|
191
|
+
(title || status || allowFullscreen || actions) && /* @__PURE__ */ jsxs(
|
|
192
|
+
"div",
|
|
193
|
+
{
|
|
194
|
+
style: {
|
|
195
|
+
display: "flex",
|
|
196
|
+
alignItems: "flex-start",
|
|
197
|
+
justifyContent: "space-between",
|
|
198
|
+
marginBottom: compact ? "8px" : "12px"
|
|
199
|
+
},
|
|
200
|
+
children: [
|
|
201
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", minWidth: 0 }, children: [
|
|
202
|
+
icon && /* @__PURE__ */ jsx("span", { style: { fontSize: compact ? "16px" : "20px", flexShrink: 0 }, children: icon }),
|
|
203
|
+
/* @__PURE__ */ jsxs("div", { style: { minWidth: 0 }, children: [
|
|
204
|
+
title && /* @__PURE__ */ jsx(
|
|
205
|
+
"h3",
|
|
206
|
+
{
|
|
207
|
+
style: {
|
|
208
|
+
margin: 0,
|
|
209
|
+
fontSize: compact ? "0.8125rem" : "0.875rem",
|
|
210
|
+
fontWeight: 500,
|
|
211
|
+
color: colors.text,
|
|
212
|
+
whiteSpace: "nowrap",
|
|
213
|
+
overflow: "hidden",
|
|
214
|
+
textOverflow: "ellipsis"
|
|
215
|
+
},
|
|
216
|
+
children: title
|
|
217
|
+
}
|
|
218
|
+
),
|
|
219
|
+
subtitle && /* @__PURE__ */ jsx(
|
|
220
|
+
"p",
|
|
221
|
+
{
|
|
222
|
+
style: {
|
|
223
|
+
margin: "2px 0 0 0",
|
|
224
|
+
fontSize: "0.6875rem",
|
|
225
|
+
color: colors.textMuted,
|
|
226
|
+
whiteSpace: "nowrap",
|
|
227
|
+
overflow: "hidden",
|
|
228
|
+
textOverflow: "ellipsis"
|
|
229
|
+
},
|
|
230
|
+
children: subtitle
|
|
231
|
+
}
|
|
232
|
+
)
|
|
233
|
+
] })
|
|
234
|
+
] }),
|
|
235
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", flexShrink: 0 }, children: [
|
|
236
|
+
actions,
|
|
237
|
+
status && resolvedStatus && statusColor && /* @__PURE__ */ jsxs(
|
|
238
|
+
"span",
|
|
239
|
+
{
|
|
240
|
+
role: "status",
|
|
241
|
+
"aria-label": `Status: ${status.label} (${resolvedStatus})`,
|
|
242
|
+
style: {
|
|
243
|
+
display: "inline-flex",
|
|
244
|
+
alignItems: "center",
|
|
245
|
+
gap: "4px",
|
|
246
|
+
fontSize: "0.5625rem",
|
|
247
|
+
fontWeight: 500,
|
|
248
|
+
letterSpacing: "0.5px",
|
|
249
|
+
padding: "2px 8px 2px 4px",
|
|
250
|
+
borderRadius: "4px",
|
|
251
|
+
background: `${statusColor}18`,
|
|
252
|
+
color: statusColor,
|
|
253
|
+
whiteSpace: "nowrap"
|
|
254
|
+
},
|
|
255
|
+
children: [
|
|
256
|
+
/* @__PURE__ */ jsx(StatusShape, { status: resolvedStatus, size: 8 }),
|
|
257
|
+
status.label
|
|
258
|
+
]
|
|
259
|
+
}
|
|
260
|
+
),
|
|
261
|
+
allowFullscreen && isInChatGPT() && /* @__PURE__ */ jsx(
|
|
262
|
+
"button",
|
|
263
|
+
{
|
|
264
|
+
onClick: toggleFullscreen,
|
|
265
|
+
"aria-label": mode === "fullscreen" ? "Exit fullscreen" : "Enter fullscreen",
|
|
266
|
+
style: {
|
|
267
|
+
background: "transparent",
|
|
268
|
+
border: "none",
|
|
269
|
+
cursor: "pointer",
|
|
270
|
+
fontSize: "14px",
|
|
271
|
+
opacity: 0.6,
|
|
272
|
+
padding: "4px",
|
|
273
|
+
color: colors.text,
|
|
274
|
+
borderRadius: "4px",
|
|
275
|
+
lineHeight: 1
|
|
276
|
+
},
|
|
277
|
+
children: mode === "fullscreen" ? "⤓" : "⤢"
|
|
278
|
+
}
|
|
279
|
+
)
|
|
280
|
+
] })
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
),
|
|
284
|
+
/* @__PURE__ */ jsx("div", { children: loading ? /* @__PURE__ */ jsx(LoadingSkeleton, { compact, isDark }) : error ? /* @__PURE__ */ jsx(ErrorDisplay, { error, onRetry, isDark }) : children }),
|
|
285
|
+
footer && !loading && !error && /* @__PURE__ */ jsx(
|
|
286
|
+
"div",
|
|
287
|
+
{
|
|
288
|
+
style: {
|
|
289
|
+
marginTop: compact ? "8px" : "12px",
|
|
290
|
+
paddingTop: compact ? "8px" : "12px",
|
|
291
|
+
borderTop: `1px solid ${colors.border}`
|
|
292
|
+
},
|
|
293
|
+
children: footer
|
|
294
|
+
}
|
|
295
|
+
)
|
|
296
|
+
]
|
|
297
|
+
}
|
|
298
|
+
);
|
|
299
|
+
};
|
|
300
|
+
const AppCard = (props) => /* @__PURE__ */ jsx(CardErrorBoundary, { componentName: props.title ?? "AppCard", children: /* @__PURE__ */ jsx(AppCardInner, { ...props }) });
|
|
301
|
+
const ChatGPTCard = AppCard;
|
|
302
|
+
export {
|
|
303
|
+
AppCard,
|
|
304
|
+
ChatGPTCard
|
|
305
|
+
};
|
|
306
|
+
//# sourceMappingURL=AppCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppCard.js","sources":["../../../src/react/chatgpt/AppCard.tsx"],"sourcesContent":["/**\n * AppCard — Universal widget wrapper for AI host environments.\n *\n * Works with: ChatGPT Apps, Anthropic MCP Apps, Google Gemini, any MCP-compatible host.\n *\n * Features:\n * - Theme-aware styling (light/dark via host environment)\n * - Astro UX 6-level status system with dual-coded indicators (color + shape)\n * - Error boundary protection with graceful fallback UI\n * - Loading and error state management\n * - Display mode support (inline/PiP/fullscreen)\n * - Widget state persistence\n * - WCAG 2.1 AA accessibility (ARIA labels, keyboard nav, screen readers)\n *\n * @example\n * ```tsx\n * import { AppCard, useToolOutput } from '@zendir/ui/react';\n *\n * function SatelliteWidget() {\n * const data = useToolOutput<SatelliteHealth>();\n * return (\n * <AppCard\n * title=\"SAT-001\"\n * subtitle=\"Health Monitor\"\n * status={{ level: 'caution', label: 'Battery Low' }}\n * allowFullscreen\n * >\n * <TelemetryCard data={data} />\n * </AppCard>\n * );\n * }\n * ```\n */\n\nimport React, { useRef, ReactNode, Component } from 'react';\nimport { useChatGPTTheme, useMaxHeight, useDisplayMode, isInChatGPT } from './index';\nimport { FONT_FAMILY_PRIMARY } from '../core/Typography';\nimport type { StatusLevel } from '../utils';\n\n// ─── Status shape helper (matches ChatPanel & Astro UX components) ───────────\n\nconst STATUS_COLORS_INTERNAL: Record<StatusLevel, string> = {\n off: '#a4abb6',\n standby: '#2dccff',\n normal: '#56f000',\n caution: '#fce83a',\n serious: '#ffb302',\n critical: '#ff3838',\n};\n\nfunction StatusShape({ status, size = 10 }: { status: StatusLevel; size?: number }) {\n const color = STATUS_COLORS_INTERNAL[status] ?? STATUS_COLORS_INTERNAL.off;\n const glow = `${color}50`;\n switch (status) {\n case 'caution':\n return <svg viewBox=\"0 0 12 12\" width={size} height={size} style={{ filter: `drop-shadow(0 0 3px ${glow})` }} aria-hidden=\"true\"><rect x=\"1\" y=\"1\" width=\"10\" height=\"10\" fill={color} /></svg>;\n case 'serious':\n return <svg viewBox=\"0 0 12 12\" width={size} height={size} style={{ filter: `drop-shadow(0 0 3px ${glow})` }} aria-hidden=\"true\"><polygon points=\"6,1 11,6 6,11 1,6\" fill={color} /></svg>;\n case 'critical':\n return <svg viewBox=\"0 0 12 12\" width={size} height={size} style={{ filter: `drop-shadow(0 0 3px ${glow})` }} aria-hidden=\"true\"><polygon points=\"6,11 1,2 11,2\" fill={color} /></svg>;\n case 'standby':\n return <svg viewBox=\"0 0 12 12\" width={size} height={size} style={{ filter: `drop-shadow(0 0 3px ${glow})` }} aria-hidden=\"true\"><circle cx=\"6\" cy=\"6\" r=\"3.5\" fill=\"none\" stroke={color} strokeWidth=\"2\" /></svg>;\n case 'off':\n return <svg viewBox=\"0 0 12 12\" width={size} height={size} style={{ filter: `drop-shadow(0 0 3px ${glow})` }} aria-hidden=\"true\"><circle cx=\"6\" cy=\"6\" r=\"3\" fill={color} /></svg>;\n default: // normal\n return <svg viewBox=\"0 0 12 12\" width={size} height={size} style={{ filter: `drop-shadow(0 0 3px ${glow})` }} aria-hidden=\"true\"><circle cx=\"6\" cy=\"6\" r=\"5\" fill={color} /></svg>;\n }\n}\n\n// ─── Legacy status mapping (for backward compatibility) ──────────────────────\n\n/**\n * Maps legacy variant strings to Astro UX StatusLevel.\n * Supports both new `StatusLevel` and old `success/warning/error/info/neutral` variants.\n */\nconst LEGACY_VARIANT_MAP: Record<string, StatusLevel> = {\n success: 'normal',\n warning: 'caution',\n error: 'critical',\n info: 'standby',\n neutral: 'off',\n};\n\nfunction resolveStatusLevel(input: string): StatusLevel {\n if (['off', 'standby', 'normal', 'caution', 'serious', 'critical'].includes(input)) {\n return input as StatusLevel;\n }\n return LEGACY_VARIANT_MAP[input] ?? 'off';\n}\n\n// ─── Error Boundary ──────────────────────────────────────────────────────────\n\ninterface CardErrorBoundaryState {\n hasError: boolean;\n error?: Error;\n}\n\nclass CardErrorBoundary extends Component<\n { children: ReactNode; componentName?: string },\n CardErrorBoundaryState\n> {\n constructor(props: { children: ReactNode; componentName?: string }) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(error: Error): CardErrorBoundaryState {\n return { hasError: true, error };\n }\n\n render() {\n if (this.state.hasError) {\n return (\n <div\n style={{\n padding: '16px',\n borderRadius: '12px',\n background: 'rgba(255, 56, 56, 0.08)',\n border: '1px solid rgba(255, 56, 56, 0.3)',\n fontFamily: FONT_FAMILY_PRIMARY,\n color: '#ff8a8a', // WCAG AA: lighter red for readable text on dark error background\n }}\n role=\"alert\"\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '8px' }}>\n <StatusShape status=\"critical\" size={12} />\n <strong style={{ fontSize: '0.875rem' }}>\n {this.props.componentName ?? 'Widget'} Error\n </strong>\n </div>\n <p style={{ margin: 0, fontSize: '0.75rem', opacity: 0.8 }}>\n {this.state.error?.message ?? 'An unexpected error occurred.'}\n </p>\n </div>\n );\n }\n return this.props.children;\n }\n}\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport interface AppCardProps {\n /** Card content */\n children: ReactNode;\n /** Card title */\n title?: string;\n /** Subtitle or description */\n subtitle?: string;\n /**\n * Status badge with Astro UX dual-coded indicator (color + shape).\n *\n * Supports both the Astro UX `StatusLevel` and legacy variants:\n * - Astro UX: `{ level: 'normal' | 'standby' | 'caution' | 'serious' | 'critical' | 'off', label: '...' }`\n * - Legacy: `{ variant: 'success' | 'warning' | 'error' | 'info' | 'neutral', label: '...' }`\n */\n status?: {\n label: string;\n level?: StatusLevel;\n /** @deprecated Use `level` (Astro UX StatusLevel) instead. Still supported for backward compatibility. */\n variant?: 'success' | 'warning' | 'error' | 'info' | 'neutral';\n };\n /** Show fullscreen button (only rendered inside ChatGPT host) */\n allowFullscreen?: boolean;\n /** Callback when fullscreen is toggled */\n onFullscreenChange?: (isFullscreen: boolean) => void;\n /** Additional CSS classes */\n className?: string;\n /** Enable compact mode (reduced padding and font sizes) */\n compact?: boolean;\n /** Header icon (ReactNode, rendered before title) */\n icon?: ReactNode;\n /** Footer content (rendered below content with a divider) */\n footer?: ReactNode;\n /** Actions (buttons) rendered in the header, right-aligned */\n actions?: ReactNode;\n /** Show a loading skeleton over the content area */\n loading?: boolean;\n /** Error state — renders an error message with a critical alert */\n error?: string | Error;\n /** Retry callback (shown when `error` is set) */\n onRetry?: () => void;\n /** Custom inline styles for the root container */\n style?: React.CSSProperties;\n}\n\n// ─── Loading Skeleton ────────────────────────────────────────────────────────\n\nfunction LoadingSkeleton({ compact, isDark }: { compact: boolean; isDark: boolean }) {\n const bar = (w: string, h = 12) => ({\n width: w,\n height: h,\n borderRadius: 4,\n background: isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)',\n animation: 'chatgpt-card-pulse 1.5s ease-in-out infinite',\n });\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: compact ? 8 : 12 }} aria-label=\"Loading...\" role=\"status\">\n <div style={bar('70%', 14)} />\n <div style={bar('100%')} />\n <div style={bar('85%')} />\n <div style={bar('60%')} />\n <style>{`@keyframes chatgpt-card-pulse { 0%,100% { opacity: 0.4 } 50% { opacity: 1 } }`}</style>\n </div>\n );\n}\n\n// ─── Error Display ───────────────────────────────────────────────────────────\n\nfunction ErrorDisplay({ error, onRetry, isDark }: { error: string | Error; onRetry?: () => void; isDark: boolean }) {\n const message = typeof error === 'string' ? error : error.message;\n return (\n <div\n role=\"alert\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n padding: '12px',\n borderRadius: 8,\n background: 'rgba(255, 56, 56, 0.08)',\n border: '1px solid rgba(255, 56, 56, 0.2)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n <StatusShape status=\"critical\" size={12} />\n <span style={{ fontSize: '0.75rem', fontWeight: 500, color: '#ff8a8a' }}>{message}</span>\n </div>\n {onRetry && (\n <button\n onClick={onRetry}\n style={{\n alignSelf: 'flex-start',\n padding: '4px 12px',\n borderRadius: 4,\n border: `1px solid ${isDark ? 'rgba(255,255,255,0.15)' : 'rgba(0,0,0,0.15)'}`,\n background: 'transparent',\n color: isDark ? '#a1a1aa' : '#636370', // WCAG AA compliant on light backgrounds\n cursor: 'pointer',\n fontSize: '0.6875rem',\n fontFamily: FONT_FAMILY_PRIMARY,\n }}\n aria-label=\"Retry loading widget\"\n >\n Retry\n </button>\n )}\n </div>\n );\n}\n\n// ─── Main Component ──────────────────────────────────────────────────────────\n\nconst AppCardInner: React.FC<AppCardProps> = ({\n children,\n title,\n subtitle,\n status,\n allowFullscreen = false,\n onFullscreenChange,\n className = '',\n compact = false,\n icon,\n footer,\n actions,\n loading = false,\n error,\n onRetry,\n style,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const { isDark, colors } = useChatGPTTheme();\n const { mode, requestMode } = useDisplayMode();\n const maxHeight = useMaxHeight();\n\n // Resolve status level (supports both Astro UX and legacy variants)\n const resolvedStatus = status\n ? resolveStatusLevel(status.level ?? status.variant ?? 'off')\n : undefined;\n const statusColor = resolvedStatus ? STATUS_COLORS_INTERNAL[resolvedStatus] : undefined;\n\n // Handle fullscreen toggle\n const toggleFullscreen = async () => {\n const newMode = mode === 'fullscreen' ? 'inline' : 'fullscreen';\n await requestMode(newMode);\n onFullscreenChange?.(newMode === 'fullscreen');\n };\n\n return (\n <div\n ref={containerRef}\n className={`chatgpt-card ${className}`}\n role=\"region\"\n aria-label={title ?? 'Widget'}\n style={{\n background: colors.surface,\n border: `1px solid ${colors.border}`,\n borderRadius: '12px',\n padding: compact ? '12px' : '16px',\n fontFamily: FONT_FAMILY_PRIMARY,\n color: colors.text,\n transition: 'all 0.2s ease',\n ...(maxHeight ? { maxHeight, overflow: 'auto' } : {}),\n ...style,\n }}\n >\n {/* Header */}\n {(title || status || allowFullscreen || actions) && (\n <div\n style={{\n display: 'flex',\n alignItems: 'flex-start',\n justifyContent: 'space-between',\n marginBottom: compact ? '8px' : '12px',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', minWidth: 0 }}>\n {icon && <span style={{ fontSize: compact ? '16px' : '20px', flexShrink: 0 }}>{icon}</span>}\n <div style={{ minWidth: 0 }}>\n {title && (\n <h3\n style={{\n margin: 0,\n fontSize: compact ? '0.8125rem' : '0.875rem',\n fontWeight: 500,\n color: colors.text,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {title}\n </h3>\n )}\n {subtitle && (\n <p\n style={{\n margin: '2px 0 0 0',\n fontSize: '0.6875rem',\n color: colors.textMuted,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {subtitle}\n </p>\n )}\n </div>\n </div>\n\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', flexShrink: 0 }}>\n {actions}\n\n {status && resolvedStatus && statusColor && (\n <span\n role=\"status\"\n aria-label={`Status: ${status.label} (${resolvedStatus})`}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: '4px',\n fontSize: '0.5625rem',\n fontWeight: 500,\n letterSpacing: '0.5px',\n padding: '2px 8px 2px 4px',\n borderRadius: '4px',\n background: `${statusColor}18`,\n color: statusColor,\n whiteSpace: 'nowrap',\n }}\n >\n <StatusShape status={resolvedStatus} size={8} />\n {status.label}\n </span>\n )}\n\n {allowFullscreen && isInChatGPT() && (\n <button\n onClick={toggleFullscreen}\n aria-label={mode === 'fullscreen' ? 'Exit fullscreen' : 'Enter fullscreen'}\n style={{\n background: 'transparent',\n border: 'none',\n cursor: 'pointer',\n fontSize: '14px',\n opacity: 0.6,\n padding: '4px',\n color: colors.text,\n borderRadius: '4px',\n lineHeight: 1,\n }}\n >\n {mode === 'fullscreen' ? '⤓' : '⤢'}\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* Content: loading → error → children */}\n <div>\n {loading ? (\n <LoadingSkeleton compact={compact} isDark={isDark} />\n ) : error ? (\n <ErrorDisplay error={error} onRetry={onRetry} isDark={isDark} />\n ) : (\n children\n )}\n </div>\n\n {/* Footer */}\n {footer && !loading && !error && (\n <div\n style={{\n marginTop: compact ? '8px' : '12px',\n paddingTop: compact ? '8px' : '12px',\n borderTop: `1px solid ${colors.border}`,\n }}\n >\n {footer}\n </div>\n )}\n </div>\n );\n};\n\n/**\n * AppCard — enterprise-ready widget wrapper for AI host environments.\n *\n * Works with ChatGPT Apps, Anthropic MCP Apps, Google Gemini, or any MCP host.\n * Wrapped in an error boundary so rendering failures in child components never\n * crash the host application — critical for sandboxed iframes.\n */\nexport const AppCard: React.FC<AppCardProps> = (props) => (\n <CardErrorBoundary componentName={props.title ?? 'AppCard'}>\n <AppCardInner {...props} />\n </CardErrorBoundary>\n);\n\n/** @deprecated Use `AppCard` instead. Alias kept for backward compatibility. */\nexport const ChatGPTCard = AppCard;\n/** @deprecated Use `AppCardProps` instead. */\nexport type ChatGPTCardProps = AppCardProps;\n\nexport default AppCard;\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChatGPT Apps SDK Integration
|
|
3
|
+
*
|
|
4
|
+
* Hooks and utilities for integrating Zendir UI components with ChatGPT's
|
|
5
|
+
* window.openai API. Based on: https://developers.openai.com/apps-sdk/build/chatgpt-ui/
|
|
6
|
+
*
|
|
7
|
+
* Key capabilities:
|
|
8
|
+
* - window.openai.toolInput / toolOutput - Tool data from MCP server
|
|
9
|
+
* - window.openai.widgetState / setWidgetState - Persistent UI state
|
|
10
|
+
* - window.openai.callTool - Invoke other MCP tools from widget
|
|
11
|
+
* - window.openai.sendFollowUpMessage - Insert user messages
|
|
12
|
+
* - window.openai.theme - Light/dark theme detection
|
|
13
|
+
* - window.openai.locale - Localization
|
|
14
|
+
* - window.openai.requestDisplayMode - Fullscreen/PiP modes
|
|
15
|
+
* - window.openai.notifyIntrinsicHeight - Dynamic height reporting
|
|
16
|
+
*/
|
|
17
|
+
export interface OpenAiGlobals {
|
|
18
|
+
/** Arguments supplied when the tool was invoked */
|
|
19
|
+
toolInput?: Record<string, unknown>;
|
|
20
|
+
/** Your structuredContent - the model reads this */
|
|
21
|
+
toolOutput?: Record<string, unknown>;
|
|
22
|
+
/** Metadata payload - only widget sees it */
|
|
23
|
+
toolResponseMetadata?: Record<string, unknown>;
|
|
24
|
+
/** Snapshot of UI state persisted between renders */
|
|
25
|
+
widgetState?: Record<string, unknown>;
|
|
26
|
+
/** Current theme */
|
|
27
|
+
theme?: 'light' | 'dark';
|
|
28
|
+
/** Current locale (e.g., 'en-US') */
|
|
29
|
+
locale?: string;
|
|
30
|
+
/** Display mode */
|
|
31
|
+
displayMode?: 'inline' | 'pip' | 'fullscreen';
|
|
32
|
+
/** Maximum allowed height */
|
|
33
|
+
maxHeight?: number;
|
|
34
|
+
/** View type */
|
|
35
|
+
view?: 'conversation' | 'modal';
|
|
36
|
+
/** User agent info */
|
|
37
|
+
userAgent?: string;
|
|
38
|
+
/** Safe area insets */
|
|
39
|
+
safeArea?: {
|
|
40
|
+
top: number;
|
|
41
|
+
bottom: number;
|
|
42
|
+
left: number;
|
|
43
|
+
right: number;
|
|
44
|
+
};
|
|
45
|
+
setWidgetState?: (state: Record<string, unknown>) => void;
|
|
46
|
+
callTool?: (name: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
47
|
+
sendFollowUpMessage?: (options: {
|
|
48
|
+
prompt: string;
|
|
49
|
+
}) => Promise<void>;
|
|
50
|
+
uploadFile?: (file: File) => Promise<{
|
|
51
|
+
fileId: string;
|
|
52
|
+
}>;
|
|
53
|
+
getFileDownloadUrl?: (options: {
|
|
54
|
+
fileId: string;
|
|
55
|
+
}) => Promise<{
|
|
56
|
+
downloadUrl: string;
|
|
57
|
+
}>;
|
|
58
|
+
requestDisplayMode?: (options: {
|
|
59
|
+
mode: 'inline' | 'pip' | 'fullscreen';
|
|
60
|
+
}) => Promise<void>;
|
|
61
|
+
requestModal?: (options: unknown) => Promise<void>;
|
|
62
|
+
notifyIntrinsicHeight?: (height: number) => void;
|
|
63
|
+
openExternal?: (options: {
|
|
64
|
+
href: string;
|
|
65
|
+
}) => void;
|
|
66
|
+
requestClose?: () => void;
|
|
67
|
+
}
|
|
68
|
+
declare global {
|
|
69
|
+
interface Window {
|
|
70
|
+
openai?: OpenAiGlobals;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Subscribe to a specific window.openai global value
|
|
75
|
+
*/
|
|
76
|
+
export declare function useOpenAiGlobal<K extends keyof OpenAiGlobals>(key: K): OpenAiGlobals[K];
|
|
77
|
+
type SetStateAction<T> = T | ((prevState: T) => T);
|
|
78
|
+
/**
|
|
79
|
+
* Manage widget state that persists across renders via window.openai.setWidgetState
|
|
80
|
+
*/
|
|
81
|
+
export declare function useWidgetState<T extends Record<string, unknown>>(defaultState: T | (() => T)): readonly [T, (state: SetStateAction<T>) => void];
|
|
82
|
+
/**
|
|
83
|
+
* Read the tool output (structuredContent) from the MCP server response
|
|
84
|
+
*/
|
|
85
|
+
export declare function useToolOutput<T = Record<string, unknown>>(): T | undefined;
|
|
86
|
+
/**
|
|
87
|
+
* Read the tool input (arguments) from the tool invocation
|
|
88
|
+
*/
|
|
89
|
+
export declare function useToolInput<T = Record<string, unknown>>(): T | undefined;
|
|
90
|
+
export type ThemeMode = 'light' | 'dark';
|
|
91
|
+
/**
|
|
92
|
+
* Get current ChatGPT theme and provide CSS-friendly values
|
|
93
|
+
* Named useChatGPTTheme to avoid conflict with the core useTheme from ThemeProvider
|
|
94
|
+
*/
|
|
95
|
+
export declare function useChatGPTTheme(): {
|
|
96
|
+
theme: ThemeMode;
|
|
97
|
+
isDark: boolean;
|
|
98
|
+
colors: {
|
|
99
|
+
background: string;
|
|
100
|
+
surface: string;
|
|
101
|
+
surfaceHover: string;
|
|
102
|
+
border: string;
|
|
103
|
+
text: string;
|
|
104
|
+
textMuted: string;
|
|
105
|
+
accent: string;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Get current locale for internationalization
|
|
110
|
+
*/
|
|
111
|
+
export declare function useLocale(): string;
|
|
112
|
+
/**
|
|
113
|
+
* Manage widget display mode (inline, PiP, fullscreen)
|
|
114
|
+
*/
|
|
115
|
+
export declare function useDisplayMode(): {
|
|
116
|
+
mode: 'inline' | 'pip' | 'fullscreen';
|
|
117
|
+
maxHeight?: number;
|
|
118
|
+
requestMode: (mode: 'inline' | 'pip' | 'fullscreen') => Promise<void>;
|
|
119
|
+
close: () => void;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Call another MCP tool from within a widget
|
|
123
|
+
*/
|
|
124
|
+
export declare function useCallTool(): {
|
|
125
|
+
callTool: <T = unknown>(name: string, args: Record<string, unknown>) => Promise<T>;
|
|
126
|
+
isLoading: boolean;
|
|
127
|
+
error: Error | null;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Send a follow-up message as if the user asked it
|
|
131
|
+
*/
|
|
132
|
+
export declare function useSendMessage(): (prompt: string) => Promise<void>;
|
|
133
|
+
/**
|
|
134
|
+
* DEPRECATED: Do not use notifyIntrinsicHeight!
|
|
135
|
+
*
|
|
136
|
+
* According to OpenAI Apps SDK examples (via DeepWiki), the correct pattern is:
|
|
137
|
+
* - The HOST provides maxHeight via window.openai.maxHeight
|
|
138
|
+
* - Widgets READ this and constrain themselves
|
|
139
|
+
* - Widgets NEVER report height back to the host
|
|
140
|
+
*
|
|
141
|
+
* Calling notifyIntrinsicHeight causes infinite resize loops in MCPJam sandbox
|
|
142
|
+
* because the sandbox responds by resizing the container, which triggers another
|
|
143
|
+
* resize event.
|
|
144
|
+
*
|
|
145
|
+
* Use useMaxHeight() instead to get the host's height constraint.
|
|
146
|
+
*
|
|
147
|
+
* @deprecated Use useMaxHeight() instead
|
|
148
|
+
*/
|
|
149
|
+
export declare function useIntrinsicHeight(_ref: {
|
|
150
|
+
current: HTMLElement | null;
|
|
151
|
+
}): void;
|
|
152
|
+
/**
|
|
153
|
+
* Get the maximum height available for the widget from the host environment.
|
|
154
|
+
* This is the CORRECT pattern per OpenAI Apps SDK examples.
|
|
155
|
+
*
|
|
156
|
+
* The host (ChatGPT/MCPJam) provides maxHeight, and widgets should constrain
|
|
157
|
+
* themselves to this height. Widgets should NOT report their height back.
|
|
158
|
+
*
|
|
159
|
+
* @returns The maximum height in pixels, or undefined if not available
|
|
160
|
+
*/
|
|
161
|
+
export declare function useMaxHeight(): number | undefined;
|
|
162
|
+
/**
|
|
163
|
+
* Open vetted external links in the user's browser
|
|
164
|
+
*/
|
|
165
|
+
export declare function useOpenExternal(): (href: string) => void;
|
|
166
|
+
export declare function isInChatGPT(): boolean;
|
|
167
|
+
export {};
|