bits-lab 0.0.0-stage → 0.1.2

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 +57 -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 +58 -4
@@ -0,0 +1,84 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useInsertionEffect } from "react";
4
+ const STYLE_ID = "bl-pin-card";
5
+ const CSS = `
6
+ .bl-pin { position: relative; display: grid; justify-items: center; width: var(--bl-w); max-width: 100%; padding-top: 56px; perspective: 1000px; color: var(--bl-ink); font-family: var(--bl-font); text-decoration: none; outline: none; }
7
+ .bl-pin__label { position: absolute; top: 0; left: 50%; z-index: 3; padding: 5px 12px; border-radius: 999px; background: var(--bl-label-bg); box-shadow: 0 0 0 1px var(--bl-line); color: var(--bl-ink); font-size: 13px; font-weight: 600; white-space: nowrap; opacity: 0; transform: translate(-50%, 10px); transition: opacity 200ms, transform 300ms cubic-bezier(.3,1.4,.5,1); }
8
+ .bl-pin__card { position: relative; z-index: 2; width: 100%; border-radius: var(--bl-radius); background: var(--bl-bg); box-shadow: 0 0 0 1px var(--bl-line), 0 18px 40px -20px rgba(0,0,0,0.7); transform-origin: 50% 100%; transition: transform 600ms cubic-bezier(.2,.9,.25,1), box-shadow 400ms; overflow: hidden; }
9
+ .bl-pin__ground { position: relative; width: 100%; height: 96px; margin-top: -40px; transform: rotateX(70deg); transform-style: preserve-3d; pointer-events: none; }
10
+ .bl-pin__ring { position: absolute; left: 50%; top: 50%; width: 140px; height: 140px; margin: -70px 0 0 -70px; border-radius: 50%; background: radial-gradient(color-mix(in srgb, var(--bl-accent) 40%, transparent), transparent 65%); opacity: 0; transition: opacity 300ms; }
11
+ .bl-pin__ring::before, .bl-pin__ring::after { content: ""; position: absolute; inset: 0; border-radius: 50%; box-shadow: 0 0 0 2px var(--bl-accent); opacity: 0; }
12
+ .bl-pin__beam { position: absolute; left: 50%; bottom: 46px; z-index: 1; width: 2px; height: 0; margin-left: -1px; background: linear-gradient(transparent, var(--bl-accent)); transition: height 500ms cubic-bezier(.2,.9,.25,1); pointer-events: none; }
13
+ .bl-pin__beam::after { content: ""; position: absolute; left: 50%; bottom: -4px; width: 8px; height: 8px; margin-left: -4px; border-radius: 50%; background: var(--bl-accent); box-shadow: 0 0 12px 3px var(--bl-accent); }
14
+ .bl-pin:is(:hover, :focus-visible, :focus-within) .bl-pin__card { transform: translateY(-14px) rotateX(38deg) scale(0.86); box-shadow: 0 0 0 1px var(--bl-accent), 0 40px 60px -30px rgba(0,0,0,0.9); }
15
+ .bl-pin:is(:hover, :focus-visible, :focus-within) .bl-pin__label { opacity: 1; transform: translate(-50%, 0); }
16
+ .bl-pin:is(:hover, :focus-visible, :focus-within) .bl-pin__beam { height: 90px; }
17
+ .bl-pin:is(:hover, :focus-visible, :focus-within) .bl-pin__ring { opacity: 1; }
18
+ .bl-pin:is(:hover, :focus-visible, :focus-within) .bl-pin__ring::before { animation: bl-pin-pulse 2s ease-out infinite; }
19
+ .bl-pin:is(:hover, :focus-visible, :focus-within) .bl-pin__ring::after { animation: bl-pin-pulse 2s ease-out 1s infinite; }
20
+ .bl-pin:focus-visible .bl-pin__label { box-shadow: 0 0 0 2px var(--bl-accent); }
21
+ @keyframes bl-pin-pulse { from { transform: scale(0.2); opacity: 1; } to { transform: scale(1); opacity: 0; } }
22
+ @media (prefers-reduced-motion: reduce) {
23
+ .bl-pin__card, .bl-pin__beam, .bl-pin__label { transition: opacity 150ms; }
24
+ .bl-pin:is(:hover, :focus-visible, :focus-within) .bl-pin__card { transform: none; }
25
+ .bl-pin__ring::before, .bl-pin__ring::after { animation: none !important; }
26
+ }
27
+ `;
28
+ function useStyles() {
29
+ useInsertionEffect(() => {
30
+ if (typeof document === "undefined") return;
31
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
32
+ style.textContent = CSS;
33
+ if (!style.isConnected) document.head.appendChild(style);
34
+ }, []);
35
+ }
36
+ function PinCard({
37
+ children,
38
+ title,
39
+ href,
40
+ target,
41
+ width = 300,
42
+ radius = 16,
43
+ backgroundColor = "#1a1c2c",
44
+ labelColor = "#0b0b14",
45
+ textColor = "#f4f4f4",
46
+ lineColor = "#333c57",
47
+ accentColor = "#73eff7",
48
+ fontFamily = "ui-sans-serif, system-ui, sans-serif",
49
+ className = "",
50
+ style
51
+ }) {
52
+ useStyles();
53
+ const Tag = href ? "a" : "div";
54
+ return /* @__PURE__ */ jsxs(
55
+ Tag,
56
+ {
57
+ className: `bl-pin ${className}`,
58
+ href,
59
+ target,
60
+ rel: target === "_blank" ? "noopener noreferrer" : void 0,
61
+ tabIndex: href ? void 0 : 0,
62
+ style: {
63
+ "--bl-w": `${width}px`,
64
+ "--bl-radius": `${radius}px`,
65
+ "--bl-bg": backgroundColor,
66
+ "--bl-label-bg": labelColor,
67
+ "--bl-ink": textColor,
68
+ "--bl-line": lineColor,
69
+ "--bl-accent": accentColor,
70
+ "--bl-font": fontFamily,
71
+ ...style
72
+ },
73
+ children: [
74
+ title && /* @__PURE__ */ jsx("span", { className: "bl-pin__label", children: title }),
75
+ /* @__PURE__ */ jsx("div", { className: "bl-pin__card", children }),
76
+ /* @__PURE__ */ jsx("span", { className: "bl-pin__beam", "aria-hidden": "true" }),
77
+ /* @__PURE__ */ jsx("span", { className: "bl-pin__ground", "aria-hidden": "true", children: /* @__PURE__ */ jsx("span", { className: "bl-pin__ring" }) })
78
+ ]
79
+ }
80
+ );
81
+ }
82
+ export {
83
+ PinCard as default
84
+ };
@@ -0,0 +1,33 @@
1
+ import { type CSSProperties } from 'react';
2
+ export type AvatarVariant = 'creature' | 'identicon';
3
+ export interface AvatarGrid {
4
+ /** 10×10 colors, row by row; null cells are empty. */
5
+ grid: (string | null)[][];
6
+ /** [x, y] cells that form the eyes (empty for identicons). */
7
+ eyes: [number, number][];
8
+ body: string;
9
+ shade: string;
10
+ backdrop: string;
11
+ }
12
+ export interface PixelAvatarProps {
13
+ /** Any string; the same seed always draws the same avatar. */
14
+ seed?: string | number;
15
+ /** Rendered size in px. */
16
+ size?: number;
17
+ variant?: AvatarVariant;
18
+ shape?: 'rounded' | 'square' | 'circle';
19
+ /** true for a seeded backdrop, a color of your own, or false for none. */
20
+ background?: boolean | string;
21
+ /** Idle blink, offset per seed. */
22
+ blink?: boolean;
23
+ /** Accessible name; defaults to "Avatar for {seed}". */
24
+ title?: string;
25
+ /** Hide from assistive tech (when a name sits next to it). */
26
+ decorative?: boolean;
27
+ className?: string;
28
+ style?: CSSProperties;
29
+ }
30
+ export declare function avatarGrid(seed: string | number, variant?: AvatarVariant): AvatarGrid;
31
+ declare function PixelAvatar({ seed, size, variant, shape, background, blink, title, decorative, className, style }: PixelAvatarProps): import("react").JSX.Element;
32
+ declare const _default: import("react").MemoExoticComponent<typeof PixelAvatar>;
33
+ export default _default;
@@ -0,0 +1,144 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { memo, useId, useInsertionEffect, useMemo } from "react";
4
+ const STYLE_ID = "bl-pixel-avatar";
5
+ const CSS = `
6
+ .bl-ava { display: inline-block; flex: 0 0 auto; vertical-align: middle; }
7
+ .bl-ava__eyes { transform-box: fill-box; transform-origin: center; animation: bl-ava-blink 5s steps(1) infinite; animation-delay: var(--bl-blink-delay, 0s); }
8
+ @keyframes bl-ava-blink { 0%, 95%, 100% { transform: none; } 96%, 98% { transform: scaleY(0.2); } }
9
+ @media (prefers-reduced-motion: reduce) { .bl-ava__eyes { animation: none; } }
10
+ `;
11
+ function useStyles() {
12
+ useInsertionEffect(() => {
13
+ if (typeof document === "undefined") return;
14
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
15
+ style.textContent = CSS;
16
+ if (!style.isConnected) document.head.appendChild(style);
17
+ }, []);
18
+ }
19
+ function hash(text) {
20
+ let h1 = 3735928559;
21
+ let h2 = 1103547991;
22
+ for (let i = 0; i < text.length; i++) {
23
+ const c = text.charCodeAt(i);
24
+ h1 = Math.imul(h1 ^ c, 2654435761);
25
+ h2 = Math.imul(h2 ^ c, 1597334677);
26
+ }
27
+ h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
28
+ return h1 >>> 0;
29
+ }
30
+ function random(seed) {
31
+ let a = seed;
32
+ return () => {
33
+ a = a + 1831565813 | 0;
34
+ let t = Math.imul(a ^ a >>> 15, 1 | a);
35
+ t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
36
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
37
+ };
38
+ }
39
+ const PALETTES = [
40
+ ["#b13e53", "#5d275d"],
41
+ ["#ef7d57", "#b13e53"],
42
+ ["#ffcd75", "#ef7d57"],
43
+ ["#a7f070", "#38b764"],
44
+ ["#38b764", "#257179"],
45
+ ["#73eff7", "#41a6f6"],
46
+ ["#41a6f6", "#3b5dc9"],
47
+ ["#94b0c2", "#566c86"]
48
+ ];
49
+ const BACKDROPS = ["#333c57", "#29366f", "#5d275d", "#257179", "#1a1c2c"];
50
+ const INK = "#0b0b14";
51
+ const WHITE = "#f4f4f4";
52
+ const G = 10;
53
+ function avatarGrid(seed, variant = "creature") {
54
+ const rand = random(hash(String(seed)));
55
+ const [body, shade] = PALETTES[Math.floor(rand() * PALETTES.length)];
56
+ const backdrop = BACKDROPS[Math.floor(rand() * BACKDROPS.length)];
57
+ const cells = Array.from({ length: G }, () => Array(G).fill(0));
58
+ const eyes = [];
59
+ if (variant === "identicon") {
60
+ for (let y = 1; y < G - 1; y++) for (let x = 1; x < G / 2; x++) cells[y][x] = rand() < 0.5 ? 1 : 0;
61
+ } else {
62
+ for (let y = 1; y < G - 1; y++) {
63
+ for (let x = 1; x < G / 2; x++) {
64
+ const towardCenter = (x - 1) / (G / 2 - 2);
65
+ const towardMiddle = 1 - Math.abs((y - 4.5) / 4.5);
66
+ cells[y][x] = rand() < 0.12 + 0.8 * Math.min(1, towardCenter * 0.7 + towardMiddle * 0.6) ? 1 : 0;
67
+ }
68
+ }
69
+ for (let y = 3; y <= 6; y++) cells[y][3] = cells[y][4] = 1;
70
+ }
71
+ for (let y = 0; y < G; y++) for (let x = 0; x < G / 2; x++) cells[y][G - 1 - x] = cells[y][x];
72
+ const grid = cells.map((row, y) => row.map((on) => on ? variant !== "identicon" && y >= 7 ? shade : body : null));
73
+ if (variant !== "identicon") {
74
+ const outline = (x, y) => [[1, 0], [-1, 0], [0, 1], [0, -1]].some(([dx, dy]) => cells[y + dy]?.[x + dx]);
75
+ for (let y = 0; y < G; y++) for (let x = 0; x < G; x++) if (!cells[y][x] && outline(x, y)) grid[y][x] = INK;
76
+ const ey = 3 + Math.floor(rand() * 2);
77
+ const ex = rand() < 0.5 ? 3 : 2;
78
+ for (const x of [ex, G - 1 - ex]) {
79
+ grid[ey][x] = WHITE;
80
+ grid[ey + 1][x] = INK;
81
+ eyes.push([x, ey], [x, ey + 1]);
82
+ }
83
+ if (rand() < 0.6) grid[ey + 3][4] = grid[ey + 3][5] = INK;
84
+ }
85
+ return { grid, eyes, body, shade, backdrop };
86
+ }
87
+ function PixelAvatar({ seed = "bits", size = 64, variant = "creature", shape = "rounded", background = true, blink = false, title, decorative = false, className = "", style }) {
88
+ useStyles();
89
+ const clip = useId().replace(/[^a-zA-Z0-9_-]/g, "");
90
+ const { grid, eyes, backdrop } = useMemo(() => avatarGrid(seed, variant), [seed, variant]);
91
+ const eyeSet = new Set(eyes.map(([x, y]) => `${x},${y}`));
92
+ const body = [];
93
+ const eyeRects = [];
94
+ grid.forEach((row, y) => {
95
+ let x = 0;
96
+ while (x < G) {
97
+ const color = row[x];
98
+ if (!color) {
99
+ x++;
100
+ continue;
101
+ }
102
+ if (eyeSet.has(`${x},${y}`)) {
103
+ eyeRects.push(/* @__PURE__ */ jsx("rect", { x, y, width: 1, height: 1, fill: color }, `e${x}-${y}`));
104
+ x++;
105
+ continue;
106
+ }
107
+ let run = 1;
108
+ while (x + run < G && row[x + run] === color && !eyeSet.has(`${x + run},${y}`)) run++;
109
+ body.push(/* @__PURE__ */ jsx("rect", { x, y, width: run, height: 1, fill: color }, `${x}-${y}`));
110
+ x += run;
111
+ }
112
+ });
113
+ const fill = background === true ? backdrop : background || "none";
114
+ const radius = shape === "circle" ? 6 : shape === "rounded" ? 2 : 0;
115
+ const delay = `${-(hash(String(seed)) % 5e3) / 1e3}s`;
116
+ const label = title ?? `Avatar for ${seed}`;
117
+ return /* @__PURE__ */ jsxs(
118
+ "svg",
119
+ {
120
+ className: `bl-ava ${className}`,
121
+ viewBox: "-1 -1 12 12",
122
+ width: size,
123
+ height: size,
124
+ shapeRendering: "crispEdges",
125
+ role: decorative ? void 0 : "img",
126
+ "aria-label": decorative ? void 0 : label,
127
+ "aria-hidden": decorative || void 0,
128
+ style: { "--bl-blink-delay": delay, ...style },
129
+ children: [
130
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", { id: `${clip}-shape`, children: /* @__PURE__ */ jsx("rect", { x: -1, y: -1, width: 12, height: 12, rx: radius }) }) }),
131
+ /* @__PURE__ */ jsxs("g", { clipPath: `url(#${clip}-shape)`, children: [
132
+ /* @__PURE__ */ jsx("rect", { x: -1, y: -1, width: 12, height: 12, fill }),
133
+ body,
134
+ /* @__PURE__ */ jsx("g", { className: blink && eyeRects.length ? "bl-ava__eyes" : void 0, children: eyeRects })
135
+ ] })
136
+ ]
137
+ }
138
+ );
139
+ }
140
+ var stdin_default = memo(PixelAvatar);
141
+ export {
142
+ avatarGrid,
143
+ stdin_default as default
144
+ };
@@ -0,0 +1,20 @@
1
+ import { type ButtonHTMLAttributes, type MouseEvent, type ReactNode, type Ref } from 'react';
2
+ export type PixelButtonVariant = 'primary' | 'secondary' | 'success' | 'warning' | 'info';
3
+ export interface PixelButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'color'> {
4
+ /** Preset face and text colors. */
5
+ variant?: PixelButtonVariant;
6
+ size?: 'sm' | 'md' | 'lg';
7
+ /** Custom face color; overrides the variant. */
8
+ color?: string;
9
+ /** Custom label color; overrides the variant. */
10
+ textColor?: string;
11
+ /** Shown before the label. */
12
+ icon?: ReactNode;
13
+ /** Shows loading pips, sets aria-busy and ignores clicks. */
14
+ loading?: boolean;
15
+ fontFamily?: string;
16
+ /** Like onClick, but skipped while loading. */
17
+ onPress?: (event: MouseEvent<HTMLButtonElement>) => void;
18
+ ref?: Ref<HTMLButtonElement>;
19
+ }
20
+ export default function PixelButton({ children, variant, size, color, textColor, icon, loading, disabled, fontFamily, type, className, style, onPress, onClick, ref, ...rest }: PixelButtonProps): import("react").JSX.Element;
@@ -0,0 +1,128 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useInsertionEffect } from "react";
4
+ const STYLE_ID = "bl-pixel-button";
5
+ const CSS = `
6
+ .bl-pxbtn {
7
+ --bl-face: #b13e53; --bl-text: #f4f4f4; --bl-ink: #0b0b14; --bl-px: 4px;
8
+ position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 10px;
9
+ margin: var(--bl-px); border: 0; cursor: pointer; user-select: none;
10
+ background: var(--bl-face); color: var(--bl-text);
11
+ font-family: var(--bl-font, "Press Start 2P", ui-monospace, monospace); text-transform: uppercase; line-height: 1;
12
+ box-shadow:
13
+ 0 calc(var(--bl-px) * -1) 0 0 var(--bl-ink), 0 var(--bl-px) 0 0 var(--bl-ink),
14
+ calc(var(--bl-px) * -1) 0 0 0 var(--bl-ink), var(--bl-px) 0 0 0 var(--bl-ink),
15
+ inset calc(var(--bl-px) * -1) calc(var(--bl-px) * -1) 0 0 rgba(11, 11, 20, 0.28),
16
+ inset var(--bl-px) var(--bl-px) 0 0 rgba(255, 255, 255, 0.32),
17
+ var(--bl-px) calc(var(--bl-px) * 2) 0 0 rgba(11, 11, 20, 0.5);
18
+ transition: transform 60ms steps(1), filter 60ms steps(1);
19
+ }
20
+ .bl-pxbtn:hover:not(:disabled) { filter: brightness(1.12); }
21
+ .bl-pxbtn:active:not(:disabled), .bl-pxbtn[data-pressed] {
22
+ transform: translateY(var(--bl-px));
23
+ box-shadow:
24
+ 0 calc(var(--bl-px) * -1) 0 0 var(--bl-ink), 0 var(--bl-px) 0 0 var(--bl-ink),
25
+ calc(var(--bl-px) * -1) 0 0 0 var(--bl-ink), var(--bl-px) 0 0 0 var(--bl-ink),
26
+ inset var(--bl-px) var(--bl-px) 0 0 rgba(11, 11, 20, 0.3);
27
+ }
28
+ .bl-pxbtn:focus-visible { outline: var(--bl-px) solid #41a6f6; outline-offset: calc(var(--bl-px) * 2); }
29
+ .bl-pxbtn[data-size="sm"] { padding: 8px 12px; font-size: 8px; --bl-px: 3px; }
30
+ .bl-pxbtn[data-size="md"] { padding: 12px 18px; font-size: 11px; }
31
+ .bl-pxbtn[data-size="lg"] { padding: 16px 26px; font-size: 14px; --bl-px: 5px; }
32
+ .bl-pxbtn:disabled { cursor: not-allowed; filter: grayscale(0.85) brightness(0.8); }
33
+ .bl-pxbtn:disabled::after {
34
+ content: ""; position: absolute; inset: 0; pointer-events: none;
35
+ background: repeating-linear-gradient(135deg, transparent 0 6px, rgba(11, 11, 20, 0.35) 6px 8px);
36
+ }
37
+ .bl-pxbtn__label { position: relative; }
38
+ .bl-pxbtn[data-loading] .bl-pxbtn__label { visibility: hidden; }
39
+ .bl-pxbtn__pips { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: 6px; }
40
+ .bl-pxbtn__pips i { width: 6px; height: 6px; background: currentColor; animation: bl-pxbtn-pip 0.9s steps(1) infinite; }
41
+ .bl-pxbtn__pips i:nth-child(2) { animation-delay: 0.3s; }
42
+ .bl-pxbtn__pips i:nth-child(3) { animation-delay: 0.6s; }
43
+ @keyframes bl-pxbtn-pip { 0%, 100% { opacity: 0.25; } 33% { opacity: 1; } }
44
+ @media (prefers-reduced-motion: reduce) {
45
+ .bl-pxbtn { transition: none; }
46
+ .bl-pxbtn__pips i { animation: none; opacity: 0.8; }
47
+ }
48
+ `;
49
+ function useStyles() {
50
+ useInsertionEffect(() => {
51
+ if (typeof document === "undefined") return;
52
+ const existing = document.getElementById(STYLE_ID);
53
+ if (existing) {
54
+ existing.textContent = CSS;
55
+ return;
56
+ }
57
+ const style = document.createElement("style");
58
+ style.id = STYLE_ID;
59
+ style.textContent = CSS;
60
+ document.head.appendChild(style);
61
+ }, []);
62
+ }
63
+ const VARIANTS = {
64
+ primary: { face: "#b13e53", text: "#f4f4f4" },
65
+ secondary: { face: "#94b0c2", text: "#0b0b14" },
66
+ success: { face: "#38b764", text: "#0b0b14" },
67
+ warning: { face: "#ffcd75", text: "#0b0b14" },
68
+ info: { face: "#41a6f6", text: "#0b0b14" }
69
+ };
70
+ function PixelButton({
71
+ children,
72
+ variant = "primary",
73
+ size = "md",
74
+ color,
75
+ textColor,
76
+ icon,
77
+ loading = false,
78
+ disabled = false,
79
+ fontFamily,
80
+ type = "button",
81
+ className = "",
82
+ style,
83
+ onPress,
84
+ onClick,
85
+ ref,
86
+ ...rest
87
+ }) {
88
+ useStyles();
89
+ const palette = VARIANTS[variant] ?? VARIANTS.primary;
90
+ return /* @__PURE__ */ jsxs(
91
+ "button",
92
+ {
93
+ ref,
94
+ type,
95
+ className: `bl-pxbtn ${className}`,
96
+ "data-size": size,
97
+ "data-loading": loading || void 0,
98
+ disabled,
99
+ "aria-busy": loading || void 0,
100
+ onClick: (event) => {
101
+ if (loading) return;
102
+ onClick?.(event);
103
+ onPress?.(event);
104
+ },
105
+ style: {
106
+ "--bl-face": color ?? palette.face,
107
+ "--bl-text": textColor ?? palette.text,
108
+ ...fontFamily ? { "--bl-font": fontFamily } : null,
109
+ ...style
110
+ },
111
+ ...rest,
112
+ children: [
113
+ /* @__PURE__ */ jsxs("span", { className: "bl-pxbtn__label", style: { display: "inline-flex", alignItems: "center", gap: 10 }, children: [
114
+ icon,
115
+ children
116
+ ] }),
117
+ loading && /* @__PURE__ */ jsxs("span", { className: "bl-pxbtn__pips", "aria-hidden": "true", children: [
118
+ /* @__PURE__ */ jsx("i", {}),
119
+ /* @__PURE__ */ jsx("i", {}),
120
+ /* @__PURE__ */ jsx("i", {})
121
+ ] })
122
+ ]
123
+ }
124
+ );
125
+ }
126
+ export {
127
+ PixelButton as default
128
+ };
@@ -0,0 +1,31 @@
1
+ import { type CSSProperties, type ReactNode, type Ref } from 'react';
2
+ export type ExplodeDirection = 'right' | 'left' | 'up' | 'down' | 'center';
3
+ export interface PixelExplodeHandle {
4
+ explode: () => void;
5
+ reassemble: () => void;
6
+ }
7
+ export interface PixelExplodeProps {
8
+ children?: ReactNode;
9
+ /** Controlled: true explodes, false reassembles. */
10
+ exploded?: boolean;
11
+ /** Tile size in px. */
12
+ pieceSize?: number;
13
+ /** Large elements use bigger tiles to stay under this count. */
14
+ maxPieces?: number;
15
+ /** Flight time in ms. */
16
+ duration?: number;
17
+ spread?: number;
18
+ gravity?: number;
19
+ /** The direction the disintegration sweeps. */
20
+ direction?: ExplodeDirection;
21
+ /** Choppy 8-bit motion instead of smooth. */
22
+ stepped?: boolean;
23
+ onExploded?: () => void;
24
+ onReassembled?: () => void;
25
+ /** CSS display of the wrapper. */
26
+ display?: CSSProperties['display'];
27
+ ref?: Ref<PixelExplodeHandle>;
28
+ className?: string;
29
+ style?: CSSProperties;
30
+ }
31
+ export default function PixelExplode({ children, exploded, pieceSize, maxPieces, duration, spread, gravity, direction, stepped, onExploded, onReassembled, display, ref, className, style }: PixelExplodeProps): import("react").JSX.Element;
@@ -0,0 +1,164 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useImperativeHandle, useRef } from "react";
4
+ function prefersReduced() {
5
+ return window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
6
+ }
7
+ function PixelExplode({
8
+ children,
9
+ exploded,
10
+ pieceSize = 8,
11
+ maxPieces = 500,
12
+ duration = 900,
13
+ spread = 1,
14
+ gravity = 1,
15
+ direction = "right",
16
+ stepped = true,
17
+ onExploded,
18
+ onReassembled,
19
+ display = "inline-block",
20
+ ref,
21
+ className = "",
22
+ style
23
+ }) {
24
+ const contentRef = useRef(null);
25
+ const layerRef = useRef(null);
26
+ const animations = useRef([]);
27
+ const state = useRef(exploded ? "gone" : "whole");
28
+ const callbacks = useRef({ onExploded, onReassembled });
29
+ callbacks.current = { onExploded, onReassembled };
30
+ const options = useRef(null);
31
+ options.current = { pieceSize, maxPieces, duration, spread, gravity, direction, stepped };
32
+ const clear = () => {
33
+ animations.current.forEach((animation) => animation.cancel());
34
+ animations.current = [];
35
+ layerRef.current?.replaceChildren();
36
+ };
37
+ const setHidden = (hidden) => {
38
+ const content = contentRef.current;
39
+ if (!content) return;
40
+ content.style.visibility = hidden ? "hidden" : "";
41
+ content.inert = hidden;
42
+ };
43
+ const build = (reverse) => {
44
+ const content = contentRef.current;
45
+ const layer = layerRef.current;
46
+ if (!content || !layer) return Promise.resolve();
47
+ clear();
48
+ const o = options.current;
49
+ const width = content.offsetWidth;
50
+ const height = content.offsetHeight;
51
+ if (!width || !height) return Promise.resolve();
52
+ const size = Math.max(o.pieceSize, Math.ceil(Math.sqrt(width * height / o.maxPieces)));
53
+ const source = content.cloneNode(true);
54
+ source.removeAttribute("id");
55
+ source.querySelectorAll("[id]").forEach((node) => node.removeAttribute("id"));
56
+ source.style.visibility = "visible";
57
+ source.style.width = `${width}px`;
58
+ source.style.height = `${height}px`;
59
+ source.style.margin = "0";
60
+ const cols = Math.ceil(width / size);
61
+ const rows = Math.ceil(height / size);
62
+ const fragment = document.createDocumentFragment();
63
+ const pending = [];
64
+ for (let r = 0; r < rows; r++) {
65
+ for (let c = 0; c < cols; c++) {
66
+ const tile = document.createElement("div");
67
+ tile.style.cssText = `position:absolute;left:${c * size}px;top:${r * size}px;width:${size}px;height:${size}px;overflow:hidden;will-change:transform,opacity;`;
68
+ const copy = source.cloneNode(true);
69
+ copy.style.position = "absolute";
70
+ copy.style.left = `${-c * size}px`;
71
+ copy.style.top = `${-r * size}px`;
72
+ tile.appendChild(copy);
73
+ fragment.appendChild(tile);
74
+ const along = o.direction === "left" ? 1 - c / cols : o.direction === "up" ? 1 - r / rows : o.direction === "down" ? r / rows : o.direction === "center" ? Math.hypot(c / cols - 0.5, r / rows - 0.5) * 1.4 : c / cols;
75
+ const delay = along * o.duration * 0.6 + Math.random() * o.duration * 0.15;
76
+ const angle = (Math.random() - 0.5) * Math.PI * 0.9 - Math.PI / 2;
77
+ const distance = (40 + Math.random() * 90) * o.spread;
78
+ const dx = Math.cos(angle) * distance * 0.7 + (o.direction === "left" ? -1 : o.direction === "right" ? 1 : 0) * distance * 0.6;
79
+ const dy = Math.sin(angle) * distance;
80
+ const fall = 60 * o.gravity;
81
+ const spin = (Math.random() - 0.5) * 180;
82
+ const keyframes = [
83
+ { transform: "translate(0, 0) rotate(0deg) scale(1)", opacity: 1 },
84
+ { transform: `translate(${dx * 0.55}px, ${dy * 0.55}px) rotate(${spin * 0.5}deg) scale(0.9)`, opacity: 1, offset: 0.45 },
85
+ { transform: `translate(${dx}px, ${dy + fall}px) rotate(${spin}deg) scale(0.4)`, opacity: 0 }
86
+ ];
87
+ const animation = tile.animate(keyframes, {
88
+ duration: o.duration * (0.7 + Math.random() * 0.5),
89
+ delay: reverse ? 0 : delay,
90
+ endDelay: reverse ? delay : 0,
91
+ easing: o.stepped ? "steps(10)" : "cubic-bezier(.3,.6,.5,1)",
92
+ fill: "both"
93
+ });
94
+ if (reverse) animation.reverse();
95
+ animations.current.push(animation);
96
+ pending.push(animation.finished.catch(() => null));
97
+ }
98
+ }
99
+ layer.appendChild(fragment);
100
+ return Promise.all(pending);
101
+ };
102
+ const explode = () => {
103
+ if (state.current === "gone" || state.current === "leaving") return;
104
+ state.current = "leaving";
105
+ if (prefersReduced()) {
106
+ const fade = contentRef.current?.animate([{ opacity: 1 }, { opacity: 0 }], { duration: 200 });
107
+ (fade?.finished ?? Promise.resolve()).catch(() => null).then(() => {
108
+ if (state.current !== "leaving") return;
109
+ setHidden(true);
110
+ state.current = "gone";
111
+ callbacks.current.onExploded?.();
112
+ });
113
+ return;
114
+ }
115
+ const run = build(false);
116
+ setHidden(true);
117
+ run.then(() => {
118
+ if (state.current !== "leaving") return;
119
+ clear();
120
+ state.current = "gone";
121
+ callbacks.current.onExploded?.();
122
+ });
123
+ };
124
+ const reassemble = () => {
125
+ if (state.current === "whole" || state.current === "returning") return;
126
+ state.current = "returning";
127
+ if (prefersReduced()) {
128
+ clear();
129
+ setHidden(false);
130
+ contentRef.current?.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 200 });
131
+ state.current = "whole";
132
+ callbacks.current.onReassembled?.();
133
+ return;
134
+ }
135
+ const run = build(true);
136
+ run.then(() => {
137
+ if (state.current !== "returning") return;
138
+ clear();
139
+ setHidden(false);
140
+ state.current = "whole";
141
+ callbacks.current.onReassembled?.();
142
+ });
143
+ };
144
+ useImperativeHandle(ref, () => ({ explode, reassemble }));
145
+ const first = useRef(true);
146
+ useEffect(() => {
147
+ if (first.current) {
148
+ first.current = false;
149
+ if (exploded) setHidden(true);
150
+ return;
151
+ }
152
+ if (exploded === void 0) return;
153
+ if (exploded) explode();
154
+ else reassemble();
155
+ }, [exploded]);
156
+ useEffect(() => () => animations.current.forEach((animation) => animation.cancel()), []);
157
+ return /* @__PURE__ */ jsxs("div", { className, style: { position: "relative", display, ...style }, children: [
158
+ /* @__PURE__ */ jsx("div", { ref: contentRef, children }),
159
+ /* @__PURE__ */ jsx("div", { ref: layerRef, "aria-hidden": "true", style: { position: "absolute", inset: 0, pointerEvents: "none", overflow: "visible" } })
160
+ ] });
161
+ }
162
+ export {
163
+ PixelExplode as default
164
+ };
@@ -0,0 +1,32 @@
1
+ import { type CSSProperties } from 'react';
2
+ export interface PixelLoaderProps {
3
+ /** 0–100. Leave undefined to simulate a load. */
4
+ progress?: number;
5
+ label?: string;
6
+ /** Title shown when progress reaches 100. */
7
+ doneLabel?: string;
8
+ /** Rotating tips under the bar; empty to hide. */
9
+ tips?: string[];
10
+ /** Time per tip, in ms. */
11
+ tipInterval?: number;
12
+ /** Number of chunks in the bar. */
13
+ chunks?: number;
14
+ /** Max width, in px. */
15
+ width?: number;
16
+ accentColor?: string;
17
+ frameColor?: string;
18
+ textColor?: string;
19
+ mutedColor?: string;
20
+ /** Rough length of a simulated load, in ms. */
21
+ simulateDuration?: number;
22
+ /** Restart a simulated load after COMPLETE. */
23
+ loop?: boolean;
24
+ /** Show the percent and chunk count. */
25
+ showPercent?: boolean;
26
+ fontFamily?: string;
27
+ /** Called when progress reaches 100. */
28
+ onComplete?: () => void;
29
+ className?: string;
30
+ style?: CSSProperties;
31
+ }
32
+ export default function PixelLoader({ progress, label, doneLabel, tips, tipInterval, chunks, width, accentColor, frameColor, textColor, mutedColor, simulateDuration, loop, showPercent, fontFamily, onComplete, className, style }: PixelLoaderProps): import("react").JSX.Element;