@heyramzi/ui 6.1.0 → 8.0.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 (332) hide show
  1. package/COMPONENTS.md +32 -40
  2. package/README.md +10 -4
  3. package/package.json +31 -29
  4. package/scripts/sync-shadcn.mjs +29 -16
  5. package/scripts/sync-transitions.mjs +11 -11
  6. package/src/ai/ai-button/AiButton.svelte +86 -0
  7. package/src/ai/ai-button/index.ts +4 -0
  8. package/src/ai/confirmation/Confirmation.svelte +8 -8
  9. package/src/ai/confirmation/confirmation-context.svelte.ts +2 -2
  10. package/src/ai/generation-progress/GenerationProgress.svelte +354 -0
  11. package/src/ai/generation-progress/index.ts +7 -0
  12. package/src/ai/index.ts +16 -24
  13. package/src/ai/prompt-input/PromptInput.svelte +19 -1
  14. package/src/ai/prompt-input/PromptInputSubmit.svelte +9 -3
  15. package/src/ai/reasoning/Reasoning.svelte +11 -8
  16. package/src/ambient.d.ts +4 -0
  17. package/src/animations/README.md +17 -17
  18. package/src/animations/index.css +3 -14
  19. package/src/animations/upstream-coverage.test.ts +1 -1
  20. package/src/components/copy/clipboard.test.ts +206 -0
  21. package/src/components/copy/clipboard.ts +49 -0
  22. package/src/components/copy/copied.svelte.ts +39 -0
  23. package/src/components/copy/copy-button.svelte +175 -0
  24. package/src/components/copy/copy-button.test.ts +110 -0
  25. package/src/components/copy/index.ts +3 -0
  26. package/src/components/data-table/data-table.test.ts +134 -0
  27. package/src/components/data-table/data-table.ts +77 -0
  28. package/src/components/data-table/index.ts +20 -0
  29. package/src/components/data-table/infinite-scroll.svelte +69 -0
  30. package/src/components/data-table/pagination.svelte +62 -0
  31. package/src/components/data-table/row-arrow.svelte +28 -0
  32. package/src/components/data-table/row-context-menu.svelte +106 -0
  33. package/src/components/data-table/row-context-menu.test.ts +18 -0
  34. package/src/components/data-table/sortable-head.svelte +56 -0
  35. package/src/components/data-table/table-skeleton.svelte +83 -0
  36. package/src/components/hold-to-confirm/hold-to-confirm.svelte +232 -0
  37. package/src/components/hold-to-confirm/index.ts +1 -0
  38. package/src/components/icon/icon.svelte +23 -0
  39. package/src/components/icon/index.ts +1 -0
  40. package/src/components/language-flag/index.ts +1 -0
  41. package/src/components/language-flag/language-flag.svelte +60 -0
  42. package/src/components/list-page/detail-empty.svelte +50 -0
  43. package/src/components/list-page/detail-header.svelte +107 -0
  44. package/src/components/list-page/detail-panel.svelte +90 -0
  45. package/src/components/list-page/detail-row.svelte +36 -0
  46. package/src/components/list-page/detail-stack.svelte +33 -0
  47. package/src/components/list-page/empty-state.svelte +91 -0
  48. package/src/components/list-page/filter-item.svelte +49 -0
  49. package/src/components/list-page/filter-popover.svelte +88 -0
  50. package/src/components/list-page/filter-section.ts +12 -0
  51. package/src/components/list-page/grouped-list.svelte +116 -0
  52. package/src/components/list-page/index.ts +28 -0
  53. package/src/components/list-page/list-page-shell.svelte +195 -0
  54. package/src/components/list-page/list-table.ts +19 -0
  55. package/src/components/list-page/master-detail.svelte +206 -0
  56. package/src/components/list-page/master-detail.test.ts +37 -0
  57. package/src/components/list-page/notice-bar.svelte +68 -0
  58. package/src/components/list-page/prev-next.svelte +104 -0
  59. package/src/components/list-page/queue-rail.ts +25 -0
  60. package/src/components/list-page/rail-body.svelte +29 -0
  61. package/src/components/list-page/rail-empty.svelte +51 -0
  62. package/src/components/list-page/rail-head.svelte +49 -0
  63. package/src/components/list-page/rail-row.svelte +163 -0
  64. package/src/components/list-page/section-host.ts +24 -0
  65. package/src/components/list-page/section-label.svelte +39 -0
  66. package/src/components/list-page/step.test.ts +21 -0
  67. package/src/components/list-page/step.ts +10 -0
  68. package/src/components/list-page/toolbar-search.svelte +63 -0
  69. package/src/components/list-page/toolbar-trigger.ts +23 -0
  70. package/src/components/list-page/types.ts +1 -0
  71. package/src/components/locale-switch/index.ts +1 -0
  72. package/src/components/locale-switch/locale-switch.svelte +59 -0
  73. package/src/components/mark/index.ts +1 -0
  74. package/src/components/mark/mark.svelte +70 -0
  75. package/src/components/open-in/index.ts +6 -0
  76. package/src/components/open-in/open-in.svelte +106 -0
  77. package/src/components/picker/index.ts +4 -0
  78. package/src/components/picker/mark-picker.svelte +84 -0
  79. package/src/components/picker/picker.svelte +143 -0
  80. package/src/components/picker/trigger.ts +42 -0
  81. package/src/components/picker/types.ts +26 -0
  82. package/src/components/segmented/animated-tabs.svelte +175 -0
  83. package/src/components/segmented/collapse.test.ts +49 -0
  84. package/src/components/segmented/collapse.ts +39 -0
  85. package/src/components/segmented/index.ts +41 -0
  86. package/src/components/segmented/section-runs.svelte +79 -0
  87. package/src/components/segmented/segment.svelte +106 -0
  88. package/src/components/segmented/segmented-filter.svelte +125 -0
  89. package/src/components/segmented/segmented-nav.svelte +82 -0
  90. package/src/components/segmented/segmented-overflow.svelte +85 -0
  91. package/src/components/segmented/segmented-track.svelte +181 -0
  92. package/src/components/segmented/segmented.test.ts +20 -0
  93. package/src/components/segmented/segmented.ts +80 -0
  94. package/src/components/star-rating-input/index.ts +9 -0
  95. package/src/components/star-rating-input/star-rating-input.svelte +256 -0
  96. package/src/components/svg/index.ts +1 -0
  97. package/src/components/svg/svg.svelte +9 -0
  98. package/src/effects/border-beam/BorderBeam.svelte +1 -1
  99. package/src/effects/image-comparison/ImageComparison.css +42 -8
  100. package/src/effects/image-comparison/ImageComparison.svelte +138 -21
  101. package/src/effects/image-comparison/compare.test.ts +17 -0
  102. package/src/effects/image-comparison/compare.ts +5 -0
  103. package/src/effects/interactive-hover-button/InteractiveHoverButton.svelte +338 -0
  104. package/src/effects/magic-card/MagicCard.css +47 -0
  105. package/src/effects/magic-card/MagicCard.svelte +57 -0
  106. package/src/effects/marquee/Marquee.css +27 -1
  107. package/src/effects/marquee/Marquee.svelte +67 -3
  108. package/src/effects/reveal/index.ts +2 -1
  109. package/src/effects/reveal/observe.test.ts +60 -0
  110. package/src/effects/reveal/observe.ts +33 -1
  111. package/src/effects/reveal/types.ts +7 -0
  112. package/src/effects/theme-toggle/ThemeToggle.css +199 -6
  113. package/src/effects/theme-toggle/ThemeToggle.svelte +51 -26
  114. package/src/gallery.test.ts +52 -0
  115. package/src/index.ts +5 -1
  116. package/src/lib/panel.ts +7 -1
  117. package/src/lib/sliding-pill.ts +68 -0
  118. package/src/lib/theme-transition.ts +41 -13
  119. package/src/lib/tone.ts +48 -0
  120. package/src/shadcn/accordion/accordion-trigger.svelte +15 -6
  121. package/src/shadcn/alert/alert.svelte +3 -1
  122. package/src/shadcn/badge/badge.svelte +8 -7
  123. package/src/shadcn/breadcrumb/breadcrumb-ellipsis.svelte +2 -2
  124. package/src/shadcn/breadcrumb/breadcrumb-separator.svelte +2 -2
  125. package/src/shadcn/calendar/calendar-month-select.svelte +2 -2
  126. package/src/shadcn/calendar/calendar-next-button.svelte +2 -2
  127. package/src/shadcn/calendar/calendar-prev-button.svelte +2 -2
  128. package/src/shadcn/calendar/calendar-year-select.svelte +2 -2
  129. package/src/shadcn/calendar/calendar.svelte +6 -0
  130. package/src/shadcn/code-block/code-block-actions.svelte +23 -0
  131. package/src/shadcn/code-block/code-block-content.svelte +55 -0
  132. package/src/shadcn/code-block/code-block-copy-button.svelte +10 -0
  133. package/src/shadcn/code-block/code-block-footer.svelte +20 -0
  134. package/src/shadcn/code-block/code-block-header.svelte +23 -0
  135. package/src/shadcn/code-block/code-block-line.svelte +71 -0
  136. package/src/shadcn/code-block/code-block-title.svelte +23 -0
  137. package/src/shadcn/code-block/code-block.svelte +47 -0
  138. package/src/shadcn/code-block/index.ts +42 -0
  139. package/src/shadcn/command/index.ts +3 -0
  140. package/src/shadcn/field/index.ts +3 -0
  141. package/src/shadcn/field/simple-field.svelte +71 -0
  142. package/src/shadcn/field/simple-field.test.ts +47 -0
  143. package/src/shadcn/hooks/highlighter.ts +132 -0
  144. package/src/shadcn/hooks/use-highlighted-code.svelte.ts +98 -0
  145. package/src/shadcn/kbd/index.ts +10 -0
  146. package/src/shadcn/kbd/kbd-group.svelte +20 -0
  147. package/src/shadcn/kbd/kbd.svelte +23 -0
  148. package/src/shadcn/message-scroller/index.ts +28 -0
  149. package/src/shadcn/message-scroller/message-scroller-button.svelte +52 -0
  150. package/src/shadcn/message-scroller/message-scroller-content.svelte +17 -0
  151. package/src/shadcn/message-scroller/message-scroller-item.svelte +22 -0
  152. package/src/shadcn/message-scroller/message-scroller-provider.svelte +7 -0
  153. package/src/shadcn/message-scroller/message-scroller-viewport.svelte +20 -0
  154. package/src/shadcn/message-scroller/message-scroller.svelte +20 -0
  155. package/src/shadcn/radio-group/radio-group-item.svelte +3 -2
  156. package/src/shadcn/sheet/sheet-content.svelte +1 -0
  157. package/src/shadcn/sheet/sheet.css +48 -0
  158. package/src/shadcn/sonner/sonner.svelte +7 -10
  159. package/src/shadcn/tabs/tabs-list.svelte +13 -2
  160. package/src/shadcn/tabs/tabs-trigger.svelte +1 -1
  161. package/src/shadcn/toggle-group/toggle-group.svelte +10 -3
  162. package/src/shadcn/trace/index.ts +29 -0
  163. package/src/shadcn/trace/trace-collapsible-content.svelte +29 -0
  164. package/src/shadcn/trace/trace-collapsible-trigger.svelte +29 -0
  165. package/src/shadcn/trace/trace-collapsible.svelte +20 -0
  166. package/src/shadcn/trace/trace-description.svelte +20 -0
  167. package/src/shadcn/trace/trace-icon.svelte +24 -0
  168. package/src/shadcn/trace/trace-line.svelte +31 -0
  169. package/src/shadcn/trace/trace-title.svelte +20 -0
  170. package/src/shadcn/trace/trace.svelte +23 -0
  171. package/src/ai/composer/Composer.css +0 -108
  172. package/src/ai/composer/Composer.svelte +0 -111
  173. package/src/ai/composer/index.ts +0 -10
  174. package/src/ai/conversation/Conversation.svelte +0 -28
  175. package/src/ai/conversation/ConversationContent.svelte +0 -35
  176. package/src/ai/conversation/ConversationEmptyState.svelte +0 -46
  177. package/src/ai/conversation/ConversationScrollButton.svelte +0 -51
  178. package/src/ai/conversation/index.ts +0 -33
  179. package/src/ai/conversation/stick-to-bottom-context.svelte.ts +0 -131
  180. package/src/animations/accordion.css +0 -58
  181. package/src/animations/icon-swap.css +0 -43
  182. package/src/animations/notification-badge.css +0 -81
  183. package/src/animations/panel.css +0 -86
  184. package/src/animations/reasoning-stream.css +0 -49
  185. package/src/animations/skeleton-reveal.css +0 -97
  186. package/src/animations/streaming-text.css +0 -31
  187. package/src/animations/tabs-sliding.css +0 -83
  188. package/src/animations/texts-reveal.css +0 -70
  189. package/src/animations/tooltip.css +0 -72
  190. package/src/animations/view-transition-reveal.ts +0 -74
  191. package/src/charts/animated-value.css +0 -7
  192. package/src/charts/animated-value.svelte +0 -110
  193. package/src/charts/area-chart.css +0 -29
  194. package/src/charts/area-chart.svelte +0 -195
  195. package/src/charts/bar-chart.css +0 -119
  196. package/src/charts/bar-chart.svelte +0 -269
  197. package/src/charts/charts.css +0 -201
  198. package/src/charts/crosshair.svelte +0 -35
  199. package/src/charts/donut-chart.css +0 -56
  200. package/src/charts/donut-chart.svelte +0 -158
  201. package/src/charts/edge-fade.svelte +0 -43
  202. package/src/charts/edge-fade.ts +0 -16
  203. package/src/charts/figure.css +0 -100
  204. package/src/charts/figure.svelte +0 -122
  205. package/src/charts/gauge-chart.css +0 -94
  206. package/src/charts/gauge-chart.svelte +0 -303
  207. package/src/charts/hover-band.test.ts +0 -30
  208. package/src/charts/hover-band.ts +0 -21
  209. package/src/charts/hover-focus.svelte +0 -85
  210. package/src/charts/index.ts +0 -30
  211. package/src/charts/legend.css +0 -131
  212. package/src/charts/legend.svelte +0 -112
  213. package/src/charts/line-chart.css +0 -26
  214. package/src/charts/line-chart.svelte +0 -256
  215. package/src/charts/motion.ts +0 -19
  216. package/src/charts/number-chart.css +0 -168
  217. package/src/charts/number-chart.svelte +0 -177
  218. package/src/charts/primitives/chart-container.svelte +0 -57
  219. package/src/charts/primitives/chart-style.svelte +0 -36
  220. package/src/charts/primitives/chart-tooltip.svelte +0 -161
  221. package/src/charts/primitives/chart-utils.ts +0 -54
  222. package/src/charts/primitives/index.ts +0 -11
  223. package/src/charts/reveal.svelte +0 -61
  224. package/src/charts/ring-chart.css +0 -96
  225. package/src/charts/ring-chart.svelte +0 -158
  226. package/src/charts/sparkline.css +0 -45
  227. package/src/charts/sparkline.svelte +0 -140
  228. package/src/charts/stat-card.css +0 -103
  229. package/src/charts/stat-card.svelte +0 -267
  230. package/src/charts/time-series-chart.css +0 -28
  231. package/src/charts/time-series-chart.svelte +0 -179
  232. package/src/charts/trend-pill.css +0 -38
  233. package/src/charts/trend-pill.svelte +0 -48
  234. package/src/lib/hooks/is-mobile.svelte.ts +0 -11
  235. package/src/lib/utils.ts +0 -45
  236. package/src/showcase/AiSection.svelte +0 -157
  237. package/src/showcase/AnimationsSection.svelte +0 -1658
  238. package/src/showcase/ChartsSection.svelte +0 -458
  239. package/src/showcase/EffectsSection.svelte +0 -152
  240. package/src/showcase/ShadcnSection.svelte +0 -27
  241. package/src/showcase/ShowcaseImport.svelte +0 -126
  242. package/src/showcase/ShowcaseList.svelte +0 -132
  243. package/src/showcase/ShowcaseNav.svelte +0 -247
  244. package/src/showcase/ShowcaseSection.svelte +0 -112
  245. package/src/showcase/ShowcaseShell.svelte +0 -55
  246. package/src/showcase/ShowcaseStage.svelte +0 -342
  247. package/src/showcase/ShowcaseVariant.svelte +0 -109
  248. package/src/showcase/assets/image-reveal/art-1.jpg +0 -0
  249. package/src/showcase/assets/image-reveal/art-2.jpg +0 -0
  250. package/src/showcase/assets/image-reveal/art-3.jpg +0 -0
  251. package/src/showcase/check.svg +0 -1
  252. package/src/showcase/chevron-arms.svg +0 -2
  253. package/src/showcase/chevron-down.svg +0 -1
  254. package/src/showcase/copy.svg +0 -2
  255. package/src/showcase/demos/ai/confirmation.svelte +0 -59
  256. package/src/showcase/demos/ai/conversation.svelte +0 -59
  257. package/src/showcase/demos/ai/loading-state.svelte +0 -19
  258. package/src/showcase/demos/ai/prompt-input.svelte +0 -57
  259. package/src/showcase/demos/ai/reasoning.svelte +0 -19
  260. package/src/showcase/demos/ai/thinking-dots.svelte +0 -15
  261. package/src/showcase/demos/ai/voice-waveform.svelte +0 -24
  262. package/src/showcase/demos/effects/animated-beam.svelte +0 -50
  263. package/src/showcase/demos/effects/animated-group.svelte +0 -47
  264. package/src/showcase/demos/effects/border-beam-default.svelte +0 -20
  265. package/src/showcase/demos/effects/border-beam-line.svelte +0 -20
  266. package/src/showcase/demos/effects/border-beam-mono.svelte +0 -20
  267. package/src/showcase/demos/effects/border-beam-sunset.svelte +0 -20
  268. package/src/showcase/demos/effects/image-comparison.svelte +0 -25
  269. package/src/showcase/demos/effects/image-reveal.svelte +0 -49
  270. package/src/showcase/demos/effects/in-view.svelte +0 -41
  271. package/src/showcase/demos/effects/integrations-hub.svelte +0 -82
  272. package/src/showcase/demos/effects/magnetic.svelte +0 -31
  273. package/src/showcase/demos/effects/marquee.svelte +0 -33
  274. package/src/showcase/demos/effects/progressive-blur.svelte +0 -47
  275. package/src/showcase/demos/effects/spotlight.svelte +0 -40
  276. package/src/showcase/demos/effects/text-effect.svelte +0 -55
  277. package/src/showcase/demos/shadcn/accordion.svelte +0 -45
  278. package/src/showcase/demos/shadcn/alert-dialog.svelte +0 -23
  279. package/src/showcase/demos/shadcn/alert.svelte +0 -30
  280. package/src/showcase/demos/shadcn/attachment.svelte +0 -71
  281. package/src/showcase/demos/shadcn/avatar.svelte +0 -30
  282. package/src/showcase/demos/shadcn/badge.svelte +0 -26
  283. package/src/showcase/demos/shadcn/breadcrumb.svelte +0 -34
  284. package/src/showcase/demos/shadcn/bubble.svelte +0 -36
  285. package/src/showcase/demos/shadcn/button.svelte +0 -11
  286. package/src/showcase/demos/shadcn/calendar.svelte +0 -8
  287. package/src/showcase/demos/shadcn/card.svelte +0 -39
  288. package/src/showcase/demos/shadcn/checkbox.svelte +0 -39
  289. package/src/showcase/demos/shadcn/collapsible.svelte +0 -20
  290. package/src/showcase/demos/shadcn/command.svelte +0 -48
  291. package/src/showcase/demos/shadcn/context-menu.svelte +0 -54
  292. package/src/showcase/demos/shadcn/demo-harness.svelte +0 -12
  293. package/src/showcase/demos/shadcn/demos.test.ts +0 -20
  294. package/src/showcase/demos/shadcn/dialog.svelte +0 -38
  295. package/src/showcase/demos/shadcn/dropdown-menu.svelte +0 -59
  296. package/src/showcase/demos/shadcn/empty.svelte +0 -29
  297. package/src/showcase/demos/shadcn/field.svelte +0 -115
  298. package/src/showcase/demos/shadcn/hover-card.svelte +0 -32
  299. package/src/showcase/demos/shadcn/index.ts +0 -358
  300. package/src/showcase/demos/shadcn/input-otp.svelte +0 -19
  301. package/src/showcase/demos/shadcn/input.svelte +0 -5
  302. package/src/showcase/demos/shadcn/label.svelte +0 -11
  303. package/src/showcase/demos/shadcn/marker.svelte +0 -30
  304. package/src/showcase/demos/shadcn/message.svelte +0 -75
  305. package/src/showcase/demos/shadcn/popover.svelte +0 -36
  306. package/src/showcase/demos/shadcn/progress.svelte +0 -13
  307. package/src/showcase/demos/shadcn/radio-group.svelte +0 -19
  308. package/src/showcase/demos/shadcn/scroll-area.svelte +0 -18
  309. package/src/showcase/demos/shadcn/select.svelte +0 -29
  310. package/src/showcase/demos/shadcn/separator.svelte +0 -12
  311. package/src/showcase/demos/shadcn/sheet.svelte +0 -48
  312. package/src/showcase/demos/shadcn/skeleton.svelte +0 -11
  313. package/src/showcase/demos/shadcn/slider.svelte +0 -7
  314. package/src/showcase/demos/shadcn/sonner.svelte +0 -18
  315. package/src/showcase/demos/shadcn/spinner.svelte +0 -11
  316. package/src/showcase/demos/shadcn/switch.svelte +0 -9
  317. package/src/showcase/demos/shadcn/table.svelte +0 -76
  318. package/src/showcase/demos/shadcn/tabs.svelte +0 -62
  319. package/src/showcase/demos/shadcn/textarea.svelte +0 -5
  320. package/src/showcase/demos/shadcn/toggle-group.svelte +0 -18
  321. package/src/showcase/demos/shadcn/toggle.svelte +0 -14
  322. package/src/showcase/demos/shadcn/tooltip.svelte +0 -13
  323. package/src/showcase/heart.svg +0 -1
  324. package/src/showcase/index.ts +0 -38
  325. package/src/showcase/kit.test.ts +0 -72
  326. package/src/showcase/kit.ts +0 -17
  327. package/src/showcase/plus.svg +0 -1
  328. package/src/showcase/showcase-shell.css +0 -91
  329. package/src/showcase/stacked-section.css +0 -15
  330. package/src/showcase/success-check.svg +0 -1
  331. package/src/showcase/types.ts +0 -29
  332. package/src/svg-raw.d.ts +0 -7
@@ -1,269 +0,0 @@
1
- <script lang="ts" generics="TData extends Record<string, unknown>">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import "./bar-chart.css";
6
- import { Axis, Bars, Chart, Highlight, Svg, Tooltip } from "layerchart";
7
- import { scaleBand } from "d3-scale";
8
- import Figure from "./figure.svelte";
9
- import { TOOLTIP_GAP, TOOLTIP_TOP } from "./motion.js";
10
-
11
- // =========================
12
- // TYPES
13
- // =========================
14
- type Series = { key: keyof TData & string; label: string; color: string };
15
-
16
- type Props = {
17
- data: TData[];
18
- xKey: keyof TData & string;
19
- /** The bar's value. Required unless `series` is set. */
20
- yKey?: keyof TData & string;
21
- /** Stacks these keys into one bar per row; the bar's value is their sum. */
22
- series?: Series[];
23
- color?: string;
24
- /** A fill per bar, for bands whose meaning changes along the axis. */
25
- colorOf?: (d: TData) => string;
26
- /** Body height in px, or "fill" to grow to the parent's height (parent must
27
- * be a flex column that gives the chart a determinate height). Default 240. */
28
- height?: number | "fill";
29
- orientation?: "vertical" | "horizontal";
30
- /** Left padding for horizontal charts (label space). Default 80. */
31
- leftPadding?: number;
32
- formatValue?: (v: number) => string;
33
- formatX?: (v: unknown) => string;
34
- /** Axis tick label. Return "" to skip a tick. Defaults to formatX. */
35
- formatTick?: (v: unknown) => string;
36
- /** Screen-reader summary; also renders an sr-only data table when set. */
37
- label?: string;
38
- /** Column header for the x values in the sr-only table. */
39
- xLabel?: string;
40
- /** Column header for the y values in the sr-only table, and the tooltip's label. */
41
- yLabel?: string;
42
- /** Show the value/label figure above the chart. */
43
- showFigure?: boolean;
44
- class?: string;
45
- };
46
-
47
- // =========================
48
- // PROPS
49
- // =========================
50
- let {
51
- data,
52
- xKey,
53
- yKey,
54
- series,
55
- color = "var(--chart-1)",
56
- colorOf,
57
- height = 240,
58
- orientation = "vertical",
59
- leftPadding = 80,
60
- formatValue = (v) => v.toLocaleString(),
61
- formatX = (v) => String(v),
62
- formatTick,
63
- label,
64
- xLabel,
65
- yLabel,
66
- showFigure = true,
67
- class: className,
68
- }: Props = $props();
69
-
70
- // =========================
71
- // STATE
72
- // =========================
73
- let active = $state<TData | null>(null);
74
-
75
- // ========================= FUNCTIONS ========================= WHY: called from the tooltip header's value expression so it re-runs on every active-band change; an unread {@const} side effect only evaluates once.
76
-
77
- // The microtask defers the state write out of template evaluation.
78
- function trackActive(d: TData): string {
79
- queueMicrotask(() => {
80
- active = d;
81
- });
82
- return formatX(d[xKey]);
83
- }
84
-
85
- function valueOf(d: TData): number {
86
- if (series) return series.reduce((sum, s) => sum + Number(d[s.key] ?? 0), 0);
87
- return Number(yKey ? (d[yKey] ?? 0) : 0);
88
- }
89
-
90
- /** Where one series' segment starts and ends inside its stacked bar. */
91
- function span(d: TData, key: string): [number, number] {
92
- let at = 0;
93
- for (const s of series ?? []) {
94
- const next = at + Number(d[s.key] ?? 0);
95
- if (s.key === key) return [at, next];
96
- at = next;
97
- }
98
- return [0, 0];
99
- }
100
-
101
- // =========================
102
- // DERIVED
103
- // =========================
104
- const yMax = $derived(Math.max(0, ...data.map(valueOf)));
105
- const total = $derived(data.reduce((sum, d) => sum + valueOf(d), 0));
106
- const valueLabel = $derived(yLabel ?? String(yKey ?? "value"));
107
- const fill = $derived(height === "fill");
108
- const horizontal = $derived(orientation === "horizontal");
109
- const radius = $derived(horizontal ? "right" : "top");
110
- // One Bars layer per fill: a stacked series, a colorOf group, or the single color.
111
- const layers = $derived.by(() => {
112
- if (series) {
113
- return series.map((s) => ({
114
- key: s.key,
115
- color: s.color,
116
- rows: data,
117
- at: (d: TData) => span(d, s.key),
118
- }));
119
- }
120
- const groups = new Map<string, TData[]>();
121
- for (const d of data) {
122
- const c = colorOf?.(d) ?? color;
123
- groups.set(c, [...(groups.get(c) ?? []), d]);
124
- }
125
- return [...groups].map(([c, rows]) => ({ key: c, color: c, rows, at: undefined }));
126
- });
127
- const activeColor = $derived(active && colorOf ? colorOf(active) : color);
128
- </script>
129
-
130
- <!-- =========================== -->
131
- <!-- BAR CHART -->
132
- <!-- =========================== -->
133
- <div
134
- class="hr-bar-chart {className ?? ''}"
135
- class:hr-bar-horizontal={horizontal}
136
- class:hr-bar-fill={fill}
137
- class:hr-bar-has-active={active !== null && !series}
138
- role="img"
139
- aria-label={label ?? "Bar chart"}
140
- onpointerleave={() => (active = null)}
141
- >
142
- {#if showFigure}
143
- <Figure
144
- value={active ? valueOf(active) : total}
145
- color="var(--chart-1)"
146
- eyebrow={active ? formatX(active[xKey]) : "Total"}
147
- format={formatValue}
148
- size="md"
149
- />
150
- {/if}
151
-
152
- <div class="hr-chart-body" style:height={fill ? null : `${height}px`}>
153
- {#if data.length === 0}
154
- <div class="empty"><p>No data</p></div>
155
- {:else}
156
- <Chart
157
- {data}
158
- x={horizontal ? valueOf : xKey}
159
- y={horizontal ? xKey : valueOf}
160
- xScale={horizontal ? undefined : scaleBand().padding(0.3)}
161
- yScale={horizontal ? scaleBand().padding(0.3) : undefined}
162
- xDomain={horizontal ? [0, yMax || 1] : undefined}
163
- yDomain={horizontal ? undefined : [0, yMax || 1]}
164
- xNice={horizontal}
165
- yNice={!horizontal}
166
- padding={{ left: horizontal ? leftPadding : 48, bottom: 28, top: 8, right: 12 }}
167
- tooltipContext={{ mode: "band" }}
168
- >
169
- <Svg>
170
- {#if horizontal}
171
- <Axis placement="left" format={(v) => (formatTick ?? formatX)(v)} />
172
- <Axis placement="bottom" format={(v) => formatValue(Number(v))} ticks={4} />
173
- <g class="hr-bar-grid">
174
- <Axis placement="bottom" grid rule={false} ticks={4} format={() => ""} />
175
- </g>
176
- {:else}
177
- <Axis placement="left" format={(v) => formatValue(Number(v))} ticks={4} />
178
- <Axis placement="bottom" format={(v) => (formatTick ?? formatX)(v)} />
179
- <g class="hr-bar-grid">
180
- <Axis placement="left" grid rule={false} ticks={4} format={() => ""} />
181
- </g>
182
- {/if}
183
- {#each layers as layer (layer.key)}
184
- {#if layer.at && horizontal}
185
- <Bars x={layer.at} style="fill: {layer.color}" class="hr-bar-bars" />
186
- {:else if layer.at}
187
- <Bars y={layer.at} style="fill: {layer.color}" class="hr-bar-bars" />
188
- {:else}
189
- <Bars
190
- data={layer.rows}
191
- rounded={radius}
192
- radius={4}
193
- style="fill: {layer.color}"
194
- class="hr-bar-bars"
195
- />
196
- {/if}
197
- {/each}
198
- <!-- WHY: the band tooltip layer eats pointer events, so bar :hover never
199
- fires. The active bar is a Highlight copy; motion "none" keeps it from
200
- sliding between bands. -->
201
- {#if !series}
202
- <Highlight
203
- motion="none"
204
- bar={{ rounded: radius, radius: 4, fill: activeColor, class: "hr-bar-active" }}
205
- />
206
- {/if}
207
- </Svg>
208
- <Tooltip.Root
209
- x={horizontal ? "pointer" : "data"}
210
- y={horizontal ? "data" : TOOLTIP_TOP}
211
- xOffset={TOOLTIP_GAP}
212
- >
213
- {#snippet children({ data: d })}
214
- <Tooltip.Header value={trackActive(d as TData)} />
215
- <Tooltip.List>
216
- {#if series}
217
- {#each series as s (s.key)}
218
- <Tooltip.Item
219
- label={s.label}
220
- value={formatValue(Number(d[s.key] ?? 0))}
221
- color={s.color}
222
- />
223
- {/each}
224
- {:else}
225
- <Tooltip.Item
226
- label={valueLabel}
227
- value={formatValue(valueOf(d as TData))}
228
- color={colorOf ? colorOf(d as TData) : color}
229
- />
230
- {/if}
231
- </Tooltip.List>
232
- {/snippet}
233
- </Tooltip.Root>
234
- </Chart>
235
- {/if}
236
- </div>
237
-
238
- {#if label && data.length > 0}
239
- <table class="hr-sr-only">
240
- <caption>{label}</caption>
241
- <thead>
242
- <tr>
243
- <th scope="col">{xLabel}</th>
244
- {#if series}
245
- {#each series as s (s.key)}
246
- <th scope="col">{s.label}</th>
247
- {/each}
248
- {:else}
249
- <th scope="col">{yLabel}</th>
250
- {/if}
251
- </tr>
252
- </thead>
253
- <tbody>
254
- {#each data as d, i (i)}
255
- <tr>
256
- <th scope="row">{formatX(d[xKey])}</th>
257
- {#if series}
258
- {#each series as s (s.key)}
259
- <td>{formatValue(Number(d[s.key] ?? 0))}</td>
260
- {/each}
261
- {:else}
262
- <td>{formatValue(valueOf(d))}</td>
263
- {/if}
264
- </tr>
265
- {/each}
266
- </tbody>
267
- </table>
268
- {/if}
269
- </div>
@@ -1,201 +0,0 @@
1
- /* Global theming for layerchart-rendered chrome shared by every chart in this
2
- package (tooltip surface, header, rows). Ships with `@heyramzi/ui/charts`, so
3
- any consumer that defines the shadcn token set gets a legible tooltip in both
4
- themes for free.
5
-
6
- WHY: layerchart's built-in `default` tooltip paints itself with
7
- `light-dark(var(--color-surface-100, white), var(--color-surface-300, black))`
8
- and a `backdrop-filter` blur. Apps that don't define `--color-surface-*` (and
9
- don't set `color-scheme`) fall back to a translucent white card, which is
10
- unreadable on a dark page. These rules repaint it with `--popover` /
11
- `--border` / `--muted-foreground`, which already flip per theme. The selectors
12
- stay unlayered so they beat layerchart's `@layer component` defaults
13
- regardless of specificity. */
14
-
15
- .lc-tooltip-container[data-variant="default"] {
16
- color: var(--popover-foreground, var(--foreground));
17
- background-color: var(--popover, #fff);
18
- border: 1px solid var(--border, transparent);
19
- border-radius: 0.5rem;
20
- padding: 0.625rem 0.75rem;
21
- min-width: 8.75rem;
22
- backdrop-filter: none;
23
- box-shadow:
24
- 0 1px 2px -1px oklch(0 0 0 / 0.2),
25
- 0 10px 28px -10px oklch(0 0 0 / 0.32);
26
- /* WHY: opacity only; the container's transform is inline positioning, so
27
- animating transform here would fight it and make the tooltip jump. */
28
- transform-origin: top left;
29
- animation: hr-tooltip-in var(--duration-fast, 250ms) var(--ease-smooth-out) both;
30
- }
31
-
32
- /* WHY `scale` and `translate`, not `transform`: the container's inline transform is
33
- its position, and the individual properties compose with it instead of fighting. */
34
- @keyframes hr-tooltip-in {
35
- from {
36
- opacity: 0;
37
- scale: var(--scale-large, 0.96);
38
- translate: calc(var(--distance-small, 6px) * -1) 0;
39
- }
40
- }
41
-
42
- @media (prefers-reduced-motion: reduce) {
43
- .lc-tooltip-container[data-variant="default"] {
44
- animation: none;
45
- }
46
- }
47
-
48
- /* bklit-ui's panel: a small title with no rule under it, and a dot on every row. */
49
- .lc-tooltip-header {
50
- color: var(--popover-foreground, var(--foreground));
51
- font-size: 0.75rem;
52
- font-weight: 500;
53
- border-bottom: none;
54
- margin-bottom: 0.5rem;
55
- padding-bottom: 0;
56
- }
57
-
58
- .lc-tooltip-list {
59
- gap: 0.375rem 1rem;
60
- font-size: 0.8125rem;
61
- }
62
-
63
- .lc-tooltip-item-color {
64
- width: 0.625rem;
65
- height: 0.625rem;
66
- }
67
-
68
- .lc-tooltip-item-label,
69
- .lc-tooltip-container .label {
70
- color: var(--muted-foreground);
71
- }
72
-
73
- .lc-tooltip-item-value,
74
- .lc-tooltip-container .value {
75
- color: var(--popover-foreground, var(--foreground));
76
- font-weight: 500;
77
- font-variant-numeric: tabular-nums;
78
- }
79
-
80
- /* Shared chart tokens, held at zero specificity by `:where()`. The reveal pair
81
- is the entrance every chart shares; motion.ts mirrors its duration. */
82
- :where(
83
- .hr-area-chart,
84
- .hr-bar-chart,
85
- .hr-line-chart,
86
- .hr-sparkline,
87
- .hr-number-chart,
88
- .hr-stat-card,
89
- .hr-legend,
90
- .hr-ts-chart,
91
- .hr-donut-chart,
92
- .hr-ring,
93
- .hr-gauge
94
- ) {
95
- --chart-label: var(--muted-foreground, oklch(0.5 0.01 286));
96
- --chart-grid: color-mix(in srgb, var(--border, oklch(0.5 0.01 286)) 65%, transparent);
97
- --chart-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
98
- --chart-motion-fast: 150ms;
99
- --chart-motion: 250ms;
100
- --chart-motion-slow: 800ms;
101
- --chart-motion-reveal: 1100ms;
102
- --chart-ease-reveal: cubic-bezier(0.85, 0, 0.15, 1);
103
- --chart-stagger: 30ms;
104
- --chart-crosshair: color-mix(
105
- in srgb,
106
- var(--muted-foreground, oklch(0.5 0.01 286)) 60%,
107
- transparent
108
- );
109
- --chart-card-shadow: 0 1px 2px 0 oklch(0 0 0 / 0.04), 0 1px 3px 0 oklch(0 0 0 / 0.06);
110
- }
111
-
112
- /* Shared layerchart chrome: axis labels, grid rules, and hover highlights were
113
- duplicated identically across every chart's scoped <style>. Centralize them
114
- here, scoped to the chart roots, so the look is defined once. `:where()` keeps
115
- specificity at 0 so a component can still override locally if it must. */
116
- :where(
117
- .hr-area-chart,
118
- .hr-bar-chart,
119
- .hr-line-chart,
120
- .hr-scatter-chart,
121
- .hr-live-line-chart,
122
- .hr-sparkline,
123
- .hr-stat-card,
124
- .hr-donut-chart
125
- )
126
- .lc-axis-tick-label {
127
- fill: var(--chart-label);
128
- font-size: 11px;
129
- }
130
- :where(
131
- .hr-area-chart,
132
- .hr-bar-chart,
133
- .hr-line-chart,
134
- .hr-scatter-chart,
135
- .hr-live-line-chart,
136
- .hr-sparkline,
137
- .hr-stat-card,
138
- .hr-donut-chart
139
- )
140
- .lc-axis-tick {
141
- stroke: transparent;
142
- }
143
- :where(
144
- .hr-area-chart,
145
- .hr-bar-chart,
146
- .hr-line-chart,
147
- .hr-scatter-chart,
148
- .hr-live-line-chart,
149
- .hr-sparkline,
150
- .hr-stat-card,
151
- .hr-donut-chart
152
- )
153
- :is(.lc-grid-x-rule, .lc-grid-y-rule) {
154
- stroke: var(--chart-grid);
155
- stroke-dasharray: 4 4;
156
- }
157
- :where(
158
- .hr-area-chart,
159
- .hr-bar-chart,
160
- .hr-line-chart,
161
- .hr-scatter-chart,
162
- .hr-live-line-chart,
163
- .hr-sparkline,
164
- .hr-stat-card,
165
- .hr-donut-chart
166
- )
167
- .lc-highlight-point {
168
- stroke: var(--background, white);
169
- stroke-width: 2;
170
- }
171
- :where(
172
- .hr-area-chart,
173
- .hr-bar-chart,
174
- .hr-line-chart,
175
- .hr-scatter-chart,
176
- .hr-live-line-chart,
177
- .hr-sparkline,
178
- .hr-stat-card,
179
- .hr-donut-chart
180
- )
181
- .lc-highlight-line {
182
- stroke: var(--chart-grid);
183
- stroke-width: 1;
184
- stroke-dasharray: none;
185
- }
186
- /* bklit-ui's hover: the series drops to 0.3 and hover-focus.svelte redraws the
187
- stretch around the point at full strength. */
188
- .hr-hover-dim {
189
- transition: opacity 400ms ease-in-out;
190
- }
191
- .hr-hover-dim.hr-hover-dimmed {
192
- opacity: 0.3;
193
- }
194
- @media (prefers-reduced-motion: reduce) {
195
- .hr-hover-dim {
196
- transition: none;
197
- }
198
- }
199
- .hr-crosshair-stop {
200
- stop-color: var(--chart-crosshair);
201
- }
@@ -1,35 +0,0 @@
1
- <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { getChartContext } from "layerchart";
6
-
7
- // =========================
8
- // TYPES
9
- // =========================
10
- type Props = {
11
- /** Gradient id. Paint the highlight line with `stroke: url(#id)`. */
12
- id: string;
13
- };
14
-
15
- // =========================
16
- // PROPS
17
- // =========================
18
- let { id }: Props = $props();
19
-
20
- const ctx = getChartContext();
21
- </script>
22
-
23
- <!-- =========================== -->
24
- <!-- CROSSHAIR -->
25
- <!-- =========================== -->
26
- <!-- WHY userSpaceOnUse: a vertical line has a zero-width bounding box, so an
27
- objectBoundingBox gradient on it paints nothing. -->
28
- <defs>
29
- <linearGradient {id} gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="0" y2={ctx.height}>
30
- <stop offset="0" class="hr-crosshair-stop" stop-opacity="0" />
31
- <stop offset="0.12" class="hr-crosshair-stop" />
32
- <stop offset="0.88" class="hr-crosshair-stop" />
33
- <stop offset="1" class="hr-crosshair-stop" stop-opacity="0" />
34
- </linearGradient>
35
- </defs>
@@ -1,56 +0,0 @@
1
- /* Styles for DonutChart. Plain stylesheet (see area-chart.css for why).
2
- Selectors are namespaced under `.hr-donut-chart`. */
3
-
4
- .hr-donut-chart {
5
- width: 100%;
6
- display: flex;
7
- justify-content: center;
8
- }
9
-
10
- .hr-donut-chart .empty {
11
- display: flex;
12
- align-items: center;
13
- justify-content: center;
14
- width: 100%;
15
- border: 1px dashed var(--chart-grid, oklch(0.5 0.01 286 / 0.2));
16
- border-radius: 0.5rem;
17
- }
18
- .hr-donut-chart .empty p {
19
- font-size: 0.8125rem;
20
- color: var(--chart-label, oklch(0.5 0.01 286));
21
- margin: 0;
22
- }
23
-
24
- /* The slice slides out a little slower than it slides back: a close is always the quicker. */
25
- .hr-donut-chart .hr-donut-arc {
26
- cursor: pointer;
27
- transition:
28
- opacity var(--chart-motion-fast, 150ms) ease,
29
- translate var(--duration-quick, 150ms) var(--ease-smooth-out, ease-out);
30
- }
31
- .hr-donut-chart .hr-donut-arc[data-hovered] {
32
- transition:
33
- opacity var(--chart-motion-fast, 150ms) ease,
34
- translate var(--duration-fast, 250ms) var(--ease-smooth-out);
35
- }
36
-
37
- .hr-donut-chart .hr-donut-center-value {
38
- fill: var(--foreground, oklch(0.18 0.02 240));
39
- font-size: 16px;
40
- font-weight: 600;
41
- font-feature-settings: "tnum";
42
- transition: opacity 180ms ease;
43
- }
44
-
45
- .hr-donut-chart .hr-donut-center-label {
46
- fill: var(--chart-label, oklch(0.5 0.01 286));
47
- font-size: 11px;
48
- transition: opacity 180ms ease;
49
- }
50
-
51
- @media (prefers-reduced-motion: reduce) {
52
- .hr-donut-chart .hr-donut-arc,
53
- .hr-donut-chart .hr-donut-arc[data-hovered] {
54
- transition: opacity 120ms ease;
55
- }
56
- }