@spatika/react 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (369) hide show
  1. package/AGENTS.md +71 -0
  2. package/README.md +4 -3
  3. package/dist/composites/AccentRule.d.ts +6 -0
  4. package/dist/composites/AccentRule.d.ts.map +1 -0
  5. package/dist/composites/AccentRule.js +6 -0
  6. package/dist/composites/AvailabilityBadge.d.ts +9 -0
  7. package/dist/composites/AvailabilityBadge.d.ts.map +1 -0
  8. package/dist/composites/AvailabilityBadge.js +9 -0
  9. package/dist/composites/Card.d.ts +7 -1
  10. package/dist/composites/Card.d.ts.map +1 -1
  11. package/dist/composites/Card.js +10 -0
  12. package/dist/composites/CareerCard.d.ts +20 -0
  13. package/dist/composites/CareerCard.d.ts.map +1 -0
  14. package/dist/composites/CareerCard.js +17 -0
  15. package/dist/composites/ChartDataGrid.d.ts +33 -0
  16. package/dist/composites/ChartDataGrid.d.ts.map +1 -0
  17. package/dist/composites/ChartDataGrid.js +77 -0
  18. package/dist/composites/ContactLink.d.ts +15 -0
  19. package/dist/composites/ContactLink.d.ts.map +1 -0
  20. package/dist/composites/ContactLink.js +8 -0
  21. package/dist/composites/CoverHero.d.ts +1 -1
  22. package/dist/composites/CoverHero.d.ts.map +1 -1
  23. package/dist/composites/CoverHero.js +2 -2
  24. package/dist/composites/DisplayHeading.d.ts +9 -0
  25. package/dist/composites/DisplayHeading.d.ts.map +1 -0
  26. package/dist/composites/DisplayHeading.js +6 -0
  27. package/dist/composites/EntityMediaCard.d.ts +1 -1
  28. package/dist/composites/EntityMediaCard.d.ts.map +1 -1
  29. package/dist/composites/EntityMediaCard.js +12 -4
  30. package/dist/composites/EventCalendar.d.ts +35 -0
  31. package/dist/composites/EventCalendar.d.ts.map +1 -0
  32. package/dist/composites/EventCalendar.js +339 -0
  33. package/dist/composites/EventEditor.d.ts +22 -0
  34. package/dist/composites/EventEditor.d.ts.map +1 -0
  35. package/dist/composites/EventEditor.js +86 -0
  36. package/dist/composites/EventTimeline.d.ts +24 -0
  37. package/dist/composites/EventTimeline.d.ts.map +1 -0
  38. package/dist/composites/EventTimeline.js +184 -0
  39. package/dist/composites/FloatChip.d.ts +15 -0
  40. package/dist/composites/FloatChip.d.ts.map +1 -0
  41. package/dist/composites/FloatChip.js +7 -0
  42. package/dist/composites/GradientText.d.ts +11 -0
  43. package/dist/composites/GradientText.d.ts.map +1 -0
  44. package/dist/composites/GradientText.js +6 -0
  45. package/dist/composites/IconTile.d.ts +10 -0
  46. package/dist/composites/IconTile.d.ts.map +1 -0
  47. package/dist/composites/IconTile.js +7 -0
  48. package/dist/composites/MapChart.d.ts +24 -0
  49. package/dist/composites/MapChart.d.ts.map +1 -0
  50. package/dist/composites/MapChart.js +58 -0
  51. package/dist/composites/MetaChip.d.ts +9 -0
  52. package/dist/composites/MetaChip.d.ts.map +1 -0
  53. package/dist/composites/MetaChip.js +6 -0
  54. package/dist/composites/PresenceDot.d.ts +10 -0
  55. package/dist/composites/PresenceDot.d.ts.map +1 -0
  56. package/dist/composites/PresenceDot.js +10 -0
  57. package/dist/composites/ProfileHero.d.ts +6 -4
  58. package/dist/composites/ProfileHero.d.ts.map +1 -1
  59. package/dist/composites/ProfileHero.js +8 -8
  60. package/dist/composites/ProjectCard.d.ts +12 -0
  61. package/dist/composites/ProjectCard.d.ts.map +1 -0
  62. package/dist/composites/ProjectCard.js +9 -0
  63. package/dist/composites/ScatterWebGL.d.ts +22 -0
  64. package/dist/composites/ScatterWebGL.d.ts.map +1 -0
  65. package/dist/composites/ScatterWebGL.js +45 -0
  66. package/dist/composites/SectionHeading.d.ts +16 -0
  67. package/dist/composites/SectionHeading.d.ts.map +1 -0
  68. package/dist/composites/SectionHeading.js +12 -0
  69. package/dist/composites/SiteFooter.d.ts +18 -0
  70. package/dist/composites/SiteFooter.d.ts.map +1 -0
  71. package/dist/composites/SiteFooter.js +15 -0
  72. package/dist/composites/SiteNav.d.ts +25 -0
  73. package/dist/composites/SiteNav.d.ts.map +1 -0
  74. package/dist/composites/SiteNav.js +44 -0
  75. package/dist/composites/StatCard.d.ts +7 -1
  76. package/dist/composites/StatCard.d.ts.map +1 -1
  77. package/dist/composites/StatCard.js +5 -2
  78. package/dist/composites/StatusDot.d.ts +1 -1
  79. package/dist/composites/Tag.d.ts +11 -0
  80. package/dist/composites/Tag.d.ts.map +1 -0
  81. package/dist/composites/Tag.js +33 -0
  82. package/dist/composites/Wordmark.d.ts +19 -0
  83. package/dist/composites/Wordmark.d.ts.map +1 -0
  84. package/dist/composites/Wordmark.js +15 -0
  85. package/dist/composites/cartesian-charts.d.ts +138 -0
  86. package/dist/composites/cartesian-charts.d.ts.map +1 -0
  87. package/dist/composites/cartesian-charts.js +401 -0
  88. package/dist/composites/chart-composition.d.ts +139 -0
  89. package/dist/composites/chart-composition.d.ts.map +1 -0
  90. package/dist/composites/chart-composition.js +486 -0
  91. package/dist/composites/chart-ui.d.ts +83 -0
  92. package/dist/composites/chart-ui.d.ts.map +1 -0
  93. package/dist/composites/chart-ui.js +108 -0
  94. package/dist/composites/charts-3d.d.ts +37 -0
  95. package/dist/composites/charts-3d.d.ts.map +1 -0
  96. package/dist/composites/charts-3d.js +121 -0
  97. package/dist/composites/flow-charts.d.ts +89 -0
  98. package/dist/composites/flow-charts.d.ts.map +1 -0
  99. package/dist/composites/flow-charts.js +186 -0
  100. package/dist/composites/radial-charts.d.ts +109 -0
  101. package/dist/composites/radial-charts.d.ts.map +1 -0
  102. package/dist/composites/radial-charts.js +176 -0
  103. package/dist/composites/scheduler-ui.d.ts +43 -0
  104. package/dist/composites/scheduler-ui.d.ts.map +1 -0
  105. package/dist/composites/scheduler-ui.js +71 -0
  106. package/dist/index.d.ts +83 -7
  107. package/dist/index.d.ts.map +1 -1
  108. package/dist/index.js +74 -7
  109. package/dist/lib/chart-export.d.ts +10 -0
  110. package/dist/lib/chart-export.d.ts.map +1 -0
  111. package/dist/lib/chart-export.js +102 -0
  112. package/dist/lib/charts.d.ts +235 -0
  113. package/dist/lib/charts.d.ts.map +1 -0
  114. package/dist/lib/charts.js +744 -0
  115. package/dist/lib/geo.d.ts +39 -0
  116. package/dist/lib/geo.d.ts.map +1 -0
  117. package/dist/lib/geo.js +101 -0
  118. package/dist/lib/iso.d.ts +21 -0
  119. package/dist/lib/iso.d.ts.map +1 -0
  120. package/dist/lib/iso.js +56 -0
  121. package/dist/lib/rrule.d.ts +20 -0
  122. package/dist/lib/rrule.d.ts.map +1 -0
  123. package/dist/lib/rrule.js +236 -0
  124. package/dist/lib/scheduler.d.ts +152 -0
  125. package/dist/lib/scheduler.d.ts.map +1 -0
  126. package/dist/lib/scheduler.js +501 -0
  127. package/dist/lib/webgl-scatter.d.ts +44 -0
  128. package/dist/lib/webgl-scatter.d.ts.map +1 -0
  129. package/dist/lib/webgl-scatter.js +185 -0
  130. package/dist/primitives/Accordion.d.ts +44 -20
  131. package/dist/primitives/Accordion.d.ts.map +1 -1
  132. package/dist/primitives/Accordion.js +82 -22
  133. package/dist/primitives/AppBar.d.ts +13 -0
  134. package/dist/primitives/AppBar.d.ts.map +1 -0
  135. package/dist/primitives/AppBar.js +27 -0
  136. package/dist/primitives/Autocomplete.d.ts +28 -0
  137. package/dist/primitives/Autocomplete.d.ts.map +1 -0
  138. package/dist/primitives/Autocomplete.js +118 -0
  139. package/dist/primitives/Avatar.d.ts +13 -1
  140. package/dist/primitives/Avatar.d.ts.map +1 -1
  141. package/dist/primitives/Avatar.js +17 -2
  142. package/dist/primitives/Backdrop.d.ts +17 -0
  143. package/dist/primitives/Backdrop.d.ts.map +1 -0
  144. package/dist/primitives/Backdrop.js +17 -0
  145. package/dist/primitives/BottomNavigation.d.ts +23 -0
  146. package/dist/primitives/BottomNavigation.d.ts.map +1 -0
  147. package/dist/primitives/BottomNavigation.js +30 -0
  148. package/dist/primitives/Button.d.ts +4 -4
  149. package/dist/primitives/Button.d.ts.map +1 -1
  150. package/dist/primitives/Button.js +2 -0
  151. package/dist/primitives/ButtonBase.d.ts +14 -0
  152. package/dist/primitives/ButtonBase.d.ts.map +1 -0
  153. package/dist/primitives/ButtonBase.js +13 -0
  154. package/dist/primitives/ButtonGroup.d.ts +25 -0
  155. package/dist/primitives/ButtonGroup.d.ts.map +1 -0
  156. package/dist/primitives/ButtonGroup.js +44 -0
  157. package/dist/primitives/CircularProgress.d.ts +16 -0
  158. package/dist/primitives/CircularProgress.d.ts.map +1 -0
  159. package/dist/primitives/CircularProgress.js +17 -0
  160. package/dist/primitives/ClickAwayListener.d.ts +16 -0
  161. package/dist/primitives/ClickAwayListener.d.ts.map +1 -0
  162. package/dist/primitives/ClickAwayListener.js +33 -0
  163. package/dist/primitives/Collapse.d.ts +19 -0
  164. package/dist/primitives/Collapse.d.ts.map +1 -0
  165. package/dist/primitives/Collapse.js +14 -0
  166. package/dist/primitives/Container.d.ts +13 -0
  167. package/dist/primitives/Container.d.ts.map +1 -0
  168. package/dist/primitives/Container.js +26 -0
  169. package/dist/primitives/Fab.d.ts +22 -0
  170. package/dist/primitives/Fab.d.ts.map +1 -0
  171. package/dist/primitives/Fab.js +42 -0
  172. package/dist/primitives/FormControl.d.ts +27 -0
  173. package/dist/primitives/FormControl.d.ts.map +1 -0
  174. package/dist/primitives/FormControl.js +24 -0
  175. package/dist/primitives/FormControlLabel.d.ts +18 -0
  176. package/dist/primitives/FormControlLabel.d.ts.map +1 -0
  177. package/dist/primitives/FormControlLabel.js +19 -0
  178. package/dist/primitives/Grid.d.ts +32 -0
  179. package/dist/primitives/Grid.d.ts.map +1 -0
  180. package/dist/primitives/Grid.js +50 -0
  181. package/dist/primitives/IconButton.d.ts +22 -0
  182. package/dist/primitives/IconButton.d.ts.map +1 -0
  183. package/dist/primitives/IconButton.js +39 -0
  184. package/dist/primitives/ImageList.d.ts +31 -0
  185. package/dist/primitives/ImageList.d.ts.map +1 -0
  186. package/dist/primitives/ImageList.js +33 -0
  187. package/dist/primitives/InputAdornment.d.ts +28 -0
  188. package/dist/primitives/InputAdornment.d.ts.map +1 -0
  189. package/dist/primitives/InputAdornment.js +13 -0
  190. package/dist/primitives/Link.d.ts +17 -0
  191. package/dist/primitives/Link.d.ts.map +1 -0
  192. package/dist/primitives/Link.js +29 -0
  193. package/dist/primitives/List.d.ts +41 -0
  194. package/dist/primitives/List.d.ts.map +1 -0
  195. package/dist/primitives/List.js +22 -0
  196. package/dist/primitives/Masonry.d.ts +14 -0
  197. package/dist/primitives/Masonry.d.ts.map +1 -0
  198. package/dist/primitives/Masonry.js +15 -0
  199. package/dist/primitives/Menu.d.ts +28 -0
  200. package/dist/primitives/Menu.d.ts.map +1 -0
  201. package/dist/primitives/Menu.js +54 -0
  202. package/dist/primitives/MobileStepper.d.ts +15 -0
  203. package/dist/primitives/MobileStepper.d.ts.map +1 -0
  204. package/dist/primitives/MobileStepper.js +8 -0
  205. package/dist/primitives/Modal.d.ts +18 -0
  206. package/dist/primitives/Modal.d.ts.map +1 -0
  207. package/dist/primitives/Modal.js +29 -0
  208. package/dist/primitives/NoSsr.d.ts +15 -0
  209. package/dist/primitives/NoSsr.d.ts.map +1 -0
  210. package/dist/primitives/NoSsr.js +19 -0
  211. package/dist/primitives/Paper.d.ts +22 -0
  212. package/dist/primitives/Paper.d.ts.map +1 -0
  213. package/dist/primitives/Paper.js +33 -0
  214. package/dist/primitives/Progress.d.ts +6 -2
  215. package/dist/primitives/Progress.d.ts.map +1 -1
  216. package/dist/primitives/Progress.js +8 -3
  217. package/dist/primitives/Snackbar.d.ts +23 -0
  218. package/dist/primitives/Snackbar.d.ts.map +1 -0
  219. package/dist/primitives/Snackbar.js +33 -0
  220. package/dist/primitives/SpeedDial.d.ts +26 -0
  221. package/dist/primitives/SpeedDial.d.ts.map +1 -0
  222. package/dist/primitives/SpeedDial.js +26 -0
  223. package/dist/primitives/Stack.d.ts +15 -0
  224. package/dist/primitives/Stack.d.ts.map +1 -0
  225. package/dist/primitives/Stack.js +45 -0
  226. package/dist/primitives/StarRating.d.ts +19 -1
  227. package/dist/primitives/StarRating.d.ts.map +1 -1
  228. package/dist/primitives/StarRating.js +36 -6
  229. package/dist/primitives/Stepper.d.ts +36 -0
  230. package/dist/primitives/Stepper.d.ts.map +1 -0
  231. package/dist/primitives/Stepper.js +53 -0
  232. package/dist/primitives/TablePagination.d.ts +16 -0
  233. package/dist/primitives/TablePagination.d.ts.map +1 -0
  234. package/dist/primitives/TablePagination.js +12 -0
  235. package/dist/primitives/TextField.d.ts +24 -0
  236. package/dist/primitives/TextField.d.ts.map +1 -0
  237. package/dist/primitives/TextField.js +19 -0
  238. package/dist/primitives/TextareaAutosize.d.ts +11 -0
  239. package/dist/primitives/TextareaAutosize.d.ts.map +1 -0
  240. package/dist/primitives/TextareaAutosize.js +26 -0
  241. package/dist/primitives/ToggleButton.d.ts +28 -0
  242. package/dist/primitives/ToggleButton.d.ts.map +1 -0
  243. package/dist/primitives/ToggleButton.js +56 -0
  244. package/dist/primitives/TransferList.d.ts +21 -0
  245. package/dist/primitives/TransferList.d.ts.map +1 -0
  246. package/dist/primitives/TransferList.js +40 -0
  247. package/dist/primitives/Typography.d.ts +23 -0
  248. package/dist/primitives/Typography.d.ts.map +1 -0
  249. package/dist/primitives/Typography.js +69 -0
  250. package/dist/primitives/transitions.d.ts +29 -0
  251. package/dist/primitives/transitions.d.ts.map +1 -0
  252. package/dist/primitives/transitions.js +52 -0
  253. package/package.json +30 -5
  254. package/skills/spatika-ui/SKILL.md +96 -0
  255. package/src/composites/AccentRule.tsx +12 -0
  256. package/src/composites/AvailabilityBadge.tsx +32 -0
  257. package/src/composites/Card.tsx +51 -1
  258. package/src/composites/CareerCard.tsx +111 -0
  259. package/src/composites/ChartDataGrid.test.tsx +57 -0
  260. package/src/composites/ChartDataGrid.tsx +196 -0
  261. package/src/composites/ContactLink.tsx +66 -0
  262. package/src/composites/CoverHero.test.tsx +38 -0
  263. package/src/composites/CoverHero.tsx +29 -22
  264. package/src/composites/DisplayHeading.tsx +27 -0
  265. package/src/composites/EntityMediaCard.test.tsx +58 -0
  266. package/src/composites/EntityMediaCard.tsx +31 -13
  267. package/src/composites/EventCalendar.tsx +928 -0
  268. package/src/composites/EventEditor.tsx +268 -0
  269. package/src/composites/EventTimeline.tsx +357 -0
  270. package/src/composites/FloatChip.tsx +63 -0
  271. package/src/composites/GradientText.tsx +31 -0
  272. package/src/composites/IconTile.tsx +33 -0
  273. package/src/composites/MapChart.test.tsx +39 -0
  274. package/src/composites/MapChart.tsx +130 -0
  275. package/src/composites/MetaChip.tsx +24 -0
  276. package/src/composites/PresenceDot.tsx +42 -0
  277. package/src/composites/ProfileHero.test.tsx +33 -0
  278. package/src/composites/ProfileHero.tsx +96 -79
  279. package/src/composites/ProjectCard.tsx +65 -0
  280. package/src/composites/ScatterWebGL.test.tsx +25 -0
  281. package/src/composites/ScatterWebGL.tsx +79 -0
  282. package/src/composites/SectionHeading.tsx +61 -0
  283. package/src/composites/SiteFooter.test.tsx +37 -0
  284. package/src/composites/SiteFooter.tsx +79 -0
  285. package/src/composites/SiteNav.test.tsx +46 -0
  286. package/src/composites/SiteNav.tsx +150 -0
  287. package/src/composites/StatCard.test.tsx +30 -0
  288. package/src/composites/StatCard.tsx +36 -1
  289. package/src/composites/Tag.tsx +50 -0
  290. package/src/composites/Wordmark.test.tsx +23 -0
  291. package/src/composites/Wordmark.tsx +46 -0
  292. package/src/composites/cartesian-charts.test.tsx +52 -0
  293. package/src/composites/cartesian-charts.tsx +1287 -0
  294. package/src/composites/chart-composition.test.tsx +53 -0
  295. package/src/composites/chart-composition.tsx +898 -0
  296. package/src/composites/chart-ui.tsx +328 -0
  297. package/src/composites/charts-3d.test.tsx +25 -0
  298. package/src/composites/charts-3d.tsx +318 -0
  299. package/src/composites/charts.test.tsx +254 -0
  300. package/src/composites/chrome.test.tsx +29 -0
  301. package/src/composites/flow-charts.test.tsx +79 -0
  302. package/src/composites/flow-charts.tsx +607 -0
  303. package/src/composites/marketing.test.tsx +192 -0
  304. package/src/composites/radial-charts.test.tsx +74 -0
  305. package/src/composites/radial-charts.tsx +617 -0
  306. package/src/composites/scheduler-ui.tsx +304 -0
  307. package/src/composites/scheduler.test.tsx +194 -0
  308. package/src/index.test.ts +22 -0
  309. package/src/index.ts +300 -5
  310. package/src/lib/chart-export.test.ts +20 -0
  311. package/src/lib/chart-export.ts +99 -0
  312. package/src/lib/charts-platform.test.ts +93 -0
  313. package/src/lib/charts.test.ts +132 -0
  314. package/src/lib/charts.ts +1021 -0
  315. package/src/lib/geo.test.ts +42 -0
  316. package/src/lib/geo.ts +138 -0
  317. package/src/lib/iso.test.ts +22 -0
  318. package/src/lib/iso.ts +102 -0
  319. package/src/lib/rrule.test.ts +53 -0
  320. package/src/lib/rrule.ts +281 -0
  321. package/src/lib/scheduler.test.ts +186 -0
  322. package/src/lib/scheduler.ts +688 -0
  323. package/src/lib/tokens.test.ts +2 -2
  324. package/src/lib/webgl-scatter.test.ts +36 -0
  325. package/src/lib/webgl-scatter.ts +230 -0
  326. package/src/primitives/Accordion.tsx +218 -63
  327. package/src/primitives/AppBar.tsx +39 -0
  328. package/src/primitives/Autocomplete.tsx +236 -0
  329. package/src/primitives/Avatar.tsx +52 -1
  330. package/src/primitives/Backdrop.tsx +48 -0
  331. package/src/primitives/BottomNavigation.tsx +102 -0
  332. package/src/primitives/Button.tsx +3 -0
  333. package/src/primitives/ButtonBase.tsx +34 -0
  334. package/src/primitives/ButtonGroup.tsx +90 -0
  335. package/src/primitives/CircularProgress.tsx +104 -0
  336. package/src/primitives/ClickAwayListener.tsx +46 -0
  337. package/src/primitives/Collapse.tsx +39 -0
  338. package/src/primitives/Container.tsx +40 -0
  339. package/src/primitives/Fab.tsx +62 -0
  340. package/src/primitives/FormControl.tsx +90 -0
  341. package/src/primitives/FormControlLabel.tsx +51 -0
  342. package/src/primitives/Grid.tsx +101 -0
  343. package/src/primitives/IconButton.tsx +59 -0
  344. package/src/primitives/ImageList.test.tsx +48 -0
  345. package/src/primitives/ImageList.tsx +112 -0
  346. package/src/primitives/InputAdornment.tsx +86 -0
  347. package/src/primitives/Link.tsx +48 -0
  348. package/src/primitives/List.tsx +121 -0
  349. package/src/primitives/Masonry.tsx +32 -0
  350. package/src/primitives/Menu.tsx +112 -0
  351. package/src/primitives/MobileStepper.tsx +64 -0
  352. package/src/primitives/Modal.tsx +70 -0
  353. package/src/primitives/NoSsr.tsx +28 -0
  354. package/src/primitives/Paper.tsx +55 -0
  355. package/src/primitives/Progress.tsx +25 -7
  356. package/src/primitives/Snackbar.tsx +83 -0
  357. package/src/primitives/SpeedDial.tsx +110 -0
  358. package/src/primitives/Stack.tsx +88 -0
  359. package/src/primitives/StarRating.tsx +87 -28
  360. package/src/primitives/Stepper.tsx +184 -0
  361. package/src/primitives/TablePagination.tsx +58 -0
  362. package/src/primitives/TextField.tsx +105 -0
  363. package/src/primitives/TextareaAutosize.tsx +49 -0
  364. package/src/primitives/ToggleButton.tsx +148 -0
  365. package/src/primitives/TransferList.tsx +110 -0
  366. package/src/primitives/Typography.tsx +90 -0
  367. package/src/primitives/mui-more.test.tsx +76 -0
  368. package/src/primitives/mui.test.tsx +134 -0
  369. package/src/primitives/transitions.tsx +120 -0
package/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  /**
2
4
  * @spatika/react — Spatika React package
3
5
  *
@@ -5,7 +7,7 @@
5
7
  * import "@spatika/tokens/styles.css";
6
8
  */
7
9
 
8
- export { cn } from "./lib/cn";
10
+ export { Portal, type PortalProps } from "./lib/portal";
9
11
  export {
10
12
  OVERLAY_Z_INDEX,
11
13
  fixedLayerStyle,
@@ -88,14 +90,113 @@ export { Badge, badgeVariants } from "./primitives/Badge";
88
90
  export { Input } from "./primitives/Input";
89
91
  export { Textarea } from "./primitives/Textarea";
90
92
  export { Label } from "./primitives/Label";
91
- export { Separator } from "./primitives/Separator";
93
+ export { Separator, Separator as Divider } from "./primitives/Separator";
92
94
  export { Skeleton } from "./primitives/Skeleton";
93
95
  export { Checkbox } from "./primitives/Checkbox";
94
96
  export { Switch } from "./primitives/Switch";
95
97
  export { RadioGroup, RadioGroupItem } from "./primitives/RadioGroup";
96
- export { Progress } from "./primitives/Progress";
98
+ export { Progress, LinearProgress, type ProgressProps } from "./primitives/Progress";
99
+ export { CircularProgress, type CircularProgressProps } from "./primitives/CircularProgress";
97
100
  export { Slider } from "./primitives/Slider";
98
- export { Avatar, AvatarImage, AvatarFallback, InitialsAvatar } from "./primitives/Avatar";
101
+ export {
102
+ Avatar,
103
+ AvatarImage,
104
+ AvatarFallback,
105
+ InitialsAvatar,
106
+ AvatarGroup,
107
+ type AvatarGroupProps,
108
+ } from "./primitives/Avatar";
109
+ export { ButtonGroup, buttonGroupVariants, type ButtonGroupProps } from "./primitives/ButtonGroup";
110
+ export { Fab, fabVariants, type FabProps } from "./primitives/Fab";
111
+ export { IconButton, iconButtonVariants, type IconButtonProps } from "./primitives/IconButton";
112
+ export { Link, linkVariants, type LinkProps } from "./primitives/Link";
113
+ export { Backdrop, type BackdropProps } from "./primitives/Backdrop";
114
+ export { Collapse, type CollapseProps } from "./primitives/Collapse";
115
+ export { ClickAwayListener, type ClickAwayListenerProps } from "./primitives/ClickAwayListener";
116
+ export { Typography, typographyVariants, type TypographyProps } from "./primitives/Typography";
117
+ export { Paper, paperVariants, type PaperProps } from "./primitives/Paper";
118
+ export { Stack, type StackProps } from "./primitives/Stack";
119
+ export { Container, containerVariants, type ContainerProps } from "./primitives/Container";
120
+ export {
121
+ List,
122
+ ListItem,
123
+ ListItemButton,
124
+ ListItemIcon,
125
+ ListItemText,
126
+ ListSubheader,
127
+ type ListProps,
128
+ type ListItemProps,
129
+ type ListItemButtonProps,
130
+ type ListItemTextProps,
131
+ } from "./primitives/List";
132
+ export {
133
+ Stepper,
134
+ Step,
135
+ StepLabel,
136
+ StepContent,
137
+ StepConnector,
138
+ type StepperProps,
139
+ type StepProps,
140
+ type StepLabelProps,
141
+ } from "./primitives/Stepper";
142
+ export {
143
+ ToggleButton,
144
+ ToggleButtonGroup,
145
+ toggleButtonVariants,
146
+ type ToggleButtonProps,
147
+ type ToggleButtonGroupProps,
148
+ } from "./primitives/ToggleButton";
149
+ export { TextField, type TextFieldProps } from "./primitives/TextField";
150
+ export { Autocomplete, type AutocompleteProps, type AutocompleteOption } from "./primitives/Autocomplete";
151
+ export { FormControlLabel, type FormControlLabelProps } from "./primitives/FormControlLabel";
152
+ export {
153
+ FormControl,
154
+ FormLabel,
155
+ FormHelperText,
156
+ FormGroup,
157
+ type FormControlProps,
158
+ } from "./primitives/FormControl";
159
+ export {
160
+ InputAdornment,
161
+ OutlinedInput,
162
+ FilledInput,
163
+ type InputAdornmentProps,
164
+ type OutlinedInputProps,
165
+ } from "./primitives/InputAdornment";
166
+ export { Box, Grid, type BoxProps, type GridProps } from "./primitives/Grid";
167
+ export {
168
+ ImageList,
169
+ ImageListItem,
170
+ ImageListItemBar,
171
+ type ImageListProps,
172
+ type ImageListItemProps,
173
+ type ImageListItemBarProps,
174
+ } from "./primitives/ImageList";
175
+ export { Rating, StarRating, type RatingProps } from "./primitives/StarRating";
176
+ export { Snackbar, SnackbarContent, type SnackbarProps } from "./primitives/Snackbar";
177
+ export { MobileStepper, type MobileStepperProps } from "./primitives/MobileStepper";
178
+ export { Modal, type ModalProps } from "./primitives/Modal";
179
+ export { Fade, Grow, Slide, Zoom, type TransitionProps, type SlideProps } from "./primitives/transitions";
180
+ export { AppBar, appBarVariants, type AppBarProps } from "./primitives/AppBar";
181
+ export {
182
+ BottomNavigation,
183
+ BottomNavigationAction,
184
+ type BottomNavigationProps,
185
+ type BottomNavigationActionProps,
186
+ } from "./primitives/BottomNavigation";
187
+ export { Masonry, type MasonryProps } from "./primitives/Masonry";
188
+ export { Menu, MenuList, MenuItem, MenuAnchor, type MenuProps, type MenuItemProps } from "./primitives/Menu";
189
+ export { TransferList, type TransferListProps } from "./primitives/TransferList";
190
+ export { ButtonBase, type ButtonBaseProps } from "./primitives/ButtonBase";
191
+ export { NoSsr, type NoSsrProps } from "./primitives/NoSsr";
192
+ export { TextareaAutosize, type TextareaAutosizeProps } from "./primitives/TextareaAutosize";
193
+ export { TablePagination, type TablePaginationProps } from "./primitives/TablePagination";
194
+ export {
195
+ SpeedDial,
196
+ SpeedDialAction,
197
+ type SpeedDialProps,
198
+ type SpeedDialActionProps,
199
+ } from "./primitives/SpeedDial";
99
200
  export {
100
201
  Select,
101
202
  SelectContent,
@@ -184,8 +285,14 @@ export {
184
285
  AccordionItem,
185
286
  AccordionTrigger,
186
287
  AccordionContent,
288
+ AccordionActions,
289
+ AccordionSummary,
290
+ AccordionDetails,
291
+ type AccordionProps,
292
+ type AccordionItemProps,
293
+ type AccordionTriggerProps,
294
+ type AccordionContentProps,
187
295
  } from "./primitives/Accordion";
188
- export { StarRating } from "./primitives/StarRating";
189
296
 
190
297
  export { GlassCard, glassCardVariants, type GlassCardProps } from "./composites/GlassCard";
191
298
  export { SurfaceCard, surfaceCardVariants, type SurfaceCardProps } from "./composites/SurfaceCard";
@@ -193,6 +300,27 @@ export { PageStickyHeader, PageHeaderBadge, type PageStickyHeaderProps } from ".
193
300
  export { PageShell, type PageShellProps } from "./composites/PageShell";
194
301
  export { SectionPanel, type SectionPanelProps } from "./composites/SectionPanel";
195
302
  export { Chip, chipVariants, type ChipProps } from "./composites/Chip";
303
+ export { Tag, tagVariants, type TagProps } from "./composites/Tag";
304
+ export { SectionHeading, type SectionHeadingProps } from "./composites/SectionHeading";
305
+ export { SiteNav, type SiteNavLink, type SiteNavProps } from "./composites/SiteNav";
306
+ export { SiteFooter, type SiteFooterProps } from "./composites/SiteFooter";
307
+ export { GradientText, type GradientTextProps } from "./composites/GradientText";
308
+ export { AccentRule, type AccentRuleProps } from "./composites/AccentRule";
309
+ export { Wordmark, type WordmarkProps } from "./composites/Wordmark";
310
+ export { DisplayHeading, type DisplayHeadingProps } from "./composites/DisplayHeading";
311
+ export { PresenceDot, type PresenceDotProps } from "./composites/PresenceDot";
312
+ export { AvailabilityBadge, type AvailabilityBadgeProps } from "./composites/AvailabilityBadge";
313
+ export { FloatChip, type FloatChipProps } from "./composites/FloatChip";
314
+ export { MetaChip, type MetaChipProps } from "./composites/MetaChip";
315
+ export { IconTile, type IconTileProps } from "./composites/IconTile";
316
+ export { ContactLink, type ContactLinkProps } from "./composites/ContactLink";
317
+ export {
318
+ CareerCard,
319
+ CareerTimeline,
320
+ type CareerCardProps,
321
+ type CareerTimelineProps,
322
+ } from "./composites/CareerCard";
323
+ export { ProjectCard, type ProjectCardProps } from "./composites/ProjectCard";
196
324
  export {
197
325
  ChipGroup,
198
326
  isOptionSelected,
@@ -220,6 +348,8 @@ export {
220
348
  CardDescription,
221
349
  CardContent,
222
350
  CardFooter,
351
+ CardActionArea,
352
+ CardMedia,
223
353
  type CardProps,
224
354
  } from "./composites/Card";
225
355
  export { AppHeader, type AppHeaderProps } from "./composites/AppHeader";
@@ -353,3 +483,168 @@ export {
353
483
  DataTableToolbar,
354
484
  type DataTableToolbarProps,
355
485
  } from "./composites/DataTableToolbar";
486
+ export {
487
+ EventCalendar,
488
+ type EventCalendarProps,
489
+ } from "./composites/EventCalendar";
490
+ export {
491
+ EventTimeline,
492
+ type EventTimelineProps,
493
+ } from "./composites/EventTimeline";
494
+ export {
495
+ EventEditor,
496
+ type EventEditorDraft,
497
+ } from "./composites/EventEditor";
498
+ export {
499
+ DEFAULT_SCHEDULER_PREFERENCES,
500
+ SCHEDULER_COLOR_TONES,
501
+ } from "./lib/scheduler";
502
+ export type {
503
+ CalendarView,
504
+ SchedulerColorTone,
505
+ SchedulerEvent,
506
+ SchedulerPreferences,
507
+ SchedulerResource,
508
+ TimelineScale,
509
+ } from "./lib/scheduler";
510
+ export {
511
+ CHART_COLOR_VARS,
512
+ chartColor,
513
+ formatChartNumber,
514
+ seriesDataFromDataset,
515
+ axisDataFromDataset,
516
+ clampZoom,
517
+ DEFAULT_ZOOM,
518
+ } from "./lib/charts";
519
+ export type {
520
+ ChartAxisConfig,
521
+ ChartCurve,
522
+ ChartDataset,
523
+ ChartInteraction,
524
+ ChartMargin,
525
+ ChartZoom,
526
+ HighlightScope,
527
+ SankeyLink,
528
+ SankeyNode,
529
+ TreeNode,
530
+ } from "./lib/charts";
531
+ export { serializeChartSvg, exportChart, downloadChartSvg, downloadChartPng } from "./lib/chart-export";
532
+ export {
533
+ ChartContainer,
534
+ ChartSurface,
535
+ ChartsGrid,
536
+ ChartsXAxis,
537
+ ChartsYAxis,
538
+ ChartsLegend,
539
+ ChartsToolbar,
540
+ ChartsBrush,
541
+ BarPlot,
542
+ LinePlot,
543
+ AreaPlot,
544
+ ScatterPlot,
545
+ useChartContext,
546
+ } from "./composites/chart-composition";
547
+ export type {
548
+ ChartContainerProps,
549
+ ComposedSeries,
550
+ ComposedSeriesType,
551
+ HighlightedItem,
552
+ } from "./composites/chart-composition";
553
+ export {
554
+ AreaChart,
555
+ BarChart,
556
+ BoxPlotChart,
557
+ BubbleChart,
558
+ CandlestickChart,
559
+ LineChart,
560
+ OhlcChart,
561
+ RangeAreaChart,
562
+ RangeBarChart,
563
+ ScatterChart,
564
+ SparkLineChart,
565
+ WaterfallChart,
566
+ } from "./composites/cartesian-charts";
567
+ export type {
568
+ BarChartProps,
569
+ BoxPlotChartProps,
570
+ CandleDatum,
571
+ CandlestickChartProps,
572
+ CartesianChartProps,
573
+ LineChartProps,
574
+ NumericSeries,
575
+ RangeAreaChartProps,
576
+ RangeBarChartProps,
577
+ RangeSeries,
578
+ ScatterChartProps,
579
+ ScatterPoint,
580
+ ScatterRenderer,
581
+ ScatterSeries,
582
+ SparkLineChartProps,
583
+ WaterfallChartProps,
584
+ } from "./composites/cartesian-charts";
585
+ export {
586
+ Gauge,
587
+ LinearGauge,
588
+ PieChart,
589
+ PolarLineChart,
590
+ RadarChart,
591
+ RadialBarChart,
592
+ RadialLineChart,
593
+ } from "./composites/radial-charts";
594
+ export type {
595
+ GaugeProps,
596
+ GaugeSection,
597
+ LinearGaugeProps,
598
+ PieChartProps,
599
+ PieDatum,
600
+ PieSeries,
601
+ RadarChartProps,
602
+ RadarSeries,
603
+ RadialBarChartProps,
604
+ RadialLineChartProps,
605
+ } from "./composites/radial-charts";
606
+ export {
607
+ ChordChart,
608
+ FunnelChart,
609
+ Heatmap,
610
+ PyramidChart,
611
+ SankeyChart,
612
+ SunburstChart,
613
+ Treemap,
614
+ } from "./composites/flow-charts";
615
+ export type {
616
+ ChordChartProps,
617
+ FunnelChartProps,
618
+ FunnelDatum,
619
+ FunnelLabelPosition,
620
+ FunnelSeries,
621
+ HeatDatum,
622
+ HeatmapProps,
623
+ SankeyChartProps,
624
+ SunburstChartProps,
625
+ TreemapProps,
626
+ } from "./composites/flow-charts";
627
+ export { MapChart } from "./composites/MapChart";
628
+ export type { MapChartProps, MapShapeDatum } from "./composites/MapChart";
629
+ export { BarChart3D, PieChart3D } from "./composites/charts-3d";
630
+ export type { BarChart3DProps, PieChart3DProps } from "./composites/charts-3d";
631
+ export { ChartDataGrid, renderChartCell } from "./composites/ChartDataGrid";
632
+ export type {
633
+ ChartDataGridProps,
634
+ ChartDataGridRow,
635
+ ChartGridColumn,
636
+ ChartGridColumnType,
637
+ } from "./composites/ChartDataGrid";
638
+ export {
639
+ mercator,
640
+ equirectangular,
641
+ geoPath,
642
+ fitFeatures,
643
+ featureId,
644
+ } from "./lib/geo";
645
+ export type {
646
+ GeoJsonFeature,
647
+ GeoJsonFeatureCollection,
648
+ GeoJsonGeometry,
649
+ GeoProjectionKind,
650
+ } from "./lib/geo";
@@ -0,0 +1,20 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { serializeChartSvg } from "./chart-export";
3
+
4
+ describe("chart export", () => {
5
+ it("serializes an SVG with an XML header", () => {
6
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
7
+ svg.setAttribute("width", "120");
8
+ svg.setAttribute("height", "80");
9
+ const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
10
+ rect.setAttribute("width", "120");
11
+ rect.setAttribute("height", "80");
12
+ rect.setAttribute("fill", "var(--chart-1)");
13
+ svg.appendChild(rect);
14
+ document.body.appendChild(svg);
15
+ const xml = serializeChartSvg(svg);
16
+ expect(xml).toContain("<?xml");
17
+ expect(xml).toContain("<svg");
18
+ svg.remove();
19
+ });
20
+ });
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Serialize a live chart SVG and download SVG / PNG.
3
+ * Computed CSS (theme variables) is baked in so the file looks the same outside the app.
4
+ */
5
+
6
+ function bakeComputedStyles(live: SVGSVGElement, clone: SVGSVGElement) {
7
+ const liveNodes = [live, ...Array.from(live.querySelectorAll("*"))];
8
+ const cloneNodes = [clone, ...Array.from(clone.querySelectorAll("*"))];
9
+ for (let i = 0; i < liveNodes.length; i++) {
10
+ const source = liveNodes[i];
11
+ const target = cloneNodes[i] as SVGElement | undefined;
12
+ if (!source || !target || !(source instanceof Element)) continue;
13
+ const style = getComputedStyle(source);
14
+ if (style.fill && style.fill !== "none") target.setAttribute("fill", style.fill);
15
+ if (style.stroke && style.stroke !== "none") target.setAttribute("stroke", style.stroke);
16
+ if (style.strokeWidth) target.setAttribute("stroke-width", style.strokeWidth);
17
+ if (style.opacity && style.opacity !== "1") target.setAttribute("opacity", style.opacity);
18
+ if (style.fontSize) target.setAttribute("font-size", style.fontSize);
19
+ if (style.fontWeight) target.setAttribute("font-weight", style.fontWeight);
20
+ if (style.fontFamily) target.setAttribute("font-family", style.fontFamily);
21
+ }
22
+ }
23
+
24
+ export function serializeChartSvg(svg: SVGSVGElement): string {
25
+ const clone = svg.cloneNode(true) as SVGSVGElement;
26
+ clone.setAttribute("xmlns", "http://www.w3.org/2000/svg");
27
+ clone.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
28
+ if (!clone.getAttribute("viewBox")) {
29
+ const width = svg.clientWidth || Number(svg.getAttribute("width")) || 320;
30
+ const height = svg.clientHeight || Number(svg.getAttribute("height")) || 240;
31
+ clone.setAttribute("viewBox", `0 0 ${width} ${height}`);
32
+ }
33
+ bakeComputedStyles(svg, clone);
34
+ return `<?xml version="1.0" encoding="UTF-8"?>${new XMLSerializer().serializeToString(clone)}`;
35
+ }
36
+
37
+ function triggerDownload(blob: Blob, filename: string) {
38
+ const href = URL.createObjectURL(blob);
39
+ const link = document.createElement("a");
40
+ link.href = href;
41
+ link.download = filename;
42
+ link.rel = "noopener";
43
+ document.body.appendChild(link);
44
+ link.click();
45
+ link.remove();
46
+ window.setTimeout(() => URL.revokeObjectURL(href), 1_000);
47
+ }
48
+
49
+ export function downloadChartSvg(svg: SVGSVGElement, filename = "chart.svg") {
50
+ const blob = new Blob([serializeChartSvg(svg)], { type: "image/svg+xml;charset=utf-8" });
51
+ triggerDownload(blob, filename);
52
+ }
53
+
54
+ export async function chartSvgToPngBlob(svg: SVGSVGElement): Promise<Blob> {
55
+ const xml = serializeChartSvg(svg);
56
+ const width = Math.max(1, svg.clientWidth || Number(svg.getAttribute("width")) || 320);
57
+ const height = Math.max(1, svg.clientHeight || Number(svg.getAttribute("height")) || 240);
58
+ const blob = new Blob([xml], { type: "image/svg+xml;charset=utf-8" });
59
+ const url = URL.createObjectURL(blob);
60
+ try {
61
+ const image = await new Promise<HTMLImageElement>((resolve, reject) => {
62
+ const img = new Image();
63
+ img.onload = () => resolve(img);
64
+ img.onerror = () => reject(new Error("Failed to rasterize chart SVG"));
65
+ img.src = url;
66
+ });
67
+ const canvas = document.createElement("canvas");
68
+ canvas.width = Math.round(width * 2);
69
+ canvas.height = Math.round(height * 2);
70
+ const ctx = canvas.getContext("2d");
71
+ if (!ctx) throw new Error("Canvas is unavailable");
72
+ const surface = svg.parentElement;
73
+ ctx.fillStyle = surface ? getComputedStyle(surface).backgroundColor || "#ffffff" : "#ffffff";
74
+ if (ctx.fillStyle === "rgba(0, 0, 0, 0)" || ctx.fillStyle === "transparent") ctx.fillStyle = "#ffffff";
75
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
76
+ ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
77
+ const png = await new Promise<Blob>((resolve, reject) => {
78
+ canvas.toBlob((next) => (next ? resolve(next) : reject(new Error("PNG export failed"))), "image/png");
79
+ });
80
+ return png;
81
+ } finally {
82
+ URL.revokeObjectURL(url);
83
+ }
84
+ }
85
+
86
+ export async function downloadChartPng(svg: SVGSVGElement, filename = "chart.png") {
87
+ const blob = await chartSvgToPngBlob(svg);
88
+ triggerDownload(blob, filename);
89
+ }
90
+
91
+ export async function exportChart(
92
+ svg: SVGSVGElement | null | undefined,
93
+ format: "svg" | "png",
94
+ filename?: string,
95
+ ) {
96
+ if (!svg) return;
97
+ if (format === "svg") downloadChartSvg(svg, filename ?? "chart.svg");
98
+ else await downloadChartPng(svg, filename ?? "chart.png");
99
+ }
@@ -0,0 +1,93 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { featureId, fitFeatures, geoPath, mercator } from "./geo";
3
+ import { ellipseSlicePath, isoBoxFaces, isoPoint } from "./iso";
4
+ import {
5
+ nearestScatterHit,
6
+ parseCssColor,
7
+ shouldUseWebGL,
8
+ WEBGL_AUTO_THRESHOLD,
9
+ } from "./webgl-scatter";
10
+
11
+ describe("geo", () => {
12
+ it("projects the equator to the mercator midpoint", () => {
13
+ const [x, y] = mercator([0, 0]);
14
+ expect(x).toBeCloseTo(0.5);
15
+ expect(y).toBeCloseTo(0.5);
16
+ });
17
+
18
+ it("builds a closed polygon path fitted to a viewport", () => {
19
+ const features = [
20
+ {
21
+ type: "Feature" as const,
22
+ id: "box",
23
+ properties: { name: "Box" },
24
+ geometry: {
25
+ type: "Polygon" as const,
26
+ coordinates: [
27
+ [
28
+ [0, 0],
29
+ [10, 0],
30
+ [10, 10],
31
+ [0, 10],
32
+ [0, 0],
33
+ ],
34
+ ],
35
+ },
36
+ },
37
+ ];
38
+ const project = fitFeatures(features, 200, 100, 10);
39
+ const d = geoPath(features[0]!.geometry, project);
40
+ expect(d.startsWith("M")).toBe(true);
41
+ expect(d.includes("Z")).toBe(true);
42
+ expect(featureId(features[0]!)).toBe("box");
43
+ });
44
+ });
45
+
46
+ describe("iso", () => {
47
+ it("projects isometric points with y up", () => {
48
+ const origin = isoPoint(0, 0, 0, 40, 80);
49
+ const raised = isoPoint(0, 10, 0, 40, 80);
50
+ expect(raised.y).toBeLessThan(origin.y);
51
+ });
52
+
53
+ it("emits three faces for a box", () => {
54
+ const faces = isoBoxFaces(0, 0, 0, 10, 20, 8, 40, 80);
55
+ expect(faces.front.startsWith("M")).toBe(true);
56
+ expect(faces.top).not.toEqual(faces.front);
57
+ expect(faces.side).not.toEqual(faces.top);
58
+ });
59
+
60
+ it("draws an elliptical pie slice", () => {
61
+ const d = ellipseSlicePath(50, 40, 30, 12, 0, 90);
62
+ expect(d.includes("A30 12")).toBe(true);
63
+ });
64
+ });
65
+
66
+ describe("webgl scatter helpers", () => {
67
+ it("parses hex and rgb colors", () => {
68
+ expect(parseCssColor("#ff0000")).toEqual([1, 0, 0, 1]);
69
+ expect(parseCssColor("rgb(0, 128, 255)")).toEqual([0, 128 / 255, 1, 1]);
70
+ expect(parseCssColor("not-a-color")).toBeNull();
71
+ });
72
+
73
+ it("selects webgl for auto clouds above the threshold", () => {
74
+ expect(shouldUseWebGL("svg", 10_000)).toBe(false);
75
+ expect(shouldUseWebGL("webgl", 3)).toBe(true);
76
+ expect(shouldUseWebGL("auto", WEBGL_AUTO_THRESHOLD)).toBe(true);
77
+ expect(shouldUseWebGL("auto", 10)).toBe(false);
78
+ });
79
+
80
+ it("finds the nearest point within the hit radius", () => {
81
+ const hit = nearestScatterHit(
82
+ [
83
+ { x: 10, y: 10, r: 4, seriesIndex: 0, pointIndex: 0 },
84
+ { x: 40, y: 40, r: 4, seriesIndex: 1, pointIndex: 2 },
85
+ ],
86
+ 41,
87
+ 39,
88
+ );
89
+ expect(hit?.seriesIndex).toBe(1);
90
+ expect(hit?.pointIndex).toBe(2);
91
+ expect(nearestScatterHit([{ x: 0, y: 0, r: 2, seriesIndex: 0, pointIndex: 0 }], 80, 80)).toBeNull();
92
+ });
93
+ });
@@ -0,0 +1,132 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ arcPath,
4
+ axisDataFromDataset,
5
+ boxPlotStats,
6
+ chartColor,
7
+ extent,
8
+ formatChartNumber,
9
+ funnelLayout,
10
+ linePath,
11
+ niceTicks,
12
+ pieSlices,
13
+ seriesDataFromDataset,
14
+ stackSeries,
15
+ squarify,
16
+ waterfallBars,
17
+ wheelZoom,
18
+ } from "./charts";
19
+
20
+ describe("chart math", () => {
21
+ it("builds nice ticks across a domain", () => {
22
+ const ticks = niceTicks(0, 100, 5);
23
+ expect(ticks[0]).toBe(0);
24
+ expect(ticks[ticks.length - 1]).toBeGreaterThanOrEqual(100);
25
+ expect(ticks.length).toBeGreaterThan(2);
26
+ });
27
+
28
+ it("stacks positive and negative series independently", () => {
29
+ const stacked = stackSeries([
30
+ [2, -1],
31
+ [3, -2],
32
+ ]);
33
+ expect(stacked[0]![0]).toEqual({ start: 0, end: 2 });
34
+ expect(stacked[1]![0]).toEqual({ start: 2, end: 5 });
35
+ expect(stacked[0]![1]).toEqual({ start: 0, end: -1 });
36
+ expect(stacked[1]![1]).toEqual({ start: -1, end: -3 });
37
+ });
38
+
39
+ it("lays out pie slices that sum to a full turn", () => {
40
+ const slices = pieSlices([1, 1, 2], {
41
+ cx: 50,
42
+ cy: 50,
43
+ innerRadius: 10,
44
+ outerRadius: 40,
45
+ });
46
+ expect(slices).toHaveLength(3);
47
+ expect(slices[2]!.percent).toBeCloseTo(0.5);
48
+ expect(slices.every((slice) => slice.path.length > 0)).toBe(true);
49
+ });
50
+
51
+ it("draws linear and monotone line paths", () => {
52
+ const pts = [
53
+ { x: 0, y: 10 },
54
+ { x: 10, y: 0 },
55
+ { x: 20, y: 8 },
56
+ ];
57
+ expect(linePath(pts, "linear")).toContain("L");
58
+ expect(linePath(pts, "monotone")).toContain("C");
59
+ });
60
+
61
+ it("computes box-plot fences and outliers", () => {
62
+ const stats = boxPlotStats([1, 2, 3, 4, 5, 100]);
63
+ expect(stats.median).toBe(3.5);
64
+ expect(stats.outliers).toEqual([100]);
65
+ });
66
+
67
+ it("builds waterfall running totals", () => {
68
+ const bars = waterfallBars([100, 20, -30, null]);
69
+ expect(bars[3]).toEqual({ index: 3, start: 0, end: 90, value: 90, total: true });
70
+ });
71
+
72
+ it("packs a treemap that fills the viewport", () => {
73
+ const rects = squarify(
74
+ [
75
+ { label: "A", value: 6 },
76
+ { label: "B", value: 4 },
77
+ ],
78
+ 0,
79
+ 0,
80
+ 100,
81
+ 50,
82
+ );
83
+ const area = rects.reduce((sum, rect) => sum + rect.w * rect.h, 0);
84
+ expect(area).toBeCloseTo(5000, 0);
85
+ });
86
+
87
+ it("lays out funnel rows from wide to narrow", () => {
88
+ const rows = funnelLayout(
89
+ [
90
+ { label: "A", value: 10 },
91
+ { label: "B", value: 5 },
92
+ ],
93
+ 100,
94
+ 80,
95
+ );
96
+ expect(rows[0]!.topRight - rows[0]!.topLeft).toBeGreaterThan(rows[1]!.topRight - rows[1]!.topLeft);
97
+ });
98
+
99
+ it("shares a max so comparison funnels stay on the same scale", () => {
100
+ const inner = funnelLayout([{ label: "A", value: 50 }], 100, 40, 6, 100);
101
+ const outer = funnelLayout([{ label: "A", value: 100 }], 100, 40, 6, 100);
102
+ expect(outer[0]!.topRight - outer[0]!.topLeft).toBe(100);
103
+ expect(inner[0]!.topRight - inner[0]!.topLeft).toBe(50);
104
+ });
105
+
106
+ it("zooms a window around an anchor", () => {
107
+ const next = wheelZoom({ x: [0, 1] }, 0.5, 0.5);
108
+ expect(next.x[1] - next.x[0]).toBeCloseTo(0.5);
109
+ expect(next.x[0]).toBeGreaterThan(0);
110
+ expect(next.x[1]).toBeLessThan(1);
111
+ });
112
+
113
+ it("reads series from a dataset", () => {
114
+ const dataset = [
115
+ { month: "Jan", views: 10 },
116
+ { month: "Feb", views: 20 },
117
+ ];
118
+ expect(seriesDataFromDataset(dataset, "views")).toEqual([10, 20]);
119
+ expect(axisDataFromDataset(dataset, "month")).toEqual(["Jan", "Feb"]);
120
+ });
121
+
122
+ it("formats compact numbers and cycles chart colors", () => {
123
+ expect(formatChartNumber(1500)).toBe("1.5k");
124
+ expect(chartColor(0)).toBe("var(--chart-1)");
125
+ expect(chartColor(5)).toBe("var(--chart-1)");
126
+ expect(extent([3, 3])).not.toEqual([3, 3]);
127
+ });
128
+
129
+ it("splits a full-circle arc into two sweeps", () => {
130
+ expect(arcPath(0, 0, 0, 10, 0, 360).split("A").length).toBeGreaterThan(2);
131
+ });
132
+ });