@zendir/ui 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (391) hide show
  1. package/CHANGELOG.md +419 -386
  2. package/README.md +640 -631
  3. package/dist/_virtual/_rolldown/runtime.js +13 -0
  4. package/dist/index.js +17 -221
  5. package/dist/react/3d/CesiumCaptureSource.d.ts +0 -1
  6. package/dist/react/3d/CesiumCaptureSource.js +364 -283
  7. package/dist/react/3d/CesiumCaptureSource.js.map +1 -1
  8. package/dist/react/3d/ZenSpace3D.d.ts +2 -3
  9. package/dist/react/3d/ZenSpace3D.js +1681 -1237
  10. package/dist/react/3d/ZenSpace3D.js.map +1 -1
  11. package/dist/react/3d/ZenSpace3DCesium.d.ts +0 -1
  12. package/dist/react/3d/ZenSpace3DCesium.js +513 -560
  13. package/dist/react/3d/ZenSpace3DCesium.js.map +1 -1
  14. package/dist/react/3d/ZenSpace3DShaders.js +61 -66
  15. package/dist/react/3d/ZenSpace3DShaders.js.map +1 -1
  16. package/dist/react/3d/ZenSpace3DTypes.d.ts +19 -20
  17. package/dist/react/3d/ZenSpace3DUtils.d.ts +0 -1
  18. package/dist/react/3d/ZenSpace3DUtils.js +37 -24
  19. package/dist/react/3d/ZenSpace3DUtils.js.map +1 -1
  20. package/dist/react/3d/capturePngAnalysis.js +42 -36
  21. package/dist/react/3d/capturePngAnalysis.js.map +1 -1
  22. package/dist/react/3d/index.d.ts +3 -3
  23. package/dist/react/3d/index.js +5 -53
  24. package/dist/react/3d/threeLoader.d.ts +1 -1
  25. package/dist/react/3d/threeLoader.js +23 -18
  26. package/dist/react/3d/threeLoader.js.map +1 -1
  27. package/dist/react/astro/ClassificationBanner.d.ts +2 -3
  28. package/dist/react/astro/ClassificationBanner.js +95 -79
  29. package/dist/react/astro/ClassificationBanner.js.map +1 -1
  30. package/dist/react/astro/GlobalStatusBar.d.ts +0 -1
  31. package/dist/react/astro/GlobalStatusBar.js +157 -163
  32. package/dist/react/astro/GlobalStatusBar.js.map +1 -1
  33. package/dist/react/astro/MissionClock.d.ts +7 -8
  34. package/dist/react/astro/MissionClock.js +377 -400
  35. package/dist/react/astro/MissionClock.js.map +1 -1
  36. package/dist/react/astro/MonitoringIcon.d.ts +1 -2
  37. package/dist/react/astro/MonitoringIcon.js +422 -358
  38. package/dist/react/astro/MonitoringIcon.js.map +1 -1
  39. package/dist/react/astro/Notification.d.ts +1 -2
  40. package/dist/react/astro/Notification.js +229 -126
  41. package/dist/react/astro/Notification.js.map +1 -1
  42. package/dist/react/astro/Progress.d.ts +0 -1
  43. package/dist/react/astro/Progress.js +199 -141
  44. package/dist/react/astro/Progress.js.map +1 -1
  45. package/dist/react/astro/SimulationControls.d.ts +3 -4
  46. package/dist/react/astro/SimulationControls.js +596 -650
  47. package/dist/react/astro/SimulationControls.js.map +1 -1
  48. package/dist/react/astro/StatusIndicator.d.ts +0 -1
  49. package/dist/react/astro/StatusIndicator.js +236 -170
  50. package/dist/react/astro/StatusIndicator.js.map +1 -1
  51. package/dist/react/astro/UnifiedTimeline.d.ts +9 -10
  52. package/dist/react/astro/UnifiedTimeline.js +2345 -2392
  53. package/dist/react/astro/UnifiedTimeline.js.map +1 -1
  54. package/dist/react/astro/index.d.ts +5 -5
  55. package/dist/react/astro/index.js +1 -25
  56. package/dist/react/cards/AccessCard.d.ts +0 -1
  57. package/dist/react/cards/AccessCard.js +471 -405
  58. package/dist/react/cards/AccessCard.js.map +1 -1
  59. package/dist/react/cards/OrbitCard.d.ts +0 -1
  60. package/dist/react/cards/OrbitCard.js +487 -364
  61. package/dist/react/cards/OrbitCard.js.map +1 -1
  62. package/dist/react/cards/SpacecraftCard.d.ts +0 -1
  63. package/dist/react/cards/SpacecraftCard.js +813 -925
  64. package/dist/react/cards/SpacecraftCard.js.map +1 -1
  65. package/dist/react/cards/TelemetryCard.d.ts +0 -1
  66. package/dist/react/cards/TelemetryCard.js +1055 -732
  67. package/dist/react/cards/TelemetryCard.js.map +1 -1
  68. package/dist/react/cards/TelemetryStreamCard.d.ts +0 -1
  69. package/dist/react/cards/TelemetryStreamCard.js +323 -297
  70. package/dist/react/cards/TelemetryStreamCard.js.map +1 -1
  71. package/dist/react/cards/index.d.ts +1 -1
  72. package/dist/react/cards/index.js +1 -8
  73. package/dist/react/charts/GroundTrackMap.d.ts +6 -7
  74. package/dist/react/charts/GroundTrackMap.js +1377 -1256
  75. package/dist/react/charts/GroundTrackMap.js.map +1 -1
  76. package/dist/react/charts/GroundTrackMapLeaflet.d.ts +1 -2
  77. package/dist/react/charts/GroundTrackMapLeaflet.js +1065 -987
  78. package/dist/react/charts/GroundTrackMapLeaflet.js.map +1 -1
  79. package/dist/react/charts/groundTrackMapLeafletTiles.js +34 -25
  80. package/dist/react/charts/groundTrackMapLeafletTiles.js.map +1 -1
  81. package/dist/react/charts/groundTrackMapLeafletUtils.js +70 -61
  82. package/dist/react/charts/groundTrackMapLeafletUtils.js.map +1 -1
  83. package/dist/react/charts/index.d.ts +1 -1
  84. package/dist/react/charts/index.js +7 -100
  85. package/dist/react/charts/unified/AstroChart.d.ts +1 -2
  86. package/dist/react/charts/unified/AstroChart.js +1331 -1411
  87. package/dist/react/charts/unified/AstroChart.js.map +1 -1
  88. package/dist/react/charts/unified/PowerOverviewChart.d.ts +3 -3
  89. package/dist/react/charts/unified/PowerOverviewChart.js +495 -478
  90. package/dist/react/charts/unified/PowerOverviewChart.js.map +1 -1
  91. package/dist/react/charts/unified/domain.d.ts +12 -13
  92. package/dist/react/charts/unified/domain.js +3999 -3145
  93. package/dist/react/charts/unified/domain.js.map +1 -1
  94. package/dist/react/charts/unified/generators.d.ts +3 -4
  95. package/dist/react/charts/unified/generators.js +561 -498
  96. package/dist/react/charts/unified/generators.js.map +1 -1
  97. package/dist/react/charts/unified/index.d.ts +1 -1
  98. package/dist/react/charts/unified/presets.d.ts +14 -15
  99. package/dist/react/charts/unified/presets.js +857 -994
  100. package/dist/react/charts/unified/presets.js.map +1 -1
  101. package/dist/react/charts/unified/sync.d.ts +2 -3
  102. package/dist/react/charts/unified/sync.js +229 -195
  103. package/dist/react/charts/unified/sync.js.map +1 -1
  104. package/dist/react/charts/unified/theme.d.ts +11 -12
  105. package/dist/react/charts/unified/theme.js +606 -642
  106. package/dist/react/charts/unified/theme.js.map +1 -1
  107. package/dist/react/charts/unified/types.d.ts +32 -33
  108. package/dist/react/charts/unified/useChartStream.d.ts +1 -2
  109. package/dist/react/charts/unified/useChartStream.js +203 -216
  110. package/dist/react/charts/unified/useChartStream.js.map +1 -1
  111. package/dist/react/chatgpt/AppCard.d.ts +1 -2
  112. package/dist/react/chatgpt/index.d.ts +7 -7
  113. package/dist/react/chatgpt/index.js +160 -139
  114. package/dist/react/chatgpt/index.js.map +1 -1
  115. package/dist/react/context/CategoryContext.d.ts +0 -1
  116. package/dist/react/context/CategoryContext.js +78 -29
  117. package/dist/react/context/CategoryContext.js.map +1 -1
  118. package/dist/react/context/DisplaySettingsContext.d.ts +1 -2
  119. package/dist/react/context/DisplaySettingsContext.js +205 -156
  120. package/dist/react/context/DisplaySettingsContext.js.map +1 -1
  121. package/dist/react/context/SpatialSelectionContext.d.ts +0 -1
  122. package/dist/react/context/SpatialSelectionContext.js +36 -7
  123. package/dist/react/context/SpatialSelectionContext.js.map +1 -1
  124. package/dist/react/core/data/DataTable.d.ts +3 -4
  125. package/dist/react/core/data/DataTable.js +473 -440
  126. package/dist/react/core/data/DataTable.js.map +1 -1
  127. package/dist/react/core/data/DataValue.d.ts +4 -5
  128. package/dist/react/core/data/DataValue.js +605 -571
  129. package/dist/react/core/data/DataValue.js.map +1 -1
  130. package/dist/react/core/data/propertyConfig.d.ts +1 -2
  131. package/dist/react/core/data/propertyConfig.js +446 -382
  132. package/dist/react/core/data/propertyConfig.js.map +1 -1
  133. package/dist/react/core/display/AstroIcon.d.ts +4 -5
  134. package/dist/react/core/display/AstroIcon.js +339 -429
  135. package/dist/react/core/display/AstroIcon.js.map +1 -1
  136. package/dist/react/core/display/Badge.d.ts +2 -3
  137. package/dist/react/core/display/Badge.js +131 -131
  138. package/dist/react/core/display/Badge.js.map +1 -1
  139. package/dist/react/core/display/CardHeader.d.ts +0 -1
  140. package/dist/react/core/display/CardHeader.js +398 -311
  141. package/dist/react/core/display/CardHeader.js.map +1 -1
  142. package/dist/react/core/display/Container.d.ts +2 -3
  143. package/dist/react/core/display/Container.js +640 -668
  144. package/dist/react/core/display/Container.js.map +1 -1
  145. package/dist/react/core/display/CopyButton.d.ts +1 -2
  146. package/dist/react/core/display/CopyButton.js +158 -101
  147. package/dist/react/core/display/CopyButton.js.map +1 -1
  148. package/dist/react/core/display/GlassCard.d.ts +3 -4
  149. package/dist/react/core/display/GlassCard.js +416 -369
  150. package/dist/react/core/display/GlassCard.js.map +1 -1
  151. package/dist/react/core/display/HeaderIconWithStatus.d.ts +0 -1
  152. package/dist/react/core/display/HeaderIconWithStatus.js +152 -152
  153. package/dist/react/core/display/HeaderIconWithStatus.js.map +1 -1
  154. package/dist/react/core/display/Icon.d.ts +2 -3
  155. package/dist/react/core/display/Icon.js +172 -143
  156. package/dist/react/core/display/Icon.js.map +1 -1
  157. package/dist/react/core/display/Typography.d.ts +24 -25
  158. package/dist/react/core/display/Typography.js +360 -178
  159. package/dist/react/core/display/Typography.js.map +1 -1
  160. package/dist/react/core/feedback/ConfirmDialog.d.ts +1 -2
  161. package/dist/react/core/feedback/ConfirmDialog.js +343 -304
  162. package/dist/react/core/feedback/ConfirmDialog.js.map +1 -1
  163. package/dist/react/core/feedback/Dialog.d.ts +2 -3
  164. package/dist/react/core/feedback/Dialog.js +189 -197
  165. package/dist/react/core/feedback/Dialog.js.map +1 -1
  166. package/dist/react/core/feedback/Toast.d.ts +2 -3
  167. package/dist/react/core/feedback/Toast.js +346 -207
  168. package/dist/react/core/feedback/Toast.js.map +1 -1
  169. package/dist/react/core/index.d.ts +26 -26
  170. package/dist/react/core/index.js +7 -119
  171. package/dist/react/core/inputs/Button.d.ts +2 -3
  172. package/dist/react/core/inputs/Button.js +281 -304
  173. package/dist/react/core/inputs/Button.js.map +1 -1
  174. package/dist/react/core/inputs/Checkbox.d.ts +2 -3
  175. package/dist/react/core/inputs/Checkbox.js +139 -127
  176. package/dist/react/core/inputs/Checkbox.js.map +1 -1
  177. package/dist/react/core/inputs/Input.d.ts +3 -4
  178. package/dist/react/core/inputs/Input.js +277 -285
  179. package/dist/react/core/inputs/Input.js.map +1 -1
  180. package/dist/react/core/inputs/LimitsBar.d.ts +1 -2
  181. package/dist/react/core/inputs/LimitsBar.js +271 -196
  182. package/dist/react/core/inputs/LimitsBar.js.map +1 -1
  183. package/dist/react/core/inputs/NumberInput.d.ts +2 -3
  184. package/dist/react/core/inputs/NumberInput.js +531 -503
  185. package/dist/react/core/inputs/NumberInput.js.map +1 -1
  186. package/dist/react/core/inputs/PinInput.d.ts +2 -3
  187. package/dist/react/core/inputs/PinInput.js +224 -207
  188. package/dist/react/core/inputs/PinInput.js.map +1 -1
  189. package/dist/react/core/inputs/Select.d.ts +1 -2
  190. package/dist/react/core/inputs/Select.js +298 -299
  191. package/dist/react/core/inputs/Select.js.map +1 -1
  192. package/dist/react/core/inputs/Toggle.d.ts +2 -3
  193. package/dist/react/core/inputs/Toggle.js +142 -148
  194. package/dist/react/core/inputs/Toggle.js.map +1 -1
  195. package/dist/react/core/layout/Box.d.ts +3 -4
  196. package/dist/react/core/layout/Box.js +118 -122
  197. package/dist/react/core/layout/Box.js.map +1 -1
  198. package/dist/react/core/layout/Center.d.ts +0 -1
  199. package/dist/react/core/layout/Center.js +45 -32
  200. package/dist/react/core/layout/Center.js.map +1 -1
  201. package/dist/react/core/layout/Divider.d.ts +1 -2
  202. package/dist/react/core/layout/Divider.js +112 -106
  203. package/dist/react/core/layout/Divider.js.map +1 -1
  204. package/dist/react/core/layout/Flex.d.ts +4 -5
  205. package/dist/react/core/layout/Flex.js +120 -124
  206. package/dist/react/core/layout/Flex.js.map +1 -1
  207. package/dist/react/core/layout/Grid.d.ts +5 -6
  208. package/dist/react/core/layout/Grid.js +131 -138
  209. package/dist/react/core/layout/Grid.js.map +1 -1
  210. package/dist/react/core/layout/Spacer.d.ts +0 -1
  211. package/dist/react/core/layout/Spacer.js +36 -29
  212. package/dist/react/core/layout/Spacer.js.map +1 -1
  213. package/dist/react/core/layout/Stack.d.ts +4 -5
  214. package/dist/react/core/layout/Stack.js +127 -70
  215. package/dist/react/core/layout/Stack.js.map +1 -1
  216. package/dist/react/core/layout/responsive.d.ts +1 -2
  217. package/dist/react/core/layout/responsive.js +25 -19
  218. package/dist/react/core/layout/responsive.js.map +1 -1
  219. package/dist/react/core/layout/useBreakpoint.d.ts +1 -1
  220. package/dist/react/core/layout/useBreakpoint.js +119 -66
  221. package/dist/react/core/layout/useBreakpoint.js.map +1 -1
  222. package/dist/react/core/navigation/AppBar.d.ts +1 -2
  223. package/dist/react/core/navigation/AppBar.js +827 -805
  224. package/dist/react/core/navigation/AppBar.js.map +1 -1
  225. package/dist/react/core/navigation/Pagination.d.ts +2 -3
  226. package/dist/react/core/navigation/Pagination.js +207 -187
  227. package/dist/react/core/navigation/Pagination.js.map +1 -1
  228. package/dist/react/core/navigation/SideNav.d.ts +5 -6
  229. package/dist/react/core/navigation/SideNav.js +855 -629
  230. package/dist/react/core/navigation/SideNav.js.map +1 -1
  231. package/dist/react/core/navigation/Tabs.d.ts +0 -1
  232. package/dist/react/core/navigation/Tabs.js +113 -119
  233. package/dist/react/core/navigation/Tabs.js.map +1 -1
  234. package/dist/react/core/overlays/Popover.d.ts +2 -3
  235. package/dist/react/core/overlays/Popover.js +303 -282
  236. package/dist/react/core/overlays/Popover.js.map +1 -1
  237. package/dist/react/core/overlays/SidePanel.d.ts +1 -2
  238. package/dist/react/core/overlays/SidePanel.js +217 -212
  239. package/dist/react/core/overlays/SidePanel.js.map +1 -1
  240. package/dist/react/core/overlays/Tooltip.d.ts +1 -2
  241. package/dist/react/core/overlays/Tooltip.js +170 -176
  242. package/dist/react/core/overlays/Tooltip.js.map +1 -1
  243. package/dist/react/core/widgets/ActivityPlanner.d.ts +0 -1
  244. package/dist/react/core/widgets/ActivityPlanner.js +855 -517
  245. package/dist/react/core/widgets/ActivityPlanner.js.map +1 -1
  246. package/dist/react/core/widgets/Capture.d.ts +2 -3
  247. package/dist/react/core/widgets/Capture.js +965 -779
  248. package/dist/react/core/widgets/Capture.js.map +1 -1
  249. package/dist/react/core/widgets/ChatPanel.d.ts +16 -17
  250. package/dist/react/core/widgets/ChatPanel.js +1734 -1034
  251. package/dist/react/core/widgets/ChatPanel.js.map +1 -1
  252. package/dist/react/core/widgets/ColorPickerPanel.d.ts +0 -1
  253. package/dist/react/core/widgets/ColorPickerPanel.js +298 -287
  254. package/dist/react/core/widgets/ColorPickerPanel.js.map +1 -1
  255. package/dist/react/core/widgets/CommandBuilder.d.ts +2 -3
  256. package/dist/react/core/widgets/CommandBuilder.js +624 -516
  257. package/dist/react/core/widgets/CommandBuilder.js.map +1 -1
  258. package/dist/react/core/widgets/ConnectionForm.d.ts +2 -3
  259. package/dist/react/core/widgets/ConnectionForm.js +528 -492
  260. package/dist/react/core/widgets/ConnectionForm.js.map +1 -1
  261. package/dist/react/core/widgets/FileExplorer.d.ts +3 -4
  262. package/dist/react/core/widgets/FileExplorer.js +617 -505
  263. package/dist/react/core/widgets/FileExplorer.js.map +1 -1
  264. package/dist/react/core/widgets/HexViewer.d.ts +2 -3
  265. package/dist/react/core/widgets/HexViewer.js +1353 -1091
  266. package/dist/react/core/widgets/HexViewer.js.map +1 -1
  267. package/dist/react/core/widgets/ImageFrame.d.ts +1 -2
  268. package/dist/react/core/widgets/ImageFrame.js +230 -193
  269. package/dist/react/core/widgets/ImageFrame.js.map +1 -1
  270. package/dist/react/core/widgets/ImageGallery.d.ts +2 -1
  271. package/dist/react/core/widgets/ImageGallery.js +380 -314
  272. package/dist/react/core/widgets/ImageGallery.js.map +1 -1
  273. package/dist/react/core/widgets/ImagePanel.d.ts +0 -1
  274. package/dist/react/core/widgets/ImagePanel.js +110 -101
  275. package/dist/react/core/widgets/ImagePanel.js.map +1 -1
  276. package/dist/react/core/widgets/LogViewer.d.ts +2 -3
  277. package/dist/react/core/widgets/LogViewer.js +711 -607
  278. package/dist/react/core/widgets/LogViewer.js.map +1 -1
  279. package/dist/react/core/widgets/MessageStream.d.ts +3 -4
  280. package/dist/react/core/widgets/MessageStream.js +514 -444
  281. package/dist/react/core/widgets/MessageStream.js.map +1 -1
  282. package/dist/react/core/widgets/MissionCalendar.d.ts +3 -4
  283. package/dist/react/core/widgets/MissionCalendar.js +1488 -1020
  284. package/dist/react/core/widgets/MissionCalendar.js.map +1 -1
  285. package/dist/react/core/widgets/PacketViewer.d.ts +2 -3
  286. package/dist/react/core/widgets/PacketViewer.js +550 -421
  287. package/dist/react/core/widgets/PacketViewer.js.map +1 -1
  288. package/dist/react/core/widgets/capture-placeholder.png.js +6 -5
  289. package/dist/react/core/widgets/capture-placeholder.png.js.map +1 -1
  290. package/dist/react/hooks/index.d.ts +5 -5
  291. package/dist/react/hooks/useAccessWindows.d.ts +0 -1
  292. package/dist/react/hooks/useCompactMode.d.ts +1 -1
  293. package/dist/react/hooks/useCompactMode.js +104 -58
  294. package/dist/react/hooks/useCompactMode.js.map +1 -1
  295. package/dist/react/hooks/useGroundTrackHistory.d.ts +0 -1
  296. package/dist/react/hooks/useSimulationScene.d.ts +1 -2
  297. package/dist/react/hooks/useSimulationScene.js +481 -374
  298. package/dist/react/hooks/useSimulationScene.js.map +1 -1
  299. package/dist/react/index.d.ts +3 -3
  300. package/dist/react/panels/LayerControlPanel.d.ts +1 -2
  301. package/dist/react/panels/LayerControlPanel.js +223 -180
  302. package/dist/react/panels/LayerControlPanel.js.map +1 -1
  303. package/dist/react/panels/ObjectInventoryPanel.d.ts +2 -3
  304. package/dist/react/panels/ObjectInventoryPanel.js +315 -250
  305. package/dist/react/panels/ObjectInventoryPanel.js.map +1 -1
  306. package/dist/react/panels/index.d.ts +1 -1
  307. package/dist/react/panels/index.js +1 -6
  308. package/dist/react/shared/ErrorBoundary.d.ts +1 -2
  309. package/dist/react/shared/ErrorBoundary.js +170 -139
  310. package/dist/react/shared/ErrorBoundary.js.map +1 -1
  311. package/dist/react/shared/Skeleton.d.ts +1 -2
  312. package/dist/react/shared/Skeleton.js +300 -301
  313. package/dist/react/shared/Skeleton.js.map +1 -1
  314. package/dist/react/theme/ThemeProvider.d.ts +2 -321
  315. package/dist/react/theme/ThemeProvider.js +313 -939
  316. package/dist/react/theme/ThemeProvider.js.map +1 -1
  317. package/dist/react/theme/cardAccent.d.ts +1 -2
  318. package/dist/react/theme/cardAccent.js +196 -126
  319. package/dist/react/theme/cardAccent.js.map +1 -1
  320. package/dist/react/theme/config.d.ts +0 -1
  321. package/dist/react/theme/config.js +47 -25
  322. package/dist/react/theme/config.js.map +1 -1
  323. package/dist/react/theme/index.d.ts +2 -2
  324. package/dist/react/theme/index.js +1 -16
  325. package/dist/react/theme/types.d.ts +332 -0
  326. package/dist/react/theme/types.js +39 -0
  327. package/dist/react/theme/types.js.map +1 -0
  328. package/dist/react/types.d.ts +8 -8
  329. package/dist/react/types.js +147 -47
  330. package/dist/react/types.js.map +1 -1
  331. package/dist/react/utils/categoryPalette.d.ts +0 -1
  332. package/dist/react/utils/categoryPalette.js +91 -102
  333. package/dist/react/utils/categoryPalette.js.map +1 -1
  334. package/dist/react/utils/index.d.ts +5 -5
  335. package/dist/react/utils/index.js +457 -371
  336. package/dist/react/utils/index.js.map +1 -1
  337. package/dist/react/visualizations/EclipseTimerCard.d.ts +0 -1
  338. package/dist/react/visualizations/LinkBudgetCard.d.ts +0 -1
  339. package/dist/react/visualizations/NavBallCard.d.ts +0 -1
  340. package/dist/react/visualizations/PropulsionCard.d.ts +1 -2
  341. package/dist/react/visualizations/SensorFootprintCard.d.ts +1 -2
  342. package/dist/react/visualizations/ThermalHeatmapCard.d.ts +0 -1
  343. package/dist/react/visualizations/index.d.ts +3 -3
  344. package/dist/react.d.ts +2 -1
  345. package/dist/react.js +17 -221
  346. package/dist/shaders/atmosphere.frag.js +6 -5
  347. package/dist/shaders/atmosphere.frag.js.map +1 -1
  348. package/dist/shaders/atmosphere.vert.js +6 -5
  349. package/dist/shaders/atmosphere.vert.js.map +1 -1
  350. package/dist/shaders/stars.frag.js +6 -5
  351. package/dist/shaders/stars.frag.js.map +1 -1
  352. package/dist/shaders/stars.vert.js +6 -5
  353. package/dist/shaders/stars.vert.js.map +1 -1
  354. package/dist/style.css +26 -3
  355. package/dist/tokens/core.d.ts +159 -0
  356. package/dist/tokens/core.js +144 -0
  357. package/dist/tokens/core.js.map +1 -0
  358. package/dist/tokens/css-vars.d.ts +213 -2
  359. package/dist/tokens/css-vars.js +590 -227
  360. package/dist/tokens/css-vars.js.map +1 -1
  361. package/dist/tokens/index.d.ts +31 -228
  362. package/dist/tokens/index.js +281 -366
  363. package/dist/tokens/index.js.map +1 -1
  364. package/dist/tokens/palettes/astro.d.ts +129 -0
  365. package/dist/tokens/palettes/astro.js +112 -0
  366. package/dist/tokens/palettes/astro.js.map +1 -0
  367. package/dist/tokens/palettes/index.d.ts +288 -0
  368. package/dist/tokens/palettes/index.js +35 -0
  369. package/dist/tokens/palettes/index.js.map +1 -0
  370. package/dist/tokens/palettes/tailwind.d.ts +324 -0
  371. package/dist/tokens/palettes/tailwind.js +201 -0
  372. package/dist/tokens/palettes/tailwind.js.map +1 -0
  373. package/dist/tokens/palettes/zendir.d.ts +126 -0
  374. package/dist/tokens/palettes/zendir.js +92 -0
  375. package/dist/tokens/palettes/zendir.js.map +1 -0
  376. package/dist/tokens/themes.d.ts +30 -0
  377. package/dist/tokens/themes.js +704 -0
  378. package/dist/tokens/themes.js.map +1 -0
  379. package/dist/tokens/tokens.css +533 -155
  380. package/dist/types/index.d.ts +2 -2
  381. package/package.json +310 -313
  382. package/dist/index.js.map +0 -1
  383. package/dist/react/3d/index.js.map +0 -1
  384. package/dist/react/astro/index.js.map +0 -1
  385. package/dist/react/cards/index.js.map +0 -1
  386. package/dist/react/charts/index.js.map +0 -1
  387. package/dist/react/core/index.js.map +0 -1
  388. package/dist/react/panels/index.js.map +0 -1
  389. package/dist/react/theme/astro-tokens.d.ts +0 -153
  390. package/dist/react/theme/index.js.map +0 -1
  391. package/dist/react.js.map +0 -1
@@ -1,163 +1,184 @@
1
- import { useState, useCallback, useEffect, useSyncExternalStore } from "react";
2
- const SET_GLOBALS_EVENT_TYPE = "openai:set_globals";
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
- const getSnapshot = useCallback(() => {
5
- var _a;
6
- return (_a = window.openai) == null ? void 0 : _a[key];
7
- }, [key]);
8
- const subscribe = useCallback((onChange) => {
9
- const handleSetGlobal = (event) => {
10
- var _a, _b;
11
- const customEvent = event;
12
- if (((_b = (_a = customEvent.detail) == null ? void 0 : _a.globals) == null ? void 0 : _b[key]) !== void 0) {
13
- onChange();
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
- const widgetStateFromWindow = useOpenAiGlobal("widgetState");
23
- const [widgetState, _setWidgetState] = useState(() => {
24
- if (widgetStateFromWindow != null) {
25
- return widgetStateFromWindow;
26
- }
27
- return typeof defaultState === "function" ? defaultState() : defaultState;
28
- });
29
- useEffect(() => {
30
- if (widgetStateFromWindow != null) {
31
- _setWidgetState(widgetStateFromWindow);
32
- }
33
- }, [widgetStateFromWindow]);
34
- const setWidgetState = useCallback((state) => {
35
- _setWidgetState((prevState) => {
36
- var _a, _b;
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
- return useOpenAiGlobal("toolOutput");
59
+ return useOpenAiGlobal("toolOutput");
46
60
  }
61
+ /**
62
+ * Read the tool input (arguments) from the tool invocation
63
+ */
47
64
  function useToolInput() {
48
- return useOpenAiGlobal("toolInput");
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
- const theme = useOpenAiGlobal("theme") ?? "dark";
52
- const isDark = theme === "dark";
53
- return {
54
- theme,
55
- isDark,
56
- colors: isDark ? {
57
- background: "#09090b",
58
- surface: "#18181b",
59
- surfaceHover: "#27272a",
60
- border: "#3f3f46",
61
- text: "#fafafa",
62
- textMuted: "#a1a1aa",
63
- accent: "#22d3ee"
64
- } : {
65
- background: "#ffffff",
66
- surface: "#f4f4f5",
67
- surfaceHover: "#e4e4e7",
68
- border: "#d4d4d8",
69
- text: "#18181b",
70
- textMuted: "#636370",
71
- // 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)
72
- accent: "#0ea5e9"
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
- return useOpenAiGlobal("locale") ?? "en-US";
100
+ return useOpenAiGlobal("locale") ?? "en-US";
78
101
  }
102
+ /**
103
+ * Manage widget display mode (inline, PiP, fullscreen)
104
+ */
79
105
  function useDisplayMode() {
80
- const mode = useOpenAiGlobal("displayMode") ?? "inline";
81
- const maxHeight = useOpenAiGlobal("maxHeight");
82
- const requestMode = useCallback(async (newMode) => {
83
- var _a, _b;
84
- await ((_b = (_a = window.openai) == null ? void 0 : _a.requestDisplayMode) == null ? void 0 : _b.call(_a, { mode: newMode }));
85
- }, []);
86
- const close = useCallback(() => {
87
- var _a, _b;
88
- (_b = (_a = window.openai) == null ? void 0 : _a.requestClose) == null ? void 0 : _b.call(_a);
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
- const [isLoading, setIsLoading] = useState(false);
94
- const [error, setError] = useState(null);
95
- const callTool = useCallback(async (name, args) => {
96
- var _a;
97
- if (!((_a = window.openai) == null ? void 0 : _a.callTool)) {
98
- throw new Error("window.openai.callTool not available");
99
- }
100
- setIsLoading(true);
101
- setError(null);
102
- try {
103
- const result = await window.openai.callTool(name, args);
104
- return result;
105
- } catch (err) {
106
- const error2 = err instanceof Error ? err : new Error(String(err));
107
- setError(error2);
108
- throw error2;
109
- } finally {
110
- setIsLoading(false);
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
- return useCallback(async (prompt) => {
117
- var _a, _b;
118
- await ((_b = (_a = window.openai) == null ? void 0 : _a.sendFollowUpMessage) == null ? void 0 : _b.call(_a, { prompt }));
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
- const [maxHeight, setMaxHeight] = useState(
123
- () => {
124
- var _a;
125
- return (_a = window.openai) == null ? void 0 : _a.maxHeight;
126
- }
127
- );
128
- useEffect(() => {
129
- const handler = (event) => {
130
- var _a;
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
- return useCallback((href) => {
142
- var _a, _b;
143
- (_b = (_a = window.openai) == null ? void 0 : _a.openExternal) == null ? void 0 : _b.call(_a, { href });
144
- }, []);
174
+ return useCallback((href) => {
175
+ window.openai?.openExternal?.({ href });
176
+ }, []);
145
177
  }
146
178
  function isInChatGPT() {
147
- return typeof window !== "undefined" && window.openai !== void 0;
179
+ return typeof window !== "undefined" && window.openai !== void 0;
148
180
  }
149
- export {
150
- isInChatGPT,
151
- useCallTool,
152
- useChatGPTTheme,
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":";AAsEA,MAAM,yBAAyB;AASxB,SAAS,gBAA+C,KAA0B;AACvF,QAAM,cAAc,YAAY,MAAM;;AACpC,YAAO,YAAO,WAAP,mBAAgB;AAAA,EACzB,GAAG,CAAC,GAAG,CAAC;AAER,QAAM,YAAY,YAAY,CAAC,aAAyB;AACtD,UAAM,kBAAkB,CAAC,UAAiB;;AACxC,YAAM,cAAc;AACpB,YAAI,uBAAY,WAAZ,mBAAoB,YAApB,mBAA8B,UAAS,QAAW;AACpD,iBAAA;AAAA,MACF;AAAA,IACF;AAEA,WAAO,iBAAiB,wBAAwB,iBAAiB,EAAE,SAAS,MAAM;AAClF,WAAO,MAAM,OAAO,oBAAoB,wBAAwB,eAAe;AAAA,EACjF,GAAG,CAAC,GAAG,CAAC;AAER,SAAO,qBAAqB,WAAW,aAAa,WAAW;AACjE;AAWO,SAAS,eACd,cACkD;AAClD,QAAM,wBAAwB,gBAAgB,aAAa;AAE3D,QAAM,CAAC,aAAa,eAAe,IAAI,SAAY,MAAM;AACvD,QAAI,yBAAyB,MAAM;AACjC,aAAO;AAAA,IACT;AACA,WAAO,OAAO,iBAAiB,aAAc,aAAA,IAA6B;AAAA,EAC5E,CAAC;AAED,YAAU,MAAM;AACd,QAAI,yBAAyB,MAAM;AACjC,sBAAgB,qBAAqB;AAAA,IACvC;AAAA,EACF,GAAG,CAAC,qBAAqB,CAAC;AAE1B,QAAM,iBAAiB,YAAY,CAAC,UAA6B;AAC/D,oBAAgB,CAAC,cAAiB;;AAChC,YAAM,WAAW,OAAO,UAAU,aAAc,MAAsB,SAAS,IAAI;AACnF,yBAAO,WAAP,mBAAe,mBAAf,4BAAgC;AAChC,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAA,CAAE;AAEL,SAAO,CAAC,aAAa,cAAc;AACrC;AASO,SAAS,gBAA4D;AAC1E,SAAO,gBAAgB,YAAY;AACrC;AAKO,SAAS,eAA2D;AACzE,SAAO,gBAAgB,WAAW;AACpC;AAYO,SAAS,kBAYd;AACA,QAAM,QAAQ,gBAAgB,OAAO,KAAK;AAC1C,QAAM,SAAS,UAAU;AAEzB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,QAAQ,SAAS;AAAA,MACf,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,cAAc;AAAA,MACd,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,IAAA,IACN;AAAA,MACF,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,cAAc;AAAA,MACd,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,WAAW;AAAA;AAAA,MACX,QAAQ;AAAA,IAAA;AAAA,EACV;AAEJ;AASO,SAAS,YAAoB;AAClC,SAAO,gBAAgB,QAAQ,KAAK;AACtC;AASO,SAAS,iBAKd;AACA,QAAM,OAAO,gBAAgB,aAAa,KAAK;AAC/C,QAAM,YAAY,gBAAgB,WAAW;AAE7C,QAAM,cAAc,YAAY,OAAO,YAA6C;;AAClF,YAAM,kBAAO,WAAP,mBAAe,uBAAf,4BAAoC,EAAE,MAAM;EACpD,GAAG,CAAA,CAAE;AAEL,QAAM,QAAQ,YAAY,MAAM;;AAC9B,uBAAO,WAAP,mBAAe,iBAAf;AAAA,EACF,GAAG,CAAA,CAAE;AAEL,SAAO,EAAE,MAAM,WAAW,aAAa,MAAA;AACzC;AASO,SAAS,cAId;AACA,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAuB,IAAI;AAErD,QAAM,WAAW,YAAY,OAC3B,MACA,SACe;;AACf,QAAI,GAAC,YAAO,WAAP,mBAAe,WAAU;AAC5B,YAAM,IAAI,MAAM,sCAAsC;AAAA,IACxD;AAEA,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,YAAM,SAAS,MAAM,OAAO,OAAO,SAAS,MAAM,IAAI;AACtD,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,YAAMA,SAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,eAASA,MAAK;AACd,YAAMA;AAAAA,IACR,UAAA;AACE,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAA,CAAE;AAEL,SAAO,EAAE,UAAU,WAAW,MAAA;AAChC;AASO,SAAS,iBAAoD;AAClE,SAAO,YAAY,OAAO,WAAmB;;AAC3C,YAAM,kBAAO,WAAP,mBAAe,wBAAf,4BAAqC,EAAE;EAC/C,GAAG,CAAA,CAAE;AACP;AAeO,SAAS,eAAmC;AACjD,QAAM,CAAC,WAAW,YAAY,IAAI;AAAA,IAChC,MAAA;;AAAM,0BAAO,WAAP,mBAAe;AAAA;AAAA,EAAA;AAGvB,YAAU,MAAM;AACd,UAAM,UAAU,CAAC,UAAuB;;AACtC,YAAI,WAAM,WAAN,mBAAc,YAAW,eAAe,MAAM,OAAO,SAAS;AAChE,qBAAa,MAAM,OAAO,QAAQ,SAAS;AAAA,MAC7C;AAAA,IACF;AAEA,WAAO,iBAAiB,sBAAsB,OAAwB;AACtE,WAAO,MAAM,OAAO,oBAAoB,sBAAsB,OAAwB;AAAA,EACxF,GAAG,CAAA,CAAE;AAEL,SAAO;AACT;AASO,SAAS,kBAA0C;AACxD,SAAO,YAAY,CAAC,SAAiB;;AACnC,uBAAO,WAAP,mBAAe,iBAAf,4BAA8B,EAAE,KAAA;AAAA,EAClC,GAAG,CAAA,CAAE;AACP;AAMO,SAAS,cAAuB;AACrC,SAAO,OAAO,WAAW,eAAe,OAAO,WAAW;AAC5D;"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/react/chatgpt/index.ts"],"sourcesContent":["/**\r\n * ChatGPT Apps SDK Integration\r\n *\r\n * Hooks and utilities for integrating Zendir UI components with ChatGPT's\r\n * window.openai API. Based on: https://developers.openai.com/apps-sdk/build/chatgpt-ui/\r\n *\r\n * Key capabilities:\r\n * - window.openai.toolInput / toolOutput - Tool data from MCP server\r\n * - window.openai.widgetState / setWidgetState - Persistent UI state\r\n * - window.openai.callTool - Invoke other MCP tools from widget\r\n * - window.openai.sendFollowUpMessage - Insert user messages\r\n * - window.openai.theme - Light/dark theme detection\r\n * - window.openai.locale - Localization\r\n * - window.openai.requestDisplayMode - Fullscreen/PiP modes\r\n * - window.openai.notifyIntrinsicHeight - Dynamic height reporting\r\n */\r\n\r\nimport { useState, useEffect, useCallback, useSyncExternalStore } from \"react\";\r\n\r\n// ============================================================================\r\n// Type Definitions\r\n// ============================================================================\r\n\r\nexport interface OpenAiGlobals {\r\n /** Arguments supplied when the tool was invoked */\r\n toolInput?: Record<string, unknown>;\r\n /** Your structuredContent - the model reads this */\r\n toolOutput?: Record<string, unknown>;\r\n /** Metadata payload - only widget sees it */\r\n toolResponseMetadata?: Record<string, unknown>;\r\n /** Snapshot of UI state persisted between renders */\r\n widgetState?: Record<string, unknown>;\r\n /** Current theme */\r\n theme?: \"light\" | \"dark\";\r\n /** Current locale (e.g., 'en-US') */\r\n locale?: string;\r\n /** Display mode */\r\n displayMode?: \"inline\" | \"pip\" | \"fullscreen\";\r\n /** Maximum allowed height */\r\n maxHeight?: number;\r\n /** View type */\r\n view?: \"conversation\" | \"modal\";\r\n /** User agent info */\r\n userAgent?: string;\r\n /** Safe area insets */\r\n safeArea?: { top: number; bottom: number; left: number; right: number };\r\n\r\n // API Methods\r\n setWidgetState?: (state: Record<string, unknown>) => void;\r\n callTool?: (name: string, args: Record<string, unknown>) => Promise<unknown>;\r\n sendFollowUpMessage?: (options: { prompt: string }) => Promise<void>;\r\n uploadFile?: (file: File) => Promise<{ fileId: string }>;\r\n getFileDownloadUrl?: (options: {\r\n fileId: string;\r\n }) => Promise<{ downloadUrl: string }>;\r\n requestDisplayMode?: (options: {\r\n mode: \"inline\" | \"pip\" | \"fullscreen\";\r\n }) => Promise<void>;\r\n requestModal?: (options: unknown) => Promise<void>;\r\n notifyIntrinsicHeight?: (height: number) => void;\r\n openExternal?: (options: { href: string }) => void;\r\n requestClose?: () => void;\r\n}\r\n\r\ndeclare global {\r\n interface Window {\r\n openai?: OpenAiGlobals;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Core Hook: useOpenAiGlobal\r\n// ============================================================================\r\n\r\nconst SET_GLOBALS_EVENT_TYPE = \"openai:set_globals\";\r\n\r\ninterface SetGlobalsEvent extends CustomEvent {\r\n detail: { globals: Partial<OpenAiGlobals> };\r\n}\r\n\r\n/**\r\n * Subscribe to a specific window.openai global value\r\n */\r\nexport function useOpenAiGlobal<K extends keyof OpenAiGlobals>(\r\n key: K,\r\n): OpenAiGlobals[K] {\r\n const getSnapshot = useCallback(() => {\r\n return window.openai?.[key];\r\n }, [key]);\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => {\r\n const handleSetGlobal = (event: Event) => {\r\n const customEvent = event as SetGlobalsEvent;\r\n if (customEvent.detail?.globals?.[key] !== undefined) {\r\n onChange();\r\n }\r\n };\r\n\r\n window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal, {\r\n passive: true,\r\n });\r\n return () =>\r\n window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal);\r\n },\r\n [key],\r\n );\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n}\r\n\r\n// ============================================================================\r\n// Widget State Hook\r\n// ============================================================================\r\n\r\ntype SetStateAction<T> = T | ((prevState: T) => T);\r\n\r\n/**\r\n * Manage widget state that persists across renders via window.openai.setWidgetState\r\n */\r\nexport function useWidgetState<T extends Record<string, unknown>>(\r\n defaultState: T | (() => T),\r\n): readonly [T, (state: SetStateAction<T>) => void] {\r\n const widgetStateFromWindow = useOpenAiGlobal(\"widgetState\") as T | undefined;\r\n\r\n const [widgetState, _setWidgetState] = useState<T>(() => {\r\n if (widgetStateFromWindow != null) {\r\n return widgetStateFromWindow;\r\n }\r\n return typeof defaultState === \"function\"\r\n ? (defaultState as () => T)()\r\n : defaultState;\r\n });\r\n\r\n useEffect(() => {\r\n if (widgetStateFromWindow != null) {\r\n _setWidgetState(widgetStateFromWindow);\r\n }\r\n }, [widgetStateFromWindow]);\r\n\r\n const setWidgetState = useCallback((state: SetStateAction<T>) => {\r\n _setWidgetState((prevState: T) => {\r\n const newState =\r\n typeof state === \"function\" ? (state as (p: T) => T)(prevState) : state;\r\n window.openai?.setWidgetState?.(newState);\r\n return newState;\r\n });\r\n }, []);\r\n\r\n return [widgetState, setWidgetState] as const;\r\n}\r\n\r\n// ============================================================================\r\n// Tool Output Hook\r\n// ============================================================================\r\n\r\n/**\r\n * Read the tool output (structuredContent) from the MCP server response\r\n */\r\nexport function useToolOutput<T = Record<string, unknown>>(): T | undefined {\r\n return useOpenAiGlobal(\"toolOutput\") as T | undefined;\r\n}\r\n\r\n/**\r\n * Read the tool input (arguments) from the tool invocation\r\n */\r\nexport function useToolInput<T = Record<string, unknown>>(): T | undefined {\r\n return useOpenAiGlobal(\"toolInput\") as T | undefined;\r\n}\r\n\r\n// ============================================================================\r\n// Theme Hook\r\n// ============================================================================\r\n\r\nexport type ThemeMode = \"light\" | \"dark\";\r\n\r\n/**\r\n * Get current ChatGPT theme and provide CSS-friendly values\r\n * Named useChatGPTTheme to avoid conflict with the core useTheme from ThemeProvider\r\n */\r\nexport function useChatGPTTheme(): {\r\n theme: ThemeMode;\r\n isDark: boolean;\r\n colors: {\r\n background: string;\r\n surface: string;\r\n surfaceHover: string;\r\n border: string;\r\n text: string;\r\n textMuted: string;\r\n accent: string;\r\n };\r\n} {\r\n const theme = useOpenAiGlobal(\"theme\") ?? \"dark\";\r\n const isDark = theme === \"dark\";\r\n\r\n return {\r\n theme,\r\n isDark,\r\n colors: isDark\r\n ? {\r\n background: \"#09090b\",\r\n surface: \"#18181b\",\r\n surfaceHover: \"#27272a\",\r\n border: \"#3f3f46\",\r\n text: \"#fafafa\",\r\n textMuted: \"#a1a1aa\",\r\n accent: \"#22d3ee\",\r\n }\r\n : {\r\n background: \"#ffffff\",\r\n surface: \"#f4f4f5\",\r\n surfaceHover: \"#e4e4e7\",\r\n border: \"#d4d4d8\",\r\n text: \"#18181b\",\r\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)\r\n accent: \"#0ea5e9\",\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Locale Hook\r\n// ============================================================================\r\n\r\n/**\r\n * Get current locale for internationalization\r\n */\r\nexport function useLocale(): string {\r\n return useOpenAiGlobal(\"locale\") ?? \"en-US\";\r\n}\r\n\r\n// ============================================================================\r\n// Display Mode Hook\r\n// ============================================================================\r\n\r\n/**\r\n * Manage widget display mode (inline, PiP, fullscreen)\r\n */\r\nexport function useDisplayMode(): {\r\n mode: \"inline\" | \"pip\" | \"fullscreen\";\r\n maxHeight?: number;\r\n requestMode: (mode: \"inline\" | \"pip\" | \"fullscreen\") => Promise<void>;\r\n close: () => void;\r\n} {\r\n const mode = useOpenAiGlobal(\"displayMode\") ?? \"inline\";\r\n const maxHeight = useOpenAiGlobal(\"maxHeight\");\r\n\r\n const requestMode = useCallback(\r\n async (newMode: \"inline\" | \"pip\" | \"fullscreen\") => {\r\n await window.openai?.requestDisplayMode?.({ mode: newMode });\r\n },\r\n [],\r\n );\r\n\r\n const close = useCallback(() => {\r\n window.openai?.requestClose?.();\r\n }, []);\r\n\r\n return { mode, maxHeight, requestMode, close };\r\n}\r\n\r\n// ============================================================================\r\n// Tool Calling Hook\r\n// ============================================================================\r\n\r\n/**\r\n * Call another MCP tool from within a widget\r\n */\r\nexport function useCallTool(): {\r\n callTool: <T = unknown>(\r\n name: string,\r\n args: Record<string, unknown>,\r\n ) => Promise<T>;\r\n isLoading: boolean;\r\n error: Error | null;\r\n} {\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [error, setError] = useState<Error | null>(null);\r\n\r\n const callTool = useCallback(\r\n async <T = unknown>(\r\n name: string,\r\n args: Record<string, unknown>,\r\n ): Promise<T> => {\r\n if (!window.openai?.callTool) {\r\n throw new Error(\"window.openai.callTool not available\");\r\n }\r\n\r\n setIsLoading(true);\r\n setError(null);\r\n\r\n try {\r\n const result = await window.openai.callTool(name, args);\r\n return result as T;\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error(String(err));\r\n setError(error);\r\n throw error;\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n },\r\n [],\r\n );\r\n\r\n return { callTool, isLoading, error };\r\n}\r\n\r\n// ============================================================================\r\n// Follow-up Message Hook\r\n// ============================================================================\r\n\r\n/**\r\n * Send a follow-up message as if the user asked it\r\n */\r\nexport function useSendMessage(): (prompt: string) => Promise<void> {\r\n return useCallback(async (prompt: string) => {\r\n await window.openai?.sendFollowUpMessage?.({ prompt });\r\n }, []);\r\n}\r\n\r\n// ============================================================================\r\n// Dynamic Height Hook\r\n// ============================================================================\r\n\r\n/**\r\n * Get the maximum height available for the widget from the host environment.\r\n * This is the CORRECT pattern per OpenAI Apps SDK examples.\r\n *\r\n * The host (ChatGPT/MCPJam) provides maxHeight, and widgets should constrain\r\n * themselves to this height. Widgets should NOT report their height back.\r\n *\r\n * @returns The maximum height in pixels, or undefined if not available\r\n */\r\nexport function useMaxHeight(): number | undefined {\r\n const [maxHeight, setMaxHeight] = useState<number | undefined>(\r\n () => window.openai?.maxHeight,\r\n );\r\n\r\n useEffect(() => {\r\n const handler = (event: CustomEvent) => {\r\n if (event.detail?.globals && \"maxHeight\" in event.detail.globals) {\r\n setMaxHeight(event.detail.globals.maxHeight);\r\n }\r\n };\r\n\r\n window.addEventListener(\"openai:set_globals\", handler as EventListener);\r\n return () =>\r\n window.removeEventListener(\r\n \"openai:set_globals\",\r\n handler as EventListener,\r\n );\r\n }, []);\r\n\r\n return maxHeight;\r\n}\r\n\r\n// ============================================================================\r\n// External Link Hook\r\n// ============================================================================\r\n\r\n/**\r\n * Open vetted external links in the user's browser\r\n */\r\nexport function useOpenExternal(): (href: string) => void {\r\n return useCallback((href: string) => {\r\n window.openai?.openExternal?.({ href });\r\n }, []);\r\n}\r\n\r\n// ============================================================================\r\n// Utility: Check if running in ChatGPT\r\n// ============================================================================\r\n\r\nexport function isInChatGPT(): boolean {\r\n return typeof window !== \"undefined\" && window.openai !== undefined;\r\n}\r\n\r\n// ============================================================================\r\n// Re-exports (types are already exported above)\r\n// ============================================================================\r\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
- const CategoryContext = createContext(null);
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
- function CategoryProvider({
7
- categories,
8
- categoryLabel = "Categories",
9
- fallbackPalette,
10
- children
11
- }) {
12
- const value = useMemo(() => ({
13
- palette: new CategoryPalette(categories, fallbackPalette),
14
- categories,
15
- categoryLabel
16
- }), [categories, categoryLabel, fallbackPalette]);
17
- return /* @__PURE__ */ jsx(CategoryContext.Provider, { value, children });
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
- return useContext(CategoryContext);
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
- const ctx = useContext(CategoryContext);
24
- if (!ctx) {
25
- throw new Error(
26
- "useCategoryPaletteRequired() was called outside of a <CategoryProvider>. Wrap a parent component with <CategoryProvider categories={[...]}> or use useCategoryPalette() for graceful null handling."
27
- );
28
- }
29
- return ctx;
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
- export {
32
- CategoryProvider,
33
- useCategoryPalette,
34
- useCategoryPaletteRequired
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":["/**\r\n * @zendir/ui — CategoryProvider\r\n *\r\n * Optional React context for sharing a `CategoryPalette` and display label\r\n * across sibling components in a dashboard layout. Components that are\r\n * \"category-aware\" (Timeline, GroundTrackMap, AstroChart, DataTable) can\r\n * read from this context to resolve colors/labels without each needing\r\n * explicit palette props.\r\n *\r\n * **This context is fully opt-in.** Components continue to work standalone\r\n * — explicit `color` / `team` props always take precedence over context.\r\n *\r\n * @example\r\n * ```tsx\r\n * import { CategoryProvider, useCategoryPalette } from '@zendir/ui';\r\n *\r\n * const categories = [\r\n * { id: 'alpha', label: 'Team Alpha', color: '#2dccff' },\r\n * { id: 'bravo', label: 'Team Bravo', color: '#fce83a' },\r\n * ];\r\n *\r\n * // Wrap a section of your dashboard\r\n * <CategoryProvider categories={categories} categoryLabel=\"Squads\">\r\n * <Timeline events={events} />\r\n * <GroundTrackMap pins={pins} />\r\n * </CategoryProvider>\r\n *\r\n * // Inside any component\r\n * function MyWidget() {\r\n * const ctx = useCategoryPalette();\r\n * if (!ctx) return null; // graceful when no provider\r\n * const color = ctx.palette.getColor('alpha');\r\n * const label = ctx.categoryLabel; // \"Squads\"\r\n * }\r\n * ```\r\n */\r\n\r\nimport React, { createContext, useContext, useMemo, type ReactNode } from 'react';\r\nimport { CategoryPalette } from '../utils/categoryPalette';\r\nimport type { CategoryDef } from '../types';\r\n\r\n// =============================================================================\r\n// Context value\r\n// =============================================================================\r\n\r\nexport interface CategoryContextValue {\r\n /** Palette instance built from the provided categories. */\r\n palette: CategoryPalette;\r\n /** All registered category definitions. */\r\n categories: CategoryDef[];\r\n /**\r\n * Human-readable label for the grouping dimension.\r\n * Defaults to `\"Categories\"`. Components that support a label override\r\n * (e.g. Timeline's `teamLabel`) should fall back to this when no\r\n * explicit prop is provided.\r\n */\r\n categoryLabel: string;\r\n}\r\n\r\nconst CategoryContext = createContext<CategoryContextValue | null>(null);\r\nCategoryContext.displayName = 'CategoryContext';\r\n\r\n// =============================================================================\r\n// Provider\r\n// =============================================================================\r\n\r\nexport interface CategoryProviderProps {\r\n /** Category definitions — each must have `id`, `label`, and `color`. */\r\n categories: CategoryDef[];\r\n /**\r\n * Display label for the grouping dimension, e.g. `\"Teams\"`, `\"Squads\"`,\r\n * `\"Subsystems\"`. Defaults to `\"Categories\"`.\r\n */\r\n categoryLabel?: string;\r\n /**\r\n * Optional custom fallback palette for auto-assigned unknown ids.\r\n * Defaults to the Astro data-viz palette built into `CategoryPalette`.\r\n */\r\n fallbackPalette?: string[];\r\n children: ReactNode;\r\n}\r\n\r\n/**\r\n * Provides a shared `CategoryPalette` to descendant components.\r\n *\r\n * Wrap a dashboard section (not the entire app) so sibling components\r\n * like Timeline + Map + Charts resolve the same colors for the same ids.\r\n */\r\nexport function CategoryProvider({\r\n categories,\r\n categoryLabel = 'Categories',\r\n fallbackPalette,\r\n children,\r\n}: CategoryProviderProps): React.ReactElement {\r\n const value = useMemo<CategoryContextValue>(() => ({\r\n palette: new CategoryPalette(categories, fallbackPalette),\r\n categories,\r\n categoryLabel,\r\n }), [categories, categoryLabel, fallbackPalette]);\r\n\r\n return (\r\n <CategoryContext.Provider value={value}>\r\n {children}\r\n </CategoryContext.Provider>\r\n );\r\n}\r\n\r\n// =============================================================================\r\n// Hooks\r\n// =============================================================================\r\n\r\n/**\r\n * Access the nearest `CategoryProvider`'s palette and label.\r\n *\r\n * Returns `null` when no provider is present — components should treat\r\n * this as \"standalone mode\" and fall back to explicit props / defaults.\r\n */\r\nexport function useCategoryPalette(): CategoryContextValue | null {\r\n return useContext(CategoryContext);\r\n}\r\n\r\n/**\r\n * Like `useCategoryPalette()` but throws if no provider is found.\r\n * Use only when you know a provider is always present.\r\n */\r\nexport function useCategoryPaletteRequired(): CategoryContextValue {\r\n const ctx = useContext(CategoryContext);\r\n if (!ctx) {\r\n throw new Error(\r\n 'useCategoryPaletteRequired() was called outside of a <CategoryProvider>. ' +\r\n 'Wrap a parent component with <CategoryProvider categories={[...]}> or ' +\r\n 'use useCategoryPalette() for graceful null handling.',\r\n );\r\n }\r\n return ctx;\r\n}\r\n"],"names":[],"mappings":";;;AA2DA,MAAM,kBAAkB,cAA2C,IAAI;AACvE,gBAAgB,cAAc;AA4BvB,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AACF,GAA8C;AAC5C,QAAM,QAAQ,QAA8B,OAAO;AAAA,IACjD,SAAS,IAAI,gBAAgB,YAAY,eAAe;AAAA,IACxD;AAAA,IACA;AAAA,EAAA,IACE,CAAC,YAAY,eAAe,eAAe,CAAC;AAEhD,SACE,oBAAC,gBAAgB,UAAhB,EAAyB,OACvB,SAAA,CACH;AAEJ;AAYO,SAAS,qBAAkD;AAChE,SAAO,WAAW,eAAe;AACnC;AAMO,SAAS,6BAAmD;AACjE,QAAM,MAAM,WAAW,eAAe;AACtC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAIJ;AACA,SAAO;AACT;"}
1
+ {"version":3,"file":"CategoryContext.js","names":[],"sources":["../../../src/react/context/CategoryContext.tsx"],"sourcesContent":["/**\r\n * @zendir/ui — CategoryProvider\r\n *\r\n * Optional React context for sharing a `CategoryPalette` and display label\r\n * across sibling components in a dashboard layout. Components that are\r\n * \"category-aware\" (Timeline, GroundTrackMap, AstroChart, DataTable) can\r\n * read from this context to resolve colors/labels without each needing\r\n * explicit palette props.\r\n *\r\n * **This context is fully opt-in.** Components continue to work standalone\r\n * — explicit `color` / `team` props always take precedence over context.\r\n *\r\n * @example\r\n * ```tsx\r\n * import { CategoryProvider, useCategoryPalette } from '@zendir/ui';\r\n *\r\n * const categories = [\r\n * { id: 'alpha', label: 'Team Alpha', color: '#2dccff' },\r\n * { id: 'bravo', label: 'Team Bravo', color: '#fce83a' },\r\n * ];\r\n *\r\n * // Wrap a section of your dashboard\r\n * <CategoryProvider categories={categories} categoryLabel=\"Squads\">\r\n * <Timeline events={events} />\r\n * <GroundTrackMap pins={pins} />\r\n * </CategoryProvider>\r\n *\r\n * // Inside any component\r\n * function MyWidget() {\r\n * const ctx = useCategoryPalette();\r\n * if (!ctx) return null; // graceful when no provider\r\n * const color = ctx.palette.getColor('alpha');\r\n * const label = ctx.categoryLabel; // \"Squads\"\r\n * }\r\n * ```\r\n */\r\n\r\nimport React, {\r\n createContext,\r\n useContext,\r\n useMemo,\r\n type ReactNode,\r\n} from \"react\";\r\nimport { CategoryPalette } from \"../utils/categoryPalette\";\r\nimport type { CategoryDef } from \"../types\";\r\n\r\n// =============================================================================\r\n// Context value\r\n// =============================================================================\r\n\r\nexport interface CategoryContextValue {\r\n /** Palette instance built from the provided categories. */\r\n palette: CategoryPalette;\r\n /** All registered category definitions. */\r\n categories: CategoryDef[];\r\n /**\r\n * Human-readable label for the grouping dimension.\r\n * Defaults to `\"Categories\"`. Components that support a label override\r\n * (e.g. Timeline's `teamLabel`) should fall back to this when no\r\n * explicit prop is provided.\r\n */\r\n categoryLabel: string;\r\n}\r\n\r\nconst CategoryContext = createContext<CategoryContextValue | null>(null);\r\nCategoryContext.displayName = \"CategoryContext\";\r\n\r\n// =============================================================================\r\n// Provider\r\n// =============================================================================\r\n\r\nexport interface CategoryProviderProps {\r\n /** Category definitions — each must have `id`, `label`, and `color`. */\r\n categories: CategoryDef[];\r\n /**\r\n * Display label for the grouping dimension, e.g. `\"Teams\"`, `\"Squads\"`,\r\n * `\"Subsystems\"`. Defaults to `\"Categories\"`.\r\n */\r\n categoryLabel?: string;\r\n /**\r\n * Optional custom fallback palette for auto-assigned unknown ids.\r\n * Defaults to the Astro data-viz palette built into `CategoryPalette`.\r\n */\r\n fallbackPalette?: string[];\r\n children: ReactNode;\r\n}\r\n\r\n/**\r\n * Provides a shared `CategoryPalette` to descendant components.\r\n *\r\n * Wrap a dashboard section (not the entire app) so sibling components\r\n * like Timeline + Map + Charts resolve the same colors for the same ids.\r\n */\r\nexport function CategoryProvider({\r\n categories,\r\n categoryLabel = \"Categories\",\r\n fallbackPalette,\r\n children,\r\n}: CategoryProviderProps): React.ReactElement {\r\n const value = useMemo<CategoryContextValue>(\r\n () => ({\r\n palette: new CategoryPalette(categories, fallbackPalette),\r\n categories,\r\n categoryLabel,\r\n }),\r\n [categories, categoryLabel, fallbackPalette],\r\n );\r\n\r\n return (\r\n <CategoryContext.Provider value={value}>\r\n {children}\r\n </CategoryContext.Provider>\r\n );\r\n}\r\n\r\n// =============================================================================\r\n// Hooks\r\n// =============================================================================\r\n\r\n/**\r\n * Access the nearest `CategoryProvider`'s palette and label.\r\n *\r\n * Returns `null` when no provider is present — components should treat\r\n * this as \"standalone mode\" and fall back to explicit props / defaults.\r\n */\r\nexport function useCategoryPalette(): CategoryContextValue | null {\r\n return useContext(CategoryContext);\r\n}\r\n\r\n/**\r\n * Like `useCategoryPalette()` but throws if no provider is found.\r\n * Use only when you know a provider is always present.\r\n */\r\nexport function useCategoryPaletteRequired(): CategoryContextValue {\r\n const ctx = useContext(CategoryContext);\r\n if (!ctx) {\r\n throw new Error(\r\n \"useCategoryPaletteRequired() was called outside of a <CategoryProvider>. \" +\r\n \"Wrap a parent component with <CategoryProvider categories={[...]}> or \" +\r\n \"use useCategoryPalette() for graceful null handling.\",\r\n );\r\n }\r\n return ctx;\r\n}\r\n"],"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;