@heyramzi/ui 0.0.0-stage → 1.53.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 (564) hide show
  1. package/COMPONENTS.md +133 -0
  2. package/README.md +136 -2
  3. package/package.json +217 -3
  4. package/scripts/lib/sync-core.mjs +113 -0
  5. package/scripts/relative-imports.mjs +39 -0
  6. package/scripts/sf-symbol.mjs +93 -0
  7. package/scripts/sync-shadcn.mjs +354 -0
  8. package/scripts/sync-transitions.mjs +146 -0
  9. package/scripts/validate-apple-symbol-exports.mjs +45 -0
  10. package/src/agents/agent-avatar.svelte +592 -0
  11. package/src/agents/agent-cast.svelte +197 -0
  12. package/src/agents/demo.svelte +125 -0
  13. package/src/agents/helpers.ts +58 -0
  14. package/src/agents/index.ts +11 -0
  15. package/src/agents/page-state.ts +70 -0
  16. package/src/agents/types.ts +74 -0
  17. package/src/agents/vendor/LICENSE +21 -0
  18. package/src/agents/vendor/color.ts +155 -0
  19. package/src/agents/vendor/draw.ts +840 -0
  20. package/src/agents/vendor/engine.ts +845 -0
  21. package/src/agents/vendor/mesh.ts +838 -0
  22. package/src/agents/vendor/plastic.ts +4958 -0
  23. package/src/agents/vendor/presets.ts +103 -0
  24. package/src/agents/vendor/shapes.ts +41 -0
  25. package/src/agents/vendor/ticker.ts +67 -0
  26. package/src/agents/vendor/types.ts +261 -0
  27. package/src/agents/vendor/wear.ts +1699 -0
  28. package/src/ai/ai-button/AiButton.svelte +86 -0
  29. package/src/ai/ai-button/index.ts +4 -0
  30. package/src/ai/confirmation/Confirmation.svelte +54 -0
  31. package/src/ai/confirmation/ConfirmationAccepted.svelte +23 -0
  32. package/src/ai/confirmation/ConfirmationAction.svelte +53 -0
  33. package/src/ai/confirmation/ConfirmationActions.svelte +24 -0
  34. package/src/ai/confirmation/ConfirmationFailed.svelte +23 -0
  35. package/src/ai/confirmation/ConfirmationRejected.svelte +23 -0
  36. package/src/ai/confirmation/ConfirmationRequest.svelte +25 -0
  37. package/src/ai/confirmation/ConfirmationTitle.svelte +25 -0
  38. package/src/ai/confirmation/confirmation-context.svelte.ts +22 -0
  39. package/src/ai/confirmation/index.ts +50 -0
  40. package/src/ai/generation-progress/GenerationProgress.svelte +354 -0
  41. package/src/ai/generation-progress/index.ts +7 -0
  42. package/src/ai/index.ts +111 -0
  43. package/src/ai/loading-state/PixelLoader.svelte +138 -0
  44. package/src/ai/loading-state/index.ts +5 -0
  45. package/src/ai/prompt-input/PromptInput.svelte +56 -0
  46. package/src/ai/prompt-input/PromptInputBody.svelte +19 -0
  47. package/src/ai/prompt-input/PromptInputSubmit.svelte +79 -0
  48. package/src/ai/prompt-input/PromptInputTextarea.svelte +74 -0
  49. package/src/ai/prompt-input/PromptInputToolbar.svelte +19 -0
  50. package/src/ai/prompt-input/index.ts +34 -0
  51. package/src/ai/reasoning/Reasoning.svelte +50 -0
  52. package/src/ai/reasoning/ReasoningContent.svelte +27 -0
  53. package/src/ai/reasoning/ReasoningTrigger.svelte +48 -0
  54. package/src/ai/reasoning/index.ts +22 -0
  55. package/src/ai/reasoning/reasoning-context.svelte.ts +20 -0
  56. package/src/ai/response/Response.css +32 -0
  57. package/src/ai/response/Response.svelte +130 -0
  58. package/src/ai/response/index.ts +5 -0
  59. package/src/ai/suggestion/Suggestion.svelte +43 -0
  60. package/src/ai/suggestion/Suggestions.svelte +25 -0
  61. package/src/ai/suggestion/index.ts +14 -0
  62. package/src/ai/thinking-dots/ThinkingDots.svelte +42 -0
  63. package/src/ai/thinking-dots/index.ts +5 -0
  64. package/src/ai/typing-dots/TypingDots.css +39 -0
  65. package/src/ai/typing-dots/TypingDots.svelte +27 -0
  66. package/src/ai/typing-dots/index.ts +10 -0
  67. package/src/ai/voice-waveform/VoiceWaveform.css +40 -0
  68. package/src/ai/voice-waveform/VoiceWaveform.svelte +46 -0
  69. package/src/ai/voice-waveform/index.ts +5 -0
  70. package/src/ambient.d.ts +4 -0
  71. package/src/animations/README.md +84 -0
  72. package/src/animations/avatar-group-hover.css +47 -0
  73. package/src/animations/card-tilt.css +74 -0
  74. package/src/animations/digit-pop-in.css +78 -0
  75. package/src/animations/dropdown.css +121 -0
  76. package/src/animations/index.css +23 -0
  77. package/src/animations/input-clear-dissolve.css +86 -0
  78. package/src/animations/input-shake.css +114 -0
  79. package/src/animations/learn-more-hover.css +48 -0
  80. package/src/animations/like-button.css +93 -0
  81. package/src/animations/modal.css +75 -0
  82. package/src/animations/page-side-by-side.css +63 -0
  83. package/src/animations/plus-menu-morph.css +97 -0
  84. package/src/animations/resize.css +20 -0
  85. package/src/animations/shimmer-text.css +72 -0
  86. package/src/animations/spinning-counter.css +52 -0
  87. package/src/animations/success-check.css +120 -0
  88. package/src/animations/text-swap.css +40 -0
  89. package/src/animations/text-swap.ts +40 -0
  90. package/src/animations/thinking-states.css +65 -0
  91. package/src/animations/upstream-coverage.test.ts +65 -0
  92. package/src/components/copy/clipboard.test.ts +206 -0
  93. package/src/components/copy/clipboard.ts +49 -0
  94. package/src/components/copy/copied.svelte.ts +39 -0
  95. package/src/components/copy/copy-button.svelte +175 -0
  96. package/src/components/copy/copy-button.test.ts +110 -0
  97. package/src/components/copy/index.ts +3 -0
  98. package/src/components/data-table/data-table.test.ts +134 -0
  99. package/src/components/data-table/data-table.ts +77 -0
  100. package/src/components/data-table/index.ts +20 -0
  101. package/src/components/data-table/infinite-scroll.svelte +69 -0
  102. package/src/components/data-table/pagination.svelte +62 -0
  103. package/src/components/data-table/row-arrow.svelte +28 -0
  104. package/src/components/data-table/row-context-menu.svelte +106 -0
  105. package/src/components/data-table/row-context-menu.test.ts +18 -0
  106. package/src/components/data-table/sortable-head.svelte +56 -0
  107. package/src/components/data-table/table-skeleton.svelte +83 -0
  108. package/src/components/hold-to-confirm/hold-to-confirm.svelte +232 -0
  109. package/src/components/hold-to-confirm/index.ts +1 -0
  110. package/src/components/icon/icon.svelte +23 -0
  111. package/src/components/icon/index.ts +1 -0
  112. package/src/components/language-flag/index.ts +1 -0
  113. package/src/components/language-flag/language-flag.svelte +60 -0
  114. package/src/components/list-page/detail-empty.svelte +50 -0
  115. package/src/components/list-page/detail-header.svelte +107 -0
  116. package/src/components/list-page/detail-panel.svelte +90 -0
  117. package/src/components/list-page/detail-row.svelte +36 -0
  118. package/src/components/list-page/detail-stack.svelte +33 -0
  119. package/src/components/list-page/empty-state.svelte +91 -0
  120. package/src/components/list-page/filter-item.svelte +49 -0
  121. package/src/components/list-page/filter-popover.svelte +88 -0
  122. package/src/components/list-page/filter-section.ts +12 -0
  123. package/src/components/list-page/grouped-list.svelte +116 -0
  124. package/src/components/list-page/index.ts +28 -0
  125. package/src/components/list-page/list-page-shell.svelte +195 -0
  126. package/src/components/list-page/list-table.ts +19 -0
  127. package/src/components/list-page/master-detail.svelte +206 -0
  128. package/src/components/list-page/master-detail.test.ts +37 -0
  129. package/src/components/list-page/notice-bar.svelte +68 -0
  130. package/src/components/list-page/prev-next.svelte +104 -0
  131. package/src/components/list-page/queue-rail.ts +25 -0
  132. package/src/components/list-page/rail-body.svelte +29 -0
  133. package/src/components/list-page/rail-empty.svelte +51 -0
  134. package/src/components/list-page/rail-head.svelte +49 -0
  135. package/src/components/list-page/rail-row.svelte +163 -0
  136. package/src/components/list-page/section-host.ts +24 -0
  137. package/src/components/list-page/section-label.svelte +39 -0
  138. package/src/components/list-page/step.test.ts +21 -0
  139. package/src/components/list-page/step.ts +10 -0
  140. package/src/components/list-page/toolbar-search.svelte +63 -0
  141. package/src/components/list-page/toolbar-trigger.ts +23 -0
  142. package/src/components/list-page/types.ts +1 -0
  143. package/src/components/locale-switch/index.ts +1 -0
  144. package/src/components/locale-switch/locale-switch.svelte +59 -0
  145. package/src/components/mark/index.ts +1 -0
  146. package/src/components/mark/mark.svelte +70 -0
  147. package/src/components/open-in/index.ts +6 -0
  148. package/src/components/open-in/open-in.svelte +106 -0
  149. package/src/components/picker/index.ts +4 -0
  150. package/src/components/picker/mark-picker.svelte +84 -0
  151. package/src/components/picker/picker.svelte +143 -0
  152. package/src/components/picker/trigger.ts +42 -0
  153. package/src/components/picker/types.ts +26 -0
  154. package/src/components/segmented/animated-tabs.svelte +175 -0
  155. package/src/components/segmented/collapse.test.ts +49 -0
  156. package/src/components/segmented/collapse.ts +39 -0
  157. package/src/components/segmented/index.ts +41 -0
  158. package/src/components/segmented/section-runs.svelte +79 -0
  159. package/src/components/segmented/segment.svelte +106 -0
  160. package/src/components/segmented/segmented-filter.svelte +125 -0
  161. package/src/components/segmented/segmented-nav.svelte +82 -0
  162. package/src/components/segmented/segmented-overflow.svelte +85 -0
  163. package/src/components/segmented/segmented-track.svelte +181 -0
  164. package/src/components/segmented/segmented.test.ts +20 -0
  165. package/src/components/segmented/segmented.ts +80 -0
  166. package/src/components/star-rating-input/index.ts +9 -0
  167. package/src/components/star-rating-input/star-rating-input.svelte +256 -0
  168. package/src/components/svg/index.ts +1 -0
  169. package/src/components/svg/svg.svelte +9 -0
  170. package/src/design/index.css +270 -0
  171. package/src/design/polish.css +159 -0
  172. package/src/effects/animated-beam/AnimatedBeam.svelte +132 -0
  173. package/src/effects/animated-beam/diagrams/BeamSvg.svelte +91 -0
  174. package/src/effects/animated-beam/index.ts +2 -0
  175. package/src/effects/animated-beam/path-calculator.svelte.ts +70 -0
  176. package/src/effects/animated-beam/types.ts +23 -0
  177. package/src/effects/border-beam/BorderBeam.svelte +223 -0
  178. package/src/effects/border-beam/css.test.ts +46 -0
  179. package/src/effects/border-beam/css.ts +574 -0
  180. package/src/effects/border-beam/presets.ts +699 -0
  181. package/src/effects/border-beam/register-properties.test.ts +74 -0
  182. package/src/effects/border-beam/register-properties.ts +73 -0
  183. package/src/effects/border-beam/types.ts +38 -0
  184. package/src/effects/image-comparison/ImageComparison.css +100 -0
  185. package/src/effects/image-comparison/ImageComparison.svelte +209 -0
  186. package/src/effects/image-comparison/compare.test.ts +17 -0
  187. package/src/effects/image-comparison/compare.ts +5 -0
  188. package/src/effects/image-reveal/ImageReveal.css +10 -0
  189. package/src/effects/image-reveal/ImageReveal.svelte +357 -0
  190. package/src/effects/image-reveal/index.ts +2 -0
  191. package/src/effects/image-reveal/types.ts +35 -0
  192. package/src/effects/interactive-hover-button/InteractiveHoverButton.svelte +338 -0
  193. package/src/effects/magic-card/MagicCard.css +47 -0
  194. package/src/effects/magic-card/MagicCard.svelte +57 -0
  195. package/src/effects/magnetic/magnetic.ts +81 -0
  196. package/src/effects/marquee/Marquee.css +78 -0
  197. package/src/effects/marquee/Marquee.svelte +160 -0
  198. package/src/effects/progressive-blur/ProgressiveBlur.css +9 -0
  199. package/src/effects/progressive-blur/ProgressiveBlur.svelte +63 -0
  200. package/src/effects/reveal/AnimatedGroup.svelte +101 -0
  201. package/src/effects/reveal/InView.svelte +77 -0
  202. package/src/effects/reveal/TextEffect.svelte +142 -0
  203. package/src/effects/reveal/index.ts +11 -0
  204. package/src/effects/reveal/observe.test.ts +60 -0
  205. package/src/effects/reveal/observe.ts +65 -0
  206. package/src/effects/reveal/reveal.css +141 -0
  207. package/src/effects/reveal/types.ts +32 -0
  208. package/src/effects/shader-gradient/ShaderGradient.svelte +227 -0
  209. package/src/effects/shader-gradient/color.ts +44 -0
  210. package/src/effects/shader-gradient/index.ts +5 -0
  211. package/src/effects/shader-gradient/renderer.ts +456 -0
  212. package/src/effects/shader-gradient/shaders.ts +324 -0
  213. package/src/effects/shader-gradient/types.ts +68 -0
  214. package/src/effects/spotlight/Spotlight.css +14 -0
  215. package/src/effects/spotlight/Spotlight.svelte +61 -0
  216. package/src/effects/theme-toggle/ThemeToggle.css +214 -0
  217. package/src/effects/theme-toggle/ThemeToggle.svelte +126 -0
  218. package/src/gallery.test.ts +52 -0
  219. package/src/icons/TradeIcon.svelte +16 -0
  220. package/src/icons/apple-symbol-exports.ts +135 -0
  221. package/src/icons/sf-symbols.ts +527 -0
  222. package/src/icons/trades.ts +89 -0
  223. package/src/index.ts +53 -0
  224. package/src/lib/arrive.ts +26 -0
  225. package/src/lib/icon-types.ts +17 -0
  226. package/src/lib/layout.ts +8 -0
  227. package/src/lib/panel.ts +21 -0
  228. package/src/lib/sliding-pill.ts +68 -0
  229. package/src/lib/theme-transition.ts +79 -0
  230. package/src/lib/tone.ts +48 -0
  231. package/src/shadcn/accordion/accordion-content.svelte +22 -0
  232. package/src/shadcn/accordion/accordion-item.svelte +17 -0
  233. package/src/shadcn/accordion/accordion-trigger.svelte +44 -0
  234. package/src/shadcn/accordion/accordion.svelte +19 -0
  235. package/src/shadcn/accordion/index.ts +16 -0
  236. package/src/shadcn/alert/alert-description.svelte +23 -0
  237. package/src/shadcn/alert/alert-title.svelte +20 -0
  238. package/src/shadcn/alert/alert.svelte +46 -0
  239. package/src/shadcn/alert/index.ts +14 -0
  240. package/src/shadcn/alert-dialog/alert-dialog-action.svelte +18 -0
  241. package/src/shadcn/alert-dialog/alert-dialog-cancel.svelte +18 -0
  242. package/src/shadcn/alert-dialog/alert-dialog-content.svelte +29 -0
  243. package/src/shadcn/alert-dialog/alert-dialog-description.svelte +17 -0
  244. package/src/shadcn/alert-dialog/alert-dialog-footer.svelte +20 -0
  245. package/src/shadcn/alert-dialog/alert-dialog-header.svelte +20 -0
  246. package/src/shadcn/alert-dialog/alert-dialog-overlay.svelte +17 -0
  247. package/src/shadcn/alert-dialog/alert-dialog-portal.svelte +7 -0
  248. package/src/shadcn/alert-dialog/alert-dialog-title.svelte +17 -0
  249. package/src/shadcn/alert-dialog/alert-dialog-trigger.svelte +7 -0
  250. package/src/shadcn/alert-dialog/alert-dialog.svelte +7 -0
  251. package/src/shadcn/alert-dialog/index.ts +37 -0
  252. package/src/shadcn/attachment/attachment-action.svelte +23 -0
  253. package/src/shadcn/attachment/attachment-actions.svelte +23 -0
  254. package/src/shadcn/attachment/attachment-content.svelte +23 -0
  255. package/src/shadcn/attachment/attachment-description.svelte +23 -0
  256. package/src/shadcn/attachment/attachment-group.svelte +23 -0
  257. package/src/shadcn/attachment/attachment-media.svelte +44 -0
  258. package/src/shadcn/attachment/attachment-title.svelte +23 -0
  259. package/src/shadcn/attachment/attachment-trigger.svelte +29 -0
  260. package/src/shadcn/attachment/attachment.svelte +55 -0
  261. package/src/shadcn/attachment/index.ts +40 -0
  262. package/src/shadcn/avatar/avatar-badge.svelte +26 -0
  263. package/src/shadcn/avatar/avatar-fallback.svelte +20 -0
  264. package/src/shadcn/avatar/avatar-group-count.svelte +23 -0
  265. package/src/shadcn/avatar/avatar-group.svelte +23 -0
  266. package/src/shadcn/avatar/avatar-image.svelte +17 -0
  267. package/src/shadcn/avatar/avatar.svelte +26 -0
  268. package/src/shadcn/avatar/index.ts +22 -0
  269. package/src/shadcn/badge/badge.svelte +54 -0
  270. package/src/shadcn/badge/index.ts +2 -0
  271. package/src/shadcn/breadcrumb/breadcrumb-ellipsis.svelte +23 -0
  272. package/src/shadcn/breadcrumb/breadcrumb-item.svelte +20 -0
  273. package/src/shadcn/breadcrumb/breadcrumb-link.svelte +31 -0
  274. package/src/shadcn/breadcrumb/breadcrumb-list.svelte +23 -0
  275. package/src/shadcn/breadcrumb/breadcrumb-page.svelte +23 -0
  276. package/src/shadcn/breadcrumb/breadcrumb-separator.svelte +27 -0
  277. package/src/shadcn/breadcrumb/breadcrumb.svelte +21 -0
  278. package/src/shadcn/breadcrumb/index.ts +25 -0
  279. package/src/shadcn/bubble/bubble-content.svelte +31 -0
  280. package/src/shadcn/bubble/bubble-group.svelte +20 -0
  281. package/src/shadcn/bubble/bubble-reactions.svelte +52 -0
  282. package/src/shadcn/bubble/bubble.svelte +58 -0
  283. package/src/shadcn/bubble/index.ts +25 -0
  284. package/src/shadcn/button/button.svelte +121 -0
  285. package/src/shadcn/button/index.ts +17 -0
  286. package/src/shadcn/calendar/calendar-caption.svelte +76 -0
  287. package/src/shadcn/calendar/calendar-cell.svelte +19 -0
  288. package/src/shadcn/calendar/calendar-day.svelte +35 -0
  289. package/src/shadcn/calendar/calendar-grid-body.svelte +12 -0
  290. package/src/shadcn/calendar/calendar-grid-head.svelte +12 -0
  291. package/src/shadcn/calendar/calendar-grid-row.svelte +12 -0
  292. package/src/shadcn/calendar/calendar-grid.svelte +16 -0
  293. package/src/shadcn/calendar/calendar-head-cell.svelte +19 -0
  294. package/src/shadcn/calendar/calendar-header.svelte +19 -0
  295. package/src/shadcn/calendar/calendar-heading.svelte +16 -0
  296. package/src/shadcn/calendar/calendar-month-select.svelte +44 -0
  297. package/src/shadcn/calendar/calendar-month.svelte +15 -0
  298. package/src/shadcn/calendar/calendar-months.svelte +19 -0
  299. package/src/shadcn/calendar/calendar-nav.svelte +19 -0
  300. package/src/shadcn/calendar/calendar-next-button.svelte +31 -0
  301. package/src/shadcn/calendar/calendar-prev-button.svelte +31 -0
  302. package/src/shadcn/calendar/calendar-year-select.svelte +43 -0
  303. package/src/shadcn/calendar/calendar.svelte +124 -0
  304. package/src/shadcn/calendar/index.ts +40 -0
  305. package/src/shadcn/card/card-action.svelte +23 -0
  306. package/src/shadcn/card/card-content.svelte +20 -0
  307. package/src/shadcn/card/card-description.svelte +20 -0
  308. package/src/shadcn/card/card-footer.svelte +23 -0
  309. package/src/shadcn/card/card-header.svelte +23 -0
  310. package/src/shadcn/card/card-title.svelte +29 -0
  311. package/src/shadcn/card/card.svelte +25 -0
  312. package/src/shadcn/card/index.ts +25 -0
  313. package/src/shadcn/checkbox/checkbox.svelte +38 -0
  314. package/src/shadcn/checkbox/index.ts +6 -0
  315. package/src/shadcn/code-block/code-block-actions.svelte +23 -0
  316. package/src/shadcn/code-block/code-block-content.svelte +55 -0
  317. package/src/shadcn/code-block/code-block-copy-button.svelte +10 -0
  318. package/src/shadcn/code-block/code-block-footer.svelte +20 -0
  319. package/src/shadcn/code-block/code-block-header.svelte +23 -0
  320. package/src/shadcn/code-block/code-block-line.svelte +71 -0
  321. package/src/shadcn/code-block/code-block-title.svelte +23 -0
  322. package/src/shadcn/code-block/code-block.svelte +47 -0
  323. package/src/shadcn/code-block/index.ts +42 -0
  324. package/src/shadcn/collapsible/collapsible-content.svelte +7 -0
  325. package/src/shadcn/collapsible/collapsible-trigger.svelte +7 -0
  326. package/src/shadcn/collapsible/collapsible.svelte +11 -0
  327. package/src/shadcn/collapsible/index.ts +13 -0
  328. package/src/shadcn/command/command-dialog.svelte +66 -0
  329. package/src/shadcn/command/command-empty.svelte +17 -0
  330. package/src/shadcn/command/command-group.svelte +40 -0
  331. package/src/shadcn/command/command-input.svelte +64 -0
  332. package/src/shadcn/command/command-item.svelte +37 -0
  333. package/src/shadcn/command/command-link-item.svelte +20 -0
  334. package/src/shadcn/command/command-list.svelte +20 -0
  335. package/src/shadcn/command/command-loading.svelte +7 -0
  336. package/src/shadcn/command/command-separator.svelte +17 -0
  337. package/src/shadcn/command/command-shortcut.svelte +23 -0
  338. package/src/shadcn/command/command.svelte +28 -0
  339. package/src/shadcn/command/index.ts +40 -0
  340. package/src/shadcn/context-menu/context-menu-checkbox-item.svelte +41 -0
  341. package/src/shadcn/context-menu/context-menu-content.svelte +28 -0
  342. package/src/shadcn/context-menu/context-menu-group-heading.svelte +21 -0
  343. package/src/shadcn/context-menu/context-menu-group.svelte +7 -0
  344. package/src/shadcn/context-menu/context-menu-item.svelte +27 -0
  345. package/src/shadcn/context-menu/context-menu-label.svelte +27 -0
  346. package/src/shadcn/context-menu/context-menu-portal.svelte +7 -0
  347. package/src/shadcn/context-menu/context-menu-radio-group.svelte +16 -0
  348. package/src/shadcn/context-menu/context-menu-radio-item.svelte +35 -0
  349. package/src/shadcn/context-menu/context-menu-separator.svelte +17 -0
  350. package/src/shadcn/context-menu/context-menu-shortcut.svelte +23 -0
  351. package/src/shadcn/context-menu/context-menu-sub-content.svelte +25 -0
  352. package/src/shadcn/context-menu/context-menu-sub-trigger.svelte +29 -0
  353. package/src/shadcn/context-menu/context-menu-sub.svelte +7 -0
  354. package/src/shadcn/context-menu/context-menu-trigger.svelte +17 -0
  355. package/src/shadcn/context-menu/context-menu.svelte +7 -0
  356. package/src/shadcn/context-menu/index.ts +52 -0
  357. package/src/shadcn/dialog/dialog-close.svelte +11 -0
  358. package/src/shadcn/dialog/dialog-content.svelte +57 -0
  359. package/src/shadcn/dialog/dialog-description.svelte +20 -0
  360. package/src/shadcn/dialog/dialog-footer.svelte +32 -0
  361. package/src/shadcn/dialog/dialog-header.svelte +20 -0
  362. package/src/shadcn/dialog/dialog-overlay.svelte +20 -0
  363. package/src/shadcn/dialog/dialog-portal.svelte +7 -0
  364. package/src/shadcn/dialog/dialog-title.svelte +17 -0
  365. package/src/shadcn/dialog/dialog-trigger.svelte +11 -0
  366. package/src/shadcn/dialog/dialog.svelte +7 -0
  367. package/src/shadcn/dialog/index.ts +34 -0
  368. package/src/shadcn/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  369. package/src/shadcn/dropdown-menu/dropdown-menu-checkbox-item.svelte +43 -0
  370. package/src/shadcn/dropdown-menu/dropdown-menu-content.svelte +31 -0
  371. package/src/shadcn/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  372. package/src/shadcn/dropdown-menu/dropdown-menu-group.svelte +7 -0
  373. package/src/shadcn/dropdown-menu/dropdown-menu-item.svelte +29 -0
  374. package/src/shadcn/dropdown-menu/dropdown-menu-label.svelte +27 -0
  375. package/src/shadcn/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  376. package/src/shadcn/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  377. package/src/shadcn/dropdown-menu/dropdown-menu-radio-item.svelte +34 -0
  378. package/src/shadcn/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  379. package/src/shadcn/dropdown-menu/dropdown-menu-shortcut.svelte +23 -0
  380. package/src/shadcn/dropdown-menu/dropdown-menu-sub-content.svelte +20 -0
  381. package/src/shadcn/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  382. package/src/shadcn/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  383. package/src/shadcn/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  384. package/src/shadcn/dropdown-menu/dropdown-menu.svelte +7 -0
  385. package/src/shadcn/dropdown-menu/index.ts +56 -0
  386. package/src/shadcn/dropdown-menu/menu-item.ts +43 -0
  387. package/src/shadcn/empty/empty-content.svelte +23 -0
  388. package/src/shadcn/empty/empty-description.svelte +23 -0
  389. package/src/shadcn/empty/empty-header.svelte +20 -0
  390. package/src/shadcn/empty/empty-media.svelte +41 -0
  391. package/src/shadcn/empty/empty-title.svelte +20 -0
  392. package/src/shadcn/empty/empty.svelte +23 -0
  393. package/src/shadcn/empty/index.ts +22 -0
  394. package/src/shadcn/field/field-content.svelte +20 -0
  395. package/src/shadcn/field/field-description.svelte +25 -0
  396. package/src/shadcn/field/field-error.svelte +58 -0
  397. package/src/shadcn/field/field-group.svelte +23 -0
  398. package/src/shadcn/field/field-label.svelte +26 -0
  399. package/src/shadcn/field/field-legend.svelte +29 -0
  400. package/src/shadcn/field/field-separator.svelte +35 -0
  401. package/src/shadcn/field/field-set.svelte +24 -0
  402. package/src/shadcn/field/field-title.svelte +23 -0
  403. package/src/shadcn/field/field.svelte +53 -0
  404. package/src/shadcn/field/index.ts +36 -0
  405. package/src/shadcn/field/simple-field.svelte +71 -0
  406. package/src/shadcn/field/simple-field.test.ts +47 -0
  407. package/src/shadcn/hooks/highlighter.ts +132 -0
  408. package/src/shadcn/hooks/is-mobile.svelte.ts +9 -0
  409. package/src/shadcn/hooks/use-highlighted-code.svelte.ts +98 -0
  410. package/src/shadcn/hover-card/hover-card-content.svelte +31 -0
  411. package/src/shadcn/hover-card/hover-card-portal.svelte +7 -0
  412. package/src/shadcn/hover-card/hover-card-trigger.svelte +7 -0
  413. package/src/shadcn/hover-card/hover-card.svelte +7 -0
  414. package/src/shadcn/hover-card/index.ts +15 -0
  415. package/src/shadcn/input/index.ts +9 -0
  416. package/src/shadcn/input/input.svelte +48 -0
  417. package/src/shadcn/input/secret-input.svelte +75 -0
  418. package/src/shadcn/input-otp/index.ts +15 -0
  419. package/src/shadcn/input-otp/input-otp-group.svelte +20 -0
  420. package/src/shadcn/input-otp/input-otp-separator.svelte +25 -0
  421. package/src/shadcn/input-otp/input-otp-slot.svelte +26 -0
  422. package/src/shadcn/input-otp/input-otp.svelte +22 -0
  423. package/src/shadcn/kbd/index.ts +10 -0
  424. package/src/shadcn/kbd/kbd-group.svelte +20 -0
  425. package/src/shadcn/kbd/kbd.svelte +23 -0
  426. package/src/shadcn/label/index.ts +7 -0
  427. package/src/shadcn/label/label.svelte +20 -0
  428. package/src/shadcn/marker/index.ts +15 -0
  429. package/src/shadcn/marker/marker-content.svelte +23 -0
  430. package/src/shadcn/marker/marker-icon.svelte +21 -0
  431. package/src/shadcn/marker/marker.svelte +52 -0
  432. package/src/shadcn/message/index.ts +22 -0
  433. package/src/shadcn/message/message-avatar.svelte +23 -0
  434. package/src/shadcn/message/message-content.svelte +23 -0
  435. package/src/shadcn/message/message-footer.svelte +23 -0
  436. package/src/shadcn/message/message-group.svelte +20 -0
  437. package/src/shadcn/message/message-header.svelte +23 -0
  438. package/src/shadcn/message/message.svelte +27 -0
  439. package/src/shadcn/message-scroller/index.ts +28 -0
  440. package/src/shadcn/message-scroller/message-scroller-button.svelte +52 -0
  441. package/src/shadcn/message-scroller/message-scroller-content.svelte +17 -0
  442. package/src/shadcn/message-scroller/message-scroller-item.svelte +22 -0
  443. package/src/shadcn/message-scroller/message-scroller-provider.svelte +7 -0
  444. package/src/shadcn/message-scroller/message-scroller-viewport.svelte +20 -0
  445. package/src/shadcn/message-scroller/message-scroller.svelte +20 -0
  446. package/src/shadcn/popover/index.ts +28 -0
  447. package/src/shadcn/popover/popover-close.svelte +7 -0
  448. package/src/shadcn/popover/popover-content.svelte +38 -0
  449. package/src/shadcn/popover/popover-description.svelte +20 -0
  450. package/src/shadcn/popover/popover-header.svelte +20 -0
  451. package/src/shadcn/popover/popover-portal.svelte +7 -0
  452. package/src/shadcn/popover/popover-title.svelte +15 -0
  453. package/src/shadcn/popover/popover-trigger.svelte +17 -0
  454. package/src/shadcn/popover/popover.svelte +7 -0
  455. package/src/shadcn/progress/index.ts +7 -0
  456. package/src/shadcn/progress/progress.svelte +30 -0
  457. package/src/shadcn/radio-group/index.ts +10 -0
  458. package/src/shadcn/radio-group/radio-group-item.svelte +32 -0
  459. package/src/shadcn/radio-group/radio-group.svelte +19 -0
  460. package/src/shadcn/scroll-area/index.ts +10 -0
  461. package/src/shadcn/scroll-area/scroll-area-scrollbar.svelte +30 -0
  462. package/src/shadcn/scroll-area/scroll-area.svelte +43 -0
  463. package/src/shadcn/select/index.ts +37 -0
  464. package/src/shadcn/select/select-content.svelte +45 -0
  465. package/src/shadcn/select/select-group-heading.svelte +21 -0
  466. package/src/shadcn/select/select-group.svelte +17 -0
  467. package/src/shadcn/select/select-item.svelte +38 -0
  468. package/src/shadcn/select/select-label.svelte +20 -0
  469. package/src/shadcn/select/select-portal.svelte +7 -0
  470. package/src/shadcn/select/select-scroll-down-button.svelte +23 -0
  471. package/src/shadcn/select/select-scroll-up-button.svelte +23 -0
  472. package/src/shadcn/select/select-separator.svelte +18 -0
  473. package/src/shadcn/select/select-trigger.svelte +33 -0
  474. package/src/shadcn/select/select.svelte +11 -0
  475. package/src/shadcn/separator/index.ts +7 -0
  476. package/src/shadcn/separator/separator.svelte +23 -0
  477. package/src/shadcn/sheet/index.ts +34 -0
  478. package/src/shadcn/sheet/sheet-close.svelte +7 -0
  479. package/src/shadcn/sheet/sheet-content.svelte +73 -0
  480. package/src/shadcn/sheet/sheet-description.svelte +17 -0
  481. package/src/shadcn/sheet/sheet-footer.svelte +20 -0
  482. package/src/shadcn/sheet/sheet-header.svelte +20 -0
  483. package/src/shadcn/sheet/sheet-overlay.svelte +20 -0
  484. package/src/shadcn/sheet/sheet-portal.svelte +7 -0
  485. package/src/shadcn/sheet/sheet-title.svelte +17 -0
  486. package/src/shadcn/sheet/sheet-trigger.svelte +7 -0
  487. package/src/shadcn/sheet/sheet.css +48 -0
  488. package/src/shadcn/sheet/sheet.svelte +7 -0
  489. package/src/shadcn/sidebar/constants.ts +6 -0
  490. package/src/shadcn/sidebar/context.svelte.ts +81 -0
  491. package/src/shadcn/sidebar/index.ts +75 -0
  492. package/src/shadcn/sidebar/sidebar-content.svelte +24 -0
  493. package/src/shadcn/sidebar/sidebar-footer.svelte +21 -0
  494. package/src/shadcn/sidebar/sidebar-group-action.svelte +33 -0
  495. package/src/shadcn/sidebar/sidebar-group-content.svelte +21 -0
  496. package/src/shadcn/sidebar/sidebar-group-label.svelte +33 -0
  497. package/src/shadcn/sidebar/sidebar-group.svelte +21 -0
  498. package/src/shadcn/sidebar/sidebar-header.svelte +21 -0
  499. package/src/shadcn/sidebar/sidebar-input.svelte +21 -0
  500. package/src/shadcn/sidebar/sidebar-inset.svelte +23 -0
  501. package/src/shadcn/sidebar/sidebar-menu-action.svelte +37 -0
  502. package/src/shadcn/sidebar/sidebar-menu-badge.svelte +24 -0
  503. package/src/shadcn/sidebar/sidebar-menu-button.svelte +103 -0
  504. package/src/shadcn/sidebar/sidebar-menu-item.svelte +21 -0
  505. package/src/shadcn/sidebar/sidebar-menu-skeleton.svelte +36 -0
  506. package/src/shadcn/sidebar/sidebar-menu-sub-button.svelte +39 -0
  507. package/src/shadcn/sidebar/sidebar-menu-sub-item.svelte +21 -0
  508. package/src/shadcn/sidebar/sidebar-menu-sub.svelte +24 -0
  509. package/src/shadcn/sidebar/sidebar-menu.svelte +21 -0
  510. package/src/shadcn/sidebar/sidebar-provider.svelte +62 -0
  511. package/src/shadcn/sidebar/sidebar-rail.svelte +36 -0
  512. package/src/shadcn/sidebar/sidebar-separator.svelte +19 -0
  513. package/src/shadcn/sidebar/sidebar-trigger.svelte +37 -0
  514. package/src/shadcn/sidebar/sidebar.svelte +109 -0
  515. package/src/shadcn/skeleton/index.ts +7 -0
  516. package/src/shadcn/skeleton/skeleton.svelte +17 -0
  517. package/src/shadcn/slider/index.ts +7 -0
  518. package/src/shadcn/slider/slider.svelte +52 -0
  519. package/src/shadcn/sonner/index.ts +1 -0
  520. package/src/shadcn/sonner/sonner.svelte +31 -0
  521. package/src/shadcn/spinner/index.ts +1 -0
  522. package/src/shadcn/spinner/spinner.svelte +26 -0
  523. package/src/shadcn/switch/index.ts +7 -0
  524. package/src/shadcn/switch/switch.svelte +31 -0
  525. package/src/shadcn/table/index.ts +28 -0
  526. package/src/shadcn/table/table-body.svelte +20 -0
  527. package/src/shadcn/table/table-caption.svelte +20 -0
  528. package/src/shadcn/table/table-cell.svelte +20 -0
  529. package/src/shadcn/table/table-footer.svelte +20 -0
  530. package/src/shadcn/table/table-head.svelte +23 -0
  531. package/src/shadcn/table/table-header.svelte +20 -0
  532. package/src/shadcn/table/table-row.svelte +23 -0
  533. package/src/shadcn/table/table.svelte +25 -0
  534. package/src/shadcn/tabs/index.ts +16 -0
  535. package/src/shadcn/tabs/tabs-content.svelte +17 -0
  536. package/src/shadcn/tabs/tabs-list.svelte +36 -0
  537. package/src/shadcn/tabs/tabs-trigger.svelte +20 -0
  538. package/src/shadcn/tabs/tabs.svelte +19 -0
  539. package/src/shadcn/textarea/index.ts +7 -0
  540. package/src/shadcn/textarea/textarea.svelte +23 -0
  541. package/src/shadcn/toggle/index.ts +13 -0
  542. package/src/shadcn/toggle/toggle.svelte +53 -0
  543. package/src/shadcn/toggle-group/index.ts +10 -0
  544. package/src/shadcn/toggle-group/toggle-group-item.svelte +35 -0
  545. package/src/shadcn/toggle-group/toggle-group.svelte +66 -0
  546. package/src/shadcn/tooltip/context.ts +16 -0
  547. package/src/shadcn/tooltip/index.ts +19 -0
  548. package/src/shadcn/tooltip/tooltip-content.svelte +38 -0
  549. package/src/shadcn/tooltip/tooltip-portal.svelte +7 -0
  550. package/src/shadcn/tooltip/tooltip-provider.svelte +16 -0
  551. package/src/shadcn/tooltip/tooltip-trigger.svelte +7 -0
  552. package/src/shadcn/tooltip/tooltip.svelte +19 -0
  553. package/src/shadcn/trace/index.ts +29 -0
  554. package/src/shadcn/trace/trace-collapsible-content.svelte +29 -0
  555. package/src/shadcn/trace/trace-collapsible-trigger.svelte +29 -0
  556. package/src/shadcn/trace/trace-collapsible.svelte +20 -0
  557. package/src/shadcn/trace/trace-description.svelte +20 -0
  558. package/src/shadcn/trace/trace-icon.svelte +24 -0
  559. package/src/shadcn/trace/trace-line.svelte +31 -0
  560. package/src/shadcn/trace/trace-title.svelte +20 -0
  561. package/src/shadcn/trace/trace.svelte +23 -0
  562. package/src/shadcn/utilities.css +549 -0
  563. package/src/test-setup.ts +34 -0
  564. package/src/tokens.css +993 -0
@@ -0,0 +1,159 @@
1
+ /* The rules the craft layer applies for itself.
2
+ *
3
+ * Two layers, on purpose. `base` holds the element defaults (focus, selection,
4
+ * scrollbars) so any component class or utility beats them. `components` holds
5
+ * the three motion primitives, so a utility still beats those too.
6
+ *
7
+ * WHY the layers are not optional: an `@import` at the top of an app stylesheet
8
+ * lands OUTSIDE Tailwind's layers, and unlayered CSS beats every layered rule
9
+ * whatever its specificity. Written bare, a `:where()` selector here would
10
+ * silently outrank `focus-visible:ring-3` on every control in the app.
11
+ *
12
+ * Imported by ./index.css. Do not import it on its own, because it reads the tokens
13
+ * that file declares. */
14
+
15
+ @layer base {
16
+ /* One ring for the whole kit. `:where` keeps it at specificity zero on top of
17
+ the layer, so a control that needs a different ring writes one and wins. */
18
+ :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
19
+ outline: none;
20
+ box-shadow: var(--ring-focus);
21
+ }
22
+
23
+ /* The accent at a low alpha, not the browser blue, because a selected word is
24
+ the one moment the palette shows up inside running text. */
25
+ ::selection {
26
+ background: color-mix(in oklab, var(--ring-color) 24%, transparent);
27
+ }
28
+
29
+ /* A default macOS overlay scrollbar paints a black bar on a dark panel. Track
30
+ transparent, thumb on the line token, so it belongs to whatever surface it
31
+ is over. The border is what insets the thumb without a second element. */
32
+ :where(html) {
33
+ scrollbar-color: var(--color-border, var(--border)) transparent;
34
+ }
35
+
36
+ ::-webkit-scrollbar {
37
+ width: 10px;
38
+ height: 10px;
39
+ }
40
+
41
+ ::-webkit-scrollbar-track {
42
+ background: transparent;
43
+ }
44
+
45
+ ::-webkit-scrollbar-thumb {
46
+ border: 3px solid transparent;
47
+ background-clip: padding-box;
48
+ border-radius: 999px;
49
+ background-color: var(--color-border, var(--border));
50
+ }
51
+
52
+ ::-webkit-scrollbar-thumb:hover {
53
+ background-color: var(--color-muted-foreground, var(--muted-foreground));
54
+ }
55
+ }
56
+
57
+ @layer components {
58
+ /* Three moves the kit repeats. They are classes rather than tokens because a
59
+ component wants one name, not four declarations, and because the reduced
60
+ motion guard then lives in one place instead of in every component.
61
+
62
+ Namespaced `t-` to match the transitions-dev snippets, which these sit
63
+ beside rather than duplicate. */
64
+
65
+ /* A control that reads as a key: it travels down a pixel under the finger.
66
+ The travel is what sells it, because a colour change alone reads as a hover
67
+ state, not as a press. */
68
+ .t-press {
69
+ transition:
70
+ background-color var(--duration-quick) var(--ease-smooth-out),
71
+ border-color var(--duration-quick) var(--ease-smooth-out),
72
+ color var(--duration-quick) var(--ease-smooth-out),
73
+ box-shadow var(--duration-quick) var(--ease-smooth-out),
74
+ transform var(--duration-micro) var(--ease-smooth-out);
75
+ }
76
+
77
+ .t-press:active:not(:disabled, [aria-disabled="true"]) {
78
+ transform: translateY(1px);
79
+ }
80
+
81
+ /* A card that answers the pointer. It rises by a pixel and gains the next
82
+ step of elevation, so the hover reads as the card coming forward rather
83
+ than as its border changing colour. */
84
+ .t-lift {
85
+ transition:
86
+ box-shadow var(--duration-fast) var(--ease-smooth-out),
87
+ transform var(--duration-fast) var(--ease-smooth-out);
88
+ }
89
+
90
+ .t-lift:hover {
91
+ transform: translateY(-1px);
92
+ box-shadow: var(--elev-raised);
93
+ }
94
+
95
+ /* A surface arriving. The open carries the distance, the scale and the blur;
96
+ the close drops all three and takes less time, per the open/close
97
+ asymmetry rule in transitions-dev. */
98
+ .t-enter {
99
+ animation: t-enter var(--duration-fast) var(--ease-smooth-out) both;
100
+ }
101
+
102
+ .t-exit {
103
+ animation: t-exit var(--duration-quick) var(--ease-smooth-out) both;
104
+ }
105
+
106
+ @media (prefers-reduced-motion: reduce) {
107
+ .t-press,
108
+ .t-lift {
109
+ transition: none;
110
+ }
111
+
112
+ .t-press:active,
113
+ .t-lift:hover {
114
+ transform: none;
115
+ }
116
+
117
+ .t-enter,
118
+ .t-exit {
119
+ animation-duration: 1ms;
120
+ }
121
+ }
122
+ }
123
+
124
+ @keyframes t-enter {
125
+ from {
126
+ opacity: 0;
127
+ transform: translateY(var(--distance-micro)) scale(var(--scale-medium));
128
+ filter: blur(var(--blur-small));
129
+ }
130
+ to {
131
+ opacity: 1;
132
+ transform: none;
133
+ filter: none;
134
+ }
135
+ }
136
+
137
+ /* A mark confirming a state that has already changed: it arrives after the box
138
+ it sits in, so it overshoots slightly instead of fading. */
139
+ @keyframes t-check {
140
+ from {
141
+ opacity: 0;
142
+ transform: scale(0.4);
143
+ }
144
+ to {
145
+ opacity: 1;
146
+ transform: scale(1);
147
+ }
148
+ }
149
+
150
+ @keyframes t-exit {
151
+ from {
152
+ opacity: 1;
153
+ transform: none;
154
+ }
155
+ to {
156
+ opacity: 0;
157
+ transform: scale(var(--scale-tiny));
158
+ }
159
+ }
@@ -0,0 +1,132 @@
1
+ <script lang="ts" module>
2
+ import type { AnimatedBeamProps } from "./types.js";
3
+ </script>
4
+
5
+ <script lang="ts">
6
+ // =========================
7
+ // IMPORTS
8
+ // =========================
9
+ import { cn } from "@heyramzi/utils";
10
+ import BeamSvg from "./diagrams/BeamSvg.svelte";
11
+ import { usePathCalculator } from "./path-calculator.svelte.js";
12
+
13
+ // =========================
14
+ // PROPS
15
+ // =========================
16
+ let {
17
+ class: className,
18
+ containerRef,
19
+ fromRef,
20
+ toRef,
21
+ curvature = 0,
22
+ reverse = false,
23
+ duration = 4,
24
+ delay = 0,
25
+ pathColor = "gray",
26
+ pathWidth = 2,
27
+ pathOpacity = 0.2,
28
+ gradientStartColor = "#ffaa40",
29
+ gradientStopColor = "#414fd2",
30
+ startXOffset = 0,
31
+ startYOffset = 0,
32
+ endXOffset = 0,
33
+ endYOffset = 0,
34
+ fromAnchor = "center",
35
+ toAnchor = "center",
36
+ }: AnimatedBeamProps = $props();
37
+
38
+ // =========================
39
+ // STATE
40
+ // =========================
41
+ const id = `beam-${Math.random().toString(36).slice(2, 10)}`;
42
+ const path = usePathCalculator();
43
+ let motionOK = $state(true);
44
+
45
+ // ========================= DERIVED ========================= WHY: a short bright band (the stops) is swept along the path by animating the
46
+
47
+ // gradient vector. forward runs the comet from start to end, reverse the other way.
48
+
49
+ // Same coordinate pairs the motion-sv version used, as SMIL value lists, so no animation runtime is pulled into the dependency-free package.
50
+ const coords = $derived(
51
+ reverse ? { x1: "90%;-10%", x2: "100%;0%" } : { x1: "10%;110%", x2: "0%;100%" },
52
+ );
53
+
54
+ // =========================
55
+ // FUNCTIONS
56
+ // =========================
57
+ function updatePath() {
58
+ path.calculatePath(
59
+ containerRef,
60
+ fromRef,
61
+ toRef,
62
+ curvature,
63
+ startXOffset,
64
+ startYOffset,
65
+ endXOffset,
66
+ endYOffset,
67
+ fromAnchor,
68
+ toAnchor,
69
+ );
70
+ }
71
+
72
+ // =========================
73
+ // EFFECTS
74
+ // =========================
75
+ $effect(() => {
76
+ // WHY: touch every geometry input so the path recomputes when a ref,
77
+ // anchor, or offset changes, not just on container resize.
78
+ void [
79
+ containerRef,
80
+ fromRef,
81
+ toRef,
82
+ curvature,
83
+ startXOffset,
84
+ startYOffset,
85
+ endXOffset,
86
+ endYOffset,
87
+ fromAnchor,
88
+ toAnchor,
89
+ ];
90
+ updatePath();
91
+ if (!containerRef) return;
92
+ let raf = 0;
93
+ const ro = new ResizeObserver(() => {
94
+ cancelAnimationFrame(raf);
95
+ raf = requestAnimationFrame(updatePath);
96
+ });
97
+ ro.observe(containerRef);
98
+ return () => {
99
+ cancelAnimationFrame(raf);
100
+ ro.disconnect();
101
+ };
102
+ });
103
+
104
+ $effect(() => {
105
+ if (typeof window === "undefined") return;
106
+ const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
107
+ motionOK = !mq.matches;
108
+ const onChange = () => (motionOK = !mq.matches);
109
+ mq.addEventListener("change", onChange);
110
+ return () => mq.removeEventListener("change", onChange);
111
+ });
112
+ </script>
113
+
114
+ <!-- =========================== -->
115
+ <!-- MARKUP -->
116
+ <!-- =========================== -->
117
+ <BeamSvg
118
+ {id}
119
+ class={cn("pointer-events-none absolute left-0 top-0 transform-gpu stroke-2", className)}
120
+ width={path.svgDimensions.width}
121
+ height={path.svgDimensions.height}
122
+ pathD={path.pathD}
123
+ {pathColor}
124
+ {pathWidth}
125
+ {pathOpacity}
126
+ {motionOK}
127
+ {coords}
128
+ {duration}
129
+ {delay}
130
+ {gradientStartColor}
131
+ {gradientStopColor}
132
+ />
@@ -0,0 +1,91 @@
1
+ <script lang="ts">
2
+ // =========================
3
+ // PROPS
4
+ // =========================
5
+ type Props = {
6
+ id: string;
7
+ class?: string;
8
+ width: number;
9
+ height: number;
10
+ pathD: string;
11
+ pathColor: string;
12
+ pathWidth: number;
13
+ pathOpacity: number;
14
+ motionOK: boolean;
15
+ coords: { x1: string; x2: string };
16
+ duration: number;
17
+ delay: number;
18
+ gradientStartColor: string;
19
+ gradientStopColor: string;
20
+ };
21
+ let {
22
+ id,
23
+ class: className,
24
+ width,
25
+ height,
26
+ pathD,
27
+ pathColor,
28
+ pathWidth,
29
+ pathOpacity,
30
+ motionOK,
31
+ coords,
32
+ duration,
33
+ delay,
34
+ gradientStartColor,
35
+ gradientStopColor,
36
+ }: Props = $props();
37
+ </script>
38
+
39
+ <svg
40
+ fill="none"
41
+ {width}
42
+ {height}
43
+ xmlns="http://www.w3.org/2000/svg"
44
+ class={className}
45
+ viewBox="0 0 {width} {height}"
46
+ >
47
+ <path
48
+ d={pathD}
49
+ stroke={pathColor}
50
+ stroke-width={pathWidth}
51
+ stroke-opacity={pathOpacity}
52
+ stroke-linecap="round"
53
+ />
54
+ {#if motionOK}
55
+ <path
56
+ d={pathD}
57
+ stroke-width={pathWidth}
58
+ stroke={`url(#${id})`}
59
+ stroke-opacity="1"
60
+ stroke-linecap="round"
61
+ />
62
+ <defs>
63
+ <linearGradient {id} gradientUnits="userSpaceOnUse" x1="0%" x2="0%" y1="0%" y2="0%">
64
+ <animate
65
+ attributeName="x1"
66
+ values={coords.x1}
67
+ dur="{duration}s"
68
+ begin="{delay}s"
69
+ calcMode="spline"
70
+ keyTimes="0;1"
71
+ keySplines="0.16 1 0.3 1"
72
+ repeatCount="indefinite"
73
+ />
74
+ <animate
75
+ attributeName="x2"
76
+ values={coords.x2}
77
+ dur="{duration}s"
78
+ begin="{delay}s"
79
+ calcMode="spline"
80
+ keyTimes="0;1"
81
+ keySplines="0.16 1 0.3 1"
82
+ repeatCount="indefinite"
83
+ />
84
+ <stop stop-color={gradientStartColor} stop-opacity="0"></stop>
85
+ <stop stop-color={gradientStartColor}></stop>
86
+ <stop offset="32.5%" stop-color={gradientStopColor}></stop>
87
+ <stop offset="100%" stop-color={gradientStopColor} stop-opacity="0"></stop>
88
+ </linearGradient>
89
+ </defs>
90
+ {/if}
91
+ </svg>
@@ -0,0 +1,2 @@
1
+ export { default as AnimatedBeam } from "./AnimatedBeam.svelte";
2
+ export type { AnimatedBeamProps, AnchorPosition } from "./types.js";
@@ -0,0 +1,70 @@
1
+ import type { AnchorPosition } from "./types.js";
2
+
3
+ function anchorX(
4
+ rect: DOMRect,
5
+ containerLeft: number,
6
+ anchor: AnchorPosition,
7
+ offset: number,
8
+ ): number {
9
+ const left = rect.left - containerLeft;
10
+ if (anchor === "left") return left + offset;
11
+ if (anchor === "right") return left + rect.width + offset;
12
+ return left + rect.width / 2 + offset;
13
+ }
14
+
15
+ export function usePathCalculator() {
16
+ let pathD = $state("");
17
+ let svgDimensions = $state({ width: 0, height: 0 });
18
+
19
+ function calculatePath(
20
+ containerRef: HTMLElement | null,
21
+ fromRef: HTMLElement | null,
22
+ toRef: HTMLElement | null,
23
+ curvature: number,
24
+ startXOffset: number,
25
+ startYOffset: number,
26
+ endXOffset: number,
27
+ endYOffset: number,
28
+ fromAnchor: AnchorPosition = "center",
29
+ toAnchor: AnchorPosition = "center",
30
+ ) {
31
+ if (!containerRef || !fromRef || !toRef) return;
32
+
33
+ const containerRect = containerRef.getBoundingClientRect();
34
+ const rectA = fromRef.getBoundingClientRect();
35
+ const rectB = toRef.getBoundingClientRect();
36
+
37
+ svgDimensions = { width: containerRect.width, height: containerRect.height };
38
+
39
+ const startX = anchorX(rectA, containerRect.left, fromAnchor, startXOffset);
40
+ const startY = rectA.top - containerRect.top + rectA.height / 2 + startYOffset;
41
+ const endX = anchorX(rectB, containerRect.left, toAnchor, endXOffset);
42
+ const endY = rectB.top - containerRect.top + rectB.height / 2 + endYOffset;
43
+
44
+ // A cubic with horizontal handles, not a quadratic through a raised midpoint.
45
+
46
+ // The quadratic put its single control point at `midY - curvature`, which for a fan into one node lands past the far end:
47
+
48
+ // the top beam dove below the hub and crossed the middle beam before arriving, and three beams bundled into a lens for the last stretch.
49
+
50
+ // Handles along the axis of travel make each beam leave and arrive perpendicular to its anchor, so a fan converges at the anchor and nowhere else.
51
+
52
+ // `curvature` still bows the middle, and zero still draws a straight line between two anchors at the same height.
53
+ const span = Math.abs(endX - startX);
54
+ const handle = Math.max(span * 0.5, 24);
55
+ const direction = endX >= startX ? 1 : -1;
56
+ const c1x = startX + handle * direction;
57
+ const c2x = endX - handle * direction;
58
+ pathD = `M ${startX},${startY} C ${c1x},${startY - curvature} ${c2x},${endY - curvature} ${endX},${endY}`;
59
+ }
60
+
61
+ return {
62
+ get pathD() {
63
+ return pathD;
64
+ },
65
+ get svgDimensions() {
66
+ return svgDimensions;
67
+ },
68
+ calculatePath,
69
+ };
70
+ }
@@ -0,0 +1,23 @@
1
+ export type AnchorPosition = "center" | "left" | "right";
2
+
3
+ export interface AnimatedBeamProps {
4
+ class?: string;
5
+ containerRef: HTMLElement | null;
6
+ fromRef: HTMLElement | null;
7
+ toRef: HTMLElement | null;
8
+ curvature?: number;
9
+ reverse?: boolean;
10
+ pathColor?: string;
11
+ pathWidth?: number;
12
+ pathOpacity?: number;
13
+ gradientStartColor?: string;
14
+ gradientStopColor?: string;
15
+ delay?: number;
16
+ duration?: number;
17
+ startXOffset?: number;
18
+ startYOffset?: number;
19
+ endXOffset?: number;
20
+ endYOffset?: number;
21
+ fromAnchor?: AnchorPosition;
22
+ toAnchor?: AnchorPosition;
23
+ }
@@ -0,0 +1,223 @@
1
+ <script lang="ts" module>
2
+ import type { ResolvedTheme } from "./presets.js";
3
+ import type { BorderBeamProps } from "./types.js";
4
+ </script>
5
+
6
+ <script lang="ts">
7
+ // IMPORTS
8
+ import { onDestroy, onMount } from "svelte";
9
+ import { generateCss } from "./css.js";
10
+ import { sizePresets, sizeThemePresets } from "./presets.js";
11
+ import { registerBorderBeamProperties } from "./register-properties.js";
12
+
13
+ // PROPS
14
+ let {
15
+ children,
16
+ size = "md",
17
+ colorVariant = "colorful",
18
+ theme = "dark",
19
+ staticColors = false,
20
+ duration,
21
+ active = true,
22
+ borderRadius,
23
+ brightness = 1.3,
24
+ saturation,
25
+ hueRange = 30,
26
+ strength = 1,
27
+ colors,
28
+ bloom = true,
29
+ pauseWhenOffscreen = true,
30
+ class: className,
31
+ onActivate,
32
+ onDeactivate,
33
+ onanimationend: userAnimationEnd,
34
+ style: userStyle,
35
+ ...rest
36
+ }: BorderBeamProps = $props();
37
+
38
+ // STATE
39
+ const uid = `bb-${Math.random().toString(36).slice(2, 10)}`;
40
+ let container = $state<HTMLElement | null>(null);
41
+ let systemTheme = $state<ResolvedTheme>("dark");
42
+ let isActive = $state(false);
43
+ let isFading = $state(false);
44
+ let detectedRadius = $state<number | null>(null);
45
+ let isOffscreen = $state(false);
46
+ let isDocHidden = $state(false);
47
+
48
+ // DERIVED
49
+ const resolvedTheme = $derived(theme === "auto" ? systemTheme : theme);
50
+ const sizeConfig = $derived(sizePresets[size]);
51
+ const themeColorsForSize = $derived(sizeThemePresets[size][resolvedTheme]);
52
+ const effectiveRadius = $derived(borderRadius ?? detectedRadius ?? sizeConfig.borderRadius);
53
+ const effectiveDuration = $derived(duration ?? (size === "line" ? 2.4 : 1.96));
54
+ const effectiveSaturation = $derived(saturation ?? themeColorsForSize.saturation);
55
+ const effectiveHueRange = $derived(size === "line" ? Math.min(hueRange, 13) : hueRange);
56
+ const resolvedStatic = $derived(colorVariant === "mono" ? true : staticColors);
57
+
58
+ const css = $derived(
59
+ generateCss({
60
+ id: uid,
61
+ borderRadius: effectiveRadius,
62
+ borderWidth: sizeConfig.borderWidth,
63
+ duration: effectiveDuration,
64
+ strokeOpacity: themeColorsForSize.strokeOpacity,
65
+ innerOpacity: themeColorsForSize.innerOpacity,
66
+ bloomOpacity: themeColorsForSize.bloomOpacity,
67
+ innerShadow: themeColorsForSize.innerShadow,
68
+ size,
69
+ colorVariant,
70
+ staticColors: resolvedStatic,
71
+ brightness,
72
+ saturation: effectiveSaturation,
73
+ hueRange: effectiveHueRange,
74
+ theme: resolvedTheme,
75
+ colors,
76
+ bloom,
77
+ }),
78
+ );
79
+
80
+ // WHY: paused state combines viewport visibility and document visibility.
81
+ // Either being false freezes the beam via `animation-play-state: paused`.
82
+ const paused = $derived(pauseWhenOffscreen && (isOffscreen || isDocHidden));
83
+
84
+ const clampedStrength = $derived(Math.max(0, Math.min(1, strength)));
85
+
86
+ // EFFECTS
87
+ let mediaQuery: MediaQueryList | null = null;
88
+ let radiusObserver: MutationObserver | null = null;
89
+ let visibilityObserver: IntersectionObserver | null = null;
90
+
91
+ onMount(() => {
92
+ // WHY: shadow-DOM consumers (chrome extensions, embedded widgets) hit a Chromium edge case where @property at-rules emitted in an injected stylesheet do not register reliably for the shadow scope.
93
+
94
+ // Without the registration, the angle property is treated as a string, the keyframe can't interpolate, and the beam appears frozen with one repaint per iteration.
95
+
96
+ // CSS.registerProperty is global and document-scoped so it always succeeds, and duplicate registrations are silently ignored.
97
+ registerBorderBeamProperties(uid, size);
98
+
99
+ if (typeof window !== "undefined") {
100
+ mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
101
+ systemTheme = mediaQuery.matches ? "dark" : "light";
102
+ const handler = (e: MediaQueryListEvent) => {
103
+ systemTheme = e.matches ? "dark" : "light";
104
+ };
105
+ mediaQuery.addEventListener("change", handler);
106
+ return () => mediaQuery?.removeEventListener("change", handler);
107
+ }
108
+ });
109
+
110
+ $effect(() => {
111
+ if (borderRadius != null || !container) return;
112
+ const detect = () => {
113
+ const first = container?.firstElementChild as HTMLElement | null;
114
+ if (!first) return;
115
+ const cs = getComputedStyle(first);
116
+ const r = parseFloat(cs.borderTopLeftRadius);
117
+ if (!isNaN(r) && r > 0) detectedRadius = r;
118
+ };
119
+ detect();
120
+ radiusObserver = new MutationObserver(detect);
121
+ radiusObserver.observe(container, { childList: true, subtree: false });
122
+ return () => radiusObserver?.disconnect();
123
+ });
124
+
125
+ $effect(() => {
126
+ if (active && !isActive && !isFading) {
127
+ isActive = true;
128
+ } else if (!active && isActive && !isFading) {
129
+ isFading = true;
130
+ }
131
+ });
132
+
133
+ // WHY: pause beam animation while the host is offscreen or the tab is hidden.
134
+
135
+ // CSS animations keep ticking on backgrounded tabs in some browsers, and an offscreen beam burns rasterization budget for nothing.
136
+ $effect(() => {
137
+ if (!pauseWhenOffscreen || !container || typeof window === "undefined") return;
138
+
139
+ visibilityObserver = new IntersectionObserver(
140
+ (entries) => {
141
+ const entry = entries[0];
142
+ if (entry) isOffscreen = !entry.isIntersecting;
143
+ },
144
+ { rootMargin: "64px" },
145
+ );
146
+ visibilityObserver.observe(container);
147
+
148
+ const onVisChange = () => {
149
+ isDocHidden = document.hidden;
150
+ };
151
+ isDocHidden = document.hidden;
152
+ document.addEventListener("visibilitychange", onVisChange);
153
+
154
+ return () => {
155
+ visibilityObserver?.disconnect();
156
+ visibilityObserver = null;
157
+ document.removeEventListener("visibilitychange", onVisChange);
158
+ };
159
+ });
160
+
161
+ onDestroy(() => {
162
+ mediaQuery = null;
163
+ radiusObserver?.disconnect();
164
+ visibilityObserver?.disconnect();
165
+ });
166
+
167
+ // FUNCTIONS
168
+ function handleAnimationEnd(e: AnimationEvent) {
169
+ const name = e.animationName;
170
+ if (name.includes("fade-out")) {
171
+ isActive = false;
172
+ isFading = false;
173
+ onDeactivate?.();
174
+ } else if (name.includes("fade-in")) {
175
+ onActivate?.();
176
+ }
177
+ userAnimationEnd?.(e as AnimationEvent & { currentTarget: EventTarget & HTMLDivElement });
178
+ }
179
+
180
+ // WHY: imperative CSS injection via Svelte action. The rolldown-based
181
+
182
+ // vite-plugin-svelte preprocessor does naive substring matching for the stylesheet markup, so an inline @html template literal containing the markup tag would trip postcss on the interpolated text.
183
+
184
+ // The action route attaches a real stylesheet node next to the host, bypassing the HTML parser entirely.
185
+ function injectStyle(node: Element, value: string) {
186
+ const styleEl = node.ownerDocument.createElement("style");
187
+ styleEl.textContent = value;
188
+ node.parentNode?.insertBefore(styleEl, node);
189
+ // WHY: $derived recomputes on any prop change, but the CSS string is
190
+ // often identical across reruns. Skip the DOM write so the browser
191
+ // doesn't re-parse the stylesheet for no reason.
192
+ let last = value;
193
+ return {
194
+ update(next: string) {
195
+ if (next === last) return;
196
+ last = next;
197
+ styleEl.textContent = next;
198
+ },
199
+ destroy() {
200
+ styleEl.remove();
201
+ },
202
+ };
203
+ }
204
+ </script>
205
+
206
+ <!-- MARKUP -->
207
+ <div
208
+ bind:this={container}
209
+ {...rest}
210
+ data-beam={uid}
211
+ data-active={isActive && !isFading ? "" : undefined}
212
+ data-fading={isFading ? "" : undefined}
213
+ data-paused={paused ? "" : undefined}
214
+ class={className}
215
+ style="--beam-strength: {clampedStrength};{userStyle ?? ''}"
216
+ onanimationend={handleAnimationEnd}
217
+ use:injectStyle={css}
218
+ >
219
+ {@render children()}
220
+ {#if bloom}
221
+ <div data-beam-bloom></div>
222
+ {/if}
223
+ </div>