@zendir/ui 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (391) hide show
  1. package/CHANGELOG.md +34 -0
  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 -538
  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 +11 -5
  229. package/dist/react/core/navigation/SideNav.js +857 -602
  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 +312 -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 +217 -194
  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 +419 -41
  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,728 +1,65 @@
1
- import { jsxs, jsx } from "react/jsx-runtime";
2
- import { useState, useEffect, useMemo, useContext, createContext } from "react";
3
- import { typography, borderRadius, spacing } from "../../tokens/index.js";
1
+ import { astroThemeDark, astroThemeLight, hybridTheme, nebulaTheme, purpleHueTheme, transparentMinimalTheme, transparentTheme } from "../../tokens/themes.js";
2
+ import { computeBorderTokens } from "./types.js";
3
+ import { createContext, useContext, useEffect, useMemo, useState } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/react/theme/ThemeProvider.tsx
6
+ /**
7
+ * @zendir/ui - Theme Provider
8
+ *
9
+ * Enterprise-grade theming system supporting Astro UX Design System and Zendir themes.
10
+ * Full Tier 3 compliance with official Astro tokens (dark + light themes).
11
+ *
12
+ * Features:
13
+ * - Multiple theme variants (Zen Hybrid default, astro, purple-hue, transparent)
14
+ * - Light and dark modes
15
+ * - Animation tokens with reduced-motion support
16
+ * - Focus ring styles for accessibility
17
+ * - CSS variable injection
18
+ * - Local storage persistence
19
+ */
4
20
  function adjustHexBrightness(hex, factor) {
5
- const normalized = hex.replace("#", "").trim();
6
- const expanded = normalized.length === 3 ? normalized.split("").map((ch) => ch + ch).join("") : normalized;
7
- if (!/^[0-9a-fA-F]{6}$/.test(expanded)) {
8
- return hex;
9
- }
10
- const clamp = (value) => Math.max(0, Math.min(255, Math.round(value)));
11
- const r = clamp(parseInt(expanded.slice(0, 2), 16) * factor);
12
- const g = clamp(parseInt(expanded.slice(2, 4), 16) * factor);
13
- const b = clamp(parseInt(expanded.slice(4, 6), 16) * factor);
14
- const toHex = (value) => value.toString(16).padStart(2, "0");
15
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
16
- }
17
- function computeBorderTokens(colors) {
18
- const thin = "1px";
19
- const medium = "1.5px";
20
- const thick = "2px";
21
- const accent = colors.accent.primary;
22
- const muted = colors.border.muted;
23
- const critical = colors.status.critical;
24
- const bgBase = colors.background.base;
25
- return {
26
- width: { thin, medium, thick },
27
- input: {
28
- default: `${thin} solid ${muted}`,
29
- hover: `${thin} solid ${accent}80`,
30
- focus: `${thin} solid ${accent}`,
31
- error: `${thin} solid ${critical}`
32
- },
33
- focusRing: {
34
- // WCAG 2.4.13: focus indicators ≥ 3:1 contrast — raised from 20%/30% to 50%/60%
35
- default: `0 0 0 3px ${accent}50, 0 0 20px ${accent}15`,
36
- button: `0 0 0 2px ${bgBase}, 0 0 0 4px ${accent}`,
37
- subtle: `0 0 0 2px ${accent}60`
38
- },
39
- divider: `${thin} solid ${muted}`,
40
- dropdown: `${thin} solid ${accent}30`,
41
- separator: `${thin} solid ${muted}`
42
- };
21
+ const normalized = hex.replace("#", "").trim();
22
+ const expanded = normalized.length === 3 ? normalized.split("").map((ch) => ch + ch).join("") : normalized;
23
+ if (!/^[0-9a-fA-F]{6}$/.test(expanded)) return hex;
24
+ const clamp = (value) => Math.max(0, Math.min(255, Math.round(value)));
25
+ const r = clamp(parseInt(expanded.slice(0, 2), 16) * factor);
26
+ const g = clamp(parseInt(expanded.slice(2, 4), 16) * factor);
27
+ const b = clamp(parseInt(expanded.slice(4, 6), 16) * factor);
28
+ const toHex = (value) => value.toString(16).padStart(2, "0");
29
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
43
30
  }
44
- const animationTokens = {
45
- fast: "all 150ms cubic-bezier(0.4, 0, 0.2, 1)",
46
- normal: "all 250ms cubic-bezier(0.4, 0, 0.2, 1)",
47
- slow: "all 400ms cubic-bezier(0.4, 0, 0.2, 1)",
48
- spring: "all 300ms cubic-bezier(0.34, 1.56, 0.64, 1)",
49
- easing: {
50
- default: "cubic-bezier(0.4, 0, 0.2, 1)",
51
- in: "ease-in",
52
- out: "ease-out",
53
- inOut: "ease-in-out"
54
- },
55
- duration: {
56
- instant: 0,
57
- fast: 150,
58
- normal: 250,
59
- slow: 400
60
- }
61
- };
62
- const animationTokensReduced = {
63
- fast: "all 0.01ms linear",
64
- normal: "all 0.01ms linear",
65
- slow: "all 0.01ms linear",
66
- spring: "all 0.01ms linear",
67
- easing: animationTokens.easing,
68
- duration: { instant: 0, fast: 0, normal: 0, slow: 0 }
69
- };
70
- const focusTokensDark = {
71
- color: "#4dacff",
72
- width: "2px",
73
- offset: "2px",
74
- ring: "0 0 0 2px #4dacff",
75
- style: {
76
- outline: "2px solid #4dacff",
77
- outlineOffset: "2px"
78
- }
79
- };
80
- const focusTokensLight = {
81
- color: "#0066cc",
82
- width: "2px",
83
- offset: "2px",
84
- ring: "0 0 0 2px #0066cc",
85
- style: {
86
- outline: "2px solid #0066cc",
87
- outlineOffset: "2px"
88
- }
89
- };
90
- const shadowsDark = {
91
- none: "none",
92
- sm: "0 1px 2px rgba(0, 0, 0, 0.3)",
93
- md: "0 4px 8px rgba(0, 0, 0, 0.4)",
94
- lg: "0 8px 16px rgba(0, 0, 0, 0.5)",
95
- xl: "0 16px 32px rgba(0, 0, 0, 0.6)",
96
- glow: (color) => `0 0 20px ${color}40, 0 0 40px ${color}20`
97
- };
98
- const shadowsLight = {
99
- none: "none",
100
- sm: "0 1px 2px rgba(0, 0, 0, 0.1)",
101
- md: "0 4px 8px rgba(0, 0, 0, 0.15)",
102
- lg: "0 8px 16px rgba(0, 0, 0, 0.2)",
103
- xl: "0 16px 32px rgba(0, 0, 0, 0.25)",
104
- glow: (color) => `0 0 20px ${color}30, 0 0 40px ${color}15`
105
- };
106
- const layoutTokens = {
107
- card: {
108
- padding: "16px",
109
- // 4 × 4px
110
- gap: "24px",
111
- // 6 × 4px — desktop grid gap (matches outer padding)
112
- gapCompact: "16px",
113
- // 4 × 4px — mobile grid gap
114
- heading: {
115
- iconSize: 18,
116
- // default card header icon (px) — matches ISS/Telemetry card header size
117
- iconSizeCompact: 16,
118
- // compact (e.g. chart inline header)
119
- titleFontSize: "1rem",
120
- // card titles (ISS, Telemetry, Mission) — reduced from 1.125rem
121
- titleFontSizeChart: "0.875rem",
122
- // chart titles (Power Trends) — slightly smaller
123
- titleFontWeight: 500,
124
- gap: 8
125
- // gap between icon and title (px)
126
- }
127
- },
128
- section: {
129
- headerPaddingBottom: "8px",
130
- // 2 × 4px
131
- headerMarginBottom: "0px",
132
- contentPaddingTop: "8px"
133
- // 2 × 4px
134
- },
135
- form: {
136
- fieldGap: "12px",
137
- // 3 × 4px — between stacked fields
138
- inlineGap: "12px",
139
- // 3 × 4px — between side-by-side fields
140
- groupPadding: "12px",
141
- // 3 × 4px — inside grouped containers
142
- groupGap: "12px",
143
- // 3 × 4px — within group items
144
- labelGap: "3px"
145
- // label text ↔ tooltip icon
146
- },
147
- surface: {
148
- padding: "12px",
149
- // 3 × 4px
150
- borderRadius: "12px",
151
- // 3 × 4px
152
- gap: "8px"
153
- // 2 × 4px
154
- }
155
- };
156
- const astroThemeDark = {
157
- colors: {
158
- background: {
159
- base: "#101923",
160
- surface: "#1b2d3e",
161
- elevated: "#243b53",
162
- overlay: "rgba(16, 25, 35, 0.95)"
163
- },
164
- border: {
165
- default: "#2b659b",
166
- muted: "#172635",
167
- focus: "#4dacff"
168
- },
169
- text: {
170
- primary: "#ffffff",
171
- secondary: "#b7c5d3",
172
- tertiary: "#8fa4b7",
173
- muted: "#8fa4b7",
174
- inverse: "#1b2d3e"
175
- },
176
- status: {
177
- normal: "#56f000",
178
- standby: "#2dccff",
179
- caution: "#fce83a",
180
- serious: "#ffb302",
181
- critical: "#ff3838",
182
- off: "#a4abb6"
183
- },
184
- semantic: {
185
- success: "#56f000",
186
- warning: "#fce83a",
187
- error: "#ff3838",
188
- info: "#4dacff"
189
- },
190
- accent: {
191
- primary: "#4dacff",
192
- secondary: "#56f000",
193
- tertiary: "#a371f7"
194
- },
195
- interactive: {
196
- default: "#4dacff",
197
- hover: "#92cbff",
198
- active: "#0066cc",
199
- disabled: "#6b7280"
200
- }
201
- },
202
- // spacing + borderRadius are sourced from tokens/index.ts (single source
203
- // of truth — see comment at the top of this file).
204
- spacing: { ...spacing },
205
- borderRadius: { ...borderRadius },
206
- elementSize: {
207
- sm: "28px",
208
- md: "36px",
209
- lg: "44px"
210
- },
211
- typography: {
212
- /**
213
- * Font families — sourced from src/tokens/index.ts. Canonical stacks:
214
- * primary: Public Sans → Roboto → system
215
- * heading: Sora → Roboto → system
216
- * mono: Roboto Mono → system mono
217
- * @see https://www.astrouxds.com/foundations/typography/
218
- */
219
- fontFamily: { ...typography.fontFamily },
220
- // Astro UX Display Styles
221
- // https://www.astrouxds.com/foundations/typography/
222
- display: {
223
- 1: { fontSize: "3.75rem", fontWeight: 300, letterSpacing: "-0.5px", lineHeight: "4.375rem" },
224
- 2: { fontSize: "3rem", fontWeight: 400, letterSpacing: "0", lineHeight: "3.5rem" }
225
- },
226
- // Astro UX Heading Styles
227
- heading: {
228
- 1: { fontSize: "2.125rem", fontWeight: 400, letterSpacing: "0.25px", lineHeight: "2.5rem" },
229
- "1Bold": { fontSize: "2.125rem", fontWeight: 700, letterSpacing: "0.25px", lineHeight: "2rem" },
230
- 2: { fontSize: "1.5rem", fontWeight: 400, letterSpacing: "0", lineHeight: "1.75rem" },
231
- 3: { fontSize: "1.25rem", fontWeight: 500, letterSpacing: "0.15px", lineHeight: "1.5rem" },
232
- 4: { fontSize: "1.25rem", fontWeight: 300, letterSpacing: "0.15px", lineHeight: "1.5rem" },
233
- 5: { fontSize: "1.125rem", fontWeight: 400, letterSpacing: "0", lineHeight: "1.5rem" },
234
- 6: { fontSize: "1.125rem", fontWeight: 300, letterSpacing: "0", lineHeight: "1.5rem" }
235
- },
236
- // Astro UX Body Styles
237
- body: {
238
- 1: { fontSize: "1rem", fontWeight: 400, letterSpacing: "0.5px", lineHeight: "1.5rem" },
239
- "1Bold": { fontSize: "1rem", fontWeight: 700, letterSpacing: "0.5px", lineHeight: "1.5rem" },
240
- 2: { fontSize: "0.875rem", fontWeight: 400, letterSpacing: "0.5px", lineHeight: "1.25rem" },
241
- "2Bold": { fontSize: "0.875rem", fontWeight: 700, letterSpacing: "0.5px", lineHeight: "1.25rem" },
242
- 3: { fontSize: "0.75rem", fontWeight: 400, letterSpacing: "0", lineHeight: "1rem" },
243
- "3Bold": { fontSize: "0.75rem", fontWeight: 700, letterSpacing: "0", lineHeight: "1rem" }
244
- },
245
- // Astro UX Control Body Styles
246
- control: {
247
- 1: { fontSize: "1rem", fontWeight: 400, letterSpacing: "0.5px", lineHeight: "1.25rem" },
248
- "1Bold": { fontSize: "1rem", fontWeight: 700, letterSpacing: "0.5px", lineHeight: "1.25rem" }
249
- },
250
- // Convenience numeric scale — sourced from tokens/index.ts. Prefer the
251
- // semantically-named display/heading/body/control style objects above
252
- // for new code; this scale is kept for the ~300 existing components
253
- // that consume `tokens.typography.fontSize.*` directly.
254
- fontSize: { ...typography.fontSize },
255
- /**
256
- * Font weights per AstroUXDS specification
257
- * Only 300, 400, 500, 700 are officially supported
258
- * @see https://www.astrouxds.com/foundations/typography/
259
- */
260
- fontWeight: {
261
- light: 300,
262
- normal: 400,
263
- medium: 500,
264
- /** @deprecated Use medium (500) instead - Astro spec only supports 300, 400, 500, 700 */
265
- semibold: 500,
266
- // Changed from 600 to 500 for Astro compliance
267
- bold: 700
268
- },
269
- lineHeight: {
270
- tight: "1.25rem",
271
- normal: "1.5rem",
272
- relaxed: "1.75rem"
273
- },
274
- letterSpacing: {
275
- tight: "-0.5px",
276
- normal: "0",
277
- wide: "0.5px"
278
- }
279
- },
280
- shadows: shadowsDark,
281
- animation: animationTokens,
282
- focus: focusTokensDark,
283
- layout: layoutTokens
284
- };
285
- const astroThemeLight = {
286
- colors: {
287
- background: {
288
- base: "#eaeef4",
289
- surface: "#f5f8fc",
290
- elevated: "#ffffff",
291
- overlay: "rgba(234, 238, 244, 0.95)"
292
- },
293
- border: {
294
- default: "#2b659b",
295
- muted: "#d1d5db",
296
- focus: "#0066cc"
297
- },
298
- text: {
299
- primary: "#1b2d3e",
300
- secondary: "#51667c",
301
- tertiary: "#556a7c",
302
- // WCAG AA: 4.81:1 on #eaeef4, 5.24:1 on #f5f8fc, 5.61:1 on #fff (was #8fa4b7 → 2.25:1 FAIL)
303
- muted: "#556a7c",
304
- // WCAG AA compliant (was #8fa4b7)
305
- inverse: "#ffffff"
306
- },
307
- status: {
308
- normal: "#56f000",
309
- standby: "#2dccff",
310
- caution: "#fce83a",
311
- serious: "#ffb302",
312
- critical: "#ff3838",
313
- off: "#a4abb6"
314
- },
315
- semantic: {
316
- success: "#56f000",
317
- warning: "#fce83a",
318
- error: "#ff3838",
319
- info: "#4dacff"
320
- },
321
- accent: {
322
- primary: "#0066cc",
323
- secondary: "#56f000",
324
- tertiary: "#7c3aed"
325
- },
326
- interactive: {
327
- default: "#0066cc",
328
- hover: "#0052a3",
329
- active: "#003d7a",
330
- disabled: "#a4abb6"
331
- }
332
- },
333
- spacing: astroThemeDark.spacing,
334
- borderRadius: astroThemeDark.borderRadius,
335
- elementSize: astroThemeDark.elementSize,
336
- typography: astroThemeDark.typography,
337
- shadows: shadowsLight,
338
- animation: animationTokens,
339
- focus: focusTokensLight,
340
- layout: layoutTokens
341
- };
342
- const focusTokensPurpleHue = {
343
- color: "#8b5cf6",
344
- width: "2px",
345
- offset: "2px",
346
- ring: "0 0 0 2px #8b5cf6",
347
- style: {
348
- outline: "2px solid #8b5cf6",
349
- outlineOffset: "2px"
350
- }
351
- };
352
- const hybridTheme = {
353
- colors: {
354
- background: {
355
- base: "#09090b",
356
- surface: "rgba(24, 24, 27, 0.98)",
357
- elevated: "rgba(39, 39, 42, 0.98)",
358
- overlay: "rgba(0, 0, 0, 0.85)"
359
- },
360
- border: {
361
- default: "rgba(139, 92, 246, 0.3)",
362
- // Purple tint
363
- muted: "rgba(63, 63, 70, 0.5)",
364
- focus: "#8b5cf6"
365
- // Zendir purple
366
- },
367
- text: {
368
- primary: "#ffffff",
369
- secondary: "#a1a1aa",
370
- tertiary: "#8e8e96",
371
- // WCAG AA: 6.12:1 on #09090b, 5.45:1 on #18181b, 4.58:1 on #27272a (was #71717a → 4.07:1 FAIL)
372
- muted: "#8e8e96",
373
- // WCAG AA compliant (was #71717a)
374
- inverse: "#09090b"
375
- },
376
- // Astro UXD Status Colors (unchanged for compliance)
377
- status: {
378
- normal: "#56f000",
379
- standby: "#2dccff",
380
- caution: "#fce83a",
381
- serious: "#ffb302",
382
- critical: "#ff3838",
383
- off: "#a4abb6"
384
- },
385
- semantic: {
386
- success: "#56f000",
387
- warning: "#fce83a",
388
- error: "#ff3838",
389
- info: "#8b5cf6"
390
- // Purple for info
391
- },
392
- // Zendir Purple Accent Palette
393
- accent: {
394
- primary: "#8b5cf6",
395
- // Vibrant purple
396
- secondary: "#a78bfa",
397
- // Light purple
398
- tertiary: "#7c3aed"
399
- // Deep purple
400
- },
401
- interactive: {
402
- default: "#8b5cf6",
403
- hover: "#a78bfa",
404
- active: "#7c3aed",
405
- disabled: "#52525b"
406
- }
407
- },
408
- spacing: astroThemeDark.spacing,
409
- borderRadius: {
410
- none: "0",
411
- xs: "2px",
412
- sm: "4px",
413
- md: "6px",
414
- lg: "10px",
415
- xl: "14px",
416
- full: "9999px"
417
- },
418
- elementSize: astroThemeDark.elementSize,
419
- typography: astroThemeDark.typography,
420
- shadows: {
421
- ...shadowsDark,
422
- glow: (color) => `0 0 20px ${color}50, 0 0 40px ${color}25, 0 4px 12px ${color}20`
423
- },
424
- animation: animationTokens,
425
- focus: focusTokensPurpleHue,
426
- layout: layoutTokens
427
- };
428
- const purpleHueTheme = {
429
- colors: {
430
- background: {
431
- base: "#0a0a0f",
432
- surface: "rgba(18, 18, 28, 0.98)",
433
- elevated: "rgba(28, 28, 42, 0.98)",
434
- overlay: "rgba(0, 0, 0, 0.9)"
435
- },
436
- border: {
437
- default: "rgba(139, 92, 246, 0.25)",
438
- muted: "rgba(55, 48, 82, 0.5)",
439
- focus: "#8b5cf6"
440
- },
441
- text: {
442
- primary: "#fafafa",
443
- secondary: "#a1a1aa",
444
- tertiary: "#8e8e96",
445
- // WCAG AA: 6.08:1 on #0a0a0f, 5.02:1 on elevated (was #71717a → 4.05:1 FAIL)
446
- muted: "#8e8e96",
447
- // WCAG AA compliant (was #71717a)
448
- inverse: "#0a0a0f"
449
- },
450
- // Astro UXD Status Colors (for compliance)
451
- status: {
452
- normal: "#56f000",
453
- standby: "#2dccff",
454
- caution: "#fce83a",
455
- serious: "#ffb302",
456
- critical: "#ff3838",
457
- off: "#a4abb6"
458
- },
459
- semantic: {
460
- success: "#56f000",
461
- warning: "#fce83a",
462
- error: "#ff3838",
463
- info: "#a78bfa"
464
- },
465
- // Zendir Purple Accent Palette
466
- accent: {
467
- primary: "#8b5cf6",
468
- // Vibrant purple
469
- secondary: "#a78bfa",
470
- // Light purple
471
- tertiary: "#7c3aed"
472
- // Deep purple
473
- },
474
- interactive: {
475
- default: "#8b5cf6",
476
- hover: "#a78bfa",
477
- active: "#7c3aed",
478
- disabled: "#52525b"
479
- }
480
- },
481
- spacing: astroThemeDark.spacing,
482
- borderRadius: {
483
- none: "0",
484
- xs: "2px",
485
- sm: "4px",
486
- md: "6px",
487
- lg: "10px",
488
- xl: "14px",
489
- full: "9999px"
490
- },
491
- elementSize: astroThemeDark.elementSize,
492
- // Same typography as hybrid (Astro UX font stack with full fallbacks) for consistent card font across themes
493
- typography: astroThemeDark.typography,
494
- shadows: {
495
- ...shadowsDark,
496
- glow: (color) => `0 0 25px ${color}60, 0 0 50px ${color}30, 0 4px 16px ${color}25`
497
- },
498
- animation: animationTokens,
499
- focus: {
500
- ...focusTokensPurpleHue
501
- },
502
- layout: layoutTokens
503
- };
504
- const transparentTheme = {
505
- colors: {
506
- background: {
507
- // Highly transparent backgrounds for glass effect
508
- base: "rgba(8, 12, 20, 0.95)",
509
- surface: "rgba(15, 20, 35, 0.85)",
510
- elevated: "rgba(25, 35, 55, 0.80)",
511
- overlay: "rgba(0, 0, 0, 0.75)"
512
- },
513
- border: {
514
- // Purple accent borders (Zendir brand)
515
- default: "rgba(139, 92, 246, 0.25)",
516
- muted: "rgba(139, 92, 246, 0.15)",
517
- focus: "#8b5cf6",
518
- // Thin faded card border with purple hint
519
- fadedBoxShadow: "inset 0 1px 0 rgba(139, 92, 246, 0.12), inset 0 -1px 0 rgba(0, 0, 0, 0.05), inset 1px 0 0 rgba(139, 92, 246, 0.06), inset -1px 0 0 rgba(139, 92, 246, 0.06)"
520
- },
521
- text: {
522
- primary: "#f0f4f8",
523
- secondary: "#94a3b8",
524
- tertiary: "#7b8da1",
525
- // WCAG AA: 5.71:1 on base, 5.34:1 on elevated (was #64748b → 3.66:1 FAIL)
526
- muted: "#7b8da1",
527
- // WCAG AA compliant (was #64748b)
528
- inverse: "#0f172a"
529
- },
530
- // Astro UXD Status Colors
531
- status: {
532
- normal: "#56f000",
533
- standby: "#2dccff",
534
- caution: "#fce83a",
535
- serious: "#ffb302",
536
- critical: "#ff3838",
537
- off: "#a4abb6"
538
- },
539
- semantic: {
540
- success: "#56f000",
541
- warning: "#fce83a",
542
- error: "#ff3838",
543
- info: "#8b5cf6"
544
- },
545
- // Purple accent (matching hybrid theme for consistency)
546
- accent: {
547
- primary: "#8b5cf6",
548
- // Vibrant purple
549
- secondary: "#a78bfa",
550
- // Light purple
551
- tertiary: "#7c3aed"
552
- // Deep purple
553
- },
554
- interactive: {
555
- default: "#8b5cf6",
556
- // Purple for interactive elements
557
- hover: "#a78bfa",
558
- // Light purple on hover
559
- active: "#7c3aed",
560
- // Deep purple on active
561
- disabled: "#475569",
562
- // Purple-hue transparent backgrounds for buttons/inputs (transparent + transparent-bold)
563
- transparentDefault: "rgba(139, 92, 246, 0.12)",
564
- transparentHover: "rgba(139, 92, 246, 0.32)",
565
- transparentInputBg: "rgba(139, 92, 246, 0.08)"
566
- }
567
- },
568
- spacing: astroThemeDark.spacing,
569
- borderRadius: {
570
- none: "0",
571
- xs: "2px",
572
- sm: "4px",
573
- md: "8px",
574
- lg: "12px",
575
- xl: "16px",
576
- full: "9999px"
577
- },
578
- elementSize: astroThemeDark.elementSize,
579
- // Same typography as hybrid for consistent card font across themes
580
- typography: astroThemeDark.typography,
581
- shadows: {
582
- ...shadowsDark,
583
- // Enhanced glow shadows for glass effect
584
- glow: (color) => `0 0 30px ${color}50, 0 0 60px ${color}25, 0 4px 20px rgba(0,0,0,0.4)`
585
- },
586
- animation: animationTokens,
587
- focus: {
588
- color: "#8b5cf6",
589
- // Purple focus ring
590
- width: "2px",
591
- offset: "2px",
592
- ring: "0 0 0 2px #8b5cf6",
593
- style: {
594
- outline: "2px solid #8b5cf6",
595
- outlineOffset: "2px"
596
- }
597
- },
598
- layout: layoutTokens
599
- };
600
- const transparentMinimalTheme = {
601
- colors: {
602
- background: {
603
- // Same as transparent theme
604
- base: "rgba(8, 12, 20, 0.95)",
605
- surface: "rgba(15, 20, 35, 0.85)",
606
- elevated: "rgba(25, 35, 55, 0.80)",
607
- overlay: "rgba(0, 0, 0, 0.75)"
608
- },
609
- border: {
610
- // Accent-colored borders for minimal theme (Zendir purple)
611
- default: "rgba(139, 92, 246, 0.25)",
612
- muted: "rgba(139, 92, 246, 0.15)",
613
- focus: "#8b5cf6",
614
- // Subtle card border using accent color
615
- fadedBoxShadow: "inset 0 1px 0 rgba(139, 92, 246, 0.1), inset 0 -1px 0 rgba(0, 0, 0, 0.1), inset 1px 0 0 rgba(139, 92, 246, 0.05), inset -1px 0 0 rgba(139, 92, 246, 0.05)"
616
- },
617
- text: {
618
- primary: "#f0f4f8",
619
- secondary: "#94a3b8",
620
- tertiary: "#7b8da1",
621
- // WCAG AA: 5.71:1 on base, 5.34:1 on elevated (was #64748b → 3.66:1 FAIL)
622
- muted: "#7b8da1",
623
- // WCAG AA compliant (was #64748b)
624
- inverse: "#0f172a"
625
- },
626
- // Astro UXD Status Colors
627
- status: {
628
- normal: "#56f000",
629
- standby: "#2dccff",
630
- caution: "#fce83a",
631
- serious: "#ffb302",
632
- critical: "#ff3838",
633
- off: "#a4abb6"
634
- },
635
- semantic: {
636
- success: "#56f000",
637
- warning: "#fce83a",
638
- error: "#ff3838",
639
- info: "#8b5cf6"
640
- },
641
- // Purple accent (matching transparent theme for consistency)
642
- accent: {
643
- primary: "#8b5cf6",
644
- // Vibrant purple
645
- secondary: "#a78bfa",
646
- // Light purple
647
- tertiary: "#7c3aed"
648
- // Deep purple
649
- },
650
- interactive: {
651
- default: "#8b5cf6",
652
- // Purple for interactive elements
653
- hover: "#a78bfa",
654
- // Light purple on hover
655
- active: "#7c3aed",
656
- // Deep purple on active
657
- disabled: "#475569",
658
- // Purple-hue transparent backgrounds for buttons/inputs (same as transparent theme)
659
- transparentDefault: "rgba(139, 92, 246, 0.12)",
660
- transparentHover: "rgba(139, 92, 246, 0.32)",
661
- transparentInputBg: "rgba(139, 92, 246, 0.08)"
662
- }
663
- },
664
- spacing: astroThemeDark.spacing,
665
- borderRadius: {
666
- none: "0",
667
- xs: "2px",
668
- sm: "4px",
669
- md: "8px",
670
- lg: "12px",
671
- xl: "16px",
672
- full: "9999px"
673
- },
674
- elementSize: astroThemeDark.elementSize,
675
- // Same typography as hybrid for consistent card font across themes
676
- typography: astroThemeDark.typography,
677
- shadows: {
678
- ...shadowsDark,
679
- // Same glow as transparent theme
680
- glow: (color) => `0 0 30px ${color}50, 0 0 60px ${color}25, 0 4px 20px rgba(0,0,0,0.4)`
681
- },
682
- animation: animationTokens,
683
- focus: {
684
- color: "#8b5cf6",
685
- // Purple focus ring
686
- width: "2px",
687
- offset: "2px",
688
- ring: "0 0 0 2px #8b5cf6",
689
- style: {
690
- outline: "2px solid #8b5cf6",
691
- outlineOffset: "2px"
692
- }
693
- },
694
- layout: layoutTokens
695
- };
696
- const ThemeContext = createContext(void 0);
31
+ var ThemeContext = createContext(void 0);
32
+ /**
33
+ * Converts a hex color to an rgba string helper.
34
+ * Accepts 3/6/8-char hex codes (#rgb, #rrggbb, #rrggbbaa).
35
+ */
697
36
  function hexToRgba(hex, alpha) {
698
- const clean = hex.replace("#", "");
699
- let r, g, b;
700
- if (clean.length === 3) {
701
- r = parseInt(clean[0] + clean[0], 16);
702
- g = parseInt(clean[1] + clean[1], 16);
703
- b = parseInt(clean[2] + clean[2], 16);
704
- } else {
705
- r = parseInt(clean.slice(0, 2), 16);
706
- g = parseInt(clean.slice(2, 4), 16);
707
- b = parseInt(clean.slice(4, 6), 16);
708
- }
709
- return `rgba(${r}, ${g}, ${b}, ${alpha})`;
37
+ const clean = hex.replace("#", "");
38
+ let r, g, b;
39
+ if (clean.length === 3) {
40
+ r = parseInt(clean[0] + clean[0], 16);
41
+ g = parseInt(clean[1] + clean[1], 16);
42
+ b = parseInt(clean[2] + clean[2], 16);
43
+ } else {
44
+ r = parseInt(clean.slice(0, 2), 16);
45
+ g = parseInt(clean.slice(2, 4), 16);
46
+ b = parseInt(clean.slice(4, 6), 16);
47
+ }
48
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
710
49
  }
711
50
  function buildScrollbarCSS(tokens, mode, reducedMotion) {
712
- const accent = tokens.colors.accent.primary;
713
- tokens.colors.background.surface;
714
- tokens.colors.background.base;
715
- const isLight = mode === "light";
716
- const thumbRest = isLight ? hexToRgba(accent, 0.28) : hexToRgba(accent, 0.35);
717
- const thumbHover = isLight ? hexToRgba(accent, 0.48) : hexToRgba(accent, 0.55);
718
- const thumbActive = isLight ? hexToRgba(accent, 0.64) : hexToRgba(accent, 0.72);
719
- const trackColor = isLight ? hexToRgba(accent, 0.04) : hexToRgba(accent, 0.06);
720
- const trackHover = isLight ? hexToRgba(accent, 0.08) : hexToRgba(accent, 0.1);
721
- const transition = reducedMotion ? "none" : "background-color 200ms ease, width 200ms ease, opacity 200ms ease";
722
- const thumbRadius = "9999px";
723
- const ffThumb = thumbRest;
724
- const ffTrack = trackColor;
725
- return `
51
+ const accent = tokens.colors.accent.primary;
52
+ tokens.colors.background.surface;
53
+ tokens.colors.background.base;
54
+ const isLight = mode === "light";
55
+ const thumbRest = isLight ? hexToRgba(accent, .28) : hexToRgba(accent, .35);
56
+ const thumbHover = isLight ? hexToRgba(accent, .48) : hexToRgba(accent, .55);
57
+ const thumbActive = isLight ? hexToRgba(accent, .64) : hexToRgba(accent, .72);
58
+ const trackColor = isLight ? hexToRgba(accent, .04) : hexToRgba(accent, .06);
59
+ const trackHover = isLight ? hexToRgba(accent, .08) : hexToRgba(accent, .1);
60
+ const transition = reducedMotion ? "none" : "background-color 200ms ease, width 200ms ease, opacity 200ms ease";
61
+ const thumbRadius = "9999px";
62
+ return `
726
63
  /* ═══════════════════════════════════════════════════════════════════════════
727
64
  Zendir Scrollbar System — Thin · Elegant · Theme-Connected
728
65
  ═══════════════════════════════════════════════════════════════════════════ */
@@ -731,7 +68,7 @@ function buildScrollbarCSS(tokens, mode, reducedMotion) {
731
68
  *,
732
69
  .zendir-scroll {
733
70
  scrollbar-width: thin;
734
- scrollbar-color: ${ffThumb} ${ffTrack};
71
+ scrollbar-color: ${thumbRest} ${trackColor};
735
72
  }
736
73
 
737
74
  /* ── Webkit / Blink (Chrome, Edge, Safari, Opera) ───────────────────────── */
@@ -846,234 +183,270 @@ function buildScrollbarCSS(tokens, mode, reducedMotion) {
846
183
  }
847
184
  `.trim();
848
185
  }
186
+ /**
187
+ * useScrollbarStyles — returns inline React.CSSProperties for a
188
+ * scrollable container that matches the current Zendir theme.
189
+ *
190
+ * Use when you need programmatic control rather than the
191
+ * `zendir-scroll` CSS class.
192
+ *
193
+ * @example
194
+ * ```tsx
195
+ * const scrollStyle = useScrollbarStyles();
196
+ * <div style={{ maxHeight: 400, ...scrollStyle }}>…</div>
197
+ * ```
198
+ */
849
199
  function useScrollbarStyles() {
850
- const { tokens, mode } = useTheme();
851
- return useMemo(() => {
852
- const accent = tokens.colors.accent.primary;
853
- const isLight = mode === "light";
854
- const thumbColor = isLight ? hexToRgba(accent, 0.28) : hexToRgba(accent, 0.35);
855
- const trackColor = isLight ? hexToRgba(accent, 0.04) : hexToRgba(accent, 0.06);
856
- return {
857
- // Firefox
858
- scrollbarWidth: "thin",
859
- scrollbarColor: `${thumbColor} ${trackColor}`,
860
- overflow: "auto"
861
- };
862
- }, [tokens, mode]);
200
+ const { tokens, mode } = useTheme();
201
+ return useMemo(() => {
202
+ const accent = tokens.colors.accent.primary;
203
+ const isLight = mode === "light";
204
+ return {
205
+ scrollbarWidth: "thin",
206
+ scrollbarColor: `${isLight ? hexToRgba(accent, .28) : hexToRgba(accent, .35)} ${isLight ? hexToRgba(accent, .04) : hexToRgba(accent, .06)}`,
207
+ overflow: "auto"
208
+ };
209
+ }, [tokens, mode]);
863
210
  }
864
- function ThemeProvider({
865
- children,
866
- theme: themeProp,
867
- defaultVariant,
868
- mode: modeProp,
869
- defaultMode: defaultModeProp,
870
- persist = true
871
- }) {
872
- const defaultTheme = themeProp ?? defaultVariant ?? "hybrid";
873
- const defaultMode = modeProp ?? defaultModeProp ?? "dark";
874
- const [theme, setThemeState] = useState(() => {
875
- if (persist && typeof window !== "undefined") {
876
- const saved = localStorage.getItem("zendir-ui-theme");
877
- if (saved === "astro" || saved === "zendir" || saved === "hybrid" || saved === "transparent" || saved === "transparent-bold" || saved === "transparent-minimal") {
878
- return saved;
879
- }
880
- }
881
- return defaultTheme;
882
- });
883
- const [mode, setModeState] = useState(() => {
884
- if (persist && typeof window !== "undefined") {
885
- const saved = localStorage.getItem("zendir-ui-mode");
886
- if (saved === "light" || saved === "dark") {
887
- return saved;
888
- }
889
- }
890
- return defaultMode;
891
- });
892
- const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);
893
- useEffect(() => {
894
- if (typeof window === "undefined") return;
895
- const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
896
- setPrefersReducedMotion(mediaQuery.matches);
897
- const handler = (e) => setPrefersReducedMotion(e.matches);
898
- mediaQuery.addEventListener("change", handler);
899
- return () => mediaQuery.removeEventListener("change", handler);
900
- }, []);
901
- const setTheme = (newTheme) => {
902
- setThemeState(newTheme);
903
- if (persist && typeof window !== "undefined") {
904
- localStorage.setItem("zendir-ui-theme", newTheme);
905
- }
906
- };
907
- const setMode = (newMode) => {
908
- setModeState(newMode);
909
- if (persist && typeof window !== "undefined") {
910
- localStorage.setItem("zendir-ui-mode", newMode);
911
- }
912
- };
913
- const toggleMode = () => {
914
- setMode(mode === "dark" ? "light" : "dark");
915
- };
916
- const [accentColor, setAccentColorState] = useState(() => {
917
- if (persist && typeof window !== "undefined") {
918
- return localStorage.getItem("zendir-ui-accent") || null;
919
- }
920
- return null;
921
- });
922
- const setAccentColor = (color) => {
923
- setAccentColorState(color);
924
- if (persist && typeof window !== "undefined") {
925
- if (color) {
926
- localStorage.setItem("zendir-ui-accent", color);
927
- } else {
928
- localStorage.removeItem("zendir-ui-accent");
929
- }
930
- }
931
- };
932
- const tokens = useMemo(() => {
933
- const base = mode === "light" ? astroThemeLight : theme === "astro" ? astroThemeDark : theme === "hybrid" ? hybridTheme : theme === "transparent" || theme === "transparent-bold" ? transparentTheme : theme === "transparent-minimal" ? transparentMinimalTheme : purpleHueTheme;
934
- const isTransparent = theme === "transparent" || theme === "transparent-bold" || theme === "transparent-minimal";
935
- const isMinimal = theme === "transparent-minimal";
936
- const resolvedAccent = isTransparent && accentColor ? {
937
- primary: accentColor,
938
- secondary: adjustHexBrightness(accentColor, 1.2),
939
- tertiary: adjustHexBrightness(accentColor, 0.85)
940
- } : base.colors.accent;
941
- const accentPrimary = resolvedAccent.primary;
942
- const accentBorderMuted = `${accentPrimary}40`;
943
- const accentBorderDefault = `${accentPrimary}66`;
944
- const accentFadedBoxShadow = `inset 0 1px 0 ${hexToRgba(accentPrimary, 0.12)}, inset 0 -1px 0 rgba(0, 0, 0, 0.05), inset 1px 0 0 ${hexToRgba(accentPrimary, 0.06)}, inset -1px 0 0 ${hexToRgba(accentPrimary, 0.06)}`;
945
- const cardStyle = isMinimal ? { border: `1px solid ${accentBorderMuted}` } : isTransparent ? { border: "none", boxShadow: accentFadedBoxShadow } : { border: `1px solid ${base.colors.border.muted}` };
946
- const cardStyleDashed = isMinimal ? { border: `1px dashed ${accentBorderMuted}` } : isTransparent ? { border: "none", boxShadow: accentFadedBoxShadow } : { border: `1px dashed ${base.colors.border.muted}` };
947
- const cardStyleDefault = isMinimal ? { border: `1px solid ${accentBorderDefault}` } : isTransparent ? { border: "none", boxShadow: accentFadedBoxShadow } : { border: `1px solid ${base.colors.border.default}` };
948
- const resolvedColors = {
949
- ...base.colors,
950
- accent: resolvedAccent,
951
- border: {
952
- ...base.colors.border,
953
- cardStyle,
954
- cardStyleDashed,
955
- cardStyleDefault
956
- }
957
- };
958
- return {
959
- ...base,
960
- colors: resolvedColors,
961
- borders: computeBorderTokens(resolvedColors),
962
- // Honor prefers-reduced-motion in the JS token surface too. The
963
- // global CSS @media rule below already strips CSS animations; this
964
- // ensures JS-driven animation libraries (Framer Motion etc.) that
965
- // read `tokens.animation.*` get the collapsed variant without each
966
- // developer having to branch on `useTheme().prefersReducedMotion`.
967
- animation: prefersReducedMotion ? animationTokensReduced : base.animation
968
- };
969
- }, [theme, mode, accentColor, prefersReducedMotion]);
970
- useEffect(() => {
971
- if (typeof document === "undefined") return;
972
- const root = document.documentElement;
973
- const { colors, typography: typography2, spacing: spacing2, borderRadius: borderRadius2, animation, focus, shadows } = tokens;
974
- root.setAttribute("data-theme", mode);
975
- root.setAttribute("data-variant", theme);
976
- root.style.setProperty("--color-background-base", colors.background.base);
977
- root.style.setProperty("--color-background-surface", colors.background.surface);
978
- root.style.setProperty("--color-background-elevated", colors.background.elevated);
979
- root.style.setProperty("--color-background-overlay", colors.background.overlay);
980
- root.style.setProperty("--color-border", colors.border.default);
981
- root.style.setProperty("--color-border-muted", colors.border.muted);
982
- root.style.setProperty("--color-border-focus", colors.border.focus);
983
- root.style.setProperty("--color-text-primary", colors.text.primary);
984
- root.style.setProperty("--color-text-secondary", colors.text.secondary);
985
- root.style.setProperty("--color-text-tertiary", colors.text.tertiary);
986
- root.style.setProperty("--color-text-inverse", colors.text.inverse);
987
- root.style.setProperty("--color-status-normal", colors.status.normal);
988
- root.style.setProperty("--color-status-standby", colors.status.standby);
989
- root.style.setProperty("--color-status-caution", colors.status.caution);
990
- root.style.setProperty("--color-status-serious", colors.status.serious);
991
- root.style.setProperty("--color-status-critical", colors.status.critical);
992
- root.style.setProperty("--color-status-off", colors.status.off);
993
- root.style.setProperty("--color-interactive-default", colors.interactive.default);
994
- root.style.setProperty("--color-interactive-hover", colors.interactive.hover);
995
- root.style.setProperty("--color-interactive-active", colors.interactive.active);
996
- root.style.setProperty("--color-interactive-disabled", colors.interactive.disabled);
997
- root.style.setProperty("--color-accent-primary", colors.accent.primary);
998
- root.style.setProperty("--color-accent-secondary", colors.accent.secondary);
999
- root.style.setProperty("--color-accent-tertiary", colors.accent.tertiary);
1000
- root.style.setProperty("--font-family-heading", typography2.fontFamily.heading || typography2.fontFamily.primary);
1001
- root.style.setProperty("--font-family-primary", typography2.fontFamily.primary);
1002
- root.style.setProperty("--font-family-mono", typography2.fontFamily.mono);
1003
- root.style.setProperty("--spacing-xxs", spacing2.xxs);
1004
- root.style.setProperty("--spacing-xs", spacing2.xs);
1005
- root.style.setProperty("--spacing-sm", spacing2.sm);
1006
- root.style.setProperty("--spacing-smd", spacing2.smd);
1007
- root.style.setProperty("--spacing-md", spacing2.md);
1008
- root.style.setProperty("--spacing-mdl", spacing2.mdl);
1009
- root.style.setProperty("--spacing-lg", spacing2.lg);
1010
- root.style.setProperty("--spacing-xl", spacing2.xl);
1011
- root.style.setProperty("--spacing-xxl", spacing2.xxl);
1012
- root.style.setProperty("--radius-sm", borderRadius2.sm);
1013
- root.style.setProperty("--radius-md", borderRadius2.md);
1014
- root.style.setProperty("--radius-lg", borderRadius2.lg);
1015
- root.style.setProperty("--radius-xl", borderRadius2.xl);
1016
- const motionMultiplier = prefersReducedMotion ? 0 : 1;
1017
- root.style.setProperty("--animation-fast", prefersReducedMotion ? "none" : animation.fast);
1018
- root.style.setProperty("--animation-normal", prefersReducedMotion ? "none" : animation.normal);
1019
- root.style.setProperty("--animation-slow", prefersReducedMotion ? "none" : animation.slow);
1020
- root.style.setProperty("--duration-fast", `${animation.duration.fast * motionMultiplier}ms`);
1021
- root.style.setProperty("--duration-normal", `${animation.duration.normal * motionMultiplier}ms`);
1022
- root.style.setProperty("--duration-slow", `${animation.duration.slow * motionMultiplier}ms`);
1023
- root.style.setProperty("--focus-ring-color", focus.color);
1024
- root.style.setProperty("--focus-ring-width", focus.width);
1025
- root.style.setProperty("--focus-ring-offset", focus.offset);
1026
- root.style.setProperty("--shadow-sm", shadows.sm);
1027
- root.style.setProperty("--shadow-md", shadows.md);
1028
- root.style.setProperty("--shadow-lg", shadows.lg);
1029
- root.style.setProperty("--shadow-xl", shadows.xl);
1030
- document.body.style.backgroundColor = colors.background.base;
1031
- document.body.style.color = colors.text.primary;
1032
- document.body.style.fontFamily = typography2.fontFamily.primary;
1033
- }, [tokens, theme, mode, prefersReducedMotion]);
1034
- const scrollbarCSS = useMemo(() => buildScrollbarCSS(tokens, mode, prefersReducedMotion), [tokens, mode, prefersReducedMotion]);
1035
- const value = useMemo(
1036
- () => ({
1037
- theme,
1038
- mode,
1039
- tokens,
1040
- prefersReducedMotion,
1041
- accentColor,
1042
- setTheme,
1043
- setMode,
1044
- toggleMode,
1045
- setAccentColor
1046
- }),
1047
- [theme, mode, tokens, prefersReducedMotion, accentColor]
1048
- );
1049
- const reducedMotionCSS = `@media (prefers-reduced-motion: reduce) {
211
+ /**
212
+ * ThemeProvider - Enterprise theme context provider
213
+ *
214
+ * Provides theme tokens, mode switching, and accessibility features
215
+ * to all child components.
216
+ *
217
+ * @example
218
+ * ```tsx
219
+ * <ThemeProvider theme="hybrid" mode="dark"> // Zen (Hybrid) is the default
220
+ * <App />
221
+ * </ThemeProvider>
222
+ * ```
223
+ */
224
+ function ThemeProvider({ children, theme: themeProp, defaultVariant, mode: modeProp, defaultMode: defaultModeProp, persist = true }) {
225
+ const defaultTheme = themeProp ?? defaultVariant ?? "hybrid";
226
+ const defaultMode = modeProp ?? defaultModeProp ?? "dark";
227
+ const [theme, setThemeState] = useState(() => {
228
+ if (persist && typeof window !== "undefined") {
229
+ const saved = localStorage.getItem("zendir-ui-theme");
230
+ if (saved === "astro" || saved === "zendir" || saved === "hybrid" || saved === "nebula" || saved === "purple-hue" || saved === "transparent" || saved === "transparent-bold" || saved === "transparent-minimal") return saved;
231
+ }
232
+ return defaultTheme;
233
+ });
234
+ const [mode, setModeState] = useState(() => {
235
+ if (persist && typeof window !== "undefined") {
236
+ const saved = localStorage.getItem("zendir-ui-mode");
237
+ if (saved === "light" || saved === "dark") return saved;
238
+ }
239
+ return defaultMode;
240
+ });
241
+ const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);
242
+ useEffect(() => {
243
+ if (typeof window === "undefined") return;
244
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
245
+ setPrefersReducedMotion(mediaQuery.matches);
246
+ const handler = (e) => setPrefersReducedMotion(e.matches);
247
+ mediaQuery.addEventListener("change", handler);
248
+ return () => mediaQuery.removeEventListener("change", handler);
249
+ }, []);
250
+ const setTheme = (newTheme) => {
251
+ setThemeState(newTheme);
252
+ if (persist && typeof window !== "undefined") localStorage.setItem("zendir-ui-theme", newTheme);
253
+ };
254
+ const setMode = (newMode) => {
255
+ setModeState(newMode);
256
+ if (persist && typeof window !== "undefined") localStorage.setItem("zendir-ui-mode", newMode);
257
+ };
258
+ const toggleMode = () => {
259
+ setMode(mode === "dark" ? "light" : "dark");
260
+ };
261
+ const [accentColor, setAccentColorState] = useState(() => {
262
+ if (persist && typeof window !== "undefined") return localStorage.getItem("zendir-ui-accent") || null;
263
+ return null;
264
+ });
265
+ const setAccentColor = (color) => {
266
+ setAccentColorState(color);
267
+ if (persist && typeof window !== "undefined") if (color) localStorage.setItem("zendir-ui-accent", color);
268
+ else localStorage.removeItem("zendir-ui-accent");
269
+ };
270
+ const tokens = useMemo(() => {
271
+ const base = mode === "light" ? astroThemeLight : theme === "astro" ? astroThemeDark : theme === "hybrid" ? hybridTheme : theme === "nebula" ? nebulaTheme : theme === "transparent" || theme === "transparent-bold" ? transparentTheme : theme === "transparent-minimal" ? transparentMinimalTheme : purpleHueTheme;
272
+ const isTransparent = theme === "transparent" || theme === "transparent-bold" || theme === "transparent-minimal";
273
+ const isMinimal = theme === "transparent-minimal";
274
+ const resolvedAccent = isTransparent && accentColor ? {
275
+ primary: accentColor,
276
+ secondary: adjustHexBrightness(accentColor, 1.2),
277
+ tertiary: adjustHexBrightness(accentColor, .85)
278
+ } : base.colors.accent;
279
+ const accentPrimary = resolvedAccent.primary;
280
+ const accentBorderMuted = `${accentPrimary}40`;
281
+ const accentBorderDefault = `${accentPrimary}66`;
282
+ const accentFadedBoxShadow = `inset 0 1px 0 ${hexToRgba(accentPrimary, .12)}, inset 0 -1px 0 rgba(0, 0, 0, 0.05), inset 1px 0 0 ${hexToRgba(accentPrimary, .06)}, inset -1px 0 0 ${hexToRgba(accentPrimary, .06)}`;
283
+ const cardStyle = isMinimal ? { border: `1px solid ${accentBorderMuted}` } : isTransparent ? {
284
+ border: "none",
285
+ boxShadow: accentFadedBoxShadow
286
+ } : { border: `1px solid ${base.colors.border.muted}` };
287
+ const cardStyleDashed = isMinimal ? { border: `1px dashed ${accentBorderMuted}` } : isTransparent ? {
288
+ border: "none",
289
+ boxShadow: accentFadedBoxShadow
290
+ } : { border: `1px dashed ${base.colors.border.muted}` };
291
+ const cardStyleDefault = isMinimal ? { border: `1px solid ${accentBorderDefault}` } : isTransparent ? {
292
+ border: "none",
293
+ boxShadow: accentFadedBoxShadow
294
+ } : { border: `1px solid ${base.colors.border.default}` };
295
+ const resolvedColors = {
296
+ ...base.colors,
297
+ accent: resolvedAccent,
298
+ border: {
299
+ ...base.colors.border,
300
+ cardStyle,
301
+ cardStyleDashed,
302
+ cardStyleDefault
303
+ }
304
+ };
305
+ return {
306
+ ...base,
307
+ colors: resolvedColors,
308
+ borders: computeBorderTokens(resolvedColors)
309
+ };
310
+ }, [
311
+ theme,
312
+ mode,
313
+ accentColor
314
+ ]);
315
+ useEffect(() => {
316
+ if (typeof document === "undefined") return;
317
+ const root = document.documentElement;
318
+ const { colors, typography, spacing, borderRadius, animation, focus, shadows } = tokens;
319
+ root.setAttribute("data-theme", mode);
320
+ root.setAttribute("data-variant", theme);
321
+ root.style.setProperty("--color-background-base", colors.background.base);
322
+ root.style.setProperty("--color-background-surface", colors.background.surface);
323
+ root.style.setProperty("--color-background-elevated", colors.background.elevated);
324
+ root.style.setProperty("--color-background-overlay", colors.background.overlay);
325
+ root.style.setProperty("--color-border", colors.border.default);
326
+ root.style.setProperty("--color-border-muted", colors.border.muted);
327
+ root.style.setProperty("--color-border-focus", colors.border.focus);
328
+ root.style.setProperty("--color-text-primary", colors.text.primary);
329
+ root.style.setProperty("--color-text-secondary", colors.text.secondary);
330
+ root.style.setProperty("--color-text-tertiary", colors.text.tertiary);
331
+ root.style.setProperty("--color-text-inverse", colors.text.inverse);
332
+ root.style.setProperty("--color-status-normal", colors.status.normal);
333
+ root.style.setProperty("--color-status-standby", colors.status.standby);
334
+ root.style.setProperty("--color-status-caution", colors.status.caution);
335
+ root.style.setProperty("--color-status-serious", colors.status.serious);
336
+ root.style.setProperty("--color-status-critical", colors.status.critical);
337
+ root.style.setProperty("--color-status-off", colors.status.off);
338
+ root.style.setProperty("--color-interactive-default", colors.interactive.default);
339
+ root.style.setProperty("--color-interactive-hover", colors.interactive.hover);
340
+ root.style.setProperty("--color-interactive-active", colors.interactive.active);
341
+ root.style.setProperty("--color-interactive-disabled", colors.interactive.disabled);
342
+ root.style.setProperty("--color-accent-primary", colors.accent.primary);
343
+ root.style.setProperty("--color-accent-secondary", colors.accent.secondary);
344
+ root.style.setProperty("--color-accent-tertiary", colors.accent.tertiary);
345
+ root.style.setProperty("--font-family-heading", typography.fontFamily.heading || typography.fontFamily.primary);
346
+ root.style.setProperty("--font-family-primary", typography.fontFamily.primary);
347
+ root.style.setProperty("--font-family-mono", typography.fontFamily.mono);
348
+ root.style.setProperty("--spacing-xxs", spacing.xxs);
349
+ root.style.setProperty("--spacing-xs", spacing.xs);
350
+ root.style.setProperty("--spacing-sm", spacing.sm);
351
+ root.style.setProperty("--spacing-smd", spacing.smd);
352
+ root.style.setProperty("--spacing-md", spacing.md);
353
+ root.style.setProperty("--spacing-mdl", spacing.mdl);
354
+ root.style.setProperty("--spacing-lg", spacing.lg);
355
+ root.style.setProperty("--spacing-xl", spacing.xl);
356
+ root.style.setProperty("--spacing-xxl", spacing.xxl);
357
+ root.style.setProperty("--radius-sm", borderRadius.sm);
358
+ root.style.setProperty("--radius-md", borderRadius.md);
359
+ root.style.setProperty("--radius-lg", borderRadius.lg);
360
+ root.style.setProperty("--radius-xl", borderRadius.xl);
361
+ const motionMultiplier = prefersReducedMotion ? 0 : 1;
362
+ root.style.setProperty("--animation-fast", prefersReducedMotion ? "none" : animation.fast);
363
+ root.style.setProperty("--animation-normal", prefersReducedMotion ? "none" : animation.normal);
364
+ root.style.setProperty("--animation-slow", prefersReducedMotion ? "none" : animation.slow);
365
+ root.style.setProperty("--duration-fast", `${animation.duration.fast * motionMultiplier}ms`);
366
+ root.style.setProperty("--duration-normal", `${animation.duration.normal * motionMultiplier}ms`);
367
+ root.style.setProperty("--duration-slow", `${animation.duration.slow * motionMultiplier}ms`);
368
+ root.style.setProperty("--focus-ring-color", focus.color);
369
+ root.style.setProperty("--focus-ring-width", focus.width);
370
+ root.style.setProperty("--focus-ring-offset", focus.offset);
371
+ root.style.setProperty("--shadow-sm", shadows.sm);
372
+ root.style.setProperty("--shadow-md", shadows.md);
373
+ root.style.setProperty("--shadow-lg", shadows.lg);
374
+ root.style.setProperty("--shadow-xl", shadows.xl);
375
+ document.body.style.backgroundColor = colors.background.base;
376
+ document.body.style.color = colors.text.primary;
377
+ document.body.style.fontFamily = typography.fontFamily.primary;
378
+ }, [
379
+ tokens,
380
+ theme,
381
+ mode,
382
+ prefersReducedMotion
383
+ ]);
384
+ const scrollbarCSS = useMemo(() => buildScrollbarCSS(tokens, mode, prefersReducedMotion), [
385
+ tokens,
386
+ mode,
387
+ prefersReducedMotion
388
+ ]);
389
+ const value = useMemo(() => ({
390
+ theme,
391
+ mode,
392
+ tokens,
393
+ prefersReducedMotion,
394
+ accentColor,
395
+ setTheme,
396
+ setMode,
397
+ toggleMode,
398
+ setAccentColor
399
+ }), [
400
+ theme,
401
+ mode,
402
+ tokens,
403
+ prefersReducedMotion,
404
+ accentColor
405
+ ]);
406
+ return /* @__PURE__ */ jsxs(ThemeContext.Provider, {
407
+ value,
408
+ children: [
409
+ /* @__PURE__ */ jsx("style", {
410
+ "data-zendir-scrollbar": "",
411
+ dangerouslySetInnerHTML: { __html: scrollbarCSS }
412
+ }),
413
+ /* @__PURE__ */ jsx("style", {
414
+ "data-zendir-reduced-motion": "",
415
+ dangerouslySetInnerHTML: { __html: `@media (prefers-reduced-motion: reduce) {
1050
416
  *, *::before, *::after {
1051
417
  animation-duration: 0.01ms !important;
1052
418
  animation-iteration-count: 1 !important;
1053
419
  transition-duration: 0.01ms !important;
1054
420
  scroll-behavior: auto !important;
1055
421
  }
1056
- }`;
1057
- return /* @__PURE__ */ jsxs(ThemeContext.Provider, { value, children: [
1058
- /* @__PURE__ */ jsx("style", { "data-zendir-scrollbar": "", dangerouslySetInnerHTML: { __html: scrollbarCSS } }),
1059
- /* @__PURE__ */ jsx("style", { "data-zendir-reduced-motion": "", dangerouslySetInnerHTML: { __html: reducedMotionCSS } }),
1060
- children
1061
- ] });
422
+ }` }
423
+ }),
424
+ children
425
+ ]
426
+ });
1062
427
  }
428
+ /**
429
+ * useTheme - Access theme context
430
+ *
431
+ * @throws Error if used outside ThemeProvider
432
+ *
433
+ * @example
434
+ * ```tsx
435
+ * const { tokens, mode, toggleMode } = useTheme();
436
+ * ```
437
+ */
1063
438
  function useTheme() {
1064
- const context = useContext(ThemeContext);
1065
- if (!context) {
1066
- throw new Error("useTheme must be used within a ThemeProvider");
1067
- }
1068
- return context;
439
+ const context = useContext(ThemeContext);
440
+ if (!context) throw new Error("useTheme must be used within a ThemeProvider");
441
+ return context;
1069
442
  }
443
+ /**
444
+ * useThemeTokens - Access only theme tokens (for memoization)
445
+ */
1070
446
  function useThemeTokens() {
1071
- return useTheme().tokens;
447
+ return useTheme().tokens;
1072
448
  }
1073
- export {
1074
- ThemeProvider,
1075
- useScrollbarStyles,
1076
- useTheme,
1077
- useThemeTokens
1078
- };
1079
- //# sourceMappingURL=ThemeProvider.js.map
449
+ //#endregion
450
+ export { ThemeProvider, useScrollbarStyles, useTheme, useThemeTokens };
451
+
452
+ //# sourceMappingURL=ThemeProvider.js.map