@teamofsilicons/silicon-ui 0.0.0-stage → 0.1.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 (352) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +63 -2
  3. package/components/accordion/accordion.d.ts +13 -0
  4. package/components/accordion/accordion.js +35 -0
  5. package/components/accordion/accordion.module.css +15 -0
  6. package/components/action-button/action-button.d.ts +11 -0
  7. package/components/action-button/action-button.js +57 -0
  8. package/components/action-button/action-button.module.css +15 -0
  9. package/components/activity-heatmap/activity-heatmap.d.ts +37 -0
  10. package/components/activity-heatmap/activity-heatmap.js +303 -0
  11. package/components/activity-heatmap/activity-heatmap.module.css +83 -0
  12. package/components/alert/alert.d.ts +13 -0
  13. package/components/alert/alert.js +79 -0
  14. package/components/alert/alert.module.css +15 -0
  15. package/components/animated-counter/animated-counter.d.ts +13 -0
  16. package/components/animated-counter/animated-counter.js +73 -0
  17. package/components/animated-counter/animated-counter.module.css +12 -0
  18. package/components/announcement-bar/announcement-bar.d.ts +53 -0
  19. package/components/announcement-bar/announcement-bar.js +187 -0
  20. package/components/announcement-bar/announcement-bar.module.css +60 -0
  21. package/components/avatar/avatar.d.ts +8 -0
  22. package/components/avatar/avatar.js +18 -0
  23. package/components/avatar/avatar.module.css +60 -0
  24. package/components/avatar-group/avatar-group.d.ts +13 -0
  25. package/components/avatar-group/avatar-group.js +24 -0
  26. package/components/avatar-group/avatar-group.module.css +27 -0
  27. package/components/badge/badge.d.ts +10 -0
  28. package/components/badge/badge.js +66 -0
  29. package/components/badge/badge.module.css +52 -0
  30. package/components/bar-chart/bar-chart.d.ts +32 -0
  31. package/components/bar-chart/bar-chart.js +327 -0
  32. package/components/bar-chart/bar-chart.module.css +49 -0
  33. package/components/billing-toggle/billing-toggle.d.ts +35 -0
  34. package/components/billing-toggle/billing-toggle.js +83 -0
  35. package/components/billing-toggle/billing-toggle.module.css +139 -0
  36. package/components/bottom-sheet/bottom-sheet.d.ts +27 -0
  37. package/components/bottom-sheet/bottom-sheet.js +386 -0
  38. package/components/bottom-sheet/bottom-sheet.module.css +69 -0
  39. package/components/breadcrumb/breadcrumb.d.ts +13 -0
  40. package/components/breadcrumb/breadcrumb.js +19 -0
  41. package/components/breadcrumb/breadcrumb.module.css +12 -0
  42. package/components/brush-chart/brush-chart.d.ts +45 -0
  43. package/components/brush-chart/brush-chart.js +426 -0
  44. package/components/brush-chart/brush-chart.module.css +69 -0
  45. package/components/button/button.d.ts +10 -0
  46. package/components/button/button.js +97 -0
  47. package/components/button/button.module.css +39 -0
  48. package/components/button-group/button-group.d.ts +59 -0
  49. package/components/button-group/button-group.js +280 -0
  50. package/components/button-group/button-group.module.css +87 -0
  51. package/components/button-link/button-link.d.ts +24 -0
  52. package/components/button-link/button-link.js +11 -0
  53. package/components/button-link/button-link.module.css +7 -0
  54. package/components/calendar/calendar.d.ts +22 -0
  55. package/components/calendar/calendar.js +253 -0
  56. package/components/calendar/calendar.module.css +51 -0
  57. package/components/card/card.d.ts +19 -0
  58. package/components/card/card.js +108 -0
  59. package/components/card/card.module.css +51 -0
  60. package/components/card-stack/card-stack.d.ts +34 -0
  61. package/components/card-stack/card-stack.js +291 -0
  62. package/components/card-stack/card-stack.module.css +63 -0
  63. package/components/carousel/carousel.d.ts +28 -0
  64. package/components/carousel/carousel.js +332 -0
  65. package/components/carousel/carousel.module.css +42 -0
  66. package/components/chat-thread/chat-thread.d.ts +135 -0
  67. package/components/chat-thread/chat-thread.js +406 -0
  68. package/components/chat-thread/chat-thread.module.css +242 -0
  69. package/components/checkbox/checkbox.d.ts +7 -0
  70. package/components/checkbox/checkbox.js +23 -0
  71. package/components/checkbox/checkbox.module.css +15 -0
  72. package/components/chip-group/chip-group.d.ts +24 -0
  73. package/components/chip-group/chip-group.js +196 -0
  74. package/components/chip-group/chip-group.module.css +38 -0
  75. package/components/code-block/code-block.d.ts +11 -0
  76. package/components/code-block/code-block.js +133 -0
  77. package/components/code-block/code-block.module.css +43 -0
  78. package/components/color-picker/color-picker.d.ts +40 -0
  79. package/components/color-picker/color-picker.js +449 -0
  80. package/components/color-picker/color-picker.module.css +111 -0
  81. package/components/combobox/combobox.d.ts +19 -0
  82. package/components/combobox/combobox.js +167 -0
  83. package/components/combobox/combobox.module.css +28 -0
  84. package/components/command-palette/command-palette.d.ts +20 -0
  85. package/components/command-palette/command-palette.js +151 -0
  86. package/components/command-palette/command-palette.module.css +94 -0
  87. package/components/comment-thread/comment-thread.d.ts +120 -0
  88. package/components/comment-thread/comment-thread.js +343 -0
  89. package/components/comment-thread/comment-thread.module.css +195 -0
  90. package/components/confirm-morph/confirm-morph.d.ts +65 -0
  91. package/components/confirm-morph/confirm-morph.js +355 -0
  92. package/components/confirm-morph/confirm-morph.module.css +146 -0
  93. package/components/context-menu/context-menu.d.ts +18 -0
  94. package/components/context-menu/context-menu.js +148 -0
  95. package/components/context-menu/context-menu.module.css +17 -0
  96. package/components/copy-button/copy-button.d.ts +10 -0
  97. package/components/copy-button/copy-button.js +69 -0
  98. package/components/copy-button/copy-button.module.css +21 -0
  99. package/components/countdown/countdown.d.ts +31 -0
  100. package/components/countdown/countdown.js +177 -0
  101. package/components/countdown/countdown.module.css +49 -0
  102. package/components/date-picker/date-picker.d.ts +17 -0
  103. package/components/date-picker/date-picker.js +100 -0
  104. package/components/date-picker/date-picker.module.css +34 -0
  105. package/components/date-range-picker/date-range-picker.d.ts +44 -0
  106. package/components/date-range-picker/date-range-picker.js +534 -0
  107. package/components/date-range-picker/date-range-picker.module.css +214 -0
  108. package/components/dialog/dialog.d.ts +11 -0
  109. package/components/dialog/dialog.js +52 -0
  110. package/components/dialog/dialog.module.css +36 -0
  111. package/components/donut-chart/donut-chart.d.ts +46 -0
  112. package/components/donut-chart/donut-chart.js +382 -0
  113. package/components/donut-chart/donut-chart.module.css +48 -0
  114. package/components/drawer/drawer.d.ts +20 -0
  115. package/components/drawer/drawer.js +111 -0
  116. package/components/drawer/drawer.module.css +97 -0
  117. package/components/dropdown-menu/dropdown-menu.d.ts +16 -0
  118. package/components/dropdown-menu/dropdown-menu.js +39 -0
  119. package/components/dropdown-menu/dropdown-menu.module.css +38 -0
  120. package/components/elastic-slider/elastic-slider.d.ts +39 -0
  121. package/components/elastic-slider/elastic-slider.js +261 -0
  122. package/components/elastic-slider/elastic-slider.module.css +40 -0
  123. package/components/empty-state/empty-state.d.ts +12 -0
  124. package/components/empty-state/empty-state.js +69 -0
  125. package/components/empty-state/empty-state.module.css +13 -0
  126. package/components/expandable-card/expandable-card.d.ts +13 -0
  127. package/components/expandable-card/expandable-card.js +89 -0
  128. package/components/expandable-card/expandable-card.module.css +22 -0
  129. package/components/expanding-button-group/expanding-button-group.d.ts +41 -0
  130. package/components/expanding-button-group/expanding-button-group.js +258 -0
  131. package/components/expanding-button-group/expanding-button-group.module.css +44 -0
  132. package/components/expanding-search/expanding-search.d.ts +38 -0
  133. package/components/expanding-search/expanding-search.js +242 -0
  134. package/components/expanding-search/expanding-search.module.css +52 -0
  135. package/components/file-dropzone/file-dropzone.d.ts +44 -0
  136. package/components/file-dropzone/file-dropzone.js +379 -0
  137. package/components/file-dropzone/file-dropzone.module.css +115 -0
  138. package/components/file-upload/file-upload.d.ts +22 -0
  139. package/components/file-upload/file-upload.js +192 -0
  140. package/components/file-upload/file-upload.module.css +49 -0
  141. package/components/filter-toolbar/filter-toolbar.d.ts +48 -0
  142. package/components/filter-toolbar/filter-toolbar.js +446 -0
  143. package/components/filter-toolbar/filter-toolbar.module.css +70 -0
  144. package/components/floating-button-group/floating-button-group.d.ts +51 -0
  145. package/components/floating-button-group/floating-button-group.js +215 -0
  146. package/components/floating-button-group/floating-button-group.module.css +74 -0
  147. package/components/gauge/gauge.d.ts +18 -0
  148. package/components/gauge/gauge.js +101 -0
  149. package/components/gauge/gauge.module.css +22 -0
  150. package/components/hold-to-confirm/hold-to-confirm.d.ts +25 -0
  151. package/components/hold-to-confirm/hold-to-confirm.js +165 -0
  152. package/components/hold-to-confirm/hold-to-confirm.module.css +20 -0
  153. package/components/hover-card/hover-card.d.ts +38 -0
  154. package/components/hover-card/hover-card.js +145 -0
  155. package/components/hover-card/hover-card.module.css +20 -0
  156. package/components/image-compare/image-compare.d.ts +27 -0
  157. package/components/image-compare/image-compare.js +267 -0
  158. package/components/image-compare/image-compare.module.css +25 -0
  159. package/components/in-view-title/in-view-title.d.ts +17 -0
  160. package/components/in-view-title/in-view-title.js +70 -0
  161. package/components/in-view-title/in-view-title.module.css +13 -0
  162. package/components/inline-edit/inline-edit.d.ts +27 -0
  163. package/components/inline-edit/inline-edit.js +315 -0
  164. package/components/inline-edit/inline-edit.module.css +73 -0
  165. package/components/input/input.d.ts +7 -0
  166. package/components/input/input.js +60 -0
  167. package/components/input/input.module.css +22 -0
  168. package/components/json-viewer/json-viewer.d.ts +48 -0
  169. package/components/json-viewer/json-viewer.js +463 -0
  170. package/components/json-viewer/json-viewer.module.css +92 -0
  171. package/components/line-chart/line-chart.d.ts +58 -0
  172. package/components/line-chart/line-chart.js +383 -0
  173. package/components/line-chart/line-chart.module.css +60 -0
  174. package/components/mention-input/mention-input.d.ts +72 -0
  175. package/components/mention-input/mention-input.js +417 -0
  176. package/components/mention-input/mention-input.module.css +134 -0
  177. package/components/metric-card/metric-card.d.ts +8 -0
  178. package/components/metric-card/metric-card.js +44 -0
  179. package/components/metric-card/metric-card.module.css +18 -0
  180. package/components/money-input/money-input.d.ts +48 -0
  181. package/components/money-input/money-input.js +503 -0
  182. package/components/money-input/money-input.module.css +77 -0
  183. package/components/morph-select/morph-select.d.ts +50 -0
  184. package/components/morph-select/morph-select.js +395 -0
  185. package/components/morph-select/morph-select.module.css +88 -0
  186. package/components/multi-select/multi-select.d.ts +18 -0
  187. package/components/multi-select/multi-select.js +105 -0
  188. package/components/multi-select/multi-select.module.css +37 -0
  189. package/components/notification-center/notification-center.d.ts +24 -0
  190. package/components/notification-center/notification-center.js +146 -0
  191. package/components/notification-center/notification-center.module.css +79 -0
  192. package/components/number-field/number-field.d.ts +41 -0
  193. package/components/number-field/number-field.js +455 -0
  194. package/components/number-field/number-field.module.css +71 -0
  195. package/components/otp-input/otp-input.d.ts +13 -0
  196. package/components/otp-input/otp-input.js +129 -0
  197. package/components/otp-input/otp-input.module.css +28 -0
  198. package/components/pagination/pagination.d.ts +7 -0
  199. package/components/pagination/pagination.js +60 -0
  200. package/components/pagination/pagination.module.css +16 -0
  201. package/components/password-field/password-field.d.ts +14 -0
  202. package/components/password-field/password-field.js +51 -0
  203. package/components/password-field/password-field.module.css +27 -0
  204. package/components/password-strength/password-strength.d.ts +107 -0
  205. package/components/password-strength/password-strength.js +161 -0
  206. package/components/password-strength/password-strength.module.css +57 -0
  207. package/components/phone-input/phone-input.d.ts +73 -0
  208. package/components/phone-input/phone-input.js +612 -0
  209. package/components/phone-input/phone-input.module.css +98 -0
  210. package/components/popover/popover.d.ts +6 -0
  211. package/components/popover/popover.js +19 -0
  212. package/components/popover/popover.module.css +32 -0
  213. package/components/progress/progress.d.ts +8 -0
  214. package/components/progress/progress.js +42 -0
  215. package/components/progress/progress.module.css +1 -0
  216. package/components/radio-cards/radio-cards.d.ts +35 -0
  217. package/components/radio-cards/radio-cards.js +110 -0
  218. package/components/radio-cards/radio-cards.module.css +84 -0
  219. package/components/radio-group/radio-group.d.ts +13 -0
  220. package/components/radio-group/radio-group.js +55 -0
  221. package/components/radio-group/radio-group.module.css +30 -0
  222. package/components/resizable-panels/resizable-panels.d.ts +37 -0
  223. package/components/resizable-panels/resizable-panels.js +338 -0
  224. package/components/resizable-panels/resizable-panels.module.css +40 -0
  225. package/components/rich-text-editor/rich-text-editor.d.ts +55 -0
  226. package/components/rich-text-editor/rich-text-editor.js +1733 -0
  227. package/components/rich-text-editor/rich-text-editor.module.css +201 -0
  228. package/components/ridgeline/ridgeline.d.ts +37 -0
  229. package/components/ridgeline/ridgeline.js +346 -0
  230. package/components/ridgeline/ridgeline.module.css +58 -0
  231. package/components/scroll-area/scroll-area.d.ts +40 -0
  232. package/components/scroll-area/scroll-area.js +153 -0
  233. package/components/scroll-area/scroll-area.module.css +79 -0
  234. package/components/search-field/search-field.d.ts +7 -0
  235. package/components/search-field/search-field.js +20 -0
  236. package/components/search-field/search-field.module.css +17 -0
  237. package/components/segmented-control/segmented-control.d.ts +16 -0
  238. package/components/segmented-control/segmented-control.js +56 -0
  239. package/components/segmented-control/segmented-control.module.css +15 -0
  240. package/components/select/select.d.ts +15 -0
  241. package/components/select/select.js +36 -0
  242. package/components/select/select.module.css +35 -0
  243. package/components/shortcut-recorder/shortcut-recorder.d.ts +108 -0
  244. package/components/shortcut-recorder/shortcut-recorder.js +380 -0
  245. package/components/shortcut-recorder/shortcut-recorder.module.css +85 -0
  246. package/components/signature-pad/signature-pad.d.ts +72 -0
  247. package/components/signature-pad/signature-pad.js +450 -0
  248. package/components/signature-pad/signature-pad.module.css +84 -0
  249. package/components/skeleton/skeleton.d.ts +13 -0
  250. package/components/skeleton/skeleton.js +53 -0
  251. package/components/skeleton/skeleton.module.css +11 -0
  252. package/components/slider/slider.d.ts +45 -0
  253. package/components/slider/slider.js +347 -0
  254. package/components/slider/slider.module.css +45 -0
  255. package/components/slope-chart/slope-chart.d.ts +38 -0
  256. package/components/slope-chart/slope-chart.js +183 -0
  257. package/components/slope-chart/slope-chart.module.css +51 -0
  258. package/components/slot-text/slot-text.d.ts +26 -0
  259. package/components/slot-text/slot-text.js +119 -0
  260. package/components/slot-text/slot-text.module.css +19 -0
  261. package/components/sortable-data-table/sortable-data-table.d.ts +38 -0
  262. package/components/sortable-data-table/sortable-data-table.js +240 -0
  263. package/components/sortable-data-table/sortable-data-table.module.css +116 -0
  264. package/components/sparkline/sparkline.d.ts +19 -0
  265. package/components/sparkline/sparkline.js +239 -0
  266. package/components/sparkline/sparkline.module.css +26 -0
  267. package/components/split-button/split-button.d.ts +19 -0
  268. package/components/split-button/split-button.js +33 -0
  269. package/components/split-button/split-button.module.css +51 -0
  270. package/components/stepper/stepper.d.ts +36 -0
  271. package/components/stepper/stepper.js +108 -0
  272. package/components/stepper/stepper.module.css +74 -0
  273. package/components/streamgraph/streamgraph.d.ts +51 -0
  274. package/components/streamgraph/streamgraph.js +376 -0
  275. package/components/streamgraph/streamgraph.module.css +55 -0
  276. package/components/swipe-actions/swipe-actions.d.ts +35 -0
  277. package/components/swipe-actions/swipe-actions.js +330 -0
  278. package/components/swipe-actions/swipe-actions.module.css +64 -0
  279. package/components/switch/switch.d.ts +7 -0
  280. package/components/switch/switch.js +45 -0
  281. package/components/switch/switch.module.css +12 -0
  282. package/components/tabs/tabs.d.ts +8 -0
  283. package/components/tabs/tabs.js +138 -0
  284. package/components/tabs/tabs.module.css +27 -0
  285. package/components/tag-input/tag-input.d.ts +15 -0
  286. package/components/tag-input/tag-input.js +150 -0
  287. package/components/tag-input/tag-input.module.css +34 -0
  288. package/components/text-morph/text-morph.d.ts +13 -0
  289. package/components/text-morph/text-morph.js +69 -0
  290. package/components/text-morph/text-morph.module.css +8 -0
  291. package/components/text-reveal/text-reveal.d.ts +14 -0
  292. package/components/text-reveal/text-reveal.js +20 -0
  293. package/components/text-reveal/text-reveal.module.css +13 -0
  294. package/components/text-shimmer/text-shimmer.d.ts +18 -0
  295. package/components/text-shimmer/text-shimmer.js +90 -0
  296. package/components/text-shimmer/text-shimmer.module.css +9 -0
  297. package/components/textarea/textarea.d.ts +7 -0
  298. package/components/textarea/textarea.js +56 -0
  299. package/components/textarea/textarea.module.css +22 -0
  300. package/components/theme-switch/theme-switch.d.ts +11 -0
  301. package/components/theme-switch/theme-switch.js +37 -0
  302. package/components/theme-switch/theme-switch.module.css +31 -0
  303. package/components/time-picker/time-picker.d.ts +13 -0
  304. package/components/time-picker/time-picker.js +95 -0
  305. package/components/time-picker/time-picker.module.css +23 -0
  306. package/components/timeline/timeline.d.ts +47 -0
  307. package/components/timeline/timeline.js +171 -0
  308. package/components/timeline/timeline.module.css +51 -0
  309. package/components/toast/toast.d.ts +8 -0
  310. package/components/toast/toast.js +118 -0
  311. package/components/toast/toast.module.css +100 -0
  312. package/components/toast-stack/toast-stack.d.ts +57 -0
  313. package/components/toast-stack/toast-stack.js +399 -0
  314. package/components/toast-stack/toast-stack.module.css +61 -0
  315. package/components/tooltip/tooltip.d.ts +8 -0
  316. package/components/tooltip/tooltip.js +62 -0
  317. package/components/tooltip/tooltip.module.css +18 -0
  318. package/components/tree-view/tree-view.d.ts +17 -0
  319. package/components/tree-view/tree-view.js +147 -0
  320. package/components/tree-view/tree-view.module.css +22 -0
  321. package/components/treemap/treemap.d.ts +35 -0
  322. package/components/treemap/treemap.js +375 -0
  323. package/components/treemap/treemap.module.css +59 -0
  324. package/components/usage-meter/usage-meter.d.ts +24 -0
  325. package/components/usage-meter/usage-meter.js +296 -0
  326. package/components/usage-meter/usage-meter.module.css +61 -0
  327. package/components/user-menu/user-menu.d.ts +62 -0
  328. package/components/user-menu/user-menu.js +316 -0
  329. package/components/user-menu/user-menu.module.css +97 -0
  330. package/components/waffle-chart/waffle-chart.d.ts +39 -0
  331. package/components/waffle-chart/waffle-chart.js +244 -0
  332. package/components/waffle-chart/waffle-chart.module.css +52 -0
  333. package/components.json +1330 -0
  334. package/lib/escape.d.ts +19 -0
  335. package/lib/escape.js +50 -0
  336. package/lib/media.d.ts +353 -0
  337. package/lib/media.js +65 -0
  338. package/lib/menu-highlight.d.ts +28 -0
  339. package/lib/menu-highlight.js +43 -0
  340. package/lib/motion-tokens.d.ts +60 -0
  341. package/lib/motion-tokens.js +25 -0
  342. package/lib/return-focus.d.ts +9 -0
  343. package/lib/return-focus.js +53 -0
  344. package/lib/silicon-provider.d.ts +60 -0
  345. package/lib/silicon-provider.js +47 -0
  346. package/lib/use-copy-feedback.d.ts +8 -0
  347. package/lib/use-copy-feedback.js +36 -0
  348. package/lib/use-today.d.ts +2 -0
  349. package/lib/use-today.js +29 -0
  350. package/package.json +66 -4
  351. package/styles.css +218 -0
  352. package/styles.css.d.ts +1 -0
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useLayoutEffect, useRef, useState } from "react";
4
+ import { AnimatePresence, motion, useReducedMotion } from "motion/react";
5
+ import { SiliconImage } from "../../lib/silicon-provider.js";
6
+ import { motionTokens } from "../../lib/motion-tokens.js";
7
+ import styles from "./avatar.module.css";
8
+ export function Avatar({ name, src, size = "md", status, className, ...props }) {
9
+ const initials = name.trim().split(/\s+/).slice(0, 2).map(part => part[0]?.toUpperCase()).join("");
10
+ const reduceMotion = !!useReducedMotion();
11
+ const image = useRef(null);
12
+ const [failedSrc, setFailedSrc] = useState();
13
+ // A photo that is already decoded shows at once. One that is still loading waits, then fades in from a soft blur.
14
+ useLayoutEffect(() => { const node = image.current; if (node && !node.complete)
15
+ node.dataset.loading = ""; }, [src]);
16
+ const showImage = src && failedSrc !== src;
17
+ return _jsxs("span", { ...props, className: [styles.avatar, styles[size], className].filter(Boolean).join(" "), role: "img", "aria-label": `${name}${status ? `, ${status}` : ""}`, children: [showImage ? _jsx(SiliconImage, { ref: image, src: src, alt: "", fill: true, sizes: size === "xl" ? "88px" : size === "lg" ? "48px" : size === "md" ? "36px" : "28px", onLoad: event => { delete event.currentTarget.dataset.loading; }, onError: () => setFailedSrc(src) }, src) : _jsx("span", { className: src ? styles.fallback : undefined, "aria-hidden": "true", children: initials }), _jsx(AnimatePresence, { initial: false, children: status && _jsx(motion.i, { className: [styles.status, styles[status]].join(" "), "aria-hidden": "true", initial: { opacity: 0, scale: .6 }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: .6, transition: { duration: reduceMotion ? 0 : motionTokens.duration.fast } }, transition: reduceMotion ? { duration: 0 } : motionTokens.spring.snappy }, status) })] });
18
+ }
@@ -0,0 +1,60 @@
1
+ .avatar {
2
+ position: relative;
3
+ display: inline-grid;
4
+ flex: 0 0 auto;
5
+ place-items: center;
6
+ overflow: visible;
7
+ border: 1px solid var(--border);
8
+ border-radius: var(--avatar-radius); corner-shape: var(--avatar-corner-shape);
9
+ background: var(--surface-muted);
10
+ color: var(--foreground);
11
+ font-size: var(--text-xs);
12
+ font-weight: 500;
13
+ }
14
+
15
+ .avatar img {
16
+ pointer-events: none;
17
+ border-radius: inherit; corner-shape: inherit;
18
+ object-fit: cover;
19
+ transition: opacity var(--duration-standard) var(--ease-enter), filter var(--duration-standard) var(--ease-enter);
20
+ }
21
+
22
+ /* Set only while a photo is still downloading after mount, so cached photos never fade. */
23
+ .avatar img[data-loading] {
24
+ opacity: 0;
25
+ filter: blur(4px);
26
+ transition: none;
27
+ }
28
+
29
+ .fallback { animation: avatar-fallback-in var(--duration-standard) var(--ease-enter) both; }
30
+
31
+ .sm { width: 28px; height: 28px; font-size: 10px; }
32
+ .md { width: 36px; height: 36px; }
33
+ .lg { width: 48px; height: 48px; font-size: var(--text-sm); }
34
+ .xl { width: 88px; height: 88px; font-size: var(--text-xl); }
35
+
36
+ .status {
37
+ position: absolute;
38
+ right: 0;
39
+ bottom: 0;
40
+ z-index: 2;
41
+ width: 10px;
42
+ height: 10px;
43
+ border: 2px solid var(--surface);
44
+ border-radius: var(--radius-full); corner-shape: round;
45
+ box-shadow: 0 0 0 1px color-mix(in oklab, var(--border) 70%, transparent);
46
+ }
47
+
48
+ .sm .status { width: 8px; height: 8px; border-width: 1.5px; }
49
+ .lg .status { width: 12px; height: 12px; }
50
+ .xl .status { width: 14px; height: 14px; right: 4px; bottom: 4px; }
51
+ .online { background: var(--success); }
52
+ .offline { background: var(--text-muted); }
53
+
54
+ @keyframes avatar-fallback-in { from { opacity: 0; } to { opacity: 1; } }
55
+
56
+ @media (prefers-reduced-motion: reduce) {
57
+ .avatar img { transition: none; }
58
+ .avatar img[data-loading] { filter: none; }
59
+ .fallback { animation: none; }
60
+ }
@@ -0,0 +1,13 @@
1
+ export interface AvatarGroupMember {
2
+ name: string;
3
+ src?: string;
4
+ status?: "online" | "offline";
5
+ }
6
+ export interface AvatarGroupProps {
7
+ members: AvatarGroupMember[];
8
+ max?: number;
9
+ size?: "sm" | "md" | "lg";
10
+ label?: string;
11
+ }
12
+ export declare function AvatarGroup({ members, max, size, label }: AvatarGroupProps): import("react").JSX.Element;
13
+ export default AvatarGroup;
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { AnimatePresence, motion, useReducedMotion } from "motion/react";
5
+ import { motionTokens } from "../../lib/motion-tokens.js";
6
+ import { Avatar } from "../avatar/avatar.js";
7
+ import styles from "./avatar-group.module.css";
8
+ /** The overflow count rolls the way it moved: more people rise in from below, fewer drop in from above. */
9
+ const rise = { hidden: (direction) => ({ opacity: 0, y: `${.4 * direction}em`, filter: `blur(${motionTokens.blur.subtle}px)` }), shown: { opacity: 1, y: 0, filter: "blur(0px)", transition: { duration: motionTokens.duration.standard, ease: [...motionTokens.ease.enter] } }, gone: (direction) => ({ opacity: 0, y: `${-.4 * direction}em`, filter: `blur(${motionTokens.blur.subtle}px)`, transition: { duration: motionTokens.duration.fast, ease: [...motionTokens.ease.standard] } }) };
10
+ // Same keys as `rise` so the settled style is identical whichever branch renders on the server.
11
+ const fade = { hidden: { opacity: 0, y: 0, filter: "blur(0px)" }, shown: { opacity: 1, y: 0, filter: "blur(0px)", transition: { duration: motionTokens.duration.instant } }, gone: { opacity: 0, y: 0, filter: "blur(0px)", transition: { duration: motionTokens.duration.instant } } };
12
+ // A person joining or leaving opens or closes their slot, so the rest of the stack slides instead of jumping.
13
+ const slot = { initial: { width: 0, opacity: 0, scale: .9 }, animate: { width: "auto", opacity: 1, scale: 1 }, exit: { width: 0, opacity: 0, scale: .9 } };
14
+ export function AvatarGroup({ members, max = 4, size = "md", label = "Team members" }) {
15
+ const reduceMotion = !!useReducedMotion();
16
+ const visible = members.slice(0, Math.max(0, max));
17
+ const overflow = Math.max(0, members.length - visible.length);
18
+ const transition = reduceMotion ? { duration: 0 } : motionTokens.spring.morph;
19
+ const [count, setCount] = useState({ overflow, direction: 1 });
20
+ if (count.overflow !== overflow)
21
+ setCount({ overflow, direction: overflow < count.overflow ? -1 : 1 });
22
+ return _jsx("div", { className: [styles.group, styles[size]].join(" "), role: "group", "aria-label": label, style: { "--count": visible.length + (overflow > 0 ? 1 : 0) }, children: _jsxs(AnimatePresence, { initial: false, children: [visible.map((member, index) => _jsx(motion.span, { className: styles.slot, style: { "--index": index }, ...slot, transition: transition, children: _jsxs("span", { className: styles.lift, children: [_jsx(Avatar, { className: styles.avatar, name: member.name, src: member.src, status: member.status, size: size }), _jsx("span", { className: styles.tip, "aria-hidden": "true", children: member.name })] }) }, member.name)), overflow > 0 ? _jsx(motion.span, { className: styles.slot, style: { "--index": visible.length }, ...slot, transition: transition, children: _jsx("span", { className: [styles.lift, styles.overflow, styles[size]].join(" "), role: "img", "aria-label": `${overflow} more ${label.toLowerCase()}`, children: _jsx(AnimatePresence, { mode: "popLayout", initial: false, custom: count.direction, children: _jsxs(motion.span, { className: styles.count, custom: count.direction, variants: reduceMotion ? fade : rise, initial: "hidden", animate: "shown", exit: "gone", "aria-hidden": "true", children: ["+", overflow] }, overflow) }) }) }, "overflow") : null] }) });
23
+ }
24
+ export default AvatarGroup;
@@ -0,0 +1,27 @@
1
+ .group { --avatar-size: 36px; display: inline-flex; height: var(--avatar-size); align-items: center; padding-left: 6px; }
2
+ .group.sm { --avatar-size: 28px; }
3
+ .group.lg { --avatar-size: 48px; }
4
+ /* Each slot is the avatar's visible width, so a slot that opens or closes moves the rest of the stack smoothly. */
5
+ .slot { position: relative; display: inline-flex; flex: 0 0 auto; height: var(--avatar-size); align-items: center; }
6
+ /* One wrapper per person carries every hover move as a single translate, so the stack never changes size. */
7
+ .lift { --fan: 0px; --aside: 0px; --rise: 0px; position: relative; display: inline-flex; margin-left: -6px; border-radius: var(--avatar-radius); corner-shape: var(--avatar-corner-shape); transform: translate(calc(var(--fan) + var(--aside)), var(--rise)); transition: transform var(--duration-standard) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard); }
8
+ .avatar, .overflow { border: 2px solid var(--surface); box-shadow: 0 0 0 1px var(--border); transition: box-shadow var(--duration-fast) var(--ease-standard); }
9
+ .overflow { position: relative; display: inline-grid; place-items: center; overflow: hidden; border-radius: var(--avatar-radius); corner-shape: var(--avatar-corner-shape); background: var(--surface-muted); color: var(--text-secondary); font-size: var(--text-xs); font-weight: 500; font-variant-numeric: tabular-nums; }
10
+ .count { display: inline-block; }
11
+ .overflow.sm { width: 28px; height: 28px; font-size: 10px; }
12
+ .overflow.md { width: 36px; height: 36px; }
13
+ .overflow.lg { width: 48px; height: 48px; font-size: var(--text-sm); }
14
+ /* The name floats above the stack, outside the layout, so showing it never moves anything. */
15
+ .tip { position: absolute; z-index: 2; bottom: calc(100% + 8px); left: 50%; padding: 4px 8px; border-radius: var(--radius-full); corner-shape: round; background: var(--foreground); color: var(--background); font-size: var(--text-xs); font-weight: 500; line-height: var(--leading-body); white-space: nowrap; pointer-events: none; opacity: 0; transform: translate(-50%, 3px); transition: opacity var(--duration-fast) var(--ease-standard), transform var(--duration-fast) var(--ease-standard); }
16
+ /* Pointing at the stack loosens its overlap from the center; the person under the pointer lifts with a crisp ring and names themselves, and their neighbors ease aside. */
17
+ @media (hover: hover) and (pointer: fine) {
18
+ .group:hover .lift { --fan: calc((var(--index) - (var(--count) - 1) / 2) * 4px); }
19
+ .slot:hover { z-index: 1; }
20
+ .slot:hover .lift { --rise: -2px; }
21
+ .slot:hover ~ .slot .lift { --aside: 3px; }
22
+ .slot:has(~ .slot:hover) .lift { --aside: -3px; }
23
+ .slot:hover .avatar, .slot:hover .overflow { box-shadow: 0 0 0 1px var(--border-strong); }
24
+ .slot:hover .tip { opacity: 1; transform: translate(-50%, 0); transition-delay: 60ms; }
25
+ }
26
+ /* Reduced motion keeps the stack still; the ring and name still answer the pointer. */
27
+ @media (prefers-reduced-motion: reduce) { .lift { transform: none !important; transition: none; } .tip { transform: translate(-50%, 0); transition: none; } }
@@ -0,0 +1,10 @@
1
+ import type { HTMLAttributes, ReactNode } from "react";
2
+ export type BadgeTone = "neutral" | "success" | "info" | "warning" | "danger";
3
+ export type BadgeSize = "sm" | "md";
4
+ export interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
5
+ tone?: BadgeTone;
6
+ size?: BadgeSize;
7
+ icon?: ReactNode;
8
+ }
9
+ export declare function Badge({ tone, size, icon, className, children, ...props }: BadgeProps): import("react").JSX.Element;
10
+ export default Badge;
@@ -0,0 +1,66 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { isValidElement, useEffect, useLayoutEffect, useRef } from "react";
4
+ import { AnimatePresence, animate, motion, useIsPresent, useMotionValue, useReducedMotion } from "motion/react";
5
+ import { motionTokens } from "../../lib/motion-tokens.js";
6
+ import styles from "./badge.module.css";
7
+ const exitFast = { duration: motionTokens.duration.fast, ease: [...motionTokens.ease.standard] };
8
+ const textIn = { opacity: 0, y: "0.3em", filter: `blur(${motionTokens.blur.soft}px)` };
9
+ const textOut = { opacity: 0, y: "-0.3em", filter: `blur(${motionTokens.blur.subtle}px)`, transition: exitFast };
10
+ const iconIn = { opacity: 0, scale: .6, filter: `blur(${motionTokens.blur.subtle}px)` };
11
+ const shown = { opacity: 1, y: "0em", scale: 1, filter: "blur(0px)" };
12
+ const fadeOnly = { opacity: 0, transition: { duration: motionTokens.duration.instant } };
13
+ /** Outgoing copies are hidden from assistive tech while they fade, so only the current text is read. */
14
+ function Swap(props) {
15
+ const present = useIsPresent();
16
+ return _jsx(motion.span, { ...props, "aria-hidden": present ? props["aria-hidden"] : true });
17
+ }
18
+ /** A new icon component crossfades in; re-rendering the same icon stays still. */
19
+ function iconKey(icon) {
20
+ if (!isValidElement(icon))
21
+ return "icon";
22
+ const type = icon.type;
23
+ return typeof type === "string" ? type : type.displayName ?? type.name ?? "icon";
24
+ }
25
+ export function Badge({ tone = "neutral", size = "md", icon, className, children, ...props }) {
26
+ const reduce = useReducedMotion();
27
+ const text = typeof children === "string" || typeof children === "number" ? String(children) : null;
28
+ const glyphKey = icon ? iconKey(icon) : "";
29
+ const body = useRef(null);
30
+ const content = useRef(null);
31
+ // Width stays auto at rest. Only a new label or icon springs it from the old size to the new one; passive reflows (a font swap, a hidden parent) follow instantly.
32
+ const width = useMotionValue("auto");
33
+ const changedAt = useRef(0);
34
+ useLayoutEffect(() => { changedAt.current = performance.now(); }, [text, glyphKey]);
35
+ useEffect(() => {
36
+ const node = content.current;
37
+ if (!node || typeof ResizeObserver === "undefined")
38
+ return;
39
+ let last;
40
+ let controls;
41
+ const settle = () => { width.jump("auto"); if (body.current)
42
+ body.current.style.width = "auto"; };
43
+ const observer = new ResizeObserver(([entry]) => {
44
+ if (!entry)
45
+ return;
46
+ const next = entry.borderBoxSize?.[0]?.inlineSize ?? node.offsetWidth;
47
+ const current = width.get();
48
+ const from = typeof current === "number" ? current : last;
49
+ last = next;
50
+ controls?.stop();
51
+ if (reduce || from === undefined || from === next || performance.now() - changedAt.current > 120)
52
+ return settle();
53
+ // Pin the old width before this frame paints, then spring to the new one.
54
+ if (body.current)
55
+ body.current.style.width = `${from}px`;
56
+ controls = animate(width, [from, next], { ...motionTokens.spring.morph, onComplete: settle });
57
+ });
58
+ observer.observe(node);
59
+ return () => { observer.disconnect(); controls?.stop(); };
60
+ }, [width, reduce]);
61
+ const enter = reduce ? { duration: motionTokens.duration.instant } : { duration: motionTokens.duration.standard, ease: [...motionTokens.ease.enter] };
62
+ const classes = [styles.badge, styles[tone], styles[size], className].filter(Boolean).join(" ");
63
+ // The pill follows its content: text and icon swap in place while the width springs to the new size.
64
+ return _jsx("span", { ...props, className: classes, children: _jsx(motion.span, { ref: body, className: styles.body, style: { width }, children: _jsxs("span", { ref: content, className: styles.content, children: [icon ? _jsx("span", { className: styles.icon, "aria-hidden": "true", children: _jsx(AnimatePresence, { mode: "popLayout", initial: false, children: _jsx(Swap, { className: styles.glyph, initial: reduce ? { opacity: 0 } : iconIn, animate: shown, exit: reduce ? fadeOnly : { ...iconIn, transition: exitFast }, transition: reduce ? enter : motionTokens.spring.snappy, children: icon }, glyphKey) }) }) : null, text === null ? children : _jsx("span", { className: styles.label, children: _jsx(AnimatePresence, { mode: "popLayout", initial: false, children: _jsx(Swap, { className: styles.text, initial: reduce ? { opacity: 0 } : textIn, animate: shown, exit: reduce ? fadeOnly : textOut, transition: enter, children: text }, text) }) })] }) }) });
65
+ }
66
+ export default Badge;
@@ -0,0 +1,52 @@
1
+ .badge {
2
+ display: inline-flex;
3
+ min-height: 26px;
4
+ align-items: center;
5
+ border: 1px solid var(--badge-border, var(--border));
6
+ border-radius: var(--radius-full); corner-shape: round;
7
+ padding: 0 10px;
8
+ color: var(--badge-foreground, var(--foreground));
9
+ background: var(--badge-background, var(--surface));
10
+ font-size: var(--text-xs);
11
+ font-weight: 500;
12
+ letter-spacing: -.01em;
13
+ line-height: 1;
14
+ white-space: nowrap;
15
+ /* Clip keeps the inline baseline while the pill morphs around swapped text. */
16
+ overflow: clip;
17
+ transition: border-color var(--duration-standard) var(--ease-standard), background-color var(--duration-standard) var(--ease-standard), color var(--duration-standard) var(--ease-standard);
18
+ }
19
+
20
+ @media (hover: hover) and (pointer: fine) {
21
+ .badge:hover { border-color: color-mix(in oklab, var(--badge-color, var(--foreground)) 32%, var(--border)); background: color-mix(in oklab, var(--badge-color, var(--foreground)) 10%, var(--surface)); }
22
+ }
23
+ .sm { min-height: 22px; padding: 0 8px; font-size: 11px; }
24
+ .md { font-size: var(--text-xs); }
25
+
26
+ .body { display: block; }
27
+ .content { position: relative; display: inline-flex; width: max-content; align-items: center; gap: 5px; }
28
+ .sm .content { gap: 4px; }
29
+ .label, .glyph { position: relative; display: inline-flex; align-items: center; }
30
+ .text { display: block; }
31
+
32
+ .icon {
33
+ position: relative;
34
+ display: inline-flex;
35
+ width: auto;
36
+ height: auto;
37
+ flex: 0 0 auto;
38
+ align-items: center;
39
+ justify-content: center;
40
+ color: var(--badge-color, var(--foreground));
41
+ line-height: 1;
42
+ }
43
+
44
+ .neutral { --badge-color: var(--text-secondary); --badge-foreground: var(--text-secondary); --badge-background: var(--surface-muted); --badge-border: var(--border); }
45
+ .success { --badge-color: var(--success); --badge-foreground: var(--success); --badge-background: color-mix(in oklab, var(--success) 10%, var(--surface)); --badge-border: color-mix(in oklab, var(--success) 25%, var(--border)); }
46
+ .info { --badge-color: var(--accent); --badge-foreground: var(--accent-strong); --badge-background: var(--accent-subtle); --badge-border: color-mix(in oklab, var(--accent) 24%, var(--border)); }
47
+ .warning { --badge-color: var(--warning); --badge-foreground: var(--warning); --badge-background: color-mix(in oklab, var(--warning) 11%, var(--surface)); --badge-border: color-mix(in oklab, var(--warning) 27%, var(--border)); }
48
+ .danger { --badge-color: var(--danger); --badge-foreground: var(--danger); --badge-background: color-mix(in oklab, var(--danger) 10%, var(--surface)); --badge-border: color-mix(in oklab, var(--danger) 26%, var(--border)); }
49
+
50
+ @media (prefers-reduced-motion: reduce) {
51
+ .badge { transition-duration: var(--duration-instant); }
52
+ }
@@ -0,0 +1,32 @@
1
+ export interface BarChartDatum {
2
+ /** Stable identity, such as an ISO date. A bar whose key survives a data change keeps its place, so switching ranges morphs instead of redrawing. */
3
+ key: string;
4
+ /** Full label for the headline and screen readers, such as "Tue, Sep 15". */
5
+ label: string;
6
+ /** Short label under the bar, such as "T" or "Sep 14". Leave it out to keep the axis quiet. */
7
+ axisLabel?: string;
8
+ value: number;
9
+ }
10
+ /** Use a bar chart for one measure across a run of days, weeks, or months, when people compare each period against the rest and against the average. */
11
+ export interface BarChartProps {
12
+ data: BarChartDatum[];
13
+ /** What is measured, such as "Active minutes". Names the chart for assistive technology. */
14
+ label: string;
15
+ /** The range on show, such as "Sep 15–21, 2026". It rests under the headline. */
16
+ period: string;
17
+ /** Unit after each value, such as "min". */
18
+ unit?: string;
19
+ /** Headline label at rest, above the average. */
20
+ averageLabel?: string;
21
+ /** Headline label while a bar is scrubbed. */
22
+ valueLabel?: string;
23
+ /** Header of the first column in the data table read by screen readers. */
24
+ categoryLabel?: string;
25
+ /** Draws the average as a reference line that springs to each new range. */
26
+ showAverage?: boolean;
27
+ /** Plot height in pixels. */
28
+ height?: number;
29
+ formatValue?: (value: number) => string;
30
+ }
31
+ export declare function BarChart({ data, label, period, unit, averageLabel, valueLabel, categoryLabel, showAverage, height, formatValue }: BarChartProps): import("react").JSX.Element;
32
+ export default BarChart;