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,117 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useInsertionEffect, useRef, useState } from "react";
4
+ const STYLE_ID = "bl-logo-orbit";
5
+ const CSS = `
6
+ .bl-orbit { position: relative; width: min(var(--bl-size), 100%); aspect-ratio: 1; margin: 0 auto; container-type: inline-size; color: var(--bl-ink); font-family: var(--bl-font); }
7
+ .bl-orbit__ring { position: absolute; inset: 0; animation: bl-orbit-spin var(--bl-dur) linear infinite; animation-direction: var(--bl-dir); pointer-events: none; }
8
+ .bl-orbit__track { position: absolute; left: 50%; top: 50%; width: calc(var(--bl-r) * 2cqi); height: calc(var(--bl-r) * 2cqi); border-radius: 50%; border: 1px dashed var(--bl-line); transform: translate(-50%, -50%); pointer-events: none; }
9
+ .bl-orbit__item { position: absolute; left: 50%; top: 50%; width: 0; height: 0; transform: rotate(var(--bl-a)) translateX(calc(var(--bl-r) * 1cqi)) rotate(calc(var(--bl-a) * -1)); }
10
+ .bl-orbit__logo { position: absolute; left: 0; top: 0; display: grid; place-items: center; width: var(--bl-item); height: var(--bl-item); margin: calc(var(--bl-item) / -2) 0 0 calc(var(--bl-item) / -2); border-radius: var(--bl-item-radius); background: var(--bl-item-bg); box-shadow: 0 0 0 1px var(--bl-line), 0 8px 20px -10px rgba(0,0,0,0.6); pointer-events: auto; outline: none; animation: bl-orbit-spin var(--bl-dur) linear infinite; animation-direction: var(--bl-cdir); transition: box-shadow 160ms, scale 160ms; }
11
+ .bl-orbit__logo > * { max-width: 62%; max-height: 62%; }
12
+ .bl-orbit__logo:hover, .bl-orbit__logo:focus-visible { scale: 1.15; box-shadow: 0 0 0 2px var(--bl-accent), 0 8px 24px -8px rgba(0,0,0,0.6); }
13
+ .bl-orbit__tip { position: absolute; left: 50%; bottom: calc(100% + 6px); padding: 3px 8px; border-radius: 6px; background: var(--bl-ink); color: var(--bl-bg); font-size: 12px; white-space: nowrap; transform: translateX(-50%); opacity: 0; pointer-events: none; transition: opacity 120ms; }
14
+ .bl-orbit__logo:hover .bl-orbit__tip, .bl-orbit__logo:focus-visible .bl-orbit__tip { opacity: 1; }
15
+ .bl-orbit__center { position: absolute; left: 50%; top: 50%; display: grid; place-items: center; width: var(--bl-center); height: var(--bl-center); border-radius: 50%; transform: translate(-50%, -50%); background: var(--bl-center-bg); box-shadow: 0 0 0 1px var(--bl-line), 0 0 60px -10px var(--bl-accent); }
16
+ .bl-orbit[data-pausable]:hover :is(.bl-orbit__ring, .bl-orbit__logo), .bl-orbit[data-pausable]:focus-within :is(.bl-orbit__ring, .bl-orbit__logo), .bl-orbit[data-paused] :is(.bl-orbit__ring, .bl-orbit__logo) { animation-play-state: paused; }
17
+ .bl-orbit__list { margin: 0; padding: 0; list-style: none; }
18
+ @keyframes bl-orbit-spin { to { rotate: 360deg; } }
19
+ @media (prefers-reduced-motion: reduce) { .bl-orbit__ring, .bl-orbit__logo { animation: none; } }
20
+ `;
21
+ function useStyles() {
22
+ useInsertionEffect(() => {
23
+ if (typeof document === "undefined") return;
24
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
25
+ style.textContent = CSS;
26
+ if (!style.isConnected) document.head.appendChild(style);
27
+ }, []);
28
+ }
29
+ function distribute(n, radii) {
30
+ const total = radii.reduce((a, b) => a + b, 0);
31
+ const counts = radii.map((r) => Math.floor(n * r / total));
32
+ let left = n - counts.reduce((a, b) => a + b, 0);
33
+ for (let i = radii.length - 1; left > 0; i = (i - 1 + radii.length) % radii.length, left--) counts[i]++;
34
+ return counts;
35
+ }
36
+ function LogoOrbit({
37
+ logos = [],
38
+ center,
39
+ rings = 2,
40
+ size = 480,
41
+ innerRadius = 24,
42
+ ringGap = 16,
43
+ itemSize = 52,
44
+ centerSize = 96,
45
+ duration = 40,
46
+ pauseOnHover = true,
47
+ showTracks = true,
48
+ label = "Integrations",
49
+ backgroundColor = "#1a1c2c",
50
+ itemColor = "#262b44",
51
+ centerColor = "#333c57",
52
+ lineColor = "rgba(148,176,194,0.25)",
53
+ accentColor = "#73eff7",
54
+ textColor = "#f4f4f4",
55
+ itemRadius = 14,
56
+ fontFamily = "ui-sans-serif, system-ui, sans-serif",
57
+ className = "",
58
+ style
59
+ }) {
60
+ useStyles();
61
+ const rootRef = useRef(null);
62
+ const [offscreen, setOffscreen] = useState(false);
63
+ useEffect(() => {
64
+ const io = new IntersectionObserver(([entry]) => setOffscreen(!entry.isIntersecting));
65
+ io.observe(rootRef.current);
66
+ return () => io.disconnect();
67
+ }, []);
68
+ const radii = Array.from({ length: Math.max(1, rings) }, (_, k) => innerRadius + k * ringGap);
69
+ const counts = distribute(logos.length, radii);
70
+ let next = 0;
71
+ const groups = counts.map((count) => {
72
+ const group = logos.slice(next, next + count);
73
+ next += count;
74
+ return group;
75
+ });
76
+ return /* @__PURE__ */ jsxs(
77
+ "div",
78
+ {
79
+ ref: rootRef,
80
+ className: `bl-orbit ${className}`,
81
+ role: "group",
82
+ "aria-label": label,
83
+ "data-pausable": pauseOnHover || void 0,
84
+ "data-paused": offscreen || void 0,
85
+ style: {
86
+ "--bl-size": `${size}px`,
87
+ // Tiles shrink with the box on small screens (cqi resolves against the orbit).
88
+ "--bl-item": `min(${itemSize}px, 12cqi)`,
89
+ "--bl-center": `min(${centerSize}px, 22cqi)`,
90
+ "--bl-item-radius": `${itemRadius}px`,
91
+ "--bl-bg": backgroundColor,
92
+ "--bl-item-bg": itemColor,
93
+ "--bl-center-bg": centerColor,
94
+ "--bl-line": lineColor,
95
+ "--bl-accent": accentColor,
96
+ "--bl-ink": textColor,
97
+ "--bl-font": fontFamily,
98
+ ...style
99
+ },
100
+ children: [
101
+ showTracks && radii.map((r, k) => /* @__PURE__ */ jsx("div", { className: "bl-orbit__track", style: { "--bl-r": r }, "aria-hidden": "true" }, `t${k}`)),
102
+ /* @__PURE__ */ jsx("div", { className: "bl-orbit__center", children: center }),
103
+ /* @__PURE__ */ jsx("ul", { className: "bl-orbit__list", children: groups.map((group, k) => {
104
+ const ringStyle = { "--bl-dur": `${duration * (1 + k * 0.5)}s`, "--bl-dir": k % 2 ? "reverse" : "normal", "--bl-cdir": k % 2 ? "normal" : "reverse", "--bl-r": radii[k] };
105
+ if (!group.length) return null;
106
+ return /* @__PURE__ */ jsx("li", { className: "bl-orbit__ring", style: ringStyle, children: /* @__PURE__ */ jsx("ul", { className: "bl-orbit__list", children: group.map((logo, i) => /* @__PURE__ */ jsx("li", { className: "bl-orbit__item", style: { "--bl-a": `${360 / group.length * i + k * 17}deg` }, children: /* @__PURE__ */ jsxs("span", { className: "bl-orbit__logo", tabIndex: 0, "aria-label": logo.label, role: "img", children: [
107
+ logo.icon,
108
+ logo.label && /* @__PURE__ */ jsx("span", { className: "bl-orbit__tip", "aria-hidden": "true", children: logo.label })
109
+ ] }) }, logo.id ?? logo.label ?? i)) }) }, k);
110
+ }) })
111
+ ]
112
+ }
113
+ );
114
+ }
115
+ export {
116
+ LogoOrbit as default
117
+ };
@@ -0,0 +1,33 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export interface MarqueeProps {
3
+ /** Logos or cards, dealt round-robin into lanes. */
4
+ items?: ReactNode[];
5
+ lanes?: number;
6
+ /** Lanes run up and down instead of across. */
7
+ vertical?: boolean;
8
+ /** px per second. */
9
+ speed?: number;
10
+ /** How much lane speeds differ (0–1). */
11
+ variance?: number;
12
+ /** Neighbouring lanes run opposite ways. */
13
+ alternate?: boolean;
14
+ /** Speed of a hovered lane, 0–1 (0 stops it). */
15
+ slow?: number;
16
+ /** Opacity of the other items in a hovered lane. */
17
+ dim?: number;
18
+ gap?: number;
19
+ /** Edge fade in px. */
20
+ fade?: number;
21
+ /** Height of a vertical wall in px. */
22
+ height?: number;
23
+ showPause?: boolean;
24
+ /** Name of the items list for screen readers, and of the pause button. */
25
+ label?: string;
26
+ textColor?: string;
27
+ accentColor?: string;
28
+ chipColor?: string;
29
+ fontFamily?: string;
30
+ className?: string;
31
+ style?: CSSProperties;
32
+ }
33
+ export default function Marquee({ items, lanes, vertical, speed, variance, alternate, slow, dim, gap, fade, height, showPause, label, textColor, accentColor, chipColor, fontFamily, className, style }: MarqueeProps): import("react").JSX.Element;
@@ -0,0 +1,148 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useInsertionEffect, useRef, useState } from "react";
4
+ const STYLE_ID = "bl-marquee-wall";
5
+ const CSS = `
6
+ .bl-mwall { position: relative; display: grid; gap: 10px; color: var(--bl-ink); font-family: var(--bl-font); }
7
+ .bl-mwall__lanes { display: flex; flex-direction: column; gap: var(--bl-gap); }
8
+ .bl-mwall[data-vertical] .bl-mwall__lanes { flex-direction: row; height: var(--bl-h); }
9
+ .bl-mwall__lane { overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 var(--bl-fade), #000 calc(100% - var(--bl-fade)), transparent); mask-image: linear-gradient(90deg, transparent, #000 var(--bl-fade), #000 calc(100% - var(--bl-fade)), transparent); }
10
+ .bl-mwall[data-vertical] .bl-mwall__lane { flex: 1; min-width: 0; -webkit-mask-image: linear-gradient(180deg, transparent, #000 var(--bl-fade), #000 calc(100% - var(--bl-fade)), transparent); mask-image: linear-gradient(180deg, transparent, #000 var(--bl-fade), #000 calc(100% - var(--bl-fade)), transparent); }
11
+ .bl-mwall__track { display: flex; width: max-content; will-change: transform; }
12
+ .bl-mwall[data-vertical] .bl-mwall__track { flex-direction: column; width: auto; }
13
+ .bl-mwall__set { display: flex; flex: none; gap: var(--bl-gap); padding-right: var(--bl-gap); }
14
+ .bl-mwall[data-vertical] .bl-mwall__set { flex-direction: column; padding: 0 0 var(--bl-gap); }
15
+ .bl-mwall__item { flex: none; transition: transform 220ms steps(3), opacity 220ms steps(3); }
16
+ .bl-mwall__lane[data-focus] .bl-mwall__item { opacity: var(--bl-dim); }
17
+ .bl-mwall__lane[data-focus] .bl-mwall__item:hover { opacity: 1; transform: scale(1.06); }
18
+ .bl-mwall__pause { justify-self: end; display: grid; place-items: center; width: 30px; height: 30px; padding: 0; border: 0; border-radius: 8px; background: var(--bl-chip); color: var(--bl-ink); cursor: pointer; }
19
+ .bl-mwall__pause:focus-visible { outline: 2px solid var(--bl-accent); outline-offset: 2px; }
20
+ .bl-mwall__sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
21
+ @media (prefers-reduced-motion: reduce) { .bl-mwall__item { transition: none; } }
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
+ function Lane({ items, index, vertical, speed, variance, alternate, slow, paused }) {
32
+ const laneRef = useRef(null);
33
+ const trackRef = useRef(null);
34
+ const setRef = useRef(null);
35
+ const pausedRef = useRef(paused);
36
+ pausedRef.current = paused;
37
+ const [copies, setCopies] = useState(2);
38
+ useEffect(() => {
39
+ const lane = laneRef.current;
40
+ const set = setRef.current;
41
+ const fit = () => {
42
+ const view = vertical ? lane.clientHeight : lane.clientWidth;
43
+ const one = (vertical ? set.offsetHeight : set.offsetWidth) || 1;
44
+ setCopies(Math.max(2, Math.ceil(view / one) + 1));
45
+ };
46
+ const resize = new ResizeObserver(fit);
47
+ resize.observe(lane);
48
+ resize.observe(set);
49
+ return () => resize.disconnect();
50
+ }, [vertical]);
51
+ useEffect(() => {
52
+ const lane = laneRef.current;
53
+ const track = trackRef.current;
54
+ const set = setRef.current;
55
+ if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) return void 0;
56
+ const dir = alternate && index % 2 ? -1 : 1;
57
+ const own = speed * (1 + (index * 37 % 7 / 6 - 0.5) * variance);
58
+ let offset = 0;
59
+ let rate = 1;
60
+ let hovered = false;
61
+ let visible = true;
62
+ let raf = 0;
63
+ let last = 0;
64
+ const tick = (now) => {
65
+ const dt = Math.max(0, Math.min(0.05, (now - last) / 1e3));
66
+ last = now;
67
+ const goal = pausedRef.current ? 0 : hovered ? slow : 1;
68
+ rate += (goal - rate) * Math.min(1, dt * 6);
69
+ const size = (vertical ? set.offsetHeight : set.offsetWidth) || 1;
70
+ offset = ((offset + dir * own * rate * dt) % size + size) % size;
71
+ track.style.transform = vertical ? `translateY(${-offset.toFixed(2)}px)` : `translateX(${-offset.toFixed(2)}px)`;
72
+ raf = visible && !document.hidden ? requestAnimationFrame(tick) : 0;
73
+ };
74
+ const start = () => {
75
+ if (raf || !visible || document.hidden) return;
76
+ last = performance.now();
77
+ raf = requestAnimationFrame(tick);
78
+ };
79
+ const onEnter = () => {
80
+ hovered = true;
81
+ lane.dataset.focus = "";
82
+ };
83
+ const onLeave = () => {
84
+ hovered = false;
85
+ delete lane.dataset.focus;
86
+ };
87
+ const observer = new IntersectionObserver(([entry]) => {
88
+ visible = entry.isIntersecting;
89
+ start();
90
+ });
91
+ observer.observe(lane);
92
+ document.addEventListener("visibilitychange", start);
93
+ lane.addEventListener("pointerenter", onEnter);
94
+ lane.addEventListener("pointerleave", onLeave);
95
+ start();
96
+ return () => {
97
+ cancelAnimationFrame(raf);
98
+ observer.disconnect();
99
+ document.removeEventListener("visibilitychange", start);
100
+ lane.removeEventListener("pointerenter", onEnter);
101
+ lane.removeEventListener("pointerleave", onLeave);
102
+ track.style.transform = "";
103
+ };
104
+ }, [index, vertical, speed, variance, alternate, slow]);
105
+ return /* @__PURE__ */ jsx("div", { ref: laneRef, className: "bl-mwall__lane", children: /* @__PURE__ */ jsx("div", { ref: trackRef, className: "bl-mwall__track", children: Array.from({ length: copies }, (_, c) => /* @__PURE__ */ jsx("div", { ref: c === 0 ? setRef : void 0, className: "bl-mwall__set", children: items.map((item, i) => /* @__PURE__ */ jsx("div", { className: "bl-mwall__item", children: item }, i)) }, c)) }) });
106
+ }
107
+ function Marquee({
108
+ items = [],
109
+ lanes = 2,
110
+ vertical = false,
111
+ speed = 40,
112
+ variance = 0.3,
113
+ alternate = true,
114
+ slow = 0.15,
115
+ dim = 0.45,
116
+ gap = 16,
117
+ fade = 56,
118
+ height = 420,
119
+ showPause = true,
120
+ label = "Featured",
121
+ textColor = "#f4f4f4",
122
+ accentColor = "#73eff7",
123
+ chipColor = "rgba(255,255,255,0.08)",
124
+ fontFamily = "inherit",
125
+ className = "",
126
+ style
127
+ }) {
128
+ useStyles();
129
+ const [paused, setPaused] = useState(false);
130
+ const count = Math.max(1, Math.min(lanes, items.length || 1));
131
+ const dealt = Array.from({ length: count }, (_, l) => items.filter((_2, i) => i % count === l));
132
+ return /* @__PURE__ */ jsxs(
133
+ "div",
134
+ {
135
+ className: `bl-mwall ${className}`,
136
+ "data-vertical": vertical || void 0,
137
+ style: { "--bl-gap": `${gap}px`, "--bl-fade": `${fade}px`, "--bl-h": `${height}px`, "--bl-dim": dim, "--bl-ink": textColor, "--bl-accent": accentColor, "--bl-chip": chipColor, "--bl-font": fontFamily, ...style },
138
+ children: [
139
+ /* @__PURE__ */ jsx("ul", { className: "bl-mwall__sr", "aria-label": label, children: items.map((item, i) => /* @__PURE__ */ jsx("li", { children: item }, i)) }),
140
+ /* @__PURE__ */ jsx("div", { className: "bl-mwall__lanes", "aria-hidden": "true", children: dealt.map((laneItems, l) => /* @__PURE__ */ jsx(Lane, { items: laneItems, index: l, vertical, speed, variance, alternate, slow, paused }, l)) }),
141
+ showPause && /* @__PURE__ */ jsx("button", { type: "button", className: "bl-mwall__pause", "aria-pressed": paused, "aria-label": paused ? `Play ${label}` : `Pause ${label}`, onClick: () => setPaused((p) => !p), children: paused ? /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M3 1.5v9l7-4.5z" }) }) : /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M2.5 1.5h2.5v9H2.5zM7 1.5h2.5v9H7z" }) }) })
142
+ ]
143
+ }
144
+ );
145
+ }
146
+ export {
147
+ Marquee as default
148
+ };
@@ -0,0 +1,33 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export interface MarqueeLineProps {
3
+ /** What scrolls past. */
4
+ items?: ReactNode[];
5
+ /** Cruising speed in px per second. */
6
+ speed?: number;
7
+ direction?: 'left' | 'right';
8
+ /** Scroll surge: up to this many times cruising speed (scrolling up can reverse it). */
9
+ boost?: number;
10
+ /** Lean in degrees at full surge. */
11
+ skew?: number;
12
+ separator?: ReactNode;
13
+ pauseOnHover?: boolean;
14
+ /** Drag to scrub. */
15
+ draggable?: boolean;
16
+ /** A pause button; motion that runs for more than 5 seconds needs one. */
17
+ showPause?: boolean;
18
+ /** Name of the items list for screen readers, and of the pause button. */
19
+ label?: string;
20
+ gap?: number;
21
+ /** Width of the faded edges in px. */
22
+ fade?: number;
23
+ padding?: number;
24
+ fontSize?: number;
25
+ backgroundColor?: string;
26
+ textColor?: string;
27
+ accentColor?: string;
28
+ chipColor?: string;
29
+ fontFamily?: string;
30
+ className?: string;
31
+ style?: CSSProperties;
32
+ }
33
+ export default function MarqueeLine({ items, speed, direction, boost, skew, separator, pauseOnHover, draggable, showPause, label, gap, fade, padding, fontSize, backgroundColor, textColor, accentColor, chipColor, fontFamily, className, style }: MarqueeLineProps): import("react").JSX.Element;
@@ -0,0 +1,167 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Fragment, useEffect, useInsertionEffect, useRef, useState } from "react";
4
+ const STYLE_ID = "bl-marquee-line";
5
+ const CSS = `
6
+ .bl-marquee { position: relative; display: flex; align-items: center; gap: 8px; overflow: hidden; padding: var(--bl-pad) 0; background: var(--bl-bg); color: var(--bl-ink); font-family: var(--bl-font); font-size: var(--bl-size); }
7
+ .bl-marquee__viewport { flex: 1; min-width: 0; overflow: hidden; cursor: grab; touch-action: pan-y; -webkit-mask-image: linear-gradient(90deg, transparent, #000 var(--bl-fade), #000 calc(100% - var(--bl-fade)), transparent); mask-image: linear-gradient(90deg, transparent, #000 var(--bl-fade), #000 calc(100% - var(--bl-fade)), transparent); }
8
+ .bl-marquee__viewport[data-dragging] { cursor: grabbing; }
9
+ .bl-marquee__track { display: flex; width: max-content; will-change: transform; }
10
+ .bl-marquee__set { display: flex; flex: none; align-items: center; gap: var(--bl-gap); padding-right: var(--bl-gap); white-space: nowrap; }
11
+ .bl-marquee__item { display: inline-flex; align-items: center; gap: 0.4em; }
12
+ .bl-marquee__sep { color: var(--bl-accent); }
13
+ .bl-marquee__pause { flex: none; display: grid; place-items: center; width: 30px; height: 30px; margin-right: 8px; padding: 0; border: 0; border-radius: 8px; background: var(--bl-chip); color: var(--bl-ink); cursor: pointer; }
14
+ .bl-marquee__pause:focus-visible { outline: 2px solid var(--bl-accent); outline-offset: 2px; }
15
+ .bl-marquee__sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
16
+ `;
17
+ function useStyles() {
18
+ useInsertionEffect(() => {
19
+ if (typeof document === "undefined") return;
20
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
21
+ style.textContent = CSS;
22
+ if (!style.isConnected) document.head.appendChild(style);
23
+ }, []);
24
+ }
25
+ function MarqueeLine({
26
+ items = [],
27
+ speed = 60,
28
+ direction = "left",
29
+ boost = 6,
30
+ skew = 8,
31
+ separator = "\u2726",
32
+ pauseOnHover = true,
33
+ draggable = true,
34
+ showPause = true,
35
+ label = "Announcements",
36
+ gap = 28,
37
+ fade = 48,
38
+ padding = 14,
39
+ fontSize = 22,
40
+ backgroundColor = "#1a1c2c",
41
+ textColor = "#f4f4f4",
42
+ accentColor = "#ffcd75",
43
+ chipColor = "rgba(255,255,255,0.08)",
44
+ fontFamily = "inherit",
45
+ className = "",
46
+ style
47
+ }) {
48
+ useStyles();
49
+ const viewportRef = useRef(null);
50
+ const trackRef = useRef(null);
51
+ const setRef = useRef(null);
52
+ const [copies, setCopies] = useState(2);
53
+ const [paused, setPaused] = useState(false);
54
+ const pausedRef = useRef(paused);
55
+ pausedRef.current = paused;
56
+ useEffect(() => {
57
+ const viewport = viewportRef.current;
58
+ const set = setRef.current;
59
+ const fit = () => setCopies(Math.max(2, Math.ceil(viewport.clientWidth * 2 / Math.max(1, set.offsetWidth)) + 1));
60
+ const resize = new ResizeObserver(fit);
61
+ resize.observe(viewport);
62
+ resize.observe(set);
63
+ return () => resize.disconnect();
64
+ }, []);
65
+ useEffect(() => {
66
+ const viewport = viewportRef.current;
67
+ const track = trackRef.current;
68
+ const set = setRef.current;
69
+ const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
70
+ if (reduced) return void 0;
71
+ const sign = direction === "right" ? -1 : 1;
72
+ let offset = 0;
73
+ let surge = 0;
74
+ let lastY = window.scrollY;
75
+ let hovered = false;
76
+ let drag = null;
77
+ let visible = true;
78
+ let raf = 0;
79
+ let last = 0;
80
+ const tick = (now) => {
81
+ const dt = Math.max(0, Math.min(0.05, (now - last) / 1e3));
82
+ last = now;
83
+ const y = window.scrollY;
84
+ const scrolled = (y - lastY) / Math.max(dt, 1e-3);
85
+ lastY = y;
86
+ const kick = Math.max(-boost, Math.min(boost, scrolled / 400));
87
+ if (Math.abs(kick) > Math.abs(surge)) surge = kick;
88
+ surge *= Math.exp(-dt * 2.5);
89
+ const holding = pausedRef.current || pauseOnHover && hovered;
90
+ if (!drag && !holding) offset += sign * speed * (1 + surge) * dt;
91
+ const width = set.offsetWidth || 1;
92
+ offset = (offset % width + width) % width;
93
+ const lean = holding ? 0 : Math.max(-1, Math.min(1, surge / boost)) * skew * sign;
94
+ track.style.transform = `translateX(${-offset.toFixed(2)}px) skewX(${(-lean).toFixed(2)}deg)`;
95
+ raf = visible && !document.hidden ? requestAnimationFrame(tick) : 0;
96
+ };
97
+ const start = () => {
98
+ if (raf || !visible || document.hidden) return;
99
+ last = performance.now();
100
+ lastY = window.scrollY;
101
+ raf = requestAnimationFrame(tick);
102
+ };
103
+ const onEnter = () => hovered = true;
104
+ const onLeave = () => hovered = false;
105
+ const onDown = (event) => {
106
+ if (!draggable || event.button > 0) return;
107
+ drag = { x: event.clientX, offset };
108
+ viewport.dataset.dragging = "";
109
+ try {
110
+ viewport.setPointerCapture(event.pointerId);
111
+ } catch {
112
+ }
113
+ };
114
+ const onMove = (event) => {
115
+ if (drag) offset = drag.offset - (event.clientX - drag.x);
116
+ };
117
+ const onUp = () => {
118
+ drag = null;
119
+ delete viewport.dataset.dragging;
120
+ };
121
+ const observer = new IntersectionObserver(([entry]) => {
122
+ visible = entry.isIntersecting;
123
+ if (visible) start();
124
+ });
125
+ observer.observe(viewport);
126
+ const onVisibility = () => start();
127
+ document.addEventListener("visibilitychange", onVisibility);
128
+ viewport.addEventListener("pointerenter", onEnter);
129
+ viewport.addEventListener("pointerleave", onLeave);
130
+ viewport.addEventListener("pointerdown", onDown);
131
+ viewport.addEventListener("pointermove", onMove);
132
+ viewport.addEventListener("pointerup", onUp);
133
+ viewport.addEventListener("pointercancel", onUp);
134
+ start();
135
+ return () => {
136
+ cancelAnimationFrame(raf);
137
+ observer.disconnect();
138
+ document.removeEventListener("visibilitychange", onVisibility);
139
+ viewport.removeEventListener("pointerenter", onEnter);
140
+ viewport.removeEventListener("pointerleave", onLeave);
141
+ viewport.removeEventListener("pointerdown", onDown);
142
+ viewport.removeEventListener("pointermove", onMove);
143
+ viewport.removeEventListener("pointerup", onUp);
144
+ viewport.removeEventListener("pointercancel", onUp);
145
+ track.style.transform = "";
146
+ };
147
+ }, [speed, direction, boost, skew, pauseOnHover, draggable]);
148
+ const renderSet = (key, ref) => /* @__PURE__ */ jsx("div", { ref, className: "bl-marquee__set", children: items.map((item, i) => /* @__PURE__ */ jsxs(Fragment, { children: [
149
+ /* @__PURE__ */ jsx("span", { className: "bl-marquee__item", children: item }),
150
+ separator && /* @__PURE__ */ jsx("span", { className: "bl-marquee__sep", "aria-hidden": "true", children: separator })
151
+ ] }, i)) }, key);
152
+ return /* @__PURE__ */ jsxs(
153
+ "div",
154
+ {
155
+ className: `bl-marquee ${className}`,
156
+ style: { "--bl-gap": `${gap}px`, "--bl-fade": `${fade}px`, "--bl-pad": `${padding}px`, "--bl-size": `${fontSize}px`, "--bl-bg": backgroundColor, "--bl-ink": textColor, "--bl-accent": accentColor, "--bl-chip": chipColor, "--bl-font": fontFamily, ...style },
157
+ children: [
158
+ /* @__PURE__ */ jsx("ul", { className: "bl-marquee__sr", "aria-label": label, children: items.map((item, i) => /* @__PURE__ */ jsx("li", { children: item }, i)) }),
159
+ /* @__PURE__ */ jsx("div", { ref: viewportRef, className: "bl-marquee__viewport", "aria-hidden": "true", children: /* @__PURE__ */ jsx("div", { ref: trackRef, className: "bl-marquee__track", children: Array.from({ length: copies }, (_, i) => renderSet(i, i === 0 ? setRef : void 0)) }) }),
160
+ showPause && /* @__PURE__ */ jsx("button", { type: "button", className: "bl-marquee__pause", "aria-pressed": paused, "aria-label": paused ? `Play ${label}` : `Pause ${label}`, onClick: () => setPaused((p) => !p), children: paused ? /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M3 1.5v9l7-4.5z" }) }) : /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M2.5 1.5h2.5v9H2.5zM7 1.5h2.5v9H7z" }) }) })
161
+ ]
162
+ }
163
+ );
164
+ }
165
+ export {
166
+ MarqueeLine as default
167
+ };
@@ -0,0 +1,13 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export interface MasonryWallProps {
3
+ /** Items of any height; give each a key so it can glide when the list changes. */
4
+ children?: ReactNode;
5
+ minColumnWidth?: number;
6
+ maxColumns?: number;
7
+ gap?: number;
8
+ /** Glide time in ms. */
9
+ duration?: number;
10
+ className?: string;
11
+ style?: CSSProperties;
12
+ }
13
+ export default function MasonryWall({ children, minColumnWidth, maxColumns, gap, duration, className, style }: MasonryWallProps): import("react").JSX.Element;
@@ -0,0 +1,90 @@
1
+ 'use client';
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { Children, useEffect, useInsertionEffect, useLayoutEffect, useRef, useState } from "react";
4
+ const STYLE_ID = "bl-masonry-wall";
5
+ const CSS = `
6
+ .bl-masonry { position: relative; width: 100%; }
7
+ .bl-masonry__item { position: absolute; top: 0; left: 0; width: var(--bl-col-w); transform: translate(var(--x), var(--y)); transition: transform var(--bl-dur) cubic-bezier(.2,.8,.2,1); }
8
+ .bl-masonry__item[data-new] { animation: bl-masonry-pop 360ms steps(4) both; animation-delay: calc(var(--i) * 40ms); }
9
+ .bl-masonry[data-ready="false"] .bl-masonry__item { transition: none; visibility: hidden; }
10
+ @keyframes bl-masonry-pop { from { opacity: 0; scale: 0.85; } }
11
+ @media (prefers-reduced-motion: reduce) { .bl-masonry__item { transition: none; } .bl-masonry__item[data-new] { animation: none; } }
12
+ `;
13
+ function useStyles() {
14
+ useInsertionEffect(() => {
15
+ if (typeof document === "undefined") return;
16
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
17
+ style.textContent = CSS;
18
+ if (!style.isConnected) document.head.appendChild(style);
19
+ }, []);
20
+ }
21
+ function MasonryWall({ children, minColumnWidth = 220, maxColumns = 6, gap = 16, duration = 450, className = "", style }) {
22
+ useStyles();
23
+ const items = Children.toArray(children);
24
+ const keys = items.map((item, i) => String(item.key ?? i));
25
+ const rootRef = useRef(null);
26
+ const nodes = useRef(/* @__PURE__ */ new Map());
27
+ const seen = useRef(null);
28
+ const [layout, setLayout] = useState({ ready: false, colWidth: 0, height: 0, pos: {} });
29
+ const [fresh, setFresh] = useState(() => /* @__PURE__ */ new Set());
30
+ useEffect(() => {
31
+ if (seen.current) {
32
+ const added = keys.filter((k) => !seen.current.has(k));
33
+ if (added.length) setFresh(new Set(added));
34
+ }
35
+ seen.current = new Set(keys);
36
+ }, [keys.join("|")]);
37
+ useLayoutEffect(() => {
38
+ const root = rootRef.current;
39
+ const place = () => {
40
+ const width = root.clientWidth;
41
+ const cols = Math.max(1, Math.min(maxColumns, Math.floor((width + gap) / (minColumnWidth + gap))));
42
+ const colWidth = (width - gap * (cols - 1)) / cols;
43
+ const heights = new Array(cols).fill(0);
44
+ const pos = {};
45
+ keys.forEach((k) => {
46
+ const node = nodes.current.get(k);
47
+ if (!node) return;
48
+ const c = heights.indexOf(Math.min(...heights));
49
+ pos[k] = { x: c * (colWidth + gap), y: heights[c] };
50
+ heights[c] += node.offsetHeight + gap;
51
+ });
52
+ setLayout({ ready: true, colWidth, height: Math.max(0, Math.max(...heights) - gap), pos });
53
+ };
54
+ place();
55
+ const resize = new ResizeObserver(place);
56
+ resize.observe(root);
57
+ nodes.current.forEach((node) => resize.observe(node));
58
+ return () => resize.disconnect();
59
+ }, [keys.join("|"), minColumnWidth, maxColumns, gap]);
60
+ return /* @__PURE__ */ jsx(
61
+ "div",
62
+ {
63
+ ref: rootRef,
64
+ className: `bl-masonry ${className}`,
65
+ "data-ready": layout.ready,
66
+ style: { "--bl-col-w": `${layout.colWidth}px`, "--bl-dur": `${duration}ms`, height: layout.height, ...style },
67
+ children: items.map((item, i) => {
68
+ const k = keys[i];
69
+ const p = layout.pos[k] ?? { x: 0, y: 0 };
70
+ return /* @__PURE__ */ jsx(
71
+ "div",
72
+ {
73
+ ref: (node) => {
74
+ if (node) nodes.current.set(k, node);
75
+ else nodes.current.delete(k);
76
+ },
77
+ className: "bl-masonry__item",
78
+ "data-new": fresh.has(k) || void 0,
79
+ style: { "--x": `${p.x}px`, "--y": `${p.y}px`, "--i": i },
80
+ children: item
81
+ },
82
+ k
83
+ );
84
+ })
85
+ }
86
+ );
87
+ }
88
+ export {
89
+ MasonryWall as default
90
+ };
@@ -0,0 +1,32 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export interface MegaMenuItem {
3
+ label: string;
4
+ /** Opens the shared panel with this content. */
5
+ content?: ReactNode;
6
+ /** A plain link when there is no content. */
7
+ href?: string;
8
+ }
9
+ export interface MegaMenuProps {
10
+ items?: MegaMenuItem[];
11
+ /** Hover intent before opening, in ms. */
12
+ openDelay?: number;
13
+ /** Grace period before closing after the pointer leaves, in ms. */
14
+ closeDelay?: number;
15
+ /** Space between the bar and the panel. */
16
+ gap?: number;
17
+ maxPanelWidth?: number;
18
+ /** Slide and resize time between triggers, in ms. */
19
+ duration?: number;
20
+ label?: string;
21
+ backgroundColor?: string;
22
+ textColor?: string;
23
+ mutedColor?: string;
24
+ hoverColor?: string;
25
+ lineColor?: string;
26
+ accentColor?: string;
27
+ radius?: number;
28
+ fontFamily?: string;
29
+ className?: string;
30
+ style?: CSSProperties;
31
+ }
32
+ export default function MegaMenu({ items, openDelay, closeDelay, gap, maxPanelWidth, duration, label, backgroundColor, textColor, mutedColor, hoverColor, lineColor, accentColor, radius, fontFamily, className, style }: MegaMenuProps): import("react").JSX.Element;