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,100 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useInsertionEffect, useRef } from "react";
4
+ const STYLE_ID = "bl-scroll-tilt";
5
+ const CSS = `
6
+ .bl-tilt { --bl-p: 0; position: relative; perspective: var(--bl-perspective); }
7
+ .bl-tilt__card { position: relative; overflow: hidden; border-radius: var(--bl-radius); box-shadow: 0 0 0 var(--bl-border) var(--bl-edge), 0 calc(10px + var(--bl-p) * 40px) calc(30px + var(--bl-p) * 60px) -20px var(--bl-shadow); transform-origin: 50% 0; transform: rotateX(calc((1 - var(--bl-p)) * var(--bl-tilt))) scale(calc(var(--bl-scale) + (1 - var(--bl-scale)) * var(--bl-p))) translateY(calc((1 - var(--bl-p)) * var(--bl-lift))); will-change: transform; }
8
+ .bl-tilt__card > img, .bl-tilt__card > video { display: block; width: 100%; height: auto; }
9
+ .bl-tilt__shine { position: absolute; inset: 0; pointer-events: none; background: linear-gradient(115deg, transparent 30%, var(--bl-shine) 48%, transparent 66%); background-size: 250% 100%; background-position: calc(100% - var(--bl-p) * 100%) 0; opacity: calc(1 - var(--bl-p) * 0.7); mix-blend-mode: screen; }
10
+ @media (prefers-reduced-motion: reduce) {
11
+ .bl-tilt__card { transform: none; }
12
+ .bl-tilt__shine { display: none; }
13
+ }
14
+ `;
15
+ function useStyles() {
16
+ useInsertionEffect(() => {
17
+ if (typeof document === "undefined") return;
18
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
19
+ style.textContent = CSS;
20
+ if (!style.isConnected) document.head.appendChild(style);
21
+ }, []);
22
+ }
23
+ function scrollParent(node) {
24
+ for (let el = node?.parentElement; el; el = el.parentElement) {
25
+ if (/(auto|scroll|overlay)/.test(getComputedStyle(el).overflowY) && el.scrollHeight > el.clientHeight) return el;
26
+ }
27
+ return window;
28
+ }
29
+ const ease = (t) => t * t * (3 - 2 * t);
30
+ function ScrollTilt({
31
+ children,
32
+ tilt = 32,
33
+ scale = 0.88,
34
+ lift = 40,
35
+ start = 1,
36
+ end = 0.35,
37
+ perspective = 1200,
38
+ shine = true,
39
+ radius = 16,
40
+ borderWidth = 1,
41
+ borderColor = "rgba(255,255,255,0.12)",
42
+ shineColor = "rgba(255,255,255,0.35)",
43
+ shadowColor = "rgba(0,0,0,0.6)",
44
+ className = "",
45
+ style
46
+ }) {
47
+ useStyles();
48
+ const ref = useRef(null);
49
+ useEffect(() => {
50
+ const root = ref.current;
51
+ const scroller = scrollParent(root);
52
+ let frame = 0;
53
+ const update = () => {
54
+ frame = 0;
55
+ const rect = root.getBoundingClientRect();
56
+ const viewTop = scroller === window ? 0 : scroller.getBoundingClientRect().top;
57
+ const viewHeight = scroller === window ? window.innerHeight : scroller.clientHeight;
58
+ const top = (rect.top - viewTop) / viewHeight;
59
+ const raw = Math.min(1, Math.max(0, (start - top) / Math.max(0.01, start - end)));
60
+ root.style.setProperty("--bl-p", ease(raw).toFixed(4));
61
+ };
62
+ const schedule = () => {
63
+ if (!frame) frame = requestAnimationFrame(update);
64
+ };
65
+ update();
66
+ scroller.addEventListener("scroll", schedule, { passive: true });
67
+ window.addEventListener("resize", schedule);
68
+ return () => {
69
+ cancelAnimationFrame(frame);
70
+ scroller.removeEventListener("scroll", schedule);
71
+ window.removeEventListener("resize", schedule);
72
+ };
73
+ }, [start, end]);
74
+ return /* @__PURE__ */ jsx(
75
+ "div",
76
+ {
77
+ ref,
78
+ className: `bl-tilt ${className}`,
79
+ style: {
80
+ "--bl-tilt": `${tilt}deg`,
81
+ "--bl-scale": scale,
82
+ "--bl-lift": `${lift}px`,
83
+ "--bl-perspective": `${perspective}px`,
84
+ "--bl-radius": `${radius}px`,
85
+ "--bl-border": `${borderWidth}px`,
86
+ "--bl-edge": borderColor,
87
+ "--bl-shine": shineColor,
88
+ "--bl-shadow": shadowColor,
89
+ ...style
90
+ },
91
+ children: /* @__PURE__ */ jsxs("div", { className: "bl-tilt__card", children: [
92
+ children,
93
+ shine && /* @__PURE__ */ jsx("div", { className: "bl-tilt__shine", "aria-hidden": "true" })
94
+ ] })
95
+ }
96
+ );
97
+ }
98
+ export {
99
+ ScrollTilt as default
100
+ };
@@ -0,0 +1,26 @@
1
+ import { type CSSProperties, type ElementType } from 'react';
2
+ export interface ScrollTypographyProps {
3
+ /** Plain text, split into words. */
4
+ text?: string;
5
+ as?: ElementType;
6
+ /** Scroll speed (px/s) that gives the full effect. */
7
+ sensitivity?: number;
8
+ minWeight?: number;
9
+ maxWeight?: number;
10
+ /** Vertical stretch at full speed (0.25 = 25% taller). */
11
+ stretch?: number;
12
+ /** How much wider fast words get, in %, if the font has a width axis. */
13
+ widthRange?: number;
14
+ /** Lean in degrees at full speed; follows the scroll direction. */
15
+ skew?: number;
16
+ /** Delay per word in ms, which makes the ripple. */
17
+ stagger?: number;
18
+ fontSize?: number | string;
19
+ textColor?: string;
20
+ /** Colour at full speed. */
21
+ accentColor?: string;
22
+ fontFamily?: string;
23
+ className?: string;
24
+ style?: CSSProperties;
25
+ }
26
+ export default function ScrollTypography({ text, as: Tag, sensitivity, minWeight, maxWeight, stretch, widthRange, skew, stagger, fontSize, textColor, accentColor, fontFamily, className, style }: ScrollTypographyProps): import("react").JSX.Element;
@@ -0,0 +1,124 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useInsertionEffect, useRef } from "react";
4
+ const STYLE_ID = "bl-scroll-typography";
5
+ const CSS = `
6
+ .bl-stype { margin: 0; font-family: var(--bl-font); font-size: var(--bl-size); line-height: 1.15; color: var(--bl-ink); text-wrap: balance; }
7
+ .bl-stype__word { --t: 0; --s: 0; display: inline-block; font-weight: calc(var(--bl-wmin) + var(--t) * (var(--bl-wmax) - var(--bl-wmin))); font-stretch: calc(100% + var(--t) * var(--bl-wdth)); color: color-mix(in srgb, var(--bl-accent) calc(var(--t) * 100%), var(--bl-ink)); transform: skewX(calc(var(--s) * var(--bl-skew))) scaleY(calc(1 + var(--t) * var(--bl-stretch))); transform-origin: 50% 100%; will-change: transform; }
8
+ `;
9
+ function useStyles() {
10
+ useInsertionEffect(() => {
11
+ if (typeof document === "undefined") return;
12
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
13
+ style.textContent = CSS;
14
+ if (!style.isConnected) document.head.appendChild(style);
15
+ }, []);
16
+ }
17
+ function scrollerOf(node) {
18
+ for (let el = node.parentElement; el && el !== document.body; el = el.parentElement) {
19
+ const { overflowY } = getComputedStyle(el);
20
+ if (/(auto|scroll|overlay)/.test(overflowY) && el.scrollHeight > el.clientHeight) return el;
21
+ }
22
+ return window;
23
+ }
24
+ function ScrollTypography({
25
+ text = "",
26
+ as: Tag = "p",
27
+ sensitivity = 2400,
28
+ minWeight = 300,
29
+ maxWeight = 900,
30
+ stretch = 0.25,
31
+ widthRange = 0,
32
+ skew = 10,
33
+ stagger = 35,
34
+ fontSize = 56,
35
+ textColor = "#f4f4f4",
36
+ accentColor = "#73eff7",
37
+ fontFamily = '"Roboto Flex", ui-sans-serif, system-ui, sans-serif',
38
+ className = "",
39
+ style
40
+ }) {
41
+ useStyles();
42
+ const rootRef = useRef(null);
43
+ const words = text.split(/\s+/).filter(Boolean);
44
+ useEffect(() => {
45
+ const root = rootRef.current;
46
+ const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
47
+ if (reduced) return void 0;
48
+ const nodes = [...root.querySelectorAll(".bl-stype__word")];
49
+ const scroller = scrollerOf(root);
50
+ const position = () => scroller === window ? window.scrollY : scroller.scrollTop;
51
+ const history = [];
52
+ let lastY = position();
53
+ let smooth = 0;
54
+ let visible = true;
55
+ let raf = 0;
56
+ let last = 0;
57
+ const at = (time) => {
58
+ for (let i = history.length - 1; i >= 0; i--) if (history[i].t <= time) return history[i].v;
59
+ return history.length ? history[0].v : 0;
60
+ };
61
+ const tick = (now) => {
62
+ const dt = Math.max(1e-3, Math.min(0.05, (now - last) / 1e3));
63
+ last = now;
64
+ const y = position();
65
+ const raw = Math.max(-1, Math.min(1, (y - lastY) / dt / sensitivity));
66
+ lastY = y;
67
+ smooth += (raw - smooth) * (1 - Math.exp(-dt * 9));
68
+ history.push({ t: now, v: smooth });
69
+ while (history.length > 2 && now - history[0].t > stagger * nodes.length + 200) history.shift();
70
+ let active = Math.abs(smooth) > 2e-3;
71
+ nodes.forEach((node, i) => {
72
+ const v = at(now - i * stagger);
73
+ if (Math.abs(v) > 2e-3) active = true;
74
+ node.style.setProperty("--t", Math.abs(v).toFixed(3));
75
+ node.style.setProperty("--s", v.toFixed(3));
76
+ });
77
+ if (active) raf = requestAnimationFrame(tick);
78
+ else {
79
+ raf = 0;
80
+ smooth = 0;
81
+ history.length = 0;
82
+ nodes.forEach((node) => {
83
+ node.style.setProperty("--t", "0");
84
+ node.style.setProperty("--s", "0");
85
+ });
86
+ }
87
+ };
88
+ const onScroll = () => {
89
+ if (raf || !visible) return;
90
+ last = performance.now();
91
+ raf = requestAnimationFrame(tick);
92
+ };
93
+ const observer = new IntersectionObserver(([entry]) => {
94
+ visible = entry.isIntersecting;
95
+ lastY = position();
96
+ });
97
+ observer.observe(root);
98
+ scroller.addEventListener("scroll", onScroll, { passive: true });
99
+ return () => {
100
+ cancelAnimationFrame(raf);
101
+ observer.disconnect();
102
+ scroller.removeEventListener("scroll", onScroll);
103
+ nodes.forEach((node) => {
104
+ node.style.removeProperty("--t");
105
+ node.style.removeProperty("--s");
106
+ });
107
+ };
108
+ }, [text, sensitivity, stagger]);
109
+ return /* @__PURE__ */ jsx(
110
+ Tag,
111
+ {
112
+ ref: rootRef,
113
+ className: `bl-stype ${className}`,
114
+ style: { "--bl-size": typeof fontSize === "number" ? `${fontSize}px` : fontSize, "--bl-wmin": minWeight, "--bl-wmax": maxWeight, "--bl-stretch": stretch, "--bl-wdth": `${widthRange}%`, "--bl-skew": `${-skew}deg`, "--bl-ink": textColor, "--bl-accent": accentColor, "--bl-font": fontFamily, ...style },
115
+ children: words.map((word, i) => /* @__PURE__ */ jsxs("span", { children: [
116
+ /* @__PURE__ */ jsx("span", { className: "bl-stype__word", children: word }),
117
+ i < words.length - 1 && " "
118
+ ] }, i))
119
+ }
120
+ );
121
+ }
122
+ export {
123
+ ScrollTypography as default
124
+ };
@@ -0,0 +1,31 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export interface ScrollZoomProps {
3
+ src?: string;
4
+ alt?: string;
5
+ /** Any node (video, canvas) instead of an image. */
6
+ media?: ReactNode;
7
+ /** Shown above the small frame; fades as the zoom starts. */
8
+ heading?: ReactNode;
9
+ /** Revealed over the full-bleed media after the zoom. */
10
+ children?: ReactNode;
11
+ /** Section length in screen heights. */
12
+ length?: number;
13
+ /** Share of the scroll spent zooming; the rest reveals. */
14
+ zoomEnd?: number;
15
+ /** Starting frame width as a share of the stage. */
16
+ startWidth?: number;
17
+ startAspect?: number;
18
+ radius?: number;
19
+ /** Space above the frame for the heading, as a share of the stage height. */
20
+ headingSpace?: number;
21
+ dim?: number;
22
+ dimColor?: string;
23
+ textColor?: string;
24
+ backgroundColor?: string;
25
+ /** Style for the media wrapper (e.g. imageRendering: "pixelated"). */
26
+ mediaStyle?: CSSProperties;
27
+ fontFamily?: string;
28
+ className?: string;
29
+ style?: CSSProperties;
30
+ }
31
+ export default function ScrollZoom({ src, alt, media, heading, children, length, zoomEnd, startWidth, startAspect, radius, headingSpace, dim, dimColor, textColor, backgroundColor, mediaStyle, fontFamily, className, style }: ScrollZoomProps): import("react").JSX.Element;
@@ -0,0 +1,123 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useInsertionEffect, useRef } from "react";
4
+ const STYLE_ID = "bl-scroll-zoom";
5
+ const CSS = `
6
+ .bl-zoom { position: relative; height: calc(var(--bl-view, 100vh) * var(--bl-length)); color: var(--bl-ink); font-family: var(--bl-font); }
7
+ .bl-zoom__stage { position: sticky; top: 0; height: var(--bl-view, 100vh); overflow: hidden; }
8
+ .bl-zoom__media { position: absolute; inset: 0; clip-path: var(--bl-clip, inset(0)); will-change: clip-path; }
9
+ .bl-zoom__media > img, .bl-zoom__media > video { display: block; width: 100%; height: 100%; object-fit: cover; transform: scale(calc(1.18 - var(--bl-p, 1) * 0.18)); }
10
+ .bl-zoom__media > :not(img):not(video) { width: 100%; height: 100%; }
11
+ .bl-zoom__dim { position: absolute; inset: 0; background: var(--bl-dim-color); opacity: calc(var(--bl-reveal, 1) * var(--bl-dim)); pointer-events: none; }
12
+ .bl-zoom__heading { position: absolute; left: 0; right: 0; top: 0; display: grid; place-items: center; height: var(--bl-head-h); padding: 0 16px; text-align: center; opacity: calc(1 - var(--bl-p, 1) * 3); transform: translateY(calc(var(--bl-p, 1) * -40px)); pointer-events: none; }
13
+ .bl-zoom__reveal { position: absolute; inset: 0; display: grid; place-items: center; padding: 24px; text-align: center; opacity: var(--bl-reveal, 1); transform: translateY(calc((1 - var(--bl-reveal, 1)) * 30px)); }
14
+ .bl-zoom[data-hidden-reveal] .bl-zoom__reveal { visibility: hidden; }
15
+ .bl-zoom[data-static] { height: auto; }
16
+ .bl-zoom[data-static] .bl-zoom__stage { position: relative; height: var(--bl-view, 100vh); }
17
+ `;
18
+ function useStyles() {
19
+ useInsertionEffect(() => {
20
+ if (typeof document === "undefined") return;
21
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
22
+ style.textContent = CSS;
23
+ if (!style.isConnected) document.head.appendChild(style);
24
+ }, []);
25
+ }
26
+ function scrollParent(node) {
27
+ for (let el = node?.parentElement; el; el = el.parentElement) {
28
+ if (/(auto|scroll|overlay)/.test(getComputedStyle(el).overflowY) && el.scrollHeight > el.clientHeight) return el;
29
+ }
30
+ return window;
31
+ }
32
+ const clamp = (value) => Math.max(0, Math.min(1, value));
33
+ const ease = (t) => 1 - (1 - t) ** 3;
34
+ function ScrollZoom({
35
+ src,
36
+ alt = "",
37
+ media,
38
+ heading,
39
+ children,
40
+ length = 3,
41
+ zoomEnd = 0.6,
42
+ startWidth = 0.46,
43
+ startAspect = 4 / 3,
44
+ radius = 18,
45
+ headingSpace = 0.24,
46
+ dim = 0.55,
47
+ dimColor = "#0b0b14",
48
+ textColor = "#f4f4f4",
49
+ backgroundColor = "#1a1c2c",
50
+ mediaStyle,
51
+ fontFamily = "ui-sans-serif, system-ui, sans-serif",
52
+ className = "",
53
+ style
54
+ }) {
55
+ useStyles();
56
+ const rootRef = useRef(null);
57
+ useEffect(() => {
58
+ const root = rootRef.current;
59
+ const scroller = scrollParent(root);
60
+ const isWindow = scroller === window;
61
+ const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
62
+ let frame = 0;
63
+ const viewport = () => isWindow ? { top: 0, height: window.innerHeight } : { top: scroller.getBoundingClientRect().top, height: scroller.clientHeight };
64
+ const update = () => {
65
+ frame = 0;
66
+ const view = viewport();
67
+ root.style.setProperty("--bl-view", `${view.height}px`);
68
+ root.style.setProperty("--bl-head-h", `${view.height * headingSpace}px`);
69
+ const rect = root.getBoundingClientRect();
70
+ const travel = rect.height - view.height;
71
+ const p = reduced ? 1 : clamp((view.top - rect.top) / Math.max(1, travel));
72
+ const zoom = ease(clamp(p / zoomEnd));
73
+ const reveal = clamp((p - zoomEnd) / Math.max(0.01, (1 - zoomEnd) * 0.6));
74
+ const width = rect.width;
75
+ const height = view.height;
76
+ const frameW = Math.min(width * startWidth, (height * (1 - headingSpace) - 24) * startAspect);
77
+ const frameH = frameW / startAspect;
78
+ const x = (width - frameW) / 2 * (1 - zoom);
79
+ const top = height * headingSpace * (1 - zoom);
80
+ const bottom = Math.max(0, height - height * headingSpace - frameH) * (1 - zoom);
81
+ root.style.setProperty("--bl-clip", `inset(${top}px ${x}px ${bottom}px ${x}px round ${radius * (1 - zoom)}px)`);
82
+ root.style.setProperty("--bl-p", String(zoom));
83
+ root.style.setProperty("--bl-reveal", String(reveal));
84
+ root.toggleAttribute("data-hidden-reveal", reveal < 0.02);
85
+ };
86
+ const schedule = () => {
87
+ if (!frame) frame = requestAnimationFrame(update);
88
+ };
89
+ if (reduced) root.setAttribute("data-static", "");
90
+ else root.removeAttribute("data-static");
91
+ scroller.addEventListener("scroll", schedule, { passive: true });
92
+ window.addEventListener("resize", schedule);
93
+ const resize = new ResizeObserver(schedule);
94
+ resize.observe(root);
95
+ if (!isWindow) resize.observe(scroller);
96
+ update();
97
+ return () => {
98
+ cancelAnimationFrame(frame);
99
+ scroller.removeEventListener("scroll", schedule);
100
+ window.removeEventListener("resize", schedule);
101
+ resize.disconnect();
102
+ };
103
+ }, [zoomEnd, startWidth, startAspect, radius, headingSpace, length]);
104
+ return /* @__PURE__ */ jsx(
105
+ "section",
106
+ {
107
+ ref: rootRef,
108
+ className: `bl-zoom ${className}`,
109
+ style: { "--bl-length": length, "--bl-dim": dim, "--bl-dim-color": dimColor, "--bl-ink": textColor, "--bl-font": fontFamily, background: backgroundColor, ...style },
110
+ children: /* @__PURE__ */ jsxs("div", { className: "bl-zoom__stage", children: [
111
+ heading && /* @__PURE__ */ jsx("div", { className: "bl-zoom__heading", children: heading }),
112
+ /* @__PURE__ */ jsxs("div", { className: "bl-zoom__media", style: mediaStyle, children: [
113
+ media ?? /* @__PURE__ */ jsx("img", { src, alt }),
114
+ /* @__PURE__ */ jsx("div", { className: "bl-zoom__dim", "aria-hidden": "true" })
115
+ ] }),
116
+ children && /* @__PURE__ */ jsx("div", { className: "bl-zoom__reveal", children })
117
+ ] })
118
+ }
119
+ );
120
+ }
121
+ export {
122
+ ScrollZoom as default
123
+ };
@@ -0,0 +1,29 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export interface ScrubNumberProps {
3
+ value?: number;
4
+ defaultValue?: number;
5
+ onChange?: (value: number) => void;
6
+ min?: number;
7
+ max?: number;
8
+ /** Step; decimals follow it. */
9
+ step?: number;
10
+ /** Drag distance per step; Shift ×10, Alt ×0.1. */
11
+ pixelsPerStep?: number;
12
+ /** Accessible name. */
13
+ label?: string;
14
+ /** What the drag handle shows (defaults to the label). */
15
+ handle?: ReactNode;
16
+ unit?: string;
17
+ width?: number;
18
+ radius?: number;
19
+ backgroundColor?: string;
20
+ chipColor?: string;
21
+ textColor?: string;
22
+ mutedColor?: string;
23
+ lineColor?: string;
24
+ accentColor?: string;
25
+ fontFamily?: string;
26
+ className?: string;
27
+ style?: CSSProperties;
28
+ }
29
+ export default function ScrubNumber({ value: controlled, defaultValue, onChange, min, max, step, pixelsPerStep, label, handle, unit, width, radius, backgroundColor, chipColor, textColor, mutedColor, lineColor, accentColor, fontFamily, className, style }: ScrubNumberProps): import("react").JSX.Element;
@@ -0,0 +1,152 @@
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-scrub-number";
5
+ const CSS = `
6
+ .bl-scrub { position: relative; display: inline-flex; align-items: stretch; overflow: hidden; border-radius: var(--bl-radius); background: var(--bl-bg); color: var(--bl-ink); font-family: var(--bl-font); font-size: 14px; box-shadow: inset 0 0 0 1px var(--bl-line); }
7
+ .bl-scrub:focus-within { box-shadow: inset 0 0 0 2px var(--bl-accent); }
8
+ .bl-scrub__handle { position: relative; display: grid; place-items: center; min-width: 30px; padding: 0 10px; background: var(--bl-chip); color: var(--bl-muted); font-weight: 700; cursor: ew-resize; user-select: none; touch-action: none; }
9
+ .bl-scrub[data-scrubbing] .bl-scrub__handle { color: var(--bl-accent); }
10
+ .bl-scrub__input { width: var(--bl-w); min-width: 0; margin: 0; padding: 8px 10px; border: 0; background: transparent; color: inherit; font: inherit; font-variant-numeric: tabular-nums; outline: none; }
11
+ .bl-scrub__unit { display: grid; place-items: center; padding-right: 10px; color: var(--bl-muted); }
12
+ .bl-scrub__ruler { position: absolute; left: 0; right: 0; bottom: 0; height: 5px; background: repeating-linear-gradient(90deg, var(--bl-accent) 0 1px, transparent 1px 8px); background-position: var(--off) 0; opacity: 0; pointer-events: none; transition: opacity 120ms; }
13
+ .bl-scrub[data-scrubbing] .bl-scrub__ruler { opacity: 0.8; }
14
+ `;
15
+ function useStyles() {
16
+ useInsertionEffect(() => {
17
+ if (typeof document === "undefined") return;
18
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
19
+ style.textContent = CSS;
20
+ if (!style.isConnected) document.head.appendChild(style);
21
+ }, []);
22
+ }
23
+ const decimalsOf = (step) => (String(step).split(".")[1] ?? "").length;
24
+ function ScrubNumber({
25
+ value: controlled,
26
+ defaultValue = 0,
27
+ onChange,
28
+ min = -Infinity,
29
+ max = Infinity,
30
+ step = 1,
31
+ pixelsPerStep = 4,
32
+ label = "Value",
33
+ handle,
34
+ unit = "",
35
+ width = 64,
36
+ radius = 8,
37
+ backgroundColor = "#1a1c2c",
38
+ chipColor = "#262b44",
39
+ textColor = "#f4f4f4",
40
+ mutedColor = "#94b0c2",
41
+ lineColor = "#333c57",
42
+ accentColor = "#73eff7",
43
+ fontFamily = "inherit",
44
+ className = "",
45
+ style
46
+ }) {
47
+ useStyles();
48
+ const id = useId();
49
+ const [inner, setInner] = useState(defaultValue);
50
+ const value = controlled ?? inner;
51
+ const decimals = decimalsOf(step);
52
+ const [draft, setDraft] = useState(null);
53
+ const [scrubbing, setScrubbing] = useState(false);
54
+ const handleRef = useRef(null);
55
+ const rootRef = useRef(null);
56
+ const valueRef = useRef(value);
57
+ valueRef.current = value;
58
+ const commit = (next) => {
59
+ const snapped = Math.round(next / step) * step;
60
+ const v = Number(Math.max(min, Math.min(max, snapped)).toFixed(decimals));
61
+ if (v === valueRef.current) return;
62
+ if (controlled === void 0) setInner(v);
63
+ onChange?.(v);
64
+ };
65
+ const commitRef = useRef(commit);
66
+ commitRef.current = commit;
67
+ useEffect(() => {
68
+ const el = handleRef.current;
69
+ const root = rootRef.current;
70
+ let drag = null;
71
+ const onDown = (event) => {
72
+ if (event.button > 0) return;
73
+ event.preventDefault();
74
+ el.setPointerCapture?.(event.pointerId);
75
+ drag = { x: event.clientX, from: valueRef.current };
76
+ setScrubbing(true);
77
+ };
78
+ const onMove = (event) => {
79
+ if (!drag) return;
80
+ const dx = event.clientX - drag.x;
81
+ const scale = event.shiftKey ? 10 : event.altKey ? 0.1 : 1;
82
+ root.style.setProperty("--off", `${dx}px`);
83
+ commitRef.current(drag.from + Math.round(dx / pixelsPerStep) * step * scale);
84
+ };
85
+ const onUp = () => {
86
+ drag = null;
87
+ setScrubbing(false);
88
+ };
89
+ el.addEventListener("pointerdown", onDown);
90
+ el.addEventListener("pointermove", onMove);
91
+ el.addEventListener("pointerup", onUp);
92
+ el.addEventListener("pointercancel", onUp);
93
+ return () => {
94
+ el.removeEventListener("pointerdown", onDown);
95
+ el.removeEventListener("pointermove", onMove);
96
+ el.removeEventListener("pointerup", onUp);
97
+ el.removeEventListener("pointercancel", onUp);
98
+ };
99
+ }, [step, pixelsPerStep]);
100
+ const finishTyping = () => {
101
+ if (draft === null) return;
102
+ const parsed = Number(draft.replace(",", "."));
103
+ if (Number.isFinite(parsed)) commit(parsed);
104
+ setDraft(null);
105
+ };
106
+ return /* @__PURE__ */ jsxs(
107
+ "span",
108
+ {
109
+ ref: rootRef,
110
+ className: `bl-scrub ${className}`,
111
+ "data-scrubbing": scrubbing || void 0,
112
+ style: { "--bl-w": `${width}px`, "--bl-radius": `${radius}px`, "--bl-bg": backgroundColor, "--bl-chip": chipColor, "--bl-ink": textColor, "--bl-muted": mutedColor, "--bl-line": lineColor, "--bl-accent": accentColor, "--bl-font": fontFamily, "--off": "0px", ...style },
113
+ children: [
114
+ /* @__PURE__ */ jsx("label", { ref: handleRef, htmlFor: id, className: "bl-scrub__handle", title: `Drag to change ${label}`, children: handle ?? label }),
115
+ /* @__PURE__ */ jsx(
116
+ "input",
117
+ {
118
+ id,
119
+ className: "bl-scrub__input",
120
+ type: "text",
121
+ inputMode: "decimal",
122
+ role: "spinbutton",
123
+ "aria-label": handle ? label : void 0,
124
+ "aria-valuenow": value,
125
+ "aria-valuemin": Number.isFinite(min) ? min : void 0,
126
+ "aria-valuemax": Number.isFinite(max) ? max : void 0,
127
+ value: draft ?? value.toFixed(decimals),
128
+ onChange: (event) => setDraft(event.target.value),
129
+ onBlur: finishTyping,
130
+ onKeyDown: (event) => {
131
+ if (event.key === "Enter") {
132
+ finishTyping();
133
+ event.currentTarget.select();
134
+ } else if (event.key === "Escape") setDraft(null);
135
+ else if (event.key === "ArrowUp" || event.key === "ArrowDown") {
136
+ event.preventDefault();
137
+ setDraft(null);
138
+ const scale = event.shiftKey ? 10 : event.altKey ? 0.1 : 1;
139
+ commit(value + (event.key === "ArrowUp" ? 1 : -1) * step * scale);
140
+ }
141
+ }
142
+ }
143
+ ),
144
+ unit && /* @__PURE__ */ jsx("span", { className: "bl-scrub__unit", "aria-hidden": "true", children: unit }),
145
+ /* @__PURE__ */ jsx("span", { className: "bl-scrub__ruler", "aria-hidden": "true" })
146
+ ]
147
+ }
148
+ );
149
+ }
150
+ export {
151
+ ScrubNumber as default
152
+ };
@@ -0,0 +1,28 @@
1
+ import { type CSSProperties, type ElementType } from 'react';
2
+ export interface ShadowStackProps {
3
+ text?: string;
4
+ as?: ElementType;
5
+ /** A solid stair-stepped block, or spaced fading copies that breathe. */
6
+ mode?: 'extrude' | 'echo';
7
+ /** Extrude depth in px. */
8
+ depth?: number;
9
+ /** Direction of the depth in degrees (0 = right, 90 = down). */
10
+ angle?: number;
11
+ /** Px per extrude layer. */
12
+ step?: number;
13
+ echoes?: number;
14
+ /** Gap between echoes in px. */
15
+ spacing?: number;
16
+ /** Depth falls away from the pointer, snapped to 15°. */
17
+ follow?: boolean;
18
+ /** Pressing squashes the title like a key. */
19
+ press?: boolean;
20
+ faceColor?: string;
21
+ /** Colours the depth steps through, front to back. */
22
+ colors?: string[];
23
+ fontSize?: number | string;
24
+ fontFamily?: string;
25
+ className?: string;
26
+ style?: CSSProperties;
27
+ }
28
+ export default function ShadowStack({ text, as: Tag, mode, depth, angle, step, echoes, spacing, follow, press, faceColor, colors, fontSize, fontFamily, className, style }: ShadowStackProps): import("react").JSX.Element;