@wallarm-org/claude-design 0.0.0-stage → 4.8.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 (963) hide show
  1. package/README.md +114 -2
  2. package/bin/claude-design.js +347 -0
  3. package/dist/SETUP.md +130 -0
  4. package/dist/UPDATE.md +84 -0
  5. package/dist/assets/Icons/activity.svg +1 -0
  6. package/dist/assets/Icons/alt.svg +1 -0
  7. package/dist/assets/Icons/android-neutral.svg +1 -0
  8. package/dist/assets/Icons/android.svg +1 -0
  9. package/dist/assets/Icons/api.svg +1 -0
  10. package/dist/assets/Icons/apple-music-neutral.svg +1 -0
  11. package/dist/assets/Icons/apple-music.svg +1 -0
  12. package/dist/assets/Icons/apple-neutral.svg +1 -0
  13. package/dist/assets/Icons/apple-podcasts-neutral.svg +1 -0
  14. package/dist/assets/Icons/apple-podcasts.svg +1 -0
  15. package/dist/assets/Icons/apple.svg +1 -0
  16. package/dist/assets/Icons/archive.svg +1 -0
  17. package/dist/assets/Icons/arrow-big-up-dash.svg +1 -0
  18. package/dist/assets/Icons/arrow-big-up.svg +1 -0
  19. package/dist/assets/Icons/arrow-down-left.svg +1 -0
  20. package/dist/assets/Icons/arrow-down-right.svg +1 -0
  21. package/dist/assets/Icons/arrow-down.svg +1 -0
  22. package/dist/assets/Icons/arrow-left.svg +1 -0
  23. package/dist/assets/Icons/arrow-right-alt.svg +1 -0
  24. package/dist/assets/Icons/arrow-right.svg +1 -0
  25. package/dist/assets/Icons/arrow-up-down.svg +1 -0
  26. package/dist/assets/Icons/arrow-up-left.svg +1 -0
  27. package/dist/assets/Icons/arrow-up-right.svg +1 -0
  28. package/dist/assets/Icons/arrow-up.svg +1 -0
  29. package/dist/assets/Icons/artstation-neutral.svg +1 -0
  30. package/dist/assets/Icons/artstation.svg +1 -0
  31. package/dist/assets/Icons/asterisk.svg +1 -0
  32. package/dist/assets/Icons/audio-waveform.svg +1 -0
  33. package/dist/assets/Icons/aws-neutral.svg +1 -0
  34. package/dist/assets/Icons/aws.svg +1 -0
  35. package/dist/assets/Icons/badge-check.svg +1 -0
  36. package/dist/assets/Icons/baidu-neutral.svg +1 -0
  37. package/dist/assets/Icons/baidu.svg +1 -0
  38. package/dist/assets/Icons/bandage.svg +1 -0
  39. package/dist/assets/Icons/behance-neutral.svg +1 -0
  40. package/dist/assets/Icons/behance.svg +1 -0
  41. package/dist/assets/Icons/bell-cog.svg +1 -0
  42. package/dist/assets/Icons/bell.svg +1 -0
  43. package/dist/assets/Icons/binary.svg +1 -0
  44. package/dist/assets/Icons/book-open.svg +1 -0
  45. package/dist/assets/Icons/book.svg +1 -0
  46. package/dist/assets/Icons/boosty-neutral.svg +1 -0
  47. package/dist/assets/Icons/boosty.svg +1 -0
  48. package/dist/assets/Icons/bot.svg +1 -0
  49. package/dist/assets/Icons/brain.svg +1 -0
  50. package/dist/assets/Icons/braze-neutral.svg +1 -0
  51. package/dist/assets/Icons/braze.svg +1 -0
  52. package/dist/assets/Icons/brevo-neutral.svg +1 -0
  53. package/dist/assets/Icons/brevo.svg +1 -0
  54. package/dist/assets/Icons/bug-off.svg +1 -0
  55. package/dist/assets/Icons/bug-play.svg +1 -0
  56. package/dist/assets/Icons/bug.svg +1 -0
  57. package/dist/assets/Icons/building.svg +1 -0
  58. package/dist/assets/Icons/building2.svg +1 -0
  59. package/dist/assets/Icons/calendar-check.svg +1 -0
  60. package/dist/assets/Icons/calendar-check2.svg +1 -0
  61. package/dist/assets/Icons/calendar-clock.svg +1 -0
  62. package/dist/assets/Icons/calendar-cog.svg +1 -0
  63. package/dist/assets/Icons/calendar-days.svg +1 -0
  64. package/dist/assets/Icons/calendar-fold.svg +1 -0
  65. package/dist/assets/Icons/calendar-heart.svg +1 -0
  66. package/dist/assets/Icons/calendar-minus.svg +1 -0
  67. package/dist/assets/Icons/calendar-minus2.svg +1 -0
  68. package/dist/assets/Icons/calendar-off.svg +1 -0
  69. package/dist/assets/Icons/calendar-plus.svg +1 -0
  70. package/dist/assets/Icons/calendar-plus2.svg +1 -0
  71. package/dist/assets/Icons/calendar-range.svg +1 -0
  72. package/dist/assets/Icons/calendar-search.svg +1 -0
  73. package/dist/assets/Icons/calendar-x.svg +1 -0
  74. package/dist/assets/Icons/calendar-x2.svg +1 -0
  75. package/dist/assets/Icons/calendar.svg +1 -0
  76. package/dist/assets/Icons/chart-area.svg +1 -0
  77. package/dist/assets/Icons/chart-bar.svg +1 -0
  78. package/dist/assets/Icons/chart-column.svg +1 -0
  79. package/dist/assets/Icons/chart-no-axes-column.svg +1 -0
  80. package/dist/assets/Icons/check-check.svg +1 -0
  81. package/dist/assets/Icons/check.svg +1 -0
  82. package/dist/assets/Icons/checkbox-indeterminate.svg +1 -0
  83. package/dist/assets/Icons/chevron-down.svg +1 -0
  84. package/dist/assets/Icons/chevron-first.svg +1 -0
  85. package/dist/assets/Icons/chevron-last.svg +1 -0
  86. package/dist/assets/Icons/chevron-left.svg +1 -0
  87. package/dist/assets/Icons/chevron-right.svg +1 -0
  88. package/dist/assets/Icons/chevron-up-down.svg +1 -0
  89. package/dist/assets/Icons/chevron-up.svg +1 -0
  90. package/dist/assets/Icons/chevrons-down-up.svg +1 -0
  91. package/dist/assets/Icons/chevrons-down.svg +1 -0
  92. package/dist/assets/Icons/chevrons-left-right.svg +1 -0
  93. package/dist/assets/Icons/chevrons-left.svg +1 -0
  94. package/dist/assets/Icons/chevrons-right-left.svg +1 -0
  95. package/dist/assets/Icons/chevrons-right.svg +1 -0
  96. package/dist/assets/Icons/chevrons-up-down.svg +1 -0
  97. package/dist/assets/Icons/chevrons-up.svg +1 -0
  98. package/dist/assets/Icons/circle-arrow-down.svg +1 -0
  99. package/dist/assets/Icons/circle-arrow-left.svg +1 -0
  100. package/dist/assets/Icons/circle-arrow-out-down-left.svg +1 -0
  101. package/dist/assets/Icons/circle-arrow-out-down-right.svg +1 -0
  102. package/dist/assets/Icons/circle-arrow-out-up-left.svg +1 -0
  103. package/dist/assets/Icons/circle-arrow-out-up-right.svg +1 -0
  104. package/dist/assets/Icons/circle-arrow-right.svg +1 -0
  105. package/dist/assets/Icons/circle-arrow-up.svg +1 -0
  106. package/dist/assets/Icons/circle-check-big.svg +1 -0
  107. package/dist/assets/Icons/circle-check.svg +1 -0
  108. package/dist/assets/Icons/circle-chevron-down.svg +1 -0
  109. package/dist/assets/Icons/circle-chevron-left.svg +1 -0
  110. package/dist/assets/Icons/circle-chevron-right.svg +1 -0
  111. package/dist/assets/Icons/circle-chevron-up.svg +1 -0
  112. package/dist/assets/Icons/circle-dashed.svg +1 -0
  113. package/dist/assets/Icons/circle-dot-dashed.svg +1 -0
  114. package/dist/assets/Icons/circle-ellipsis.svg +1 -0
  115. package/dist/assets/Icons/circle-gauge.svg +1 -0
  116. package/dist/assets/Icons/circle-help.svg +1 -0
  117. package/dist/assets/Icons/circle-minus.svg +1 -0
  118. package/dist/assets/Icons/circle-plus.svg +1 -0
  119. package/dist/assets/Icons/circle-slash.svg +1 -0
  120. package/dist/assets/Icons/circle-slash2.svg +1 -0
  121. package/dist/assets/Icons/circle-stop.svg +1 -0
  122. package/dist/assets/Icons/circle.svg +1 -0
  123. package/dist/assets/Icons/clipboard-check.svg +1 -0
  124. package/dist/assets/Icons/clipboard-x.svg +1 -0
  125. package/dist/assets/Icons/clipboard.svg +1 -0
  126. package/dist/assets/Icons/clock-fading.svg +1 -0
  127. package/dist/assets/Icons/clock.svg +1 -0
  128. package/dist/assets/Icons/cloud-off.svg +1 -0
  129. package/dist/assets/Icons/cloud-sync.svg +1 -0
  130. package/dist/assets/Icons/cloud.svg +1 -0
  131. package/dist/assets/Icons/code.svg +1 -0
  132. package/dist/assets/Icons/collapse.svg +1 -0
  133. package/dist/assets/Icons/columns3-cog.svg +1 -0
  134. package/dist/assets/Icons/command.svg +1 -0
  135. package/dist/assets/Icons/compass.svg +1 -0
  136. package/dist/assets/Icons/copy-slash.svg +1 -0
  137. package/dist/assets/Icons/copy.svg +1 -0
  138. package/dist/assets/Icons/corner-down-left.svg +1 -0
  139. package/dist/assets/Icons/corner-down-right.svg +1 -0
  140. package/dist/assets/Icons/corner-left-down.svg +1 -0
  141. package/dist/assets/Icons/corner-left-up.svg +1 -0
  142. package/dist/assets/Icons/corner-right-down.svg +1 -0
  143. package/dist/assets/Icons/corner-right-up.svg +1 -0
  144. package/dist/assets/Icons/corner-up-left.svg +1 -0
  145. package/dist/assets/Icons/corner-up-right.svg +1 -0
  146. package/dist/assets/Icons/cpu.svg +1 -0
  147. package/dist/assets/Icons/credit-card.svg +1 -0
  148. package/dist/assets/Icons/crosshair.svg +1 -0
  149. package/dist/assets/Icons/ctrl.svg +1 -0
  150. package/dist/assets/Icons/database.svg +1 -0
  151. package/dist/assets/Icons/devianart-neutral.svg +1 -0
  152. package/dist/assets/Icons/devianart.svg +1 -0
  153. package/dist/assets/Icons/discord-neutral.svg +1 -0
  154. package/dist/assets/Icons/discord.svg +1 -0
  155. package/dist/assets/Icons/dollar-sign.svg +1 -0
  156. package/dist/assets/Icons/dot.svg +1 -0
  157. package/dist/assets/Icons/download.svg +1 -0
  158. package/dist/assets/Icons/dprofile-neutral.svg +1 -0
  159. package/dist/assets/Icons/dprofile.svg +1 -0
  160. package/dist/assets/Icons/dribbble-neutral.svg +1 -0
  161. package/dist/assets/Icons/dribbble.svg +1 -0
  162. package/dist/assets/Icons/droplet.svg +1 -0
  163. package/dist/assets/Icons/duplicate.svg +1 -0
  164. package/dist/assets/Icons/dzen-neutral.svg +1 -0
  165. package/dist/assets/Icons/dzen.svg +1 -0
  166. package/dist/assets/Icons/earth-lock.svg +1 -0
  167. package/dist/assets/Icons/earth.svg +1 -0
  168. package/dist/assets/Icons/ellipsis.svg +1 -0
  169. package/dist/assets/Icons/expand.svg +1 -0
  170. package/dist/assets/Icons/external-link.svg +1 -0
  171. package/dist/assets/Icons/eye-off.svg +1 -0
  172. package/dist/assets/Icons/eye.svg +1 -0
  173. package/dist/assets/Icons/facebook-neutral.svg +1 -0
  174. package/dist/assets/Icons/facebook.svg +1 -0
  175. package/dist/assets/Icons/fast-forward.svg +1 -0
  176. package/dist/assets/Icons/figma-neutral.svg +1 -0
  177. package/dist/assets/Icons/figma.svg +1 -0
  178. package/dist/assets/Icons/file-down.svg +1 -0
  179. package/dist/assets/Icons/file-plus.svg +1 -0
  180. package/dist/assets/Icons/file-text.svg +1 -0
  181. package/dist/assets/Icons/file.svg +1 -0
  182. package/dist/assets/Icons/film.svg +1 -0
  183. package/dist/assets/Icons/filter-x.svg +1 -0
  184. package/dist/assets/Icons/filter.svg +1 -0
  185. package/dist/assets/Icons/fingerprint-pattern.svg +1 -0
  186. package/dist/assets/Icons/flag.svg +1 -0
  187. package/dist/assets/Icons/flask-conical.svg +1 -0
  188. package/dist/assets/Icons/folder.svg +1 -0
  189. package/dist/assets/Icons/funnel-plus.svg +1 -0
  190. package/dist/assets/Icons/ghost.svg +1 -0
  191. package/dist/assets/Icons/git-branch.svg +1 -0
  192. package/dist/assets/Icons/git-commit-horizontal.svg +1 -0
  193. package/dist/assets/Icons/git-commit-vertical.svg +1 -0
  194. package/dist/assets/Icons/git-compare-arrows-alt.svg +1 -0
  195. package/dist/assets/Icons/git-compare-arrows.svg +1 -0
  196. package/dist/assets/Icons/git-compare.svg +1 -0
  197. package/dist/assets/Icons/git-fork.svg +1 -0
  198. package/dist/assets/Icons/git-graph.svg +1 -0
  199. package/dist/assets/Icons/git-merge.svg +1 -0
  200. package/dist/assets/Icons/git-pull-request-arrow.svg +1 -0
  201. package/dist/assets/Icons/git-pull-request-closed.svg +1 -0
  202. package/dist/assets/Icons/git-pull-request-create-arrow.svg +1 -0
  203. package/dist/assets/Icons/git-pull-request-create.svg +1 -0
  204. package/dist/assets/Icons/git-pull-request-draft.svg +1 -0
  205. package/dist/assets/Icons/git-pull-request.svg +1 -0
  206. package/dist/assets/Icons/github-neutral.svg +1 -0
  207. package/dist/assets/Icons/github.svg +1 -0
  208. package/dist/assets/Icons/globe-lock.svg +1 -0
  209. package/dist/assets/Icons/globe.svg +1 -0
  210. package/dist/assets/Icons/gmail-neutral.svg +1 -0
  211. package/dist/assets/Icons/gmail.svg +1 -0
  212. package/dist/assets/Icons/google-meet-neutral.svg +1 -0
  213. package/dist/assets/Icons/google-meet.svg +1 -0
  214. package/dist/assets/Icons/google-neutral.svg +1 -0
  215. package/dist/assets/Icons/google-play-neutral.svg +1 -0
  216. package/dist/assets/Icons/google-play.svg +1 -0
  217. package/dist/assets/Icons/google-podcast-neutral.svg +1 -0
  218. package/dist/assets/Icons/google-podcast.svg +1 -0
  219. package/dist/assets/Icons/google.svg +1 -0
  220. package/dist/assets/Icons/grip-horizontal.svg +1 -0
  221. package/dist/assets/Icons/grip-vertical.svg +1 -0
  222. package/dist/assets/Icons/hammer.svg +1 -0
  223. package/dist/assets/Icons/heart-pulse.svg +1 -0
  224. package/dist/assets/Icons/history.svg +1 -0
  225. package/dist/assets/Icons/home.svg +1 -0
  226. package/dist/assets/Icons/imo-neutral.svg +1 -0
  227. package/dist/assets/Icons/imo.svg +1 -0
  228. package/dist/assets/Icons/infinity.svg +1 -0
  229. package/dist/assets/Icons/info.svg +1 -0
  230. package/dist/assets/Icons/infobip-neutral.svg +1 -0
  231. package/dist/assets/Icons/infobip.svg +1 -0
  232. package/dist/assets/Icons/instagram-neutral.svg +1 -0
  233. package/dist/assets/Icons/instagram.svg +1 -0
  234. package/dist/assets/Icons/key-round.svg +1 -0
  235. package/dist/assets/Icons/key-square.svg +1 -0
  236. package/dist/assets/Icons/keyboard.svg +1 -0
  237. package/dist/assets/Icons/kickstarter-neutral.svg +1 -0
  238. package/dist/assets/Icons/kickstarter.svg +1 -0
  239. package/dist/assets/Icons/laptop.svg +1 -0
  240. package/dist/assets/Icons/layers.svg +1 -0
  241. package/dist/assets/Icons/layers2.svg +1 -0
  242. package/dist/assets/Icons/layers3.svg +1 -0
  243. package/dist/assets/Icons/layout-dashboard.svg +1 -0
  244. package/dist/assets/Icons/layout-grid.svg +1 -0
  245. package/dist/assets/Icons/layout-list.svg +1 -0
  246. package/dist/assets/Icons/layout-panel-left.svg +1 -0
  247. package/dist/assets/Icons/layout-panel-top.svg +1 -0
  248. package/dist/assets/Icons/layout-template.svg +1 -0
  249. package/dist/assets/Icons/library-big.svg +1 -0
  250. package/dist/assets/Icons/life-buoy.svg +1 -0
  251. package/dist/assets/Icons/lightbulb-off.svg +1 -0
  252. package/dist/assets/Icons/lightbulb.svg +1 -0
  253. package/dist/assets/Icons/line-neutral.svg +1 -0
  254. package/dist/assets/Icons/line.svg +1 -0
  255. package/dist/assets/Icons/link.svg +1 -0
  256. package/dist/assets/Icons/link2-off.svg +1 -0
  257. package/dist/assets/Icons/link2.svg +1 -0
  258. package/dist/assets/Icons/linkedin-neutral.svg +1 -0
  259. package/dist/assets/Icons/linkedin.svg +1 -0
  260. package/dist/assets/Icons/list-checks.svg +1 -0
  261. package/dist/assets/Icons/list-collapse.svg +1 -0
  262. package/dist/assets/Icons/list-filter.svg +1 -0
  263. package/dist/assets/Icons/list-minus.svg +1 -0
  264. package/dist/assets/Icons/list-ordered.svg +1 -0
  265. package/dist/assets/Icons/list-plus.svg +1 -0
  266. package/dist/assets/Icons/list-restart.svg +1 -0
  267. package/dist/assets/Icons/list-start.svg +1 -0
  268. package/dist/assets/Icons/list-todo.svg +1 -0
  269. package/dist/assets/Icons/list-tree.svg +1 -0
  270. package/dist/assets/Icons/list-video.svg +1 -0
  271. package/dist/assets/Icons/list-x.svg +1 -0
  272. package/dist/assets/Icons/list.svg +1 -0
  273. package/dist/assets/Icons/loader-circle.svg +1 -0
  274. package/dist/assets/Icons/loader.svg +1 -0
  275. package/dist/assets/Icons/lock-open.svg +1 -0
  276. package/dist/assets/Icons/lock.svg +1 -0
  277. package/dist/assets/Icons/log-in.svg +1 -0
  278. package/dist/assets/Icons/log-out.svg +1 -0
  279. package/dist/assets/Icons/mail-check.svg +1 -0
  280. package/dist/assets/Icons/mail-minus.svg +1 -0
  281. package/dist/assets/Icons/mail-open.svg +1 -0
  282. package/dist/assets/Icons/mail-plus.svg +1 -0
  283. package/dist/assets/Icons/mail-question.svg +1 -0
  284. package/dist/assets/Icons/mail-search.svg +1 -0
  285. package/dist/assets/Icons/mail-warning.svg +1 -0
  286. package/dist/assets/Icons/mail-x.svg +1 -0
  287. package/dist/assets/Icons/mail.svg +1 -0
  288. package/dist/assets/Icons/mailbox.svg +1 -0
  289. package/dist/assets/Icons/mailersend-neutral.svg +1 -0
  290. package/dist/assets/Icons/mailersend.svg +1 -0
  291. package/dist/assets/Icons/mailgun-neutral.svg +1 -0
  292. package/dist/assets/Icons/mailgun.svg +1 -0
  293. package/dist/assets/Icons/mailjet-neutral.svg +1 -0
  294. package/dist/assets/Icons/mailjet.svg +1 -0
  295. package/dist/assets/Icons/mails.svg +1 -0
  296. package/dist/assets/Icons/mailtrap-neutral.svg +1 -0
  297. package/dist/assets/Icons/mailtrap.svg +1 -0
  298. package/dist/assets/Icons/mandrill-neutral.svg +1 -0
  299. package/dist/assets/Icons/mandrill.svg +1 -0
  300. package/dist/assets/Icons/map-pin.svg +1 -0
  301. package/dist/assets/Icons/maqsam-neutral.svg +1 -0
  302. package/dist/assets/Icons/maqsam.svg +1 -0
  303. package/dist/assets/Icons/mattermost-neutral.svg +1 -0
  304. package/dist/assets/Icons/mattermost.svg +1 -0
  305. package/dist/assets/Icons/maximize.svg +1 -0
  306. package/dist/assets/Icons/maximize2.svg +1 -0
  307. package/dist/assets/Icons/medium-neutral.svg +1 -0
  308. package/dist/assets/Icons/medium.svg +1 -0
  309. package/dist/assets/Icons/megaphone-off.svg +1 -0
  310. package/dist/assets/Icons/megaphone.svg +1 -0
  311. package/dist/assets/Icons/menu.svg +1 -0
  312. package/dist/assets/Icons/merge.svg +1 -0
  313. package/dist/assets/Icons/message-square-code.svg +1 -0
  314. package/dist/assets/Icons/message-square-dashed.svg +1 -0
  315. package/dist/assets/Icons/message-square-diff.svg +1 -0
  316. package/dist/assets/Icons/message-square-dot.svg +1 -0
  317. package/dist/assets/Icons/message-square-heart.svg +1 -0
  318. package/dist/assets/Icons/message-square-off.svg +1 -0
  319. package/dist/assets/Icons/message-square-plus.svg +1 -0
  320. package/dist/assets/Icons/message-square-quote.svg +1 -0
  321. package/dist/assets/Icons/message-square-reply.svg +1 -0
  322. package/dist/assets/Icons/message-square-share.svg +1 -0
  323. package/dist/assets/Icons/message-square-text.svg +1 -0
  324. package/dist/assets/Icons/message-square-warning.svg +1 -0
  325. package/dist/assets/Icons/message-square-x.svg +1 -0
  326. package/dist/assets/Icons/message-square.svg +1 -0
  327. package/dist/assets/Icons/messages-square.svg +1 -0
  328. package/dist/assets/Icons/messenger-neutral.svg +1 -0
  329. package/dist/assets/Icons/messenger.svg +1 -0
  330. package/dist/assets/Icons/microsoft-neutral.svg +1 -0
  331. package/dist/assets/Icons/microsoft-teams-neutral.svg +1 -0
  332. package/dist/assets/Icons/microsoft-teams.svg +1 -0
  333. package/dist/assets/Icons/microsoft.svg +1 -0
  334. package/dist/assets/Icons/minimize.svg +1 -0
  335. package/dist/assets/Icons/minimize2.svg +1 -0
  336. package/dist/assets/Icons/minus.svg +1 -0
  337. package/dist/assets/Icons/moon.svg +1 -0
  338. package/dist/assets/Icons/mouse-pointer-ban.svg +1 -0
  339. package/dist/assets/Icons/mouse-pointer-click.svg +1 -0
  340. package/dist/assets/Icons/mouse-pointer.svg +1 -0
  341. package/dist/assets/Icons/mouse-pointer2.svg +1 -0
  342. package/dist/assets/Icons/mouse.svg +1 -0
  343. package/dist/assets/Icons/move-diagonal.svg +1 -0
  344. package/dist/assets/Icons/move-diagonal2.svg +1 -0
  345. package/dist/assets/Icons/move-down-left.svg +1 -0
  346. package/dist/assets/Icons/move-down-right.svg +1 -0
  347. package/dist/assets/Icons/move-down.svg +1 -0
  348. package/dist/assets/Icons/move-horizontal.svg +1 -0
  349. package/dist/assets/Icons/move-left.svg +1 -0
  350. package/dist/assets/Icons/move-right.svg +1 -0
  351. package/dist/assets/Icons/move-up-left.svg +1 -0
  352. package/dist/assets/Icons/move-up-right.svg +1 -0
  353. package/dist/assets/Icons/move-up.svg +1 -0
  354. package/dist/assets/Icons/move-vertical.svg +1 -0
  355. package/dist/assets/Icons/move3-d.svg +1 -0
  356. package/dist/assets/Icons/netcore-neutral.svg +1 -0
  357. package/dist/assets/Icons/netcore.svg +1 -0
  358. package/dist/assets/Icons/notebook-pen.svg +1 -0
  359. package/dist/assets/Icons/notebook-tabs.svg +1 -0
  360. package/dist/assets/Icons/notebook-text.svg +1 -0
  361. package/dist/assets/Icons/notebook.svg +1 -0
  362. package/dist/assets/Icons/notepad-text-dashed.svg +1 -0
  363. package/dist/assets/Icons/notepad-text.svg +1 -0
  364. package/dist/assets/Icons/notion-neutral.svg +1 -0
  365. package/dist/assets/Icons/notion.svg +1 -0
  366. package/dist/assets/Icons/octagon-alert.svg +1 -0
  367. package/dist/assets/Icons/octagon-pause.svg +1 -0
  368. package/dist/assets/Icons/octagon-x.svg +1 -0
  369. package/dist/assets/Icons/octagon.svg +1 -0
  370. package/dist/assets/Icons/ok-neutral.svg +1 -0
  371. package/dist/assets/Icons/ok-only-sign-neutral.svg +1 -0
  372. package/dist/assets/Icons/ok-only-sign.svg +1 -0
  373. package/dist/assets/Icons/ok.svg +1 -0
  374. package/dist/assets/Icons/onlyfans-neutral.svg +1 -0
  375. package/dist/assets/Icons/onlyfans.svg +1 -0
  376. package/dist/assets/Icons/option.svg +1 -0
  377. package/dist/assets/Icons/outlook365-neutral.svg +1 -0
  378. package/dist/assets/Icons/outlook365.svg +1 -0
  379. package/dist/assets/Icons/paintbrush.svg +1 -0
  380. package/dist/assets/Icons/panel-bottom-open.svg +1 -0
  381. package/dist/assets/Icons/panel-bottom.svg +1 -0
  382. package/dist/assets/Icons/panel-left-close.svg +1 -0
  383. package/dist/assets/Icons/panel-left-dashed.svg +1 -0
  384. package/dist/assets/Icons/panel-left-open.svg +1 -0
  385. package/dist/assets/Icons/panel-left.svg +1 -0
  386. package/dist/assets/Icons/panel-right-animated.svg +1 -0
  387. package/dist/assets/Icons/panel-right-close.svg +1 -0
  388. package/dist/assets/Icons/panel-right-dashed.svg +1 -0
  389. package/dist/assets/Icons/panel-right-open.svg +1 -0
  390. package/dist/assets/Icons/panel-right.svg +1 -0
  391. package/dist/assets/Icons/panel-top-bottom-dashed.svg +1 -0
  392. package/dist/assets/Icons/panel-top-close.svg +1 -0
  393. package/dist/assets/Icons/panel-top-open.svg +1 -0
  394. package/dist/assets/Icons/panel-top.svg +1 -0
  395. package/dist/assets/Icons/panels-left-bottom.svg +1 -0
  396. package/dist/assets/Icons/panels-right-bottom.svg +1 -0
  397. package/dist/assets/Icons/panels-top-left.svg +1 -0
  398. package/dist/assets/Icons/paperclip.svg +1 -0
  399. package/dist/assets/Icons/patreon-neutral.svg +1 -0
  400. package/dist/assets/Icons/patreon.svg +1 -0
  401. package/dist/assets/Icons/paypal-neutral.svg +1 -0
  402. package/dist/assets/Icons/paypal.svg +1 -0
  403. package/dist/assets/Icons/pen-line.svg +1 -0
  404. package/dist/assets/Icons/pen-off.svg +1 -0
  405. package/dist/assets/Icons/pen-tool.svg +1 -0
  406. package/dist/assets/Icons/pen.svg +1 -0
  407. package/dist/assets/Icons/pencil-line.svg +1 -0
  408. package/dist/assets/Icons/pencil-off.svg +1 -0
  409. package/dist/assets/Icons/pencil-ruler.svg +1 -0
  410. package/dist/assets/Icons/pencil.svg +1 -0
  411. package/dist/assets/Icons/pentagon.svg +1 -0
  412. package/dist/assets/Icons/percentage.svg +1 -0
  413. package/dist/assets/Icons/phone.svg +1 -0
  414. package/dist/assets/Icons/pin-off.svg +1 -0
  415. package/dist/assets/Icons/pin.svg +1 -0
  416. package/dist/assets/Icons/pinterest-neutral.svg +1 -0
  417. package/dist/assets/Icons/pinterest.svg +1 -0
  418. package/dist/assets/Icons/play.svg +1 -0
  419. package/dist/assets/Icons/plug.svg +1 -0
  420. package/dist/assets/Icons/plunk-neutral.svg +1 -0
  421. package/dist/assets/Icons/plunk.svg +1 -0
  422. package/dist/assets/Icons/plus.svg +1 -0
  423. package/dist/assets/Icons/postmark-neutral.svg +1 -0
  424. package/dist/assets/Icons/postmark.svg +1 -0
  425. package/dist/assets/Icons/product-hunt-neutral.svg +1 -0
  426. package/dist/assets/Icons/product-hunt.svg +1 -0
  427. package/dist/assets/Icons/quora-neutral.svg +1 -0
  428. package/dist/assets/Icons/quora.svg +1 -0
  429. package/dist/assets/Icons/quote.svg +1 -0
  430. package/dist/assets/Icons/radar.svg +1 -0
  431. package/dist/assets/Icons/reddit-neutral.svg +1 -0
  432. package/dist/assets/Icons/reddit.svg +1 -0
  433. package/dist/assets/Icons/redo-dot.svg +1 -0
  434. package/dist/assets/Icons/redo.svg +1 -0
  435. package/dist/assets/Icons/redo2.svg +1 -0
  436. package/dist/assets/Icons/refresh-ccw.svg +1 -0
  437. package/dist/assets/Icons/refresh-cw-off.svg +1 -0
  438. package/dist/assets/Icons/resend-neutral.svg +1 -0
  439. package/dist/assets/Icons/resend.svg +1 -0
  440. package/dist/assets/Icons/rss.svg +1 -0
  441. package/dist/assets/Icons/rules.svg +1 -0
  442. package/dist/assets/Icons/scan-line.svg +1 -0
  443. package/dist/assets/Icons/scroll-text.svg +1 -0
  444. package/dist/assets/Icons/search-hint.svg +1 -0
  445. package/dist/assets/Icons/search-x.svg +1 -0
  446. package/dist/assets/Icons/search.svg +1 -0
  447. package/dist/assets/Icons/sendgrid-neutral.svg +1 -0
  448. package/dist/assets/Icons/sendgrid.svg +1 -0
  449. package/dist/assets/Icons/server.svg +1 -0
  450. package/dist/assets/Icons/ses-neutral.svg +1 -0
  451. package/dist/assets/Icons/ses.svg +1 -0
  452. package/dist/assets/Icons/settings.svg +1 -0
  453. package/dist/assets/Icons/settings2.svg +1 -0
  454. package/dist/assets/Icons/shapes.svg +1 -0
  455. package/dist/assets/Icons/share.svg +1 -0
  456. package/dist/assets/Icons/sheet.svg +1 -0
  457. package/dist/assets/Icons/shield-alert.svg +1 -0
  458. package/dist/assets/Icons/shield-ban.svg +1 -0
  459. package/dist/assets/Icons/shield-check.svg +1 -0
  460. package/dist/assets/Icons/shield-ellipsis.svg +1 -0
  461. package/dist/assets/Icons/shield-half.svg +1 -0
  462. package/dist/assets/Icons/shield-minus.svg +1 -0
  463. package/dist/assets/Icons/shield-off.svg +1 -0
  464. package/dist/assets/Icons/shield-plus.svg +1 -0
  465. package/dist/assets/Icons/shield-question.svg +1 -0
  466. package/dist/assets/Icons/shield-user.svg +1 -0
  467. package/dist/assets/Icons/shield-x.svg +1 -0
  468. package/dist/assets/Icons/shield.svg +1 -0
  469. package/dist/assets/Icons/shift.svg +1 -0
  470. package/dist/assets/Icons/signal-neutral.svg +1 -0
  471. package/dist/assets/Icons/signal.svg +1 -0
  472. package/dist/assets/Icons/signpost.svg +1 -0
  473. package/dist/assets/Icons/sina-weibo-neutral.svg +1 -0
  474. package/dist/assets/Icons/sina-weibo.svg +1 -0
  475. package/dist/assets/Icons/skull.svg +1 -0
  476. package/dist/assets/Icons/skype-neutral.svg +1 -0
  477. package/dist/assets/Icons/skype.svg +1 -0
  478. package/dist/assets/Icons/slack-neutral.svg +1 -0
  479. package/dist/assets/Icons/slack.svg +1 -0
  480. package/dist/assets/Icons/sliders-horizontal.svg +1 -0
  481. package/dist/assets/Icons/sliders-vertical.svg +1 -0
  482. package/dist/assets/Icons/smtp-neutral.svg +1 -0
  483. package/dist/assets/Icons/smtp.svg +1 -0
  484. package/dist/assets/Icons/snapchat-neutral.svg +1 -0
  485. package/dist/assets/Icons/snapchat.svg +1 -0
  486. package/dist/assets/Icons/soundcloud-neutral.svg +1 -0
  487. package/dist/assets/Icons/soundcloud.svg +1 -0
  488. package/dist/assets/Icons/space.svg +1 -0
  489. package/dist/assets/Icons/sparkpost-neutral.svg +1 -0
  490. package/dist/assets/Icons/sparkpost.svg +1 -0
  491. package/dist/assets/Icons/speed.svg +1 -0
  492. package/dist/assets/Icons/split.svg +1 -0
  493. package/dist/assets/Icons/spotify-neutral.svg +1 -0
  494. package/dist/assets/Icons/spotify.svg +1 -0
  495. package/dist/assets/Icons/square-arrow-out-up-right.svg +1 -0
  496. package/dist/assets/Icons/square-minus.svg +1 -0
  497. package/dist/assets/Icons/square-pen.svg +1 -0
  498. package/dist/assets/Icons/square-plus.svg +1 -0
  499. package/dist/assets/Icons/square-user-round.svg +1 -0
  500. package/dist/assets/Icons/stack-overflow-neutral.svg +1 -0
  501. package/dist/assets/Icons/stack-overflow.svg +1 -0
  502. package/dist/assets/Icons/star.svg +1 -0
  503. package/dist/assets/Icons/sun.svg +1 -0
  504. package/dist/assets/Icons/syringe.svg +1 -0
  505. package/dist/assets/Icons/tag.svg +1 -0
  506. package/dist/assets/Icons/target.svg +1 -0
  507. package/dist/assets/Icons/teams-neutral.svg +1 -0
  508. package/dist/assets/Icons/teams.svg +1 -0
  509. package/dist/assets/Icons/telegram-neutral.svg +1 -0
  510. package/dist/assets/Icons/telegram-only-sign-neutral.svg +1 -0
  511. package/dist/assets/Icons/telegram-only-sign.svg +1 -0
  512. package/dist/assets/Icons/telegram.svg +1 -0
  513. package/dist/assets/Icons/terminal.svg +1 -0
  514. package/dist/assets/Icons/test-policies.svg +1 -0
  515. package/dist/assets/Icons/threads-neutral.svg +1 -0
  516. package/dist/assets/Icons/threads.svg +1 -0
  517. package/dist/assets/Icons/thumbs-down.svg +1 -0
  518. package/dist/assets/Icons/thumbs-up.svg +1 -0
  519. package/dist/assets/Icons/tiktok-neutral.svg +1 -0
  520. package/dist/assets/Icons/tiktok.svg +1 -0
  521. package/dist/assets/Icons/tinder-neutral.svg +1 -0
  522. package/dist/assets/Icons/tinder.svg +1 -0
  523. package/dist/assets/Icons/trash.svg +1 -0
  524. package/dist/assets/Icons/trash2.svg +1 -0
  525. package/dist/assets/Icons/triangle-alert.svg +1 -0
  526. package/dist/assets/Icons/tumblr-neutral.svg +1 -0
  527. package/dist/assets/Icons/tumblr.svg +1 -0
  528. package/dist/assets/Icons/twitch-neutral.svg +1 -0
  529. package/dist/assets/Icons/twitch.svg +1 -0
  530. package/dist/assets/Icons/undo-dot.svg +1 -0
  531. package/dist/assets/Icons/undo.svg +1 -0
  532. package/dist/assets/Icons/undo2.svg +1 -0
  533. package/dist/assets/Icons/unplug.svg +1 -0
  534. package/dist/assets/Icons/user-check.svg +1 -0
  535. package/dist/assets/Icons/user-minus.svg +1 -0
  536. package/dist/assets/Icons/user-plus.svg +1 -0
  537. package/dist/assets/Icons/user-round-x.svg +1 -0
  538. package/dist/assets/Icons/user-round.svg +1 -0
  539. package/dist/assets/Icons/user.svg +1 -0
  540. package/dist/assets/Icons/username.svg +1 -0
  541. package/dist/assets/Icons/users-round.svg +1 -0
  542. package/dist/assets/Icons/users.svg +1 -0
  543. package/dist/assets/Icons/viber-neutral.svg +1 -0
  544. package/dist/assets/Icons/viber.svg +1 -0
  545. package/dist/assets/Icons/video.svg +1 -0
  546. package/dist/assets/Icons/vimeo-neutral.svg +1 -0
  547. package/dist/assets/Icons/vimeo.svg +1 -0
  548. package/dist/assets/Icons/vk-music-neutral.svg +1 -0
  549. package/dist/assets/Icons/vk-music.svg +1 -0
  550. package/dist/assets/Icons/vk-neutral.svg +1 -0
  551. package/dist/assets/Icons/vk-only-sign-neutral.svg +1 -0
  552. package/dist/assets/Icons/vk-only-sign.svg +1 -0
  553. package/dist/assets/Icons/vk.svg +1 -0
  554. package/dist/assets/Icons/webhook-neutral.svg +1 -0
  555. package/dist/assets/Icons/webhook.svg +1 -0
  556. package/dist/assets/Icons/wechat-neutral.svg +1 -0
  557. package/dist/assets/Icons/wechat.svg +1 -0
  558. package/dist/assets/Icons/whatsapp-badge-neutral.svg +1 -0
  559. package/dist/assets/Icons/whatsapp-badge.svg +1 -0
  560. package/dist/assets/Icons/whatsapp-neutral.svg +1 -0
  561. package/dist/assets/Icons/whatsapp.svg +1 -0
  562. package/dist/assets/Icons/workflow.svg +1 -0
  563. package/dist/assets/Icons/wrap-text.svg +1 -0
  564. package/dist/assets/Icons/wrench.svg +1 -0
  565. package/dist/assets/Icons/x-ex-twitter-neutral.svg +1 -0
  566. package/dist/assets/Icons/x-ex-twitter.svg +1 -0
  567. package/dist/assets/Icons/x.svg +1 -0
  568. package/dist/assets/Icons/xing-neutral.svg +1 -0
  569. package/dist/assets/Icons/xing.svg +1 -0
  570. package/dist/assets/Icons/yandex-music-neutral.svg +1 -0
  571. package/dist/assets/Icons/yandex-music.svg +1 -0
  572. package/dist/assets/Icons/yelp-neutral.svg +1 -0
  573. package/dist/assets/Icons/yelp.svg +1 -0
  574. package/dist/assets/Icons/youtube-music-neutral.svg +1 -0
  575. package/dist/assets/Icons/youtube-music.svg +1 -0
  576. package/dist/assets/Icons/youtube-neutral.svg +1 -0
  577. package/dist/assets/Icons/youtube-shorts-neutral.svg +1 -0
  578. package/dist/assets/Icons/youtube-shorts.svg +1 -0
  579. package/dist/assets/Icons/youtube.svg +1 -0
  580. package/dist/assets/Icons/zap.svg +1 -0
  581. package/dist/assets/Icons/zoom-in.svg +1 -0
  582. package/dist/assets/Icons/zoom-neutral.svg +1 -0
  583. package/dist/assets/Icons/zoom-out.svg +1 -0
  584. package/dist/assets/Icons/zoom.svg +1 -0
  585. package/dist/assets/Icons/zulip-neutral.svg +1 -0
  586. package/dist/assets/Icons/zulip.svg +1 -0
  587. package/dist/assets/Logos/wallarm.svg +1 -0
  588. package/dist/assets.json +4666 -0
  589. package/dist/project/README.md +265 -0
  590. package/dist/project/components/Accordion/README.md +354 -0
  591. package/dist/project/components/Accordion/preview.html +2 -0
  592. package/dist/project/components/Accordion/stories.js +12 -0
  593. package/dist/project/components/AgentAvatar/README.md +127 -0
  594. package/dist/project/components/AgentAvatar/preview.html +2 -0
  595. package/dist/project/components/AgentAvatar/stories.js +12 -0
  596. package/dist/project/components/AgentAvatar/stories.md +1805 -0
  597. package/dist/project/components/AgentGlyph/README.md +1182 -0
  598. package/dist/project/components/AgentGlyph/preview.html +2 -0
  599. package/dist/project/components/AgentGlyph/stories.js +12 -0
  600. package/dist/project/components/AgentLookBuilder/README.md +269 -0
  601. package/dist/project/components/AgentLookBuilder/preview.html +2 -0
  602. package/dist/project/components/AgentLookBuilder/stories.js +12 -0
  603. package/dist/project/components/Alert/README.md +492 -0
  604. package/dist/project/components/Alert/preview.html +2 -0
  605. package/dist/project/components/Alert/stories.js +12 -0
  606. package/dist/project/components/AnimatedBackground/README.md +124 -0
  607. package/dist/project/components/AnimatedBackground/preview.html +2 -0
  608. package/dist/project/components/AnimatedBackground/stories.js +12 -0
  609. package/dist/project/components/AppShell/README.md +75 -0
  610. package/dist/project/components/AppShell/preview.html +2 -0
  611. package/dist/project/components/AppShell/stories.js +28 -0
  612. package/dist/project/components/AppShell/stories.md +2878 -0
  613. package/dist/project/components/ApprovalCard/README.md +353 -0
  614. package/dist/project/components/ApprovalCard/preview.html +2 -0
  615. package/dist/project/components/ApprovalCard/stories.js +12 -0
  616. package/dist/project/components/AreaChart/README.md +673 -0
  617. package/dist/project/components/AreaChart/preview.html +2 -0
  618. package/dist/project/components/AreaChart/stories.js +12 -0
  619. package/dist/project/components/AssistantMessage/README.md +724 -0
  620. package/dist/project/components/AssistantMessage/preview.html +2 -0
  621. package/dist/project/components/AssistantMessage/stories.js +55 -0
  622. package/dist/project/components/Attribute/README.md +1174 -0
  623. package/dist/project/components/Attribute/preview.html +2 -0
  624. package/dist/project/components/Attribute/stories.js +12 -0
  625. package/dist/project/components/Avatar/README.md +416 -0
  626. package/dist/project/components/Avatar/preview.html +2 -0
  627. package/dist/project/components/Avatar/stories.js +12 -0
  628. package/dist/project/components/Badge/README.md +853 -0
  629. package/dist/project/components/Badge/preview.html +2 -0
  630. package/dist/project/components/Badge/stories.js +12 -0
  631. package/dist/project/components/Banner/README.md +341 -0
  632. package/dist/project/components/Banner/preview.html +2 -0
  633. package/dist/project/components/Banner/stories.js +12 -0
  634. package/dist/project/components/BarList/README.md +757 -0
  635. package/dist/project/components/BarList/preview.html +2 -0
  636. package/dist/project/components/BarList/stories.js +12 -0
  637. package/dist/project/components/Breadcrumbs/README.md +274 -0
  638. package/dist/project/components/Breadcrumbs/preview.html +2 -0
  639. package/dist/project/components/Breadcrumbs/stories.js +12 -0
  640. package/dist/project/components/BulkBar/README.md +19 -0
  641. package/dist/project/components/Button/README.md +467 -0
  642. package/dist/project/components/Button/preview.html +2 -0
  643. package/dist/project/components/Button/stories.js +12 -0
  644. package/dist/project/components/Calendar/README.md +654 -0
  645. package/dist/project/components/Calendar/preview.html +2 -0
  646. package/dist/project/components/Calendar/stories.js +12 -0
  647. package/dist/project/components/Card/README.md +367 -0
  648. package/dist/project/components/Card/preview.html +2 -0
  649. package/dist/project/components/Card/stories.js +12 -0
  650. package/dist/project/components/ChainOfThought/README.md +412 -0
  651. package/dist/project/components/ChainOfThought/preview.html +2 -0
  652. package/dist/project/components/ChainOfThought/stories.js +12 -0
  653. package/dist/project/components/Chart/README.md +224 -0
  654. package/dist/project/components/Chart/preview.html +2 -0
  655. package/dist/project/components/Chart/stories.js +12 -0
  656. package/dist/project/components/Chat/README.md +1244 -0
  657. package/dist/project/components/Chat/preview.html +2 -0
  658. package/dist/project/components/Chat/stories.js +12 -0
  659. package/dist/project/components/ChatInput/README.md +378 -0
  660. package/dist/project/components/ChatInput/preview.html +2 -0
  661. package/dist/project/components/ChatInput/stories.js +12 -0
  662. package/dist/project/components/ChatPermissions/README.md +218 -0
  663. package/dist/project/components/ChatPermissions/preview.html +2 -0
  664. package/dist/project/components/ChatPermissions/stories.js +12 -0
  665. package/dist/project/components/Checkbox/README.md +367 -0
  666. package/dist/project/components/Checkbox/preview.html +2 -0
  667. package/dist/project/components/Checkbox/stories.js +12 -0
  668. package/dist/project/components/Code/README.md +243 -0
  669. package/dist/project/components/Code/preview.html +2 -0
  670. package/dist/project/components/Code/stories.js +12 -0
  671. package/dist/project/components/CodeEditor/README.md +280 -0
  672. package/dist/project/components/CodeEditor/preview.html +2 -0
  673. package/dist/project/components/CodeEditor/stories.js +162 -0
  674. package/dist/project/components/CodeEditor/stories.md +1533 -0
  675. package/dist/project/components/CodeSnippet/README.md +1352 -0
  676. package/dist/project/components/CodeSnippet/preview.html +2 -0
  677. package/dist/project/components/CodeSnippet/stories.js +156 -0
  678. package/dist/project/components/ColumnChart/README.md +521 -0
  679. package/dist/project/components/ColumnChart/preview.html +2 -0
  680. package/dist/project/components/ColumnChart/stories.js +12 -0
  681. package/dist/project/components/Conversation/README.md +314 -0
  682. package/dist/project/components/Conversation/preview.html +2 -0
  683. package/dist/project/components/Conversation/stories.js +12 -0
  684. package/dist/project/components/Copyable/README.md +406 -0
  685. package/dist/project/components/Copyable/preview.html +2 -0
  686. package/dist/project/components/Copyable/stories.js +12 -0
  687. package/dist/project/components/Country/README.md +226 -0
  688. package/dist/project/components/Country/preview.html +2 -0
  689. package/dist/project/components/Country/stories.js +12 -0
  690. package/dist/project/components/Cover/preview.html +43 -0
  691. package/dist/project/components/DateInput/README.md +458 -0
  692. package/dist/project/components/DateInput/preview.html +2 -0
  693. package/dist/project/components/DateInput/stories.js +12 -0
  694. package/dist/project/components/DateRangeInput/README.md +412 -0
  695. package/dist/project/components/DateRangeInput/preview.html +2 -0
  696. package/dist/project/components/DateRangeInput/stories.js +12 -0
  697. package/dist/project/components/Dialog/README.md +1140 -0
  698. package/dist/project/components/Dialog/preview.html +2 -0
  699. package/dist/project/components/Dialog/stories.js +12 -0
  700. package/dist/project/components/Drawer/README.md +1163 -0
  701. package/dist/project/components/Drawer/preview.html +2 -0
  702. package/dist/project/components/Drawer/stories.js +12 -0
  703. package/dist/project/components/DropdownMenu/README.md +678 -0
  704. package/dist/project/components/DropdownMenu/preview.html +2 -0
  705. package/dist/project/components/DropdownMenu/stories.js +12 -0
  706. package/dist/project/components/EmptyState/README.md +276 -0
  707. package/dist/project/components/EmptyState/preview.html +2 -0
  708. package/dist/project/components/EmptyState/stories.js +12 -0
  709. package/dist/project/components/FeedbackPulse/README.md +125 -0
  710. package/dist/project/components/FeedbackPulse/preview.html +2 -0
  711. package/dist/project/components/FeedbackPulse/stories.js +12 -0
  712. package/dist/project/components/Field/README.md +676 -0
  713. package/dist/project/components/Field/preview.html +2 -0
  714. package/dist/project/components/Field/stories.js +12 -0
  715. package/dist/project/components/FileUpload/README.md +544 -0
  716. package/dist/project/components/FileUpload/preview.html +2 -0
  717. package/dist/project/components/FileUpload/stories.js +12 -0
  718. package/dist/project/components/FilterCascade/README.md +348 -0
  719. package/dist/project/components/FilterCascade/preview.html +2 -0
  720. package/dist/project/components/FilterCascade/stories.js +12 -0
  721. package/dist/project/components/FilterDropdown/README.md +542 -0
  722. package/dist/project/components/FilterDropdown/preview.html +2 -0
  723. package/dist/project/components/FilterDropdown/stories.js +12 -0
  724. package/dist/project/components/FilterInput/README.md +416 -0
  725. package/dist/project/components/FilterInput/preview.html +2 -0
  726. package/dist/project/components/FilterInput/stories.js +12 -0
  727. package/dist/project/components/FilterInput/stories.md +6682 -0
  728. package/dist/project/components/Flex/README.md +225 -0
  729. package/dist/project/components/Flex/preview.html +2 -0
  730. package/dist/project/components/Flex/stories.js +12 -0
  731. package/dist/project/components/FormatDateTime/README.md +315 -0
  732. package/dist/project/components/FormatDateTime/preview.html +2 -0
  733. package/dist/project/components/FormatDateTime/stories.js +12 -0
  734. package/dist/project/components/FormatNumber/README.md +317 -0
  735. package/dist/project/components/FormatNumber/preview.html +2 -0
  736. package/dist/project/components/FormatNumber/stories.js +12 -0
  737. package/dist/project/components/Heading/README.md +240 -0
  738. package/dist/project/components/Heading/preview.html +2 -0
  739. package/dist/project/components/Heading/stories.js +12 -0
  740. package/dist/project/components/HorizontalBarStack/README.md +281 -0
  741. package/dist/project/components/HorizontalBarStack/preview.html +2 -0
  742. package/dist/project/components/HorizontalBarStack/stories.js +12 -0
  743. package/dist/project/components/HttpMethod/README.md +137 -0
  744. package/dist/project/components/HttpMethod/preview.html +2 -0
  745. package/dist/project/components/HttpMethod/stories.js +12 -0
  746. package/dist/project/components/ImageCropper/README.md +332 -0
  747. package/dist/project/components/ImageCropper/preview.html +2 -0
  748. package/dist/project/components/ImageCropper/stories.js +33 -0
  749. package/dist/project/components/Indicator/README.md +110 -0
  750. package/dist/project/components/Indicator/preview.html +2 -0
  751. package/dist/project/components/Indicator/stories.js +12 -0
  752. package/dist/project/components/InlineEdit/README.md +977 -0
  753. package/dist/project/components/InlineEdit/preview.html +2 -0
  754. package/dist/project/components/InlineEdit/stories.js +12 -0
  755. package/dist/project/components/Input/README.md +187 -0
  756. package/dist/project/components/Input/preview.html +2 -0
  757. package/dist/project/components/Input/stories.js +12 -0
  758. package/dist/project/components/InputGroup/README.md +423 -0
  759. package/dist/project/components/InputGroup/preview.html +2 -0
  760. package/dist/project/components/InputGroup/stories.js +12 -0
  761. package/dist/project/components/InputOTP/README.md +201 -0
  762. package/dist/project/components/InputOTP/preview.html +2 -0
  763. package/dist/project/components/InputOTP/stories.js +12 -0
  764. package/dist/project/components/Ip/README.md +226 -0
  765. package/dist/project/components/Ip/preview.html +2 -0
  766. package/dist/project/components/Ip/stories.js +12 -0
  767. package/dist/project/components/Kbd/README.md +126 -0
  768. package/dist/project/components/Kbd/preview.html +2 -0
  769. package/dist/project/components/Kbd/stories.js +12 -0
  770. package/dist/project/components/LineChart/README.md +1479 -0
  771. package/dist/project/components/LineChart/preview.html +2 -0
  772. package/dist/project/components/LineChart/stories.js +12 -0
  773. package/dist/project/components/Link/README.md +160 -0
  774. package/dist/project/components/Link/preview.html +2 -0
  775. package/dist/project/components/Link/stories.js +12 -0
  776. package/dist/project/components/List/README.md +181 -0
  777. package/dist/project/components/List/preview.html +2 -0
  778. package/dist/project/components/List/stories.js +12 -0
  779. package/dist/project/components/Loader/README.md +145 -0
  780. package/dist/project/components/Loader/preview.html +2 -0
  781. package/dist/project/components/Loader/stories.js +12 -0
  782. package/dist/project/components/Logo/README.md +183 -0
  783. package/dist/project/components/Logo/preview.html +2 -0
  784. package/dist/project/components/Logo/stories.js +12 -0
  785. package/dist/project/components/MessageActions/README.md +255 -0
  786. package/dist/project/components/MessageActions/preview.html +2 -0
  787. package/dist/project/components/MessageActions/stories.js +12 -0
  788. package/dist/project/components/Metric/README.md +324 -0
  789. package/dist/project/components/Metric/preview.html +2 -0
  790. package/dist/project/components/Metric/stories.js +12 -0
  791. package/dist/project/components/NavRail/README.md +25 -0
  792. package/dist/project/components/NotificationCenter/README.md +91 -0
  793. package/dist/project/components/NotificationCenter/preview.html +2 -0
  794. package/dist/project/components/NotificationCenter/stories.js +12 -0
  795. package/dist/project/components/NotificationCenter/stories.md +2170 -0
  796. package/dist/project/components/NumberInput/README.md +177 -0
  797. package/dist/project/components/NumberInput/preview.html +2 -0
  798. package/dist/project/components/NumberInput/stories.js +12 -0
  799. package/dist/project/components/NumericBadge/README.md +252 -0
  800. package/dist/project/components/NumericBadge/preview.html +2 -0
  801. package/dist/project/components/NumericBadge/stories.js +12 -0
  802. package/dist/project/components/OverflowList/README.md +324 -0
  803. package/dist/project/components/OverflowList/preview.html +2 -0
  804. package/dist/project/components/OverflowList/stories.js +12 -0
  805. package/dist/project/components/OverflowTooltip/README.md +421 -0
  806. package/dist/project/components/OverflowTooltip/preview.html +2 -0
  807. package/dist/project/components/OverflowTooltip/stories.js +12 -0
  808. package/dist/project/components/Overlay/README.md +95 -0
  809. package/dist/project/components/Overlay/preview.html +2 -0
  810. package/dist/project/components/Overlay/stories.js +12 -0
  811. package/dist/project/components/Overview/README.md +445 -0
  812. package/dist/project/components/Overview/preview.html +2 -0
  813. package/dist/project/components/Overview/stories.js +12 -0
  814. package/dist/project/components/Page/README.md +215 -0
  815. package/dist/project/components/Page/preview.html +2 -0
  816. package/dist/project/components/Page/stories.js +12 -0
  817. package/dist/project/components/Pagination/README.md +302 -0
  818. package/dist/project/components/Pagination/preview.html +2 -0
  819. package/dist/project/components/Pagination/stories.js +12 -0
  820. package/dist/project/components/ParameterPath/README.md +284 -0
  821. package/dist/project/components/ParameterPath/preview.html +2 -0
  822. package/dist/project/components/ParameterPath/stories.js +12 -0
  823. package/dist/project/components/PasswordComplexity/README.md +171 -0
  824. package/dist/project/components/PasswordComplexity/preview.html +2 -0
  825. package/dist/project/components/PasswordComplexity/stories.js +12 -0
  826. package/dist/project/components/PasswordInput/README.md +254 -0
  827. package/dist/project/components/PasswordInput/preview.html +2 -0
  828. package/dist/project/components/PasswordInput/stories.js +12 -0
  829. package/dist/project/components/PieChart/README.md +895 -0
  830. package/dist/project/components/PieChart/preview.html +2 -0
  831. package/dist/project/components/PieChart/stories.js +12 -0
  832. package/dist/project/components/Popover/README.md +282 -0
  833. package/dist/project/components/Popover/preview.html +2 -0
  834. package/dist/project/components/Popover/stories.js +12 -0
  835. package/dist/project/components/Progress/README.md +174 -0
  836. package/dist/project/components/Progress/preview.html +2 -0
  837. package/dist/project/components/Progress/stories.js +12 -0
  838. package/dist/project/components/Radio/README.md +264 -0
  839. package/dist/project/components/Radio/preview.html +2 -0
  840. package/dist/project/components/Radio/stories.js +12 -0
  841. package/dist/project/components/RemoteShell/README.md +1758 -0
  842. package/dist/project/components/RemoteShell/preview.html +2 -0
  843. package/dist/project/components/RemoteShell/stories.js +28 -0
  844. package/dist/project/components/Resizable/README.md +290 -0
  845. package/dist/project/components/Resizable/preview.html +2 -0
  846. package/dist/project/components/Resizable/stories.js +12 -0
  847. package/dist/project/components/ResponseCode/README.md +205 -0
  848. package/dist/project/components/ResponseCode/preview.html +2 -0
  849. package/dist/project/components/ResponseCode/stories.js +12 -0
  850. package/dist/project/components/ScrollArea/README.md +234 -0
  851. package/dist/project/components/ScrollArea/preview.html +2 -0
  852. package/dist/project/components/ScrollArea/stories.js +12 -0
  853. package/dist/project/components/SearchInput/README.md +158 -0
  854. package/dist/project/components/SearchInput/preview.html +2 -0
  855. package/dist/project/components/SearchInput/stories.js +12 -0
  856. package/dist/project/components/SearchModal/README.md +836 -0
  857. package/dist/project/components/SearchModal/preview.html +2 -0
  858. package/dist/project/components/SearchModal/stories.js +12 -0
  859. package/dist/project/components/SegmentedControl/README.md +382 -0
  860. package/dist/project/components/SegmentedControl/preview.html +2 -0
  861. package/dist/project/components/SegmentedControl/stories.js +12 -0
  862. package/dist/project/components/SegmentedTabs/README.md +390 -0
  863. package/dist/project/components/SegmentedTabs/preview.html +2 -0
  864. package/dist/project/components/SegmentedTabs/stories.js +12 -0
  865. package/dist/project/components/Select/README.md +1311 -0
  866. package/dist/project/components/Select/preview.html +2 -0
  867. package/dist/project/components/Select/stories.js +12 -0
  868. package/dist/project/components/Selection/README.md +648 -0
  869. package/dist/project/components/Selection/preview.html +2 -0
  870. package/dist/project/components/Selection/stories.js +12 -0
  871. package/dist/project/components/Separator/README.md +77 -0
  872. package/dist/project/components/Separator/preview.html +2 -0
  873. package/dist/project/components/Separator/stories.js +12 -0
  874. package/dist/project/components/Skeleton/README.md +358 -0
  875. package/dist/project/components/Skeleton/preview.html +2 -0
  876. package/dist/project/components/Skeleton/stories.js +12 -0
  877. package/dist/project/components/Slider/README.md +433 -0
  878. package/dist/project/components/Slider/preview.html +2 -0
  879. package/dist/project/components/Slider/stories.js +12 -0
  880. package/dist/project/components/SplashScreen/README.md +192 -0
  881. package/dist/project/components/SplashScreen/preview.html +2 -0
  882. package/dist/project/components/SplashScreen/stories.js +12 -0
  883. package/dist/project/components/SplitButton/README.md +402 -0
  884. package/dist/project/components/SplitButton/preview.html +2 -0
  885. package/dist/project/components/SplitButton/stories.js +12 -0
  886. package/dist/project/components/Stack/README.md +269 -0
  887. package/dist/project/components/Stack/preview.html +2 -0
  888. package/dist/project/components/Stack/stories.js +12 -0
  889. package/dist/project/components/Stepper/README.md +682 -0
  890. package/dist/project/components/Stepper/preview.html +2 -0
  891. package/dist/project/components/Stepper/stories.js +12 -0
  892. package/dist/project/components/Switch/README.md +236 -0
  893. package/dist/project/components/Switch/preview.html +2 -0
  894. package/dist/project/components/Switch/stories.js +12 -0
  895. package/dist/project/components/Table/README.md +471 -0
  896. package/dist/project/components/Table/preview.html +2 -0
  897. package/dist/project/components/Table/stories.js +12 -0
  898. package/dist/project/components/Table/stories.md +3697 -0
  899. package/dist/project/components/Tabs/README.md +443 -0
  900. package/dist/project/components/Tabs/preview.html +2 -0
  901. package/dist/project/components/Tabs/stories.js +12 -0
  902. package/dist/project/components/Tag/README.md +324 -0
  903. package/dist/project/components/Tag/preview.html +2 -0
  904. package/dist/project/components/Tag/stories.js +12 -0
  905. package/dist/project/components/Text/README.md +200 -0
  906. package/dist/project/components/Text/preview.html +2 -0
  907. package/dist/project/components/Text/stories.js +12 -0
  908. package/dist/project/components/Textarea/README.md +273 -0
  909. package/dist/project/components/Textarea/preview.html +2 -0
  910. package/dist/project/components/Textarea/stories.js +12 -0
  911. package/dist/project/components/TimeInput/README.md +359 -0
  912. package/dist/project/components/TimeInput/preview.html +2 -0
  913. package/dist/project/components/TimeInput/stories.js +12 -0
  914. package/dist/project/components/Timeline/README.md +204 -0
  915. package/dist/project/components/Timeline/preview.html +2 -0
  916. package/dist/project/components/Timeline/stories.js +12 -0
  917. package/dist/project/components/Toast/README.md +718 -0
  918. package/dist/project/components/Toast/preview.html +2 -0
  919. package/dist/project/components/Toast/stories.js +12 -0
  920. package/dist/project/components/ToggleButton/README.md +292 -0
  921. package/dist/project/components/ToggleButton/preview.html +2 -0
  922. package/dist/project/components/ToggleButton/stories.js +12 -0
  923. package/dist/project/components/Tooltip/README.md +199 -0
  924. package/dist/project/components/Tooltip/preview.html +2 -0
  925. package/dist/project/components/Tooltip/stories.js +12 -0
  926. package/dist/project/components/TopHeader/README.md +21 -0
  927. package/dist/project/components/Tour/README.md +532 -0
  928. package/dist/project/components/Tour/preview.html +2 -0
  929. package/dist/project/components/Tour/stories.js +12 -0
  930. package/dist/project/components/Tree/README.md +450 -0
  931. package/dist/project/components/Tree/preview.html +2 -0
  932. package/dist/project/components/Tree/stories.js +12 -0
  933. package/dist/project/components/TreeView/README.md +531 -0
  934. package/dist/project/components/TreeView/preview.html +2 -0
  935. package/dist/project/components/TreeView/stories.js +12 -0
  936. package/dist/project/components/UTILITIES.md +647 -0
  937. package/dist/project/components/UserMessage/README.md +166 -0
  938. package/dist/project/components/UserMessage/preview.html +2 -0
  939. package/dist/project/components/UserMessage/stories.js +12 -0
  940. package/dist/project/components/UtilityPage/README.md +147 -0
  941. package/dist/project/components/UtilityPage/preview.html +2 -0
  942. package/dist/project/components/UtilityPage/stories.js +12 -0
  943. package/dist/project/components/WallyAssistant/README.md +1380 -0
  944. package/dist/project/components/WallyAssistant/preview.html +2 -0
  945. package/dist/project/components/WallyAssistant/stories.js +12 -0
  946. package/dist/project/components/WallyIcon/README.md +130 -0
  947. package/dist/project/components/WallyIcon/preview.html +2 -0
  948. package/dist/project/components/WallyIcon/stories.js +12 -0
  949. package/dist/project/components/WallySkeleton/README.md +96 -0
  950. package/dist/project/components/WallySkeleton/preview.html +2 -0
  951. package/dist/project/components/WallySkeleton/stories.js +12 -0
  952. package/dist/project/components/bundle.css +18734 -0
  953. package/dist/project/components/bundle.js +167 -0
  954. package/dist/project/components/index.d.ts +27226 -0
  955. package/dist/project/design-system.json +35 -0
  956. package/dist/project/fonts/Geist-Variable.woff2 +0 -0
  957. package/dist/project/fonts/GeistMono-Variable.woff2 +0 -0
  958. package/dist/project/fonts/GeistPixel-Square.woff2 +0 -0
  959. package/dist/project/sampler.dc.html +238 -0
  960. package/dist/project/tokens.css +1395 -0
  961. package/dist/project/tokens.json +5235 -0
  962. package/dist/wallarm-sampler.dc.html +239 -0
  963. package/package.json +67 -3
@@ -0,0 +1,1479 @@
1
+ A time series in the family's card — request volume, error rate, latency, anything where the X axis reads left to right; reach for `BarList` for a top-N comparison and `PieChart` for a share of a total. Every part is an opt-in child, so a bare sparkline and a fully instrumented panel are the same component with different children, and hover, filtering and zoom all travel through one context.
2
+
3
+ ## Props as canvas attributes
4
+
5
+ Use kebab-case attribute names. Pass non-string values through renderVals holes, including booleans. The full emitted API is in `components/index.d.ts`.
6
+
7
+ | Attribute | Type | Required | Default | Description |
8
+ | --- | --- | --- | --- | --- |
9
+ | `data` | `T[]` | yes | — | Long-form data array, one entry per X position. |
10
+ | `series` | `complex` | yes | — | Schema describing each line drawn from `data`. |
11
+ | `x-key` | `Extract<keyof T, string>` | yes | — | Key on each datum used as the X-axis value. Required — a silent fallback would hide key-name typos until the chart renders empty. |
12
+ | `active-key` | `string \| null \| undefined` | no | — | Controlled hover key — pass alongside `onActiveKeyChange` for cross-chart sync. **Heads-up:** if the controlled value points at a series key that no longer exists in `series` (filter, schema change, refresh), the chart pushes `null` back through `onActiveKeyChange` so sibling charts stop highlighting a stale key. If you wire `activeKey` to external state, the snap-to-null write will arrive as a normal state change — do not be surprised when your value resets after a series disappears. |
13
+ | `on-active-key-change` | `((key: string \| null) => void) \| undefined` | no | — | |
14
+ | `filtered-keys` | `string[] \| undefined` | no | — | Controlled set of `series.key` values to hide from the plot. |
15
+ | `on-zoom-change` | `complex` | no | — | Fired after the user confirms a brush selection. |
16
+ | `sync-id` | `string \| number \| undefined` | no | — | Charts that share a `syncId` synchronise their tooltip cursor and brush via recharts' built-in middleware — hovering one chart highlights the matching X on every sibling chart with the same id. Pair with `activeKey` + `onActiveKeyChange` if you also want the *series* highlight to sync. |
17
+ | `sync-method` | `complex` | no | — | How sibling `syncId` charts match X positions. Defaults to `'index'` (Recharts' default). Use `'value'` when the synced charts have different dataset lengths but share categorical X values. |
18
+ | `default-checked` | `boolean \| undefined` | no | — | |
19
+ | `default-value` | `string \| number \| readonly string[] \| undefined` | no | — | |
20
+ | `auto-focus` | `boolean \| undefined` | no | — | |
21
+ | `id` | `string \| undefined` | no | — | |
22
+ | `tab-index` | `number \| undefined` | no | — | |
23
+ | `title` | `string \| undefined` | no | — | |
24
+ | `rel` | `string \| undefined` | no | — | |
25
+ | `on-change` | `ChangeEventHandler<T, Element> \| undefined` | no | — | |
26
+ | `data-testid` | `string \| undefined` | no | — | |
27
+
28
+ ## Sub-components
29
+
30
+ - `WallarmDS.LineChartBody` — `LineChartBodyProps` in the declaration bundle.
31
+ - `WallarmDS.LineChartEmpty` — `LineChartEmptyProps` in the declaration bundle.
32
+ - `WallarmDS.LineChartGrid` — `LineChartGridProps` in the declaration bundle.
33
+ - `WallarmDS.LineChartHoverPopoverDot` — `LineChartHoverPopoverDotProps` in the declaration bundle.
34
+ - `WallarmDS.LineChartHoverPopover` — `LineChartHoverPopoverProps` in the declaration bundle.
35
+ - `WallarmDS.LineChartHoverPopoverRow` — `LineChartHoverPopoverRowProps` in the declaration bundle.
36
+ - `WallarmDS.LineChartHoverPopoverTimestamp` — `LineChartHoverPopoverTimestampProps` in the declaration bundle.
37
+ - `WallarmDS.LineChartLegendItem` — `LineChartLegendItemProps` in the declaration bundle.
38
+ - `WallarmDS.LineChartLegend` — `LineChartLegendProps` in the declaration bundle.
39
+ - `WallarmDS.LineChartLine` — `LineChartLineProps` in the declaration bundle.
40
+ - `WallarmDS.LineChartTooltip` — `LineChartTooltipProps` in the declaration bundle.
41
+ - `WallarmDS.LineChartXAxis` — `LineChartXAxisProps` in the declaration bundle.
42
+ - `WallarmDS.LineChartYAxis` — `LineChartYAxisProps` in the declaration bundle.
43
+ - `WallarmDS.LineChartZoomBrush` — `LineChartZoomBrushProps` in the declaration bundle.
44
+ - `WallarmDS.LineChartZoomPopoverConfirm` — `LineChartZoomPopoverConfirmProps` in the declaration bundle.
45
+ - `WallarmDS.LineChartZoomPopover` — `LineChartZoomPopoverProps` in the declaration bundle.
46
+ - `WallarmDS.LineChartZoomPopoverRange` — `LineChartZoomPopoverRangeProps` in the declaration bundle.
47
+
48
+ ## Stories
49
+
50
+ ### Default
51
+
52
+ One series with the full chrome — grid, both axes, and a tooltip that follows the pointer
53
+ along the line.
54
+
55
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#Default
56
+
57
+ ### DefaultMulti
58
+
59
+ Three series with a legend composed from `LineChartLegendItem` rows. The dot in each row is
60
+ the same one the tooltip uses, so the colours cannot drift apart.
61
+
62
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#DefaultMulti
63
+
64
+ ### WithMetric
65
+
66
+ The metric variant: the shared `Metric` bricks sit to the left of the legend in a row of
67
+ their own between the header and the plot. Pure composition — the chart is untouched and the
68
+ card simply grows by that row.
69
+
70
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#WithMetric
71
+
72
+ ### Curves
73
+
74
+ Straight joins tell the truth about where the samples are; `monotone` smooths between them
75
+ and reads better for a rate. Mix the two only when the series mean genuinely different
76
+ things.
77
+
78
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#Curves
79
+
80
+ ### LineStyling
81
+
82
+ A dashed series against a solid one — the way to separate a threshold or a projection from
83
+ measured data — and a CSS colour string for a series whose colour is decided elsewhere.
84
+
85
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#LineStyling
86
+
87
+ ### EdgeCases
88
+
89
+ The three shapes that break naive charts: a sparkline with no chrome at all, a single data
90
+ point, and a series with null gaps, which has to break the line rather than bridge it.
91
+
92
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#EdgeCases
93
+
94
+ ### CustomTooltip
95
+
96
+ Composing the hover popover yourself, a `LineChartHoverPopoverRow` per series, for when a
97
+ value needs its unit rather than the default name-and-number.
98
+
99
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#CustomTooltip
100
+
101
+ ### LegendPlacements
102
+
103
+ Legend placement is structural rather than a prop: JSX order picks top or bottom, and
104
+ wrapping the body and the legend in an `HStack` picks left or right, where a vertical
105
+ orientation stacks its rows.
106
+
107
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#LegendPlacements
108
+
109
+ ### Filterable
110
+
111
+ Clicking a legend row isolates that series and clicking another adds it back, with the
112
+ header's clear control appearing while anything is hidden.
113
+
114
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#Filterable
115
+
116
+ ### CrossChartHoverSync
117
+
118
+ Two cards sharing a pointer, and it takes two mechanisms: `syncId` lines up the cursor and
119
+ tooltip through recharts, while `activeKey` shares the series highlight through our own
120
+ context.
121
+
122
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#CrossChartHoverSync
123
+
124
+ ### Zoom
125
+
126
+ Drag across the plot to choose a range, then confirm in the popover — Enter or the button
127
+ emits `onZoomChange`, while Escape, an outside click or a new drag dismisses it. Slicing the
128
+ data to that range is yours, and so is the way back out.
129
+
130
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#Zoom
131
+
132
+ ### Loading
133
+
134
+ There is no `loading` prop: the state is composed from the same primitives as a populated
135
+ chart — `Skeleton` chips inside the legend and a bare `LineChartEmpty` for the dashed plot —
136
+ with `aria-busy` on the `Chart` left to the caller.
137
+
138
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#Loading
139
+
140
+ ### Refreshing
141
+
142
+ Each panel loads for two seconds before swapping to data, and the refresh button replays it.
143
+ The skeleton and the real chart share an outer layout, so nothing but the content moves on
144
+ the swap.
145
+
146
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#Refreshing
147
+
148
+ ### Empty
149
+
150
+ `LineChartEmpty` keeps the dashed plot frame and puts the message inside it, so a card with
151
+ no data still reads as a chart rather than as something broken.
152
+
153
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#Empty
154
+
155
+ ### LongTimeRange
156
+
157
+ A thousand hourly samples in one card: drag to zoom and the header's control restores the
158
+ full range. The story slices the data itself, exactly as a consumer has to.
159
+
160
+ Source: SimpleCharts/LineChart/LineChart.stories.tsx#LongTimeRange
161
+
162
+ ## Story sources
163
+
164
+ ### SimpleCharts/LineChart/LineChart.stories.tsx
165
+
166
+ ```tsx
167
+ import { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
168
+ import type { Meta, StoryFn } from 'storybook-react-rsbuild';
169
+ import { FilterX, RefreshCcw, ZoomOut } from '../../../icons';
170
+ import { formatFullNumber } from '../../../utils/abbreviateNumber';
171
+ import { Button } from '../../Button';
172
+ import { Skeleton } from '../../Skeleton';
173
+ import { HStack } from '../../Stack';
174
+ import { Tooltip, TooltipContent, TooltipTrigger } from '../../Tooltip';
175
+ import { Chart } from '../Chart/Chart';
176
+ import { ChartActions } from '../Chart/ChartActions';
177
+ import { ChartHeader } from '../Chart/ChartHeader';
178
+ import { ChartTitle } from '../Chart/ChartTitle';
179
+ import { useChartTimeFormatters } from '../hooks/useChartTimeFormatters';
180
+ import { MetricDelta } from '../Metric/MetricDelta';
181
+ import { MetricHeader } from '../Metric/MetricHeader';
182
+ import { MetricValue } from '../Metric/MetricValue';
183
+ import { LineChart } from './LineChart';
184
+ import { LineChartBody } from './LineChartBody';
185
+ import type { LineChartSeries, LineChartZoomRange } from './LineChartContext';
186
+ import { LineChartEmpty } from './LineChartEmpty';
187
+ import { LineChartGrid } from './LineChartGrid';
188
+ import { LineChartHoverPopover } from './LineChartHoverPopover';
189
+ import { LineChartHoverPopoverDot } from './LineChartHoverPopoverDot';
190
+ import { LineChartHoverPopoverRow } from './LineChartHoverPopoverRow';
191
+ import { LineChartHoverPopoverTimestamp } from './LineChartHoverPopoverTimestamp';
192
+ import { LineChartLegend } from './LineChartLegend';
193
+ import { LineChartLegendItem } from './LineChartLegendItem';
194
+ import { LineChartLine } from './LineChartLine';
195
+ import { LineChartTooltip } from './LineChartTooltip';
196
+ import { LineChartXAxis } from './LineChartXAxis';
197
+ import { LineChartYAxis } from './LineChartYAxis';
198
+ import { LineChartZoomBrush } from './LineChartZoomBrush';
199
+ import { formatRange } from './lib/formatRange';
200
+ import {
201
+ customColorSeries,
202
+ dailyData60,
203
+ dashedSeries,
204
+ dataWithErrorGaps,
205
+ hourlyData24,
206
+ hourlyData1000,
207
+ hourlyDataA,
208
+ hourlyDataB,
209
+ multiSeries,
210
+ singlePointData,
211
+ singleSeries,
212
+ unitsByKey,
213
+ } from './lib/sampleData';
214
+
215
+ const formatYTick = (value: unknown) => formatFullNumber(Number(value));
216
+
217
+ const DESCRIPTION = [
218
+ "A time series in the family's card — request volume, error rate, latency, anything where the X axis reads left to right; reach for `BarList` for a top-N comparison and `PieChart` for a share of a total.",
219
+ 'Every part is an opt-in child, so a bare sparkline and a fully instrumented panel are the same component with different children, and hover, filtering and zoom all travel through one context.',
220
+ ].join(' ');
221
+
222
+ const meta = {
223
+ title: 'Data Display/SimpleCharts/LineChart',
224
+ component: LineChart,
225
+ subcomponents: {
226
+ LineChartBody,
227
+ LineChartGrid,
228
+ LineChartXAxis,
229
+ LineChartYAxis,
230
+ LineChartLine,
231
+ LineChartTooltip,
232
+ LineChartHoverPopover,
233
+ LineChartHoverPopoverTimestamp,
234
+ LineChartHoverPopoverRow,
235
+ LineChartHoverPopoverDot,
236
+ LineChartLegend,
237
+ LineChartLegendItem,
238
+ LineChartZoomBrush,
239
+ LineChartEmpty,
240
+ },
241
+ parameters: {
242
+ layout: 'padded',
243
+ design: {
244
+ type: 'figma',
245
+ url: 'https://www.figma.com/design/VKb5gW46uSGw0rqrhZsbXT/WADS-Components?node-id=7490-123142&m=dev',
246
+ },
247
+ docs: { description: { component: DESCRIPTION } },
248
+ },
249
+ tags: ['autodocs'],
250
+ } satisfies Meta<typeof LineChart>;
251
+
252
+ export default meta;
253
+
254
+ /**
255
+ * One series with the full chrome — grid, both axes, and a tooltip that follows the pointer
256
+ * along the line.
257
+ */
258
+ export const Default: StoryFn<typeof meta> = () => {
259
+ const { formatHour, formatHourWithTimezone } = useChartTimeFormatters();
260
+ return (
261
+ <div className='w-560'>
262
+ <Chart>
263
+ <ChartHeader>
264
+ <ChartTitle>Requests per hour</ChartTitle>
265
+ </ChartHeader>
266
+ <LineChart data={hourlyData24} series={singleSeries} xKey='timestamp'>
267
+ <LineChartBody>
268
+ <LineChartGrid />
269
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
270
+ <LineChartYAxis tickFormatter={formatYTick} />
271
+ <LineChartLine seriesKey='requests' curve='linear' />
272
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
273
+ </LineChartBody>
274
+ </LineChart>
275
+ </Chart>
276
+ </div>
277
+ );
278
+ };
279
+
280
+ Default.parameters = {
281
+ design: {
282
+ type: 'figma',
283
+ url: 'https://www.figma.com/design/VKb5gW46uSGw0rqrhZsbXT/WADS-Components?node-id=7490-123143&m=dev',
284
+ },
285
+ };
286
+
287
+ /**
288
+ * Three series with a legend composed from `LineChartLegendItem` rows. The dot in each row is
289
+ * the same one the tooltip uses, so the colours cannot drift apart.
290
+ */
291
+ export const DefaultMulti: StoryFn<typeof meta> = () => {
292
+ const { formatHour, formatHourWithTimezone } = useChartTimeFormatters();
293
+ return (
294
+ <div className='w-560'>
295
+ <Chart data-testid='chart'>
296
+ <ChartHeader>
297
+ <ChartTitle>Traffic, errors, and latency</ChartTitle>
298
+ </ChartHeader>
299
+ <LineChart
300
+ data-testid='line-chart'
301
+ data={hourlyData24}
302
+ series={multiSeries}
303
+ xKey='timestamp'
304
+ >
305
+ <LineChartLegend>
306
+ {multiSeries.map(s => (
307
+ <LineChartLegendItem key={s.key} seriesKey={s.key}>
308
+ <LineChartHoverPopoverDot color={s.color} />
309
+ <span className='text-xs font-mono text-text-primary'>{s.label}</span>
310
+ </LineChartLegendItem>
311
+ ))}
312
+ </LineChartLegend>
313
+ <LineChartBody>
314
+ <LineChartGrid />
315
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
316
+ <LineChartYAxis tickFormatter={formatYTick} />
317
+ {multiSeries.map(s => (
318
+ <LineChartLine key={s.key} seriesKey={s.key} />
319
+ ))}
320
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
321
+ </LineChartBody>
322
+ </LineChart>
323
+ </Chart>
324
+ </div>
325
+ );
326
+ };
327
+
328
+ DefaultMulti.parameters = {
329
+ design: {
330
+ type: 'figma',
331
+ url: 'https://www.figma.com/design/VKb5gW46uSGw0rqrhZsbXT/WADS-Components?node-id=7509-2355&m=dev',
332
+ },
333
+ };
334
+
335
+ const MultiLegend = ({ series = multiSeries }: { series?: LineChartSeries[] }) => (
336
+ <LineChartLegend>
337
+ {series.map(s => (
338
+ <LineChartLegendItem key={s.key} seriesKey={s.key}>
339
+ <LineChartHoverPopoverDot color={s.color} />
340
+ <span className='text-xs font-mono text-text-primary'>{s.label}</span>
341
+ </LineChartLegendItem>
342
+ ))}
343
+ </LineChartLegend>
344
+ );
345
+
346
+ /**
347
+ * The metric variant: the shared `Metric` bricks sit to the left of the legend in a row of
348
+ * their own between the header and the plot. Pure composition — the chart is untouched and the
349
+ * card simply grows by that row.
350
+ */
351
+ export const WithMetric: StoryFn<typeof meta> = () => {
352
+ const { formatHour, formatHourWithTimezone } = useChartTimeFormatters();
353
+ return (
354
+ <div className='w-800'>
355
+ <Chart>
356
+ <ChartHeader>
357
+ <ChartTitle>Requests per hour</ChartTitle>
358
+ </ChartHeader>
359
+ <LineChart data={hourlyData24} series={multiSeries} xKey='timestamp'>
360
+ <div className='flex items-center justify-between pr-8'>
361
+ <MetricHeader className='px-16'>
362
+ <MetricValue>{2903}</MetricValue>
363
+ <MetricDelta value={10} trend='up' sentiment='negative' />
364
+ </MetricHeader>
365
+ <MultiLegend />
366
+ </div>
367
+ <LineChartBody>
368
+ <LineChartGrid />
369
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
370
+ <LineChartYAxis tickFormatter={formatYTick} />
371
+ {multiSeries.map(s => (
372
+ <LineChartLine key={s.key} seriesKey={s.key} />
373
+ ))}
374
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
375
+ </LineChartBody>
376
+ </LineChart>
377
+ </Chart>
378
+ </div>
379
+ );
380
+ };
381
+
382
+ WithMetric.parameters = {
383
+ design: {
384
+ type: 'figma',
385
+ url: 'https://www.figma.com/design/VKb5gW46uSGw0rqrhZsbXT/WADS-Components?node-id=11626-37312',
386
+ },
387
+ };
388
+
389
+ /**
390
+ * Straight joins tell the truth about where the samples are; `monotone` smooths between them
391
+ * and reads better for a rate. Mix the two only when the series mean genuinely different
392
+ * things.
393
+ */
394
+ export const Curves: StoryFn<typeof meta> = () => {
395
+ const { formatHour, formatHourWithTimezone } = useChartTimeFormatters();
396
+ return (
397
+ <div className='grid grid-cols-2 gap-16 w-1120'>
398
+ <Chart>
399
+ <ChartHeader>
400
+ <ChartTitle>Linear interpolation</ChartTitle>
401
+ </ChartHeader>
402
+ <LineChart data={hourlyData24} series={multiSeries} xKey='timestamp'>
403
+ <MultiLegend />
404
+ <LineChartBody>
405
+ <LineChartGrid />
406
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
407
+ <LineChartYAxis tickFormatter={formatYTick} />
408
+ {multiSeries.map(s => (
409
+ <LineChartLine key={s.key} seriesKey={s.key} curve='linear' />
410
+ ))}
411
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
412
+ </LineChartBody>
413
+ </LineChart>
414
+ </Chart>
415
+
416
+ <Chart>
417
+ <ChartHeader>
418
+ <ChartTitle>Mixed curves — monotone vs linear</ChartTitle>
419
+ </ChartHeader>
420
+ <LineChart data={hourlyData24} series={multiSeries} xKey='timestamp'>
421
+ <MultiLegend />
422
+ <LineChartBody>
423
+ <LineChartGrid />
424
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
425
+ <LineChartYAxis tickFormatter={formatYTick} />
426
+ <LineChartLine seriesKey='requests' curve='monotone' />
427
+ <LineChartLine seriesKey='errors' curve='linear' />
428
+ <LineChartLine seriesKey='latency' curve='linear' />
429
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
430
+ </LineChartBody>
431
+ </LineChart>
432
+ </Chart>
433
+ </div>
434
+ );
435
+ };
436
+
437
+ /**
438
+ * A dashed series against a solid one — the way to separate a threshold or a projection from
439
+ * measured data — and a CSS colour string for a series whose colour is decided elsewhere.
440
+ */
441
+ export const LineStyling: StoryFn<typeof meta> = () => {
442
+ const { formatHour, formatHourWithTimezone } = useChartTimeFormatters();
443
+ return (
444
+ <div className='grid grid-cols-2 gap-16 w-1120'>
445
+ <Chart>
446
+ <ChartHeader>
447
+ <ChartTitle>Solid + dashed series</ChartTitle>
448
+ </ChartHeader>
449
+ <LineChart data={hourlyData24} series={dashedSeries} xKey='timestamp'>
450
+ <MultiLegend series={dashedSeries} />
451
+ <LineChartBody>
452
+ <LineChartGrid />
453
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
454
+ <LineChartYAxis tickFormatter={formatYTick} />
455
+ {dashedSeries.map(s => (
456
+ <LineChartLine key={s.key} seriesKey={s.key} />
457
+ ))}
458
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
459
+ </LineChartBody>
460
+ </LineChart>
461
+ </Chart>
462
+
463
+ <Chart>
464
+ <ChartHeader>
465
+ <ChartTitle>Custom palette via CSS color string</ChartTitle>
466
+ </ChartHeader>
467
+ <LineChart data={hourlyData24} series={customColorSeries} xKey='timestamp'>
468
+ <MultiLegend series={customColorSeries} />
469
+ <LineChartBody>
470
+ <LineChartGrid />
471
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
472
+ <LineChartYAxis tickFormatter={formatYTick} />
473
+ {customColorSeries.map(s => (
474
+ <LineChartLine key={s.key} seriesKey={s.key} />
475
+ ))}
476
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
477
+ </LineChartBody>
478
+ </LineChart>
479
+ </Chart>
480
+ </div>
481
+ );
482
+ };
483
+
484
+ /**
485
+ * The three shapes that break naive charts: a sparkline with no chrome at all, a single data
486
+ * point, and a series with null gaps, which has to break the line rather than bridge it.
487
+ */
488
+ export const EdgeCases: StoryFn<typeof meta> = () => {
489
+ const { formatHour, formatHourWithTimezone } = useChartTimeFormatters();
490
+ return (
491
+ <div className='grid grid-cols-2 gap-16 w-1120'>
492
+ <Chart>
493
+ <ChartHeader>
494
+ <ChartTitle>Sparkline — no chrome</ChartTitle>
495
+ </ChartHeader>
496
+ <LineChart data={hourlyData24} series={singleSeries} xKey='timestamp'>
497
+ <LineChartBody>
498
+ <LineChartLine seriesKey='requests' />
499
+ </LineChartBody>
500
+ </LineChart>
501
+ </Chart>
502
+
503
+ <Chart>
504
+ <ChartHeader>
505
+ <ChartTitle>Single data point</ChartTitle>
506
+ </ChartHeader>
507
+ <LineChart data={singlePointData} series={singleSeries} xKey='timestamp'>
508
+ <LineChartBody>
509
+ <LineChartGrid />
510
+ <LineChartXAxis tickFormatter={formatHour} />
511
+ <LineChartYAxis tickFormatter={formatYTick} />
512
+ <LineChartLine seriesKey='requests' />
513
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
514
+ </LineChartBody>
515
+ </LineChart>
516
+ </Chart>
517
+
518
+ <Chart>
519
+ <ChartHeader>
520
+ <ChartTitle>Series with null gaps</ChartTitle>
521
+ </ChartHeader>
522
+ <LineChart data={dataWithErrorGaps} series={multiSeries} xKey='timestamp'>
523
+ <MultiLegend />
524
+ <LineChartBody>
525
+ <LineChartGrid />
526
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
527
+ <LineChartYAxis tickFormatter={formatYTick} />
528
+ {multiSeries.map(s => (
529
+ <LineChartLine key={s.key} seriesKey={s.key} />
530
+ ))}
531
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
532
+ </LineChartBody>
533
+ </LineChart>
534
+ </Chart>
535
+ </div>
536
+ );
537
+ };
538
+
539
+ /**
540
+ * Composing the hover popover yourself, a `LineChartHoverPopoverRow` per series, for when a
541
+ * value needs its unit rather than the default name-and-number.
542
+ */
543
+ export const CustomTooltip: StoryFn<typeof meta> = () => {
544
+ const { formatHour, formatHourWithTimezone } = useChartTimeFormatters();
545
+ return (
546
+ <div className='w-560'>
547
+ <Chart>
548
+ <ChartHeader>
549
+ <ChartTitle>Custom tooltip with units</ChartTitle>
550
+ </ChartHeader>
551
+ <LineChart data={hourlyData24} series={multiSeries} xKey='timestamp'>
552
+ <LineChartLegend>
553
+ {multiSeries.map(s => (
554
+ <LineChartLegendItem key={s.key} seriesKey={s.key}>
555
+ <LineChartHoverPopoverDot color={s.color} />
556
+ <span className='text-xs font-mono text-text-primary'>{s.label}</span>
557
+ </LineChartLegendItem>
558
+ ))}
559
+ </LineChartLegend>
560
+ <LineChartBody>
561
+ <LineChartGrid />
562
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
563
+ <LineChartYAxis tickFormatter={formatYTick} />
564
+ {multiSeries.map(s => (
565
+ <LineChartLine key={s.key} seriesKey={s.key} />
566
+ ))}
567
+ <LineChartTooltip>
568
+ {({ rows, xValue }) => (
569
+ <LineChartHoverPopover>
570
+ <LineChartHoverPopoverTimestamp>
571
+ {formatHourWithTimezone(xValue)}
572
+ </LineChartHoverPopoverTimestamp>
573
+ {rows.map(({ series: s, value: raw }) => {
574
+ const value = typeof raw === 'number' ? raw : 0;
575
+ const unit = unitsByKey[s.key] ?? '';
576
+ return (
577
+ <LineChartHoverPopoverRow
578
+ key={s.key}
579
+ series={s}
580
+ value={value}
581
+ formatValue={v =>
582
+ `${typeof v === 'number' ? formatFullNumber(v) : String(v ?? '')}${unit}`
583
+ }
584
+ />
585
+ );
586
+ })}
587
+ </LineChartHoverPopover>
588
+ )}
589
+ </LineChartTooltip>
590
+ </LineChartBody>
591
+ </LineChart>
592
+ </Chart>
593
+ </div>
594
+ );
595
+ };
596
+
597
+ /**
598
+ * Legend placement is structural rather than a prop: JSX order picks top or bottom, and
599
+ * wrapping the body and the legend in an `HStack` picks left or right, where a vertical
600
+ * orientation stacks its rows.
601
+ */
602
+ export const LegendPlacements: StoryFn<typeof meta> = () => {
603
+ const { formatHour, formatHourWithTimezone } = useChartTimeFormatters();
604
+ return (
605
+ <div className='grid grid-cols-2 gap-16 w-1120'>
606
+ <Chart>
607
+ <ChartHeader>
608
+ <ChartTitle>Top — JSX order</ChartTitle>
609
+ </ChartHeader>
610
+ <LineChart data={hourlyData24} series={multiSeries} xKey='timestamp'>
611
+ <LineChartLegend>
612
+ {multiSeries.map(s => (
613
+ <LineChartLegendItem key={s.key} seriesKey={s.key}>
614
+ <LineChartHoverPopoverDot color={s.color} />
615
+ <span className='text-xs font-mono text-text-primary'>{s.label}</span>
616
+ </LineChartLegendItem>
617
+ ))}
618
+ </LineChartLegend>
619
+ <LineChartBody>
620
+ <LineChartGrid />
621
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
622
+ <LineChartYAxis tickFormatter={formatYTick} />
623
+ {multiSeries.map(s => (
624
+ <LineChartLine key={s.key} seriesKey={s.key} />
625
+ ))}
626
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
627
+ </LineChartBody>
628
+ </LineChart>
629
+ </Chart>
630
+
631
+ <Chart>
632
+ <ChartHeader>
633
+ <ChartTitle>Bottom — JSX order</ChartTitle>
634
+ </ChartHeader>
635
+ <LineChart data={hourlyData24} series={multiSeries} xKey='timestamp'>
636
+ <LineChartBody>
637
+ <LineChartGrid />
638
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
639
+ <LineChartYAxis tickFormatter={formatYTick} />
640
+ {multiSeries.map(s => (
641
+ <LineChartLine key={s.key} seriesKey={s.key} />
642
+ ))}
643
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
644
+ </LineChartBody>
645
+ <LineChartLegend>
646
+ {multiSeries.map(s => (
647
+ <LineChartLegendItem key={s.key} seriesKey={s.key}>
648
+ <LineChartHoverPopoverDot color={s.color} />
649
+ <span className='text-xs font-mono text-text-primary'>{s.label}</span>
650
+ </LineChartLegendItem>
651
+ ))}
652
+ </LineChartLegend>
653
+ </LineChart>
654
+ </Chart>
655
+
656
+ <Chart>
657
+ <ChartHeader>
658
+ <ChartTitle>Left — wrapped in HStack</ChartTitle>
659
+ </ChartHeader>
660
+ <LineChart data={hourlyData24} series={multiSeries} xKey='timestamp'>
661
+ <HStack flexGrow gap={12} align='stretch'>
662
+ <LineChartLegend orientation='vertical'>
663
+ {multiSeries.map(s => (
664
+ <LineChartLegendItem key={s.key} seriesKey={s.key}>
665
+ <LineChartHoverPopoverDot color={s.color} />
666
+ <span className='text-xs font-mono text-text-primary'>{s.label}</span>
667
+ </LineChartLegendItem>
668
+ ))}
669
+ </LineChartLegend>
670
+ <LineChartBody>
671
+ <LineChartGrid />
672
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
673
+ <LineChartYAxis tickFormatter={formatYTick} />
674
+ {multiSeries.map(s => (
675
+ <LineChartLine key={s.key} seriesKey={s.key} />
676
+ ))}
677
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
678
+ </LineChartBody>
679
+ </HStack>
680
+ </LineChart>
681
+ </Chart>
682
+
683
+ <Chart>
684
+ <ChartHeader>
685
+ <ChartTitle>Right — wrapped in HStack</ChartTitle>
686
+ </ChartHeader>
687
+ <LineChart data={hourlyData24} series={multiSeries} xKey='timestamp'>
688
+ <HStack flexGrow gap={12} align='stretch'>
689
+ <LineChartBody>
690
+ <LineChartGrid />
691
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
692
+ <LineChartYAxis tickFormatter={formatYTick} />
693
+ {multiSeries.map(s => (
694
+ <LineChartLine key={s.key} seriesKey={s.key} />
695
+ ))}
696
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
697
+ </LineChartBody>
698
+ <LineChartLegend orientation='vertical'>
699
+ {multiSeries.map(s => (
700
+ <LineChartLegendItem key={s.key} seriesKey={s.key}>
701
+ <LineChartHoverPopoverDot color={s.color} />
702
+ <span className='text-xs font-mono text-text-primary'>{s.label}</span>
703
+ </LineChartLegendItem>
704
+ ))}
705
+ </LineChartLegend>
706
+ </HStack>
707
+ </LineChart>
708
+ </Chart>
709
+ </div>
710
+ );
711
+ };
712
+
713
+ LegendPlacements.parameters = {
714
+ layout: 'padded',
715
+ };
716
+
717
+ /**
718
+ * Clicking a legend row isolates that series and clicking another adds it back, with the
719
+ * header's clear control appearing while anything is hidden.
720
+ */
721
+ export const Filterable: StoryFn<typeof meta> = () => {
722
+ const { formatHour, formatHourWithTimezone } = useChartTimeFormatters();
723
+ const [hidden, setHidden] = useState<string[]>([]);
724
+ // First click on a fully-visible chart isolates the clicked series (hides
725
+ // every other one); after that, clicks toggle individual series in and out.
726
+ const toggle = (key: string) => {
727
+ setHidden(prev => {
728
+ if (prev.length === 0) return multiSeries.filter(s => s.key !== key).map(s => s.key);
729
+ if (prev.includes(key)) return prev.filter(k => k !== key);
730
+ return [...prev, key];
731
+ });
732
+ };
733
+ const filtered = hidden.length > 0;
734
+
735
+ return (
736
+ <div className='w-560'>
737
+ <Chart data-testid='chart'>
738
+ <ChartHeader>
739
+ <ChartTitle>Click a row to isolate, click another to add</ChartTitle>
740
+ <ChartActions alwaysVisible={filtered}>
741
+ {filtered && (
742
+ <Tooltip>
743
+ <TooltipTrigger asChild>
744
+ <Button
745
+ variant='ghost'
746
+ color='neutral'
747
+ size='small'
748
+ aria-label='Clear filter'
749
+ onClick={() => setHidden([])}
750
+ >
751
+ <FilterX />
752
+ </Button>
753
+ </TooltipTrigger>
754
+ <TooltipContent>Remove filter</TooltipContent>
755
+ </Tooltip>
756
+ )}
757
+ </ChartActions>
758
+ </ChartHeader>
759
+ <LineChart
760
+ data-testid='line-chart'
761
+ data={hourlyData24}
762
+ series={multiSeries}
763
+ xKey='timestamp'
764
+ filteredKeys={hidden}
765
+ >
766
+ <LineChartLegend>
767
+ {multiSeries.map(s => (
768
+ <Tooltip key={s.key}>
769
+ <TooltipTrigger asChild>
770
+ <LineChartLegendItem seriesKey={s.key} onClick={() => toggle(s.key)}>
771
+ <LineChartHoverPopoverDot color={s.color} />
772
+ <span className='text-xs font-mono text-text-primary'>{s.label}</span>
773
+ </LineChartLegendItem>
774
+ </TooltipTrigger>
775
+ <TooltipContent>
776
+ {hidden.includes(s.key) ? 'Remove filter' : 'Click to filter'}
777
+ </TooltipContent>
778
+ </Tooltip>
779
+ ))}
780
+ </LineChartLegend>
781
+ <LineChartBody>
782
+ <LineChartGrid />
783
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
784
+ <LineChartYAxis tickFormatter={formatYTick} />
785
+ {multiSeries.map(s => (
786
+ <LineChartLine key={s.key} seriesKey={s.key} />
787
+ ))}
788
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
789
+ </LineChartBody>
790
+ </LineChart>
791
+ </Chart>
792
+ </div>
793
+ );
794
+ };
795
+
796
+ /**
797
+ * Two cards sharing a pointer, and it takes two mechanisms: `syncId` lines up the cursor and
798
+ * tooltip through recharts, while `activeKey` shares the series highlight through our own
799
+ * context.
800
+ */
801
+ export const CrossChartHoverSync: StoryFn<typeof meta> = () => {
802
+ const { formatHour, formatHourWithTimezone } = useChartTimeFormatters();
803
+ // `syncId` syncs the *cursor X* (tooltip + brush) via recharts' own redux
804
+ // middleware. `activeKey` + `onActiveKeyChange` sync the *series highlight*
805
+ // (line dimming + legend hover) via our context. The two pair cleanly —
806
+ // each owns the surface it controls and neither reinvents the other.
807
+ const [activeKey, setActiveKey] = useState<string | null>(null);
808
+
809
+ return (
810
+ <div className='grid grid-cols-2 gap-16 w-1120'>
811
+ <Chart>
812
+ <ChartHeader>
813
+ <ChartTitle>Region A</ChartTitle>
814
+ </ChartHeader>
815
+ <LineChart
816
+ data={hourlyDataA}
817
+ series={multiSeries}
818
+ xKey='timestamp'
819
+ syncId='regions'
820
+ activeKey={activeKey}
821
+ onActiveKeyChange={setActiveKey}
822
+ >
823
+ <LineChartLegend>
824
+ {multiSeries.map(s => (
825
+ <LineChartLegendItem key={s.key} seriesKey={s.key}>
826
+ <LineChartHoverPopoverDot color={s.color} />
827
+ <span className='text-xs font-mono text-text-primary'>{s.label}</span>
828
+ </LineChartLegendItem>
829
+ ))}
830
+ </LineChartLegend>
831
+ <LineChartBody>
832
+ <LineChartGrid />
833
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
834
+ <LineChartYAxis tickFormatter={formatYTick} />
835
+ {multiSeries.map(s => (
836
+ <LineChartLine key={s.key} seriesKey={s.key} />
837
+ ))}
838
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
839
+ </LineChartBody>
840
+ </LineChart>
841
+ </Chart>
842
+
843
+ <Chart>
844
+ <ChartHeader>
845
+ <ChartTitle>Region B</ChartTitle>
846
+ </ChartHeader>
847
+ <LineChart
848
+ data={hourlyDataB}
849
+ series={multiSeries}
850
+ xKey='timestamp'
851
+ syncId='regions'
852
+ activeKey={activeKey}
853
+ onActiveKeyChange={setActiveKey}
854
+ >
855
+ <LineChartLegend>
856
+ {multiSeries.map(s => (
857
+ <LineChartLegendItem key={s.key} seriesKey={s.key}>
858
+ <LineChartHoverPopoverDot color={s.color} />
859
+ <span className='text-xs font-mono text-text-primary'>{s.label}</span>
860
+ </LineChartLegendItem>
861
+ ))}
862
+ </LineChartLegend>
863
+ <LineChartBody>
864
+ <LineChartGrid />
865
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
866
+ <LineChartYAxis tickFormatter={formatYTick} />
867
+ {multiSeries.map(s => (
868
+ <LineChartLine key={s.key} seriesKey={s.key} />
869
+ ))}
870
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
871
+ </LineChartBody>
872
+ </LineChart>
873
+ </Chart>
874
+ </div>
875
+ );
876
+ };
877
+
878
+ const ZoomControlledChart = () => {
879
+ const { formatDate, formatDateWithTimezone } = useChartTimeFormatters();
880
+ const [visibleData, setVisibleData] = useState(dailyData60);
881
+ const handleZoom = useCallback((range: LineChartZoomRange | null) => {
882
+ if (!range) {
883
+ setVisibleData(dailyData60);
884
+ return;
885
+ }
886
+ setVisibleData(prev => prev.slice(range.fromIndex, range.toIndex + 1));
887
+ }, []);
888
+ const isZoomed = visibleData !== dailyData60;
889
+ // Daily data — time is always 00:00 so the zoom popover renders date-only.
890
+ const formatDateOnlyRange = useMemo(() => formatRange(formatDate), [formatDate]);
891
+
892
+ const chartRef = useRef<HTMLDivElement>(null);
893
+
894
+ useEffect(() => {
895
+ if (!isZoomed) return;
896
+
897
+ const handleKey = (event: KeyboardEvent) => {
898
+ if (event.key !== 'Escape') return;
899
+ const target = event.target;
900
+ const isAmbient =
901
+ target === null || target === document.body || target === document.documentElement;
902
+ const isInChart = target instanceof Node && chartRef.current?.contains(target);
903
+ if (!isAmbient && !isInChart) return;
904
+ event.preventDefault();
905
+ handleZoom(null);
906
+ };
907
+
908
+ window.addEventListener('keydown', handleKey);
909
+
910
+ return () => window.removeEventListener('keydown', handleKey);
911
+ }, [isZoomed, handleZoom]);
912
+
913
+ return (
914
+ <Chart ref={chartRef} data-testid='chart'>
915
+ <ChartHeader>
916
+ <ChartTitle>Drag on the plot, then click "Zoom in" — Esc to cancel</ChartTitle>
917
+ <ChartActions alwaysVisible={isZoomed}>
918
+ {isZoomed && (
919
+ <Tooltip>
920
+ <TooltipTrigger asChild>
921
+ <Button
922
+ variant='ghost'
923
+ color='neutral'
924
+ size='small'
925
+ aria-label='Reset time selection'
926
+ onClick={() => handleZoom(null)}
927
+ >
928
+ <ZoomOut />
929
+ </Button>
930
+ </TooltipTrigger>
931
+ <TooltipContent>Reset time selection</TooltipContent>
932
+ </Tooltip>
933
+ )}
934
+ </ChartActions>
935
+ </ChartHeader>
936
+ <LineChart
937
+ data-testid='line-chart'
938
+ data={visibleData}
939
+ series={multiSeries}
940
+ xKey='timestamp'
941
+ onZoomChange={handleZoom}
942
+ >
943
+ <MultiLegend />
944
+ <LineChartBody height={220}>
945
+ <LineChartGrid />
946
+ <LineChartXAxis tickFormatter={formatDate} minTickGap={48} />
947
+ <LineChartYAxis tickFormatter={formatYTick} />
948
+ {multiSeries.map(s => (
949
+ <LineChartLine key={s.key} seriesKey={s.key} />
950
+ ))}
951
+ <LineChartTooltip xTickFormatter={formatDateWithTimezone} />
952
+ <LineChartZoomBrush formatRange={formatDateOnlyRange} />
953
+ </LineChartBody>
954
+ </LineChart>
955
+ </Chart>
956
+ );
957
+ };
958
+
959
+ /**
960
+ * Drag across the plot to choose a range, then confirm in the popover — Enter or the button
961
+ * emits `onZoomChange`, while Escape, an outside click or a new drag dismisses it. Slicing the
962
+ * data to that range is yours, and so is the way back out.
963
+ */
964
+ export const Zoom: StoryFn<typeof meta> = () => (
965
+ <div className='w-560'>
966
+ <ZoomControlledChart />
967
+ </div>
968
+ );
969
+
970
+ const LoadingLegend = ({ orientation }: { orientation?: 'horizontal' | 'vertical' }) => (
971
+ <LineChartLegend orientation={orientation}>
972
+ {[0, 1, 2].map(i => (
973
+ <LineChartLegendItem key={i} seriesKey={`skeleton-${i}`}>
974
+ <Skeleton width='72px' height='20px' rounded={4} />
975
+ </LineChartLegendItem>
976
+ ))}
977
+ </LineChartLegend>
978
+ );
979
+
980
+ /**
981
+ * There is no `loading` prop: the state is composed from the same primitives as a populated
982
+ * chart — `Skeleton` chips inside the legend and a bare `LineChartEmpty` for the dashed plot —
983
+ * with `aria-busy` on the `Chart` left to the caller.
984
+ */
985
+ export const Loading: StoryFn<typeof meta> = () => (
986
+ <div className='grid grid-cols-2 gap-16 w-1120'>
987
+ <Chart aria-busy='true' aria-live='polite'>
988
+ <ChartHeader>
989
+ <ChartTitle>No legend</ChartTitle>
990
+ </ChartHeader>
991
+ <LineChartEmpty />
992
+ </Chart>
993
+
994
+ <Chart aria-busy='true' aria-live='polite'>
995
+ <ChartHeader>
996
+ <ChartTitle>Top — JSX order</ChartTitle>
997
+ </ChartHeader>
998
+ <LoadingLegend />
999
+ <LineChartEmpty />
1000
+ </Chart>
1001
+
1002
+ <Chart aria-busy='true' aria-live='polite'>
1003
+ <ChartHeader>
1004
+ <ChartTitle>Bottom — JSX order</ChartTitle>
1005
+ </ChartHeader>
1006
+ <LineChartEmpty />
1007
+ <LoadingLegend />
1008
+ </Chart>
1009
+
1010
+ <Chart aria-busy='true' aria-live='polite'>
1011
+ <ChartHeader>
1012
+ <ChartTitle>Left — wrapped in HStack</ChartTitle>
1013
+ </ChartHeader>
1014
+ <HStack flexGrow gap={12} align='stretch'>
1015
+ <LoadingLegend orientation='vertical' />
1016
+ <LineChartEmpty className='flex-1 min-w-0' />
1017
+ </HStack>
1018
+ </Chart>
1019
+
1020
+ <Chart aria-busy='true' aria-live='polite'>
1021
+ <ChartHeader>
1022
+ <ChartTitle>Right — wrapped in HStack</ChartTitle>
1023
+ </ChartHeader>
1024
+ <HStack flexGrow gap={12} align='stretch'>
1025
+ <LineChartEmpty className='flex-1 min-w-0' />
1026
+ <LoadingLegend orientation='vertical' />
1027
+ </HStack>
1028
+ </Chart>
1029
+ </div>
1030
+ );
1031
+
1032
+ Loading.parameters = {
1033
+ design: {
1034
+ type: 'figma',
1035
+ url: 'https://www.figma.com/design/VKb5gW46uSGw0rqrhZsbXT/WADS-Components?node-id=7519-2617&m=dev',
1036
+ },
1037
+ };
1038
+
1039
+ type RefreshingPlacement = 'none' | 'top' | 'bottom' | 'left' | 'right';
1040
+
1041
+ const RefreshingChart = ({
1042
+ placement,
1043
+ title,
1044
+ }: {
1045
+ placement: RefreshingPlacement;
1046
+ title: string;
1047
+ }) => {
1048
+ const { formatHour, formatHourWithTimezone } = useChartTimeFormatters();
1049
+ const [loading, setLoading] = useState(true);
1050
+
1051
+ useEffect(() => {
1052
+ if (!loading) return;
1053
+ const id = setTimeout(() => setLoading(false), 2000);
1054
+ return () => clearTimeout(id);
1055
+ }, [loading]);
1056
+
1057
+ const isSide = placement === 'left' || placement === 'right';
1058
+ const orientation = isSide ? 'vertical' : 'horizontal';
1059
+
1060
+ const legend = loading ? (
1061
+ <LoadingLegend orientation={orientation} />
1062
+ ) : (
1063
+ <LineChartLegend orientation={orientation}>
1064
+ {multiSeries.map(s => (
1065
+ <LineChartLegendItem key={s.key} seriesKey={s.key}>
1066
+ <LineChartHoverPopoverDot color={s.color} />
1067
+ <span className='text-xs font-mono text-text-primary'>{s.label}</span>
1068
+ </LineChartLegendItem>
1069
+ ))}
1070
+ </LineChartLegend>
1071
+ );
1072
+
1073
+ const body = loading ? (
1074
+ <LineChartEmpty className={isSide ? 'flex-1 min-w-0' : undefined} />
1075
+ ) : (
1076
+ <LineChartBody>
1077
+ <LineChartGrid />
1078
+ <LineChartXAxis tickFormatter={formatHour} minTickGap={32} />
1079
+ <LineChartYAxis tickFormatter={formatYTick} />
1080
+ {multiSeries.map(s => (
1081
+ <LineChartLine key={s.key} seriesKey={s.key} />
1082
+ ))}
1083
+ <LineChartTooltip xTickFormatter={formatHourWithTimezone} />
1084
+ </LineChartBody>
1085
+ );
1086
+
1087
+ let inner: ReactNode;
1088
+ if (placement === 'none') {
1089
+ inner = body;
1090
+ } else if (placement === 'top') {
1091
+ inner = (
1092
+ <>
1093
+ {legend}
1094
+ {body}
1095
+ </>
1096
+ );
1097
+ } else if (placement === 'bottom') {
1098
+ inner = (
1099
+ <>
1100
+ {body}
1101
+ {legend}
1102
+ </>
1103
+ );
1104
+ } else if (placement === 'left') {
1105
+ inner = (
1106
+ <HStack flexGrow gap={12} align='stretch'>
1107
+ {legend}
1108
+ {body}
1109
+ </HStack>
1110
+ );
1111
+ } else {
1112
+ inner = (
1113
+ <HStack flexGrow gap={12} align='stretch'>
1114
+ {body}
1115
+ {legend}
1116
+ </HStack>
1117
+ );
1118
+ }
1119
+
1120
+ return (
1121
+ <Chart aria-busy={loading} aria-live='polite'>
1122
+ <ChartHeader>
1123
+ <ChartTitle>{title}</ChartTitle>
1124
+ <ChartActions alwaysVisible>
1125
+ <Tooltip disabled={loading}>
1126
+ <TooltipTrigger asChild>
1127
+ <Button
1128
+ variant='ghost'
1129
+ color='neutral'
1130
+ size='small'
1131
+ aria-label='Reload'
1132
+ disabled={loading}
1133
+ onClick={() => setLoading(true)}
1134
+ >
1135
+ <RefreshCcw />
1136
+ </Button>
1137
+ </TooltipTrigger>
1138
+ <TooltipContent>Reload</TooltipContent>
1139
+ </Tooltip>
1140
+ </ChartActions>
1141
+ </ChartHeader>
1142
+ {loading ? (
1143
+ inner
1144
+ ) : (
1145
+ <LineChart data={hourlyData24} series={multiSeries} xKey='timestamp'>
1146
+ {inner}
1147
+ </LineChart>
1148
+ )}
1149
+ </Chart>
1150
+ );
1151
+ };
1152
+
1153
+ /**
1154
+ * Each panel loads for two seconds before swapping to data, and the refresh button replays it.
1155
+ * The skeleton and the real chart share an outer layout, so nothing but the content moves on
1156
+ * the swap.
1157
+ */
1158
+ export const Refreshing: StoryFn<typeof meta> = () => (
1159
+ <div className='grid grid-cols-2 gap-16 w-1120'>
1160
+ <RefreshingChart placement='none' title='No legend' />
1161
+ <RefreshingChart placement='top' title='Top — JSX order' />
1162
+ <RefreshingChart placement='bottom' title='Bottom — JSX order' />
1163
+ <RefreshingChart placement='left' title='Left — wrapped in HStack' />
1164
+ <RefreshingChart placement='right' title='Right — wrapped in HStack' />
1165
+ </div>
1166
+ );
1167
+
1168
+ /**
1169
+ * `LineChartEmpty` keeps the dashed plot frame and puts the message inside it, so a card with
1170
+ * no data still reads as a chart rather than as something broken.
1171
+ */
1172
+ export const Empty: StoryFn<typeof meta> = () => (
1173
+ <div className='w-560'>
1174
+ <Chart>
1175
+ <ChartHeader>
1176
+ <ChartTitle>No data</ChartTitle>
1177
+ </ChartHeader>
1178
+ <LineChartEmpty>No data</LineChartEmpty>
1179
+ </Chart>
1180
+ </div>
1181
+ );
1182
+
1183
+ Empty.parameters = {
1184
+ design: {
1185
+ type: 'figma',
1186
+ url: 'https://www.figma.com/design/VKb5gW46uSGw0rqrhZsbXT/WADS-Components?node-id=8670-2594&m=dev',
1187
+ },
1188
+ };
1189
+
1190
+ const LongTimeRangeChart = () => {
1191
+ const { formatDate, formatDateTime, formatDateTimeWithTimezone } = useChartTimeFormatters();
1192
+ const formatDateTimeRangeText = useMemo(() => formatRange(formatDateTime), [formatDateTime]);
1193
+ const [range, setRange] = useState<LineChartZoomRange | null>(null);
1194
+ const visibleData = useMemo(() => {
1195
+ if (!range) return hourlyData1000;
1196
+ return hourlyData1000.slice(range.fromIndex, range.toIndex + 1);
1197
+ }, [range]);
1198
+
1199
+ return (
1200
+ <Chart>
1201
+ <ChartHeader>
1202
+ <ChartTitle>1,000 hourly samples — drag to zoom</ChartTitle>
1203
+ <ChartActions alwaysVisible={range !== null}>
1204
+ {range !== null && (
1205
+ <Tooltip>
1206
+ <TooltipTrigger asChild>
1207
+ <Button
1208
+ variant='ghost'
1209
+ color='neutral'
1210
+ size='small'
1211
+ aria-label='Reset time selection'
1212
+ onClick={() => setRange(null)}
1213
+ >
1214
+ <ZoomOut />
1215
+ </Button>
1216
+ </TooltipTrigger>
1217
+ <TooltipContent>Reset time selection</TooltipContent>
1218
+ </Tooltip>
1219
+ )}
1220
+ </ChartActions>
1221
+ </ChartHeader>
1222
+ <LineChart data={visibleData} series={multiSeries} xKey='timestamp' onZoomChange={setRange}>
1223
+ <LineChartLegend>
1224
+ {multiSeries.map(s => (
1225
+ <LineChartLegendItem key={s.key} seriesKey={s.key}>
1226
+ <LineChartHoverPopoverDot color={s.color} />
1227
+ <span className='text-xs font-mono text-text-primary'>{s.label}</span>
1228
+ </LineChartLegendItem>
1229
+ ))}
1230
+ </LineChartLegend>
1231
+ <LineChartBody height={220}>
1232
+ <LineChartGrid />
1233
+ <LineChartXAxis tickFormatter={formatDate} minTickGap={64} />
1234
+ <LineChartYAxis tickFormatter={formatYTick} />
1235
+ {multiSeries.map(s => (
1236
+ <LineChartLine key={s.key} seriesKey={s.key} disableAnimation />
1237
+ ))}
1238
+ <LineChartTooltip xTickFormatter={formatDateTimeWithTimezone} />
1239
+ <LineChartZoomBrush formatRange={formatDateTimeRangeText} />
1240
+ </LineChartBody>
1241
+ </LineChart>
1242
+ </Chart>
1243
+ );
1244
+ };
1245
+
1246
+ /**
1247
+ * A thousand hourly samples in one card: drag to zoom and the header's control restores the
1248
+ * full range. The story slices the data itself, exactly as a consumer has to.
1249
+ */
1250
+ export const LongTimeRange: StoryFn<typeof meta> = () => (
1251
+ <div className='w-720'>
1252
+ <LongTimeRangeChart />
1253
+ </div>
1254
+ );
1255
+ ```
1256
+
1257
+ ### ../utils/abbreviateNumber.ts
1258
+
1259
+ ```tsx
1260
+ /**
1261
+ * Suffix tiers: [minAbsValue, divisor, suffix].
1262
+ * Sorted descending so the first match wins.
1263
+ *
1264
+ * Boundaries use "rounding-aware" thresholds:
1265
+ * 999,500 rounds to 1M (not 999.5k), 999,499 stays 999k.
1266
+ */
1267
+ const tiers: [threshold: number, divisor: number, suffix: string][] = [
1268
+ [999_500_000_000, 1e12, 'T'],
1269
+ [999_500_000, 1e9, 'B'],
1270
+ [999_500, 1e6, 'M'],
1271
+ [1_000, 1e3, 'k'],
1272
+ ];
1273
+
1274
+ const fullFormatter = new Intl.NumberFormat('en-US');
1275
+
1276
+ /**
1277
+ * Abbreviate a number for table cells: `12042` → `"12k"`, `59614283` → `"59.6M"`.
1278
+ *
1279
+ * Rules (from the Number display & abbreviation guide):
1280
+ * - Suffixes: k (10³), M (10⁶), B (10⁹), T (10¹²) — k lowercase, rest uppercase, no space
1281
+ * - Boundary: moves to next suffix when rounding would reach 1000×
1282
+ * - Precision: ≥100 → 0 decimals; 10–99 → 1 decimal (drop .0); 1–9.9 → 1 decimal
1283
+ * - Negative numbers supported
1284
+ */
1285
+ export const abbreviateNumber = (value: number): string => {
1286
+ if (value === 0) return '0';
1287
+
1288
+ const sign = value < 0 ? '-' : '';
1289
+ const abs = Math.abs(value);
1290
+
1291
+ if (abs < 1_000) return String(value);
1292
+
1293
+ const tier = tiers.find(([threshold]) => abs >= threshold);
1294
+
1295
+ if (!tier) return String(value);
1296
+
1297
+ const [, divisor, suffix] = tier;
1298
+ const scaled = abs / divisor;
1299
+
1300
+ // ≥100 → 0 decimals; <100 → 1 decimal (drop trailing .0)
1301
+ const precision = scaled >= 100 ? 0 : 1;
1302
+ const rounded = Math.round(scaled * 10 ** precision) / 10 ** precision;
1303
+ const formatted = rounded % 1 === 0 ? String(rounded) : rounded.toFixed(1);
1304
+
1305
+ return `${sign}${formatted}${suffix}`;
1306
+ };
1307
+
1308
+ /**
1309
+ * Format a number with thousand separators for tooltips: `59614283` → `"59,614,283"`.
1310
+ */
1311
+ export const formatFullNumber = (value: number): string => fullFormatter.format(value);
1312
+
1313
+ /**
1314
+ * Format a percentage with boundary safety:
1315
+ * - Never show 100% when real value < 100 → ">99%" (or ">99.9%" etc.)
1316
+ * - Never show 0% when real value > 0 → "<1%" (or "<0.1%" etc.)
1317
+ * - `decimals` controls fractional precision (default 0)
1318
+ */
1319
+ export const formatPercent = (value: number, decimals = 0): string => {
1320
+ if (value === 0) return '0%';
1321
+ if (value === 100) return '100%';
1322
+
1323
+ const factor = 10 ** decimals;
1324
+ const rounded = Math.round(value * factor) / factor;
1325
+
1326
+ // Boundary safety: value > 0 but rounds to 0
1327
+ if (value > 0 && rounded === 0) {
1328
+ const threshold = 1 / factor;
1329
+ return `<${threshold}%`;
1330
+ }
1331
+
1332
+ // Boundary safety: value < 100 but rounds to 100
1333
+ if (value < 100 && rounded === 100) {
1334
+ const max = 100 - 1 / factor;
1335
+ return `>${decimals > 0 ? max.toFixed(decimals) : String(max)}%`;
1336
+ }
1337
+
1338
+ return `${decimals > 0 ? rounded.toFixed(decimals) : String(rounded)}%`;
1339
+ };
1340
+
1341
+ /**
1342
+ * Byte-formatting tiers: [minValue, divisor, suffix].
1343
+ * Uses decimal (SI) units: KB = 1000, MB = 1e6, etc.
1344
+ */
1345
+ const byteTiers: [threshold: number, divisor: number, suffix: string][] = [
1346
+ [999_500_000_000, 1e12, 'TB'],
1347
+ [999_500_000, 1e9, 'GB'],
1348
+ [999_500, 1e6, 'MB'],
1349
+ [1_000, 1e3, 'KB'],
1350
+ ];
1351
+
1352
+ /**
1353
+ * Format bytes using decimal (SI) units: 512 B, 3.4 KB, 12.7 MB, 2.3 GB, 1.1 TB.
1354
+ * Same decimal precision rules as abbreviateNumber.
1355
+ * Returns `{ display, full }` where `full` = "2,345,678,901 bytes".
1356
+ */
1357
+ export const formatBytes = (value: number): { display: string; full: string } => {
1358
+ const full = `${fullFormatter.format(value)} bytes`;
1359
+
1360
+ if (value < 1_000) {
1361
+ return { display: `${value} B`, full };
1362
+ }
1363
+
1364
+ const tier = byteTiers.find(([threshold]) => value >= threshold);
1365
+
1366
+ if (!tier) {
1367
+ return { display: `${value} B`, full };
1368
+ }
1369
+
1370
+ const [, divisor, suffix] = tier;
1371
+ const scaled = value / divisor;
1372
+
1373
+ const precision = scaled >= 100 ? 0 : 1;
1374
+ const rounded = Math.round(scaled * 10 ** precision) / 10 ** precision;
1375
+ const formatted = rounded % 1 === 0 ? String(rounded) : rounded.toFixed(1);
1376
+
1377
+ return { display: `${formatted} ${suffix}`, full };
1378
+ };
1379
+ ```
1380
+
1381
+ ### SimpleCharts/LineChart/lib/formatRange.ts
1382
+
1383
+ ```tsx
1384
+ /** Higher-order range formatter — joins `format(from)` and `format(to)` with `→`. */
1385
+ export const formatRange =
1386
+ (format: (value: unknown) => string) =>
1387
+ (range: { from: unknown; to: unknown }): string =>
1388
+ `${format(range.from)} → ${format(range.to)}`;
1389
+ ```
1390
+
1391
+ ### SimpleCharts/LineChart/lib/sampleData.ts
1392
+
1393
+ ```tsx
1394
+ import type { LineChartDatum, LineChartSeries } from '../LineChartContext';
1395
+
1396
+ // Deterministic pseudo-random in [0, 1) so the same `(i, seed, salt)` produces
1397
+ // the same value across runs — keeps screenshot tests stable while letting us
1398
+ // add point-to-point jitter that monotone smooths out and linear preserves.
1399
+ const jitter = (i: number, seed: number, salt: number): number => {
1400
+ const v = Math.sin((i + seed) * salt) * 43758.5453;
1401
+ return v - Math.floor(v);
1402
+ };
1403
+
1404
+ export const genHourly = (count: number, seed = 1): LineChartDatum[] => {
1405
+ // Local-time anchor so the first sample reads `00:00` in the viewer's
1406
+ // timezone instead of drifting by the UTC offset.
1407
+ const start = new Date(2025, 0, 1, 0, 0, 0).getTime();
1408
+ const out: LineChartDatum[] = [];
1409
+ for (let i = 0; i < count; i++) {
1410
+ const t = start + i * 60 * 60 * 1000;
1411
+ const requests = Math.round(
1412
+ 120 + Math.sin((i + seed) / 4) * 30 + (jitter(i, seed, 12.9898) - 0.5) * 80,
1413
+ );
1414
+ const errors = Math.round(
1415
+ 24 + Math.cos((i + seed) / 5) * 10 + (jitter(i, seed, 78.233) - 0.5) * 32,
1416
+ );
1417
+ const latency = Math.round(
1418
+ 80 + Math.sin((i + seed) / 6) * 14 + (jitter(i, seed, 39.346) - 0.5) * 40,
1419
+ );
1420
+ out.push({ timestamp: t, requests, errors, latency });
1421
+ }
1422
+ return out;
1423
+ };
1424
+
1425
+ export const genDaily = (count: number): LineChartDatum[] => {
1426
+ const start = new Date(2024, 0, 1, 0, 0, 0).getTime();
1427
+ const out: LineChartDatum[] = [];
1428
+ for (let i = 0; i < count; i++) {
1429
+ const t = start + i * 24 * 60 * 60 * 1000;
1430
+ const requests = Math.round(1000 + Math.sin(i / 9) * 400 + (i % 13) * 12);
1431
+ const errors = Math.round(80 + Math.cos(i / 11) * 30 + (i % 7) * 3);
1432
+ out.push({ timestamp: t, requests, errors });
1433
+ }
1434
+ return out;
1435
+ };
1436
+
1437
+ export const singleSeries: LineChartSeries[] = [
1438
+ { key: 'requests', label: 'Requests', color: 'brand' },
1439
+ ];
1440
+
1441
+ export const multiSeries: LineChartSeries[] = [
1442
+ { key: 'requests', label: 'Requests', color: 'brand' },
1443
+ { key: 'errors', label: 'Errors', color: 'red' },
1444
+ { key: 'latency', label: 'Latency', color: 'blue' },
1445
+ ];
1446
+
1447
+ export const dashedSeries: LineChartSeries[] = [
1448
+ { key: 'requests', label: 'Requests', color: 'brand' },
1449
+ { key: 'errors', label: 'Errors (target)', color: 'red', variant: 'dashed' },
1450
+ ];
1451
+
1452
+ export const customColorSeries: LineChartSeries[] = [
1453
+ { key: 'requests', label: 'Requests', color: 'var(--color-violet-500)' },
1454
+ { key: 'errors', label: 'Errors', color: 'var(--color-emerald-500)' },
1455
+ ];
1456
+
1457
+ export const hourlyData24 = genHourly(24);
1458
+ export const hourlyDataA = genHourly(24, 1);
1459
+ export const hourlyDataB = genHourly(24, 7);
1460
+ export const dailyData60 = genDaily(60);
1461
+ export const hourlyData1000 = genHourly(1000);
1462
+
1463
+ export const singlePointData: LineChartDatum[] = [
1464
+ { timestamp: new Date(2025, 0, 1, 12, 0, 0).getTime(), requests: 142 },
1465
+ ];
1466
+
1467
+ export const dataWithErrorGaps: LineChartDatum[] = hourlyData24.map((d, i) => {
1468
+ if ((i >= 6 && i <= 8) || (i >= 15 && i <= 16)) {
1469
+ return { ...d, errors: null };
1470
+ }
1471
+ return d;
1472
+ });
1473
+
1474
+ export const unitsByKey: Record<string, string> = {
1475
+ requests: ' req',
1476
+ errors: ' err',
1477
+ latency: ' ms',
1478
+ };
1479
+ ```