bits-lab 0.0.0-stage → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -2
  3. package/dist/Accordion.d.ts +52 -0
  4. package/dist/Accordion.js +192 -0
  5. package/dist/AchievementToast.d.ts +36 -0
  6. package/dist/AchievementToast.js +162 -0
  7. package/dist/AgentCard.d.ts +41 -0
  8. package/dist/AgentCard.js +168 -0
  9. package/dist/ArcadeButtons.d.ts +23 -0
  10. package/dist/ArcadeButtons.js +169 -0
  11. package/dist/AuroraBands.d.ts +19 -0
  12. package/dist/AuroraBands.js +126 -0
  13. package/dist/AvatarTooltips.d.ts +32 -0
  14. package/dist/AvatarTooltips.js +121 -0
  15. package/dist/BarRace.d.ts +39 -0
  16. package/dist/BarRace.js +227 -0
  17. package/dist/BentoGrid.d.ts +50 -0
  18. package/dist/BentoGrid.js +145 -0
  19. package/dist/BootSequence.d.ts +48 -0
  20. package/dist/BootSequence.js +234 -0
  21. package/dist/BreadcrumbTrail.d.ts +31 -0
  22. package/dist/BreadcrumbTrail.js +181 -0
  23. package/dist/CRTPower.d.ts +30 -0
  24. package/dist/CRTPower.js +142 -0
  25. package/dist/CardDeck.d.ts +29 -0
  26. package/dist/CardDeck.js +154 -0
  27. package/dist/ChangelogTimeline.d.ts +35 -0
  28. package/dist/ChangelogTimeline.js +137 -0
  29. package/dist/ChapterProgress.d.ts +23 -0
  30. package/dist/ChapterProgress.js +211 -0
  31. package/dist/ChatBubbles.d.ts +42 -0
  32. package/dist/ChatBubbles.js +198 -0
  33. package/dist/ChiptuneKit.d.ts +158 -0
  34. package/dist/ChiptuneKit.js +207 -0
  35. package/dist/CipherCard.d.ts +22 -0
  36. package/dist/CipherCard.js +91 -0
  37. package/dist/CloudSky.d.ts +28 -0
  38. package/dist/CloudSky.js +222 -0
  39. package/dist/CodeRain.d.ts +24 -0
  40. package/dist/CodeRain.js +158 -0
  41. package/dist/CodeShowcase.d.ts +50 -0
  42. package/dist/CodeShowcase.js +307 -0
  43. package/dist/ColorDial.d.ts +42 -0
  44. package/dist/ColorDial.js +288 -0
  45. package/dist/CommandPalette.d.ts +59 -0
  46. package/dist/CommandPalette.js +349 -0
  47. package/dist/CompareSlider.d.ts +33 -0
  48. package/dist/CompareSlider.js +152 -0
  49. package/dist/Confetti.d.ts +61 -0
  50. package/dist/Confetti.js +176 -0
  51. package/dist/ConnectBeams.d.ts +39 -0
  52. package/dist/ConnectBeams.js +132 -0
  53. package/dist/ContextOrb.d.ts +34 -0
  54. package/dist/ContextOrb.js +269 -0
  55. package/dist/ContourLines.d.ts +20 -0
  56. package/dist/ContourLines.js +159 -0
  57. package/dist/Coverflow.d.ts +27 -0
  58. package/dist/Coverflow.js +167 -0
  59. package/dist/CursorAttractor.d.ts +21 -0
  60. package/dist/CursorAttractor.js +136 -0
  61. package/dist/CutReveal.d.ts +21 -0
  62. package/dist/CutReveal.js +116 -0
  63. package/dist/DateRange.d.ts +45 -0
  64. package/dist/DateRange.js +327 -0
  65. package/dist/DeviceFrame.d.ts +30 -0
  66. package/dist/DeviceFrame.js +145 -0
  67. package/dist/DiffReveal.d.ts +36 -0
  68. package/dist/DiffReveal.js +247 -0
  69. package/dist/DirectionHover.d.ts +15 -0
  70. package/dist/DirectionHover.js +90 -0
  71. package/dist/Discard.d.ts +18 -0
  72. package/dist/Discard.js +61 -0
  73. package/dist/DitherField.d.ts +15 -0
  74. package/dist/DitherField.js +157 -0
  75. package/dist/DotGlobe.d.ts +48 -0
  76. package/dist/DotGlobe.js +312 -0
  77. package/dist/DotMap.d.ts +47 -0
  78. package/dist/DotMap.js +172 -0
  79. package/dist/DropZone.d.ts +57 -0
  80. package/dist/DropZone.js +304 -0
  81. package/dist/DynamicIsland.d.ts +32 -0
  82. package/dist/DynamicIsland.js +92 -0
  83. package/dist/EdgeFX.d.ts +27 -0
  84. package/dist/EdgeFX.js +98 -0
  85. package/dist/ElasticString.d.ts +22 -0
  86. package/dist/ElasticString.js +127 -0
  87. package/dist/ExpandCard.d.ts +44 -0
  88. package/dist/ExpandCard.js +182 -0
  89. package/dist/FeatureTabs.d.ts +34 -0
  90. package/dist/FeatureTabs.js +169 -0
  91. package/dist/FeedList.d.ts +37 -0
  92. package/dist/FeedList.js +163 -0
  93. package/dist/FlickerGrid.d.ts +29 -0
  94. package/dist/FlickerGrid.js +156 -0
  95. package/dist/FocusGrid.d.ts +20 -0
  96. package/dist/FocusGrid.js +48 -0
  97. package/dist/FocusPull.d.ts +26 -0
  98. package/dist/FocusPull.js +106 -0
  99. package/dist/Footprints.d.ts +24 -0
  100. package/dist/Footprints.js +126 -0
  101. package/dist/FunnelFlow.d.ts +34 -0
  102. package/dist/FunnelFlow.js +267 -0
  103. package/dist/GameOver.d.ts +46 -0
  104. package/dist/GameOver.js +191 -0
  105. package/dist/GaugeMeter.d.ts +38 -0
  106. package/dist/GaugeMeter.js +195 -0
  107. package/dist/GlassPanel.d.ts +27 -0
  108. package/dist/GlassPanel.js +80 -0
  109. package/dist/GrainFX.d.ts +34 -0
  110. package/dist/GrainFX.js +122 -0
  111. package/dist/GravityBox.d.ts +30 -0
  112. package/dist/GravityBox.js +220 -0
  113. package/dist/HealthBar.d.ts +33 -0
  114. package/dist/HealthBar.js +140 -0
  115. package/dist/Heatmap.d.ts +42 -0
  116. package/dist/Heatmap.js +232 -0
  117. package/dist/HexField.d.ts +29 -0
  118. package/dist/HexField.js +188 -0
  119. package/dist/HoldToConfirm.d.ts +29 -0
  120. package/dist/HoldToConfirm.js +163 -0
  121. package/dist/HorizontalTrack.d.ts +28 -0
  122. package/dist/HorizontalTrack.js +195 -0
  123. package/dist/HotbarDock.d.ts +40 -0
  124. package/dist/HotbarDock.js +148 -0
  125. package/dist/InkText.d.ts +27 -0
  126. package/dist/InkText.js +65 -0
  127. package/dist/InlineEdit.d.ts +30 -0
  128. package/dist/InlineEdit.js +198 -0
  129. package/dist/InteractiveGrid.d.ts +25 -0
  130. package/dist/InteractiveGrid.js +194 -0
  131. package/dist/InventoryGrid.d.ts +45 -0
  132. package/dist/InventoryGrid.js +272 -0
  133. package/dist/JellyBlob.d.ts +30 -0
  134. package/dist/JellyBlob.js +209 -0
  135. package/dist/KineticHeadline.d.ts +30 -0
  136. package/dist/KineticHeadline.js +133 -0
  137. package/dist/LavaLamp.d.ts +21 -0
  138. package/dist/LavaLamp.js +133 -0
  139. package/dist/LetterSwap.d.ts +20 -0
  140. package/dist/LetterSwap.js +78 -0
  141. package/dist/LevelMap.d.ts +35 -0
  142. package/dist/LevelMap.js +189 -0
  143. package/dist/LightShafts.d.ts +22 -0
  144. package/dist/LightShafts.js +170 -0
  145. package/dist/LightboxGallery.d.ts +26 -0
  146. package/dist/LightboxGallery.js +327 -0
  147. package/dist/LinkPeek.d.ts +36 -0
  148. package/dist/LinkPeek.js +194 -0
  149. package/dist/LogoOrbit.d.ts +37 -0
  150. package/dist/LogoOrbit.js +117 -0
  151. package/dist/Marquee.d.ts +33 -0
  152. package/dist/Marquee.js +148 -0
  153. package/dist/MarqueeLine.d.ts +33 -0
  154. package/dist/MarqueeLine.js +167 -0
  155. package/dist/MasonryWall.d.ts +13 -0
  156. package/dist/MasonryWall.js +90 -0
  157. package/dist/MegaMenu.d.ts +32 -0
  158. package/dist/MegaMenu.js +280 -0
  159. package/dist/MeteorShower.d.ts +24 -0
  160. package/dist/MeteorShower.js +155 -0
  161. package/dist/Minimap.d.ts +21 -0
  162. package/dist/Minimap.js +236 -0
  163. package/dist/MobileTabBar.d.ts +38 -0
  164. package/dist/MobileTabBar.js +148 -0
  165. package/dist/MorphDialog.d.ts +34 -0
  166. package/dist/MorphDialog.js +199 -0
  167. package/dist/MorphPopover.d.ts +33 -0
  168. package/dist/MorphPopover.js +168 -0
  169. package/dist/MorphWords.d.ts +18 -0
  170. package/dist/MorphWords.js +136 -0
  171. package/dist/OTPInput.d.ts +43 -0
  172. package/dist/OTPInput.js +174 -0
  173. package/dist/OverlayKit.d.ts +97 -0
  174. package/dist/OverlayKit.js +466 -0
  175. package/dist/OverlayMenu.d.ts +32 -0
  176. package/dist/OverlayMenu.js +154 -0
  177. package/dist/ParallaxCollage.d.ts +41 -0
  178. package/dist/ParallaxCollage.js +143 -0
  179. package/dist/PasswordMeter.d.ts +44 -0
  180. package/dist/PasswordMeter.js +165 -0
  181. package/dist/PegBoard.d.ts +26 -0
  182. package/dist/PegBoard.js +184 -0
  183. package/dist/PinCard.d.ts +21 -0
  184. package/dist/PinCard.js +84 -0
  185. package/dist/PixelAvatar.d.ts +33 -0
  186. package/dist/PixelAvatar.js +144 -0
  187. package/dist/PixelButton.d.ts +20 -0
  188. package/dist/PixelButton.js +128 -0
  189. package/dist/PixelExplode.d.ts +31 -0
  190. package/dist/PixelExplode.js +164 -0
  191. package/dist/PixelLoader.d.ts +32 -0
  192. package/dist/PixelLoader.js +142 -0
  193. package/dist/PixelParallax.d.ts +41 -0
  194. package/dist/PixelParallax.js +151 -0
  195. package/dist/PixelSpinners.d.ts +21 -0
  196. package/dist/PixelSpinners.js +110 -0
  197. package/dist/PixelType.d.ts +26 -0
  198. package/dist/PixelType.js +220 -0
  199. package/dist/PointerKit.d.ts +23 -0
  200. package/dist/PointerKit.js +222 -0
  201. package/dist/Polaroids.d.ts +41 -0
  202. package/dist/Polaroids.js +293 -0
  203. package/dist/PressStart.d.ts +28 -0
  204. package/dist/PressStart.js +99 -0
  205. package/dist/PricingFlip.d.ts +52 -0
  206. package/dist/PricingFlip.js +190 -0
  207. package/dist/ProximityType.d.ts +26 -0
  208. package/dist/ProximityType.js +135 -0
  209. package/dist/QuestDialog.d.ts +50 -0
  210. package/dist/QuestDialog.js +204 -0
  211. package/dist/QuestLog.d.ts +39 -0
  212. package/dist/QuestLog.js +214 -0
  213. package/dist/RangeDual.d.ts +34 -0
  214. package/dist/RangeDual.js +238 -0
  215. package/dist/RatingPips.d.ts +25 -0
  216. package/dist/RatingPips.js +129 -0
  217. package/dist/RetroHorizon.d.ts +27 -0
  218. package/dist/RetroHorizon.js +169 -0
  219. package/dist/Reveal.d.ts +30 -0
  220. package/dist/Reveal.js +92 -0
  221. package/dist/RingProgress.d.ts +45 -0
  222. package/dist/RingProgress.js +180 -0
  223. package/dist/RollingNumber.d.ts +28 -0
  224. package/dist/RollingNumber.js +108 -0
  225. package/dist/ScanScope.d.ts +24 -0
  226. package/dist/ScanScope.js +164 -0
  227. package/dist/ScoreTicker.d.ts +32 -0
  228. package/dist/ScoreTicker.js +176 -0
  229. package/dist/ScreenScroller.d.ts +24 -0
  230. package/dist/ScreenScroller.js +138 -0
  231. package/dist/Screensaver.d.ts +31 -0
  232. package/dist/Screensaver.js +221 -0
  233. package/dist/ScrollTilt.d.ts +27 -0
  234. package/dist/ScrollTilt.js +100 -0
  235. package/dist/ScrollTypography.d.ts +26 -0
  236. package/dist/ScrollTypography.js +124 -0
  237. package/dist/ScrollZoom.d.ts +31 -0
  238. package/dist/ScrollZoom.js +123 -0
  239. package/dist/ScrubNumber.d.ts +29 -0
  240. package/dist/ScrubNumber.js +152 -0
  241. package/dist/ShadowStack.d.ts +28 -0
  242. package/dist/ShadowStack.js +116 -0
  243. package/dist/SideRail.d.ts +43 -0
  244. package/dist/SideRail.js +253 -0
  245. package/dist/SignalText.d.ts +25 -0
  246. package/dist/SignalText.js +178 -0
  247. package/dist/SkeletonShimmer.d.ts +18 -0
  248. package/dist/SkeletonShimmer.js +111 -0
  249. package/dist/SketchHighlight.d.ts +27 -0
  250. package/dist/SketchHighlight.js +180 -0
  251. package/dist/SlideTabs.d.ts +40 -0
  252. package/dist/SlideTabs.js +190 -0
  253. package/dist/SmartNavbar.d.ts +48 -0
  254. package/dist/SmartNavbar.js +188 -0
  255. package/dist/SparkChart.d.ts +41 -0
  256. package/dist/SparkChart.js +188 -0
  257. package/dist/Spoiler.d.ts +22 -0
  258. package/dist/Spoiler.js +97 -0
  259. package/dist/SpotlightTour.d.ts +38 -0
  260. package/dist/SpotlightTour.js +231 -0
  261. package/dist/SpringDrawer.d.ts +39 -0
  262. package/dist/SpringDrawer.js +360 -0
  263. package/dist/SpriteAnimator.d.ts +41 -0
  264. package/dist/SpriteAnimator.js +124 -0
  265. package/dist/StatCard.d.ts +43 -0
  266. package/dist/StatCard.js +168 -0
  267. package/dist/StepLoader.d.ts +41 -0
  268. package/dist/StepLoader.js +191 -0
  269. package/dist/StepperForm.d.ts +41 -0
  270. package/dist/StepperForm.js +206 -0
  271. package/dist/StickerBoard.d.ts +39 -0
  272. package/dist/StickerBoard.js +209 -0
  273. package/dist/StickyReveal.d.ts +42 -0
  274. package/dist/StickyReveal.js +181 -0
  275. package/dist/StoryViewer.d.ts +36 -0
  276. package/dist/StoryViewer.js +175 -0
  277. package/dist/StreamingText.d.ts +29 -0
  278. package/dist/StreamingText.js +271 -0
  279. package/dist/SuggestionChips.d.ts +32 -0
  280. package/dist/SuggestionChips.js +96 -0
  281. package/dist/SwipeActions.d.ts +30 -0
  282. package/dist/SwipeActions.js +141 -0
  283. package/dist/TagInput.d.ts +30 -0
  284. package/dist/TagInput.js +284 -0
  285. package/dist/TallyUp.d.ts +38 -0
  286. package/dist/TallyUp.js +157 -0
  287. package/dist/TerminalDemo.d.ts +63 -0
  288. package/dist/TerminalDemo.js +214 -0
  289. package/dist/TestimonialWall.d.ts +35 -0
  290. package/dist/TestimonialWall.js +131 -0
  291. package/dist/TextOnPath.d.ts +36 -0
  292. package/dist/TextOnPath.js +130 -0
  293. package/dist/ThinkingShimmer.d.ts +36 -0
  294. package/dist/ThinkingShimmer.js +132 -0
  295. package/dist/ToastStack.d.ts +62 -0
  296. package/dist/ToastStack.js +289 -0
  297. package/dist/ToggleGroup.d.ts +39 -0
  298. package/dist/ToggleGroup.js +190 -0
  299. package/dist/ToggleKit.d.ts +70 -0
  300. package/dist/ToggleKit.js +229 -0
  301. package/dist/TracingLine.d.ts +24 -0
  302. package/dist/TracingLine.js +139 -0
  303. package/dist/TradingCard.d.ts +30 -0
  304. package/dist/TradingCard.js +147 -0
  305. package/dist/VanishInput.d.ts +34 -0
  306. package/dist/VanishInput.js +190 -0
  307. package/dist/VideoHero.d.ts +32 -0
  308. package/dist/VideoHero.js +207 -0
  309. package/dist/VoiceOrb.d.ts +23 -0
  310. package/dist/VoiceOrb.js +182 -0
  311. package/dist/VoxelTiles.d.ts +38 -0
  312. package/dist/VoxelTiles.js +201 -0
  313. package/dist/WarpField.d.ts +18 -0
  314. package/dist/WarpField.js +160 -0
  315. package/dist/WebcamPixels.d.ts +38 -0
  316. package/dist/WebcamPixels.js +292 -0
  317. package/dist/WheelPicker.d.ts +29 -0
  318. package/dist/WheelPicker.js +199 -0
  319. package/dist/WobbleCard.d.ts +23 -0
  320. package/dist/WobbleCard.js +112 -0
  321. package/dist/index.d.ts +158 -0
  322. package/dist/index.js +159 -0
  323. package/package.json +58 -4
@@ -0,0 +1,190 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useInsertionEffect, useLayoutEffect, useRef, useState } from "react";
4
+ const STYLE_ID = "bl-toggle-group";
5
+ const CSS = `
6
+ .bl-tg { position: relative; display: inline-flex; max-width: 100%; overflow-x: auto; scrollbar-width: none; padding: var(--bl-pad); gap: var(--bl-gap); border-radius: var(--bl-radius); background: var(--bl-track); box-shadow: inset 0 0 0 1px var(--bl-line); font-family: var(--bl-font); isolation: isolate; }
7
+ .bl-tg[data-full] { display: flex; width: 100%; }
8
+ .bl-tg[data-full] .bl-tg__item { flex: 1 0 auto; }
9
+ .bl-tg__thumb { position: absolute; z-index: 0; top: var(--bl-pad); bottom: var(--bl-pad); left: 0; border-radius: var(--bl-inner-radius); background: var(--bl-thumb); box-shadow: 0 1px 2px rgba(0,0,0,0.3), 0 4px 12px -6px rgba(0,0,0,0.5); transition: transform var(--bl-dur) cubic-bezier(.3,1.25,.5,1), width var(--bl-dur) cubic-bezier(.3,1.25,.5,1); }
10
+ .bl-tg__thumb[data-instant] { transition: none; }
11
+ .bl-tg__item { position: relative; z-index: 1; display: inline-flex; flex: 0 0 auto; align-items: center; justify-content: center; gap: 7px; min-width: 0; height: var(--bl-h); padding: 0 var(--bl-item-pad); border: 0; border-radius: var(--bl-inner-radius); background: transparent; color: var(--bl-muted); font: inherit; font-size: var(--bl-size); font-weight: 600; white-space: nowrap; cursor: pointer; transition: color 180ms, background-color 180ms, border-radius 180ms; }
12
+ .bl-tg__item:hover:not(:disabled) { color: var(--bl-ink); }
13
+ .bl-tg__item:disabled { opacity: 0.4; cursor: not-allowed; }
14
+ .bl-tg__item:focus-visible { outline: 2px solid var(--bl-accent); outline-offset: 1px; z-index: 2; }
15
+ .bl-tg[data-type="single"] .bl-tg__item[aria-checked="true"] { color: var(--bl-thumb-ink); }
16
+ .bl-tg[data-type="multiple"] .bl-tg__item[aria-pressed="true"] { background: var(--bl-thumb); color: var(--bl-thumb-ink); animation: bl-tg-pop 260ms cubic-bezier(.3,1.4,.5,1); }
17
+ .bl-tg[data-type="multiple"] .bl-tg__item[data-join-left] { border-top-left-radius: 0; border-bottom-left-radius: 0; }
18
+ .bl-tg[data-type="multiple"] .bl-tg__item[data-join-right] { border-top-right-radius: 0; border-bottom-right-radius: 0; }
19
+ .bl-tg[data-type="multiple"] .bl-tg__item[data-join-right]::after { content: ""; position: absolute; top: 0; bottom: 0; right: calc(var(--bl-gap) * -1); width: var(--bl-gap); background: var(--bl-thumb); }
20
+ @keyframes bl-tg-pop { 40% { transform: scale(0.94); } }
21
+ @media (prefers-reduced-motion: reduce) { .bl-tg__thumb, .bl-tg__item { transition: none; animation: none !important; } }
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 ToggleGroup({
32
+ items = [],
33
+ type = "single",
34
+ value,
35
+ defaultValue,
36
+ onChange,
37
+ label = "Options",
38
+ fullWidth = false,
39
+ size = "md",
40
+ duration = 340,
41
+ radius = 12,
42
+ gap = 2,
43
+ padding = 4,
44
+ trackColor = "rgba(255,255,255,0.06)",
45
+ lineColor = "rgba(255,255,255,0.1)",
46
+ thumbColor = "#f4f4f4",
47
+ thumbTextColor = "#1a1c2c",
48
+ textColor = "#f4f4f4",
49
+ mutedColor = "#94b0c2",
50
+ accentColor = "#73eff7",
51
+ fontFamily = "ui-sans-serif, system-ui, sans-serif",
52
+ className = "",
53
+ style
54
+ }) {
55
+ useStyles();
56
+ const multiple = type === "multiple";
57
+ const [inner, setInner] = useState(() => defaultValue ?? (multiple ? [] : items.find((item) => !item.disabled)?.value));
58
+ const selected = value !== void 0 ? value : inner;
59
+ const selectedSet = new Set(multiple ? selected ?? [] : [selected]);
60
+ const [focusIndex, setFocusIndex] = useState(null);
61
+ const refs = useRef([]);
62
+ const thumbRef = useRef(null);
63
+ const placed = useRef(false);
64
+ const commit = (next) => {
65
+ if (value === void 0) setInner(next);
66
+ onChange?.(next);
67
+ };
68
+ const toggle = (item) => {
69
+ if (item.disabled) return;
70
+ if (!multiple) {
71
+ if (item.value !== selected) commit(item.value);
72
+ return;
73
+ }
74
+ const current = selected ?? [];
75
+ commit(current.includes(item.value) ? current.filter((v) => v !== item.value) : items.filter((i) => i.value === item.value || current.includes(i.value)).map((i) => i.value));
76
+ };
77
+ const selectedIndex = multiple ? -1 : items.findIndex((item) => item.value === selected);
78
+ useLayoutEffect(() => {
79
+ const thumb = thumbRef.current;
80
+ const target = refs.current[selectedIndex];
81
+ if (!thumb) return void 0;
82
+ const place = () => {
83
+ const node = refs.current[selectedIndex];
84
+ if (!node) {
85
+ thumb.style.opacity = "0";
86
+ return;
87
+ }
88
+ thumb.style.opacity = "1";
89
+ thumb.style.width = `${node.offsetWidth}px`;
90
+ thumb.style.transform = `translateX(${node.offsetLeft}px)`;
91
+ };
92
+ if (!placed.current) thumb.setAttribute("data-instant", "");
93
+ place();
94
+ if (!placed.current) {
95
+ placed.current = true;
96
+ requestAnimationFrame(() => thumb.removeAttribute("data-instant"));
97
+ }
98
+ const observer = new ResizeObserver(() => {
99
+ thumb.setAttribute("data-instant", "");
100
+ place();
101
+ requestAnimationFrame(() => thumb.removeAttribute("data-instant"));
102
+ });
103
+ if (target) observer.observe(target);
104
+ if (thumb.parentElement) observer.observe(thumb.parentElement);
105
+ return () => observer.disconnect();
106
+ }, [selectedIndex, items.length, size]);
107
+ const enabled = items.map((item, i) => item.disabled ? -1 : i).filter((i) => i >= 0);
108
+ const tabStop = focusIndex ?? (multiple ? enabled[0] : selectedIndex >= 0 ? selectedIndex : enabled[0]);
109
+ const onKeyDown = (event, index) => {
110
+ const position = enabled.indexOf(index);
111
+ const keys = { ArrowRight: position + 1, ArrowDown: position + 1, ArrowLeft: position - 1, ArrowUp: position - 1, Home: 0, End: enabled.length - 1 };
112
+ if (!(event.key in keys)) return;
113
+ event.preventDefault();
114
+ const next = enabled[(keys[event.key] + enabled.length) % enabled.length];
115
+ setFocusIndex(next);
116
+ refs.current[next]?.focus();
117
+ if (!multiple) toggle(items[next]);
118
+ };
119
+ const heights = { sm: 30, md: 38, lg: 46 };
120
+ const fontSizes = { sm: 13, md: 14, lg: 15 };
121
+ return /* @__PURE__ */ jsxs(
122
+ "div",
123
+ {
124
+ className: `bl-tg ${className}`,
125
+ role: multiple ? "group" : "radiogroup",
126
+ "aria-label": label,
127
+ "data-type": type,
128
+ "data-full": fullWidth || void 0,
129
+ style: {
130
+ "--bl-h": `${heights[size] ?? heights.md}px`,
131
+ "--bl-size": `${fontSizes[size] ?? fontSizes.md}px`,
132
+ "--bl-item-pad": size === "sm" ? "10px" : "14px",
133
+ "--bl-pad": `${padding}px`,
134
+ "--bl-gap": `${gap}px`,
135
+ "--bl-radius": `${radius}px`,
136
+ "--bl-inner-radius": `${Math.max(0, radius - padding)}px`,
137
+ "--bl-dur": `${duration}ms`,
138
+ "--bl-track": trackColor,
139
+ "--bl-line": lineColor,
140
+ "--bl-thumb": thumbColor,
141
+ "--bl-thumb-ink": thumbTextColor,
142
+ "--bl-ink": textColor,
143
+ "--bl-muted": mutedColor,
144
+ "--bl-accent": accentColor,
145
+ "--bl-font": fontFamily,
146
+ ...style
147
+ },
148
+ children: [
149
+ !multiple && /* @__PURE__ */ jsx("span", { ref: thumbRef, className: "bl-tg__thumb", "aria-hidden": "true" }),
150
+ items.map((item, index) => {
151
+ const on = selectedSet.has(item.value);
152
+ const joinLeft = multiple && on && index > 0 && selectedSet.has(items[index - 1].value);
153
+ const joinRight = multiple && on && index < items.length - 1 && selectedSet.has(items[index + 1].value);
154
+ return /* @__PURE__ */ jsxs(
155
+ "button",
156
+ {
157
+ ref: (node) => {
158
+ refs.current[index] = node;
159
+ },
160
+ type: "button",
161
+ className: "bl-tg__item",
162
+ role: multiple ? void 0 : "radio",
163
+ "aria-checked": multiple ? void 0 : on,
164
+ "aria-pressed": multiple ? on : void 0,
165
+ "aria-label": item.ariaLabel,
166
+ disabled: item.disabled,
167
+ tabIndex: index === tabStop ? 0 : -1,
168
+ "data-join-left": joinLeft || void 0,
169
+ "data-join-right": joinRight || void 0,
170
+ onClick: () => {
171
+ setFocusIndex(index);
172
+ toggle(item);
173
+ },
174
+ onKeyDown: (event) => onKeyDown(event, index),
175
+ onBlur: (event) => !event.currentTarget.parentElement?.contains(event.relatedTarget) && setFocusIndex(null),
176
+ children: [
177
+ item.icon,
178
+ item.label
179
+ ]
180
+ },
181
+ item.value
182
+ );
183
+ })
184
+ ]
185
+ }
186
+ );
187
+ }
188
+ export {
189
+ ToggleGroup as default
190
+ };
@@ -0,0 +1,70 @@
1
+ import { type CSSProperties, type ReactNode, type InputHTMLAttributes, type ChangeEvent, type ButtonHTMLAttributes } from 'react';
2
+ export type ToggleSize = 'sm' | 'md' | 'lg';
3
+ type InputRest = Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'size' | 'color' | 'checked' | 'defaultChecked' | 'onChange' | 'value' | 'name' | 'disabled' | 'className' | 'style'>;
4
+ interface ToggleBase {
5
+ label?: ReactNode;
6
+ description?: ReactNode;
7
+ disabled?: boolean;
8
+ size?: ToggleSize;
9
+ /** Accent color for this control (sets --bl-tk-accent). */
10
+ color?: string;
11
+ /** Submitted with the form, like a plain input. */
12
+ name?: string;
13
+ value?: string;
14
+ className?: string;
15
+ style?: CSSProperties;
16
+ }
17
+ export interface SwitchProps extends ToggleBase, InputRest {
18
+ checked?: boolean;
19
+ defaultChecked?: boolean;
20
+ onCheckedChange?: (checked: boolean) => void;
21
+ }
22
+ export interface CheckboxProps extends SwitchProps {
23
+ /** Shows a dash; set for "some selected" parents. */
24
+ indeterminate?: boolean;
25
+ }
26
+ export interface RadioProps extends ToggleBase, InputRest {
27
+ checked?: boolean;
28
+ onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
29
+ }
30
+ export interface RadioOption {
31
+ value: string;
32
+ label?: ReactNode;
33
+ description?: ReactNode;
34
+ disabled?: boolean;
35
+ }
36
+ export interface RadioGroupProps {
37
+ options?: RadioOption[];
38
+ value?: string | null;
39
+ defaultValue?: string | null;
40
+ onValueChange?: (value: string) => void;
41
+ /** Rendered as the fieldset legend. */
42
+ label?: ReactNode;
43
+ name?: string;
44
+ orientation?: 'vertical' | 'horizontal';
45
+ size?: ToggleSize;
46
+ color?: string;
47
+ disabled?: boolean;
48
+ className?: string;
49
+ style?: CSSProperties;
50
+ }
51
+ export declare function Switch({ checked, defaultChecked, onCheckedChange, label, description, disabled, size, color, name, value, className, style, ...rest }: SwitchProps): import("react").JSX.Element;
52
+ export declare function Checkbox({ checked, defaultChecked, onCheckedChange, indeterminate, label, description, disabled, size, color, name, value, className, style, ...rest }: CheckboxProps): import("react").JSX.Element;
53
+ export declare function Radio({ checked, onChange, label, description, disabled, size, color, name, value, className, style, ...rest }: RadioProps): import("react").JSX.Element;
54
+ export declare function RadioGroup({ options, value, defaultValue, onValueChange, label, name, orientation, size, color, disabled, className, style }: RadioGroupProps): import("react").JSX.Element;
55
+ export interface NotifyBellProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'type' | 'style' | 'color'> {
56
+ pressed?: boolean;
57
+ defaultPressed?: boolean;
58
+ onPressedChange?: (pressed: boolean) => void;
59
+ /** The button's name; shown beside the bell unless showLabel is false. */
60
+ label?: string;
61
+ showLabel?: boolean;
62
+ disabled?: boolean;
63
+ size?: ToggleSize;
64
+ /** Accent colour when on. */
65
+ color?: string;
66
+ className?: string;
67
+ style?: CSSProperties;
68
+ }
69
+ export declare function NotifyBell({ pressed, defaultPressed, onPressedChange, label, showLabel, disabled, size, color, className, style, ...rest }: NotifyBellProps): import("react").JSX.Element;
70
+ export default Switch;
@@ -0,0 +1,229 @@
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-toggle-kit";
5
+ const CSS = `
6
+ .bl-tk { --tk-accent: var(--bl-tk-accent, #73eff7); --tk-ink: var(--bl-tk-ink, #f4f4f4); --tk-muted: var(--bl-tk-muted, #94b0c2); --tk-track: var(--bl-tk-track, #333c57); --tk-on-ink: var(--bl-tk-on-ink, #1a1c2c); --tk-size: 22px; position: relative; display: inline-flex; align-items: flex-start; gap: 10px; color: var(--tk-ink); font-family: var(--bl-tk-font, ui-sans-serif, system-ui, sans-serif); font-size: 14px; line-height: 1.4; cursor: pointer; -webkit-tap-highlight-color: transparent; }
7
+ .bl-tk[data-size="sm"] { --tk-size: 18px; font-size: 13px; }
8
+ .bl-tk[data-size="lg"] { --tk-size: 26px; font-size: 15px; }
9
+ .bl-tk[data-disabled] { opacity: 0.45; cursor: not-allowed; }
10
+ .bl-tk__input { position: absolute; width: 1px; height: 1px; margin: 0; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; opacity: 0; }
11
+ .bl-tk__text { display: grid; gap: 2px; padding-top: calc((var(--tk-size) - 1.4em) / 2); }
12
+ .bl-tk__desc { color: var(--tk-muted); font-size: 0.92em; }
13
+ .bl-tk__input:focus-visible + .bl-tk__control { outline: 2px solid var(--tk-accent); outline-offset: 3px; }
14
+
15
+ /* Switch */
16
+ .bl-tk__switch { position: relative; flex: 0 0 auto; width: calc(var(--tk-size) * 1.8); height: var(--tk-size); border-radius: 999px; background: var(--tk-track); transition: background-color 220ms cubic-bezier(.2,.9,.25,1); }
17
+ .bl-tk__thumb { position: absolute; top: 3px; left: 3px; width: calc(var(--tk-size) - 6px); height: calc(var(--tk-size) - 6px); border-radius: 999px; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,0.35); transition: left 320ms cubic-bezier(.3,1.35,.5,1), width 160ms cubic-bezier(.2,.9,.25,1); }
18
+ .bl-tk__input:checked + .bl-tk__switch { background: var(--tk-accent); }
19
+ .bl-tk__input:checked + .bl-tk__switch .bl-tk__thumb { left: calc(100% - var(--tk-size) + 3px); }
20
+ .bl-tk:active .bl-tk__input:not(:disabled) + .bl-tk__switch .bl-tk__thumb { width: calc(var(--tk-size) * 1.12); }
21
+ .bl-tk:active .bl-tk__input:checked:not(:disabled) + .bl-tk__switch .bl-tk__thumb { left: calc(100% - var(--tk-size) * 1.12 - 3px); }
22
+
23
+ /* Checkbox */
24
+ .bl-tk__box { position: relative; flex: 0 0 auto; display: grid; place-items: center; width: var(--tk-size); height: var(--tk-size); border-radius: calc(var(--tk-size) * 0.28); background: transparent; box-shadow: inset 0 0 0 2px var(--tk-track); color: var(--tk-on-ink); transition: background-color 160ms, box-shadow 160ms; animation: bl-tk-pop-off 260ms cubic-bezier(.3,1.35,.5,1); }
25
+ .bl-tk__box svg { width: 70%; height: 70%; overflow: visible; }
26
+ .bl-tk__check, .bl-tk__dash { fill: none; stroke: currentColor; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 220ms cubic-bezier(.2,.9,.25,1); }
27
+ .bl-tk__input:checked + .bl-tk__box, .bl-tk__input:indeterminate + .bl-tk__box { background: var(--tk-accent); box-shadow: inset 0 0 0 2px var(--tk-accent); animation: bl-tk-pop-on 320ms cubic-bezier(.3,1.35,.5,1); }
28
+ .bl-tk__input:checked:not(:indeterminate) + .bl-tk__box .bl-tk__check { stroke-dashoffset: 0; transition-delay: 60ms; }
29
+ .bl-tk__input:indeterminate + .bl-tk__box .bl-tk__dash { stroke-dashoffset: 0; }
30
+
31
+ /* Radio */
32
+ .bl-tk__radio { position: relative; flex: 0 0 auto; display: grid; place-items: center; width: var(--tk-size); height: var(--tk-size); border-radius: 50%; box-shadow: inset 0 0 0 2px var(--tk-track); transition: box-shadow 160ms; }
33
+ .bl-tk__dot { width: 45%; height: 45%; border-radius: 50%; background: var(--tk-accent); transform: scale(0); transition: transform 320ms cubic-bezier(.3,1.5,.5,1); }
34
+ .bl-tk__input:checked + .bl-tk__radio { box-shadow: inset 0 0 0 2px var(--tk-accent); }
35
+ .bl-tk__input:checked + .bl-tk__radio .bl-tk__dot { transform: scale(1); }
36
+ .bl-tk:active .bl-tk__input:not(:disabled) + .bl-tk__radio { transform: scale(0.9); }
37
+
38
+ .bl-tk-group { margin: 0; padding: 0; border: 0; font-family: var(--bl-tk-font, ui-sans-serif, system-ui, sans-serif); }
39
+ .bl-tk-group legend { margin-bottom: 10px; padding: 0; color: var(--bl-tk-muted, #94b0c2); font-size: 12px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; }
40
+ .bl-tk-group__list { display: flex; flex-direction: column; gap: 12px; }
41
+ .bl-tk-group[data-orientation="horizontal"] .bl-tk-group__list { flex-direction: row; flex-wrap: wrap; gap: 18px; }
42
+
43
+ /* Bell */
44
+ .bl-tk__bell { margin: 0; padding: 4px 10px 4px 4px; border: 0; border-radius: 10px; background: transparent; text-align: left; }
45
+ .bl-tk__bell:focus-visible { outline: 2px solid var(--tk-accent); outline-offset: 2px; }
46
+ .bl-tk__bell-icon { display: grid; place-items: center; flex: 0 0 auto; width: var(--tk-size); height: var(--tk-size); color: var(--tk-muted); transition: color 160ms; }
47
+ .bl-tk__bell[aria-pressed="true"] .bl-tk__bell-icon { color: var(--tk-accent); }
48
+ .bl-tk__bell-icon svg { width: 100%; height: 100%; overflow: visible; fill: currentColor; shape-rendering: crispEdges; transform-origin: 50% 8%; }
49
+ .bl-tk__bell[aria-pressed="true"] .bl-tk__bell-icon svg { animation: bl-tk-ring 720ms steps(8); }
50
+ .bl-tk__bell-waves { opacity: 0; }
51
+ .bl-tk__bell[aria-pressed="true"] .bl-tk__bell-waves { animation: bl-tk-waves 720ms steps(4); }
52
+ .bl-tk__bell[aria-pressed="true"] .bl-tk__bell-slash { display: none; }
53
+
54
+ @keyframes bl-tk-pop-on { 40% { transform: scale(0.82); } }
55
+ @keyframes bl-tk-pop-off { 40% { transform: scale(0.88); } }
56
+ @keyframes bl-tk-ring { 12% { transform: rotate(18deg); } 25% { transform: rotate(-16deg); } 38% { transform: rotate(12deg); } 50% { transform: rotate(-8deg); } 62% { transform: rotate(4deg); } 75% { transform: none; } }
57
+ @keyframes bl-tk-waves { 15%, 60% { opacity: 1; } }
58
+ @media (prefers-reduced-motion: reduce) {
59
+ .bl-tk__switch, .bl-tk__thumb, .bl-tk__check, .bl-tk__dash, .bl-tk__dot, .bl-tk__box, .bl-tk__radio, .bl-tk__bell-icon, .bl-tk__bell-icon svg, .bl-tk__bell-waves { transition: none; animation: none !important; }
60
+ }
61
+ `;
62
+ function useStyles() {
63
+ useInsertionEffect(() => {
64
+ if (typeof document === "undefined") return;
65
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
66
+ style.textContent = CSS;
67
+ if (!style.isConnected) document.head.appendChild(style);
68
+ }, []);
69
+ }
70
+ function useChecked(checked, defaultChecked, onCheckedChange) {
71
+ const [inner, setInner] = useState(defaultChecked ?? false);
72
+ const value = checked ?? inner;
73
+ const set = (next) => {
74
+ if (checked === void 0) setInner(next);
75
+ onCheckedChange?.(next);
76
+ };
77
+ return [value, set];
78
+ }
79
+ const accentVars = (color) => color ? { "--bl-tk-accent": color } : null;
80
+ function Label({ label, description, id }) {
81
+ if (!label && !description) return null;
82
+ return /* @__PURE__ */ jsxs("span", { className: "bl-tk__text", children: [
83
+ label && /* @__PURE__ */ jsx("span", { children: label }),
84
+ description && /* @__PURE__ */ jsx("span", { id, className: "bl-tk__desc", children: description })
85
+ ] });
86
+ }
87
+ function Switch({ checked, defaultChecked, onCheckedChange, label, description, disabled = false, size = "md", color, name, value, className = "", style, ...rest }) {
88
+ useStyles();
89
+ const uid = useId().replace(/[^a-zA-Z0-9_-]/g, "");
90
+ const [on, setOn] = useChecked(checked, defaultChecked, onCheckedChange);
91
+ return /* @__PURE__ */ jsxs("label", { className: `bl-tk ${className}`, "data-size": size, "data-disabled": disabled || void 0, style: { ...accentVars(color), ...style }, children: [
92
+ /* @__PURE__ */ jsx(
93
+ "input",
94
+ {
95
+ ...rest,
96
+ type: "checkbox",
97
+ role: "switch",
98
+ className: "bl-tk__input",
99
+ checked: on,
100
+ disabled,
101
+ name,
102
+ value,
103
+ "aria-describedby": description ? `${uid}-desc` : void 0,
104
+ onChange: (event) => setOn(event.target.checked)
105
+ }
106
+ ),
107
+ /* @__PURE__ */ jsx("span", { className: "bl-tk__switch bl-tk__control", "aria-hidden": "true", children: /* @__PURE__ */ jsx("span", { className: "bl-tk__thumb" }) }),
108
+ /* @__PURE__ */ jsx(Label, { label, description, id: `${uid}-desc` })
109
+ ] });
110
+ }
111
+ function Checkbox({ checked, defaultChecked, onCheckedChange, indeterminate = false, label, description, disabled = false, size = "md", color, name, value, className = "", style, ...rest }) {
112
+ useStyles();
113
+ const uid = useId().replace(/[^a-zA-Z0-9_-]/g, "");
114
+ const ref = useRef(null);
115
+ const [on, setOn] = useChecked(checked, defaultChecked, onCheckedChange);
116
+ useEffect(() => {
117
+ if (ref.current) ref.current.indeterminate = indeterminate;
118
+ }, [indeterminate]);
119
+ return /* @__PURE__ */ jsxs("label", { className: `bl-tk ${className}`, "data-size": size, "data-disabled": disabled || void 0, style: { ...accentVars(color), ...style }, children: [
120
+ /* @__PURE__ */ jsx(
121
+ "input",
122
+ {
123
+ ...rest,
124
+ ref,
125
+ type: "checkbox",
126
+ className: "bl-tk__input",
127
+ checked: on,
128
+ disabled,
129
+ name,
130
+ value,
131
+ "aria-describedby": description ? `${uid}-desc` : void 0,
132
+ onChange: (event) => setOn(event.target.checked)
133
+ }
134
+ ),
135
+ /* @__PURE__ */ jsx("span", { className: "bl-tk__box bl-tk__control", "aria-hidden": "true", children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 16 16", children: [
136
+ /* @__PURE__ */ jsx("path", { className: "bl-tk__check", pathLength: "1", d: "M3 8.5 6.5 12 13 4.5" }),
137
+ /* @__PURE__ */ jsx("path", { className: "bl-tk__dash", pathLength: "1", d: "M4 8h8" })
138
+ ] }) }),
139
+ /* @__PURE__ */ jsx(Label, { label, description, id: `${uid}-desc` })
140
+ ] });
141
+ }
142
+ function Radio({ checked, onChange, label, description, disabled = false, size = "md", color, name, value, className = "", style, ...rest }) {
143
+ useStyles();
144
+ const uid = useId().replace(/[^a-zA-Z0-9_-]/g, "");
145
+ return /* @__PURE__ */ jsxs("label", { className: `bl-tk ${className}`, "data-size": size, "data-disabled": disabled || void 0, style: { ...accentVars(color), ...style }, children: [
146
+ /* @__PURE__ */ jsx(
147
+ "input",
148
+ {
149
+ ...rest,
150
+ type: "radio",
151
+ className: "bl-tk__input",
152
+ checked,
153
+ disabled,
154
+ name,
155
+ value,
156
+ "aria-describedby": description ? `${uid}-desc` : void 0,
157
+ onChange
158
+ }
159
+ ),
160
+ /* @__PURE__ */ jsx("span", { className: "bl-tk__radio bl-tk__control", "aria-hidden": "true", children: /* @__PURE__ */ jsx("span", { className: "bl-tk__dot" }) }),
161
+ /* @__PURE__ */ jsx(Label, { label, description, id: `${uid}-desc` })
162
+ ] });
163
+ }
164
+ function RadioGroup({ options = [], value, defaultValue, onValueChange, label, name, orientation = "vertical", size = "md", color, disabled = false, className = "", style }) {
165
+ useStyles();
166
+ const uid = useId().replace(/[^a-zA-Z0-9_-]/g, "");
167
+ const [inner, setInner] = useState(defaultValue ?? null);
168
+ const selected = value !== void 0 ? value : inner;
169
+ return /* @__PURE__ */ jsxs("fieldset", { className: `bl-tk-group ${className}`, "data-orientation": orientation, disabled, style: { ...accentVars(color), ...style }, children: [
170
+ label && /* @__PURE__ */ jsx("legend", { children: label }),
171
+ /* @__PURE__ */ jsx("div", { className: "bl-tk-group__list", children: options.map((option) => /* @__PURE__ */ jsx(
172
+ Radio,
173
+ {
174
+ name: name ?? `${uid}-radio`,
175
+ value: option.value,
176
+ label: option.label,
177
+ description: option.description,
178
+ disabled: option.disabled,
179
+ size,
180
+ checked: selected === option.value,
181
+ onChange: () => {
182
+ if (value === void 0) setInner(option.value);
183
+ onValueChange?.(option.value);
184
+ }
185
+ },
186
+ option.value
187
+ )) })
188
+ ] });
189
+ }
190
+ const SLASH = Array.from({ length: 10 }, (_, i) => i + 1);
191
+ function NotifyBell({ pressed, defaultPressed, onPressedChange, label = "Notifications", showLabel = true, disabled = false, size = "md", color, className = "", style, ...rest }) {
192
+ useStyles();
193
+ const [on, setOn] = useChecked(pressed, defaultPressed, onPressedChange);
194
+ return /* @__PURE__ */ jsxs(
195
+ "button",
196
+ {
197
+ ...rest,
198
+ type: "button",
199
+ className: `bl-tk bl-tk__bell ${className}`,
200
+ "aria-pressed": on,
201
+ "aria-label": showLabel ? void 0 : label,
202
+ disabled,
203
+ "data-size": size,
204
+ "data-disabled": disabled || void 0,
205
+ onClick: () => setOn(!on),
206
+ style: { ...accentVars(color), ...style },
207
+ children: [
208
+ /* @__PURE__ */ jsx("span", { className: "bl-tk__bell-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 12 12", children: [
209
+ /* @__PURE__ */ jsx("path", { d: "M5 1h2v1h1v1h1v4h1v1h1v1H1V8h1V7h1V3h1V2h1zM5 10h2v1H5z" }),
210
+ /* @__PURE__ */ jsxs("g", { className: "bl-tk__bell-waves", children: [
211
+ /* @__PURE__ */ jsx("rect", { x: "0", y: "3", width: "1", height: "2" }),
212
+ /* @__PURE__ */ jsx("rect", { x: "11", y: "3", width: "1", height: "2" })
213
+ ] }),
214
+ /* @__PURE__ */ jsx("g", { className: "bl-tk__bell-slash", children: SLASH.map((i) => /* @__PURE__ */ jsx("rect", { x: i, y: i, width: "1", height: "1" }, i)) })
215
+ ] }) }),
216
+ showLabel && /* @__PURE__ */ jsx("span", { className: "bl-tk__text", children: /* @__PURE__ */ jsx("span", { children: label }) })
217
+ ]
218
+ }
219
+ );
220
+ }
221
+ var stdin_default = Switch;
222
+ export {
223
+ Checkbox,
224
+ NotifyBell,
225
+ Radio,
226
+ RadioGroup,
227
+ Switch,
228
+ stdin_default as default
229
+ };
@@ -0,0 +1,24 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ export interface TracingLineProps {
3
+ /** Entries. Each direct child gets a marker. */
4
+ children?: ReactNode;
5
+ /** Width of the left gutter holding the line, in px. */
6
+ gutter?: number;
7
+ lineWidth?: number;
8
+ markerSize?: number;
9
+ /** Marker position below each child's top, in px. */
10
+ markerOffset?: number;
11
+ /** Square markers and head, for a pixel look. */
12
+ square?: boolean;
13
+ /** Viewport position (0 top, 1 bottom) the line draws down to. */
14
+ activeLine?: number;
15
+ fromColor?: string;
16
+ toColor?: string;
17
+ glowColor?: string;
18
+ trackColor?: string;
19
+ /** Fill of markers the line hasn't reached yet. */
20
+ backgroundColor?: string;
21
+ className?: string;
22
+ style?: CSSProperties;
23
+ }
24
+ export default function TracingLine({ children, gutter, lineWidth, markerSize, markerOffset, square, activeLine, fromColor, toColor, glowColor, trackColor, backgroundColor, className, style }: TracingLineProps): import("react").JSX.Element;
@@ -0,0 +1,139 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useInsertionEffect, useRef, useState } from "react";
4
+ const STYLE_ID = "bl-tracing-line";
5
+ const CSS = `
6
+ .bl-trace { position: relative; padding-left: var(--bl-gutter); }
7
+ .bl-trace__track, .bl-trace__fill { position: absolute; left: calc(var(--bl-gutter) / 2 - var(--bl-w) / 2); top: var(--bl-start); width: var(--bl-w); border-radius: var(--bl-w); }
8
+ .bl-trace__track { bottom: var(--bl-end); background: var(--bl-track); }
9
+ .bl-trace__fill { height: var(--bl-fill); background: linear-gradient(to bottom, var(--bl-from), var(--bl-to)); box-shadow: 0 0 12px var(--bl-glow); }
10
+ .bl-trace__head { position: absolute; left: calc(var(--bl-gutter) / 2); top: calc(var(--bl-start) + var(--bl-fill)); width: calc(var(--bl-w) * 4); height: calc(var(--bl-w) * 4); border-radius: var(--bl-dot-radius); background: var(--bl-to); box-shadow: 0 0 0 4px var(--bl-glow), 0 0 22px 4px var(--bl-glow); transform: translate(-50%, -50%); opacity: var(--bl-head-o); }
11
+ .bl-trace__marker { position: absolute; left: calc(var(--bl-gutter) / 2); width: var(--bl-marker); height: var(--bl-marker); border-radius: var(--bl-dot-radius); background: var(--bl-bg); box-shadow: inset 0 0 0 2px var(--bl-track); transform: translate(-50%, -50%) scale(0.85); transition: box-shadow 250ms, background-color 250ms, transform 250ms; }
12
+ .bl-trace__marker[data-passed] { background: var(--bl-to); box-shadow: inset 0 0 0 2px var(--bl-to), 0 0 0 4px var(--bl-glow); transform: translate(-50%, -50%) scale(1); }
13
+ .bl-trace__content > * { scroll-margin-top: 24px; }
14
+ @media (prefers-reduced-motion: reduce) { .bl-trace__marker { transition: none; } }
15
+ `;
16
+ function useStyles() {
17
+ useInsertionEffect(() => {
18
+ if (typeof document === "undefined") return;
19
+ const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
20
+ style.textContent = CSS;
21
+ if (!style.isConnected) document.head.appendChild(style);
22
+ }, []);
23
+ }
24
+ function scrollParent(node) {
25
+ for (let el = node?.parentElement; el; el = el.parentElement) {
26
+ if (/(auto|scroll|overlay)/.test(getComputedStyle(el).overflowY) && el.scrollHeight > el.clientHeight) return el;
27
+ }
28
+ return window;
29
+ }
30
+ function TracingLine({
31
+ children,
32
+ gutter = 56,
33
+ lineWidth = 3,
34
+ markerSize = 14,
35
+ markerOffset = 14,
36
+ square = false,
37
+ activeLine = 0.55,
38
+ fromColor = "#41a6f6",
39
+ toColor = "#73eff7",
40
+ glowColor = "rgba(115,239,247,0.35)",
41
+ trackColor = "rgba(148,176,194,0.22)",
42
+ backgroundColor = "#1a1c2c",
43
+ className = "",
44
+ style
45
+ }) {
46
+ useStyles();
47
+ const rootRef = useRef(null);
48
+ const contentRef = useRef(null);
49
+ const [markers, setMarkers] = useState([]);
50
+ const [passed, setPassed] = useState(-1);
51
+ useEffect(() => {
52
+ const root = rootRef.current;
53
+ const content = contentRef.current;
54
+ const scroller = scrollParent(root);
55
+ let frame = 0;
56
+ let positions = [];
57
+ let lastPassed = -2;
58
+ const measure = () => {
59
+ positions = [...content.children].map((child) => child.offsetTop + markerOffset);
60
+ setMarkers((prev) => prev.length === positions.length && prev.every((y, i) => y === positions[i]) ? prev : positions);
61
+ const first = positions[0] ?? 0;
62
+ const last = positions[positions.length - 1] ?? root.offsetHeight;
63
+ root.style.setProperty("--bl-start", `${first}px`);
64
+ root.style.setProperty("--bl-end", `${root.offsetHeight - last}px`);
65
+ };
66
+ const update = () => {
67
+ frame = 0;
68
+ const rect = root.getBoundingClientRect();
69
+ const viewTop = scroller === window ? 0 : scroller.getBoundingClientRect().top;
70
+ const viewHeight = scroller === window ? window.innerHeight : scroller.clientHeight;
71
+ const line = viewTop + viewHeight * activeLine - rect.top;
72
+ const first = positions[0] ?? 0;
73
+ const last = positions[positions.length - 1] ?? rect.height;
74
+ const fill = Math.min(last - first, Math.max(0, line - first));
75
+ root.style.setProperty("--bl-fill", `${fill}px`);
76
+ root.style.setProperty("--bl-head-o", fill > 0 && fill < last - first ? "1" : "0");
77
+ let count = -1;
78
+ positions.forEach((y, i) => {
79
+ if (y <= first + fill + 0.5) count = i;
80
+ });
81
+ if (count !== lastPassed) {
82
+ lastPassed = count;
83
+ setPassed(count);
84
+ }
85
+ };
86
+ const schedule = () => {
87
+ if (!frame) frame = requestAnimationFrame(update);
88
+ };
89
+ const observer = new ResizeObserver(() => {
90
+ measure();
91
+ schedule();
92
+ });
93
+ observer.observe(content);
94
+ [...content.children].forEach((child) => observer.observe(child));
95
+ measure();
96
+ update();
97
+ scroller.addEventListener("scroll", schedule, { passive: true });
98
+ window.addEventListener("resize", schedule);
99
+ return () => {
100
+ cancelAnimationFrame(frame);
101
+ observer.disconnect();
102
+ scroller.removeEventListener("scroll", schedule);
103
+ window.removeEventListener("resize", schedule);
104
+ };
105
+ }, [activeLine, markerOffset, children]);
106
+ return /* @__PURE__ */ jsxs(
107
+ "div",
108
+ {
109
+ ref: rootRef,
110
+ className: `bl-trace ${className}`,
111
+ style: {
112
+ "--bl-gutter": `${gutter}px`,
113
+ "--bl-w": `${lineWidth}px`,
114
+ "--bl-marker": `${markerSize}px`,
115
+ "--bl-dot-radius": square ? "0" : "50%",
116
+ "--bl-from": fromColor,
117
+ "--bl-to": toColor,
118
+ "--bl-glow": glowColor,
119
+ "--bl-track": trackColor,
120
+ "--bl-bg": backgroundColor,
121
+ "--bl-start": "0px",
122
+ "--bl-end": "0px",
123
+ "--bl-fill": "0px",
124
+ "--bl-head-o": 0,
125
+ ...style
126
+ },
127
+ children: [
128
+ /* @__PURE__ */ jsx("div", { className: "bl-trace__track", "aria-hidden": "true" }),
129
+ /* @__PURE__ */ jsx("div", { className: "bl-trace__fill", "aria-hidden": "true" }),
130
+ markers.map((y, index) => /* @__PURE__ */ jsx("span", { className: "bl-trace__marker", style: { top: y }, "data-passed": index <= passed ? "" : void 0, "aria-hidden": "true" }, index)),
131
+ /* @__PURE__ */ jsx("div", { className: "bl-trace__head", "aria-hidden": "true" }),
132
+ /* @__PURE__ */ jsx("div", { ref: contentRef, className: "bl-trace__content", children })
133
+ ]
134
+ }
135
+ );
136
+ }
137
+ export {
138
+ TracingLine as default
139
+ };