@heyramzi/ui 2.0.1 → 2.2.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 (341) hide show
  1. package/package.json +48 -24
  2. package/scripts/sync-shadcn.mjs +3 -4
  3. package/src/agents/agent-avatar.svelte +604 -575
  4. package/src/agents/agent-cast.svelte +179 -183
  5. package/src/agents/demo.svelte +125 -113
  6. package/src/agents/helpers.ts +23 -17
  7. package/src/agents/index.ts +4 -4
  8. package/src/agents/page-state.ts +6 -6
  9. package/src/agents/types.ts +6 -6
  10. package/src/ai/ai-button/AiButton.svelte +4 -12
  11. package/src/ai/generation-progress/GenerationProgress.svelte +10 -3
  12. package/src/ai/prompt-input/PromptInputTextarea.svelte +1 -2
  13. package/src/ai/response/Response.css +2 -3
  14. package/src/animations/avatar-group-hover.css +2 -16
  15. package/src/animations/card-tilt.css +3 -6
  16. package/src/animations/digit-pop-in.css +2 -15
  17. package/src/animations/dropdown.css +4 -17
  18. package/src/animations/input-clear-dissolve.css +5 -18
  19. package/src/animations/input-shake.css +9 -41
  20. package/src/animations/learn-more-hover.css +17 -9
  21. package/src/animations/like-button.css +2 -4
  22. package/src/animations/page-side-by-side.css +2 -10
  23. package/src/animations/plus-menu-morph.css +2 -5
  24. package/src/animations/shimmer-text.css +5 -18
  25. package/src/animations/spinning-counter.css +2 -6
  26. package/src/animations/success-check.css +2 -15
  27. package/src/animations/thinking-states.css +2 -7
  28. package/src/brand/brand.test.ts +21 -5
  29. package/src/brand/index.ts +4 -10
  30. package/src/canvas/README.md +9 -12
  31. package/src/canvas/card/card-frame.svelte +43 -39
  32. package/src/canvas/card/resize-handles.svelte +89 -80
  33. package/src/canvas/chrome/chrome-zoom.svelte +101 -100
  34. package/src/canvas/chrome/lock-badge.svelte +8 -8
  35. package/src/canvas/chrome/side-handles.svelte +24 -19
  36. package/src/canvas/chrome/size-chip.svelte +30 -30
  37. package/src/canvas/chrome/snap-guides.svelte +20 -20
  38. package/src/canvas/components/icons/ToolIcon.svelte +8 -8
  39. package/src/canvas/components/shared/svg/PreviewSvg.svelte +19 -19
  40. package/src/canvas/components/shared/svg/ShapeOutline.svelte +71 -48
  41. package/src/canvas/components/shared/svg/StrokeNode.svelte +21 -27
  42. package/src/canvas/components/shared/svg/TextRule.svelte +25 -17
  43. package/src/canvas/edges/bend-handle.svelte +46 -46
  44. package/src/canvas/edges/edge-gradient.svelte +10 -10
  45. package/src/canvas/edges/gradient-edge.svelte +45 -29
  46. package/src/canvas/editor/lock.test.ts +6 -1
  47. package/src/canvas/editor/style.ts +7 -1
  48. package/src/canvas/headless/svg-figure.test.ts +5 -1
  49. package/src/canvas/lod/lod-switch.svelte +111 -106
  50. package/src/canvas/pen/PenField.svelte +87 -81
  51. package/src/canvas/pen/PenOverlay.svelte +127 -127
  52. package/src/canvas/pen/ShapeNode.svelte +31 -32
  53. package/src/canvas/pen/TextNode.svelte +54 -53
  54. package/src/canvas/pen/host-field.test.svelte +7 -7
  55. package/src/canvas/pen/shapes.ts +7 -1
  56. package/src/canvas/screen/GlyphIcon.svelte +22 -17
  57. package/src/canvas/screen/PartView.svelte +138 -72
  58. package/src/canvas/screen/ScreenBody.svelte +81 -60
  59. package/src/canvas/screen/ScreenCard.svelte +20 -20
  60. package/src/canvas/ui/CanvasToolbar.svelte +173 -85
  61. package/src/canvas/ui/FrameLayer.svelte +59 -59
  62. package/src/canvas/ui/PenLayer.svelte +39 -30
  63. package/src/canvas/ui/StylePanel.svelte +119 -102
  64. package/src/canvas/ui/canvas-grid.svelte +137 -129
  65. package/src/charts/animated-value.svelte +1 -1
  66. package/src/charts/area-chart.css +2 -5
  67. package/src/charts/area-chart.svelte +1 -1
  68. package/src/charts/bar-chart.css +2 -3
  69. package/src/charts/bar-chart.svelte +1 -1
  70. package/src/charts/charts.css +5 -17
  71. package/src/charts/crosshair.svelte +1 -1
  72. package/src/charts/dashboard/dashboard-empty.svelte +25 -25
  73. package/src/charts/dashboard/dashboard-section.svelte +24 -24
  74. package/src/charts/dashboard/data-panel.svelte +50 -50
  75. package/src/charts/dashboard/data-sort-head.svelte +56 -56
  76. package/src/charts/dashboard/data-table.svelte +138 -138
  77. package/src/charts/dashboard/panel-grid.svelte +30 -30
  78. package/src/charts/dashboard/period-filter.svelte +25 -25
  79. package/src/charts/dashboard/rating-chip.svelte +19 -19
  80. package/src/charts/dashboard/stat-band.svelte +32 -32
  81. package/src/charts/dashboard/stat-tile.svelte +106 -99
  82. package/src/charts/donut-chart.svelte +1 -1
  83. package/src/charts/edge-fade.svelte +1 -1
  84. package/src/charts/figure.svelte +1 -1
  85. package/src/charts/gauge-chart.css +4 -7
  86. package/src/charts/gauge-chart.svelte +1 -1
  87. package/src/charts/hover-focus.svelte +1 -1
  88. package/src/charts/legend.css +1 -3
  89. package/src/charts/legend.svelte +1 -1
  90. package/src/charts/line-chart.svelte +1 -1
  91. package/src/charts/number-chart.css +6 -9
  92. package/src/charts/number-chart.svelte +1 -1
  93. package/src/charts/reference-line.svelte +19 -19
  94. package/src/charts/reveal.svelte +1 -1
  95. package/src/charts/ring-chart.css +2 -4
  96. package/src/charts/ring-chart.svelte +1 -1
  97. package/src/charts/sparkline.svelte +5 -2
  98. package/src/charts/stat-card.svelte +1 -1
  99. package/src/charts/time-series-chart.css +2 -5
  100. package/src/charts/trend-pill.css +2 -4
  101. package/src/charts/trend-pill.svelte +1 -1
  102. package/src/components/copy/copy-button.svelte +93 -98
  103. package/src/components/copy/copy-button.test.ts +10 -2
  104. package/src/components/data-table/infinite-scroll.svelte +42 -42
  105. package/src/components/data-table/pagination.svelte +34 -22
  106. package/src/components/data-table/row-arrow.svelte +19 -16
  107. package/src/components/data-table/row-context-menu.svelte +52 -52
  108. package/src/components/data-table/sortable-head.svelte +25 -25
  109. package/src/components/data-table/table-skeleton.svelte +41 -36
  110. package/src/components/docs/doc-page.svelte +18 -9
  111. package/src/components/docs/on-this-page.svelte +16 -3
  112. package/src/components/docs/scroll-spy.svelte.ts +2 -3
  113. package/src/components/field-row/field-row.svelte +10 -8
  114. package/src/components/hold-to-confirm/hold-to-confirm.svelte +5 -1
  115. package/src/components/icon/icon.svelte +14 -14
  116. package/src/components/language-flag/language-flag.svelte +3 -1
  117. package/src/components/list-page/detail-empty.svelte +34 -34
  118. package/src/components/list-page/detail-header.svelte +55 -47
  119. package/src/components/list-page/detail-panel.svelte +51 -59
  120. package/src/components/list-page/detail-row.svelte +19 -19
  121. package/src/components/list-page/detail-stack.svelte +21 -21
  122. package/src/components/list-page/empty-state.svelte +30 -30
  123. package/src/components/list-page/filter-item.svelte +20 -20
  124. package/src/components/list-page/filter-popover.svelte +60 -55
  125. package/src/components/list-page/grouped-list.svelte +4 -2
  126. package/src/components/list-page/index.ts +8 -4
  127. package/src/components/list-page/list-page-shell.svelte +2 -5
  128. package/src/components/list-page/master-detail.svelte +87 -88
  129. package/src/components/list-page/notice-bar.svelte +38 -38
  130. package/src/components/list-page/prev-next.svelte +63 -63
  131. package/src/components/list-page/rail-body.svelte +18 -18
  132. package/src/components/list-page/rail-empty.svelte +23 -30
  133. package/src/components/list-page/rail-head.svelte +24 -24
  134. package/src/components/list-page/rail-row.svelte +77 -73
  135. package/src/components/list-page/section-host.ts +2 -3
  136. package/src/components/locale-switch/locale-switch.svelte +41 -41
  137. package/src/components/mark/mark.svelte +34 -38
  138. package/src/components/open-in/index.ts +1 -5
  139. package/src/components/open-in/open-in.svelte +40 -40
  140. package/src/components/picker/mark-picker.svelte +49 -49
  141. package/src/components/picker/picker.svelte +5 -3
  142. package/src/components/section-header/index.ts +1 -0
  143. package/src/components/section-header/section-header.svelte +1 -1
  144. package/src/components/section-header/section-header.test.ts +7 -1
  145. package/src/components/section-header/section-label.svelte +39 -0
  146. package/src/components/segmented/animated-tabs.svelte +31 -2
  147. package/src/components/segmented/collapse.test.ts +2 -1
  148. package/src/components/segmented/index.ts +2 -0
  149. package/src/components/segmented/segment.svelte +52 -49
  150. package/src/components/segmented/segmented-filter.svelte +79 -80
  151. package/src/components/segmented/segmented-nav.svelte +34 -40
  152. package/src/components/segmented/segmented-overflow.svelte +53 -50
  153. package/src/components/segmented/segmented-track.svelte +62 -46
  154. package/src/components/segmented/segmented.ts +2 -3
  155. package/src/components/star-rating-input/star-rating-input.svelte +103 -103
  156. package/src/components/svg/svg.svelte +4 -4
  157. package/src/components/table-view/table-view.svelte +17 -2
  158. package/src/components/table-view/table-view.test.ts +7 -1
  159. package/src/components/table-view/types.ts +11 -11
  160. package/src/components/tags-input/index.ts +13 -0
  161. package/src/components/tags-input/tags-input.svelte +305 -0
  162. package/src/components/tags-input/tags.test.ts +64 -0
  163. package/src/components/tags-input/tags.ts +142 -0
  164. package/src/components/theme/index.ts +2 -4
  165. package/src/components/theme/theme-provider.svelte +1 -3
  166. package/src/components/toolbar/index.ts +2 -0
  167. package/src/components/{list-page → toolbar}/toolbar-search.svelte +25 -25
  168. package/src/components/toolbar/toolbar.svelte +13 -9
  169. package/src/components/toolbar/toolbar.test.ts +10 -1
  170. package/src/design/index.css +21 -78
  171. package/src/design/polish.css +26 -35
  172. package/src/editor/editor-toolbar.svelte +104 -99
  173. package/src/editor/editor.svelte +296 -266
  174. package/src/editor/image-toolbar.svelte +20 -22
  175. package/src/editor/index.ts +1 -4
  176. package/src/editor/inline-editor.svelte +280 -238
  177. package/src/editor/markdown.ts +15 -15
  178. package/src/editor/renderer.svelte +71 -71
  179. package/src/editor/slash-menu.svelte +24 -27
  180. package/src/effects/animated-beam/diagrams/BeamSvg.svelte +1 -1
  181. package/src/effects/image-comparison/ImageComparison.svelte +11 -1
  182. package/src/effects/interactive-hover-button/InteractiveHoverButton.svelte +59 -46
  183. package/src/effects/magic-card/MagicCard.css +14 -7
  184. package/src/effects/marquee/Marquee.svelte +3 -5
  185. package/src/effects/reveal/observe.ts +0 -3
  186. package/src/effects/spotlight/Spotlight.svelte +1 -1
  187. package/src/effects/theme-toggle/ThemeToggle.css +25 -22
  188. package/src/effects/theme-toggle/ThemeToggle.svelte +6 -7
  189. package/src/gallery.test.ts +14 -4
  190. package/src/inbox/README.md +27 -0
  191. package/src/inbox/inbox.test.ts +214 -0
  192. package/src/inbox/index.ts +31 -0
  193. package/src/inbox/logic.ts +169 -0
  194. package/src/inbox/thread-inbox.svelte +439 -0
  195. package/src/inbox/types.ts +161 -0
  196. package/src/lib/theme-transition.ts +2 -4
  197. package/src/lib/tone.ts +2 -4
  198. package/src/lib/utils.ts +2 -2
  199. package/src/modules.test.ts +105 -0
  200. package/src/onboarding/define-tours.test.ts +55 -40
  201. package/src/onboarding/define-tours.ts +23 -23
  202. package/src/onboarding/demo.svelte +24 -5
  203. package/src/onboarding/index.ts +1 -8
  204. package/src/onboarding/onboarding-provider.svelte +19 -7
  205. package/src/onboarding/onboarding.svelte.ts +16 -16
  206. package/src/onboarding/pick.test.ts +61 -52
  207. package/src/onboarding/pick.ts +16 -13
  208. package/src/onboarding/stores.test.ts +80 -80
  209. package/src/onboarding/stores.ts +41 -39
  210. package/src/onboarding/tour-card.svelte +30 -5
  211. package/src/onboarding/tour-runner.svelte +12 -3
  212. package/src/onboarding/types.ts +20 -12
  213. package/src/onboarding/wait.ts +22 -22
  214. package/src/panel/README.md +5 -0
  215. package/src/panel/index.ts +2 -0
  216. package/src/panel/side-panel.svelte +194 -0
  217. package/src/record/README.md +3 -0
  218. package/src/record/demo-data.ts +352 -0
  219. package/src/record/field-section.svelte +57 -0
  220. package/src/record/fields.ts +194 -0
  221. package/src/record/format.ts +94 -0
  222. package/src/{tasks/record → record}/index.ts +49 -35
  223. package/src/{tasks/record → record}/info-list.svelte +145 -114
  224. package/src/record/kinds.ts +42 -0
  225. package/src/record/logic.ts +326 -0
  226. package/src/record/next-up.svelte +81 -0
  227. package/src/{tasks/record → record}/project-list.svelte +56 -50
  228. package/src/{tasks/record → record}/record-demo.svelte +130 -110
  229. package/src/{tasks/record → record}/record-header.svelte +37 -28
  230. package/src/{tasks/record → record}/record-shell.svelte +54 -54
  231. package/src/record/record-stats.svelte +48 -0
  232. package/src/record/record-timeline.svelte +251 -0
  233. package/src/record/record.test.ts +471 -0
  234. package/src/{tasks/record → record}/steps-rail.svelte +225 -216
  235. package/src/record/types.ts +299 -0
  236. package/src/record/where-we-are.svelte +125 -0
  237. package/src/shadcn/button/button.svelte +1 -1
  238. package/src/shadcn/card/card-title.svelte +1 -5
  239. package/src/shadcn/hooks/use-highlighted-code.svelte.ts +2 -13
  240. package/src/shadcn/sheet/sheet-content.svelte +2 -4
  241. package/src/shadcn/table/table-cell.svelte +2 -3
  242. package/src/shadcn/utilities.css +3 -8
  243. package/src/slides/Controls.svelte +150 -124
  244. package/src/slides/Deck.svelte +243 -238
  245. package/src/slides/Fragment.svelte +64 -57
  246. package/src/slides/Overview.svelte +106 -101
  247. package/src/slides/Presenter.svelte +300 -266
  248. package/src/slides/Slide.svelte +185 -170
  249. package/src/slides/SlideList.svelte +16 -12
  250. package/src/slides/ambient.d.ts +1 -1
  251. package/src/slides/bridges.ts +42 -23
  252. package/src/slides/deck-controller.svelte.ts +47 -35
  253. package/src/slides/demo-slides.svelte +330 -306
  254. package/src/slides/demo.svelte +164 -160
  255. package/src/slides/export/capture.ts +20 -16
  256. package/src/slides/export/ffmpeg.ts +43 -38
  257. package/src/slides/export/index.ts +5 -5
  258. package/src/slides/export/launch.ts +3 -1
  259. package/src/slides/export/pdf.ts +30 -27
  260. package/src/slides/export/types.ts +10 -8
  261. package/src/slides/index.ts +11 -11
  262. package/src/slides/labels.ts +22 -19
  263. package/src/slides/layout.ts +9 -2
  264. package/src/slides/model.ts +4 -4
  265. package/src/slides/navigation.ts +43 -31
  266. package/src/slides/theme.css +5 -7
  267. package/src/slides/types.ts +9 -10
  268. package/src/status/README.md +18 -0
  269. package/src/status/define-statuses.ts +25 -0
  270. package/src/status/index.ts +11 -0
  271. package/src/{tasks → status}/status-badge.svelte +3 -1
  272. package/src/{tasks → status}/status-dot.svelte +1 -3
  273. package/src/{tasks → status}/status-icon.svelte +1 -1
  274. package/src/status/status-types.ts +40 -0
  275. package/src/tasks/README.md +1 -1
  276. package/src/tasks/board-order.ts +2 -4
  277. package/src/tasks/demo.svelte +192 -34
  278. package/src/tasks/detail/detail-demo.svelte +75 -15
  279. package/src/tasks/detail/detail-types.ts +45 -45
  280. package/src/tasks/detail/task-detail.svelte +40 -10
  281. package/src/tasks/detail/task-property.svelte +8 -2
  282. package/src/tasks/detail/task-thread.svelte +53 -12
  283. package/src/tasks/gantt/gantt-bar.svelte +17 -6
  284. package/src/tasks/gantt/gantt-grid.svelte +40 -9
  285. package/src/tasks/gantt/gantt-group-row.svelte +8 -2
  286. package/src/tasks/gantt/gantt-header.svelte +9 -3
  287. package/src/tasks/gantt/gantt-task-row.svelte +26 -6
  288. package/src/tasks/gantt/gantt.css +2 -1
  289. package/src/tasks/gantt/gantt.test.ts +4 -2
  290. package/src/tasks/gantt/logic.test.ts +110 -20
  291. package/src/tasks/gantt/logic.ts +42 -6
  292. package/src/tasks/inbox/inbox-card.svelte +15 -7
  293. package/src/tasks/inbox/inbox-draft.svelte +1 -1
  294. package/src/tasks/inbox/inbox-logic.ts +6 -40
  295. package/src/tasks/inbox/inbox-statuses.ts +24 -24
  296. package/src/tasks/inbox/inbox-trace.svelte +9 -3
  297. package/src/tasks/inbox/inbox-types.ts +54 -58
  298. package/src/tasks/inbox/index.ts +22 -21
  299. package/src/tasks/index.ts +52 -53
  300. package/src/tasks/kanban-board.svelte +16 -12
  301. package/src/tasks/kanban-types.ts +2 -3
  302. package/src/tasks/presets/sales.ts +7 -7
  303. package/src/tasks/task-gantt.svelte +28 -8
  304. package/src/tasks/task-list.svelte +41 -17
  305. package/src/tasks/time/duration.ts +40 -40
  306. package/src/tasks/time/time-chip.svelte +9 -2
  307. package/src/tasks/time/time-dot.svelte +1 -1
  308. package/src/tasks/time/time-ring.svelte +11 -3
  309. package/src/tasks/time/time-tracker.svelte +57 -15
  310. package/src/tasks/time/time-types.ts +57 -57
  311. package/src/tasks/use-kanban-dnd.svelte.ts +2 -3
  312. package/src/thread/README.md +31 -0
  313. package/src/thread/index.ts +12 -0
  314. package/src/thread/logic.ts +61 -0
  315. package/src/thread/thread.svelte +432 -0
  316. package/src/thread/thread.test.ts +73 -0
  317. package/src/thread/types.ts +93 -0
  318. package/src/tokens/craft.css +17 -53
  319. package/src/tokens/index.css +3 -13
  320. package/src/tokens/palette.css +13 -11
  321. package/src/tokens/primitives.css +10 -23
  322. package/src/components/list-page/section-label.svelte +0 -39
  323. package/src/tasks/define-statuses.ts +0 -32
  324. package/src/tasks/inbox/inbox.svelte +0 -203
  325. package/src/tasks/record/demo-data.ts +0 -286
  326. package/src/tasks/record/field-section.svelte +0 -53
  327. package/src/tasks/record/fields.ts +0 -142
  328. package/src/tasks/record/format.ts +0 -87
  329. package/src/tasks/record/kinds.ts +0 -42
  330. package/src/tasks/record/logic.ts +0 -324
  331. package/src/tasks/record/next-up.svelte +0 -70
  332. package/src/tasks/record/record-stats.svelte +0 -48
  333. package/src/tasks/record/record-timeline.svelte +0 -231
  334. package/src/tasks/record/record.test.ts +0 -350
  335. package/src/tasks/record/types.ts +0 -280
  336. package/src/tasks/record/where-we-are.svelte +0 -121
  337. package/src/tasks/side-panel.svelte +0 -193
  338. package/src/tasks/status-types.ts +0 -40
  339. /package/src/components/{list-page → toolbar}/toolbar-trigger.ts +0 -0
  340. /package/src/{tasks → panel}/side-panel-types.ts +0 -0
  341. /package/src/{tasks/record → record}/gutter.ts +0 -0
@@ -1,37 +1,37 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import type { Snippet } from "svelte";
6
- import { cn } from "../../lib/utils.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import type { Snippet } from "svelte";
6
+ import { cn } from "../../lib/utils.js";
7
7
 
8
- // =========================
9
- // TYPES
10
- // =========================
11
- interface Props {
12
- /** `<DataPanel>` children, or tiles standing beside one. */
13
- children: Snippet;
14
- /**
15
- * Panels per row: two charts, three breakdowns, or `main`, where the first
16
- * child takes two thirds and the rates beside it one third.
17
- */
18
- columns?: 2 | 3 | "main";
19
- class?: string;
20
- };
8
+ // =========================
9
+ // TYPES
10
+ // =========================
11
+ interface Props {
12
+ /** `<DataPanel>` children, or tiles standing beside one. */
13
+ children: Snippet;
14
+ /**
15
+ * Panels per row: two charts, three breakdowns, or `main`, where the first
16
+ * child takes two thirds and the rates beside it one third.
17
+ */
18
+ columns?: 2 | 3 | "main";
19
+ class?: string;
20
+ }
21
21
 
22
- // =========================
23
- // PROPS
24
- // =========================
25
- let { children, columns = 2, class: className }: Props = $props();
22
+ // =========================
23
+ // PROPS
24
+ // =========================
25
+ let { children, columns = 2, class: className }: Props = $props();
26
26
 
27
- // =========================
28
- // CONSTANTS
29
- // =========================
30
- const COLUMNS: Record<2 | 3 | "main", string> = {
31
- 2: "lg:grid-cols-2",
32
- 3: "lg:grid-cols-2 xl:grid-cols-3",
33
- main: "lg:grid-cols-3 lg:[&>*:first-child]:col-span-2",
34
- };
27
+ // =========================
28
+ // CONSTANTS
29
+ // =========================
30
+ const COLUMNS: Record<2 | 3 | "main", string> = {
31
+ 2: "lg:grid-cols-2",
32
+ 3: "lg:grid-cols-2 xl:grid-cols-3",
33
+ main: "lg:grid-cols-3 lg:[&>*:first-child]:col-span-2",
34
+ };
35
35
  </script>
36
36
 
37
37
  <!-- =========================== -->
@@ -1,31 +1,31 @@
1
1
  <script lang="ts" generics="T extends string">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { cn } from "../../lib/utils.js";
6
- import { SegmentedFilter, SegmentedNav, type TabDef } from "../../components/segmented/index.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { cn } from "../../lib/utils.js";
6
+ import { SegmentedFilter, SegmentedNav, type TabDef } from "../../components/segmented/index.js";
7
7
 
8
- // =========================
9
- // TYPES
10
- // =========================
11
- interface Props {
12
- options: readonly TabDef<T>[];
13
- value: T;
14
- /**
15
- * Give this and the strip is links, so the choice survives reload, back and a
16
- * shared link. Omit it and the strip is a `<SegmentedFilter>` the caller owns.
17
- */
18
- href?: (value: T) => string;
19
- /** Filter mode only. Ignored when `href` is set. */
20
- onValueChange?: (value: T) => void;
21
- ariaLabel: string;
22
- class?: string;
23
- };
8
+ // =========================
9
+ // TYPES
10
+ // =========================
11
+ interface Props {
12
+ options: readonly TabDef<T>[];
13
+ value: T;
14
+ /**
15
+ * Give this and the strip is links, so the choice survives reload, back and a
16
+ * shared link. Omit it and the strip is a `<SegmentedFilter>` the caller owns.
17
+ */
18
+ href?: (value: T) => string;
19
+ /** Filter mode only. Ignored when `href` is set. */
20
+ onValueChange?: (value: T) => void;
21
+ ariaLabel: string;
22
+ class?: string;
23
+ }
24
24
 
25
- // =========================
26
- // PROPS
27
- // =========================
28
- let { options, value, href, onValueChange, ariaLabel, class: className }: Props = $props();
25
+ // =========================
26
+ // PROPS
27
+ // =========================
28
+ let { options, value, href, onValueChange, ariaLabel, class: className }: Props = $props();
29
29
  </script>
30
30
 
31
31
  <!-- =========================== -->
@@ -1,26 +1,26 @@
1
1
  <script lang="ts">
2
- /*
3
- * One A to E grade on one colour scale, so a C means one thing everywhere.
4
- * Light mode takes the 800 shades, since amber on cream fails contrast.
5
- */
6
- import { cn } from "../../lib/utils.js";
2
+ /*
3
+ * One A to E grade on one colour scale, so a C means one thing everywhere.
4
+ * Light mode takes the 800 shades, since amber on cream fails contrast.
5
+ */
6
+ import { cn } from "../../lib/utils.js";
7
7
 
8
- interface Props {
9
- grade: string;
10
- /** What the letter hides: the score and what it was charged for. */
11
- hint?: string;
12
- class?: string;
13
- };
8
+ interface Props {
9
+ grade: string;
10
+ /** What the letter hides: the score and what it was charged for. */
11
+ hint?: string;
12
+ class?: string;
13
+ }
14
14
 
15
- let { grade, hint, class: className }: Props = $props();
15
+ let { grade, hint, class: className }: Props = $props();
16
16
 
17
- const TONE: Record<string, string> = {
18
- A: "bg-success/12 text-success-800 dark:text-success",
19
- B: "bg-success/12 text-success-800 dark:text-success",
20
- C: "bg-muted text-foreground",
21
- D: "bg-warning/18 text-warning-800 dark:text-warning",
22
- E: "bg-destructive/12 text-destructive",
23
- };
17
+ const TONE: Record<string, string> = {
18
+ A: "bg-success/12 text-success-800 dark:text-success",
19
+ B: "bg-success/12 text-success-800 dark:text-success",
20
+ C: "bg-muted text-foreground",
21
+ D: "bg-warning/18 text-warning-800 dark:text-warning",
22
+ E: "bg-destructive/12 text-destructive",
23
+ };
24
24
  </script>
25
25
 
26
26
  <span
@@ -1,39 +1,39 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import type { Snippet } from "svelte";
6
- import { cn } from "../../lib/utils.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import type { Snippet } from "svelte";
6
+ import { cn } from "../../lib/utils.js";
7
7
 
8
- // =========================
9
- // TYPES
10
- // =========================
11
- interface Props {
12
- /** `<StatTile>` children. Four to a row on a desk, two on a phone. */
13
- children: Snippet;
14
- /**
15
- * Cards per row at the widest breakpoint, four unless the set is smaller.
16
- * Five and six are only for a fixed scorecard. The headline stays one row.
17
- */
18
- columns?: 2 | 3 | 4 | 5 | 6;
19
- class?: string;
20
- };
8
+ // =========================
9
+ // TYPES
10
+ // =========================
11
+ interface Props {
12
+ /** `<StatTile>` children. Four to a row on a desk, two on a phone. */
13
+ children: Snippet;
14
+ /**
15
+ * Cards per row at the widest breakpoint, four unless the set is smaller.
16
+ * Five and six are only for a fixed scorecard. The headline stays one row.
17
+ */
18
+ columns?: 2 | 3 | 4 | 5 | 6;
19
+ class?: string;
20
+ }
21
21
 
22
- // =========================
23
- // PROPS
24
- // =========================
25
- let { children, columns = 4, class: className }: Props = $props();
22
+ // =========================
23
+ // PROPS
24
+ // =========================
25
+ let { children, columns = 4, class: className }: Props = $props();
26
26
 
27
- // =========================
28
- // DERIVED
29
- // =========================
30
- const COLUMNS: Record<2 | 3 | 4 | 5 | 6, string> = {
31
- 2: "sm:grid-cols-2",
32
- 3: "sm:grid-cols-2 lg:grid-cols-3",
33
- 4: "sm:grid-cols-2 lg:grid-cols-4",
34
- 5: "sm:grid-cols-3 lg:grid-cols-5",
35
- 6: "sm:grid-cols-3 xl:grid-cols-6",
36
- };
27
+ // =========================
28
+ // DERIVED
29
+ // =========================
30
+ const COLUMNS: Record<2 | 3 | 4 | 5 | 6, string> = {
31
+ 2: "sm:grid-cols-2",
32
+ 3: "sm:grid-cols-2 lg:grid-cols-3",
33
+ 4: "sm:grid-cols-2 lg:grid-cols-4",
34
+ 5: "sm:grid-cols-3 lg:grid-cols-5",
35
+ 6: "sm:grid-cols-3 xl:grid-cols-6",
36
+ };
37
37
  </script>
38
38
 
39
39
  <!-- =========================== -->
@@ -1,108 +1,108 @@
1
1
  <script lang="ts" module>
2
- /**
3
- * Which way a metric has to move to be good news. `neutral` fits a figure like
4
- * spend, which isn't a win or a loss until the return sits beside it.
5
- */
6
- export type StatDirection = "up-good" | "down-good" | "neutral";
2
+ /**
3
+ * Which way a metric has to move to be good news. `neutral` fits a figure like
4
+ * spend, which isn't a win or a loss until the return sits beside it.
5
+ */
6
+ export type StatDirection = "up-good" | "down-good" | "neutral";
7
7
  </script>
8
8
 
9
9
  <script lang="ts">
10
- // =========================
11
- // IMPORTS
12
- // =========================
13
- import NumberChart from "../number-chart.svelte";
14
- import Sparkline from "../sparkline.svelte";
15
- import type { Snippet } from "svelte";
16
- import { cn } from "../../lib/utils.js";
17
- import { Icon } from "../../components/icon/index.js";
18
- import type { PhosphorIcon } from "../../lib/icon-types.js";
10
+ // =========================
11
+ // IMPORTS
12
+ // =========================
13
+ import NumberChart from "../number-chart.svelte";
14
+ import Sparkline from "../sparkline.svelte";
15
+ import type { Snippet } from "svelte";
16
+ import { cn } from "../../lib/utils.js";
17
+ import { Icon } from "../../components/icon/index.js";
18
+ import type { PhosphorIcon } from "../../lib/icon-types.js";
19
19
 
20
- // =========================
21
- // TYPES
22
- // =========================
23
- interface Props {
24
- label: string;
25
- /** Already formatted. The tile never guesses a currency or a locale. */
26
- value: string;
27
- /**
28
- * Percent change against the previous period. `null` means nothing to
29
- * compare yet and draws a dash. Omit it when the figure has no period at all.
30
- */
31
- deltaPct?: number | null;
32
- direction?: StatDirection;
33
- /** The one figure the screen was opened to read. Set it on exactly one tile. */
34
- lead?: boolean;
35
- /** A quiet line under the value: what it was measured over, or why it is a dash. */
36
- hint?: string;
37
- /**
38
- * 0 to 1, drawn as a track under the value: share of a total or progress to
39
- * a target. Omit it for a cash balance.
40
- */
41
- share?: number;
42
- /** What `share` is measured against, e.g. "of revenue". Only with `share`. */
43
- shareLabel?: string;
44
- /** Track colour. The first series token unless a tile means something else. */
45
- color?: string;
46
- /**
47
- * A shape behind the figure, oldest first, bled along the card's bottom.
48
- * The treatment every tile gives a number with a history. Omit when there
49
- * is none.
50
- */
51
- series?: number[];
52
- /** Leading mark before the label. */
53
- icon?: PhosphorIcon;
54
- /**
55
- * Makes the tile a link, like a balance that opens the bank. It lives here so
56
- * a linked figure isn't drawn as a second, different card style.
57
- */
58
- href?: string;
59
- /** What the link opens, shown on hover. Only with `href`. */
60
- hrefLabel?: string;
61
- /**
62
- * `_blank` for a figure that leaves the app (a bank, a provider console),
63
- * `_self` for one that is another page of this app. Only with `href`.
64
- */
65
- target?: "_self" | "_blank";
66
- /**
67
- * A chip at the end of the label row: the limit the figure is judged against,
68
- * the state it is in. Wins over `hrefLabel`, which is only a hover hint.
69
- */
70
- badge?: Snippet;
71
- /** A loss or an overrun: the figure turns the destructive colour. */
72
- negative?: boolean;
73
- class?: string;
74
- };
20
+ // =========================
21
+ // TYPES
22
+ // =========================
23
+ interface Props {
24
+ label: string;
25
+ /** Already formatted. The tile never guesses a currency or a locale. */
26
+ value: string;
27
+ /**
28
+ * Percent change against the previous period. `null` means nothing to
29
+ * compare yet and draws a dash. Omit it when the figure has no period at all.
30
+ */
31
+ deltaPct?: number | null;
32
+ direction?: StatDirection;
33
+ /** The one figure the screen was opened to read. Set it on exactly one tile. */
34
+ lead?: boolean;
35
+ /** A quiet line under the value: what it was measured over, or why it is a dash. */
36
+ hint?: string;
37
+ /**
38
+ * 0 to 1, drawn as a track under the value: share of a total or progress to
39
+ * a target. Omit it for a cash balance.
40
+ */
41
+ share?: number;
42
+ /** What `share` is measured against, e.g. "of revenue". Only with `share`. */
43
+ shareLabel?: string;
44
+ /** Track colour. The first series token unless a tile means something else. */
45
+ color?: string;
46
+ /**
47
+ * A shape behind the figure, oldest first, bled along the card's bottom.
48
+ * The treatment every tile gives a number with a history. Omit when there
49
+ * is none.
50
+ */
51
+ series?: number[];
52
+ /** Leading mark before the label. */
53
+ icon?: PhosphorIcon;
54
+ /**
55
+ * Makes the tile a link, like a balance that opens the bank. It lives here so
56
+ * a linked figure isn't drawn as a second, different card style.
57
+ */
58
+ href?: string;
59
+ /** What the link opens, shown on hover. Only with `href`. */
60
+ hrefLabel?: string;
61
+ /**
62
+ * `_blank` for a figure that leaves the app (a bank, a provider console),
63
+ * `_self` for one that is another page of this app. Only with `href`.
64
+ */
65
+ target?: "_self" | "_blank";
66
+ /**
67
+ * A chip at the end of the label row: the limit the figure is judged against,
68
+ * the state it is in. Wins over `hrefLabel`, which is only a hover hint.
69
+ */
70
+ badge?: Snippet;
71
+ /** A loss or an overrun: the figure turns the destructive colour. */
72
+ negative?: boolean;
73
+ class?: string;
74
+ }
75
75
 
76
- // =========================
77
- // PROPS
78
- // =========================
79
- let {
80
- label,
81
- value,
82
- deltaPct,
83
- direction = "neutral",
84
- lead = false,
85
- hint,
86
- share,
87
- shareLabel,
88
- color,
89
- series,
90
- icon,
91
- href,
92
- hrefLabel,
93
- target = "_blank",
94
- badge,
95
- negative = false,
96
- class: className,
97
- }: Props = $props();
76
+ // =========================
77
+ // PROPS
78
+ // =========================
79
+ let {
80
+ label,
81
+ value,
82
+ deltaPct,
83
+ direction = "neutral",
84
+ lead = false,
85
+ hint,
86
+ share,
87
+ shareLabel,
88
+ color,
89
+ series,
90
+ icon,
91
+ href,
92
+ hrefLabel,
93
+ target = "_blank",
94
+ badge,
95
+ negative = false,
96
+ class: className,
97
+ }: Props = $props();
98
98
 
99
- // =========================
100
- // DERIVED
101
- // =========================
102
- // `Sparkline` plots rows, and a card carries a bare series. Two points is a
103
- // line, not a shape, so it is not drawn.
104
- let points = $derived(series?.map((value, index) => ({ i: index, v: value })) ?? []);
105
- let hasSeries = $derived(points.length > 2);
99
+ // =========================
100
+ // DERIVED
101
+ // =========================
102
+ // `Sparkline` plots rows, and a card carries a bare series. Two points is a
103
+ // line, not a shape, so it is not drawn.
104
+ let points = $derived(series?.map((value, index) => ({ i: index, v: value })) ?? []);
105
+ let hasSeries = $derived(points.length > 2);
106
106
  </script>
107
107
 
108
108
  <!-- =========================== -->
@@ -155,7 +155,14 @@ let hasSeries = $derived(points.length > 2);
155
155
  class="pointer-events-none absolute inset-x-px bottom-px h-12 overflow-hidden rounded-b-[calc(var(--radius-xl)-1px)]"
156
156
  aria-hidden="true"
157
157
  >
158
- <Sparkline data={points} xKey="i" yKey="v" color={color ?? "var(--chart-1)"} height={48} bare />
158
+ <Sparkline
159
+ data={points}
160
+ xKey="i"
161
+ yKey="v"
162
+ color={color ?? "var(--chart-1)"}
163
+ height={48}
164
+ bare
165
+ />
159
166
  </div>
160
167
  {/if}
161
168
  </svelte:element>
@@ -25,7 +25,7 @@
25
25
  /** Format the center value */
26
26
  formatValue?: (v: number) => string;
27
27
  class?: string;
28
- };
28
+ }
29
29
 
30
30
  // =========================
31
31
  // PROPS
@@ -12,7 +12,7 @@
12
12
  id: string;
13
13
  /** Fraction of the shape's width faded at each side, 0-0.45. */
14
14
  amount?: number;
15
- };
15
+ }
16
16
 
17
17
  // =========================
18
18
  // PROPS
@@ -41,7 +41,7 @@
41
41
  /** Leading icon before the title. */
42
42
  icon?: Snippet;
43
43
  class?: string;
44
- };
44
+ }
45
45
 
46
46
  // =========================
47
47
  // PROPS
@@ -1,7 +1,5 @@
1
- /* Styles for GaugeChart. Plain stylesheet (see area-chart.css for why).
2
- Selectors are namespaced under `.hr-gauge` (the generic ones below would
3
- otherwise collide with RingChart's identical `.value`/`.label`/`.center`/
4
- `.fill`/`svg` names once they are no longer Svelte-scoped). */
1
+ /* A plain stylesheet (see area-chart.css), namespaced under `.hr-gauge` because RingChart's
2
+ unscoped `.value`, `.label` and `.center` would otherwise collide. */
5
3
 
6
4
  .hr-gauge {
7
5
  position: relative;
@@ -51,9 +49,8 @@
51
49
  /* WHY: active paint comes from the fill attribute (flat or gradient url), so
52
50
  no CSS fill here, which would override it. */
53
51
  .hr-gauge .fill {
54
- /* WHY: each active notch fades up in arc order; the per-notch stagger
55
- sweeps the colour around the arc so the gauge reads as filling, instead
56
- of every notch popping in from the centre at once. */
52
+ /* WHY: active notches fade up in arc order, so the gauge reads as filling
53
+ instead of every notch popping in at once. */
57
54
  animation: hr-gauge-notch-in 0.3s var(--chart-ease-out, cubic-bezier(0.22, 1, 0.36, 1)) both;
58
55
  }
59
56
 
@@ -67,7 +67,7 @@
67
67
  /** Accessible description, e.g. "ARR run rate". */
68
68
  ariaLabel?: string;
69
69
  class?: string;
70
- };
70
+ }
71
71
 
72
72
  // =========================
73
73
  // PROPS
@@ -20,7 +20,7 @@
20
20
  bleed?: number;
21
21
  /** How far the band reaches each side of the point, as a share of the gap to its neighbour. */
22
22
  reach?: number;
23
- };
23
+ }
24
24
 
25
25
  // =========================
26
26
  // PROPS
@@ -111,9 +111,7 @@
111
111
  height: 100%;
112
112
  border-radius: 999px;
113
113
  /* WHY: scaleX from the left avoids the layout thrash of animating width;
114
- the bar's fill fraction is set inline as --hr-bar-scale. The entrance
115
- sweeps from 0 once (delays match the ring sweep); the transition takes
116
- over for later data changes. */
114
+ the bar's fill fraction is set inline as --hr-bar-scale. */
117
115
  transform-origin: left center;
118
116
  transform: scaleX(var(--hr-bar-scale, 0));
119
117
  animation: hr-legend-fill var(--chart-motion-reveal, 1100ms)
@@ -33,7 +33,7 @@
33
33
  hoveredIndex?: number | null;
34
34
  onHoverChange?: (index: number | null) => void;
35
35
  class?: string;
36
- };
36
+ }
37
37
 
38
38
  // =========================
39
39
  // PROPS
@@ -57,7 +57,7 @@
57
57
  formatValue?: (v: number) => string;
58
58
  formatX?: (v: unknown) => string;
59
59
  class?: string;
60
- };
60
+ }
61
61
 
62
62
  // =========================
63
63
  // PROPS
@@ -18,9 +18,8 @@
18
18
  border-color: color-mix(in srgb, var(--ring, var(--chart-1)) 28%, var(--border, transparent));
19
19
  }
20
20
  }
21
- /* WHY a bare mode and not a second component: a band is one panel with
22
- hairlines through it, so a figure inside it must bring no edge of its own.
23
- Same object, one less border. */
21
+ /* A band is one panel with hairlines through it, so a figure inside it must bring no
22
+ edge of its own. */
24
23
  .hr-number-chart[data-bare] {
25
24
  padding: 1rem;
26
25
  border: 0;
@@ -60,9 +59,8 @@
60
59
  font-size: 0.625rem;
61
60
  }
62
61
 
63
- /* WHY the row is baseline-aligned and top-anchored: a band mixes figures that
64
- carry a caption with figures that do not, and every value in the row has to
65
- sit on one line. The slack falls to the bottom, where nothing reads it. */
62
+ /* Baseline-aligned and top-anchored, so values sit on one line even when only some
63
+ figures carry a caption. */
66
64
  .hr-number-row {
67
65
  display: flex;
68
66
  align-items: baseline;
@@ -108,9 +106,8 @@
108
106
  .hr-number-delta-text {
109
107
  font-variant-numeric: tabular-nums;
110
108
  }
111
- /* The readable form of a trend colour: a hue picked to read as a mark measures
112
- about 3.5:1 as 12px text, so it is mixed toward the page foreground. One rule
113
- serves both themes and the package needs to know nothing about which is on. */
109
+ /* A trend hue measures about 3.5:1 as 12px text, so it's mixed toward the foreground,
110
+ which works in both themes. */
114
111
  .hr-number-delta[data-tone="up"] {
115
112
  color: color-mix(
116
113
  in oklab,
@@ -80,7 +80,7 @@
80
80
  /** Rendered at the right of the label row. */
81
81
  trailing?: Snippet;
82
82
  class?: string;
83
- };
83
+ }
84
84
 
85
85
  // =========================
86
86
  // PROPS