bits-lab 0.0.0-stage → 0.1.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 (323) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +51 -2
  3. package/dist/Accordion.d.ts +52 -0
  4. package/dist/Accordion.js +192 -0
  5. package/dist/AchievementToast.d.ts +36 -0
  6. package/dist/AchievementToast.js +162 -0
  7. package/dist/AgentCard.d.ts +41 -0
  8. package/dist/AgentCard.js +168 -0
  9. package/dist/ArcadeButtons.d.ts +23 -0
  10. package/dist/ArcadeButtons.js +169 -0
  11. package/dist/AuroraBands.d.ts +19 -0
  12. package/dist/AuroraBands.js +126 -0
  13. package/dist/AvatarTooltips.d.ts +32 -0
  14. package/dist/AvatarTooltips.js +121 -0
  15. package/dist/BarRace.d.ts +39 -0
  16. package/dist/BarRace.js +227 -0
  17. package/dist/BentoGrid.d.ts +50 -0
  18. package/dist/BentoGrid.js +145 -0
  19. package/dist/BootSequence.d.ts +48 -0
  20. package/dist/BootSequence.js +234 -0
  21. package/dist/BreadcrumbTrail.d.ts +31 -0
  22. package/dist/BreadcrumbTrail.js +181 -0
  23. package/dist/CRTPower.d.ts +30 -0
  24. package/dist/CRTPower.js +142 -0
  25. package/dist/CardDeck.d.ts +29 -0
  26. package/dist/CardDeck.js +154 -0
  27. package/dist/ChangelogTimeline.d.ts +35 -0
  28. package/dist/ChangelogTimeline.js +137 -0
  29. package/dist/ChapterProgress.d.ts +23 -0
  30. package/dist/ChapterProgress.js +211 -0
  31. package/dist/ChatBubbles.d.ts +42 -0
  32. package/dist/ChatBubbles.js +198 -0
  33. package/dist/ChiptuneKit.d.ts +158 -0
  34. package/dist/ChiptuneKit.js +207 -0
  35. package/dist/CipherCard.d.ts +22 -0
  36. package/dist/CipherCard.js +91 -0
  37. package/dist/CloudSky.d.ts +28 -0
  38. package/dist/CloudSky.js +222 -0
  39. package/dist/CodeRain.d.ts +24 -0
  40. package/dist/CodeRain.js +158 -0
  41. package/dist/CodeShowcase.d.ts +50 -0
  42. package/dist/CodeShowcase.js +307 -0
  43. package/dist/ColorDial.d.ts +42 -0
  44. package/dist/ColorDial.js +288 -0
  45. package/dist/CommandPalette.d.ts +59 -0
  46. package/dist/CommandPalette.js +349 -0
  47. package/dist/CompareSlider.d.ts +33 -0
  48. package/dist/CompareSlider.js +152 -0
  49. package/dist/Confetti.d.ts +61 -0
  50. package/dist/Confetti.js +176 -0
  51. package/dist/ConnectBeams.d.ts +39 -0
  52. package/dist/ConnectBeams.js +132 -0
  53. package/dist/ContextOrb.d.ts +34 -0
  54. package/dist/ContextOrb.js +269 -0
  55. package/dist/ContourLines.d.ts +20 -0
  56. package/dist/ContourLines.js +159 -0
  57. package/dist/Coverflow.d.ts +27 -0
  58. package/dist/Coverflow.js +167 -0
  59. package/dist/CursorAttractor.d.ts +21 -0
  60. package/dist/CursorAttractor.js +136 -0
  61. package/dist/CutReveal.d.ts +21 -0
  62. package/dist/CutReveal.js +116 -0
  63. package/dist/DateRange.d.ts +45 -0
  64. package/dist/DateRange.js +327 -0
  65. package/dist/DeviceFrame.d.ts +30 -0
  66. package/dist/DeviceFrame.js +145 -0
  67. package/dist/DiffReveal.d.ts +36 -0
  68. package/dist/DiffReveal.js +247 -0
  69. package/dist/DirectionHover.d.ts +15 -0
  70. package/dist/DirectionHover.js +90 -0
  71. package/dist/Discard.d.ts +18 -0
  72. package/dist/Discard.js +61 -0
  73. package/dist/DitherField.d.ts +15 -0
  74. package/dist/DitherField.js +157 -0
  75. package/dist/DotGlobe.d.ts +48 -0
  76. package/dist/DotGlobe.js +312 -0
  77. package/dist/DotMap.d.ts +47 -0
  78. package/dist/DotMap.js +172 -0
  79. package/dist/DropZone.d.ts +57 -0
  80. package/dist/DropZone.js +304 -0
  81. package/dist/DynamicIsland.d.ts +32 -0
  82. package/dist/DynamicIsland.js +92 -0
  83. package/dist/EdgeFX.d.ts +27 -0
  84. package/dist/EdgeFX.js +98 -0
  85. package/dist/ElasticString.d.ts +22 -0
  86. package/dist/ElasticString.js +127 -0
  87. package/dist/ExpandCard.d.ts +44 -0
  88. package/dist/ExpandCard.js +182 -0
  89. package/dist/FeatureTabs.d.ts +34 -0
  90. package/dist/FeatureTabs.js +169 -0
  91. package/dist/FeedList.d.ts +37 -0
  92. package/dist/FeedList.js +163 -0
  93. package/dist/FlickerGrid.d.ts +29 -0
  94. package/dist/FlickerGrid.js +156 -0
  95. package/dist/FocusGrid.d.ts +20 -0
  96. package/dist/FocusGrid.js +48 -0
  97. package/dist/FocusPull.d.ts +26 -0
  98. package/dist/FocusPull.js +106 -0
  99. package/dist/Footprints.d.ts +24 -0
  100. package/dist/Footprints.js +126 -0
  101. package/dist/FunnelFlow.d.ts +34 -0
  102. package/dist/FunnelFlow.js +267 -0
  103. package/dist/GameOver.d.ts +46 -0
  104. package/dist/GameOver.js +191 -0
  105. package/dist/GaugeMeter.d.ts +38 -0
  106. package/dist/GaugeMeter.js +195 -0
  107. package/dist/GlassPanel.d.ts +27 -0
  108. package/dist/GlassPanel.js +80 -0
  109. package/dist/GrainFX.d.ts +34 -0
  110. package/dist/GrainFX.js +122 -0
  111. package/dist/GravityBox.d.ts +30 -0
  112. package/dist/GravityBox.js +220 -0
  113. package/dist/HealthBar.d.ts +33 -0
  114. package/dist/HealthBar.js +140 -0
  115. package/dist/Heatmap.d.ts +42 -0
  116. package/dist/Heatmap.js +232 -0
  117. package/dist/HexField.d.ts +29 -0
  118. package/dist/HexField.js +188 -0
  119. package/dist/HoldToConfirm.d.ts +29 -0
  120. package/dist/HoldToConfirm.js +163 -0
  121. package/dist/HorizontalTrack.d.ts +28 -0
  122. package/dist/HorizontalTrack.js +195 -0
  123. package/dist/HotbarDock.d.ts +40 -0
  124. package/dist/HotbarDock.js +148 -0
  125. package/dist/InkText.d.ts +27 -0
  126. package/dist/InkText.js +65 -0
  127. package/dist/InlineEdit.d.ts +30 -0
  128. package/dist/InlineEdit.js +198 -0
  129. package/dist/InteractiveGrid.d.ts +25 -0
  130. package/dist/InteractiveGrid.js +194 -0
  131. package/dist/InventoryGrid.d.ts +45 -0
  132. package/dist/InventoryGrid.js +272 -0
  133. package/dist/JellyBlob.d.ts +30 -0
  134. package/dist/JellyBlob.js +209 -0
  135. package/dist/KineticHeadline.d.ts +30 -0
  136. package/dist/KineticHeadline.js +133 -0
  137. package/dist/LavaLamp.d.ts +21 -0
  138. package/dist/LavaLamp.js +133 -0
  139. package/dist/LetterSwap.d.ts +20 -0
  140. package/dist/LetterSwap.js +78 -0
  141. package/dist/LevelMap.d.ts +35 -0
  142. package/dist/LevelMap.js +189 -0
  143. package/dist/LightShafts.d.ts +22 -0
  144. package/dist/LightShafts.js +170 -0
  145. package/dist/LightboxGallery.d.ts +26 -0
  146. package/dist/LightboxGallery.js +327 -0
  147. package/dist/LinkPeek.d.ts +36 -0
  148. package/dist/LinkPeek.js +194 -0
  149. package/dist/LogoOrbit.d.ts +37 -0
  150. package/dist/LogoOrbit.js +117 -0
  151. package/dist/Marquee.d.ts +33 -0
  152. package/dist/Marquee.js +148 -0
  153. package/dist/MarqueeLine.d.ts +33 -0
  154. package/dist/MarqueeLine.js +167 -0
  155. package/dist/MasonryWall.d.ts +13 -0
  156. package/dist/MasonryWall.js +90 -0
  157. package/dist/MegaMenu.d.ts +32 -0
  158. package/dist/MegaMenu.js +280 -0
  159. package/dist/MeteorShower.d.ts +24 -0
  160. package/dist/MeteorShower.js +155 -0
  161. package/dist/Minimap.d.ts +21 -0
  162. package/dist/Minimap.js +236 -0
  163. package/dist/MobileTabBar.d.ts +38 -0
  164. package/dist/MobileTabBar.js +148 -0
  165. package/dist/MorphDialog.d.ts +34 -0
  166. package/dist/MorphDialog.js +199 -0
  167. package/dist/MorphPopover.d.ts +33 -0
  168. package/dist/MorphPopover.js +168 -0
  169. package/dist/MorphWords.d.ts +18 -0
  170. package/dist/MorphWords.js +136 -0
  171. package/dist/OTPInput.d.ts +43 -0
  172. package/dist/OTPInput.js +174 -0
  173. package/dist/OverlayKit.d.ts +97 -0
  174. package/dist/OverlayKit.js +466 -0
  175. package/dist/OverlayMenu.d.ts +32 -0
  176. package/dist/OverlayMenu.js +154 -0
  177. package/dist/ParallaxCollage.d.ts +41 -0
  178. package/dist/ParallaxCollage.js +143 -0
  179. package/dist/PasswordMeter.d.ts +44 -0
  180. package/dist/PasswordMeter.js +165 -0
  181. package/dist/PegBoard.d.ts +26 -0
  182. package/dist/PegBoard.js +184 -0
  183. package/dist/PinCard.d.ts +21 -0
  184. package/dist/PinCard.js +84 -0
  185. package/dist/PixelAvatar.d.ts +33 -0
  186. package/dist/PixelAvatar.js +144 -0
  187. package/dist/PixelButton.d.ts +20 -0
  188. package/dist/PixelButton.js +128 -0
  189. package/dist/PixelExplode.d.ts +31 -0
  190. package/dist/PixelExplode.js +164 -0
  191. package/dist/PixelLoader.d.ts +32 -0
  192. package/dist/PixelLoader.js +142 -0
  193. package/dist/PixelParallax.d.ts +41 -0
  194. package/dist/PixelParallax.js +151 -0
  195. package/dist/PixelSpinners.d.ts +21 -0
  196. package/dist/PixelSpinners.js +110 -0
  197. package/dist/PixelType.d.ts +26 -0
  198. package/dist/PixelType.js +220 -0
  199. package/dist/PointerKit.d.ts +23 -0
  200. package/dist/PointerKit.js +222 -0
  201. package/dist/Polaroids.d.ts +41 -0
  202. package/dist/Polaroids.js +293 -0
  203. package/dist/PressStart.d.ts +28 -0
  204. package/dist/PressStart.js +99 -0
  205. package/dist/PricingFlip.d.ts +52 -0
  206. package/dist/PricingFlip.js +190 -0
  207. package/dist/ProximityType.d.ts +26 -0
  208. package/dist/ProximityType.js +135 -0
  209. package/dist/QuestDialog.d.ts +50 -0
  210. package/dist/QuestDialog.js +204 -0
  211. package/dist/QuestLog.d.ts +39 -0
  212. package/dist/QuestLog.js +214 -0
  213. package/dist/RangeDual.d.ts +34 -0
  214. package/dist/RangeDual.js +238 -0
  215. package/dist/RatingPips.d.ts +25 -0
  216. package/dist/RatingPips.js +129 -0
  217. package/dist/RetroHorizon.d.ts +27 -0
  218. package/dist/RetroHorizon.js +169 -0
  219. package/dist/Reveal.d.ts +30 -0
  220. package/dist/Reveal.js +92 -0
  221. package/dist/RingProgress.d.ts +45 -0
  222. package/dist/RingProgress.js +180 -0
  223. package/dist/RollingNumber.d.ts +28 -0
  224. package/dist/RollingNumber.js +108 -0
  225. package/dist/ScanScope.d.ts +24 -0
  226. package/dist/ScanScope.js +164 -0
  227. package/dist/ScoreTicker.d.ts +32 -0
  228. package/dist/ScoreTicker.js +176 -0
  229. package/dist/ScreenScroller.d.ts +24 -0
  230. package/dist/ScreenScroller.js +138 -0
  231. package/dist/Screensaver.d.ts +31 -0
  232. package/dist/Screensaver.js +221 -0
  233. package/dist/ScrollTilt.d.ts +27 -0
  234. package/dist/ScrollTilt.js +100 -0
  235. package/dist/ScrollTypography.d.ts +26 -0
  236. package/dist/ScrollTypography.js +124 -0
  237. package/dist/ScrollZoom.d.ts +31 -0
  238. package/dist/ScrollZoom.js +123 -0
  239. package/dist/ScrubNumber.d.ts +29 -0
  240. package/dist/ScrubNumber.js +152 -0
  241. package/dist/ShadowStack.d.ts +28 -0
  242. package/dist/ShadowStack.js +116 -0
  243. package/dist/SideRail.d.ts +43 -0
  244. package/dist/SideRail.js +253 -0
  245. package/dist/SignalText.d.ts +25 -0
  246. package/dist/SignalText.js +178 -0
  247. package/dist/SkeletonShimmer.d.ts +18 -0
  248. package/dist/SkeletonShimmer.js +111 -0
  249. package/dist/SketchHighlight.d.ts +27 -0
  250. package/dist/SketchHighlight.js +180 -0
  251. package/dist/SlideTabs.d.ts +40 -0
  252. package/dist/SlideTabs.js +190 -0
  253. package/dist/SmartNavbar.d.ts +48 -0
  254. package/dist/SmartNavbar.js +188 -0
  255. package/dist/SparkChart.d.ts +41 -0
  256. package/dist/SparkChart.js +188 -0
  257. package/dist/Spoiler.d.ts +22 -0
  258. package/dist/Spoiler.js +97 -0
  259. package/dist/SpotlightTour.d.ts +38 -0
  260. package/dist/SpotlightTour.js +231 -0
  261. package/dist/SpringDrawer.d.ts +39 -0
  262. package/dist/SpringDrawer.js +360 -0
  263. package/dist/SpriteAnimator.d.ts +41 -0
  264. package/dist/SpriteAnimator.js +124 -0
  265. package/dist/StatCard.d.ts +43 -0
  266. package/dist/StatCard.js +168 -0
  267. package/dist/StepLoader.d.ts +41 -0
  268. package/dist/StepLoader.js +191 -0
  269. package/dist/StepperForm.d.ts +41 -0
  270. package/dist/StepperForm.js +206 -0
  271. package/dist/StickerBoard.d.ts +39 -0
  272. package/dist/StickerBoard.js +209 -0
  273. package/dist/StickyReveal.d.ts +42 -0
  274. package/dist/StickyReveal.js +181 -0
  275. package/dist/StoryViewer.d.ts +36 -0
  276. package/dist/StoryViewer.js +175 -0
  277. package/dist/StreamingText.d.ts +29 -0
  278. package/dist/StreamingText.js +271 -0
  279. package/dist/SuggestionChips.d.ts +32 -0
  280. package/dist/SuggestionChips.js +96 -0
  281. package/dist/SwipeActions.d.ts +30 -0
  282. package/dist/SwipeActions.js +141 -0
  283. package/dist/TagInput.d.ts +30 -0
  284. package/dist/TagInput.js +284 -0
  285. package/dist/TallyUp.d.ts +38 -0
  286. package/dist/TallyUp.js +157 -0
  287. package/dist/TerminalDemo.d.ts +63 -0
  288. package/dist/TerminalDemo.js +214 -0
  289. package/dist/TestimonialWall.d.ts +35 -0
  290. package/dist/TestimonialWall.js +131 -0
  291. package/dist/TextOnPath.d.ts +36 -0
  292. package/dist/TextOnPath.js +130 -0
  293. package/dist/ThinkingShimmer.d.ts +36 -0
  294. package/dist/ThinkingShimmer.js +132 -0
  295. package/dist/ToastStack.d.ts +62 -0
  296. package/dist/ToastStack.js +289 -0
  297. package/dist/ToggleGroup.d.ts +39 -0
  298. package/dist/ToggleGroup.js +190 -0
  299. package/dist/ToggleKit.d.ts +70 -0
  300. package/dist/ToggleKit.js +229 -0
  301. package/dist/TracingLine.d.ts +24 -0
  302. package/dist/TracingLine.js +139 -0
  303. package/dist/TradingCard.d.ts +30 -0
  304. package/dist/TradingCard.js +147 -0
  305. package/dist/VanishInput.d.ts +34 -0
  306. package/dist/VanishInput.js +190 -0
  307. package/dist/VideoHero.d.ts +32 -0
  308. package/dist/VideoHero.js +207 -0
  309. package/dist/VoiceOrb.d.ts +23 -0
  310. package/dist/VoiceOrb.js +182 -0
  311. package/dist/VoxelTiles.d.ts +38 -0
  312. package/dist/VoxelTiles.js +201 -0
  313. package/dist/WarpField.d.ts +18 -0
  314. package/dist/WarpField.js +160 -0
  315. package/dist/WebcamPixels.d.ts +38 -0
  316. package/dist/WebcamPixels.js +292 -0
  317. package/dist/WheelPicker.d.ts +29 -0
  318. package/dist/WheelPicker.js +199 -0
  319. package/dist/WobbleCard.d.ts +23 -0
  320. package/dist/WobbleCard.js +112 -0
  321. package/dist/index.d.ts +158 -0
  322. package/dist/index.js +159 -0
  323. package/package.json +34 -4
@@ -0,0 +1,168 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useId, useInsertionEffect, useRef, useState } from "react";
4
+ const STYLE_ID = "bl-agent-card";
5
+ const CSS = `
6
+ .bl-agent { width: 100%; max-width: var(--bl-w); overflow: hidden; border-radius: var(--bl-radius); background: var(--bl-bg); color: var(--bl-ink); font-family: var(--bl-font); box-shadow: 0 0 0 1px var(--bl-line); transition: box-shadow 300ms; }
7
+ .bl-agent[data-status="running"] { box-shadow: 0 0 0 1px var(--bl-accent), 0 0 24px -8px var(--bl-accent); }
8
+ .bl-agent[data-status="error"] { box-shadow: 0 0 0 1px var(--bl-error); }
9
+ .bl-agent__head { display: flex; align-items: center; gap: 10px; width: 100%; padding: 12px 14px; border: 0; background: transparent; color: inherit; font: inherit; text-align: left; cursor: pointer; }
10
+ .bl-agent__head:focus-visible { outline: 2px solid var(--bl-accent); outline-offset: -2px; }
11
+ .bl-agent__icon { position: relative; display: grid; place-items: center; flex: 0 0 auto; width: 26px; height: 26px; border-radius: 8px; background: var(--bl-chip); color: var(--bl-muted); }
12
+ .bl-agent[data-status="success"] .bl-agent__icon { background: color-mix(in srgb, var(--bl-ok) 22%, transparent); color: var(--bl-ok); }
13
+ .bl-agent[data-status="error"] .bl-agent__icon { background: color-mix(in srgb, var(--bl-error) 22%, transparent); color: var(--bl-error); }
14
+ .bl-agent__spin { position: absolute; inset: 3px; border-radius: 50%; border: 2px solid color-mix(in srgb, var(--bl-accent) 25%, transparent); border-top-color: var(--bl-accent); animation: bl-agent-spin 800ms linear infinite; }
15
+ .bl-agent__title { display: grid; flex: 1; min-width: 0; gap: 1px; }
16
+ .bl-agent__tool { font-family: var(--bl-mono); font-size: 13px; font-weight: 700; }
17
+ .bl-agent__args { overflow: hidden; color: var(--bl-muted); font-family: var(--bl-mono); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
18
+ .bl-agent__meta { flex: 0 0 auto; color: var(--bl-muted); font-size: 12px; font-variant-numeric: tabular-nums; }
19
+ .bl-agent__chev { flex: 0 0 auto; color: var(--bl-muted); transition: transform 220ms; }
20
+ .bl-agent__head[aria-expanded="true"] .bl-agent__chev { transform: rotate(180deg); }
21
+ .bl-agent__body { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 260ms cubic-bezier(.2,.9,.25,1); }
22
+ .bl-agent__body[data-open] { grid-template-rows: 1fr; }
23
+ .bl-agent__inner { min-height: 0; overflow: hidden; }
24
+ .bl-agent__logs { max-height: var(--bl-log-h); margin: 0 14px; padding: 10px 12px; overflow-y: auto; border-radius: 10px; background: var(--bl-code); font-family: var(--bl-mono); font-size: 12px; line-height: 1.6; list-style: none; }
25
+ .bl-agent__logs li { color: var(--bl-muted); white-space: pre-wrap; overflow-wrap: anywhere; animation: bl-agent-line 260ms ease both; }
26
+ .bl-agent__logs li::before { content: "\u203A "; color: var(--bl-dim); }
27
+ .bl-agent__out { margin: 10px 14px 14px; padding: 10px 12px; border-radius: 10px; background: color-mix(in srgb, var(--bl-ok) 10%, transparent); font-size: 13px; line-height: 1.5; }
28
+ .bl-agent__out[data-error] { background: color-mix(in srgb, var(--bl-error) 12%, transparent); color: var(--bl-error); }
29
+ .bl-agent__out pre { margin: 0; font-family: var(--bl-mono); font-size: 12px; white-space: pre-wrap; overflow-wrap: anywhere; }
30
+ .bl-agent__empty { padding: 10px 14px 14px; color: var(--bl-dim); font-size: 13px; }
31
+ .bl-agent__sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
32
+ @keyframes bl-agent-spin { to { transform: rotate(360deg); } }
33
+ @keyframes bl-agent-line { from { opacity: 0; transform: translateY(4px); } }
34
+ @media (prefers-reduced-motion: reduce) { .bl-agent__spin { animation-duration: 2.4s; } .bl-agent__logs li { animation: none; } .bl-agent__body, .bl-agent__chev { transition: none; } }
35
+ `;
36
+ function useStyles() {
37
+ useInsertionEffect(() => {
38
+ if (typeof document === "undefined") return;
39
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
40
+ style.textContent = CSS;
41
+ if (!style.isConnected) document.head.appendChild(style);
42
+ }, []);
43
+ }
44
+ const summarize = (args) => {
45
+ if (args == null) return "";
46
+ if (typeof args === "string") return args;
47
+ return Object.entries(args).map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join(", ");
48
+ };
49
+ const seconds = (ms) => ms < 1e3 ? `${Math.round(ms)}ms` : `${(ms / 1e3).toFixed(ms < 1e4 ? 1 : 0)}s`;
50
+ const ICONS = {
51
+ success: "M3 8.5 6.5 12 13 4.5",
52
+ error: "M4 4l8 8M12 4l-8 8",
53
+ queued: "M8 4v4l2.5 2.5"
54
+ };
55
+ function AgentCard({
56
+ tool = "tool",
57
+ args,
58
+ status = "running",
59
+ startedAt,
60
+ duration,
61
+ logs = [],
62
+ result,
63
+ error,
64
+ icon,
65
+ defaultOpen = false,
66
+ open: controlledOpen,
67
+ onOpenChange,
68
+ width = 520,
69
+ logHeight = 160,
70
+ backgroundColor = "#1a1c2c",
71
+ chipColor = "#262b44",
72
+ codeColor = "#0b0b14",
73
+ textColor = "#f4f4f4",
74
+ mutedColor = "#94b0c2",
75
+ dimColor = "#566c86",
76
+ lineColor = "#333c57",
77
+ accentColor = "#73eff7",
78
+ okColor = "#38b764",
79
+ errorColor = "#ef7d57",
80
+ radius = 14,
81
+ fontFamily = "ui-sans-serif, system-ui, sans-serif",
82
+ monoFamily = "ui-monospace, SFMono-Regular, Menlo, monospace",
83
+ className = "",
84
+ style
85
+ }) {
86
+ useStyles();
87
+ const uid = useId().replace(/[^a-zA-Z0-9_-]/g, "");
88
+ const [innerOpen, setInnerOpen] = useState(defaultOpen);
89
+ const open = controlledOpen ?? innerOpen;
90
+ const [now, setNow] = useState(() => Date.now());
91
+ const logRef = useRef(null);
92
+ const stick = useRef(true);
93
+ useEffect(() => {
94
+ if (status !== "running") return void 0;
95
+ const timer = setInterval(() => setNow(Date.now()), 100);
96
+ return () => clearInterval(timer);
97
+ }, [status]);
98
+ useEffect(() => {
99
+ const node = logRef.current;
100
+ if (node && stick.current) node.scrollTop = node.scrollHeight;
101
+ }, [logs.length, open]);
102
+ const toggle = () => {
103
+ if (controlledOpen === void 0) setInnerOpen((o) => !o);
104
+ onOpenChange?.(!open);
105
+ };
106
+ const elapsed = duration ?? (startedAt ? Math.max(0, now - startedAt) : null);
107
+ const meta = status === "queued" ? "Queued" : status === "running" ? elapsed != null ? seconds(elapsed) : "Running" : status === "success" ? elapsed != null ? `Done in ${seconds(elapsed)}` : "Done" : elapsed != null ? `Failed after ${seconds(elapsed)}` : "Failed";
108
+ const statusText = { queued: "queued", running: "running", success: "finished", error: "failed" }[status];
109
+ return /* @__PURE__ */ jsxs(
110
+ "article",
111
+ {
112
+ className: `bl-agent ${className}`,
113
+ "data-status": status,
114
+ "aria-labelledby": `${uid}-tool`,
115
+ style: {
116
+ "--bl-w": `${width}px`,
117
+ "--bl-log-h": `${logHeight}px`,
118
+ "--bl-bg": backgroundColor,
119
+ "--bl-chip": chipColor,
120
+ "--bl-code": codeColor,
121
+ "--bl-ink": textColor,
122
+ "--bl-muted": mutedColor,
123
+ "--bl-dim": dimColor,
124
+ "--bl-line": lineColor,
125
+ "--bl-accent": accentColor,
126
+ "--bl-ok": okColor,
127
+ "--bl-error": errorColor,
128
+ "--bl-radius": `${radius}px`,
129
+ "--bl-font": fontFamily,
130
+ "--bl-mono": monoFamily,
131
+ ...style
132
+ },
133
+ children: [
134
+ /* @__PURE__ */ jsxs("button", { type: "button", className: "bl-agent__head", "aria-expanded": open, "aria-controls": `${uid}-body`, onClick: toggle, children: [
135
+ /* @__PURE__ */ jsx("span", { className: "bl-agent__icon", "aria-hidden": "true", children: status === "running" ? /* @__PURE__ */ jsx("span", { className: "bl-agent__spin" }) : status === "queued" && icon ? icon : /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: ICONS[status] ?? ICONS.queued }) }) }),
136
+ /* @__PURE__ */ jsxs("span", { className: "bl-agent__title", children: [
137
+ /* @__PURE__ */ jsx("span", { id: `${uid}-tool`, className: "bl-agent__tool", children: tool }),
138
+ args != null && /* @__PURE__ */ jsx("span", { className: "bl-agent__args", children: summarize(args) })
139
+ ] }),
140
+ /* @__PURE__ */ jsx("span", { className: "bl-agent__meta", children: meta }),
141
+ /* @__PURE__ */ jsx("svg", { className: "bl-agent__chev", width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M3 4.5 6 7.5 9 4.5" }) })
142
+ ] }),
143
+ /* @__PURE__ */ jsx("div", { id: `${uid}-body`, className: "bl-agent__body", "data-open": open || void 0, inert: open ? void 0 : true, children: /* @__PURE__ */ jsxs("div", { className: "bl-agent__inner", children: [
144
+ logs.length > 0 ? /* @__PURE__ */ jsx(
145
+ "ol",
146
+ {
147
+ ref: logRef,
148
+ className: "bl-agent__logs",
149
+ "aria-label": "Logs",
150
+ tabIndex: 0,
151
+ onScroll: (event) => {
152
+ const node = event.currentTarget;
153
+ stick.current = node.scrollTop + node.clientHeight >= node.scrollHeight - 8;
154
+ },
155
+ children: logs.map((line, i) => /* @__PURE__ */ jsx("li", { children: line }, i))
156
+ }
157
+ ) : /* @__PURE__ */ jsx("p", { className: "bl-agent__empty", children: status === "queued" ? "Waiting to start\u2026" : "No logs." }),
158
+ status === "error" && error && /* @__PURE__ */ jsx("div", { className: "bl-agent__out", "data-error": "", children: typeof error === "string" ? /* @__PURE__ */ jsx("pre", { children: error }) : error }),
159
+ status === "success" && result != null && /* @__PURE__ */ jsx("div", { className: "bl-agent__out", children: typeof result === "string" ? /* @__PURE__ */ jsx("pre", { children: result }) : result })
160
+ ] }) }),
161
+ /* @__PURE__ */ jsx("span", { className: "bl-agent__sr", "aria-live": "polite", children: `${tool} ${statusText}${status === "error" && typeof error === "string" ? `: ${error.split("\n")[0]}` : ""}` })
162
+ ]
163
+ }
164
+ );
165
+ }
166
+ export {
167
+ AgentCard as default
168
+ };
@@ -0,0 +1,23 @@
1
+ import { type CSSProperties, type MouseEvent as ReactMouseEvent, type ReactNode } from 'react';
2
+ export interface ArcadeButtonsProps {
3
+ children?: ReactNode;
4
+ /** Blast off and drop back in, hop away from the pointer, or stretch like a slingshot. */
5
+ behavior?: 'launch' | 'dodge' | 'sling';
6
+ /** Launch calls it at lift-off; sling on a far enough release (without an event). */
7
+ onClick?: (event?: ReactMouseEvent<HTMLButtonElement>) => void;
8
+ /** Dodges before giving in. */
9
+ maxDodges?: number;
10
+ /** How close the pointer gets before it dodges, in px. */
11
+ dodgeRadius?: number;
12
+ /** How far the sling stretches, in px. */
13
+ pull?: number;
14
+ disabled?: boolean;
15
+ color?: string;
16
+ textColor?: string;
17
+ smokeColor?: string;
18
+ accentColor?: string;
19
+ fontFamily?: string;
20
+ className?: string;
21
+ style?: CSSProperties;
22
+ }
23
+ export default function ArcadeButtons({ children, behavior, onClick, maxDodges, dodgeRadius, pull, disabled, color, textColor, smokeColor, accentColor, fontFamily, className, style }: ArcadeButtonsProps): import("react").JSX.Element;
@@ -0,0 +1,169 @@
1
+ 'use client';
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useInsertionEffect, useRef, useState } from "react";
4
+ const STYLE_ID = "bl-arcade-buttons";
5
+ const CSS = `
6
+ .bl-arcade { position: relative; display: inline-block; transform: translate(var(--dx), var(--dy)); transition: transform 260ms cubic-bezier(.3,1.5,.5,1); }
7
+ .bl-arcade__btn { position: relative; display: inline-flex; align-items: center; gap: 8px; padding: 12px 22px; border: 0; border-radius: 4px; background: var(--bl-bg); color: var(--bl-ink); font: inherit; font-family: var(--bl-font); font-size: 15px; font-weight: 700; cursor: pointer; box-shadow: inset -4px -4px 0 rgba(0,0,0,0.3), inset 4px 4px 0 rgba(255,255,255,0.25), 0 4px 0 rgba(0,0,0,0.45); touch-action: none; user-select: none; transform: translate(var(--sx, 0px), var(--sy, 0px)) scale(var(--scx, 1), var(--scy, 1)); transition: transform 420ms cubic-bezier(.3,1.8,.4,1); }
8
+ .bl-arcade__btn:active { box-shadow: inset 4px 4px 0 rgba(0,0,0,0.3), 0 1px 0 rgba(0,0,0,0.45); translate: 0 3px; }
9
+ .bl-arcade__btn:focus-visible { outline: 2px solid var(--bl-accent); outline-offset: 3px; }
10
+ .bl-arcade__btn:disabled { opacity: 0.5; cursor: not-allowed; }
11
+ .bl-arcade[data-state="rumble"] .bl-arcade__btn { animation: bl-arcade-rumble 70ms steps(2) infinite; }
12
+ .bl-arcade[data-state="flying"] .bl-arcade__btn { animation: bl-arcade-launch 520ms cubic-bezier(.5,0,.9,.4) forwards; }
13
+ .bl-arcade[data-state="landing"] .bl-arcade__btn { animation: bl-arcade-land 420ms cubic-bezier(.2,1.4,.4,1) both; }
14
+ .bl-arcade__smoke { position: absolute; left: 50%; bottom: -6px; width: 10px; height: 10px; margin-left: -5px; background: var(--bl-smoke); opacity: 0; pointer-events: none; }
15
+ .bl-arcade[data-state="flying"] .bl-arcade__smoke { animation: bl-arcade-puff 600ms steps(5) forwards; }
16
+ .bl-arcade[data-state="flying"] .bl-arcade__smoke:nth-child(2) { --side: -1; animation-delay: 60ms; }
17
+ .bl-arcade[data-state="flying"] .bl-arcade__smoke:nth-child(3) { --side: 1; animation-delay: 120ms; }
18
+ .bl-arcade[data-pulling] { transition: none; }
19
+ .bl-arcade[data-pulling] .bl-arcade__btn { transition: none; }
20
+ @keyframes bl-arcade-rumble { 50% { transform: translate(1px, -1px); } }
21
+ @keyframes bl-arcade-launch { to { transform: translateY(-140vh) scaleY(1.2); } }
22
+ @keyframes bl-arcade-land { from { transform: translateY(-60px); opacity: 0; } }
23
+ @keyframes bl-arcade-puff { 0% { opacity: 0.9; transform: scale(0.6); } 100% { opacity: 0; transform: translate(calc(var(--side, 0) * 18px), 10px) scale(2.4); } }
24
+ @media (prefers-reduced-motion: reduce) { .bl-arcade, .bl-arcade__btn { transition: none !important; animation: none !important; transform: none !important; } .bl-arcade__smoke { display: none; } }
25
+ `;
26
+ function useStyles() {
27
+ useInsertionEffect(() => {
28
+ if (typeof document === "undefined") return;
29
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
30
+ style.textContent = CSS;
31
+ if (!style.isConnected) document.head.appendChild(style);
32
+ }, []);
33
+ }
34
+ function ArcadeButtons({
35
+ children,
36
+ behavior = "launch",
37
+ onClick,
38
+ maxDodges = 5,
39
+ dodgeRadius = 70,
40
+ pull = 90,
41
+ disabled = false,
42
+ color = "#b13e53",
43
+ textColor = "#f4f4f4",
44
+ smokeColor = "#94b0c2",
45
+ accentColor = "#73eff7",
46
+ fontFamily = "inherit",
47
+ className = "",
48
+ style
49
+ }) {
50
+ useStyles();
51
+ const wrapRef = useRef(null);
52
+ const btnRef = useRef(null);
53
+ const [offset, setOffset] = useState({ x: 0, y: 0 });
54
+ const [state, setState] = useState("idle");
55
+ const dodges = useRef(0);
56
+ const timers = useRef([]);
57
+ const clickRef = useRef(onClick);
58
+ clickRef.current = onClick;
59
+ const reduced = () => window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
60
+ useEffect(() => () => timers.current.forEach(clearTimeout), []);
61
+ useEffect(() => {
62
+ if (behavior !== "dodge") return void 0;
63
+ dodges.current = 0;
64
+ setOffset({ x: 0, y: 0 });
65
+ const onMove = (event) => {
66
+ if (event.pointerType !== "mouse" || dodges.current >= maxDodges || reduced()) return;
67
+ const r = btnRef.current.getBoundingClientRect();
68
+ const dx = event.clientX - (r.left + r.width / 2);
69
+ const dy = event.clientY - (r.top + r.height / 2);
70
+ if (Math.hypot(dx / (r.width / 2 + dodgeRadius), dy / (r.height / 2 + dodgeRadius)) > 1) return;
71
+ dodges.current += 1;
72
+ const away = Math.atan2(-dy, -dx) + (Math.random() - 0.5) * 1.2;
73
+ setOffset((o) => {
74
+ const nx = o.x + Math.cos(away) * (r.width * 0.9);
75
+ const ny = o.y + Math.sin(away) * (r.height * 1.6);
76
+ const len = Math.hypot(nx, ny);
77
+ const max = r.width * 1.6;
78
+ return len > max ? { x: nx / len * max * 0.5, y: ny / len * max * 0.5 } : { x: nx, y: ny };
79
+ });
80
+ };
81
+ window.addEventListener("pointermove", onMove, { passive: true });
82
+ return () => window.removeEventListener("pointermove", onMove);
83
+ }, [behavior, maxDodges, dodgeRadius]);
84
+ useEffect(() => {
85
+ if (behavior !== "sling") return void 0;
86
+ const btn = btnRef.current;
87
+ const wrap = wrapRef.current;
88
+ let drag = null;
89
+ const paint = (x, y) => {
90
+ const d = Math.min(1, Math.hypot(x, y) / pull);
91
+ btn.style.setProperty("--sx", `${x}px`);
92
+ btn.style.setProperty("--sy", `${y}px`);
93
+ btn.style.setProperty("--scx", (1 + d * 0.25).toFixed(3));
94
+ btn.style.setProperty("--scy", (1 - d * 0.18).toFixed(3));
95
+ };
96
+ const onDown = (event) => {
97
+ if (event.button > 0 || reduced() || btn.disabled) return;
98
+ drag = { x: event.clientX, y: event.clientY, far: false };
99
+ btn.setPointerCapture?.(event.pointerId);
100
+ wrap.dataset.pulling = "";
101
+ };
102
+ const onMove = (event) => {
103
+ if (!drag) return;
104
+ let x = event.clientX - drag.x;
105
+ let y = event.clientY - drag.y;
106
+ const len = Math.hypot(x, y);
107
+ const k = len > 0 ? pull * (1 - Math.exp(-len / pull)) / len : 0;
108
+ x *= k;
109
+ y *= k;
110
+ drag.far = len > pull * 0.8;
111
+ paint(x, y);
112
+ };
113
+ const onUp = () => {
114
+ if (!drag) return;
115
+ const far = drag.far;
116
+ drag = null;
117
+ delete wrap.dataset.pulling;
118
+ paint(0, 0);
119
+ if (far) clickRef.current?.();
120
+ };
121
+ btn.addEventListener("pointerdown", onDown);
122
+ btn.addEventListener("pointermove", onMove);
123
+ btn.addEventListener("pointerup", onUp);
124
+ btn.addEventListener("pointercancel", onUp);
125
+ return () => {
126
+ btn.removeEventListener("pointerdown", onDown);
127
+ btn.removeEventListener("pointermove", onMove);
128
+ btn.removeEventListener("pointerup", onUp);
129
+ btn.removeEventListener("pointercancel", onUp);
130
+ };
131
+ }, [behavior, pull]);
132
+ const handleClick = (event) => {
133
+ if (behavior === "launch" && !reduced()) {
134
+ if (state !== "idle") return;
135
+ setState("rumble");
136
+ timers.current = [
137
+ setTimeout(() => {
138
+ setState("flying");
139
+ clickRef.current?.(event);
140
+ }, 380),
141
+ setTimeout(() => setState("landing"), 1500),
142
+ setTimeout(() => setState("idle"), 1950)
143
+ ];
144
+ return;
145
+ }
146
+ if (behavior === "sling" && event.detail > 0 && !reduced()) return;
147
+ clickRef.current?.(event);
148
+ };
149
+ return /* @__PURE__ */ jsxs(
150
+ "span",
151
+ {
152
+ ref: wrapRef,
153
+ className: `bl-arcade ${className}`,
154
+ "data-state": state,
155
+ style: { "--dx": `${offset.x}px`, "--dy": `${offset.y}px`, "--bl-bg": color, "--bl-ink": textColor, "--bl-smoke": smokeColor, "--bl-accent": accentColor, "--bl-font": fontFamily, ...style },
156
+ children: [
157
+ /* @__PURE__ */ jsx("button", { ref: btnRef, type: "button", className: "bl-arcade__btn", disabled, onClick: handleClick, children }),
158
+ behavior === "launch" && /* @__PURE__ */ jsxs(Fragment, { children: [
159
+ /* @__PURE__ */ jsx("span", { className: "bl-arcade__smoke", "aria-hidden": "true" }),
160
+ /* @__PURE__ */ jsx("span", { className: "bl-arcade__smoke", "aria-hidden": "true" }),
161
+ /* @__PURE__ */ jsx("span", { className: "bl-arcade__smoke", "aria-hidden": "true" })
162
+ ] })
163
+ ]
164
+ }
165
+ );
166
+ }
167
+ export {
168
+ ArcadeButtons as default
169
+ };
@@ -0,0 +1,19 @@
1
+ import { type CSSProperties } from 'react';
2
+ export interface AuroraBandsProps {
3
+ /** One colour per curtain (cycled). */
4
+ colors?: string[];
5
+ /** How many curtains. */
6
+ ribbons?: number;
7
+ speed?: number;
8
+ /** How many flat light steps the glow is drawn in. */
9
+ bands?: number;
10
+ /** Curtain height as a share of the sky. */
11
+ height?: number;
12
+ pixelSize?: number;
13
+ stars?: number;
14
+ skyTop?: string;
15
+ skyBottom?: string;
16
+ className?: string;
17
+ style?: CSSProperties;
18
+ }
19
+ export default function AuroraBands({ colors, ribbons, speed, bands, height, pixelSize, stars, skyTop, skyBottom, className, style }: AuroraBandsProps): import("react").JSX.Element;
@@ -0,0 +1,126 @@
1
+ 'use client';
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useEffect, useRef } from "react";
4
+ const hexToRgb = (hex) => {
5
+ const n = parseInt(hex.replace("#", "").replace(/^(.)(.)(.)$/, "$1$1$2$2$3$3"), 16);
6
+ return [n >> 16 & 255, n >> 8 & 255, n & 255];
7
+ };
8
+ function AuroraBands({
9
+ colors = ["#38b764", "#73eff7", "#b13e53"],
10
+ ribbons = 3,
11
+ speed = 1,
12
+ bands = 5,
13
+ height = 0.38,
14
+ pixelSize = 4,
15
+ stars = 70,
16
+ skyTop = "#0b0b14",
17
+ skyBottom = "#1a1c2c",
18
+ className = "",
19
+ style
20
+ }) {
21
+ const canvasRef = useRef(null);
22
+ useEffect(() => {
23
+ const canvas = canvasRef.current;
24
+ const ctx = canvas.getContext("2d");
25
+ const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
26
+ const tints = colors.map(hexToRgb);
27
+ const top = hexToRgb(skyTop);
28
+ const bottom = hexToRgb(skyBottom);
29
+ let w = 0;
30
+ let h = 0;
31
+ let img = null;
32
+ let sky = [];
33
+ let field = [];
34
+ let t = 3;
35
+ let raf = 0;
36
+ let last = 0;
37
+ let visible = true;
38
+ const fit = () => {
39
+ w = Math.max(1, Math.ceil(canvas.clientWidth / pixelSize));
40
+ h = Math.max(1, Math.ceil(canvas.clientHeight / pixelSize));
41
+ canvas.width = w;
42
+ canvas.height = h;
43
+ img = ctx.createImageData(w, h);
44
+ sky = Array.from({ length: h }, (_, y) => top.map((c, k) => c + (bottom[k] - c) * (y / h)));
45
+ field = Array.from({ length: stars }, (_, i) => ({ x: Math.floor((Math.sin(i * 12.9898) * 0.5 + 0.5) * w), y: Math.floor((Math.sin(i * 78.233) * 0.5 + 0.5) * h * 0.8), phase: i }));
46
+ };
47
+ const frame = () => {
48
+ const d = img.data;
49
+ for (let y = 0; y < h; y++) {
50
+ const [r, g, b] = sky[y];
51
+ for (let x = 0; x < w; x++) {
52
+ const i = (y * w + x) * 4;
53
+ d[i] = r;
54
+ d[i + 1] = g;
55
+ d[i + 2] = b;
56
+ d[i + 3] = 255;
57
+ }
58
+ }
59
+ field.forEach((s) => {
60
+ const twinkle = 0.5 + 0.5 * Math.sin(t * 2 + s.phase);
61
+ const i = (s.y * w + s.x) * 4;
62
+ const v = 120 + twinkle * 135;
63
+ d[i] = v;
64
+ d[i + 1] = v;
65
+ d[i + 2] = v;
66
+ });
67
+ for (let r = 0; r < ribbons; r++) {
68
+ const [cr, cg, cb] = tints[r % tints.length];
69
+ for (let x = 0; x < w; x++) {
70
+ const u = x / w;
71
+ const centre = h * (0.32 + r * 0.1 + 0.1 * Math.sin(u * 5 + t * 0.5 + r * 1.9) + 0.05 * Math.sin(u * 13 - t * 0.9 + r));
72
+ const thick = h * height * (0.5 + 0.25 * Math.sin(u * 7 + t * 0.7 + r * 2.3));
73
+ const streak = 0.65 + 0.35 * Math.sin(x * 0.9 + t * 3 + r * 5) * Math.sin(x * 0.23 - t);
74
+ for (let y = 0; y < h; y++) {
75
+ const dy = (y - centre) / thick;
76
+ let v = dy > 0 ? Math.exp(-dy * dy * 9) : Math.exp(dy * 1.6);
77
+ v *= streak;
78
+ if (v < 0.08) continue;
79
+ const level = Math.floor(v * bands) / bands;
80
+ if (!level) continue;
81
+ const i = (y * w + x) * 4;
82
+ d[i] = Math.min(255, d[i] + cr * level);
83
+ d[i + 1] = Math.min(255, d[i + 1] + cg * level);
84
+ d[i + 2] = Math.min(255, d[i + 2] + cb * level);
85
+ }
86
+ }
87
+ }
88
+ ctx.putImageData(img, 0, 0);
89
+ };
90
+ const tick = (now) => {
91
+ t += Math.max(0, Math.min(0.05, (now - last) / 1e3)) * speed;
92
+ last = now;
93
+ frame();
94
+ raf = visible && !document.hidden ? requestAnimationFrame(tick) : 0;
95
+ };
96
+ const start = () => {
97
+ if (raf || reduced || !visible || document.hidden) return;
98
+ last = performance.now();
99
+ raf = requestAnimationFrame(tick);
100
+ };
101
+ const resize = new ResizeObserver(() => {
102
+ fit();
103
+ frame();
104
+ });
105
+ resize.observe(canvas);
106
+ const observer = new IntersectionObserver(([entry]) => {
107
+ visible = entry.isIntersecting;
108
+ start();
109
+ });
110
+ observer.observe(canvas);
111
+ document.addEventListener("visibilitychange", start);
112
+ fit();
113
+ frame();
114
+ start();
115
+ return () => {
116
+ cancelAnimationFrame(raf);
117
+ resize.disconnect();
118
+ observer.disconnect();
119
+ document.removeEventListener("visibilitychange", start);
120
+ };
121
+ }, [colors.join(), ribbons, speed, bands, height, pixelSize, stars, skyTop, skyBottom]);
122
+ return /* @__PURE__ */ jsx("canvas", { ref: canvasRef, "aria-hidden": "true", className, style: { display: "block", width: "100%", height: "100%", background: skyTop, imageRendering: "pixelated", ...style } });
123
+ }
124
+ export {
125
+ AuroraBands as default
126
+ };
@@ -0,0 +1,32 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export interface StackPerson {
3
+ id?: string;
4
+ name: string;
5
+ role?: string;
6
+ /** An image URL or any node; initials are used otherwise. */
7
+ avatar?: ReactNode;
8
+ }
9
+ export interface AvatarTooltipsProps {
10
+ people?: StackPerson[];
11
+ /** Visible avatars; the rest fold into a "+N" chip. */
12
+ max?: number;
13
+ size?: number;
14
+ /** Overlap at rest, in px. */
15
+ overlap?: number;
16
+ /** Gap when fanned out, in px. */
17
+ spread?: number;
18
+ ring?: number;
19
+ /** How far the tag swings toward the pointer, in degrees. */
20
+ sway?: number;
21
+ label?: string;
22
+ backgroundColor?: string;
23
+ chipColor?: string;
24
+ textColor?: string;
25
+ tooltipColor?: string;
26
+ tooltipTextColor?: string;
27
+ accentColor?: string;
28
+ fontFamily?: string;
29
+ className?: string;
30
+ style?: CSSProperties;
31
+ }
32
+ export default function AvatarTooltips({ people, max, size, overlap, spread, ring, sway, label, backgroundColor, chipColor, textColor, tooltipColor, tooltipTextColor, accentColor, fontFamily, className, style }: AvatarTooltipsProps): import("react").JSX.Element;
@@ -0,0 +1,121 @@
1
+ 'use client';
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useId, useInsertionEffect, useState } from "react";
4
+ const STYLE_ID = "bl-avatar-tooltips";
5
+ const CSS = `
6
+ .bl-avs { display: inline-flex; align-items: center; margin: 0; padding: var(--bl-pad) 0 0; list-style: none; font-family: var(--bl-font); }
7
+ .bl-avs__item { position: relative; flex: 0 0 auto; transition: margin 340ms cubic-bezier(.3,1.35,.5,1); }
8
+ .bl-avs__item + .bl-avs__item { margin-left: calc(var(--bl-overlap) * -1); }
9
+ .bl-avs:hover .bl-avs__item + .bl-avs__item, .bl-avs:focus-within .bl-avs__item + .bl-avs__item { margin-left: var(--bl-spread); }
10
+ .bl-avs__face { position: relative; display: grid; place-items: center; width: var(--bl-size); height: var(--bl-size); overflow: hidden; border-radius: 50%; background: var(--bl-chip); color: var(--bl-ink); font-size: calc(var(--bl-size) * 0.34); font-weight: 700; box-shadow: 0 0 0 var(--bl-ring) var(--bl-bg); outline: none; cursor: default; transition: transform 240ms cubic-bezier(.3,1.5,.5,1); }
11
+ .bl-avs__face img, .bl-avs__face svg { width: 100%; height: 100%; object-fit: cover; }
12
+ .bl-avs__item:hover, .bl-avs__item:focus-within { z-index: 2; }
13
+ .bl-avs__item:hover .bl-avs__face, .bl-avs__face:focus { transform: translateY(-6px) scale(1.08); }
14
+ .bl-avs__face:focus-visible { box-shadow: 0 0 0 var(--bl-ring) var(--bl-bg), 0 0 0 calc(var(--bl-ring) + 2px) var(--bl-accent); }
15
+ .bl-avs__tip { position: absolute; left: 50%; bottom: calc(100% + 10px); display: grid; justify-items: center; gap: 1px; padding: 6px 10px; border-radius: 8px; background: var(--bl-tip); color: var(--bl-tip-ink); white-space: nowrap; pointer-events: none; opacity: 0; transform: translate(-50%, 8px) scale(0.6) rotate(var(--bl-sway, 0deg)); transform-origin: bottom center; transition: opacity 120ms, transform 340ms cubic-bezier(.3,1.6,.5,1); }
16
+ .bl-avs__tip::after { content: ""; position: absolute; left: 50%; top: 100%; border: 5px solid transparent; border-top-color: var(--bl-tip); transform: translateX(-50%); }
17
+ .bl-avs__item:hover .bl-avs__tip, .bl-avs__face:focus + .bl-avs__tip { opacity: 1; transform: translate(-50%, 0) scale(1) rotate(var(--bl-sway, 0deg)); }
18
+ .bl-avs__name { font-size: 13px; font-weight: 700; }
19
+ .bl-avs__role { font-size: 11px; opacity: 0.75; }
20
+ .bl-avs__more { background: var(--bl-accent); color: var(--bl-tip); }
21
+ @media (prefers-reduced-motion: reduce) { .bl-avs__item, .bl-avs__face, .bl-avs__tip { transition: opacity 120ms; } }
22
+ `;
23
+ function useStyles() {
24
+ useInsertionEffect(() => {
25
+ if (typeof document === "undefined") return;
26
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
27
+ style.textContent = CSS;
28
+ if (!style.isConnected) document.head.appendChild(style);
29
+ }, []);
30
+ }
31
+ const initials = (name) => String(name).split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0].toUpperCase()).join("");
32
+ function AvatarTooltips({
33
+ people = [],
34
+ max = 5,
35
+ size = 48,
36
+ overlap = 14,
37
+ spread = 6,
38
+ ring = 3,
39
+ sway = 12,
40
+ label = "Team",
41
+ backgroundColor = "#1a1c2c",
42
+ chipColor = "#333c57",
43
+ textColor = "#f4f4f4",
44
+ tooltipColor = "#f4f4f4",
45
+ tooltipTextColor = "#1a1c2c",
46
+ accentColor = "#73eff7",
47
+ fontFamily = "ui-sans-serif, system-ui, sans-serif",
48
+ className = "",
49
+ style
50
+ }) {
51
+ useStyles();
52
+ const uid = useId().replace(/[^a-zA-Z0-9_-]/g, "");
53
+ const [swayBy, setSwayBy] = useState({});
54
+ const shown = people.length > max ? people.slice(0, max - 1) : people;
55
+ const rest = people.length > max ? people.slice(max - 1) : [];
56
+ const onMove = (key, event) => {
57
+ const rect = event.currentTarget.getBoundingClientRect();
58
+ const offset = (event.clientX - rect.left) / rect.width - 0.5;
59
+ setSwayBy((current) => ({ ...current, [key]: offset * 2 * sway }));
60
+ };
61
+ const item = (key, face, tip, name, extraClass = "") => /* @__PURE__ */ jsxs("li", { className: "bl-avs__item", onPointerMove: (event) => onMove(key, event), onPointerLeave: () => setSwayBy((current) => ({ ...current, [key]: 0 })), children: [
62
+ /* @__PURE__ */ jsx("span", { className: `bl-avs__face ${extraClass}`, tabIndex: 0, role: "img", "aria-label": name, "aria-describedby": `${uid}-${key}`, children: face }),
63
+ /* @__PURE__ */ jsx("span", { id: `${uid}-${key}`, className: "bl-avs__tip", role: "tooltip", style: { "--bl-sway": `${(swayBy[key] ?? 0).toFixed(1)}deg` }, children: tip })
64
+ ] }, key);
65
+ return /* @__PURE__ */ jsxs(
66
+ "ul",
67
+ {
68
+ className: `bl-avs ${className}`,
69
+ "aria-label": `${label}: ${people.length} ${people.length === 1 ? "person" : "people"}`,
70
+ style: {
71
+ "--bl-size": `${size}px`,
72
+ "--bl-overlap": `${overlap}px`,
73
+ "--bl-spread": `${spread}px`,
74
+ "--bl-ring": `${ring}px`,
75
+ "--bl-pad": `${Math.round(size * 0.9)}px`,
76
+ "--bl-bg": backgroundColor,
77
+ "--bl-chip": chipColor,
78
+ "--bl-ink": textColor,
79
+ "--bl-tip": tooltipColor,
80
+ "--bl-tip-ink": tooltipTextColor,
81
+ "--bl-accent": accentColor,
82
+ "--bl-font": fontFamily,
83
+ ...style
84
+ },
85
+ children: [
86
+ shown.map((person, i) => {
87
+ const key = person.id ?? `p${i}`;
88
+ const face = person.avatar ? typeof person.avatar === "string" ? /* @__PURE__ */ jsx("img", { src: person.avatar, alt: "" }) : person.avatar : initials(person.name);
89
+ return item(
90
+ key,
91
+ face,
92
+ /* @__PURE__ */ jsxs(Fragment, { children: [
93
+ /* @__PURE__ */ jsx("span", { className: "bl-avs__name", children: person.name }),
94
+ person.role && /* @__PURE__ */ jsx("span", { className: "bl-avs__role", children: person.role })
95
+ ] }),
96
+ person.role ? `${person.name}, ${person.role}` : person.name
97
+ );
98
+ }),
99
+ rest.length > 0 && item(
100
+ "more",
101
+ `+${rest.length}`,
102
+ /* @__PURE__ */ jsxs(Fragment, { children: [
103
+ /* @__PURE__ */ jsxs("span", { className: "bl-avs__name", children: [
104
+ rest.length,
105
+ " more"
106
+ ] }),
107
+ /* @__PURE__ */ jsxs("span", { className: "bl-avs__role", children: [
108
+ rest.slice(0, 4).map((p) => p.name).join(", "),
109
+ rest.length > 4 ? "\u2026" : ""
110
+ ] })
111
+ ] }),
112
+ `${rest.length} more: ${rest.map((p) => p.name).join(", ")}`,
113
+ "bl-avs__more"
114
+ )
115
+ ]
116
+ }
117
+ );
118
+ }
119
+ export {
120
+ AvatarTooltips as default
121
+ };