@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 +1 @@
1
- {"version":3,"file":"SidePanel.js","sources":["../../../../src/react/core/overlays/SidePanel.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - SidePanel Component\r\n * \r\n * A sliding panel that pushes content instead of overlaying it.\r\n * Designed to be placed as a flex sibling so the parent layout\r\n * naturally adjusts when the panel opens/closes.\r\n * \r\n * Features:\r\n * - Push-content behavior (flex sibling, content adjusts automatically)\r\n * - Smooth slide-in/out animation\r\n * - Configurable width, position (left/right)\r\n * - Optional overlay backdrop (for modal-like behavior)\r\n * - Theme-integrated via useTheme()\r\n * - Accessible (focus trap, keyboard support)\r\n * - Close on escape key\r\n * \r\n * @example\r\n * ```tsx\r\n * // Push-content pattern: SidePanel as flex sibling\r\n * <div style={{ display: 'flex', height: '100vh' }}>\r\n * <main style={{ flex: 1, transition: 'all 0.3s ease' }}>\r\n * {children}\r\n * </main>\r\n * <SidePanel\r\n * open={isChatOpen}\r\n * onClose={() => setIsChatOpen(false)}\r\n * title=\"Chat Assistant\"\r\n * width={380}\r\n * >\r\n * <ChatPanel messages={messages} onSend={handleSend} />\r\n * </SidePanel>\r\n * </div>\r\n * ```\r\n */\r\n\r\nimport React, { memo, useEffect, useRef, useCallback, useState } from 'react';\r\nimport { useTheme } from '../../theme';\r\nimport { classNames } from '../../utils';\r\nimport { useBreakpoint } from '../layout/useBreakpoint';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport type SidePanelPosition = 'left' | 'right';\r\n\r\nexport interface SidePanelProps {\r\n /** Whether the panel is open */\r\n open: boolean;\r\n /** Called when the panel should close */\r\n onClose: () => void;\r\n /** Panel title displayed in the header */\r\n title?: string;\r\n /** Panel width in px or CSS string (default: 380) */\r\n width?: number | string;\r\n /** Which side the panel slides in from (default: 'right') */\r\n position?: SidePanelPosition;\r\n /** Show a close button in the header (default: true) */\r\n showCloseButton?: boolean;\r\n /** Close when pressing Escape (default: true) */\r\n closeOnEscape?: boolean;\r\n /** Show a semi-transparent overlay behind the panel (default: false) */\r\n overlay?: boolean;\r\n /** Close when clicking the overlay (default: true, only applies when overlay=true) */\r\n closeOnOverlayClick?: boolean;\r\n /** Panel content */\r\n children: React.ReactNode;\r\n /** Optional header actions (rendered in header, right of title) */\r\n headerActions?: React.ReactNode;\r\n /** Optional leading element (rendered in header, left of title — useful for collapse icons) */\r\n headerLeading?: React.ReactNode;\r\n /** Called when the header bar is clicked (useful for collapse-on-click) */\r\n onHeaderClick?: () => void;\r\n /** Custom style overrides for the header bar */\r\n headerStyle?: React.CSSProperties;\r\n /** Custom className */\r\n className?: string;\r\n /** Custom style overrides for the panel container */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n// ============================================================================\r\n// Unique animation ID\r\n// ============================================================================\r\n\r\nlet sidePanelInstanceCount = 0;\r\n\r\n// ============================================================================\r\n// Component\r\n// ============================================================================\r\n\r\nexport const SidePanel = memo(function SidePanel({\r\n open,\r\n onClose,\r\n title,\r\n width = 380,\r\n position = 'right',\r\n showCloseButton = true,\r\n closeOnEscape = true,\r\n overlay = false,\r\n closeOnOverlayClick = true,\r\n children,\r\n headerActions,\r\n headerLeading,\r\n onHeaderClick,\r\n headerStyle: headerStyleProp,\r\n className = '',\r\n style: styleProp,\r\n}: SidePanelProps): React.ReactElement | null {\r\n const { tokens, theme } = useTheme();\r\n const isTransparentTheme = theme === 'transparent' || theme === 'transparent-bold' || theme === 'transparent-minimal';\r\n const panelRef = useRef<HTMLDivElement>(null);\r\n const [animState, setAnimState] = useState<'closed' | 'opening' | 'open' | 'closing'>('closed');\r\n const _instanceId = useRef(++sidePanelInstanceCount);\r\n\r\n const { isMobile } = useBreakpoint();\r\n const resolvedWidth = isMobile ? '100%' : (typeof width === 'number' ? `${width}px` : width);\r\n\r\n // Animate open/close\r\n useEffect(() => {\r\n if (open) {\r\n setAnimState('opening');\r\n const timer = setTimeout(() => setAnimState('open'), 30);\r\n return () => clearTimeout(timer);\r\n } else {\r\n if (animState === 'open' || animState === 'opening') {\r\n setAnimState('closing');\r\n const timer = setTimeout(() => setAnimState('closed'), 550);\r\n return () => clearTimeout(timer);\r\n }\r\n }\r\n }, [open]);\r\n\r\n // Escape key handler\r\n const handleKeyDown = useCallback((e: KeyboardEvent) => {\r\n if (closeOnEscape && e.key === 'Escape') {\r\n onClose();\r\n }\r\n }, [closeOnEscape, onClose]);\r\n\r\n useEffect(() => {\r\n if (open) {\r\n document.addEventListener('keydown', handleKeyDown);\r\n return () => document.removeEventListener('keydown', handleKeyDown);\r\n }\r\n }, [open, handleKeyDown]);\r\n\r\n // Don't render at all when fully closed\r\n if (animState === 'closed') return null;\r\n\r\n const isVisible = animState === 'open';\r\n const slideFrom = position === 'right' ? 'translateX(100%)' : 'translateX(-100%)';\r\n\r\n return (\r\n <>\r\n {/* Optional overlay */}\r\n {overlay && (\r\n <div\r\n className=\"zendir-sidepanel-overlay\"\r\n onClick={closeOnOverlayClick ? onClose : undefined}\r\n style={{\r\n position: 'fixed',\r\n inset: 0,\r\n backgroundColor: isTransparentTheme ? `${tokens.colors.background.base}4D` : `${tokens.colors.background.base}66`,\r\n backdropFilter: isTransparentTheme ? 'blur(2px)' : undefined,\r\n WebkitBackdropFilter: isTransparentTheme ? 'blur(2px)' : undefined,\r\n zIndex: 999,\r\n opacity: isVisible ? 1 : 0,\r\n transition: 'opacity 0.3s ease',\r\n pointerEvents: isVisible ? 'auto' : 'none',\r\n }}\r\n />\r\n )}\r\n\r\n {/* Panel */}\r\n <div\r\n ref={panelRef}\r\n className={classNames('zendir-sidepanel', className)}\r\n style={{\r\n width: isVisible ? resolvedWidth : '0px',\r\n minWidth: isVisible ? resolvedWidth : '0px',\r\n maxWidth: resolvedWidth,\r\n height: '100%',\r\n overflow: 'hidden',\r\n transition: 'width 0.6s cubic-bezier(0.2, 0.8, 0.2, 1), min-width 0.6s cubic-bezier(0.2, 0.8, 0.2, 1)',\r\n flexShrink: 0,\r\n position: 'relative',\r\n zIndex: overlay ? 1000 : 'auto',\r\n ...(overlay && { position: 'fixed', top: 0, [position]: 0 }),\r\n ...styleProp,\r\n }}\r\n >\r\n <div\r\n style={{\r\n width: resolvedWidth,\r\n height: '100%',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n backgroundColor: isTransparentTheme\r\n ? 'rgba(15, 15, 35, 0.85)'\r\n : tokens.colors.background.surface,\r\n ...(isTransparentTheme && {\r\n backdropFilter: 'blur(16px)',\r\n WebkitBackdropFilter: 'blur(16px)',\r\n }),\r\n borderLeft: position === 'right' ? tokens.borders.divider : undefined,\r\n borderRight: position === 'left' ? tokens.borders.divider : undefined,\r\n transform: isVisible ? 'translateX(0)' : slideFrom,\r\n transition: 'transform 0.6s cubic-bezier(0.2, 0.8, 0.2, 1)',\r\n overflow: 'hidden',\r\n }}\r\n >\r\n {/* Header */}\r\n {(title || showCloseButton || headerActions || headerLeading) && (\r\n <div\r\n onClick={onHeaderClick}\r\n role={onHeaderClick ? 'button' : undefined}\r\n tabIndex={onHeaderClick ? 0 : undefined}\r\n onKeyDown={onHeaderClick ? (e: React.KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onHeaderClick(); } } : undefined}\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'space-between',\r\n padding: `${tokens.spacing.md} ${tokens.spacing.md}`,\r\n borderBottom: tokens.borders.divider,\r\n flexShrink: 0,\r\n gap: tokens.spacing.sm,\r\n ...(onHeaderClick && { cursor: 'pointer' }),\r\n ...headerStyleProp,\r\n }}\r\n >\r\n <div style={{ display: 'flex', alignItems: 'center', gap: tokens.spacing.sm, flex: 1, minWidth: 0 }}>\r\n {headerLeading}\r\n {title && (\r\n <h3\r\n style={{\r\n margin: 0,\r\n fontSize: tokens.typography.fontSize.base,\r\n fontWeight: tokens.typography.fontWeight.semibold,\r\n color: tokens.colors.text.primary,\r\n whiteSpace: 'nowrap',\r\n overflow: 'hidden',\r\n textOverflow: 'ellipsis',\r\n }}\r\n >\r\n {title}\r\n </h3>\r\n )}\r\n </div>\r\n <div style={{ display: 'flex', alignItems: 'center', gap: tokens.spacing.xs, flexShrink: 0 }}>\r\n {headerActions}\r\n {showCloseButton && (\r\n <button\r\n type=\"button\"\r\n onClick={onClose}\r\n aria-label=\"Close panel\"\r\n style={{\r\n padding: tokens.spacing.sm,\r\n minWidth: 44,\r\n minHeight: 44,\r\n backgroundColor: 'transparent',\r\n border: 'none',\r\n borderRadius: tokens.borderRadius.sm,\r\n cursor: 'pointer',\r\n color: tokens.colors.text.muted ?? tokens.colors.text.tertiary,\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n transition: `color 0.15s ease, background-color 0.15s ease`,\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.color = tokens.colors.text.primary;\r\n e.currentTarget.style.backgroundColor = tokens.colors.background.base;\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.color = tokens.colors.text.muted ?? tokens.colors.text.tertiary;\r\n e.currentTarget.style.backgroundColor = 'transparent';\r\n }}\r\n >\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\" />\r\n </svg>\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Content */}\r\n <div\r\n style={{\r\n flex: 1,\r\n overflow: 'auto',\r\n minHeight: 0,\r\n }}\r\n >\r\n {children}\r\n </div>\r\n </div>\r\n </div>\r\n </>\r\n );\r\n});\r\n\r\nexport default SidePanel;\r\n"],"names":["SidePanel"],"mappings":"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"}
1
+ {"version":3,"file":"SidePanel.js","names":[],"sources":["../../../../src/react/core/overlays/SidePanel.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - SidePanel Component\r\n *\r\n * A sliding panel that pushes content instead of overlaying it.\r\n * Designed to be placed as a flex sibling so the parent layout\r\n * naturally adjusts when the panel opens/closes.\r\n *\r\n * Features:\r\n * - Push-content behavior (flex sibling, content adjusts automatically)\r\n * - Smooth slide-in/out animation\r\n * - Configurable width, position (left/right)\r\n * - Optional overlay backdrop (for modal-like behavior)\r\n * - Theme-integrated via useTheme()\r\n * - Accessible (focus trap, keyboard support)\r\n * - Close on escape key\r\n *\r\n * @example\r\n * ```tsx\r\n * // Push-content pattern: SidePanel as flex sibling\r\n * <div style={{ display: 'flex', height: '100vh' }}>\r\n * <main style={{ flex: 1, transition: 'all 0.3s ease' }}>\r\n * {children}\r\n * </main>\r\n * <SidePanel\r\n * open={isChatOpen}\r\n * onClose={() => setIsChatOpen(false)}\r\n * title=\"Chat Assistant\"\r\n * width={380}\r\n * >\r\n * <ChatPanel messages={messages} onSend={handleSend} />\r\n * </SidePanel>\r\n * </div>\r\n * ```\r\n */\r\n\r\nimport React, { memo, useEffect, useRef, useCallback, useState } from \"react\";\r\nimport { useTheme } from \"../../theme\";\r\nimport { classNames } from \"../../utils\";\r\nimport { useBreakpoint } from \"../layout/useBreakpoint\";\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport type SidePanelPosition = \"left\" | \"right\";\r\n\r\nexport interface SidePanelProps {\r\n /** Whether the panel is open */\r\n open: boolean;\r\n /** Called when the panel should close */\r\n onClose: () => void;\r\n /** Panel title displayed in the header */\r\n title?: string;\r\n /** Panel width in px or CSS string (default: 380) */\r\n width?: number | string;\r\n /** Which side the panel slides in from (default: 'right') */\r\n position?: SidePanelPosition;\r\n /** Show a close button in the header (default: true) */\r\n showCloseButton?: boolean;\r\n /** Close when pressing Escape (default: true) */\r\n closeOnEscape?: boolean;\r\n /** Show a semi-transparent overlay behind the panel (default: false) */\r\n overlay?: boolean;\r\n /** Close when clicking the overlay (default: true, only applies when overlay=true) */\r\n closeOnOverlayClick?: boolean;\r\n /** Panel content */\r\n children: React.ReactNode;\r\n /** Optional header actions (rendered in header, right of title) */\r\n headerActions?: React.ReactNode;\r\n /** Optional leading element (rendered in header, left of title — useful for collapse icons) */\r\n headerLeading?: React.ReactNode;\r\n /** Called when the header bar is clicked (useful for collapse-on-click) */\r\n onHeaderClick?: () => void;\r\n /** Custom style overrides for the header bar */\r\n headerStyle?: React.CSSProperties;\r\n /** Custom className */\r\n className?: string;\r\n /** Custom style overrides for the panel container */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n// ============================================================================\r\n// Unique animation ID\r\n// ============================================================================\r\n\r\nlet sidePanelInstanceCount = 0;\r\n\r\n// ============================================================================\r\n// Component\r\n// ============================================================================\r\n\r\nexport const SidePanel = memo(function SidePanel({\r\n open,\r\n onClose,\r\n title,\r\n width = 380,\r\n position = \"right\",\r\n showCloseButton = true,\r\n closeOnEscape = true,\r\n overlay = false,\r\n closeOnOverlayClick = true,\r\n children,\r\n headerActions,\r\n headerLeading,\r\n onHeaderClick,\r\n headerStyle: headerStyleProp,\r\n className = \"\",\r\n style: styleProp,\r\n}: SidePanelProps): React.ReactElement | null {\r\n const { tokens, theme } = useTheme();\r\n const isTransparentTheme =\r\n theme === \"transparent\" ||\r\n theme === \"transparent-bold\" ||\r\n theme === \"transparent-minimal\";\r\n const panelRef = useRef<HTMLDivElement>(null);\r\n const [animState, setAnimState] = useState<\r\n \"closed\" | \"opening\" | \"open\" | \"closing\"\r\n >(\"closed\");\r\n const _instanceId = useRef(++sidePanelInstanceCount);\r\n\r\n const { isMobile } = useBreakpoint();\r\n const resolvedWidth = isMobile\r\n ? \"100%\"\r\n : typeof width === \"number\"\r\n ? `${width}px`\r\n : width;\r\n\r\n // Animate open/close\r\n useEffect(() => {\r\n if (open) {\r\n setAnimState(\"opening\");\r\n const timer = setTimeout(() => setAnimState(\"open\"), 30);\r\n return () => clearTimeout(timer);\r\n } else {\r\n if (animState === \"open\" || animState === \"opening\") {\r\n setAnimState(\"closing\");\r\n const timer = setTimeout(() => setAnimState(\"closed\"), 550);\r\n return () => clearTimeout(timer);\r\n }\r\n }\r\n }, [open]);\r\n\r\n // Escape key handler\r\n const handleKeyDown = useCallback(\r\n (e: KeyboardEvent) => {\r\n if (closeOnEscape && e.key === \"Escape\") {\r\n onClose();\r\n }\r\n },\r\n [closeOnEscape, onClose],\r\n );\r\n\r\n useEffect(() => {\r\n if (open) {\r\n document.addEventListener(\"keydown\", handleKeyDown);\r\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\r\n }\r\n }, [open, handleKeyDown]);\r\n\r\n // Don't render at all when fully closed\r\n if (animState === \"closed\") return null;\r\n\r\n const isVisible = animState === \"open\";\r\n const slideFrom =\r\n position === \"right\" ? \"translateX(100%)\" : \"translateX(-100%)\";\r\n\r\n return (\r\n <>\r\n {/* Optional overlay */}\r\n {overlay && (\r\n <div\r\n className=\"zendir-sidepanel-overlay\"\r\n onClick={closeOnOverlayClick ? onClose : undefined}\r\n style={{\r\n position: \"fixed\",\r\n inset: 0,\r\n backgroundColor: isTransparentTheme\r\n ? `${tokens.colors.background.base}4D`\r\n : `${tokens.colors.background.base}66`,\r\n backdropFilter: isTransparentTheme ? \"blur(2px)\" : undefined,\r\n WebkitBackdropFilter: isTransparentTheme ? \"blur(2px)\" : undefined,\r\n zIndex: 999,\r\n opacity: isVisible ? 1 : 0,\r\n transition: \"opacity 0.3s ease\",\r\n pointerEvents: isVisible ? \"auto\" : \"none\",\r\n }}\r\n />\r\n )}\r\n\r\n {/* Panel */}\r\n <div\r\n ref={panelRef}\r\n className={classNames(\"zendir-sidepanel\", className)}\r\n style={{\r\n width: isVisible ? resolvedWidth : \"0px\",\r\n minWidth: isVisible ? resolvedWidth : \"0px\",\r\n maxWidth: resolvedWidth,\r\n height: \"100%\",\r\n overflow: \"hidden\",\r\n transition:\r\n \"width 0.6s cubic-bezier(0.2, 0.8, 0.2, 1), min-width 0.6s cubic-bezier(0.2, 0.8, 0.2, 1)\",\r\n flexShrink: 0,\r\n position: \"relative\",\r\n zIndex: overlay ? 1000 : \"auto\",\r\n ...(overlay && { position: \"fixed\", top: 0, [position]: 0 }),\r\n ...styleProp,\r\n }}\r\n >\r\n <div\r\n style={{\r\n width: resolvedWidth,\r\n height: \"100%\",\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n backgroundColor: isTransparentTheme\r\n ? \"rgba(15, 15, 35, 0.85)\"\r\n : tokens.colors.background.surface,\r\n ...(isTransparentTheme && {\r\n backdropFilter: \"blur(16px)\",\r\n WebkitBackdropFilter: \"blur(16px)\",\r\n }),\r\n borderLeft:\r\n position === \"right\" ? tokens.borders.divider : undefined,\r\n borderRight:\r\n position === \"left\" ? tokens.borders.divider : undefined,\r\n transform: isVisible ? \"translateX(0)\" : slideFrom,\r\n transition: \"transform 0.6s cubic-bezier(0.2, 0.8, 0.2, 1)\",\r\n overflow: \"hidden\",\r\n }}\r\n >\r\n {/* Header */}\r\n {(title || showCloseButton || headerActions || headerLeading) && (\r\n <div\r\n onClick={onHeaderClick}\r\n role={onHeaderClick ? \"button\" : undefined}\r\n tabIndex={onHeaderClick ? 0 : undefined}\r\n onKeyDown={\r\n onHeaderClick\r\n ? (e: React.KeyboardEvent) => {\r\n if (e.key === \"Enter\" || e.key === \" \") {\r\n e.preventDefault();\r\n onHeaderClick();\r\n }\r\n }\r\n : undefined\r\n }\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"space-between\",\r\n padding: `${tokens.spacing.md} ${tokens.spacing.md}`,\r\n borderBottom: tokens.borders.divider,\r\n flexShrink: 0,\r\n gap: tokens.spacing.sm,\r\n ...(onHeaderClick && { cursor: \"pointer\" }),\r\n ...headerStyleProp,\r\n }}\r\n >\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: tokens.spacing.sm,\r\n flex: 1,\r\n minWidth: 0,\r\n }}\r\n >\r\n {headerLeading}\r\n {title && (\r\n <h3\r\n style={{\r\n margin: 0,\r\n fontSize: tokens.typography.fontSize.base,\r\n fontWeight: tokens.typography.fontWeight.semibold,\r\n color: tokens.colors.text.primary,\r\n whiteSpace: \"nowrap\",\r\n overflow: \"hidden\",\r\n textOverflow: \"ellipsis\",\r\n }}\r\n >\r\n {title}\r\n </h3>\r\n )}\r\n </div>\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: tokens.spacing.xs,\r\n flexShrink: 0,\r\n }}\r\n >\r\n {headerActions}\r\n {showCloseButton && (\r\n <button\r\n type=\"button\"\r\n onClick={onClose}\r\n aria-label=\"Close panel\"\r\n style={{\r\n padding: tokens.spacing.sm,\r\n minWidth: 44,\r\n minHeight: 44,\r\n backgroundColor: \"transparent\",\r\n border: \"none\",\r\n borderRadius: tokens.borderRadius.sm,\r\n cursor: \"pointer\",\r\n color:\r\n tokens.colors.text.muted ?? tokens.colors.text.tertiary,\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n transition: `color 0.15s ease, background-color 0.15s ease`,\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.color = tokens.colors.text.primary;\r\n e.currentTarget.style.backgroundColor =\r\n tokens.colors.background.base;\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.color =\r\n tokens.colors.text.muted ?? tokens.colors.text.tertiary;\r\n e.currentTarget.style.backgroundColor = \"transparent\";\r\n }}\r\n >\r\n <svg\r\n width=\"20\"\r\n height=\"20\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"currentColor\"\r\n >\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\" />\r\n </svg>\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Content */}\r\n <div\r\n style={{\r\n flex: 1,\r\n overflow: \"auto\",\r\n minHeight: 0,\r\n }}\r\n >\r\n {children}\r\n </div>\r\n </div>\r\n </div>\r\n </>\r\n );\r\n});\r\n\r\nexport default SidePanel;\r\n"],"mappings":"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"}
@@ -1,6 +1,5 @@
1
1
  import { default as React } from 'react';
2
-
3
- export type TooltipPlacement = 'top' | 'bottom' | 'left' | 'right';
2
+ export type TooltipPlacement = "top" | "bottom" | "left" | "right";
4
3
  export interface TooltipProps {
5
4
  /** Tooltip content */
6
5
  content: React.ReactNode;
@@ -1,179 +1,173 @@
1
- import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
- import { memo, useState, useRef, useCallback, useLayoutEffect, useEffect } from "react";
3
- import ReactDOM from "react-dom";
4
1
  import { useTheme } from "../../theme/ThemeProvider.js";
5
2
  import { classNames } from "../../utils/index.js";
6
- const Tooltip = memo(function Tooltip2({
7
- content,
8
- placement = "top",
9
- delay = 200,
10
- disabled = false,
11
- children,
12
- className = ""
13
- }) {
14
- const { tokens } = useTheme();
15
- const [visible, setVisible] = useState(false);
16
- const [positioned, setPositioned] = useState(false);
17
- const [position, setPosition] = useState({ top: 0, left: 0 });
18
- const triggerRef = useRef(null);
19
- const tooltipRef = useRef(null);
20
- const timeoutRef = useRef();
21
- const hideTimeoutRef = useRef();
22
- const showTooltip = useCallback(() => {
23
- if (disabled) return;
24
- if (hideTimeoutRef.current) {
25
- clearTimeout(hideTimeoutRef.current);
26
- hideTimeoutRef.current = void 0;
27
- }
28
- timeoutRef.current = window.setTimeout(() => {
29
- setVisible(true);
30
- setPositioned(false);
31
- }, delay);
32
- }, [disabled, delay]);
33
- const hideTooltip = useCallback(() => {
34
- if (timeoutRef.current) {
35
- clearTimeout(timeoutRef.current);
36
- }
37
- hideTimeoutRef.current = window.setTimeout(() => {
38
- setVisible(false);
39
- setPositioned(false);
40
- }, 100);
41
- }, []);
42
- const hideImmediately = useCallback(() => {
43
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
44
- if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
45
- setVisible(false);
46
- setPositioned(false);
47
- }, []);
48
- const calculatePosition = useCallback(() => {
49
- if (!triggerRef.current || !tooltipRef.current) return;
50
- const triggerRect = triggerRef.current.getBoundingClientRect();
51
- const tooltipRect = tooltipRef.current.getBoundingClientRect();
52
- const gap = 8;
53
- const viewportWidth = window.innerWidth;
54
- const viewportHeight = window.innerHeight;
55
- let top = 0;
56
- let left = 0;
57
- switch (placement) {
58
- case "top":
59
- top = triggerRect.top - tooltipRect.height - gap;
60
- left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
61
- break;
62
- case "bottom":
63
- top = triggerRect.bottom + gap;
64
- left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
65
- break;
66
- case "left":
67
- top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;
68
- left = triggerRect.left - tooltipRect.width - gap;
69
- break;
70
- case "right":
71
- top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;
72
- left = triggerRect.right + gap;
73
- break;
74
- }
75
- if (left < gap) left = gap;
76
- if (left + tooltipRect.width > viewportWidth - gap) {
77
- left = viewportWidth - tooltipRect.width - gap;
78
- }
79
- if (top < gap) top = gap;
80
- if (top + tooltipRect.height > viewportHeight - gap) {
81
- top = viewportHeight - tooltipRect.height - gap;
82
- }
83
- setPosition({ top, left });
84
- setPositioned(true);
85
- }, [placement]);
86
- useLayoutEffect(() => {
87
- if (visible && triggerRef.current && tooltipRef.current) {
88
- calculatePosition();
89
- }
90
- }, [visible, calculatePosition]);
91
- useEffect(() => {
92
- if (!visible) return;
93
- const handleScrollOrResize = () => {
94
- calculatePosition();
95
- };
96
- window.addEventListener("scroll", handleScrollOrResize, true);
97
- window.addEventListener("resize", handleScrollOrResize);
98
- return () => {
99
- window.removeEventListener("scroll", handleScrollOrResize, true);
100
- window.removeEventListener("resize", handleScrollOrResize);
101
- };
102
- }, [visible, calculatePosition]);
103
- useEffect(() => {
104
- if (!visible) return;
105
- const handleEscape = (e) => {
106
- if (e.key === "Escape") {
107
- hideImmediately();
108
- }
109
- };
110
- document.addEventListener("keydown", handleEscape);
111
- return () => document.removeEventListener("keydown", handleEscape);
112
- }, [visible, hideImmediately]);
113
- useEffect(() => {
114
- return () => {
115
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
116
- if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
117
- };
118
- }, []);
119
- return /* @__PURE__ */ jsxs(Fragment, { children: [
120
- /* @__PURE__ */ jsx(
121
- "div",
122
- {
123
- ref: triggerRef,
124
- className: classNames("zendir-tooltip-trigger", className),
125
- style: { display: "inline-flex", pointerEvents: "auto", maxWidth: "100%", width: "inherit" },
126
- onMouseEnter: showTooltip,
127
- onMouseLeave: hideTooltip,
128
- onFocus: showTooltip,
129
- onBlur: hideTooltip,
130
- children
131
- }
132
- ),
133
- visible && ReactDOM.createPortal(
134
- /* @__PURE__ */ jsxs(
135
- "div",
136
- {
137
- ref: tooltipRef,
138
- role: "tooltip",
139
- onMouseEnter: showTooltip,
140
- onMouseLeave: hideTooltip,
141
- style: {
142
- position: "fixed",
143
- top: positioned ? position.top : 0,
144
- left: positioned ? position.left : 0,
145
- width: "max-content",
146
- padding: `${tokens.spacing.sm} ${tokens.spacing.smd}`,
147
- backgroundColor: tokens.colors.background.elevated,
148
- color: tokens.colors.text.primary,
149
- fontSize: "0.75rem",
150
- fontWeight: 500,
151
- fontFamily: tokens.typography.fontFamily.primary,
152
- borderRadius: tokens.borderRadius.md,
153
- border: `1px solid ${tokens.colors.accent.primary}20`,
154
- boxShadow: positioned ? `${tokens.shadows.lg}, 0 0 20px ${tokens.colors.accent.primary}10` : "none",
155
- zIndex: 2147483100,
156
- maxWidth: "min(280px, calc(100vw - 24px))",
157
- whiteSpace: "normal",
158
- pointerEvents: "auto",
159
- visibility: positioned ? "visible" : "hidden",
160
- opacity: positioned ? 1 : 0,
161
- transition: positioned ? void 0 : "none",
162
- animation: positioned ? `zendir-tooltip ${tokens.animation.duration.fast}ms ${tokens.animation.easing.default} both` : "none",
163
- backdropFilter: "blur(8px)"
164
- },
165
- children: [
166
- content,
167
- /* @__PURE__ */ jsx("style", { children: `@keyframes zendir-tooltip { from { opacity: 0; transform: scale(0.95) translateY(${placement === "bottom" ? "-4px" : placement === "top" ? "4px" : "0"}); } to { opacity: 1; transform: scale(1) translateY(0); } }
168
- @media (prefers-reduced-motion: reduce) { @keyframes zendir-tooltip { from, to { opacity: 1; transform: none; } } }` })
169
- ]
170
- }
171
- ),
172
- document.body
173
- )
174
- ] });
3
+ import { memo, useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ import ReactDOM from "react-dom";
6
+ //#region src/react/core/overlays/Tooltip.tsx
7
+ /**
8
+ * @zendir/ui - Tooltip Component
9
+ *
10
+ * Tooltip following Astro UX Design System.
11
+ * Uses a portal to render in document.body, ensuring correct positioning
12
+ * even when the trigger is inside containers with CSS transforms or overflow.
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * <Tooltip content="Click to enable telemetry">
17
+ * <Button>Enable</Button>
18
+ * </Tooltip>
19
+ * ```
20
+ */
21
+ var Tooltip = memo(function Tooltip({ content, placement = "top", delay = 200, disabled = false, children, className = "" }) {
22
+ const { tokens } = useTheme();
23
+ const [visible, setVisible] = useState(false);
24
+ const [positioned, setPositioned] = useState(false);
25
+ const [position, setPosition] = useState({
26
+ top: 0,
27
+ left: 0
28
+ });
29
+ const triggerRef = useRef(null);
30
+ const tooltipRef = useRef(null);
31
+ const timeoutRef = useRef();
32
+ const hideTimeoutRef = useRef();
33
+ const showTooltip = useCallback(() => {
34
+ if (disabled) return;
35
+ if (hideTimeoutRef.current) {
36
+ clearTimeout(hideTimeoutRef.current);
37
+ hideTimeoutRef.current = void 0;
38
+ }
39
+ timeoutRef.current = window.setTimeout(() => {
40
+ setVisible(true);
41
+ setPositioned(false);
42
+ }, delay);
43
+ }, [disabled, delay]);
44
+ const hideTooltip = useCallback(() => {
45
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
46
+ hideTimeoutRef.current = window.setTimeout(() => {
47
+ setVisible(false);
48
+ setPositioned(false);
49
+ }, 100);
50
+ }, []);
51
+ const hideImmediately = useCallback(() => {
52
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
53
+ if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
54
+ setVisible(false);
55
+ setPositioned(false);
56
+ }, []);
57
+ const calculatePosition = useCallback(() => {
58
+ if (!triggerRef.current || !tooltipRef.current) return;
59
+ const triggerRect = triggerRef.current.getBoundingClientRect();
60
+ const tooltipRect = tooltipRef.current.getBoundingClientRect();
61
+ const gap = 8;
62
+ const viewportWidth = window.innerWidth;
63
+ const viewportHeight = window.innerHeight;
64
+ let top = 0;
65
+ let left = 0;
66
+ switch (placement) {
67
+ case "top":
68
+ top = triggerRect.top - tooltipRect.height - gap;
69
+ left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
70
+ break;
71
+ case "bottom":
72
+ top = triggerRect.bottom + gap;
73
+ left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
74
+ break;
75
+ case "left":
76
+ top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;
77
+ left = triggerRect.left - tooltipRect.width - gap;
78
+ break;
79
+ case "right":
80
+ top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;
81
+ left = triggerRect.right + gap;
82
+ break;
83
+ }
84
+ if (left < gap) left = gap;
85
+ if (left + tooltipRect.width > viewportWidth - gap) left = viewportWidth - tooltipRect.width - gap;
86
+ if (top < gap) top = gap;
87
+ if (top + tooltipRect.height > viewportHeight - gap) top = viewportHeight - tooltipRect.height - gap;
88
+ setPosition({
89
+ top,
90
+ left
91
+ });
92
+ setPositioned(true);
93
+ }, [placement]);
94
+ useLayoutEffect(() => {
95
+ if (visible && triggerRef.current && tooltipRef.current) calculatePosition();
96
+ }, [visible, calculatePosition]);
97
+ useEffect(() => {
98
+ if (!visible) return;
99
+ const handleScrollOrResize = () => {
100
+ calculatePosition();
101
+ };
102
+ window.addEventListener("scroll", handleScrollOrResize, true);
103
+ window.addEventListener("resize", handleScrollOrResize);
104
+ return () => {
105
+ window.removeEventListener("scroll", handleScrollOrResize, true);
106
+ window.removeEventListener("resize", handleScrollOrResize);
107
+ };
108
+ }, [visible, calculatePosition]);
109
+ useEffect(() => {
110
+ if (!visible) return;
111
+ const handleEscape = (e) => {
112
+ if (e.key === "Escape") hideImmediately();
113
+ };
114
+ document.addEventListener("keydown", handleEscape);
115
+ return () => document.removeEventListener("keydown", handleEscape);
116
+ }, [visible, hideImmediately]);
117
+ useEffect(() => {
118
+ return () => {
119
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
120
+ if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
121
+ };
122
+ }, []);
123
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
124
+ ref: triggerRef,
125
+ className: classNames("zendir-tooltip-trigger", className),
126
+ style: {
127
+ display: "inline-flex",
128
+ pointerEvents: "auto",
129
+ maxWidth: "100%",
130
+ width: "inherit"
131
+ },
132
+ onMouseEnter: showTooltip,
133
+ onMouseLeave: hideTooltip,
134
+ onFocus: showTooltip,
135
+ onBlur: hideTooltip,
136
+ children
137
+ }), visible && ReactDOM.createPortal(/* @__PURE__ */ jsxs("div", {
138
+ ref: tooltipRef,
139
+ role: "tooltip",
140
+ onMouseEnter: showTooltip,
141
+ onMouseLeave: hideTooltip,
142
+ style: {
143
+ position: "fixed",
144
+ top: positioned ? position.top : 0,
145
+ left: positioned ? position.left : 0,
146
+ width: "max-content",
147
+ padding: `${tokens.spacing.sm} ${tokens.spacing.smd}`,
148
+ backgroundColor: tokens.colors.background.elevated,
149
+ color: tokens.colors.text.primary,
150
+ fontSize: "0.75rem",
151
+ fontWeight: 500,
152
+ fontFamily: tokens.typography.fontFamily.primary,
153
+ borderRadius: tokens.borderRadius.md,
154
+ border: `1px solid ${tokens.colors.accent.primary}20`,
155
+ boxShadow: positioned ? `${tokens.shadows.lg}, 0 0 20px ${tokens.colors.accent.primary}10` : "none",
156
+ zIndex: 2147483100,
157
+ maxWidth: "min(280px, calc(100vw - 24px))",
158
+ whiteSpace: "normal",
159
+ pointerEvents: "auto",
160
+ visibility: positioned ? "visible" : "hidden",
161
+ opacity: positioned ? 1 : 0,
162
+ transition: positioned ? void 0 : "none",
163
+ animation: positioned ? `zendir-tooltip ${tokens.animation.duration.fast}ms ${tokens.animation.easing.default} both` : "none",
164
+ backdropFilter: "blur(8px)"
165
+ },
166
+ children: [content, /* @__PURE__ */ jsx("style", { children: `@keyframes zendir-tooltip { from { opacity: 0; transform: scale(0.95) translateY(${placement === "bottom" ? "-4px" : placement === "top" ? "4px" : "0"}); } to { opacity: 1; transform: scale(1) translateY(0); } }
167
+ @media (prefers-reduced-motion: reduce) { @keyframes zendir-tooltip { from, to { opacity: 1; transform: none; } } }` })]
168
+ }), document.body)] });
175
169
  });
176
- export {
177
- Tooltip
178
- };
179
- //# sourceMappingURL=Tooltip.js.map
170
+ //#endregion
171
+ export { Tooltip, Tooltip as default };
172
+
173
+ //# sourceMappingURL=Tooltip.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Tooltip.js","sources":["../../../../src/react/core/overlays/Tooltip.tsx"],"sourcesContent":["/**\n * @zendir/ui - Tooltip Component\n * \n * Tooltip following Astro UX Design System.\n * Uses a portal to render in document.body, ensuring correct positioning\n * even when the trigger is inside containers with CSS transforms or overflow.\n * \n * @example\n * ```tsx\n * <Tooltip content=\"Click to enable telemetry\">\n * <Button>Enable</Button>\n * </Tooltip>\n * ```\n */\n\nimport React, { memo, useState, useRef, useEffect, useLayoutEffect, useCallback } from 'react';\nimport ReactDOM from 'react-dom';\nimport { useTheme } from '../../theme';\nimport { classNames } from '../../utils';\n\nexport type TooltipPlacement = 'top' | 'bottom' | 'left' | 'right';\n\nexport interface TooltipProps {\n /** Tooltip content */\n content: React.ReactNode;\n /** Placement */\n placement?: TooltipPlacement;\n /** Delay before showing (ms) */\n delay?: number;\n /** Disabled state */\n disabled?: boolean;\n /** Children element to trigger tooltip */\n children: React.ReactElement;\n /** Custom className */\n className?: string;\n}\n\nexport const Tooltip = memo(function Tooltip({\n content,\n placement = 'top',\n delay = 200,\n disabled = false,\n children,\n className = '',\n}: TooltipProps): React.ReactElement {\n const { tokens } = useTheme();\n const [visible, setVisible] = useState(false);\n const [positioned, setPositioned] = useState(false);\n const [position, setPosition] = useState({ top: 0, left: 0 });\n const triggerRef = useRef<HTMLDivElement>(null);\n const tooltipRef = useRef<HTMLDivElement>(null);\n const timeoutRef = useRef<number>();\n const hideTimeoutRef = useRef<number>();\n \n const showTooltip = useCallback(() => {\n if (disabled) return;\n // Cancel any pending hide so moving between trigger ↔ tooltip keeps it open\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = undefined;\n }\n timeoutRef.current = window.setTimeout(() => {\n setVisible(true);\n setPositioned(false);\n }, delay);\n }, [disabled, delay]);\n \n const hideTooltip = useCallback(() => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n // Small delay so user can move pointer from trigger to tooltip (WCAG 1.4.13)\n hideTimeoutRef.current = window.setTimeout(() => {\n setVisible(false);\n setPositioned(false);\n }, 100);\n }, []);\n \n const hideImmediately = useCallback(() => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);\n setVisible(false);\n setPositioned(false);\n }, []);\n \n const calculatePosition = useCallback(() => {\n if (!triggerRef.current || !tooltipRef.current) return;\n \n const triggerRect = triggerRef.current.getBoundingClientRect();\n const tooltipRect = tooltipRef.current.getBoundingClientRect();\n const gap = 8;\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n \n let top = 0;\n let left = 0;\n \n switch (placement) {\n case 'top':\n top = triggerRect.top - tooltipRect.height - gap;\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\n break;\n case 'bottom':\n top = triggerRect.bottom + gap;\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\n break;\n case 'left':\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\n left = triggerRect.left - tooltipRect.width - gap;\n break;\n case 'right':\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\n left = triggerRect.right + gap;\n break;\n }\n \n // Keep tooltip within viewport bounds\n if (left < gap) left = gap;\n if (left + tooltipRect.width > viewportWidth - gap) {\n left = viewportWidth - tooltipRect.width - gap;\n }\n if (top < gap) top = gap;\n if (top + tooltipRect.height > viewportHeight - gap) {\n top = viewportHeight - tooltipRect.height - gap;\n }\n \n setPosition({ top, left });\n setPositioned(true);\n }, [placement]);\n \n // Use useLayoutEffect for initial positioning - runs synchronously\n // before browser paint, preventing flash at wrong position\n useLayoutEffect(() => {\n if (visible && triggerRef.current && tooltipRef.current) {\n calculatePosition();\n }\n }, [visible, calculatePosition]);\n \n // Use useEffect for scroll/resize listeners\n useEffect(() => {\n if (!visible) return;\n \n const handleScrollOrResize = () => {\n calculatePosition();\n };\n \n window.addEventListener('scroll', handleScrollOrResize, true);\n window.addEventListener('resize', handleScrollOrResize);\n \n return () => {\n window.removeEventListener('scroll', handleScrollOrResize, true);\n window.removeEventListener('resize', handleScrollOrResize);\n };\n }, [visible, calculatePosition]);\n \n // Escape key dismisses tooltip (WCAG 1.4.13 Content on Hover or Focus)\n useEffect(() => {\n if (!visible) return;\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n hideImmediately();\n }\n };\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }, [visible, hideImmediately]);\n \n useEffect(() => {\n return () => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);\n };\n }, []);\n \n return (\n <>\n <div\n ref={triggerRef}\n className={classNames('zendir-tooltip-trigger', className)}\n style={{ display: 'inline-flex', pointerEvents: 'auto', maxWidth: '100%', width: 'inherit' }}\n onMouseEnter={showTooltip}\n onMouseLeave={hideTooltip}\n onFocus={showTooltip}\n onBlur={hideTooltip}\n >\n {children}\n </div>\n \n {visible && ReactDOM.createPortal(\n <div\n ref={tooltipRef}\n role=\"tooltip\"\n onMouseEnter={showTooltip}\n onMouseLeave={hideTooltip}\n style={{\n position: 'fixed',\n top: positioned ? position.top : 0,\n left: positioned ? position.left : 0,\n width: 'max-content',\n padding: `${tokens.spacing.sm} ${tokens.spacing.smd}`,\n backgroundColor: tokens.colors.background.elevated,\n color: tokens.colors.text.primary,\n fontSize: '0.75rem',\n fontWeight: 500,\n fontFamily: tokens.typography.fontFamily.primary,\n borderRadius: tokens.borderRadius.md,\n border: `1px solid ${tokens.colors.accent.primary}20`,\n boxShadow: positioned ? `${tokens.shadows.lg}, 0 0 20px ${tokens.colors.accent.primary}10` : 'none',\n zIndex: 2147483100,\n maxWidth: 'min(280px, calc(100vw - 24px))',\n whiteSpace: 'normal',\n pointerEvents: 'auto',\n visibility: positioned ? 'visible' : 'hidden',\n opacity: positioned ? 1 : 0,\n transition: positioned ? undefined : 'none',\n animation: positioned ? `zendir-tooltip ${tokens.animation.duration.fast}ms ${tokens.animation.easing.default} both` : 'none',\n backdropFilter: 'blur(8px)',\n }}\n >\n {content}\n <style>\n {`@keyframes zendir-tooltip { from { opacity: 0; transform: scale(0.95) translateY(${placement === 'bottom' ? '-4px' : placement === 'top' ? '4px' : '0'}); } to { opacity: 1; transform: scale(1) translateY(0); } }\n @media (prefers-reduced-motion: reduce) { @keyframes zendir-tooltip { from, to { opacity: 1; transform: none; } } }`}\n </style>\n </div>,\n document.body\n )}\n </>\n );\n});\n\nexport default Tooltip;\n"],"names":["Tooltip"],"mappings":"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"}
1
+ {"version":3,"file":"Tooltip.js","names":[],"sources":["../../../../src/react/core/overlays/Tooltip.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - Tooltip Component\r\n *\r\n * Tooltip following Astro UX Design System.\r\n * Uses a portal to render in document.body, ensuring correct positioning\r\n * even when the trigger is inside containers with CSS transforms or overflow.\r\n *\r\n * @example\r\n * ```tsx\r\n * <Tooltip content=\"Click to enable telemetry\">\r\n * <Button>Enable</Button>\r\n * </Tooltip>\r\n * ```\r\n */\r\n\r\nimport React, {\r\n memo,\r\n useState,\r\n useRef,\r\n useEffect,\r\n useLayoutEffect,\r\n useCallback,\r\n} from \"react\";\r\nimport ReactDOM from \"react-dom\";\r\nimport { useTheme } from \"../../theme\";\r\nimport { classNames } from \"../../utils\";\r\n\r\nexport type TooltipPlacement = \"top\" | \"bottom\" | \"left\" | \"right\";\r\n\r\nexport interface TooltipProps {\r\n /** Tooltip content */\r\n content: React.ReactNode;\r\n /** Placement */\r\n placement?: TooltipPlacement;\r\n /** Delay before showing (ms) */\r\n delay?: number;\r\n /** Disabled state */\r\n disabled?: boolean;\r\n /** Children element to trigger tooltip */\r\n children: React.ReactElement;\r\n /** Custom className */\r\n className?: string;\r\n}\r\n\r\nexport const Tooltip = memo(function Tooltip({\r\n content,\r\n placement = \"top\",\r\n delay = 200,\r\n disabled = false,\r\n children,\r\n className = \"\",\r\n}: TooltipProps): React.ReactElement {\r\n const { tokens } = useTheme();\r\n const [visible, setVisible] = useState(false);\r\n const [positioned, setPositioned] = useState(false);\r\n const [position, setPosition] = useState({ top: 0, left: 0 });\r\n const triggerRef = useRef<HTMLDivElement>(null);\r\n const tooltipRef = useRef<HTMLDivElement>(null);\r\n const timeoutRef = useRef<number>();\r\n const hideTimeoutRef = useRef<number>();\r\n\r\n const showTooltip = useCallback(() => {\r\n if (disabled) return;\r\n // Cancel any pending hide so moving between trigger ↔ tooltip keeps it open\r\n if (hideTimeoutRef.current) {\r\n clearTimeout(hideTimeoutRef.current);\r\n hideTimeoutRef.current = undefined;\r\n }\r\n timeoutRef.current = window.setTimeout(() => {\r\n setVisible(true);\r\n setPositioned(false);\r\n }, delay);\r\n }, [disabled, delay]);\r\n\r\n const hideTooltip = useCallback(() => {\r\n if (timeoutRef.current) {\r\n clearTimeout(timeoutRef.current);\r\n }\r\n // Small delay so user can move pointer from trigger to tooltip (WCAG 1.4.13)\r\n hideTimeoutRef.current = window.setTimeout(() => {\r\n setVisible(false);\r\n setPositioned(false);\r\n }, 100);\r\n }, []);\r\n\r\n const hideImmediately = useCallback(() => {\r\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\r\n if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);\r\n setVisible(false);\r\n setPositioned(false);\r\n }, []);\r\n\r\n const calculatePosition = useCallback(() => {\r\n if (!triggerRef.current || !tooltipRef.current) return;\r\n\r\n const triggerRect = triggerRef.current.getBoundingClientRect();\r\n const tooltipRect = tooltipRef.current.getBoundingClientRect();\r\n const gap = 8;\r\n const viewportWidth = window.innerWidth;\r\n const viewportHeight = window.innerHeight;\r\n\r\n let top = 0;\r\n let left = 0;\r\n\r\n switch (placement) {\r\n case \"top\":\r\n top = triggerRect.top - tooltipRect.height - gap;\r\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\r\n break;\r\n case \"bottom\":\r\n top = triggerRect.bottom + gap;\r\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\r\n break;\r\n case \"left\":\r\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\r\n left = triggerRect.left - tooltipRect.width - gap;\r\n break;\r\n case \"right\":\r\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\r\n left = triggerRect.right + gap;\r\n break;\r\n }\r\n\r\n // Keep tooltip within viewport bounds\r\n if (left < gap) left = gap;\r\n if (left + tooltipRect.width > viewportWidth - gap) {\r\n left = viewportWidth - tooltipRect.width - gap;\r\n }\r\n if (top < gap) top = gap;\r\n if (top + tooltipRect.height > viewportHeight - gap) {\r\n top = viewportHeight - tooltipRect.height - gap;\r\n }\r\n\r\n setPosition({ top, left });\r\n setPositioned(true);\r\n }, [placement]);\r\n\r\n // Use useLayoutEffect for initial positioning - runs synchronously\r\n // before browser paint, preventing flash at wrong position\r\n useLayoutEffect(() => {\r\n if (visible && triggerRef.current && tooltipRef.current) {\r\n calculatePosition();\r\n }\r\n }, [visible, calculatePosition]);\r\n\r\n // Use useEffect for scroll/resize listeners\r\n useEffect(() => {\r\n if (!visible) return;\r\n\r\n const handleScrollOrResize = () => {\r\n calculatePosition();\r\n };\r\n\r\n window.addEventListener(\"scroll\", handleScrollOrResize, true);\r\n window.addEventListener(\"resize\", handleScrollOrResize);\r\n\r\n return () => {\r\n window.removeEventListener(\"scroll\", handleScrollOrResize, true);\r\n window.removeEventListener(\"resize\", handleScrollOrResize);\r\n };\r\n }, [visible, calculatePosition]);\r\n\r\n // Escape key dismisses tooltip (WCAG 1.4.13 Content on Hover or Focus)\r\n useEffect(() => {\r\n if (!visible) return;\r\n const handleEscape = (e: KeyboardEvent) => {\r\n if (e.key === \"Escape\") {\r\n hideImmediately();\r\n }\r\n };\r\n document.addEventListener(\"keydown\", handleEscape);\r\n return () => document.removeEventListener(\"keydown\", handleEscape);\r\n }, [visible, hideImmediately]);\r\n\r\n useEffect(() => {\r\n return () => {\r\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\r\n if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);\r\n };\r\n }, []);\r\n\r\n return (\r\n <>\r\n <div\r\n ref={triggerRef}\r\n className={classNames(\"zendir-tooltip-trigger\", className)}\r\n style={{\r\n display: \"inline-flex\",\r\n pointerEvents: \"auto\",\r\n maxWidth: \"100%\",\r\n width: \"inherit\",\r\n }}\r\n onMouseEnter={showTooltip}\r\n onMouseLeave={hideTooltip}\r\n onFocus={showTooltip}\r\n onBlur={hideTooltip}\r\n >\r\n {children}\r\n </div>\r\n\r\n {visible &&\r\n ReactDOM.createPortal(\r\n <div\r\n ref={tooltipRef}\r\n role=\"tooltip\"\r\n onMouseEnter={showTooltip}\r\n onMouseLeave={hideTooltip}\r\n style={{\r\n position: \"fixed\",\r\n top: positioned ? position.top : 0,\r\n left: positioned ? position.left : 0,\r\n width: \"max-content\",\r\n padding: `${tokens.spacing.sm} ${tokens.spacing.smd}`,\r\n backgroundColor: tokens.colors.background.elevated,\r\n color: tokens.colors.text.primary,\r\n fontSize: \"0.75rem\",\r\n fontWeight: 500,\r\n fontFamily: tokens.typography.fontFamily.primary,\r\n borderRadius: tokens.borderRadius.md,\r\n border: `1px solid ${tokens.colors.accent.primary}20`,\r\n boxShadow: positioned\r\n ? `${tokens.shadows.lg}, 0 0 20px ${tokens.colors.accent.primary}10`\r\n : \"none\",\r\n zIndex: 2147483100,\r\n maxWidth: \"min(280px, calc(100vw - 24px))\",\r\n whiteSpace: \"normal\",\r\n pointerEvents: \"auto\",\r\n visibility: positioned ? \"visible\" : \"hidden\",\r\n opacity: positioned ? 1 : 0,\r\n transition: positioned ? undefined : \"none\",\r\n animation: positioned\r\n ? `zendir-tooltip ${tokens.animation.duration.fast}ms ${tokens.animation.easing.default} both`\r\n : \"none\",\r\n backdropFilter: \"blur(8px)\",\r\n }}\r\n >\r\n {content}\r\n <style>\r\n {`@keyframes zendir-tooltip { from { opacity: 0; transform: scale(0.95) translateY(${placement === \"bottom\" ? \"-4px\" : placement === \"top\" ? \"4px\" : \"0\"}); } to { opacity: 1; transform: scale(1) translateY(0); } }\r\n @media (prefers-reduced-motion: reduce) { @keyframes zendir-tooltip { from, to { opacity: 1; transform: none; } } }`}\r\n </style>\r\n </div>,\r\n document.body,\r\n )}\r\n </>\r\n );\r\n});\r\n\r\nexport default Tooltip;\r\n"],"mappings":"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"}
@@ -1,6 +1,5 @@
1
1
  import { default as React } from 'react';
2
2
  import { CalendarEvent, CalendarTimeline, ActivityType } from './MissionCalendar';
3
-
4
3
  export interface ActivityFormData {
5
4
  title: string;
6
5
  type: ActivityType;