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,214 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useInsertionEffect, useRef, useState } from "react";
4
+ const STYLE_ID = "bl-terminal-demo";
5
+ const CSS = `
6
+ .bl-term { position: relative; width: 100%; max-width: var(--bl-w); overflow: hidden; border-radius: var(--bl-radius); background: var(--bl-bg); color: var(--bl-ink); box-shadow: inset 0 0 0 1px var(--bl-line), 0 30px 60px -30px rgba(0,0,0,0.6); font: 400 var(--bl-size)/1.6 var(--bl-font); }
7
+ .bl-term__bar { position: relative; display: flex; align-items: center; height: 38px; padding: 0 14px; border-bottom: 1px solid var(--bl-line); background: var(--bl-bar); }
8
+ .bl-term__lights { display: flex; gap: 7px; }
9
+ .bl-term__lights i { width: 11px; height: 11px; border-radius: 50%; }
10
+ .bl-term__title { position: absolute; left: 50%; transform: translateX(-50%); color: var(--bl-muted); font-size: 12px; white-space: nowrap; }
11
+ .bl-term__replay { margin-left: auto; padding: 3px 8px; border: 1px solid var(--bl-line); border-radius: 6px; background: transparent; color: var(--bl-muted); font: inherit; font-size: 11px; cursor: pointer; }
12
+ .bl-term__replay:hover { color: var(--bl-ink); }
13
+ .bl-term__replay:focus-visible { outline: 2px solid var(--bl-prompt); outline-offset: 2px; }
14
+ .bl-term__body { height: var(--bl-h); overflow-y: auto; padding: 14px 16px; scrollbar-width: thin; }
15
+ .bl-term__line { min-height: 1.6em; white-space: pre-wrap; word-break: break-word; }
16
+ .bl-term__prompt { color: var(--bl-prompt); margin-right: 0.6em; user-select: none; }
17
+ .bl-term__line[data-kind="output"] { color: var(--bl-muted); }
18
+ .bl-term__line[data-kind="success"] { color: var(--bl-success); }
19
+ .bl-term__line[data-kind="error"] { color: var(--bl-error); }
20
+ .bl-term__line[data-kind="info"] { color: var(--bl-info); }
21
+ .bl-term__line[data-kind="spinner"] { color: var(--bl-ink); }
22
+ .bl-term__mark { display: inline-block; width: 1.4em; }
23
+ .bl-term__cursor { display: inline-block; width: 0.6em; height: 1.15em; margin-left: 1px; vertical-align: text-bottom; background: var(--bl-ink); animation: bl-term-blink 1s steps(1) infinite; }
24
+ @keyframes bl-term-blink { 50% { opacity: 0; } }
25
+ .bl-term__sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
26
+ @media (prefers-reduced-motion: reduce) { .bl-term__cursor { animation: none; } }
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
+ const SPINNER = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
37
+ const MARKS = { success: "\u2714", error: "\u2716", info: "\u2139" };
38
+ const DEFAULT_SCRIPT = [
39
+ { type: "command", text: "npx bits-lab add dot-globe" },
40
+ { type: "output", text: "Resolving registry\u2026" },
41
+ { type: "spinner", text: "Fetching component", duration: 1200, done: "Fetched dot-globe.jsx (12 kB)" },
42
+ { type: "spinner", text: "Writing files", duration: 800, done: "Wrote src/components/DotGlobe.jsx" },
43
+ { type: "info", text: "No dependencies to install." },
44
+ { type: "pause", duration: 400 },
45
+ { type: "command", text: "npm run dev" },
46
+ { type: "output", text: " VITE ready in 312 ms\n \u279C Local: http://localhost:5173/" },
47
+ { type: "success", text: "Done. Happy shipping!" }
48
+ ];
49
+ const finalLine = (step, prompt) => {
50
+ if (step.type === "command") return { kind: "command", text: step.text, prompt: step.prompt ?? prompt };
51
+ if (step.type === "spinner") return { kind: step.failed ? "error" : "success", text: step.done ?? step.text };
52
+ return { kind: step.type, text: step.text };
53
+ };
54
+ function TerminalDemo({
55
+ script = DEFAULT_SCRIPT,
56
+ title = "zsh \u2014 bits-lab",
57
+ prompt = "$",
58
+ typingSpeed = 45,
59
+ lineDelay = 260,
60
+ loop = false,
61
+ loopDelay = 2600,
62
+ startOnView = true,
63
+ showControls = true,
64
+ width = 640,
65
+ height = 300,
66
+ radius = 12,
67
+ fontSize = 13.5,
68
+ fontFamily = "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
69
+ background = "#11131c",
70
+ barColor = "#181b27",
71
+ lineColor = "rgba(255,255,255,0.08)",
72
+ textColor = "#e8eaf0",
73
+ mutedColor = "#94b0c2",
74
+ promptColor = "#73eff7",
75
+ successColor = "#a7f070",
76
+ errorColor = "#ef7d57",
77
+ infoColor = "#ffcd75",
78
+ className = "",
79
+ style
80
+ }) {
81
+ useStyles();
82
+ const rootRef = useRef(null);
83
+ const bodyRef = useRef(null);
84
+ const [lines, setLines] = useState([]);
85
+ const [running, setRunning] = useState(false);
86
+ const [finished, setFinished] = useState(false);
87
+ const [run, setRun] = useState(0);
88
+ const [inView, setInView] = useState(!startOnView);
89
+ const scriptKey = JSON.stringify(script);
90
+ useEffect(() => {
91
+ if (!startOnView || inView) return;
92
+ const io = new IntersectionObserver(([entry]) => entry.isIntersecting && setInView(true), { threshold: 0.35 });
93
+ io.observe(rootRef.current);
94
+ return () => io.disconnect();
95
+ }, [startOnView, inView]);
96
+ useEffect(() => {
97
+ if (!inView) return;
98
+ const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
99
+ if (reduced) {
100
+ setLines(script.filter((step) => step.type !== "pause").map((step) => finalLine(step, prompt)));
101
+ setFinished(true);
102
+ return;
103
+ }
104
+ let cancelled = false;
105
+ const timers = /* @__PURE__ */ new Set();
106
+ const wait = (ms) => new Promise((resolve) => {
107
+ const id = setTimeout(() => {
108
+ timers.delete(id);
109
+ resolve();
110
+ }, ms);
111
+ timers.add(id);
112
+ });
113
+ const push = (line) => setLines((prev) => [...prev, line]);
114
+ const patchLast = (patch) => setLines((prev) => [...prev.slice(0, -1), { ...prev[prev.length - 1], ...patch }]);
115
+ (async () => {
116
+ do {
117
+ setLines([]);
118
+ setFinished(false);
119
+ setRunning(true);
120
+ for (const step of script) {
121
+ if (cancelled) return;
122
+ if (step.type === "pause") {
123
+ await wait(step.duration ?? 600);
124
+ } else if (step.type === "command") {
125
+ push({ kind: "command", text: "", prompt: step.prompt ?? prompt, typing: true });
126
+ await wait(step.delay ?? 380);
127
+ for (let i = 1; i <= step.text.length && !cancelled; i++) {
128
+ patchLast({ text: step.text.slice(0, i) });
129
+ await wait(typingSpeed * (0.55 + Math.random() * 0.9));
130
+ }
131
+ await wait(320);
132
+ patchLast({ typing: false });
133
+ } else if (step.type === "spinner") {
134
+ push({ kind: "spinner", text: step.text, frame: 0 });
135
+ const end = performance.now() + (step.duration ?? 1e3);
136
+ for (let frame = 1; performance.now() < end && !cancelled; frame++) {
137
+ await wait(80);
138
+ patchLast({ frame });
139
+ }
140
+ patchLast(finalLine(step, prompt));
141
+ } else {
142
+ push(finalLine(step, prompt));
143
+ }
144
+ await wait(step.after ?? lineDelay);
145
+ }
146
+ if (cancelled) return;
147
+ setRunning(false);
148
+ setFinished(true);
149
+ if (loop) await wait(loopDelay);
150
+ } while (loop && !cancelled);
151
+ })();
152
+ return () => {
153
+ cancelled = true;
154
+ timers.forEach(clearTimeout);
155
+ };
156
+ }, [inView, run, scriptKey, prompt, typingSpeed, lineDelay, loop, loopDelay]);
157
+ useEffect(() => {
158
+ const body = bodyRef.current;
159
+ if (body) body.scrollTop = body.scrollHeight;
160
+ }, [lines]);
161
+ const transcript = script.filter((step) => step.type !== "pause").map((step) => finalLine(step, prompt)).map((line) => line.kind === "command" ? `${line.prompt} ${line.text}` : line.text).join("\n");
162
+ return /* @__PURE__ */ jsxs(
163
+ "div",
164
+ {
165
+ ref: rootRef,
166
+ className: `bl-term ${className}`,
167
+ style: {
168
+ "--bl-w": `${width}px`,
169
+ "--bl-h": `${height}px`,
170
+ "--bl-radius": `${radius}px`,
171
+ "--bl-size": `${fontSize}px`,
172
+ "--bl-font": fontFamily,
173
+ "--bl-bg": background,
174
+ "--bl-bar": barColor,
175
+ "--bl-line": lineColor,
176
+ "--bl-ink": textColor,
177
+ "--bl-muted": mutedColor,
178
+ "--bl-prompt": promptColor,
179
+ "--bl-success": successColor,
180
+ "--bl-error": errorColor,
181
+ "--bl-info": infoColor,
182
+ ...style
183
+ },
184
+ children: [
185
+ /* @__PURE__ */ jsxs("div", { className: "bl-term__bar", children: [
186
+ /* @__PURE__ */ jsxs("span", { className: "bl-term__lights", "aria-hidden": "true", children: [
187
+ /* @__PURE__ */ jsx("i", { style: { background: "#ff5f57" } }),
188
+ /* @__PURE__ */ jsx("i", { style: { background: "#febc2e" } }),
189
+ /* @__PURE__ */ jsx("i", { style: { background: "#28c840" } })
190
+ ] }),
191
+ /* @__PURE__ */ jsx("span", { className: "bl-term__title", children: title }),
192
+ showControls && !loop && finished && /* @__PURE__ */ jsx("button", { className: "bl-term__replay", type: "button", onClick: () => setRun((r) => r + 1), children: "Replay" })
193
+ ] }),
194
+ /* @__PURE__ */ jsxs("div", { ref: bodyRef, className: "bl-term__body", "aria-hidden": "true", children: [
195
+ lines.map((line, i) => /* @__PURE__ */ jsxs("div", { className: "bl-term__line", "data-kind": line.kind, children: [
196
+ line.kind === "command" && /* @__PURE__ */ jsx("span", { className: "bl-term__prompt", children: line.prompt }),
197
+ line.kind === "spinner" && /* @__PURE__ */ jsx("span", { className: "bl-term__mark", children: SPINNER[line.frame % SPINNER.length] }),
198
+ MARKS[line.kind] && /* @__PURE__ */ jsx("span", { className: "bl-term__mark", children: MARKS[line.kind] }),
199
+ line.text,
200
+ line.typing && /* @__PURE__ */ jsx("span", { className: "bl-term__cursor" })
201
+ ] }, i)),
202
+ (finished || !running) && /* @__PURE__ */ jsxs("div", { className: "bl-term__line", children: [
203
+ /* @__PURE__ */ jsx("span", { className: "bl-term__prompt", children: prompt }),
204
+ /* @__PURE__ */ jsx("span", { className: "bl-term__cursor" })
205
+ ] })
206
+ ] }),
207
+ /* @__PURE__ */ jsx("pre", { className: "bl-term__sr", "aria-label": `${title} terminal transcript`, children: transcript })
208
+ ]
209
+ }
210
+ );
211
+ }
212
+ export {
213
+ TerminalDemo as default
214
+ };
@@ -0,0 +1,35 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export interface Testimonial {
3
+ quote: ReactNode;
4
+ name: ReactNode;
5
+ role?: ReactNode;
6
+ /** An image URL or any node. */
7
+ avatar?: ReactNode;
8
+ }
9
+ export interface TestimonialWallProps {
10
+ testimonials?: Testimonial[];
11
+ rows?: number;
12
+ /** Pixels per second. */
13
+ speed?: number;
14
+ cardWidth?: number;
15
+ /** Lines shown until a card is hovered or focused. */
16
+ lines?: number;
17
+ gap?: number;
18
+ /** Width of the edge fade in px. */
19
+ fade?: number;
20
+ showPause?: boolean;
21
+ pauseLabel?: string;
22
+ playLabel?: string;
23
+ label?: string;
24
+ backgroundColor?: string;
25
+ cardColor?: string;
26
+ textColor?: string;
27
+ mutedColor?: string;
28
+ lineColor?: string;
29
+ accentColor?: string;
30
+ radius?: number;
31
+ fontFamily?: string;
32
+ className?: string;
33
+ style?: CSSProperties;
34
+ }
35
+ export default function TestimonialWall({ testimonials, rows, speed, cardWidth, lines, gap, fade, showPause, pauseLabel, playLabel, label, backgroundColor, cardColor, textColor, mutedColor, lineColor, accentColor, radius, fontFamily, className, style }: TestimonialWallProps): import("react").JSX.Element;
@@ -0,0 +1,131 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useInsertionEffect, useRef, useState } from "react";
4
+ const STYLE_ID = "bl-testimonial-wall";
5
+ const CSS = `
6
+ .bl-wall { position: relative; display: grid; gap: var(--bl-gap); width: 100%; color: var(--bl-ink); font-family: var(--bl-font); }
7
+ .bl-wall__row { position: relative; overflow: hidden; padding: 14px 0; -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-wall__track { display: flex; width: max-content; animation: bl-wall-scroll var(--bl-dur, 60s) linear infinite; animation-direction: var(--bl-dir, normal); }
9
+ .bl-wall__set { display: flex; flex: 0 0 auto; align-items: flex-start; gap: var(--bl-gap); margin: 0; padding: 0 var(--bl-gap) 0 0; list-style: none; }
10
+ .bl-wall__row:hover .bl-wall__track, .bl-wall__row:focus-within .bl-wall__track, .bl-wall[data-paused] .bl-wall__track { animation-play-state: paused; }
11
+ .bl-wall__card { position: relative; display: grid; gap: 12px; width: var(--bl-card-w); margin: 0; padding: 18px; box-sizing: border-box; border-radius: var(--bl-radius); background: var(--bl-card); box-shadow: 0 0 0 1px var(--bl-line); outline: none; transition: transform 220ms cubic-bezier(.2,.9,.25,1.2), box-shadow 220ms; }
12
+ .bl-wall__card:hover, .bl-wall__card:focus-visible { z-index: 1; transform: translateY(-4px) scale(1.03); box-shadow: 0 0 0 2px var(--bl-accent), 0 18px 40px -18px rgba(0,0,0,0.7); }
13
+ .bl-wall__quote { margin: 0; color: var(--bl-ink); font-size: 15px; line-height: 1.55; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: var(--bl-lines); overflow: hidden; }
14
+ .bl-wall__card:hover .bl-wall__quote, .bl-wall__card:focus-visible .bl-wall__quote { -webkit-line-clamp: unset; }
15
+ .bl-wall__who { display: flex; align-items: center; gap: 10px; min-width: 0; }
16
+ .bl-wall__avatar { flex: 0 0 auto; display: grid; place-items: center; width: 36px; height: 36px; overflow: hidden; border-radius: 50%; background: var(--bl-line); }
17
+ .bl-wall__avatar img { width: 100%; height: 100%; object-fit: cover; }
18
+ .bl-wall__name { display: block; font-size: 14px; font-weight: 700; font-style: normal; }
19
+ .bl-wall__role { display: block; color: var(--bl-muted); font-size: 13px; }
20
+ .bl-wall__pause { justify-self: end; display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border: 0; border-radius: 999px; background: var(--bl-card); color: var(--bl-muted); font: inherit; font-size: 13px; cursor: pointer; box-shadow: 0 0 0 1px var(--bl-line); }
21
+ .bl-wall__pause:hover { color: var(--bl-ink); }
22
+ .bl-wall__pause:focus-visible { outline: 2px solid var(--bl-accent); outline-offset: 2px; }
23
+ @keyframes bl-wall-scroll { to { transform: translateX(-50%); } }
24
+ @media (prefers-reduced-motion: reduce) {
25
+ .bl-wall__row { overflow-x: auto; -webkit-mask-image: none; mask-image: none; }
26
+ .bl-wall__track { animation: none; }
27
+ .bl-wall__set[aria-hidden] { display: none; }
28
+ .bl-wall__pause { display: none; }
29
+ }
30
+ `;
31
+ function useStyles() {
32
+ useInsertionEffect(() => {
33
+ if (typeof document === "undefined") return;
34
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
35
+ style.textContent = CSS;
36
+ if (!style.isConnected) document.head.appendChild(style);
37
+ }, []);
38
+ }
39
+ function Card({ item, hidden }) {
40
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("figure", { className: "bl-wall__card", tabIndex: hidden ? -1 : 0, children: [
41
+ /* @__PURE__ */ jsx("blockquote", { className: "bl-wall__quote", children: item.quote }),
42
+ /* @__PURE__ */ jsxs("figcaption", { className: "bl-wall__who", children: [
43
+ item.avatar && /* @__PURE__ */ jsx("span", { className: "bl-wall__avatar", children: typeof item.avatar === "string" ? /* @__PURE__ */ jsx("img", { src: item.avatar, alt: "" }) : item.avatar }),
44
+ /* @__PURE__ */ jsxs("span", { children: [
45
+ /* @__PURE__ */ jsx("cite", { className: "bl-wall__name", children: item.name }),
46
+ item.role && /* @__PURE__ */ jsx("span", { className: "bl-wall__role", children: item.role })
47
+ ] })
48
+ ] })
49
+ ] }) });
50
+ }
51
+ function Row({ items, reverse, speed }) {
52
+ const setRef = useRef(null);
53
+ const [duration, setDuration] = useState(60);
54
+ useEffect(() => {
55
+ const node = setRef.current;
56
+ const measure = () => setDuration(Math.max(8, node.offsetWidth / speed));
57
+ const resize = new ResizeObserver(measure);
58
+ resize.observe(node);
59
+ measure();
60
+ return () => resize.disconnect();
61
+ }, [speed]);
62
+ return /* @__PURE__ */ jsx("div", { className: "bl-wall__row", children: /* @__PURE__ */ jsxs("div", { className: "bl-wall__track", style: { "--bl-dur": `${duration}s`, "--bl-dir": reverse ? "reverse" : "normal" }, children: [
63
+ /* @__PURE__ */ jsx("ul", { ref: setRef, className: "bl-wall__set", children: items.map((item, i) => /* @__PURE__ */ jsx(Card, { item }, i)) }),
64
+ /* @__PURE__ */ jsx("ul", { className: "bl-wall__set", "aria-hidden": "true", children: items.map((item, i) => /* @__PURE__ */ jsx(Card, { item, hidden: true }, i)) })
65
+ ] }) });
66
+ }
67
+ function TestimonialWall({
68
+ testimonials = [],
69
+ rows = 3,
70
+ speed = 30,
71
+ cardWidth = 300,
72
+ lines = 4,
73
+ gap = 16,
74
+ fade = 80,
75
+ showPause = true,
76
+ pauseLabel = "Pause",
77
+ playLabel = "Play",
78
+ label = "What people say",
79
+ backgroundColor = "#1a1c2c",
80
+ cardColor = "#262b44",
81
+ textColor = "#f4f4f4",
82
+ mutedColor = "#94b0c2",
83
+ lineColor = "#333c57",
84
+ accentColor = "#73eff7",
85
+ radius = 14,
86
+ fontFamily = "ui-sans-serif, system-ui, sans-serif",
87
+ className = "",
88
+ style
89
+ }) {
90
+ useStyles();
91
+ const [paused, setPaused] = useState(false);
92
+ const rowCount = Math.max(1, Math.min(rows, testimonials.length || 1));
93
+ const perRow = Math.max(3, Math.ceil(testimonials.length / rowCount));
94
+ const dealt = Array.from(
95
+ { length: rowCount },
96
+ (_, r) => testimonials.length ? Array.from({ length: perRow }, (_2, i) => testimonials[(r * perRow + i) % testimonials.length]) : []
97
+ );
98
+ return /* @__PURE__ */ jsxs(
99
+ "section",
100
+ {
101
+ className: `bl-wall ${className}`,
102
+ "aria-label": label,
103
+ "data-paused": paused || void 0,
104
+ style: {
105
+ "--bl-gap": `${gap}px`,
106
+ "--bl-fade": `${fade}px`,
107
+ "--bl-card-w": `min(${cardWidth}px, 80vw)`,
108
+ "--bl-lines": lines,
109
+ "--bl-bg": backgroundColor,
110
+ "--bl-card": cardColor,
111
+ "--bl-ink": textColor,
112
+ "--bl-muted": mutedColor,
113
+ "--bl-line": lineColor,
114
+ "--bl-accent": accentColor,
115
+ "--bl-radius": `${radius}px`,
116
+ "--bl-font": fontFamily,
117
+ ...style
118
+ },
119
+ children: [
120
+ dealt.map((items, r) => /* @__PURE__ */ jsx(Row, { items, reverse: r % 2 === 1, speed: speed * (1 + r % 3 * 0.18) }, r)),
121
+ showPause && /* @__PURE__ */ jsxs("button", { type: "button", className: "bl-wall__pause", onClick: () => setPaused((p) => !p), children: [
122
+ /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "currentColor", "aria-hidden": "true", children: paused ? /* @__PURE__ */ jsx("path", { d: "M3 1.5v9l7.5-4.5z" }) : /* @__PURE__ */ jsx("path", { d: "M2.5 1.5h2.5v9H2.5zM7 1.5h2.5v9H7z" }) }),
123
+ paused ? playLabel : pauseLabel
124
+ ] })
125
+ ]
126
+ }
127
+ );
128
+ }
129
+ export {
130
+ TestimonialWall as default
131
+ };
@@ -0,0 +1,36 @@
1
+ import { type CSSProperties } from 'react';
2
+ export type PathPreset = 'wave' | 'arc' | 'smile' | 'circle' | 'loop';
3
+ export declare const PATHS: Record<PathPreset, {
4
+ viewBox: string;
5
+ d: string;
6
+ }>;
7
+ export interface TextOnPathProps {
8
+ /** End it with a separator so the loop reads cleanly. */
9
+ text?: string;
10
+ /** A preset name or any SVG path data (pair custom paths with viewBox). */
11
+ path?: PathPreset | (string & {});
12
+ viewBox?: string;
13
+ /** Minimum copies of the text; more are added if the path needs them. */
14
+ repeat?: number;
15
+ /** Scroll speed in viewBox units per second; 0 for still text. */
16
+ speed?: number;
17
+ direction?: 'forward' | 'reverse';
18
+ /** Starting position along the path, in percent. */
19
+ offset?: number;
20
+ fontSize?: number;
21
+ fontWeight?: number;
22
+ letterSpacing?: number;
23
+ /** Draw the guide path. */
24
+ showPath?: boolean;
25
+ pauseOnHover?: boolean;
26
+ /** Max width, in px. */
27
+ width?: number;
28
+ textColor?: string;
29
+ guideColor?: string;
30
+ fontFamily?: string;
31
+ /** Accessible name; defaults to the text. */
32
+ label?: string;
33
+ className?: string;
34
+ style?: CSSProperties;
35
+ }
36
+ export default function TextOnPath({ text, path, viewBox, repeat, speed, direction, offset, fontSize, fontWeight, letterSpacing, showPath, pauseOnHover, width, textColor, guideColor, fontFamily, label, className, style }: TextOnPathProps): import("react").JSX.Element;
@@ -0,0 +1,130 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useId, useInsertionEffect, useRef, useState } from "react";
4
+ const STYLE_ID = "bl-text-on-path";
5
+ const CSS = `
6
+ .bl-tpath { display: block; width: 100%; max-width: var(--bl-w); overflow: visible; color: var(--bl-ink); font-family: var(--bl-font); }
7
+ .bl-tpath text { fill: currentColor; font-size: var(--bl-size); font-weight: var(--bl-weight); letter-spacing: var(--bl-spacing); }
8
+ .bl-tpath__guide { fill: none; stroke: var(--bl-guide); stroke-width: 1; stroke-dasharray: 3 5; }
9
+ `;
10
+ function useStyles() {
11
+ useInsertionEffect(() => {
12
+ if (typeof document === "undefined") return;
13
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
14
+ style.textContent = CSS;
15
+ if (!style.isConnected) document.head.appendChild(style);
16
+ }, []);
17
+ }
18
+ const PATHS = {
19
+ wave: { viewBox: "0 0 1000 240", d: "M0,140 C125,40 250,40 375,140 S625,240 750,140 S875,40 1000,120" },
20
+ arc: { viewBox: "0 0 1000 320", d: "M40,300 Q500,-120 960,300" },
21
+ smile: { viewBox: "0 0 1000 300", d: "M40,40 Q500,460 960,40" },
22
+ circle: { viewBox: "0 0 1000 1000", d: "M500,500 m-380,0 a380,380 0 1,1 760,0 a380,380 0 1,1 -760,0" },
23
+ loop: { viewBox: "0 0 1000 400", d: "M40,300 C200,300 260,60 420,60 C600,60 560,340 420,340 C280,340 360,120 600,120 C780,120 820,300 960,300" }
24
+ };
25
+ function TextOnPath({
26
+ text = "Text along a path \xB7 ",
27
+ path = "wave",
28
+ viewBox,
29
+ repeat = 3,
30
+ speed = 40,
31
+ direction = "forward",
32
+ offset = 0,
33
+ fontSize = 42,
34
+ fontWeight = 700,
35
+ letterSpacing = 1,
36
+ showPath = false,
37
+ pauseOnHover = true,
38
+ width = 900,
39
+ textColor = "#f4f4f4",
40
+ guideColor = "rgba(255,255,255,0.18)",
41
+ fontFamily = "ui-sans-serif, system-ui, sans-serif",
42
+ label,
43
+ className = "",
44
+ style
45
+ }) {
46
+ useStyles();
47
+ const uid = useId().replace(/[^a-zA-Z0-9_-]/g, "");
48
+ const preset = typeof path === "string" && PATHS[path] ? PATHS[path] : null;
49
+ const d = preset ? preset.d : path;
50
+ const box = viewBox ?? preset?.viewBox ?? "0 0 1000 300";
51
+ const svgRef = useRef(null);
52
+ const textPathRef = useRef(null);
53
+ const hovering = useRef(false);
54
+ const [grown, setGrown] = useState(1);
55
+ const copies = Math.max(repeat, grown);
56
+ useEffect(() => {
57
+ const svg = svgRef.current;
58
+ const textPath = textPathRef.current;
59
+ if (!svg || !textPath) return void 0;
60
+ textPath.setAttribute("startOffset", `${offset}%`);
61
+ if (!speed || window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) return void 0;
62
+ const pathEl = svg.querySelector("path[id]");
63
+ const length = pathEl.getTotalLength();
64
+ const copy = textPath.getComputedTextLength() / copies || length;
65
+ const needed = Math.ceil(length / copy) + 1;
66
+ if (needed > copies) {
67
+ setGrown(needed);
68
+ return void 0;
69
+ }
70
+ let shift = 0;
71
+ let last = performance.now();
72
+ let frame = 0;
73
+ let visible = true;
74
+ const sign = direction === "reverse" ? 1 : -1;
75
+ const tick = (now) => {
76
+ const dt = Math.min(0.1, (now - last) / 1e3);
77
+ last = now;
78
+ if (!(pauseOnHover && hovering.current)) shift = (shift + speed * dt) % copy;
79
+ textPath.setAttribute("startOffset", `${offset / 100 * length + sign * shift + (sign < 0 ? 0 : -copy)}`);
80
+ if (visible) frame = requestAnimationFrame(tick);
81
+ };
82
+ const observer = new IntersectionObserver(([entry]) => {
83
+ visible = entry.isIntersecting;
84
+ if (visible && !frame) {
85
+ last = performance.now();
86
+ frame = requestAnimationFrame(tick);
87
+ } else if (!visible) {
88
+ cancelAnimationFrame(frame);
89
+ frame = 0;
90
+ }
91
+ });
92
+ observer.observe(svg);
93
+ frame = requestAnimationFrame(tick);
94
+ return () => {
95
+ cancelAnimationFrame(frame);
96
+ observer.disconnect();
97
+ };
98
+ }, [d, speed, direction, copies, offset, text, fontSize, letterSpacing, pauseOnHover]);
99
+ const content = speed ? text.repeat(copies) : text;
100
+ return /* @__PURE__ */ jsxs(
101
+ "svg",
102
+ {
103
+ ref: svgRef,
104
+ className: `bl-tpath ${className}`,
105
+ viewBox: box,
106
+ role: "img",
107
+ "aria-label": label ?? text.trim(),
108
+ onPointerEnter: () => hovering.current = true,
109
+ onPointerLeave: () => hovering.current = false,
110
+ style: {
111
+ "--bl-w": `${width}px`,
112
+ "--bl-size": `${fontSize}px`,
113
+ "--bl-weight": fontWeight,
114
+ "--bl-spacing": `${letterSpacing}px`,
115
+ "--bl-ink": textColor,
116
+ "--bl-guide": guideColor,
117
+ "--bl-font": fontFamily,
118
+ ...style
119
+ },
120
+ children: [
121
+ /* @__PURE__ */ jsx("path", { id: `${uid}-path`, d, fill: "none", className: showPath ? "bl-tpath__guide" : void 0 }),
122
+ /* @__PURE__ */ jsx("text", { "aria-hidden": "true", dominantBaseline: "middle", children: /* @__PURE__ */ jsx("textPath", { ref: textPathRef, href: `#${uid}-path`, children: content }) })
123
+ ]
124
+ }
125
+ );
126
+ }
127
+ export {
128
+ PATHS,
129
+ TextOnPath as default
130
+ };
@@ -0,0 +1,36 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export interface ThinkingStep {
3
+ id?: string | number;
4
+ label: ReactNode;
5
+ status?: 'pending' | 'active' | 'done';
6
+ detail?: ReactNode;
7
+ }
8
+ export interface ThinkingShimmerProps {
9
+ /** While true the label shimmers and the timer ticks. */
10
+ thinking?: boolean;
11
+ steps?: ThinkingStep[];
12
+ label?: string;
13
+ /** Header text once done, given the elapsed seconds. */
14
+ doneLabel?: (seconds: number) => string;
15
+ /** Epoch ms when the work began, if it started before this mounted. */
16
+ startedAt?: number;
17
+ showTimer?: boolean;
18
+ defaultOpen?: boolean;
19
+ open?: boolean;
20
+ onOpenChange?: (open: boolean) => void;
21
+ /** One shimmer pass, in ms. */
22
+ shimmerSpeed?: number;
23
+ /** Max width, in px. */
24
+ width?: number;
25
+ textColor?: string;
26
+ mutedColor?: string;
27
+ shineColor?: string;
28
+ lineColor?: string;
29
+ hoverColor?: string;
30
+ accentColor?: string;
31
+ successColor?: string;
32
+ fontFamily?: string;
33
+ className?: string;
34
+ style?: CSSProperties;
35
+ }
36
+ export default function ThinkingShimmer({ thinking, steps, label, doneLabel, startedAt, showTimer, defaultOpen, open: controlledOpen, onOpenChange, shimmerSpeed, width, textColor, mutedColor, shineColor, lineColor, hoverColor, accentColor, successColor, fontFamily, className, style }: ThinkingShimmerProps): import("react").JSX.Element;