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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Steven Phung
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,52 @@
1
- # Temporary Holding Version
1
+ # Bits Lab
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 159 original React components with an 8-bit soul: text effects, animated backgrounds, game UI, inputs, data displays, overlays, navigation and playful toys. Every component brings its own styles, so there is nothing else to import or configure.
4
+
5
+ Browse them all, tweak their props and copy the code at **https://bits-lab.vercel.app**.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install bits-lab
11
+ ```
12
+
13
+ Needs React 19. Nothing else has dependencies, except `GravityBox`, which uses `matter-js` for its physics. Install it and import GravityBox from its own entry point:
14
+
15
+ ```bash
16
+ npm install matter-js
17
+ ```
18
+
19
+ ```jsx
20
+ import GravityBox from "bits-lab/GravityBox";
21
+ ```
22
+
23
+ ## Use
24
+
25
+ ```jsx
26
+ import { FocusPull, HoldToConfirm, PixelSpinners } from "bits-lab";
27
+
28
+ export default function Page() {
29
+ return (
30
+ <>
31
+ <FocusPull as="h1" text="Every pixel snaps into focus" />
32
+ <HoldToConfirm onConfirm={() => console.log("Deleted")}>Hold to delete</HoldToConfirm>
33
+ <PixelSpinners type="hourglass" label="Loading" showLabel />
34
+ </>
35
+ );
36
+ }
37
+ ```
38
+
39
+ Each component also has its own entry point, which is handy for components with several exports:
40
+
41
+ ```jsx
42
+ import Toaster, { toast } from "bits-lab/ToastStack";
43
+ import { Switch, Checkbox } from "bits-lab/ToggleKit";
44
+ ```
45
+
46
+ - **TypeScript:** types are included.
47
+ - **Next.js:** every file starts with `"use client"`, so components work in the App Router without a wrapper.
48
+ - **Accessibility:** components follow WAI-ARIA patterns, work with the keyboard and respect reduced motion.
49
+
50
+ ## License
51
+
52
+ MIT © Steven Phung
@@ -0,0 +1,52 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export interface AccordionItem {
3
+ /** Stable id used in value / defaultValue; defaults to the item's index. */
4
+ id?: string;
5
+ title: ReactNode;
6
+ /** A string, or nodes whose direct children stagger in. */
7
+ content?: ReactNode;
8
+ icon?: ReactNode;
9
+ disabled?: boolean;
10
+ }
11
+ export interface AccordionProps {
12
+ items?: AccordionItem[];
13
+ /** One section open at a time, or many. */
14
+ type?: 'single' | 'multiple';
15
+ defaultValue?: string | string[];
16
+ /** Controlled open section(s): an id in single mode, ids in multiple mode. */
17
+ value?: string | string[] | null;
18
+ /** Receives an id (or null) in single mode, an array of ids in multiple mode. */
19
+ onValueChange?: (value: string | string[] | null) => void;
20
+ /** Single mode: whether the open section can be closed. */
21
+ collapsible?: boolean;
22
+ /** Opening spring stiffness. */
23
+ stiffness?: number;
24
+ /** Opening spring damping. */
25
+ damping?: number;
26
+ /** Delay between content children appearing, in ms. */
27
+ stagger?: number;
28
+ /** Max width in px. */
29
+ width?: number;
30
+ radius?: number;
31
+ backgroundColor?: string;
32
+ textColor?: string;
33
+ mutedColor?: string;
34
+ lineColor?: string;
35
+ hoverColor?: string;
36
+ accentColor?: string;
37
+ /** Heading level wrapping each trigger (2–6). */
38
+ headingLevel?: number;
39
+ fontFamily?: string;
40
+ className?: string;
41
+ style?: CSSProperties;
42
+ }
43
+ export interface SpringOptions {
44
+ stiffness?: number;
45
+ damping?: number;
46
+ mass?: number;
47
+ }
48
+ export declare function springEasing({ stiffness, damping, mass }?: SpringOptions): {
49
+ easing: string;
50
+ duration: number;
51
+ };
52
+ export default function Accordion({ items, type, defaultValue, value: controlled, onValueChange, collapsible, stiffness, damping, stagger, width, radius, backgroundColor, textColor, mutedColor, lineColor, hoverColor, accentColor, headingLevel, fontFamily, className, style }: AccordionProps): import("react").JSX.Element;
@@ -0,0 +1,192 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useId, useInsertionEffect, useLayoutEffect, useRef, useState } from "react";
4
+ const STYLE_ID = "bl-accordion";
5
+ const STYLES = `
6
+ .bl-acc { width: 100%; max-width: var(--bl-w); border-radius: var(--bl-radius); background: var(--bl-bg); box-shadow: inset 0 0 0 1px var(--bl-line); color: var(--bl-ink); font-family: var(--bl-font); overflow: hidden; }
7
+ .bl-acc__item + .bl-acc__item { border-top: 1px solid var(--bl-line); }
8
+ .bl-acc__heading { margin: 0; font: inherit; }
9
+ .bl-acc__trigger { display: flex; align-items: center; gap: 12px; width: 100%; padding: 16px 18px; border: 0; background: transparent; color: inherit; font: inherit; font-size: 15px; font-weight: 600; text-align: left; cursor: pointer; }
10
+ .bl-acc__trigger:hover { background: var(--bl-hover); }
11
+ .bl-acc__trigger:focus-visible { outline: 2px solid var(--bl-accent); outline-offset: -2px; }
12
+ .bl-acc__trigger:disabled { opacity: 0.45; cursor: not-allowed; }
13
+ .bl-acc__title { flex: 1; min-width: 0; }
14
+ .bl-acc__chev { flex: 0 0 auto; color: var(--bl-muted); transition: transform var(--bl-dur) var(--bl-ease); }
15
+ .bl-acc__trigger[aria-expanded="true"] .bl-acc__chev { transform: rotate(180deg); color: var(--bl-accent); }
16
+ .bl-acc__panel { overflow: hidden; }
17
+ .bl-acc__panel:not([data-open]):not([data-animating]) { height: 0; visibility: hidden; }
18
+ .bl-acc__body { padding: 0 18px 18px; color: var(--bl-muted); font-size: 14px; line-height: 1.6; }
19
+ .bl-acc__body > * { margin: 0 0 10px; }
20
+ .bl-acc__body > :last-child { margin-bottom: 0; }
21
+ .bl-acc__panel[data-open] .bl-acc__body > * { animation: bl-acc-in 380ms cubic-bezier(.2,.9,.25,1) both; animation-delay: calc(var(--i, 0) * var(--bl-stagger)); }
22
+ @keyframes bl-acc-in { from { opacity: 0; transform: translateY(8px); } }
23
+ @media (prefers-reduced-motion: reduce) { .bl-acc__chev { transition: none; } .bl-acc__panel[data-open] .bl-acc__body > * { animation: none; } }
24
+ `;
25
+ function useStyles() {
26
+ useInsertionEffect(() => {
27
+ if (typeof document === "undefined") return;
28
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
29
+ style.textContent = STYLES;
30
+ if (!style.isConnected) document.head.appendChild(style);
31
+ }, []);
32
+ }
33
+ function springEasing({ stiffness = 260, damping = 22, mass = 1 } = {}) {
34
+ const supported = typeof CSS !== "undefined" && CSS.supports?.("animation-timing-function", "linear(0, 1)");
35
+ let x = 0;
36
+ let v = 0;
37
+ const dt = 1 / 120;
38
+ const points = [0];
39
+ let t = 0;
40
+ while (t < 3) {
41
+ const force = -stiffness * (x - 1) - damping * v;
42
+ v += force / mass * dt;
43
+ x += v * dt;
44
+ t += dt;
45
+ points.push(x);
46
+ if (Math.abs(x - 1) < 1e-3 && Math.abs(v) < 0.01) break;
47
+ }
48
+ const duration = Math.round(t * 1e3);
49
+ if (!supported) return { easing: "cubic-bezier(.2,.9,.25,1)", duration: Math.min(duration, 500) };
50
+ const step = Math.max(1, Math.floor(points.length / 40));
51
+ const sampled = points.filter((_, i) => i % step === 0);
52
+ sampled.push(1);
53
+ return { easing: `linear(${sampled.map((p) => p.toFixed(3)).join(", ")})`, duration };
54
+ }
55
+ function Accordion({
56
+ items = [],
57
+ type = "single",
58
+ defaultValue,
59
+ value: controlled,
60
+ onValueChange,
61
+ collapsible = true,
62
+ stiffness = 260,
63
+ damping = 22,
64
+ stagger = 45,
65
+ width = 640,
66
+ radius = 14,
67
+ backgroundColor = "#1a1c2c",
68
+ textColor = "#f4f4f4",
69
+ mutedColor = "#94b0c2",
70
+ lineColor = "rgba(255,255,255,0.1)",
71
+ hoverColor = "rgba(255,255,255,0.04)",
72
+ accentColor = "#73eff7",
73
+ headingLevel = 3,
74
+ fontFamily = "ui-sans-serif, system-ui, sans-serif",
75
+ className = "",
76
+ style
77
+ }) {
78
+ useStyles();
79
+ const uid = useId().replace(/[^a-zA-Z0-9_-]/g, "");
80
+ const multiple = type === "multiple";
81
+ const [inner, setInner] = useState(() => {
82
+ const start = defaultValue ?? [];
83
+ return Array.isArray(start) ? start : [start];
84
+ });
85
+ const open = controlled !== void 0 ? Array.isArray(controlled) ? controlled : controlled ? [controlled] : [] : inner;
86
+ const panels = useRef({});
87
+ const triggers = useRef([]);
88
+ const previous = useRef(open);
89
+ const spring = springEasing({ stiffness, damping });
90
+ const toggle = (id) => {
91
+ const isOpen = open.includes(id);
92
+ if (isOpen && !multiple && !collapsible) return;
93
+ const next = isOpen ? open.filter((v) => v !== id) : multiple ? [...open, id] : [id];
94
+ if (controlled === void 0) setInner(next);
95
+ onValueChange?.(multiple ? next : next[0] ?? null);
96
+ };
97
+ useLayoutEffect(() => {
98
+ const before = previous.current;
99
+ previous.current = open;
100
+ const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
101
+ for (const [id, panel] of Object.entries(panels.current)) {
102
+ if (!panel) continue;
103
+ const was = before.includes(id);
104
+ const is = open.includes(id);
105
+ if (was === is) continue;
106
+ if (is) [...panel.firstElementChild.children].forEach((child, i) => child.style.setProperty("--i", String(i)));
107
+ if (reduced) continue;
108
+ const target = is ? panel.scrollHeight : 0;
109
+ const from = is ? 0 : panel.scrollHeight;
110
+ panel.setAttribute("data-animating", "");
111
+ const animation = panel.animate([{ height: `${from}px` }, { height: `${target}px` }], is ? spring : { duration: 240, easing: "cubic-bezier(.4,0,.2,1)" });
112
+ animation.onfinish = animation.oncancel = () => panel.removeAttribute("data-animating");
113
+ }
114
+ }, [open.join("|")]);
115
+ const onKeyDown = (event, index) => {
116
+ const enabled = items.map((item, i) => item.disabled ? -1 : i).filter((i) => i >= 0);
117
+ const position = enabled.indexOf(index);
118
+ const keys = { ArrowDown: position + 1, ArrowUp: position - 1, Home: 0, End: enabled.length - 1 };
119
+ if (!(event.key in keys)) return;
120
+ event.preventDefault();
121
+ triggers.current[enabled[(keys[event.key] + enabled.length) % enabled.length]]?.focus();
122
+ };
123
+ const Heading = `h${Math.min(6, Math.max(2, headingLevel))}`;
124
+ return /* @__PURE__ */ jsx(
125
+ "div",
126
+ {
127
+ className: `bl-acc ${className}`,
128
+ style: {
129
+ "--bl-w": `${width}px`,
130
+ "--bl-radius": `${radius}px`,
131
+ "--bl-bg": backgroundColor,
132
+ "--bl-ink": textColor,
133
+ "--bl-muted": mutedColor,
134
+ "--bl-line": lineColor,
135
+ "--bl-hover": hoverColor,
136
+ "--bl-accent": accentColor,
137
+ "--bl-dur": `${Math.min(spring.duration, 450)}ms`,
138
+ "--bl-ease": "cubic-bezier(.2,.9,.25,1.2)",
139
+ "--bl-stagger": `${stagger}ms`,
140
+ "--bl-font": fontFamily,
141
+ ...style
142
+ },
143
+ children: items.map((item, index) => {
144
+ const id = item.id ?? String(index);
145
+ const isOpen = open.includes(id);
146
+ return /* @__PURE__ */ jsxs("div", { className: "bl-acc__item", children: [
147
+ /* @__PURE__ */ jsx(Heading, { className: "bl-acc__heading", children: /* @__PURE__ */ jsxs(
148
+ "button",
149
+ {
150
+ ref: (node) => {
151
+ triggers.current[index] = node;
152
+ },
153
+ type: "button",
154
+ id: `${uid}-trigger-${index}`,
155
+ className: "bl-acc__trigger",
156
+ "aria-expanded": isOpen,
157
+ "aria-controls": `${uid}-panel-${index}`,
158
+ "aria-disabled": !multiple && !collapsible && isOpen ? true : void 0,
159
+ disabled: item.disabled,
160
+ onClick: () => toggle(id),
161
+ onKeyDown: (event) => onKeyDown(event, index),
162
+ children: [
163
+ item.icon,
164
+ /* @__PURE__ */ jsx("span", { className: "bl-acc__title", children: item.title }),
165
+ /* @__PURE__ */ jsx("svg", { className: "bl-acc__chev", width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M3 5.5 7 9.5l4-4" }) })
166
+ ]
167
+ }
168
+ ) }),
169
+ /* @__PURE__ */ jsx(
170
+ "div",
171
+ {
172
+ ref: (node) => {
173
+ panels.current[id] = node;
174
+ },
175
+ id: `${uid}-panel-${index}`,
176
+ className: "bl-acc__panel",
177
+ role: "region",
178
+ "aria-labelledby": `${uid}-trigger-${index}`,
179
+ "data-open": isOpen || void 0,
180
+ inert: isOpen ? void 0 : true,
181
+ children: /* @__PURE__ */ jsx("div", { className: "bl-acc__body", children: typeof item.content === "string" ? /* @__PURE__ */ jsx("p", { children: item.content }) : item.content })
182
+ }
183
+ )
184
+ ] }, id);
185
+ })
186
+ }
187
+ );
188
+ }
189
+ export {
190
+ Accordion as default,
191
+ springEasing
192
+ };
@@ -0,0 +1,36 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export type AchievementTier = 'bronze' | 'silver' | 'gold' | 'diamond';
3
+ export interface AchievementData {
4
+ title: ReactNode;
5
+ description?: ReactNode;
6
+ /** Icon or sprite in the badge; defaults to a star. */
7
+ icon?: ReactNode;
8
+ /** XP shown on the badge. */
9
+ xp?: number;
10
+ /** A preset tier, or any CSS color for the accent. */
11
+ tier?: AchievementTier | (string & {});
12
+ /** Time on screen for this toast, in ms. */
13
+ duration?: number;
14
+ }
15
+ export interface Achievement extends AchievementData {
16
+ id: number;
17
+ }
18
+ export declare function achievement(data: AchievementData): number;
19
+ export interface AchievementToasterProps {
20
+ /** Corner the stack grows from. */
21
+ position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
22
+ /** Most toasts on screen at once; the rest queue. */
23
+ max?: number;
24
+ /** Default time on screen, in ms (hover pauses it). */
25
+ duration?: number;
26
+ /** Small heading on every toast. */
27
+ label?: string;
28
+ /** Position inside the nearest positioned parent instead of the window. */
29
+ contained?: boolean;
30
+ fontFamily?: string;
31
+ /** Called when a toast appears, e.g. to play a sound. */
32
+ onShow?: (toast: Achievement) => void;
33
+ className?: string;
34
+ style?: CSSProperties;
35
+ }
36
+ export default function AchievementToaster({ position, max, duration, label, contained, fontFamily, onShow, className, style }: AchievementToasterProps): import("react").JSX.Element;
@@ -0,0 +1,162 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useCallback, useEffect, useInsertionEffect, useRef, useState } from "react";
4
+ const STYLE_ID = "bl-achievement";
5
+ const CSS = `
6
+ .bl-ach-region { position: var(--bl-position); z-index: 1000; display: flex; flex-direction: column; gap: 14px; pointer-events: none; width: min(380px, calc(100% - 32px)); }
7
+ .bl-ach-region[data-corner*="bottom"] { bottom: 20px; flex-direction: column-reverse; }
8
+ .bl-ach-region[data-corner*="top"] { top: 20px; }
9
+ .bl-ach-region[data-corner*="right"] { right: 20px; }
10
+ .bl-ach-region[data-corner*="left"] { left: 20px; }
11
+ .bl-ach {
12
+ --bl-tier: #ffcd75;
13
+ position: relative; display: grid; grid-template-columns: 56px 1fr auto; align-items: center; gap: 14px;
14
+ padding: 12px 12px 16px; margin: 4px; background: #1a1c2c; color: #f4f4f4; pointer-events: auto;
15
+ font-family: var(--bl-font, "Press Start 2P", ui-monospace, monospace);
16
+ box-shadow: 0 -4px 0 0 #0b0b14, 0 4px 0 0 #0b0b14, -4px 0 0 0 #0b0b14, 4px 0 0 0 #0b0b14, 8px 8px 0 0 rgba(11, 11, 20, 0.5);
17
+ animation: bl-ach-in 360ms steps(6) both;
18
+ }
19
+ .bl-ach-region[data-corner*="left"] .bl-ach { animation-name: bl-ach-in-left; }
20
+ .bl-ach[data-leaving] { animation: bl-ach-out 240ms steps(4) both; }
21
+ .bl-ach__icon { position: relative; display: grid; place-items: center; width: 56px; height: 56px; background: #0b0b14; box-shadow: inset 0 0 0 3px var(--bl-tier); }
22
+ .bl-ach__icon > :not(.bl-ach__spark) { animation: bl-ach-pop 500ms steps(5) 200ms both; }
23
+ .bl-ach__spark { position: absolute; left: 50%; top: 50%; width: 6px; height: 6px; margin: -3px; background: var(--bl-tier); opacity: 0; animation: bl-ach-spark 600ms steps(6) 260ms; }
24
+ .bl-ach__label { margin: 0 0 6px; font-size: 8px; color: var(--bl-tier); letter-spacing: 0.08em; text-transform: uppercase; }
25
+ .bl-ach__title { margin: 0; font-size: 11px; line-height: 1.4; text-transform: uppercase; }
26
+ .bl-ach__desc { margin: 6px 0 0; font: 14px/1.35 var(--bl-body, ui-monospace, monospace); color: #94b0c2; }
27
+ .bl-ach__xp { align-self: start; padding: 4px 6px; background: #38b764; color: #0b0b14; font-size: 8px; white-space: nowrap; }
28
+ .bl-ach__close { position: absolute; top: 4px; right: 4px; width: 22px; height: 22px; border: 0; background: none; color: #94b0c2; font: 12px/1 monospace; cursor: pointer; }
29
+ .bl-ach__close:hover, .bl-ach__close:focus-visible { color: #f4f4f4; outline: 2px solid #41a6f6; }
30
+ .bl-ach__timer { position: absolute; left: 0; right: 0; bottom: 0; height: 4px; background: var(--bl-tier); transform-origin: left; animation: bl-ach-timer var(--bl-duration) linear both; }
31
+ .bl-ach:hover .bl-ach__timer, .bl-ach:focus-within .bl-ach__timer { animation-play-state: paused; }
32
+ @keyframes bl-ach-in { from { transform: translateX(110%); } }
33
+ @keyframes bl-ach-in-left { from { transform: translateX(-110%); } }
34
+ @keyframes bl-ach-out { to { transform: translateY(20%); opacity: 0; } }
35
+ @keyframes bl-ach-pop { 0% { transform: scale(0); } 60% { transform: scale(1.25); } 100% { transform: scale(1); } }
36
+ @keyframes bl-ach-spark { 0% { opacity: 1; transform: translate(0, 0); } 100% { opacity: 0; transform: translate(var(--dx), var(--dy)); } }
37
+ @keyframes bl-ach-timer { from { transform: scaleX(1); } to { transform: scaleX(0); } }
38
+ @media (prefers-reduced-motion: reduce) {
39
+ .bl-ach, .bl-ach[data-leaving] { animation: bl-ach-fade 200ms both; }
40
+ .bl-ach[data-leaving] { animation-direction: reverse; }
41
+ .bl-ach__icon > *, .bl-ach__spark { animation: none !important; }
42
+ @keyframes bl-ach-fade { from { opacity: 0; } }
43
+ }
44
+ `;
45
+ function useStyles() {
46
+ useInsertionEffect(() => {
47
+ if (typeof document === "undefined") return;
48
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
49
+ style.textContent = CSS;
50
+ if (!style.isConnected) document.head.appendChild(style);
51
+ }, []);
52
+ }
53
+ const TIERS = { bronze: "#ef7d57", silver: "#94b0c2", gold: "#ffcd75", diamond: "#73eff7" };
54
+ const listeners = /* @__PURE__ */ new Set();
55
+ let nextId = 1;
56
+ function achievement(data) {
57
+ const toast = { id: nextId++, tier: "gold", ...data };
58
+ listeners.forEach((listener) => listener(toast));
59
+ return toast.id;
60
+ }
61
+ const SPARKS = [
62
+ [-30, -26],
63
+ [30, -26],
64
+ [-34, 10],
65
+ [34, 10],
66
+ [0, -38],
67
+ [0, 34]
68
+ ];
69
+ function Toast({ toast, duration, label, onDone }) {
70
+ const [leaving, setLeaving] = useState(false);
71
+ const leave = useCallback(() => setLeaving(true), []);
72
+ useEffect(() => {
73
+ if (!leaving) return void 0;
74
+ const timer = setTimeout(() => onDone(toast.id), 240);
75
+ return () => clearTimeout(timer);
76
+ }, [leaving, onDone, toast.id]);
77
+ return /* @__PURE__ */ jsxs(
78
+ "article",
79
+ {
80
+ className: "bl-ach",
81
+ "data-leaving": leaving || void 0,
82
+ style: { "--bl-tier": TIERS[toast.tier] ?? toast.tier, "--bl-duration": `${toast.duration ?? duration}ms` },
83
+ onKeyDown: (event) => event.key === "Escape" && leave(),
84
+ "aria-label": `${label}: ${toast.title}`,
85
+ children: [
86
+ /* @__PURE__ */ jsxs("div", { className: "bl-ach__icon", "aria-hidden": "true", children: [
87
+ toast.icon ?? /* @__PURE__ */ jsx("span", { style: { fontSize: 22, color: "var(--bl-tier)" }, children: "\u2605" }),
88
+ SPARKS.map(([dx, dy], index) => /* @__PURE__ */ jsx("i", { className: "bl-ach__spark", style: { "--dx": `${dx}px`, "--dy": `${dy}px` } }, index))
89
+ ] }),
90
+ /* @__PURE__ */ jsxs("div", { children: [
91
+ /* @__PURE__ */ jsx("p", { className: "bl-ach__label", children: label }),
92
+ /* @__PURE__ */ jsx("p", { className: "bl-ach__title", children: toast.title }),
93
+ toast.description && /* @__PURE__ */ jsx("p", { className: "bl-ach__desc", children: toast.description })
94
+ ] }),
95
+ toast.xp != null && /* @__PURE__ */ jsxs("span", { className: "bl-ach__xp", children: [
96
+ "+",
97
+ toast.xp,
98
+ " XP"
99
+ ] }),
100
+ /* @__PURE__ */ jsx("button", { type: "button", className: "bl-ach__close", onClick: leave, "aria-label": "Dismiss", children: "\xD7" }),
101
+ /* @__PURE__ */ jsx("span", { className: "bl-ach__timer", onAnimationEnd: leave })
102
+ ]
103
+ }
104
+ );
105
+ }
106
+ function AchievementToaster({
107
+ position = "bottom-right",
108
+ max = 3,
109
+ duration = 4500,
110
+ label = "Achievement unlocked",
111
+ contained = false,
112
+ fontFamily,
113
+ onShow,
114
+ className = "",
115
+ style
116
+ }) {
117
+ useStyles();
118
+ const [visible, setVisible] = useState([]);
119
+ const queue = useRef([]);
120
+ const onShowRef = useRef(onShow);
121
+ onShowRef.current = onShow;
122
+ const pump = useCallback(() => {
123
+ setVisible((current) => {
124
+ if (current.length >= max || !queue.current.length) return current;
125
+ const next = queue.current.shift();
126
+ onShowRef.current?.(next);
127
+ return [...current, next];
128
+ });
129
+ }, [max]);
130
+ useEffect(() => {
131
+ const listener = (toast) => {
132
+ queue.current.push(toast);
133
+ pump();
134
+ };
135
+ listeners.add(listener);
136
+ return () => {
137
+ listeners.delete(listener);
138
+ };
139
+ }, [pump]);
140
+ const remove = useCallback(
141
+ (id) => {
142
+ setVisible((current) => current.filter((toast) => toast.id !== id));
143
+ setTimeout(pump, 0);
144
+ },
145
+ [pump]
146
+ );
147
+ return /* @__PURE__ */ jsx(
148
+ "section",
149
+ {
150
+ className: `bl-ach-region ${className}`,
151
+ "data-corner": position,
152
+ "aria-live": "polite",
153
+ "aria-label": "Achievements",
154
+ style: { "--bl-position": contained ? "absolute" : "fixed", ...fontFamily ? { "--bl-font": fontFamily } : null, ...style },
155
+ children: visible.map((toast) => /* @__PURE__ */ jsx(Toast, { toast, duration, label, onDone: remove }, toast.id))
156
+ }
157
+ );
158
+ }
159
+ export {
160
+ achievement,
161
+ AchievementToaster as default
162
+ };
@@ -0,0 +1,41 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export type AgentStatus = 'queued' | 'running' | 'success' | 'error';
3
+ export interface AgentCardProps {
4
+ /** The tool's name. */
5
+ tool?: string;
6
+ /** Arguments, summarised on one line. */
7
+ args?: Record<string, unknown> | string;
8
+ status?: AgentStatus;
9
+ /** When the call started (ms since epoch); drives the live timer. */
10
+ startedAt?: number;
11
+ /** Final duration in ms; overrides the timer. */
12
+ duration?: number;
13
+ logs?: string[];
14
+ result?: ReactNode;
15
+ error?: ReactNode;
16
+ /** Icon shown while queued. */
17
+ icon?: ReactNode;
18
+ defaultOpen?: boolean;
19
+ open?: boolean;
20
+ onOpenChange?: (open: boolean) => void;
21
+ /** Max width in px. */
22
+ width?: number;
23
+ /** Max height of the log panel in px. */
24
+ logHeight?: number;
25
+ backgroundColor?: string;
26
+ chipColor?: string;
27
+ codeColor?: string;
28
+ textColor?: string;
29
+ mutedColor?: string;
30
+ dimColor?: string;
31
+ lineColor?: string;
32
+ accentColor?: string;
33
+ okColor?: string;
34
+ errorColor?: string;
35
+ radius?: number;
36
+ fontFamily?: string;
37
+ monoFamily?: string;
38
+ className?: string;
39
+ style?: CSSProperties;
40
+ }
41
+ export default function AgentCard({ tool, args, status, startedAt, duration, logs, result, error, icon, defaultOpen, open: controlledOpen, onOpenChange, width, logHeight, backgroundColor, chipColor, codeColor, textColor, mutedColor, dimColor, lineColor, accentColor, okColor, errorColor, radius, fontFamily, monoFamily, className, style }: AgentCardProps): import("react").JSX.Element;