@zendir/ui 0.5.0 → 0.6.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 +20 -0
- package/README.md +640 -631
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/index.js +17 -221
- package/dist/react/3d/CesiumCaptureSource.d.ts +0 -1
- package/dist/react/3d/CesiumCaptureSource.js +364 -283
- package/dist/react/3d/CesiumCaptureSource.js.map +1 -1
- package/dist/react/3d/ZenSpace3D.d.ts +2 -3
- package/dist/react/3d/ZenSpace3D.js +1681 -1237
- package/dist/react/3d/ZenSpace3D.js.map +1 -1
- package/dist/react/3d/ZenSpace3DCesium.d.ts +0 -1
- package/dist/react/3d/ZenSpace3DCesium.js +513 -560
- package/dist/react/3d/ZenSpace3DCesium.js.map +1 -1
- package/dist/react/3d/ZenSpace3DShaders.js +61 -66
- package/dist/react/3d/ZenSpace3DShaders.js.map +1 -1
- package/dist/react/3d/ZenSpace3DTypes.d.ts +19 -20
- package/dist/react/3d/ZenSpace3DUtils.d.ts +0 -1
- package/dist/react/3d/ZenSpace3DUtils.js +37 -24
- package/dist/react/3d/ZenSpace3DUtils.js.map +1 -1
- package/dist/react/3d/capturePngAnalysis.js +42 -36
- package/dist/react/3d/capturePngAnalysis.js.map +1 -1
- package/dist/react/3d/index.d.ts +3 -3
- package/dist/react/3d/index.js +5 -53
- package/dist/react/3d/threeLoader.d.ts +1 -1
- package/dist/react/3d/threeLoader.js +23 -18
- package/dist/react/3d/threeLoader.js.map +1 -1
- package/dist/react/astro/ClassificationBanner.d.ts +2 -3
- package/dist/react/astro/ClassificationBanner.js +95 -79
- package/dist/react/astro/ClassificationBanner.js.map +1 -1
- package/dist/react/astro/GlobalStatusBar.d.ts +0 -1
- package/dist/react/astro/GlobalStatusBar.js +157 -163
- package/dist/react/astro/GlobalStatusBar.js.map +1 -1
- package/dist/react/astro/MissionClock.d.ts +7 -8
- package/dist/react/astro/MissionClock.js +377 -400
- package/dist/react/astro/MissionClock.js.map +1 -1
- package/dist/react/astro/MonitoringIcon.d.ts +1 -2
- package/dist/react/astro/MonitoringIcon.js +422 -358
- package/dist/react/astro/MonitoringIcon.js.map +1 -1
- package/dist/react/astro/Notification.d.ts +1 -2
- package/dist/react/astro/Notification.js +229 -126
- package/dist/react/astro/Notification.js.map +1 -1
- package/dist/react/astro/Progress.d.ts +0 -1
- package/dist/react/astro/Progress.js +199 -141
- package/dist/react/astro/Progress.js.map +1 -1
- package/dist/react/astro/SimulationControls.d.ts +3 -4
- package/dist/react/astro/SimulationControls.js +596 -650
- package/dist/react/astro/SimulationControls.js.map +1 -1
- package/dist/react/astro/StatusIndicator.d.ts +0 -1
- package/dist/react/astro/StatusIndicator.js +236 -170
- package/dist/react/astro/StatusIndicator.js.map +1 -1
- package/dist/react/astro/UnifiedTimeline.d.ts +9 -10
- package/dist/react/astro/UnifiedTimeline.js +2345 -2392
- package/dist/react/astro/UnifiedTimeline.js.map +1 -1
- package/dist/react/astro/index.d.ts +5 -5
- package/dist/react/astro/index.js +1 -25
- package/dist/react/cards/AccessCard.d.ts +0 -1
- package/dist/react/cards/AccessCard.js +471 -405
- package/dist/react/cards/AccessCard.js.map +1 -1
- package/dist/react/cards/OrbitCard.d.ts +0 -1
- package/dist/react/cards/OrbitCard.js +487 -364
- package/dist/react/cards/OrbitCard.js.map +1 -1
- package/dist/react/cards/SpacecraftCard.d.ts +0 -1
- package/dist/react/cards/SpacecraftCard.js +813 -925
- package/dist/react/cards/SpacecraftCard.js.map +1 -1
- package/dist/react/cards/TelemetryCard.d.ts +0 -1
- package/dist/react/cards/TelemetryCard.js +1055 -732
- package/dist/react/cards/TelemetryCard.js.map +1 -1
- package/dist/react/cards/TelemetryStreamCard.d.ts +0 -1
- package/dist/react/cards/TelemetryStreamCard.js +323 -297
- package/dist/react/cards/TelemetryStreamCard.js.map +1 -1
- package/dist/react/cards/index.d.ts +1 -1
- package/dist/react/cards/index.js +1 -8
- package/dist/react/charts/GroundTrackMap.d.ts +6 -7
- package/dist/react/charts/GroundTrackMap.js +1377 -1256
- package/dist/react/charts/GroundTrackMap.js.map +1 -1
- package/dist/react/charts/GroundTrackMapLeaflet.d.ts +1 -2
- package/dist/react/charts/GroundTrackMapLeaflet.js +1065 -987
- package/dist/react/charts/GroundTrackMapLeaflet.js.map +1 -1
- package/dist/react/charts/groundTrackMapLeafletTiles.js +34 -25
- package/dist/react/charts/groundTrackMapLeafletTiles.js.map +1 -1
- package/dist/react/charts/groundTrackMapLeafletUtils.js +70 -61
- package/dist/react/charts/groundTrackMapLeafletUtils.js.map +1 -1
- package/dist/react/charts/index.d.ts +1 -1
- package/dist/react/charts/index.js +7 -100
- package/dist/react/charts/unified/AstroChart.d.ts +1 -2
- package/dist/react/charts/unified/AstroChart.js +1331 -1411
- package/dist/react/charts/unified/AstroChart.js.map +1 -1
- package/dist/react/charts/unified/PowerOverviewChart.d.ts +3 -3
- package/dist/react/charts/unified/PowerOverviewChart.js +495 -478
- package/dist/react/charts/unified/PowerOverviewChart.js.map +1 -1
- package/dist/react/charts/unified/domain.d.ts +12 -13
- package/dist/react/charts/unified/domain.js +3999 -3145
- package/dist/react/charts/unified/domain.js.map +1 -1
- package/dist/react/charts/unified/generators.d.ts +3 -4
- package/dist/react/charts/unified/generators.js +561 -498
- package/dist/react/charts/unified/generators.js.map +1 -1
- package/dist/react/charts/unified/index.d.ts +1 -1
- package/dist/react/charts/unified/presets.d.ts +14 -15
- package/dist/react/charts/unified/presets.js +857 -994
- package/dist/react/charts/unified/presets.js.map +1 -1
- package/dist/react/charts/unified/sync.d.ts +2 -3
- package/dist/react/charts/unified/sync.js +229 -195
- package/dist/react/charts/unified/sync.js.map +1 -1
- package/dist/react/charts/unified/theme.d.ts +11 -12
- package/dist/react/charts/unified/theme.js +606 -642
- package/dist/react/charts/unified/theme.js.map +1 -1
- package/dist/react/charts/unified/types.d.ts +32 -33
- package/dist/react/charts/unified/useChartStream.d.ts +1 -2
- package/dist/react/charts/unified/useChartStream.js +203 -216
- package/dist/react/charts/unified/useChartStream.js.map +1 -1
- package/dist/react/chatgpt/AppCard.d.ts +1 -2
- package/dist/react/chatgpt/index.d.ts +7 -7
- package/dist/react/chatgpt/index.js +160 -139
- package/dist/react/chatgpt/index.js.map +1 -1
- package/dist/react/context/CategoryContext.d.ts +0 -1
- package/dist/react/context/CategoryContext.js +78 -29
- package/dist/react/context/CategoryContext.js.map +1 -1
- package/dist/react/context/DisplaySettingsContext.d.ts +1 -2
- package/dist/react/context/DisplaySettingsContext.js +205 -156
- package/dist/react/context/DisplaySettingsContext.js.map +1 -1
- package/dist/react/context/SpatialSelectionContext.d.ts +0 -1
- package/dist/react/context/SpatialSelectionContext.js +36 -7
- package/dist/react/context/SpatialSelectionContext.js.map +1 -1
- package/dist/react/core/data/DataTable.d.ts +3 -4
- package/dist/react/core/data/DataTable.js +473 -440
- package/dist/react/core/data/DataTable.js.map +1 -1
- package/dist/react/core/data/DataValue.d.ts +4 -5
- package/dist/react/core/data/DataValue.js +605 -571
- package/dist/react/core/data/DataValue.js.map +1 -1
- package/dist/react/core/data/propertyConfig.d.ts +1 -2
- package/dist/react/core/data/propertyConfig.js +446 -382
- package/dist/react/core/data/propertyConfig.js.map +1 -1
- package/dist/react/core/display/AstroIcon.d.ts +4 -5
- package/dist/react/core/display/AstroIcon.js +339 -429
- package/dist/react/core/display/AstroIcon.js.map +1 -1
- package/dist/react/core/display/Badge.d.ts +2 -3
- package/dist/react/core/display/Badge.js +131 -131
- package/dist/react/core/display/Badge.js.map +1 -1
- package/dist/react/core/display/CardHeader.d.ts +0 -1
- package/dist/react/core/display/CardHeader.js +398 -311
- package/dist/react/core/display/CardHeader.js.map +1 -1
- package/dist/react/core/display/Container.d.ts +2 -3
- package/dist/react/core/display/Container.js +640 -668
- package/dist/react/core/display/Container.js.map +1 -1
- package/dist/react/core/display/CopyButton.d.ts +1 -2
- package/dist/react/core/display/CopyButton.js +158 -101
- package/dist/react/core/display/CopyButton.js.map +1 -1
- package/dist/react/core/display/GlassCard.d.ts +3 -4
- package/dist/react/core/display/GlassCard.js +416 -369
- package/dist/react/core/display/GlassCard.js.map +1 -1
- package/dist/react/core/display/HeaderIconWithStatus.d.ts +0 -1
- package/dist/react/core/display/HeaderIconWithStatus.js +152 -152
- package/dist/react/core/display/HeaderIconWithStatus.js.map +1 -1
- package/dist/react/core/display/Icon.d.ts +2 -3
- package/dist/react/core/display/Icon.js +172 -143
- package/dist/react/core/display/Icon.js.map +1 -1
- package/dist/react/core/display/Typography.d.ts +24 -25
- package/dist/react/core/display/Typography.js +360 -178
- package/dist/react/core/display/Typography.js.map +1 -1
- package/dist/react/core/feedback/ConfirmDialog.d.ts +1 -2
- package/dist/react/core/feedback/ConfirmDialog.js +343 -304
- package/dist/react/core/feedback/ConfirmDialog.js.map +1 -1
- package/dist/react/core/feedback/Dialog.d.ts +2 -3
- package/dist/react/core/feedback/Dialog.js +189 -197
- package/dist/react/core/feedback/Dialog.js.map +1 -1
- package/dist/react/core/feedback/Toast.d.ts +2 -3
- package/dist/react/core/feedback/Toast.js +346 -207
- package/dist/react/core/feedback/Toast.js.map +1 -1
- package/dist/react/core/index.d.ts +26 -26
- package/dist/react/core/index.js +7 -119
- package/dist/react/core/inputs/Button.d.ts +2 -3
- package/dist/react/core/inputs/Button.js +281 -304
- package/dist/react/core/inputs/Button.js.map +1 -1
- package/dist/react/core/inputs/Checkbox.d.ts +2 -3
- package/dist/react/core/inputs/Checkbox.js +139 -127
- package/dist/react/core/inputs/Checkbox.js.map +1 -1
- package/dist/react/core/inputs/Input.d.ts +3 -4
- package/dist/react/core/inputs/Input.js +277 -285
- package/dist/react/core/inputs/Input.js.map +1 -1
- package/dist/react/core/inputs/LimitsBar.d.ts +1 -2
- package/dist/react/core/inputs/LimitsBar.js +271 -196
- package/dist/react/core/inputs/LimitsBar.js.map +1 -1
- package/dist/react/core/inputs/NumberInput.d.ts +2 -3
- package/dist/react/core/inputs/NumberInput.js +531 -503
- package/dist/react/core/inputs/NumberInput.js.map +1 -1
- package/dist/react/core/inputs/PinInput.d.ts +2 -3
- package/dist/react/core/inputs/PinInput.js +224 -207
- package/dist/react/core/inputs/PinInput.js.map +1 -1
- package/dist/react/core/inputs/Select.d.ts +1 -2
- package/dist/react/core/inputs/Select.js +298 -299
- package/dist/react/core/inputs/Select.js.map +1 -1
- package/dist/react/core/inputs/Toggle.d.ts +2 -3
- package/dist/react/core/inputs/Toggle.js +142 -148
- package/dist/react/core/inputs/Toggle.js.map +1 -1
- package/dist/react/core/layout/Box.d.ts +3 -4
- package/dist/react/core/layout/Box.js +118 -122
- package/dist/react/core/layout/Box.js.map +1 -1
- package/dist/react/core/layout/Center.d.ts +0 -1
- package/dist/react/core/layout/Center.js +45 -32
- package/dist/react/core/layout/Center.js.map +1 -1
- package/dist/react/core/layout/Divider.d.ts +1 -2
- package/dist/react/core/layout/Divider.js +112 -106
- package/dist/react/core/layout/Divider.js.map +1 -1
- package/dist/react/core/layout/Flex.d.ts +4 -5
- package/dist/react/core/layout/Flex.js +120 -124
- package/dist/react/core/layout/Flex.js.map +1 -1
- package/dist/react/core/layout/Grid.d.ts +5 -6
- package/dist/react/core/layout/Grid.js +131 -138
- package/dist/react/core/layout/Grid.js.map +1 -1
- package/dist/react/core/layout/Spacer.d.ts +0 -1
- package/dist/react/core/layout/Spacer.js +36 -29
- package/dist/react/core/layout/Spacer.js.map +1 -1
- package/dist/react/core/layout/Stack.d.ts +4 -5
- package/dist/react/core/layout/Stack.js +127 -70
- package/dist/react/core/layout/Stack.js.map +1 -1
- package/dist/react/core/layout/responsive.d.ts +1 -2
- package/dist/react/core/layout/responsive.js +25 -19
- package/dist/react/core/layout/responsive.js.map +1 -1
- package/dist/react/core/layout/useBreakpoint.d.ts +1 -1
- package/dist/react/core/layout/useBreakpoint.js +119 -66
- package/dist/react/core/layout/useBreakpoint.js.map +1 -1
- package/dist/react/core/navigation/AppBar.d.ts +1 -2
- package/dist/react/core/navigation/AppBar.js +827 -805
- package/dist/react/core/navigation/AppBar.js.map +1 -1
- package/dist/react/core/navigation/Pagination.d.ts +2 -3
- package/dist/react/core/navigation/Pagination.js +207 -187
- package/dist/react/core/navigation/Pagination.js.map +1 -1
- package/dist/react/core/navigation/SideNav.d.ts +5 -6
- package/dist/react/core/navigation/SideNav.js +855 -629
- package/dist/react/core/navigation/SideNav.js.map +1 -1
- package/dist/react/core/navigation/Tabs.d.ts +0 -1
- package/dist/react/core/navigation/Tabs.js +113 -119
- package/dist/react/core/navigation/Tabs.js.map +1 -1
- package/dist/react/core/overlays/Popover.d.ts +2 -3
- package/dist/react/core/overlays/Popover.js +303 -282
- package/dist/react/core/overlays/Popover.js.map +1 -1
- package/dist/react/core/overlays/SidePanel.d.ts +1 -2
- package/dist/react/core/overlays/SidePanel.js +217 -212
- package/dist/react/core/overlays/SidePanel.js.map +1 -1
- package/dist/react/core/overlays/Tooltip.d.ts +1 -2
- package/dist/react/core/overlays/Tooltip.js +170 -176
- package/dist/react/core/overlays/Tooltip.js.map +1 -1
- package/dist/react/core/widgets/ActivityPlanner.d.ts +0 -1
- package/dist/react/core/widgets/ActivityPlanner.js +855 -517
- package/dist/react/core/widgets/ActivityPlanner.js.map +1 -1
- package/dist/react/core/widgets/Capture.d.ts +2 -3
- package/dist/react/core/widgets/Capture.js +965 -779
- package/dist/react/core/widgets/Capture.js.map +1 -1
- package/dist/react/core/widgets/ChatPanel.d.ts +16 -17
- package/dist/react/core/widgets/ChatPanel.js +1734 -1034
- package/dist/react/core/widgets/ChatPanel.js.map +1 -1
- package/dist/react/core/widgets/ColorPickerPanel.d.ts +0 -1
- package/dist/react/core/widgets/ColorPickerPanel.js +298 -287
- package/dist/react/core/widgets/ColorPickerPanel.js.map +1 -1
- package/dist/react/core/widgets/CommandBuilder.d.ts +2 -3
- package/dist/react/core/widgets/CommandBuilder.js +624 -516
- package/dist/react/core/widgets/CommandBuilder.js.map +1 -1
- package/dist/react/core/widgets/ConnectionForm.d.ts +2 -3
- package/dist/react/core/widgets/ConnectionForm.js +528 -492
- package/dist/react/core/widgets/ConnectionForm.js.map +1 -1
- package/dist/react/core/widgets/FileExplorer.d.ts +3 -4
- package/dist/react/core/widgets/FileExplorer.js +617 -505
- package/dist/react/core/widgets/FileExplorer.js.map +1 -1
- package/dist/react/core/widgets/HexViewer.d.ts +2 -3
- package/dist/react/core/widgets/HexViewer.js +1353 -1091
- package/dist/react/core/widgets/HexViewer.js.map +1 -1
- package/dist/react/core/widgets/ImageFrame.d.ts +1 -2
- package/dist/react/core/widgets/ImageFrame.js +230 -193
- package/dist/react/core/widgets/ImageFrame.js.map +1 -1
- package/dist/react/core/widgets/ImageGallery.d.ts +2 -1
- package/dist/react/core/widgets/ImageGallery.js +380 -314
- package/dist/react/core/widgets/ImageGallery.js.map +1 -1
- package/dist/react/core/widgets/ImagePanel.d.ts +0 -1
- package/dist/react/core/widgets/ImagePanel.js +110 -101
- package/dist/react/core/widgets/ImagePanel.js.map +1 -1
- package/dist/react/core/widgets/LogViewer.d.ts +2 -3
- package/dist/react/core/widgets/LogViewer.js +711 -607
- package/dist/react/core/widgets/LogViewer.js.map +1 -1
- package/dist/react/core/widgets/MessageStream.d.ts +3 -4
- package/dist/react/core/widgets/MessageStream.js +514 -444
- package/dist/react/core/widgets/MessageStream.js.map +1 -1
- package/dist/react/core/widgets/MissionCalendar.d.ts +3 -4
- package/dist/react/core/widgets/MissionCalendar.js +1488 -1020
- package/dist/react/core/widgets/MissionCalendar.js.map +1 -1
- package/dist/react/core/widgets/PacketViewer.d.ts +2 -3
- package/dist/react/core/widgets/PacketViewer.js +550 -421
- package/dist/react/core/widgets/PacketViewer.js.map +1 -1
- package/dist/react/core/widgets/capture-placeholder.png.js +6 -5
- package/dist/react/core/widgets/capture-placeholder.png.js.map +1 -1
- package/dist/react/hooks/index.d.ts +5 -5
- package/dist/react/hooks/useAccessWindows.d.ts +0 -1
- package/dist/react/hooks/useCompactMode.d.ts +1 -1
- package/dist/react/hooks/useCompactMode.js +104 -58
- package/dist/react/hooks/useCompactMode.js.map +1 -1
- package/dist/react/hooks/useGroundTrackHistory.d.ts +0 -1
- package/dist/react/hooks/useSimulationScene.d.ts +1 -2
- package/dist/react/hooks/useSimulationScene.js +481 -374
- package/dist/react/hooks/useSimulationScene.js.map +1 -1
- package/dist/react/index.d.ts +3 -3
- package/dist/react/panels/LayerControlPanel.d.ts +1 -2
- package/dist/react/panels/LayerControlPanel.js +223 -180
- package/dist/react/panels/LayerControlPanel.js.map +1 -1
- package/dist/react/panels/ObjectInventoryPanel.d.ts +2 -3
- package/dist/react/panels/ObjectInventoryPanel.js +315 -250
- package/dist/react/panels/ObjectInventoryPanel.js.map +1 -1
- package/dist/react/panels/index.d.ts +1 -1
- package/dist/react/panels/index.js +1 -6
- package/dist/react/shared/ErrorBoundary.d.ts +1 -2
- package/dist/react/shared/ErrorBoundary.js +170 -139
- package/dist/react/shared/ErrorBoundary.js.map +1 -1
- package/dist/react/shared/Skeleton.d.ts +1 -2
- package/dist/react/shared/Skeleton.js +300 -301
- package/dist/react/shared/Skeleton.js.map +1 -1
- package/dist/react/theme/ThemeProvider.d.ts +2 -321
- package/dist/react/theme/ThemeProvider.js +312 -939
- package/dist/react/theme/ThemeProvider.js.map +1 -1
- package/dist/react/theme/cardAccent.d.ts +1 -2
- package/dist/react/theme/cardAccent.js +196 -126
- package/dist/react/theme/cardAccent.js.map +1 -1
- package/dist/react/theme/config.d.ts +0 -1
- package/dist/react/theme/config.js +47 -25
- package/dist/react/theme/config.js.map +1 -1
- package/dist/react/theme/index.d.ts +2 -2
- package/dist/react/theme/index.js +1 -16
- package/dist/react/theme/types.d.ts +332 -0
- package/dist/react/theme/types.js +39 -0
- package/dist/react/theme/types.js.map +1 -0
- package/dist/react/types.d.ts +8 -8
- package/dist/react/types.js +147 -47
- package/dist/react/types.js.map +1 -1
- package/dist/react/utils/categoryPalette.d.ts +0 -1
- package/dist/react/utils/categoryPalette.js +91 -102
- package/dist/react/utils/categoryPalette.js.map +1 -1
- package/dist/react/utils/index.d.ts +5 -5
- package/dist/react/utils/index.js +457 -371
- package/dist/react/utils/index.js.map +1 -1
- package/dist/react/visualizations/EclipseTimerCard.d.ts +0 -1
- package/dist/react/visualizations/LinkBudgetCard.d.ts +0 -1
- package/dist/react/visualizations/NavBallCard.d.ts +0 -1
- package/dist/react/visualizations/PropulsionCard.d.ts +1 -2
- package/dist/react/visualizations/SensorFootprintCard.d.ts +1 -2
- package/dist/react/visualizations/ThermalHeatmapCard.d.ts +0 -1
- package/dist/react/visualizations/index.d.ts +3 -3
- package/dist/react.d.ts +2 -1
- package/dist/react.js +17 -221
- package/dist/shaders/atmosphere.frag.js +6 -5
- package/dist/shaders/atmosphere.frag.js.map +1 -1
- package/dist/shaders/atmosphere.vert.js +6 -5
- package/dist/shaders/atmosphere.vert.js.map +1 -1
- package/dist/shaders/stars.frag.js +6 -5
- package/dist/shaders/stars.frag.js.map +1 -1
- package/dist/shaders/stars.vert.js +6 -5
- package/dist/shaders/stars.vert.js.map +1 -1
- package/dist/style.css +217 -194
- package/dist/tokens/core.d.ts +159 -0
- package/dist/tokens/core.js +144 -0
- package/dist/tokens/core.js.map +1 -0
- package/dist/tokens/css-vars.d.ts +213 -2
- package/dist/tokens/css-vars.js +590 -227
- package/dist/tokens/css-vars.js.map +1 -1
- package/dist/tokens/index.d.ts +31 -228
- package/dist/tokens/index.js +281 -366
- package/dist/tokens/index.js.map +1 -1
- package/dist/tokens/palettes/astro.d.ts +129 -0
- package/dist/tokens/palettes/astro.js +112 -0
- package/dist/tokens/palettes/astro.js.map +1 -0
- package/dist/tokens/palettes/index.d.ts +288 -0
- package/dist/tokens/palettes/index.js +35 -0
- package/dist/tokens/palettes/index.js.map +1 -0
- package/dist/tokens/palettes/tailwind.d.ts +324 -0
- package/dist/tokens/palettes/tailwind.js +201 -0
- package/dist/tokens/palettes/tailwind.js.map +1 -0
- package/dist/tokens/palettes/zendir.d.ts +126 -0
- package/dist/tokens/palettes/zendir.js +92 -0
- package/dist/tokens/palettes/zendir.js.map +1 -0
- package/dist/tokens/themes.d.ts +30 -0
- package/dist/tokens/themes.js +704 -0
- package/dist/tokens/themes.js.map +1 -0
- package/dist/tokens/tokens.css +419 -41
- package/dist/types/index.d.ts +2 -2
- package/package.json +310 -313
- package/dist/index.js.map +0 -1
- package/dist/react/3d/index.js.map +0 -1
- package/dist/react/astro/index.js.map +0 -1
- package/dist/react/cards/index.js.map +0 -1
- package/dist/react/charts/index.js.map +0 -1
- package/dist/react/core/index.js.map +0 -1
- package/dist/react/panels/index.js.map +0 -1
- package/dist/react/theme/astro-tokens.d.ts +0 -153
- package/dist/react/theme/index.js.map +0 -1
- package/dist/react.js.map +0 -1
|
@@ -1,163 +1,184 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { useCallback, useEffect, useState, useSyncExternalStore } from "react";
|
|
2
|
+
//#region src/react/chatgpt/index.ts
|
|
3
|
+
/**
|
|
4
|
+
* ChatGPT Apps SDK Integration
|
|
5
|
+
*
|
|
6
|
+
* Hooks and utilities for integrating Zendir UI components with ChatGPT's
|
|
7
|
+
* window.openai API. Based on: https://developers.openai.com/apps-sdk/build/chatgpt-ui/
|
|
8
|
+
*
|
|
9
|
+
* Key capabilities:
|
|
10
|
+
* - window.openai.toolInput / toolOutput - Tool data from MCP server
|
|
11
|
+
* - window.openai.widgetState / setWidgetState - Persistent UI state
|
|
12
|
+
* - window.openai.callTool - Invoke other MCP tools from widget
|
|
13
|
+
* - window.openai.sendFollowUpMessage - Insert user messages
|
|
14
|
+
* - window.openai.theme - Light/dark theme detection
|
|
15
|
+
* - window.openai.locale - Localization
|
|
16
|
+
* - window.openai.requestDisplayMode - Fullscreen/PiP modes
|
|
17
|
+
* - window.openai.notifyIntrinsicHeight - Dynamic height reporting
|
|
18
|
+
*/
|
|
19
|
+
var SET_GLOBALS_EVENT_TYPE = "openai:set_globals";
|
|
20
|
+
/**
|
|
21
|
+
* Subscribe to a specific window.openai global value
|
|
22
|
+
*/
|
|
3
23
|
function useOpenAiGlobal(key) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal, { passive: true });
|
|
17
|
-
return () => window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal);
|
|
18
|
-
}, [key]);
|
|
19
|
-
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
24
|
+
const getSnapshot = useCallback(() => {
|
|
25
|
+
return window.openai?.[key];
|
|
26
|
+
}, [key]);
|
|
27
|
+
return useSyncExternalStore(useCallback((onChange) => {
|
|
28
|
+
const handleSetGlobal = (event) => {
|
|
29
|
+
if (event.detail?.globals?.[key] !== void 0) onChange();
|
|
30
|
+
};
|
|
31
|
+
window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal, { passive: true });
|
|
32
|
+
return () => window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal);
|
|
33
|
+
}, [key]), getSnapshot, getSnapshot);
|
|
20
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Manage widget state that persists across renders via window.openai.setWidgetState
|
|
37
|
+
*/
|
|
21
38
|
function useWidgetState(defaultState) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const newState = typeof state === "function" ? state(prevState) : state;
|
|
38
|
-
(_b = (_a = window.openai) == null ? void 0 : _a.setWidgetState) == null ? void 0 : _b.call(_a, newState);
|
|
39
|
-
return newState;
|
|
40
|
-
});
|
|
41
|
-
}, []);
|
|
42
|
-
return [widgetState, setWidgetState];
|
|
39
|
+
const widgetStateFromWindow = useOpenAiGlobal("widgetState");
|
|
40
|
+
const [widgetState, _setWidgetState] = useState(() => {
|
|
41
|
+
if (widgetStateFromWindow != null) return widgetStateFromWindow;
|
|
42
|
+
return typeof defaultState === "function" ? defaultState() : defaultState;
|
|
43
|
+
});
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (widgetStateFromWindow != null) _setWidgetState(widgetStateFromWindow);
|
|
46
|
+
}, [widgetStateFromWindow]);
|
|
47
|
+
return [widgetState, useCallback((state) => {
|
|
48
|
+
_setWidgetState((prevState) => {
|
|
49
|
+
const newState = typeof state === "function" ? state(prevState) : state;
|
|
50
|
+
window.openai?.setWidgetState?.(newState);
|
|
51
|
+
return newState;
|
|
52
|
+
});
|
|
53
|
+
}, [])];
|
|
43
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Read the tool output (structuredContent) from the MCP server response
|
|
57
|
+
*/
|
|
44
58
|
function useToolOutput() {
|
|
45
|
-
|
|
59
|
+
return useOpenAiGlobal("toolOutput");
|
|
46
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Read the tool input (arguments) from the tool invocation
|
|
63
|
+
*/
|
|
47
64
|
function useToolInput() {
|
|
48
|
-
|
|
65
|
+
return useOpenAiGlobal("toolInput");
|
|
49
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Get current ChatGPT theme and provide CSS-friendly values
|
|
69
|
+
* Named useChatGPTTheme to avoid conflict with the core useTheme from ThemeProvider
|
|
70
|
+
*/
|
|
50
71
|
function useChatGPTTheme() {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
};
|
|
72
|
+
const theme = useOpenAiGlobal("theme") ?? "dark";
|
|
73
|
+
const isDark = theme === "dark";
|
|
74
|
+
return {
|
|
75
|
+
theme,
|
|
76
|
+
isDark,
|
|
77
|
+
colors: isDark ? {
|
|
78
|
+
background: "#09090b",
|
|
79
|
+
surface: "#18181b",
|
|
80
|
+
surfaceHover: "#27272a",
|
|
81
|
+
border: "#3f3f46",
|
|
82
|
+
text: "#fafafa",
|
|
83
|
+
textMuted: "#a1a1aa",
|
|
84
|
+
accent: "#22d3ee"
|
|
85
|
+
} : {
|
|
86
|
+
background: "#ffffff",
|
|
87
|
+
surface: "#f4f4f5",
|
|
88
|
+
surfaceHover: "#e4e4e7",
|
|
89
|
+
border: "#d4d4d8",
|
|
90
|
+
text: "#18181b",
|
|
91
|
+
textMuted: "#636370",
|
|
92
|
+
accent: "#0ea5e9"
|
|
93
|
+
}
|
|
94
|
+
};
|
|
75
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Get current locale for internationalization
|
|
98
|
+
*/
|
|
76
99
|
function useLocale() {
|
|
77
|
-
|
|
100
|
+
return useOpenAiGlobal("locale") ?? "en-US";
|
|
78
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Manage widget display mode (inline, PiP, fullscreen)
|
|
104
|
+
*/
|
|
79
105
|
function useDisplayMode() {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return { mode, maxHeight, requestMode, close };
|
|
106
|
+
return {
|
|
107
|
+
mode: useOpenAiGlobal("displayMode") ?? "inline",
|
|
108
|
+
maxHeight: useOpenAiGlobal("maxHeight"),
|
|
109
|
+
requestMode: useCallback(async (newMode) => {
|
|
110
|
+
await window.openai?.requestDisplayMode?.({ mode: newMode });
|
|
111
|
+
}, []),
|
|
112
|
+
close: useCallback(() => {
|
|
113
|
+
window.openai?.requestClose?.();
|
|
114
|
+
}, [])
|
|
115
|
+
};
|
|
91
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Call another MCP tool from within a widget
|
|
119
|
+
*/
|
|
92
120
|
function useCallTool() {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return { callTool, isLoading, error };
|
|
121
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
122
|
+
const [error, setError] = useState(null);
|
|
123
|
+
return {
|
|
124
|
+
callTool: useCallback(async (name, args) => {
|
|
125
|
+
if (!window.openai?.callTool) throw new Error("window.openai.callTool not available");
|
|
126
|
+
setIsLoading(true);
|
|
127
|
+
setError(null);
|
|
128
|
+
try {
|
|
129
|
+
return await window.openai.callTool(name, args);
|
|
130
|
+
} catch (err) {
|
|
131
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
132
|
+
setError(error);
|
|
133
|
+
throw error;
|
|
134
|
+
} finally {
|
|
135
|
+
setIsLoading(false);
|
|
136
|
+
}
|
|
137
|
+
}, []),
|
|
138
|
+
isLoading,
|
|
139
|
+
error
|
|
140
|
+
};
|
|
114
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Send a follow-up message as if the user asked it
|
|
144
|
+
*/
|
|
115
145
|
function useSendMessage() {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}, []);
|
|
146
|
+
return useCallback(async (prompt) => {
|
|
147
|
+
await window.openai?.sendFollowUpMessage?.({ prompt });
|
|
148
|
+
}, []);
|
|
120
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Get the maximum height available for the widget from the host environment.
|
|
152
|
+
* This is the CORRECT pattern per OpenAI Apps SDK examples.
|
|
153
|
+
*
|
|
154
|
+
* The host (ChatGPT/MCPJam) provides maxHeight, and widgets should constrain
|
|
155
|
+
* themselves to this height. Widgets should NOT report their height back.
|
|
156
|
+
*
|
|
157
|
+
* @returns The maximum height in pixels, or undefined if not available
|
|
158
|
+
*/
|
|
121
159
|
function useMaxHeight() {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if (((_a = event.detail) == null ? void 0 : _a.globals) && "maxHeight" in event.detail.globals) {
|
|
132
|
-
setMaxHeight(event.detail.globals.maxHeight);
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
window.addEventListener("openai:set_globals", handler);
|
|
136
|
-
return () => window.removeEventListener("openai:set_globals", handler);
|
|
137
|
-
}, []);
|
|
138
|
-
return maxHeight;
|
|
160
|
+
const [maxHeight, setMaxHeight] = useState(() => window.openai?.maxHeight);
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
const handler = (event) => {
|
|
163
|
+
if (event.detail?.globals && "maxHeight" in event.detail.globals) setMaxHeight(event.detail.globals.maxHeight);
|
|
164
|
+
};
|
|
165
|
+
window.addEventListener("openai:set_globals", handler);
|
|
166
|
+
return () => window.removeEventListener("openai:set_globals", handler);
|
|
167
|
+
}, []);
|
|
168
|
+
return maxHeight;
|
|
139
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Open vetted external links in the user's browser
|
|
172
|
+
*/
|
|
140
173
|
function useOpenExternal() {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}, []);
|
|
174
|
+
return useCallback((href) => {
|
|
175
|
+
window.openai?.openExternal?.({ href });
|
|
176
|
+
}, []);
|
|
145
177
|
}
|
|
146
178
|
function isInChatGPT() {
|
|
147
|
-
|
|
179
|
+
return typeof window !== "undefined" && window.openai !== void 0;
|
|
148
180
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
useDisplayMode,
|
|
154
|
-
useLocale,
|
|
155
|
-
useMaxHeight,
|
|
156
|
-
useOpenAiGlobal,
|
|
157
|
-
useOpenExternal,
|
|
158
|
-
useSendMessage,
|
|
159
|
-
useToolInput,
|
|
160
|
-
useToolOutput,
|
|
161
|
-
useWidgetState
|
|
162
|
-
};
|
|
163
|
-
//# sourceMappingURL=index.js.map
|
|
181
|
+
//#endregion
|
|
182
|
+
export { isInChatGPT, useCallTool, useChatGPTTheme, useDisplayMode, useLocale, useMaxHeight, useOpenAiGlobal, useOpenExternal, useSendMessage, useToolInput, useToolOutput, useWidgetState };
|
|
183
|
+
|
|
184
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/react/chatgpt/index.ts"],"sourcesContent":["/**\n * ChatGPT Apps SDK Integration\n * \n * Hooks and utilities for integrating Zendir UI components with ChatGPT's\n * window.openai API. Based on: https://developers.openai.com/apps-sdk/build/chatgpt-ui/\n * \n * Key capabilities:\n * - window.openai.toolInput / toolOutput - Tool data from MCP server\n * - window.openai.widgetState / setWidgetState - Persistent UI state\n * - window.openai.callTool - Invoke other MCP tools from widget\n * - window.openai.sendFollowUpMessage - Insert user messages\n * - window.openai.theme - Light/dark theme detection\n * - window.openai.locale - Localization\n * - window.openai.requestDisplayMode - Fullscreen/PiP modes\n * - window.openai.notifyIntrinsicHeight - Dynamic height reporting\n */\n\nimport { useState, useEffect, useCallback, useSyncExternalStore } from 'react';\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\nexport interface OpenAiGlobals {\n /** Arguments supplied when the tool was invoked */\n toolInput?: Record<string, unknown>;\n /** Your structuredContent - the model reads this */\n toolOutput?: Record<string, unknown>;\n /** Metadata payload - only widget sees it */\n toolResponseMetadata?: Record<string, unknown>;\n /** Snapshot of UI state persisted between renders */\n widgetState?: Record<string, unknown>;\n /** Current theme */\n theme?: 'light' | 'dark';\n /** Current locale (e.g., 'en-US') */\n locale?: string;\n /** Display mode */\n displayMode?: 'inline' | 'pip' | 'fullscreen';\n /** Maximum allowed height */\n maxHeight?: number;\n /** View type */\n view?: 'conversation' | 'modal';\n /** User agent info */\n userAgent?: string;\n /** Safe area insets */\n safeArea?: { top: number; bottom: number; left: number; right: number };\n \n // API Methods\n setWidgetState?: (state: Record<string, unknown>) => void;\n callTool?: (name: string, args: Record<string, unknown>) => Promise<unknown>;\n sendFollowUpMessage?: (options: { prompt: string }) => Promise<void>;\n uploadFile?: (file: File) => Promise<{ fileId: string }>;\n getFileDownloadUrl?: (options: { fileId: string }) => Promise<{ downloadUrl: string }>;\n requestDisplayMode?: (options: { mode: 'inline' | 'pip' | 'fullscreen' }) => Promise<void>;\n requestModal?: (options: unknown) => Promise<void>;\n notifyIntrinsicHeight?: (height: number) => void;\n openExternal?: (options: { href: string }) => void;\n requestClose?: () => void;\n}\n\ndeclare global {\n interface Window {\n openai?: OpenAiGlobals;\n }\n}\n\n// ============================================================================\n// Core Hook: useOpenAiGlobal\n// ============================================================================\n\nconst SET_GLOBALS_EVENT_TYPE = 'openai:set_globals';\n\ninterface SetGlobalsEvent extends CustomEvent {\n detail: { globals: Partial<OpenAiGlobals> };\n}\n\n/**\n * Subscribe to a specific window.openai global value\n */\nexport function useOpenAiGlobal<K extends keyof OpenAiGlobals>(key: K): OpenAiGlobals[K] {\n const getSnapshot = useCallback(() => {\n return window.openai?.[key];\n }, [key]);\n\n const subscribe = useCallback((onChange: () => void) => {\n const handleSetGlobal = (event: Event) => {\n const customEvent = event as SetGlobalsEvent;\n if (customEvent.detail?.globals?.[key] !== undefined) {\n onChange();\n }\n };\n\n window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal, { passive: true });\n return () => window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal);\n }, [key]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n// ============================================================================\n// Widget State Hook\n// ============================================================================\n\ntype SetStateAction<T> = T | ((prevState: T) => T);\n\n/**\n * Manage widget state that persists across renders via window.openai.setWidgetState\n */\nexport function useWidgetState<T extends Record<string, unknown>>(\n defaultState: T | (() => T)\n): readonly [T, (state: SetStateAction<T>) => void] {\n const widgetStateFromWindow = useOpenAiGlobal('widgetState') as T | undefined;\n\n const [widgetState, _setWidgetState] = useState<T>(() => {\n if (widgetStateFromWindow != null) {\n return widgetStateFromWindow;\n }\n return typeof defaultState === 'function' ? (defaultState as () => T)() : defaultState;\n });\n\n useEffect(() => {\n if (widgetStateFromWindow != null) {\n _setWidgetState(widgetStateFromWindow);\n }\n }, [widgetStateFromWindow]);\n\n const setWidgetState = useCallback((state: SetStateAction<T>) => {\n _setWidgetState((prevState: T) => {\n const newState = typeof state === 'function' ? (state as (p: T) => T)(prevState) : state;\n window.openai?.setWidgetState?.(newState);\n return newState;\n });\n }, []);\n\n return [widgetState, setWidgetState] as const;\n}\n\n// ============================================================================\n// Tool Output Hook\n// ============================================================================\n\n/**\n * Read the tool output (structuredContent) from the MCP server response\n */\nexport function useToolOutput<T = Record<string, unknown>>(): T | undefined {\n return useOpenAiGlobal('toolOutput') as T | undefined;\n}\n\n/**\n * Read the tool input (arguments) from the tool invocation\n */\nexport function useToolInput<T = Record<string, unknown>>(): T | undefined {\n return useOpenAiGlobal('toolInput') as T | undefined;\n}\n\n// ============================================================================\n// Theme Hook\n// ============================================================================\n\nexport type ThemeMode = 'light' | 'dark';\n\n/**\n * Get current ChatGPT theme and provide CSS-friendly values\n * Named useChatGPTTheme to avoid conflict with the core useTheme from ThemeProvider\n */\nexport function useChatGPTTheme(): {\n theme: ThemeMode;\n isDark: boolean;\n colors: {\n background: string;\n surface: string;\n surfaceHover: string;\n border: string;\n text: string;\n textMuted: string;\n accent: string;\n };\n} {\n const theme = useOpenAiGlobal('theme') ?? 'dark';\n const isDark = theme === 'dark';\n\n return {\n theme,\n isDark,\n colors: isDark ? {\n background: '#09090b',\n surface: '#18181b',\n surfaceHover: '#27272a',\n border: '#3f3f46',\n text: '#fafafa',\n textMuted: '#a1a1aa',\n accent: '#22d3ee',\n } : {\n background: '#ffffff',\n surface: '#f4f4f5',\n surfaceHover: '#e4e4e7',\n border: '#d4d4d8',\n text: '#18181b',\n textMuted: '#636370', // WCAG AA: 5.90:1 on #fff, 5.39:1 on #f4f4f5, 4.66:1 on #e4e4e7 (was #71717a → 4.49:1 FAIL on surface)\n accent: '#0ea5e9',\n },\n };\n}\n\n// ============================================================================\n// Locale Hook\n// ============================================================================\n\n/**\n * Get current locale for internationalization\n */\nexport function useLocale(): string {\n return useOpenAiGlobal('locale') ?? 'en-US';\n}\n\n// ============================================================================\n// Display Mode Hook\n// ============================================================================\n\n/**\n * Manage widget display mode (inline, PiP, fullscreen)\n */\nexport function useDisplayMode(): {\n mode: 'inline' | 'pip' | 'fullscreen';\n maxHeight?: number;\n requestMode: (mode: 'inline' | 'pip' | 'fullscreen') => Promise<void>;\n close: () => void;\n} {\n const mode = useOpenAiGlobal('displayMode') ?? 'inline';\n const maxHeight = useOpenAiGlobal('maxHeight');\n\n const requestMode = useCallback(async (newMode: 'inline' | 'pip' | 'fullscreen') => {\n await window.openai?.requestDisplayMode?.({ mode: newMode });\n }, []);\n\n const close = useCallback(() => {\n window.openai?.requestClose?.();\n }, []);\n\n return { mode, maxHeight, requestMode, close };\n}\n\n// ============================================================================\n// Tool Calling Hook\n// ============================================================================\n\n/**\n * Call another MCP tool from within a widget\n */\nexport function useCallTool(): {\n callTool: <T = unknown>(name: string, args: Record<string, unknown>) => Promise<T>;\n isLoading: boolean;\n error: Error | null;\n} {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const callTool = useCallback(async <T = unknown>(\n name: string,\n args: Record<string, unknown>\n ): Promise<T> => {\n if (!window.openai?.callTool) {\n throw new Error('window.openai.callTool not available');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await window.openai.callTool(name, args);\n return result as T;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n throw error;\n } finally {\n setIsLoading(false);\n }\n }, []);\n\n return { callTool, isLoading, error };\n}\n\n// ============================================================================\n// Follow-up Message Hook\n// ============================================================================\n\n/**\n * Send a follow-up message as if the user asked it\n */\nexport function useSendMessage(): (prompt: string) => Promise<void> {\n return useCallback(async (prompt: string) => {\n await window.openai?.sendFollowUpMessage?.({ prompt });\n }, []);\n}\n\n// ============================================================================\n// Dynamic Height Hook\n// ============================================================================\n\n/**\n * Get the maximum height available for the widget from the host environment.\n * This is the CORRECT pattern per OpenAI Apps SDK examples.\n * \n * The host (ChatGPT/MCPJam) provides maxHeight, and widgets should constrain\n * themselves to this height. Widgets should NOT report their height back.\n * \n * @returns The maximum height in pixels, or undefined if not available\n */\nexport function useMaxHeight(): number | undefined {\n const [maxHeight, setMaxHeight] = useState<number | undefined>(\n () => window.openai?.maxHeight\n );\n \n useEffect(() => {\n const handler = (event: CustomEvent) => {\n if (event.detail?.globals && 'maxHeight' in event.detail.globals) {\n setMaxHeight(event.detail.globals.maxHeight);\n }\n };\n \n window.addEventListener('openai:set_globals', handler as EventListener);\n return () => window.removeEventListener('openai:set_globals', handler as EventListener);\n }, []);\n \n return maxHeight;\n}\n\n// ============================================================================\n// External Link Hook\n// ============================================================================\n\n/**\n * Open vetted external links in the user's browser\n */\nexport function useOpenExternal(): (href: string) => void {\n return useCallback((href: string) => {\n window.openai?.openExternal?.({ href });\n }, []);\n}\n\n// ============================================================================\n// Utility: Check if running in ChatGPT\n// ============================================================================\n\nexport function isInChatGPT(): boolean {\n return typeof window !== 'undefined' && window.openai !== undefined;\n}\n\n// ============================================================================\n// Re-exports (types are already exported above)\n// ============================================================================\n\n"],"names":["error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/react/chatgpt/index.ts"],"sourcesContent":["/**\n * ChatGPT Apps SDK Integration\n *\n * Hooks and utilities for integrating Zendir UI components with ChatGPT's\n * window.openai API. Based on: https://developers.openai.com/apps-sdk/build/chatgpt-ui/\n *\n * Key capabilities:\n * - window.openai.toolInput / toolOutput - Tool data from MCP server\n * - window.openai.widgetState / setWidgetState - Persistent UI state\n * - window.openai.callTool - Invoke other MCP tools from widget\n * - window.openai.sendFollowUpMessage - Insert user messages\n * - window.openai.theme - Light/dark theme detection\n * - window.openai.locale - Localization\n * - window.openai.requestDisplayMode - Fullscreen/PiP modes\n * - window.openai.notifyIntrinsicHeight - Dynamic height reporting\n */\n\nimport { useState, useEffect, useCallback, useSyncExternalStore } from \"react\";\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\nexport interface OpenAiGlobals {\n /** Arguments supplied when the tool was invoked */\n toolInput?: Record<string, unknown>;\n /** Your structuredContent - the model reads this */\n toolOutput?: Record<string, unknown>;\n /** Metadata payload - only widget sees it */\n toolResponseMetadata?: Record<string, unknown>;\n /** Snapshot of UI state persisted between renders */\n widgetState?: Record<string, unknown>;\n /** Current theme */\n theme?: \"light\" | \"dark\";\n /** Current locale (e.g., 'en-US') */\n locale?: string;\n /** Display mode */\n displayMode?: \"inline\" | \"pip\" | \"fullscreen\";\n /** Maximum allowed height */\n maxHeight?: number;\n /** View type */\n view?: \"conversation\" | \"modal\";\n /** User agent info */\n userAgent?: string;\n /** Safe area insets */\n safeArea?: { top: number; bottom: number; left: number; right: number };\n\n // API Methods\n setWidgetState?: (state: Record<string, unknown>) => void;\n callTool?: (name: string, args: Record<string, unknown>) => Promise<unknown>;\n sendFollowUpMessage?: (options: { prompt: string }) => Promise<void>;\n uploadFile?: (file: File) => Promise<{ fileId: string }>;\n getFileDownloadUrl?: (options: {\n fileId: string;\n }) => Promise<{ downloadUrl: string }>;\n requestDisplayMode?: (options: {\n mode: \"inline\" | \"pip\" | \"fullscreen\";\n }) => Promise<void>;\n requestModal?: (options: unknown) => Promise<void>;\n notifyIntrinsicHeight?: (height: number) => void;\n openExternal?: (options: { href: string }) => void;\n requestClose?: () => void;\n}\n\ndeclare global {\n interface Window {\n openai?: OpenAiGlobals;\n }\n}\n\n// ============================================================================\n// Core Hook: useOpenAiGlobal\n// ============================================================================\n\nconst SET_GLOBALS_EVENT_TYPE = \"openai:set_globals\";\n\ninterface SetGlobalsEvent extends CustomEvent {\n detail: { globals: Partial<OpenAiGlobals> };\n}\n\n/**\n * Subscribe to a specific window.openai global value\n */\nexport function useOpenAiGlobal<K extends keyof OpenAiGlobals>(\n key: K,\n): OpenAiGlobals[K] {\n const getSnapshot = useCallback(() => {\n return window.openai?.[key];\n }, [key]);\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const handleSetGlobal = (event: Event) => {\n const customEvent = event as SetGlobalsEvent;\n if (customEvent.detail?.globals?.[key] !== undefined) {\n onChange();\n }\n };\n\n window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal, {\n passive: true,\n });\n return () =>\n window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal);\n },\n [key],\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n// ============================================================================\n// Widget State Hook\n// ============================================================================\n\ntype SetStateAction<T> = T | ((prevState: T) => T);\n\n/**\n * Manage widget state that persists across renders via window.openai.setWidgetState\n */\nexport function useWidgetState<T extends Record<string, unknown>>(\n defaultState: T | (() => T),\n): readonly [T, (state: SetStateAction<T>) => void] {\n const widgetStateFromWindow = useOpenAiGlobal(\"widgetState\") as T | undefined;\n\n const [widgetState, _setWidgetState] = useState<T>(() => {\n if (widgetStateFromWindow != null) {\n return widgetStateFromWindow;\n }\n return typeof defaultState === \"function\"\n ? (defaultState as () => T)()\n : defaultState;\n });\n\n useEffect(() => {\n if (widgetStateFromWindow != null) {\n _setWidgetState(widgetStateFromWindow);\n }\n }, [widgetStateFromWindow]);\n\n const setWidgetState = useCallback((state: SetStateAction<T>) => {\n _setWidgetState((prevState: T) => {\n const newState =\n typeof state === \"function\" ? (state as (p: T) => T)(prevState) : state;\n window.openai?.setWidgetState?.(newState);\n return newState;\n });\n }, []);\n\n return [widgetState, setWidgetState] as const;\n}\n\n// ============================================================================\n// Tool Output Hook\n// ============================================================================\n\n/**\n * Read the tool output (structuredContent) from the MCP server response\n */\nexport function useToolOutput<T = Record<string, unknown>>(): T | undefined {\n return useOpenAiGlobal(\"toolOutput\") as T | undefined;\n}\n\n/**\n * Read the tool input (arguments) from the tool invocation\n */\nexport function useToolInput<T = Record<string, unknown>>(): T | undefined {\n return useOpenAiGlobal(\"toolInput\") as T | undefined;\n}\n\n// ============================================================================\n// Theme Hook\n// ============================================================================\n\nexport type ThemeMode = \"light\" | \"dark\";\n\n/**\n * Get current ChatGPT theme and provide CSS-friendly values\n * Named useChatGPTTheme to avoid conflict with the core useTheme from ThemeProvider\n */\nexport function useChatGPTTheme(): {\n theme: ThemeMode;\n isDark: boolean;\n colors: {\n background: string;\n surface: string;\n surfaceHover: string;\n border: string;\n text: string;\n textMuted: string;\n accent: string;\n };\n} {\n const theme = useOpenAiGlobal(\"theme\") ?? \"dark\";\n const isDark = theme === \"dark\";\n\n return {\n theme,\n isDark,\n colors: isDark\n ? {\n background: \"#09090b\",\n surface: \"#18181b\",\n surfaceHover: \"#27272a\",\n border: \"#3f3f46\",\n text: \"#fafafa\",\n textMuted: \"#a1a1aa\",\n accent: \"#22d3ee\",\n }\n : {\n background: \"#ffffff\",\n surface: \"#f4f4f5\",\n surfaceHover: \"#e4e4e7\",\n border: \"#d4d4d8\",\n text: \"#18181b\",\n textMuted: \"#636370\", // WCAG AA: 5.90:1 on #fff, 5.39:1 on #f4f4f5, 4.66:1 on #e4e4e7 (was #71717a → 4.49:1 FAIL on surface)\n accent: \"#0ea5e9\",\n },\n };\n}\n\n// ============================================================================\n// Locale Hook\n// ============================================================================\n\n/**\n * Get current locale for internationalization\n */\nexport function useLocale(): string {\n return useOpenAiGlobal(\"locale\") ?? \"en-US\";\n}\n\n// ============================================================================\n// Display Mode Hook\n// ============================================================================\n\n/**\n * Manage widget display mode (inline, PiP, fullscreen)\n */\nexport function useDisplayMode(): {\n mode: \"inline\" | \"pip\" | \"fullscreen\";\n maxHeight?: number;\n requestMode: (mode: \"inline\" | \"pip\" | \"fullscreen\") => Promise<void>;\n close: () => void;\n} {\n const mode = useOpenAiGlobal(\"displayMode\") ?? \"inline\";\n const maxHeight = useOpenAiGlobal(\"maxHeight\");\n\n const requestMode = useCallback(\n async (newMode: \"inline\" | \"pip\" | \"fullscreen\") => {\n await window.openai?.requestDisplayMode?.({ mode: newMode });\n },\n [],\n );\n\n const close = useCallback(() => {\n window.openai?.requestClose?.();\n }, []);\n\n return { mode, maxHeight, requestMode, close };\n}\n\n// ============================================================================\n// Tool Calling Hook\n// ============================================================================\n\n/**\n * Call another MCP tool from within a widget\n */\nexport function useCallTool(): {\n callTool: <T = unknown>(\n name: string,\n args: Record<string, unknown>,\n ) => Promise<T>;\n isLoading: boolean;\n error: Error | null;\n} {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const callTool = useCallback(\n async <T = unknown>(\n name: string,\n args: Record<string, unknown>,\n ): Promise<T> => {\n if (!window.openai?.callTool) {\n throw new Error(\"window.openai.callTool not available\");\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await window.openai.callTool(name, args);\n return result as T;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n throw error;\n } finally {\n setIsLoading(false);\n }\n },\n [],\n );\n\n return { callTool, isLoading, error };\n}\n\n// ============================================================================\n// Follow-up Message Hook\n// ============================================================================\n\n/**\n * Send a follow-up message as if the user asked it\n */\nexport function useSendMessage(): (prompt: string) => Promise<void> {\n return useCallback(async (prompt: string) => {\n await window.openai?.sendFollowUpMessage?.({ prompt });\n }, []);\n}\n\n// ============================================================================\n// Dynamic Height Hook\n// ============================================================================\n\n/**\n * Get the maximum height available for the widget from the host environment.\n * This is the CORRECT pattern per OpenAI Apps SDK examples.\n *\n * The host (ChatGPT/MCPJam) provides maxHeight, and widgets should constrain\n * themselves to this height. Widgets should NOT report their height back.\n *\n * @returns The maximum height in pixels, or undefined if not available\n */\nexport function useMaxHeight(): number | undefined {\n const [maxHeight, setMaxHeight] = useState<number | undefined>(\n () => window.openai?.maxHeight,\n );\n\n useEffect(() => {\n const handler = (event: CustomEvent) => {\n if (event.detail?.globals && \"maxHeight\" in event.detail.globals) {\n setMaxHeight(event.detail.globals.maxHeight);\n }\n };\n\n window.addEventListener(\"openai:set_globals\", handler as EventListener);\n return () =>\n window.removeEventListener(\n \"openai:set_globals\",\n handler as EventListener,\n );\n }, []);\n\n return maxHeight;\n}\n\n// ============================================================================\n// External Link Hook\n// ============================================================================\n\n/**\n * Open vetted external links in the user's browser\n */\nexport function useOpenExternal(): (href: string) => void {\n return useCallback((href: string) => {\n window.openai?.openExternal?.({ href });\n }, []);\n}\n\n// ============================================================================\n// Utility: Check if running in ChatGPT\n// ============================================================================\n\nexport function isInChatGPT(): boolean {\n return typeof window !== \"undefined\" && window.openai !== undefined;\n}\n\n// ============================================================================\n// Re-exports (types are already exported above)\n// ============================================================================\n"],"mappings":"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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { default as React, ReactNode } from 'react';
|
|
2
2
|
import { CategoryPalette } from '../utils/categoryPalette';
|
|
3
3
|
import { CategoryDef } from '../types';
|
|
4
|
-
|
|
5
4
|
export interface CategoryContextValue {
|
|
6
5
|
/** Palette instance built from the provided categories. */
|
|
7
6
|
palette: CategoryPalette;
|
|
@@ -1,36 +1,85 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo, useContext, createContext } from "react";
|
|
3
1
|
import { CategoryPalette } from "../utils/categoryPalette.js";
|
|
4
|
-
|
|
2
|
+
import { createContext, useContext, useMemo } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region src/react/context/CategoryContext.tsx
|
|
5
|
+
/**
|
|
6
|
+
* @zendir/ui — CategoryProvider
|
|
7
|
+
*
|
|
8
|
+
* Optional React context for sharing a `CategoryPalette` and display label
|
|
9
|
+
* across sibling components in a dashboard layout. Components that are
|
|
10
|
+
* "category-aware" (Timeline, GroundTrackMap, AstroChart, DataTable) can
|
|
11
|
+
* read from this context to resolve colors/labels without each needing
|
|
12
|
+
* explicit palette props.
|
|
13
|
+
*
|
|
14
|
+
* **This context is fully opt-in.** Components continue to work standalone
|
|
15
|
+
* — explicit `color` / `team` props always take precedence over context.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* import { CategoryProvider, useCategoryPalette } from '@zendir/ui';
|
|
20
|
+
*
|
|
21
|
+
* const categories = [
|
|
22
|
+
* { id: 'alpha', label: 'Team Alpha', color: '#2dccff' },
|
|
23
|
+
* { id: 'bravo', label: 'Team Bravo', color: '#fce83a' },
|
|
24
|
+
* ];
|
|
25
|
+
*
|
|
26
|
+
* // Wrap a section of your dashboard
|
|
27
|
+
* <CategoryProvider categories={categories} categoryLabel="Squads">
|
|
28
|
+
* <Timeline events={events} />
|
|
29
|
+
* <GroundTrackMap pins={pins} />
|
|
30
|
+
* </CategoryProvider>
|
|
31
|
+
*
|
|
32
|
+
* // Inside any component
|
|
33
|
+
* function MyWidget() {
|
|
34
|
+
* const ctx = useCategoryPalette();
|
|
35
|
+
* if (!ctx) return null; // graceful when no provider
|
|
36
|
+
* const color = ctx.palette.getColor('alpha');
|
|
37
|
+
* const label = ctx.categoryLabel; // "Squads"
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
var CategoryContext = createContext(null);
|
|
5
42
|
CategoryContext.displayName = "CategoryContext";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Provides a shared `CategoryPalette` to descendant components.
|
|
45
|
+
*
|
|
46
|
+
* Wrap a dashboard section (not the entire app) so sibling components
|
|
47
|
+
* like Timeline + Map + Charts resolve the same colors for the same ids.
|
|
48
|
+
*/
|
|
49
|
+
function CategoryProvider({ categories, categoryLabel = "Categories", fallbackPalette, children }) {
|
|
50
|
+
const value = useMemo(() => ({
|
|
51
|
+
palette: new CategoryPalette(categories, fallbackPalette),
|
|
52
|
+
categories,
|
|
53
|
+
categoryLabel
|
|
54
|
+
}), [
|
|
55
|
+
categories,
|
|
56
|
+
categoryLabel,
|
|
57
|
+
fallbackPalette
|
|
58
|
+
]);
|
|
59
|
+
return /* @__PURE__ */ jsx(CategoryContext.Provider, {
|
|
60
|
+
value,
|
|
61
|
+
children
|
|
62
|
+
});
|
|
18
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Access the nearest `CategoryProvider`'s palette and label.
|
|
66
|
+
*
|
|
67
|
+
* Returns `null` when no provider is present — components should treat
|
|
68
|
+
* this as "standalone mode" and fall back to explicit props / defaults.
|
|
69
|
+
*/
|
|
19
70
|
function useCategoryPalette() {
|
|
20
|
-
|
|
71
|
+
return useContext(CategoryContext);
|
|
21
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Like `useCategoryPalette()` but throws if no provider is found.
|
|
75
|
+
* Use only when you know a provider is always present.
|
|
76
|
+
*/
|
|
22
77
|
function useCategoryPaletteRequired() {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"useCategoryPaletteRequired() was called outside of a <CategoryProvider>. Wrap a parent component with <CategoryProvider categories={[...]}> or use useCategoryPalette() for graceful null handling."
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
return ctx;
|
|
78
|
+
const ctx = useContext(CategoryContext);
|
|
79
|
+
if (!ctx) throw new Error("useCategoryPaletteRequired() was called outside of a <CategoryProvider>. Wrap a parent component with <CategoryProvider categories={[...]}> or use useCategoryPalette() for graceful null handling.");
|
|
80
|
+
return ctx;
|
|
30
81
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
};
|
|
36
|
-
//# sourceMappingURL=CategoryContext.js.map
|
|
82
|
+
//#endregion
|
|
83
|
+
export { CategoryProvider, useCategoryPalette, useCategoryPaletteRequired };
|
|
84
|
+
|
|
85
|
+
//# sourceMappingURL=CategoryContext.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CategoryContext.js","sources":["../../../src/react/context/CategoryContext.tsx"],"sourcesContent":["/**\
|
|
1
|
+
{"version":3,"file":"CategoryContext.js","names":[],"sources":["../../../src/react/context/CategoryContext.tsx"],"sourcesContent":["/**\n * @zendir/ui — CategoryProvider\n *\n * Optional React context for sharing a `CategoryPalette` and display label\n * across sibling components in a dashboard layout. Components that are\n * \"category-aware\" (Timeline, GroundTrackMap, AstroChart, DataTable) can\n * read from this context to resolve colors/labels without each needing\n * explicit palette props.\n *\n * **This context is fully opt-in.** Components continue to work standalone\n * — explicit `color` / `team` props always take precedence over context.\n *\n * @example\n * ```tsx\n * import { CategoryProvider, useCategoryPalette } from '@zendir/ui';\n *\n * const categories = [\n * { id: 'alpha', label: 'Team Alpha', color: '#2dccff' },\n * { id: 'bravo', label: 'Team Bravo', color: '#fce83a' },\n * ];\n *\n * // Wrap a section of your dashboard\n * <CategoryProvider categories={categories} categoryLabel=\"Squads\">\n * <Timeline events={events} />\n * <GroundTrackMap pins={pins} />\n * </CategoryProvider>\n *\n * // Inside any component\n * function MyWidget() {\n * const ctx = useCategoryPalette();\n * if (!ctx) return null; // graceful when no provider\n * const color = ctx.palette.getColor('alpha');\n * const label = ctx.categoryLabel; // \"Squads\"\n * }\n * ```\n */\n\nimport React, {\n createContext,\n useContext,\n useMemo,\n type ReactNode,\n} from \"react\";\nimport { CategoryPalette } from \"../utils/categoryPalette\";\nimport type { CategoryDef } from \"../types\";\n\n// =============================================================================\n// Context value\n// =============================================================================\n\nexport interface CategoryContextValue {\n /** Palette instance built from the provided categories. */\n palette: CategoryPalette;\n /** All registered category definitions. */\n categories: CategoryDef[];\n /**\n * Human-readable label for the grouping dimension.\n * Defaults to `\"Categories\"`. Components that support a label override\n * (e.g. Timeline's `teamLabel`) should fall back to this when no\n * explicit prop is provided.\n */\n categoryLabel: string;\n}\n\nconst CategoryContext = createContext<CategoryContextValue | null>(null);\nCategoryContext.displayName = \"CategoryContext\";\n\n// =============================================================================\n// Provider\n// =============================================================================\n\nexport interface CategoryProviderProps {\n /** Category definitions — each must have `id`, `label`, and `color`. */\n categories: CategoryDef[];\n /**\n * Display label for the grouping dimension, e.g. `\"Teams\"`, `\"Squads\"`,\n * `\"Subsystems\"`. Defaults to `\"Categories\"`.\n */\n categoryLabel?: string;\n /**\n * Optional custom fallback palette for auto-assigned unknown ids.\n * Defaults to the Astro data-viz palette built into `CategoryPalette`.\n */\n fallbackPalette?: string[];\n children: ReactNode;\n}\n\n/**\n * Provides a shared `CategoryPalette` to descendant components.\n *\n * Wrap a dashboard section (not the entire app) so sibling components\n * like Timeline + Map + Charts resolve the same colors for the same ids.\n */\nexport function CategoryProvider({\n categories,\n categoryLabel = \"Categories\",\n fallbackPalette,\n children,\n}: CategoryProviderProps): React.ReactElement {\n const value = useMemo<CategoryContextValue>(\n () => ({\n palette: new CategoryPalette(categories, fallbackPalette),\n categories,\n categoryLabel,\n }),\n [categories, categoryLabel, fallbackPalette],\n );\n\n return (\n <CategoryContext.Provider value={value}>\n {children}\n </CategoryContext.Provider>\n );\n}\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\n/**\n * Access the nearest `CategoryProvider`'s palette and label.\n *\n * Returns `null` when no provider is present — components should treat\n * this as \"standalone mode\" and fall back to explicit props / defaults.\n */\nexport function useCategoryPalette(): CategoryContextValue | null {\n return useContext(CategoryContext);\n}\n\n/**\n * Like `useCategoryPalette()` but throws if no provider is found.\n * Use only when you know a provider is always present.\n */\nexport function useCategoryPaletteRequired(): CategoryContextValue {\n const ctx = useContext(CategoryContext);\n if (!ctx) {\n throw new Error(\n \"useCategoryPaletteRequired() was called outside of a <CategoryProvider>. \" +\n \"Wrap a parent component with <CategoryProvider categories={[...]}> or \" +\n \"use useCategoryPalette() for graceful null handling.\",\n );\n }\n return ctx;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgEA,IAAM,kBAAkB,cAA2C,IAAI;AACvE,gBAAgB,cAAc;;;;;;;AA4B9B,SAAgB,iBAAiB,EAC/B,YACA,gBAAgB,cAChB,iBACA,YAC4C;CAC5C,MAAM,QAAQ,eACL;EACL,SAAS,IAAI,gBAAgB,YAAY,eAAe;EACxD;EACA;CACF,IACA;EAAC;EAAY;EAAe;CAAe,CAC7C;CAEA,OACE,oBAAC,gBAAgB,UAAjB;EAAiC;EAC9B;CACuB,CAAA;AAE9B;;;;;;;AAYA,SAAgB,qBAAkD;CAChE,OAAO,WAAW,eAAe;AACnC;;;;;AAMA,SAAgB,6BAAmD;CACjE,MAAM,MAAM,WAAW,eAAe;CACtC,IAAI,CAAC,KACH,MAAM,IAAI,MACR,qMAGF;CAEF,OAAO;AACT"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { default as React, ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
export type ColorTarget = 'both' | 'accent' | 'glass';
|
|
2
|
+
export type ColorTarget = "both" | "accent" | "glass";
|
|
4
3
|
export interface DisplaySettings {
|
|
5
4
|
/** Global compact mode - affects all cards */
|
|
6
5
|
compactMode: boolean;
|