@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,496 +1,532 @@
1
- import { jsxs, jsx } from "react/jsx-runtime";
2
- import { memo, useMemo, useId, useRef, useState, useEffect, useCallback } from "react";
3
1
  import { useTheme } from "../../theme/ThemeProvider.js";
4
2
  import { useBreakpoint } from "../layout/useBreakpoint.js";
5
- const PROTOCOLS = ["wss", "ws", "mqtts", "mqtt", "tcp"];
6
- const DEFAULT_PORTS = {
7
- ws: 80,
8
- wss: 443,
9
- mqtt: 1883,
10
- mqtts: 8883,
11
- tcp: 1883
3
+ import { memo, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/react/core/widgets/ConnectionForm.tsx
6
+ /**
7
+ * @zendir/ui - ConnectionForm Component
8
+ *
9
+ * MQTT/WebSocket connection form with URL composition, recent connections,
10
+ * URL parameter sharing, and persistence. Tailored for operator dashboards
11
+ * that require broker configuration (host, port, protocol, credentials).
12
+ *
13
+ * Astro UX Compliance:
14
+ * - Status indicators for connection state (connected/disconnected/error)
15
+ * - Form validation with clear error states
16
+ * - Keyboard shortcut for quick connect (Ctrl+Enter)
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * <ConnectionForm
21
+ * onConnect={(config) => client.connect(config)}
22
+ * onDisconnect={() => client.disconnect()}
23
+ * connected={isConnected}
24
+ * defaultProtocol="wss"
25
+ * showAdvanced
26
+ * />
27
+ * ```
28
+ */
29
+ var PROTOCOLS = [
30
+ "wss",
31
+ "ws",
32
+ "mqtts",
33
+ "mqtt",
34
+ "tcp"
35
+ ];
36
+ var DEFAULT_PORTS = {
37
+ ws: 80,
38
+ wss: 443,
39
+ mqtt: 1883,
40
+ mqtts: 8883,
41
+ tcp: 1883
12
42
  };
13
- const ConnectionForm = memo(function ConnectionForm2({
14
- onConnect,
15
- onDisconnect,
16
- connected = false,
17
- connecting = false,
18
- defaultProtocol = "wss",
19
- defaultHost = "localhost",
20
- defaultPort,
21
- defaultPath = "/mqtt",
22
- showAdvanced = false,
23
- persistKey,
24
- parseUrlParams = false,
25
- error,
26
- compact = false,
27
- style,
28
- labelPlacement = "outlined"
29
- }) {
30
- const { tokens } = useTheme();
31
- const { isMobile } = useBreakpoint();
32
- const isOutlined = labelPlacement === "outlined";
33
- const initialConfig = useMemo(() => {
34
- if (persistKey) {
35
- try {
36
- const saved = localStorage.getItem(persistKey);
37
- if (saved) return JSON.parse(saved);
38
- } catch {
39
- }
40
- }
41
- if (parseUrlParams && typeof window !== "undefined") {
42
- const params = new URLSearchParams(window.location.search);
43
- if (params.has("host")) {
44
- return {
45
- host: params.get("host") || defaultHost,
46
- port: parseInt(params.get("port") || String(defaultPort || DEFAULT_PORTS[defaultProtocol])),
47
- protocol: params.get("protocol") || defaultProtocol,
48
- path: params.get("path") || defaultPath,
49
- username: params.get("username") || "",
50
- password: params.get("password") || "",
51
- clientId: params.get("clientId") || ""
52
- };
53
- }
54
- }
55
- return {
56
- host: defaultHost,
57
- port: defaultPort || DEFAULT_PORTS[defaultProtocol],
58
- protocol: defaultProtocol,
59
- path: defaultPath,
60
- username: "",
61
- password: "",
62
- clientId: ""
63
- };
64
- }, []);
65
- const baseId = useId();
66
- const passwordInputRef = useRef(null);
67
- const usernameInputRef = useRef(null);
68
- const [config, setConfig] = useState(initialConfig);
69
- const [showAdv, setShowAdv] = useState(showAdvanced);
70
- const [showPassword, setShowPassword] = useState(false);
71
- useEffect(() => {
72
- if (persistKey) {
73
- try {
74
- localStorage.setItem(persistKey, JSON.stringify(config));
75
- } catch {
76
- }
77
- }
78
- }, [config, persistKey]);
79
- const updateField = useCallback((key, value) => {
80
- setConfig((prev) => ({ ...prev, [key]: value }));
81
- }, []);
82
- const handleProtocolChange = useCallback((protocol) => {
83
- setConfig((prev) => ({
84
- ...prev,
85
- protocol,
86
- port: prev.port === DEFAULT_PORTS[prev.protocol] ? DEFAULT_PORTS[protocol] : prev.port
87
- }));
88
- }, []);
89
- const handleSubmit = useCallback((e) => {
90
- e.preventDefault();
91
- if (!connected) onConnect(config);
92
- else onDisconnect == null ? void 0 : onDisconnect();
93
- }, [config, connected, onConnect, onDisconnect]);
94
- const getShareUrl = useCallback(() => {
95
- const base = window.location.origin + window.location.pathname;
96
- const params = new URLSearchParams({
97
- host: config.host,
98
- port: String(config.port),
99
- protocol: config.protocol,
100
- ...config.path ? { path: config.path } : {}
101
- });
102
- return `${base}?${params.toString()}`;
103
- }, [config]);
104
- const fullUrl = `${config.protocol}://${config.host}:${config.port}${config.path || ""}`;
105
- const inputStyle = {
106
- width: "100%",
107
- minHeight: compact ? 32 : 40,
108
- padding: compact ? `6px ${tokens.spacing.sm}` : `${tokens.spacing.sm} ${tokens.spacing.md}`,
109
- fontSize: tokens.typography.fontSize.sm,
110
- fontFamily: tokens.typography.fontFamily.primary,
111
- color: tokens.colors.text.primary,
112
- backgroundColor: tokens.colors.background.base,
113
- border: `1px solid ${tokens.colors.border.default}`,
114
- borderRadius: tokens.borderRadius.md,
115
- outline: "none",
116
- transition: tokens.animation.fast,
117
- boxSizing: "border-box"
118
- };
119
- const labelStyle = isOutlined ? {
120
- position: "absolute",
121
- top: 0,
122
- left: "10px",
123
- transform: "translateY(-50%)",
124
- backgroundColor: tokens.colors.background.base,
125
- padding: "0 5px",
126
- fontSize: tokens.typography.fontSize.xxs,
127
- fontWeight: tokens.typography.fontWeight.medium,
128
- color: tokens.colors.text.tertiary,
129
- textTransform: "uppercase",
130
- letterSpacing: "0.04em",
131
- zIndex: 1,
132
- pointerEvents: "none",
133
- lineHeight: 1.2,
134
- whiteSpace: "nowrap"
135
- } : {
136
- display: "block",
137
- fontSize: tokens.typography.fontSize.xxs,
138
- fontWeight: tokens.typography.fontWeight.medium,
139
- color: tokens.colors.text.tertiary,
140
- marginBottom: "4px",
141
- textTransform: "uppercase",
142
- letterSpacing: "0.04em"
143
- };
144
- const fieldWrapperStyle = isOutlined ? { position: "relative" } : {};
145
- const statusColor = connected ? tokens.colors.status.normal : error ? tokens.colors.status.critical : tokens.colors.status.off;
146
- return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, "aria-label": "Connection configuration", style: {
147
- fontFamily: tokens.typography.fontFamily.primary,
148
- ...style
149
- }, children: [
150
- /* @__PURE__ */ jsxs("div", { "aria-live": "polite", style: {
151
- display: "flex",
152
- alignItems: "center",
153
- gap: tokens.spacing.sm,
154
- flexWrap: "wrap",
155
- marginBottom: tokens.spacing.md
156
- }, children: [
157
- /* @__PURE__ */ jsx("div", { style: {
158
- width: 8,
159
- height: 8,
160
- borderRadius: "50%",
161
- backgroundColor: statusColor,
162
- boxShadow: connected ? `0 0 6px ${statusColor}` : "none",
163
- transition: tokens.animation.fast
164
- } }),
165
- /* @__PURE__ */ jsx("span", { style: {
166
- fontSize: tokens.typography.fontSize.xs,
167
- color: tokens.colors.text.secondary,
168
- fontWeight: tokens.typography.fontWeight.medium
169
- }, children: connecting ? "Connecting..." : connected ? "Connected" : "Disconnected" }),
170
- /* @__PURE__ */ jsx("div", { style: { flex: 1 } }),
171
- /* @__PURE__ */ jsx("span", { style: {
172
- fontSize: tokens.typography.fontSize.xxs,
173
- color: tokens.colors.text.tertiary,
174
- fontFamily: tokens.typography.fontFamily.mono,
175
- overflow: "hidden",
176
- textOverflow: "ellipsis",
177
- maxWidth: isMobile ? "100%" : 280,
178
- whiteSpace: isMobile ? "normal" : "nowrap",
179
- wordBreak: isMobile ? "break-all" : "normal"
180
- }, children: fullUrl })
181
- ] }),
182
- /* @__PURE__ */ jsxs(
183
- "div",
184
- {
185
- style: {
186
- display: "grid",
187
- gridTemplateColumns: isMobile ? "1fr" : "minmax(80px, 100px) 1fr minmax(60px, 80px)",
188
- gap: tokens.spacing.sm
189
- },
190
- children: [
191
- /* @__PURE__ */ jsxs("div", { style: fieldWrapperStyle, children: [
192
- /* @__PURE__ */ jsx("label", { htmlFor: `${baseId}-protocol`, style: labelStyle, children: "Protocol" }),
193
- /* @__PURE__ */ jsx(
194
- "select",
195
- {
196
- id: `${baseId}-protocol`,
197
- value: config.protocol,
198
- onChange: (e) => handleProtocolChange(e.target.value),
199
- disabled: connected || connecting,
200
- style: {
201
- ...inputStyle,
202
- cursor: "pointer",
203
- appearance: "auto"
204
- },
205
- children: PROTOCOLS.map((p) => /* @__PURE__ */ jsx("option", { value: p, children: p.toUpperCase() }, p))
206
- }
207
- )
208
- ] }),
209
- /* @__PURE__ */ jsxs("div", { style: fieldWrapperStyle, children: [
210
- /* @__PURE__ */ jsx("label", { htmlFor: `${baseId}-host`, style: labelStyle, children: "Host" }),
211
- /* @__PURE__ */ jsx(
212
- "input",
213
- {
214
- id: `${baseId}-host`,
215
- type: "text",
216
- value: config.host,
217
- onChange: (e) => updateField("host", e.target.value),
218
- disabled: connected || connecting,
219
- placeholder: "broker.example.com",
220
- style: inputStyle
221
- }
222
- )
223
- ] }),
224
- /* @__PURE__ */ jsxs("div", { style: fieldWrapperStyle, children: [
225
- /* @__PURE__ */ jsx("label", { htmlFor: `${baseId}-port`, style: labelStyle, children: "Port" }),
226
- /* @__PURE__ */ jsx(
227
- "input",
228
- {
229
- id: `${baseId}-port`,
230
- type: "number",
231
- value: config.port,
232
- min: 1,
233
- max: 65535,
234
- onChange: (e) => {
235
- const v = parseInt(e.target.value) || 0;
236
- updateField("port", Math.max(0, Math.min(65535, v)));
237
- },
238
- disabled: connected || connecting,
239
- style: { ...inputStyle, fontFamily: tokens.typography.fontFamily.mono }
240
- }
241
- )
242
- ] })
243
- ]
244
- }
245
- ),
246
- /* @__PURE__ */ jsxs("div", { style: { marginTop: tokens.spacing.sm, ...fieldWrapperStyle }, children: [
247
- /* @__PURE__ */ jsx("label", { htmlFor: `${baseId}-path`, style: labelStyle, children: "Path" }),
248
- /* @__PURE__ */ jsx(
249
- "input",
250
- {
251
- id: `${baseId}-path`,
252
- type: "text",
253
- value: config.path || "",
254
- onChange: (e) => updateField("path", e.target.value),
255
- disabled: connected || connecting,
256
- placeholder: "/mqtt",
257
- style: inputStyle
258
- }
259
- )
260
- ] }),
261
- /* @__PURE__ */ jsxs(
262
- "button",
263
- {
264
- type: "button",
265
- onClick: () => setShowAdv((p) => !p),
266
- style: {
267
- display: "flex",
268
- alignItems: "center",
269
- gap: "4px",
270
- fontSize: tokens.typography.fontSize.xxs,
271
- color: tokens.colors.text.tertiary,
272
- backgroundColor: "transparent",
273
- border: "none",
274
- cursor: "pointer",
275
- marginTop: tokens.spacing.sm,
276
- padding: 0,
277
- fontFamily: tokens.typography.fontFamily.primary
278
- },
279
- children: [
280
- /* @__PURE__ */ jsx(
281
- "svg",
282
- {
283
- width: "12",
284
- height: "12",
285
- viewBox: "0 0 24 24",
286
- fill: "none",
287
- stroke: "currentColor",
288
- strokeWidth: "2",
289
- style: { transition: tokens.animation.fast, transform: showAdv ? "rotate(90deg)" : "rotate(0)" },
290
- children: /* @__PURE__ */ jsx("polyline", { points: "9 18 15 12 9 6" })
291
- }
292
- ),
293
- "Advanced"
294
- ]
295
- }
296
- ),
297
- showAdv && /* @__PURE__ */ jsxs("div", { style: {
298
- marginTop: tokens.spacing.sm,
299
- display: "grid",
300
- gridTemplateColumns: isMobile ? "1fr" : "1fr 1fr",
301
- gap: tokens.spacing.sm
302
- }, children: [
303
- /* @__PURE__ */ jsxs("div", { style: fieldWrapperStyle, children: [
304
- /* @__PURE__ */ jsx("label", { htmlFor: `${baseId}-username`, style: labelStyle, children: "Username" }),
305
- /* @__PURE__ */ jsx(
306
- "input",
307
- {
308
- ref: usernameInputRef,
309
- id: `${baseId}-username`,
310
- type: "text",
311
- value: config.username || "",
312
- onChange: (e) => updateField("username", e.target.value),
313
- onPaste: (e) => {
314
- const pasted = e.clipboardData.getData("text");
315
- const trimmed = pasted.trim();
316
- const input = usernameInputRef.current;
317
- if (input) {
318
- const cur = config.username || "";
319
- const start = input.selectionStart ?? cur.length;
320
- const end = input.selectionEnd ?? cur.length;
321
- const newValue = cur.slice(0, start) + trimmed + cur.slice(end);
322
- if (trimmed !== pasted || newValue !== cur) {
323
- e.preventDefault();
324
- updateField("username", newValue);
325
- requestAnimationFrame(() => {
326
- input.setSelectionRange(start + trimmed.length, start + trimmed.length);
327
- });
328
- }
329
- } else if (trimmed !== pasted) {
330
- e.preventDefault();
331
- updateField("username", trimmed);
332
- }
333
- },
334
- onBlur: () => {
335
- const cur = config.username ?? "";
336
- const trimmed = cur.trim();
337
- if (trimmed !== cur) updateField("username", trimmed);
338
- },
339
- disabled: connected || connecting,
340
- autoComplete: "username",
341
- style: inputStyle
342
- }
343
- )
344
- ] }),
345
- /* @__PURE__ */ jsxs("div", { style: fieldWrapperStyle, children: [
346
- /* @__PURE__ */ jsx("label", { htmlFor: `${baseId}-password`, style: labelStyle, children: "Password" }),
347
- /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
348
- /* @__PURE__ */ jsx(
349
- "input",
350
- {
351
- ref: passwordInputRef,
352
- id: `${baseId}-password`,
353
- type: showPassword ? "text" : "password",
354
- value: config.password || "",
355
- onChange: (e) => updateField("password", e.target.value),
356
- onPaste: (e) => {
357
- const pasted = e.clipboardData.getData("text");
358
- const trimmed = pasted.trim();
359
- const input = passwordInputRef.current;
360
- if (input) {
361
- const cur = config.password || "";
362
- const start = input.selectionStart ?? cur.length;
363
- const end = input.selectionEnd ?? cur.length;
364
- const newValue = cur.slice(0, start) + trimmed + cur.slice(end);
365
- if (trimmed !== pasted || newValue !== cur) {
366
- e.preventDefault();
367
- updateField("password", newValue);
368
- requestAnimationFrame(() => {
369
- const pos = start + trimmed.length;
370
- input.setSelectionRange(pos, pos);
371
- });
372
- }
373
- } else if (trimmed !== pasted) {
374
- e.preventDefault();
375
- updateField("password", trimmed);
376
- }
377
- },
378
- onBlur: () => {
379
- const cur = config.password ?? "";
380
- const trimmed = cur.trim();
381
- if (trimmed !== cur) updateField("password", trimmed);
382
- },
383
- disabled: connected || connecting,
384
- autoComplete: "current-password",
385
- style: { ...inputStyle, paddingRight: 36 }
386
- }
387
- ),
388
- /* @__PURE__ */ jsx(
389
- "button",
390
- {
391
- type: "button",
392
- onClick: () => setShowPassword((p) => !p),
393
- style: {
394
- position: "absolute",
395
- right: 8,
396
- top: "50%",
397
- transform: "translateY(-50%)",
398
- background: "none",
399
- border: "none",
400
- cursor: "pointer",
401
- color: tokens.colors.text.tertiary,
402
- fontSize: tokens.typography.fontSize.xxs,
403
- minHeight: 32,
404
- padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`
405
- },
406
- children: showPassword ? "Hide" : "Show"
407
- }
408
- )
409
- ] })
410
- ] }),
411
- /* @__PURE__ */ jsxs("div", { style: { gridColumn: "1 / -1", ...fieldWrapperStyle }, children: [
412
- /* @__PURE__ */ jsx("label", { htmlFor: `${baseId}-clientId`, style: labelStyle, children: "Client ID" }),
413
- /* @__PURE__ */ jsx(
414
- "input",
415
- {
416
- id: `${baseId}-clientId`,
417
- type: "text",
418
- value: config.clientId || "",
419
- onChange: (e) => updateField("clientId", e.target.value),
420
- disabled: connected || connecting,
421
- placeholder: "auto-generated if empty",
422
- style: inputStyle
423
- }
424
- )
425
- ] })
426
- ] }),
427
- error && /* @__PURE__ */ jsx("div", { style: {
428
- marginTop: tokens.spacing.sm,
429
- padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`,
430
- fontSize: tokens.typography.fontSize.xs,
431
- color: tokens.colors.status.critical,
432
- backgroundColor: `${tokens.colors.status.critical}10`,
433
- border: `1px solid ${tokens.colors.status.critical}20`,
434
- borderRadius: tokens.borderRadius.sm
435
- }, children: error }),
436
- /* @__PURE__ */ jsxs("div", { style: {
437
- display: "flex",
438
- alignItems: "center",
439
- gap: tokens.spacing.sm,
440
- flexDirection: isMobile ? "column" : "row",
441
- marginTop: tokens.spacing.md
442
- }, children: [
443
- /* @__PURE__ */ jsx(
444
- "button",
445
- {
446
- type: "submit",
447
- disabled: connecting || !config.host,
448
- style: {
449
- flex: 1,
450
- padding: compact ? `8px ${tokens.spacing.md}` : `${tokens.spacing.sm} ${tokens.spacing.lg}`,
451
- minHeight: 44,
452
- fontSize: tokens.typography.fontSize.sm,
453
- fontWeight: tokens.typography.fontWeight.semibold,
454
- fontFamily: tokens.typography.fontFamily.primary,
455
- color: tokens.colors.text.inverse || "#fff",
456
- backgroundColor: connected ? tokens.colors.status.critical : tokens.colors.accent.primary,
457
- border: "none",
458
- borderRadius: tokens.borderRadius.md,
459
- cursor: connecting || !config.host ? "not-allowed" : "pointer",
460
- opacity: connecting || !config.host ? 0.6 : 1,
461
- transition: tokens.animation.fast
462
- },
463
- children: connecting ? "Connecting..." : connected ? "Disconnect" : "Connect"
464
- }
465
- ),
466
- parseUrlParams && !connected && /* @__PURE__ */ jsx(
467
- "button",
468
- {
469
- type: "button",
470
- title: "Copy share URL",
471
- onClick: () => {
472
- var _a;
473
- (_a = navigator.clipboard) == null ? void 0 : _a.writeText(getShareUrl());
474
- },
475
- style: {
476
- padding: compact ? "8px" : tokens.spacing.sm,
477
- minHeight: 44,
478
- width: isMobile ? "100%" : "auto",
479
- fontSize: tokens.typography.fontSize.xs,
480
- color: tokens.colors.text.tertiary,
481
- backgroundColor: "transparent",
482
- border: `1px solid ${tokens.colors.border.muted}`,
483
- borderRadius: tokens.borderRadius.md,
484
- cursor: "pointer",
485
- fontFamily: tokens.typography.fontFamily.primary
486
- },
487
- children: "Share"
488
- }
489
- )
490
- ] })
491
- ] });
43
+ var ConnectionForm = memo(function ConnectionForm({ onConnect, onDisconnect, connected = false, connecting = false, defaultProtocol = "wss", defaultHost = "localhost", defaultPort, defaultPath = "/mqtt", showAdvanced = false, persistKey, parseUrlParams = false, error, compact = false, style, labelPlacement = "outlined" }) {
44
+ const { tokens } = useTheme();
45
+ const { isMobile } = useBreakpoint();
46
+ const isOutlined = labelPlacement === "outlined";
47
+ const initialConfig = useMemo(() => {
48
+ if (persistKey) try {
49
+ const saved = localStorage.getItem(persistKey);
50
+ if (saved) return JSON.parse(saved);
51
+ } catch {}
52
+ if (parseUrlParams && typeof window !== "undefined") {
53
+ const params = new URLSearchParams(window.location.search);
54
+ if (params.has("host")) return {
55
+ host: params.get("host") || defaultHost,
56
+ port: parseInt(params.get("port") || String(defaultPort || DEFAULT_PORTS[defaultProtocol])),
57
+ protocol: params.get("protocol") || defaultProtocol,
58
+ path: params.get("path") || defaultPath,
59
+ username: params.get("username") || "",
60
+ password: params.get("password") || "",
61
+ clientId: params.get("clientId") || ""
62
+ };
63
+ }
64
+ return {
65
+ host: defaultHost,
66
+ port: defaultPort || DEFAULT_PORTS[defaultProtocol],
67
+ protocol: defaultProtocol,
68
+ path: defaultPath,
69
+ username: "",
70
+ password: "",
71
+ clientId: ""
72
+ };
73
+ }, []);
74
+ const baseId = useId();
75
+ const passwordInputRef = useRef(null);
76
+ const usernameInputRef = useRef(null);
77
+ const [config, setConfig] = useState(initialConfig);
78
+ const [showAdv, setShowAdv] = useState(showAdvanced);
79
+ const [showPassword, setShowPassword] = useState(false);
80
+ useEffect(() => {
81
+ if (persistKey) try {
82
+ localStorage.setItem(persistKey, JSON.stringify(config));
83
+ } catch {}
84
+ }, [config, persistKey]);
85
+ const updateField = useCallback((key, value) => {
86
+ setConfig((prev) => ({
87
+ ...prev,
88
+ [key]: value
89
+ }));
90
+ }, []);
91
+ const handleProtocolChange = useCallback((protocol) => {
92
+ setConfig((prev) => ({
93
+ ...prev,
94
+ protocol,
95
+ port: prev.port === DEFAULT_PORTS[prev.protocol] ? DEFAULT_PORTS[protocol] : prev.port
96
+ }));
97
+ }, []);
98
+ const handleSubmit = useCallback((e) => {
99
+ e.preventDefault();
100
+ if (!connected) onConnect(config);
101
+ else onDisconnect?.();
102
+ }, [
103
+ config,
104
+ connected,
105
+ onConnect,
106
+ onDisconnect
107
+ ]);
108
+ const getShareUrl = useCallback(() => {
109
+ return `${window.location.origin + window.location.pathname}?${new URLSearchParams({
110
+ host: config.host,
111
+ port: String(config.port),
112
+ protocol: config.protocol,
113
+ ...config.path ? { path: config.path } : {}
114
+ }).toString()}`;
115
+ }, [config]);
116
+ const fullUrl = `${config.protocol}://${config.host}:${config.port}${config.path || ""}`;
117
+ const inputStyle = {
118
+ width: "100%",
119
+ minHeight: compact ? 32 : 40,
120
+ padding: compact ? `6px ${tokens.spacing.sm}` : `${tokens.spacing.sm} ${tokens.spacing.md}`,
121
+ fontSize: tokens.typography.fontSize.sm,
122
+ fontFamily: tokens.typography.fontFamily.primary,
123
+ color: tokens.colors.text.primary,
124
+ backgroundColor: tokens.colors.background.base,
125
+ border: `1px solid ${tokens.colors.border.default}`,
126
+ borderRadius: tokens.borderRadius.md,
127
+ outline: "none",
128
+ transition: tokens.animation.fast,
129
+ boxSizing: "border-box"
130
+ };
131
+ const labelStyle = isOutlined ? {
132
+ position: "absolute",
133
+ top: 0,
134
+ left: "10px",
135
+ transform: "translateY(-50%)",
136
+ backgroundColor: tokens.colors.background.base,
137
+ padding: "0 5px",
138
+ fontSize: tokens.typography.fontSize.xxs,
139
+ fontWeight: tokens.typography.fontWeight.medium,
140
+ color: tokens.colors.text.tertiary,
141
+ textTransform: "uppercase",
142
+ letterSpacing: "0.04em",
143
+ zIndex: 1,
144
+ pointerEvents: "none",
145
+ lineHeight: 1.2,
146
+ whiteSpace: "nowrap"
147
+ } : {
148
+ display: "block",
149
+ fontSize: tokens.typography.fontSize.xxs,
150
+ fontWeight: tokens.typography.fontWeight.medium,
151
+ color: tokens.colors.text.tertiary,
152
+ marginBottom: "4px",
153
+ textTransform: "uppercase",
154
+ letterSpacing: "0.04em"
155
+ };
156
+ const fieldWrapperStyle = isOutlined ? { position: "relative" } : {};
157
+ const statusColor = connected ? tokens.colors.status.normal : error ? tokens.colors.status.critical : tokens.colors.status.off;
158
+ return /* @__PURE__ */ jsxs("form", {
159
+ onSubmit: handleSubmit,
160
+ "aria-label": "Connection configuration",
161
+ style: {
162
+ fontFamily: tokens.typography.fontFamily.primary,
163
+ ...style
164
+ },
165
+ children: [
166
+ /* @__PURE__ */ jsxs("div", {
167
+ "aria-live": "polite",
168
+ style: {
169
+ display: "flex",
170
+ alignItems: "center",
171
+ gap: tokens.spacing.sm,
172
+ flexWrap: "wrap",
173
+ marginBottom: tokens.spacing.md
174
+ },
175
+ children: [
176
+ /* @__PURE__ */ jsx("div", { style: {
177
+ width: 8,
178
+ height: 8,
179
+ borderRadius: "50%",
180
+ backgroundColor: statusColor,
181
+ boxShadow: connected ? `0 0 6px ${statusColor}` : "none",
182
+ transition: tokens.animation.fast
183
+ } }),
184
+ /* @__PURE__ */ jsx("span", {
185
+ style: {
186
+ fontSize: tokens.typography.fontSize.xs,
187
+ color: tokens.colors.text.secondary,
188
+ fontWeight: tokens.typography.fontWeight.medium
189
+ },
190
+ children: connecting ? "Connecting..." : connected ? "Connected" : "Disconnected"
191
+ }),
192
+ /* @__PURE__ */ jsx("div", { style: { flex: 1 } }),
193
+ /* @__PURE__ */ jsx("span", {
194
+ style: {
195
+ fontSize: tokens.typography.fontSize.xxs,
196
+ color: tokens.colors.text.tertiary,
197
+ fontFamily: tokens.typography.fontFamily.mono,
198
+ overflow: "hidden",
199
+ textOverflow: "ellipsis",
200
+ maxWidth: isMobile ? "100%" : 280,
201
+ whiteSpace: isMobile ? "normal" : "nowrap",
202
+ wordBreak: isMobile ? "break-all" : "normal"
203
+ },
204
+ children: fullUrl
205
+ })
206
+ ]
207
+ }),
208
+ /* @__PURE__ */ jsxs("div", {
209
+ style: {
210
+ display: "grid",
211
+ gridTemplateColumns: isMobile ? "1fr" : "minmax(80px, 100px) 1fr minmax(60px, 80px)",
212
+ gap: tokens.spacing.sm
213
+ },
214
+ children: [
215
+ /* @__PURE__ */ jsxs("div", {
216
+ style: fieldWrapperStyle,
217
+ children: [/* @__PURE__ */ jsx("label", {
218
+ htmlFor: `${baseId}-protocol`,
219
+ style: labelStyle,
220
+ children: "Protocol"
221
+ }), /* @__PURE__ */ jsx("select", {
222
+ id: `${baseId}-protocol`,
223
+ value: config.protocol,
224
+ onChange: (e) => handleProtocolChange(e.target.value),
225
+ disabled: connected || connecting,
226
+ style: {
227
+ ...inputStyle,
228
+ cursor: "pointer",
229
+ appearance: "auto"
230
+ },
231
+ children: PROTOCOLS.map((p) => /* @__PURE__ */ jsx("option", {
232
+ value: p,
233
+ children: p.toUpperCase()
234
+ }, p))
235
+ })]
236
+ }),
237
+ /* @__PURE__ */ jsxs("div", {
238
+ style: fieldWrapperStyle,
239
+ children: [/* @__PURE__ */ jsx("label", {
240
+ htmlFor: `${baseId}-host`,
241
+ style: labelStyle,
242
+ children: "Host"
243
+ }), /* @__PURE__ */ jsx("input", {
244
+ id: `${baseId}-host`,
245
+ type: "text",
246
+ value: config.host,
247
+ onChange: (e) => updateField("host", e.target.value),
248
+ disabled: connected || connecting,
249
+ placeholder: "broker.example.com",
250
+ style: inputStyle
251
+ })]
252
+ }),
253
+ /* @__PURE__ */ jsxs("div", {
254
+ style: fieldWrapperStyle,
255
+ children: [/* @__PURE__ */ jsx("label", {
256
+ htmlFor: `${baseId}-port`,
257
+ style: labelStyle,
258
+ children: "Port"
259
+ }), /* @__PURE__ */ jsx("input", {
260
+ id: `${baseId}-port`,
261
+ type: "number",
262
+ value: config.port,
263
+ min: 1,
264
+ max: 65535,
265
+ onChange: (e) => {
266
+ const v = parseInt(e.target.value) || 0;
267
+ updateField("port", Math.max(0, Math.min(65535, v)));
268
+ },
269
+ disabled: connected || connecting,
270
+ style: {
271
+ ...inputStyle,
272
+ fontFamily: tokens.typography.fontFamily.mono
273
+ }
274
+ })]
275
+ })
276
+ ]
277
+ }),
278
+ /* @__PURE__ */ jsxs("div", {
279
+ style: {
280
+ marginTop: tokens.spacing.sm,
281
+ ...fieldWrapperStyle
282
+ },
283
+ children: [/* @__PURE__ */ jsx("label", {
284
+ htmlFor: `${baseId}-path`,
285
+ style: labelStyle,
286
+ children: "Path"
287
+ }), /* @__PURE__ */ jsx("input", {
288
+ id: `${baseId}-path`,
289
+ type: "text",
290
+ value: config.path || "",
291
+ onChange: (e) => updateField("path", e.target.value),
292
+ disabled: connected || connecting,
293
+ placeholder: "/mqtt",
294
+ style: inputStyle
295
+ })]
296
+ }),
297
+ /* @__PURE__ */ jsxs("button", {
298
+ type: "button",
299
+ onClick: () => setShowAdv((p) => !p),
300
+ style: {
301
+ display: "flex",
302
+ alignItems: "center",
303
+ gap: "4px",
304
+ fontSize: tokens.typography.fontSize.xxs,
305
+ color: tokens.colors.text.tertiary,
306
+ backgroundColor: "transparent",
307
+ border: "none",
308
+ cursor: "pointer",
309
+ marginTop: tokens.spacing.sm,
310
+ padding: 0,
311
+ fontFamily: tokens.typography.fontFamily.primary
312
+ },
313
+ children: [/* @__PURE__ */ jsx("svg", {
314
+ width: "12",
315
+ height: "12",
316
+ viewBox: "0 0 24 24",
317
+ fill: "none",
318
+ stroke: "currentColor",
319
+ strokeWidth: "2",
320
+ style: {
321
+ transition: tokens.animation.fast,
322
+ transform: showAdv ? "rotate(90deg)" : "rotate(0)"
323
+ },
324
+ children: /* @__PURE__ */ jsx("polyline", { points: "9 18 15 12 9 6" })
325
+ }), "Advanced"]
326
+ }),
327
+ showAdv && /* @__PURE__ */ jsxs("div", {
328
+ style: {
329
+ marginTop: tokens.spacing.sm,
330
+ display: "grid",
331
+ gridTemplateColumns: isMobile ? "1fr" : "1fr 1fr",
332
+ gap: tokens.spacing.sm
333
+ },
334
+ children: [
335
+ /* @__PURE__ */ jsxs("div", {
336
+ style: fieldWrapperStyle,
337
+ children: [/* @__PURE__ */ jsx("label", {
338
+ htmlFor: `${baseId}-username`,
339
+ style: labelStyle,
340
+ children: "Username"
341
+ }), /* @__PURE__ */ jsx("input", {
342
+ ref: usernameInputRef,
343
+ id: `${baseId}-username`,
344
+ type: "text",
345
+ value: config.username || "",
346
+ onChange: (e) => updateField("username", e.target.value),
347
+ onPaste: (e) => {
348
+ const pasted = e.clipboardData.getData("text");
349
+ const trimmed = pasted.trim();
350
+ const input = usernameInputRef.current;
351
+ if (input) {
352
+ const cur = config.username || "";
353
+ const start = input.selectionStart ?? cur.length;
354
+ const end = input.selectionEnd ?? cur.length;
355
+ const newValue = cur.slice(0, start) + trimmed + cur.slice(end);
356
+ if (trimmed !== pasted || newValue !== cur) {
357
+ e.preventDefault();
358
+ updateField("username", newValue);
359
+ requestAnimationFrame(() => {
360
+ input.setSelectionRange(start + trimmed.length, start + trimmed.length);
361
+ });
362
+ }
363
+ } else if (trimmed !== pasted) {
364
+ e.preventDefault();
365
+ updateField("username", trimmed);
366
+ }
367
+ },
368
+ onBlur: () => {
369
+ const cur = config.username ?? "";
370
+ const trimmed = cur.trim();
371
+ if (trimmed !== cur) updateField("username", trimmed);
372
+ },
373
+ disabled: connected || connecting,
374
+ autoComplete: "username",
375
+ style: inputStyle
376
+ })]
377
+ }),
378
+ /* @__PURE__ */ jsxs("div", {
379
+ style: fieldWrapperStyle,
380
+ children: [/* @__PURE__ */ jsx("label", {
381
+ htmlFor: `${baseId}-password`,
382
+ style: labelStyle,
383
+ children: "Password"
384
+ }), /* @__PURE__ */ jsxs("div", {
385
+ style: { position: "relative" },
386
+ children: [/* @__PURE__ */ jsx("input", {
387
+ ref: passwordInputRef,
388
+ id: `${baseId}-password`,
389
+ type: showPassword ? "text" : "password",
390
+ value: config.password || "",
391
+ onChange: (e) => updateField("password", e.target.value),
392
+ onPaste: (e) => {
393
+ const pasted = e.clipboardData.getData("text");
394
+ const trimmed = pasted.trim();
395
+ const input = passwordInputRef.current;
396
+ if (input) {
397
+ const cur = config.password || "";
398
+ const start = input.selectionStart ?? cur.length;
399
+ const end = input.selectionEnd ?? cur.length;
400
+ const newValue = cur.slice(0, start) + trimmed + cur.slice(end);
401
+ if (trimmed !== pasted || newValue !== cur) {
402
+ e.preventDefault();
403
+ updateField("password", newValue);
404
+ requestAnimationFrame(() => {
405
+ const pos = start + trimmed.length;
406
+ input.setSelectionRange(pos, pos);
407
+ });
408
+ }
409
+ } else if (trimmed !== pasted) {
410
+ e.preventDefault();
411
+ updateField("password", trimmed);
412
+ }
413
+ },
414
+ onBlur: () => {
415
+ const cur = config.password ?? "";
416
+ const trimmed = cur.trim();
417
+ if (trimmed !== cur) updateField("password", trimmed);
418
+ },
419
+ disabled: connected || connecting,
420
+ autoComplete: "current-password",
421
+ style: {
422
+ ...inputStyle,
423
+ paddingRight: 36
424
+ }
425
+ }), /* @__PURE__ */ jsx("button", {
426
+ type: "button",
427
+ onClick: () => setShowPassword((p) => !p),
428
+ style: {
429
+ position: "absolute",
430
+ right: 8,
431
+ top: "50%",
432
+ transform: "translateY(-50%)",
433
+ background: "none",
434
+ border: "none",
435
+ cursor: "pointer",
436
+ color: tokens.colors.text.tertiary,
437
+ fontSize: tokens.typography.fontSize.xxs,
438
+ minHeight: 32,
439
+ padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`
440
+ },
441
+ children: showPassword ? "Hide" : "Show"
442
+ })]
443
+ })]
444
+ }),
445
+ /* @__PURE__ */ jsxs("div", {
446
+ style: {
447
+ gridColumn: "1 / -1",
448
+ ...fieldWrapperStyle
449
+ },
450
+ children: [/* @__PURE__ */ jsx("label", {
451
+ htmlFor: `${baseId}-clientId`,
452
+ style: labelStyle,
453
+ children: "Client ID"
454
+ }), /* @__PURE__ */ jsx("input", {
455
+ id: `${baseId}-clientId`,
456
+ type: "text",
457
+ value: config.clientId || "",
458
+ onChange: (e) => updateField("clientId", e.target.value),
459
+ disabled: connected || connecting,
460
+ placeholder: "auto-generated if empty",
461
+ style: inputStyle
462
+ })]
463
+ })
464
+ ]
465
+ }),
466
+ error && /* @__PURE__ */ jsx("div", {
467
+ style: {
468
+ marginTop: tokens.spacing.sm,
469
+ padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`,
470
+ fontSize: tokens.typography.fontSize.xs,
471
+ color: tokens.colors.status.critical,
472
+ backgroundColor: `${tokens.colors.status.critical}10`,
473
+ border: `1px solid ${tokens.colors.status.critical}20`,
474
+ borderRadius: tokens.borderRadius.sm
475
+ },
476
+ children: error
477
+ }),
478
+ /* @__PURE__ */ jsxs("div", {
479
+ style: {
480
+ display: "flex",
481
+ alignItems: "center",
482
+ gap: tokens.spacing.sm,
483
+ flexDirection: isMobile ? "column" : "row",
484
+ marginTop: tokens.spacing.md
485
+ },
486
+ children: [/* @__PURE__ */ jsx("button", {
487
+ type: "submit",
488
+ disabled: connecting || !config.host,
489
+ style: {
490
+ flex: 1,
491
+ padding: compact ? `8px ${tokens.spacing.md}` : `${tokens.spacing.sm} ${tokens.spacing.lg}`,
492
+ minHeight: 44,
493
+ fontSize: tokens.typography.fontSize.sm,
494
+ fontWeight: tokens.typography.fontWeight.semibold,
495
+ fontFamily: tokens.typography.fontFamily.primary,
496
+ color: tokens.colors.text.inverse || "#fff",
497
+ backgroundColor: connected ? tokens.colors.status.critical : tokens.colors.accent.primary,
498
+ border: "none",
499
+ borderRadius: tokens.borderRadius.md,
500
+ cursor: connecting || !config.host ? "not-allowed" : "pointer",
501
+ opacity: connecting || !config.host ? .6 : 1,
502
+ transition: tokens.animation.fast
503
+ },
504
+ children: connecting ? "Connecting..." : connected ? "Disconnect" : "Connect"
505
+ }), parseUrlParams && !connected && /* @__PURE__ */ jsx("button", {
506
+ type: "button",
507
+ title: "Copy share URL",
508
+ onClick: () => {
509
+ navigator.clipboard?.writeText(getShareUrl());
510
+ },
511
+ style: {
512
+ padding: compact ? "8px" : tokens.spacing.sm,
513
+ minHeight: 44,
514
+ width: isMobile ? "100%" : "auto",
515
+ fontSize: tokens.typography.fontSize.xs,
516
+ color: tokens.colors.text.tertiary,
517
+ backgroundColor: "transparent",
518
+ border: `1px solid ${tokens.colors.border.muted}`,
519
+ borderRadius: tokens.borderRadius.md,
520
+ cursor: "pointer",
521
+ fontFamily: tokens.typography.fontFamily.primary
522
+ },
523
+ children: "Share"
524
+ })]
525
+ })
526
+ ]
527
+ });
492
528
  });
493
- export {
494
- ConnectionForm
495
- };
496
- //# sourceMappingURL=ConnectionForm.js.map
529
+ //#endregion
530
+ export { ConnectionForm, ConnectionForm as default };
531
+
532
+ //# sourceMappingURL=ConnectionForm.js.map