@cdx-ui/components 0.3.4 → 0.3.6

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 (287) hide show
  1. package/README.md +1 -1
  2. package/coverage.svg +1 -1
  3. package/docs/components/bar-chart/content.md +703 -0
  4. package/docs/components/content.md +9 -1
  5. package/docs/components/line-chart/content.md +567 -0
  6. package/docs/components/pie-chart/content.md +493 -0
  7. package/docs/components/progress-segmented/content.md +1 -1
  8. package/docs/components/select/content.md +144 -2
  9. package/docs/components/stepper/content.md +599 -0
  10. package/docs/components/system-alert/content.md +533 -0
  11. package/docs/foundations/expressions/icons/content.md +1 -1
  12. package/docs/foundations/styles/tokens/all-tokens/content.md +2 -1
  13. package/docs/llms.txt +10 -0
  14. package/docs/patterns/content.md +1 -0
  15. package/docs/patterns/dashboard/content.md +423 -19
  16. package/docs/patterns/insights/content.md +590 -0
  17. package/docs/resources/release-notes/0.3.4/content.md +27 -0
  18. package/docs/resources/release-notes/0.3.5/content.md +7 -0
  19. package/docs/resources/release-notes/content.md +2 -0
  20. package/lib/commonjs/components/BarChart/geometry.js +1130 -0
  21. package/lib/commonjs/components/BarChart/geometry.js.map +1 -0
  22. package/lib/commonjs/components/BarChart/index.js +942 -0
  23. package/lib/commonjs/components/BarChart/index.js.map +1 -0
  24. package/lib/commonjs/components/BarChart/styles.js +26 -0
  25. package/lib/commonjs/components/BarChart/styles.js.map +1 -0
  26. package/lib/commonjs/components/Button/index.js +2 -2
  27. package/lib/commonjs/components/Button/index.js.map +1 -1
  28. package/lib/commonjs/components/Chip/styles.js +3 -1
  29. package/lib/commonjs/components/Chip/styles.js.map +1 -1
  30. package/lib/commonjs/components/LineChart/geometry.js +698 -0
  31. package/lib/commonjs/components/LineChart/geometry.js.map +1 -0
  32. package/lib/commonjs/components/LineChart/index.js +747 -0
  33. package/lib/commonjs/components/LineChart/index.js.map +1 -0
  34. package/lib/commonjs/components/LineChart/styles.js +25 -0
  35. package/lib/commonjs/components/LineChart/styles.js.map +1 -0
  36. package/lib/commonjs/components/PieChart/geometry.js +216 -0
  37. package/lib/commonjs/components/PieChart/geometry.js.map +1 -0
  38. package/lib/commonjs/components/PieChart/index.js +476 -0
  39. package/lib/commonjs/components/PieChart/index.js.map +1 -0
  40. package/lib/commonjs/components/PieChart/styles.js +88 -0
  41. package/lib/commonjs/components/PieChart/styles.js.map +1 -0
  42. package/lib/commonjs/components/ProgressCircle/ProgressCircleRing.js +9 -31
  43. package/lib/commonjs/components/ProgressCircle/ProgressCircleRing.js.map +1 -1
  44. package/lib/commonjs/components/ProgressCircle/ProgressRing.js +52 -0
  45. package/lib/commonjs/components/ProgressCircle/ProgressRing.js.map +1 -0
  46. package/lib/commonjs/components/ScrollShadow/useScrollShadow.js +8 -7
  47. package/lib/commonjs/components/ScrollShadow/useScrollShadow.js.map +1 -1
  48. package/lib/commonjs/components/Stepper/index.js +369 -0
  49. package/lib/commonjs/components/Stepper/index.js.map +1 -0
  50. package/lib/commonjs/components/Stepper/styles.js +211 -0
  51. package/lib/commonjs/components/Stepper/styles.js.map +1 -0
  52. package/lib/commonjs/components/Stepper/useStepperLabelFit.js +22 -0
  53. package/lib/commonjs/components/Stepper/useStepperLabelFit.js.map +1 -0
  54. package/lib/commonjs/components/Stepper/useStepperLabelFit.web.js +52 -0
  55. package/lib/commonjs/components/Stepper/useStepperLabelFit.web.js.map +1 -0
  56. package/lib/commonjs/components/Stepper/useStepperRingColors.js +31 -0
  57. package/lib/commonjs/components/Stepper/useStepperRingColors.js.map +1 -0
  58. package/lib/commonjs/components/SystemAlert/animation.js +218 -0
  59. package/lib/commonjs/components/SystemAlert/animation.js.map +1 -0
  60. package/lib/commonjs/components/SystemAlert/index.js +525 -0
  61. package/lib/commonjs/components/SystemAlert/index.js.map +1 -0
  62. package/lib/commonjs/components/SystemAlert/styles.js +178 -0
  63. package/lib/commonjs/components/SystemAlert/styles.js.map +1 -0
  64. package/lib/commonjs/components/SystemAlert/useSystemAlertStatusBarStyle.js +53 -0
  65. package/lib/commonjs/components/SystemAlert/useSystemAlertStatusBarStyle.js.map +1 -0
  66. package/lib/commonjs/components/Tabs/index.js +4 -0
  67. package/lib/commonjs/components/Tabs/index.js.map +1 -1
  68. package/lib/commonjs/components/Tabs/styles.js +1 -1
  69. package/lib/commonjs/components/Tabs/styles.js.map +1 -1
  70. package/lib/commonjs/components/chart/ChartInspector.js +610 -0
  71. package/lib/commonjs/components/chart/ChartInspector.js.map +1 -0
  72. package/lib/commonjs/components/chart/format.js +93 -0
  73. package/lib/commonjs/components/chart/format.js.map +1 -0
  74. package/lib/commonjs/components/chart/index.js +2 -0
  75. package/lib/commonjs/components/chart/index.js.map +1 -0
  76. package/lib/commonjs/components/chart/motion.js +97 -0
  77. package/lib/commonjs/components/chart/motion.js.map +1 -0
  78. package/lib/commonjs/components/chart/palette.js +178 -0
  79. package/lib/commonjs/components/chart/palette.js.map +1 -0
  80. package/lib/commonjs/components/chart/size.js +34 -0
  81. package/lib/commonjs/components/chart/size.js.map +1 -0
  82. package/lib/commonjs/components/chart/ticks.js +59 -0
  83. package/lib/commonjs/components/chart/ticks.js.map +1 -0
  84. package/lib/commonjs/components/chart/types.js +6 -0
  85. package/lib/commonjs/components/chart/types.js.map +1 -0
  86. package/lib/commonjs/components/chart/useChartHostWidth.js +27 -0
  87. package/lib/commonjs/components/chart/useChartHostWidth.js.map +1 -0
  88. package/lib/commonjs/components/index.js +60 -0
  89. package/lib/commonjs/components/index.js.map +1 -1
  90. package/lib/commonjs/figma/SystemAlert.Button.figma.js +28 -0
  91. package/lib/commonjs/figma/SystemAlert.Button.figma.js.map +1 -0
  92. package/lib/commonjs/figma/SystemAlert.Close.figma.js +22 -0
  93. package/lib/commonjs/figma/SystemAlert.Close.figma.js.map +1 -0
  94. package/lib/commonjs/figma/SystemAlert.Description.figma.js +20 -0
  95. package/lib/commonjs/figma/SystemAlert.Description.figma.js.map +1 -0
  96. package/lib/commonjs/figma/SystemAlert.IconButton.figma.js +31 -0
  97. package/lib/commonjs/figma/SystemAlert.IconButton.figma.js.map +1 -0
  98. package/lib/commonjs/figma/SystemAlert.figma.js +48 -0
  99. package/lib/commonjs/figma/SystemAlert.figma.js.map +1 -0
  100. package/lib/module/components/BarChart/geometry.js +1110 -0
  101. package/lib/module/components/BarChart/geometry.js.map +1 -0
  102. package/lib/module/components/BarChart/index.js +936 -0
  103. package/lib/module/components/BarChart/index.js.map +1 -0
  104. package/lib/module/components/BarChart/styles.js +22 -0
  105. package/lib/module/components/BarChart/styles.js.map +1 -0
  106. package/lib/module/components/Button/index.js +2 -2
  107. package/lib/module/components/Button/index.js.map +1 -1
  108. package/lib/module/components/Chip/styles.js +3 -1
  109. package/lib/module/components/Chip/styles.js.map +1 -1
  110. package/lib/module/components/LineChart/geometry.js +685 -0
  111. package/lib/module/components/LineChart/geometry.js.map +1 -0
  112. package/lib/module/components/LineChart/index.js +741 -0
  113. package/lib/module/components/LineChart/index.js.map +1 -0
  114. package/lib/module/components/LineChart/styles.js +21 -0
  115. package/lib/module/components/LineChart/styles.js.map +1 -0
  116. package/lib/module/components/PieChart/geometry.js +209 -0
  117. package/lib/module/components/PieChart/geometry.js.map +1 -0
  118. package/lib/module/components/PieChart/index.js +471 -0
  119. package/lib/module/components/PieChart/index.js.map +1 -0
  120. package/lib/module/components/PieChart/styles.js +84 -0
  121. package/lib/module/components/PieChart/styles.js.map +1 -0
  122. package/lib/module/components/ProgressCircle/ProgressCircleRing.js +10 -32
  123. package/lib/module/components/ProgressCircle/ProgressCircleRing.js.map +1 -1
  124. package/lib/module/components/ProgressCircle/ProgressRing.js +48 -0
  125. package/lib/module/components/ProgressCircle/ProgressRing.js.map +1 -0
  126. package/lib/module/components/ScrollShadow/useScrollShadow.js +8 -7
  127. package/lib/module/components/ScrollShadow/useScrollShadow.js.map +1 -1
  128. package/lib/module/components/Stepper/index.js +360 -0
  129. package/lib/module/components/Stepper/index.js.map +1 -0
  130. package/lib/module/components/Stepper/styles.js +206 -0
  131. package/lib/module/components/Stepper/styles.js.map +1 -0
  132. package/lib/module/components/Stepper/useStepperLabelFit.js +18 -0
  133. package/lib/module/components/Stepper/useStepperLabelFit.js.map +1 -0
  134. package/lib/module/components/Stepper/useStepperLabelFit.web.js +48 -0
  135. package/lib/module/components/Stepper/useStepperLabelFit.web.js.map +1 -0
  136. package/lib/module/components/Stepper/useStepperRingColors.js +28 -0
  137. package/lib/module/components/Stepper/useStepperRingColors.js.map +1 -0
  138. package/lib/module/components/SystemAlert/animation.js +213 -0
  139. package/lib/module/components/SystemAlert/animation.js.map +1 -0
  140. package/lib/module/components/SystemAlert/index.js +515 -0
  141. package/lib/module/components/SystemAlert/index.js.map +1 -0
  142. package/lib/module/components/SystemAlert/styles.js +174 -0
  143. package/lib/module/components/SystemAlert/styles.js.map +1 -0
  144. package/lib/module/components/SystemAlert/useSystemAlertStatusBarStyle.js +49 -0
  145. package/lib/module/components/SystemAlert/useSystemAlertStatusBarStyle.js.map +1 -0
  146. package/lib/module/components/Tabs/index.js +4 -0
  147. package/lib/module/components/Tabs/index.js.map +1 -1
  148. package/lib/module/components/Tabs/styles.js +1 -1
  149. package/lib/module/components/Tabs/styles.js.map +1 -1
  150. package/lib/module/components/chart/ChartInspector.js +600 -0
  151. package/lib/module/components/chart/ChartInspector.js.map +1 -0
  152. package/lib/module/components/chart/format.js +84 -0
  153. package/lib/module/components/chart/format.js.map +1 -0
  154. package/lib/module/components/chart/index.js +2 -0
  155. package/lib/module/components/chart/index.js.map +1 -0
  156. package/lib/module/components/chart/motion.js +89 -0
  157. package/lib/module/components/chart/motion.js.map +1 -0
  158. package/lib/module/components/chart/palette.js +168 -0
  159. package/lib/module/components/chart/palette.js.map +1 -0
  160. package/lib/module/components/chart/size.js +29 -0
  161. package/lib/module/components/chart/size.js.map +1 -0
  162. package/lib/module/components/chart/ticks.js +55 -0
  163. package/lib/module/components/chart/ticks.js.map +1 -0
  164. package/lib/module/components/chart/types.js +4 -0
  165. package/lib/module/components/chart/types.js.map +1 -0
  166. package/lib/module/components/chart/useChartHostWidth.js +23 -0
  167. package/lib/module/components/chart/useChartHostWidth.js.map +1 -0
  168. package/lib/module/components/index.js +5 -0
  169. package/lib/module/components/index.js.map +1 -1
  170. package/lib/module/figma/SystemAlert.Button.figma.js +22 -0
  171. package/lib/module/figma/SystemAlert.Button.figma.js.map +1 -0
  172. package/lib/module/figma/SystemAlert.Close.figma.js +18 -0
  173. package/lib/module/figma/SystemAlert.Close.figma.js.map +1 -0
  174. package/lib/module/figma/SystemAlert.Description.figma.js +14 -0
  175. package/lib/module/figma/SystemAlert.Description.figma.js.map +1 -0
  176. package/lib/module/figma/SystemAlert.IconButton.figma.js +25 -0
  177. package/lib/module/figma/SystemAlert.IconButton.figma.js.map +1 -0
  178. package/lib/module/figma/SystemAlert.figma.js +42 -0
  179. package/lib/module/figma/SystemAlert.figma.js.map +1 -0
  180. package/lib/typescript/components/BarChart/geometry.d.ts +236 -0
  181. package/lib/typescript/components/BarChart/geometry.d.ts.map +1 -0
  182. package/lib/typescript/components/BarChart/index.d.ts +193 -0
  183. package/lib/typescript/components/BarChart/index.d.ts.map +1 -0
  184. package/lib/typescript/components/BarChart/styles.d.ts +32 -0
  185. package/lib/typescript/components/BarChart/styles.d.ts.map +1 -0
  186. package/lib/typescript/components/Chip/styles.d.ts.map +1 -1
  187. package/lib/typescript/components/LineChart/geometry.d.ts +248 -0
  188. package/lib/typescript/components/LineChart/geometry.d.ts.map +1 -0
  189. package/lib/typescript/components/LineChart/index.d.ts +105 -0
  190. package/lib/typescript/components/LineChart/index.d.ts.map +1 -0
  191. package/lib/typescript/components/LineChart/styles.d.ts +12 -0
  192. package/lib/typescript/components/LineChart/styles.d.ts.map +1 -0
  193. package/lib/typescript/components/PieChart/geometry.d.ts +43 -0
  194. package/lib/typescript/components/PieChart/geometry.d.ts.map +1 -0
  195. package/lib/typescript/components/PieChart/index.d.ts +147 -0
  196. package/lib/typescript/components/PieChart/index.d.ts.map +1 -0
  197. package/lib/typescript/components/PieChart/styles.d.ts +27 -0
  198. package/lib/typescript/components/PieChart/styles.d.ts.map +1 -0
  199. package/lib/typescript/components/ProgressCircle/ProgressCircleRing.d.ts.map +1 -1
  200. package/lib/typescript/components/ProgressCircle/ProgressRing.d.ts +17 -0
  201. package/lib/typescript/components/ProgressCircle/ProgressRing.d.ts.map +1 -0
  202. package/lib/typescript/components/ScrollShadow/useScrollShadow.d.ts.map +1 -1
  203. package/lib/typescript/components/Stepper/index.d.ts +68 -0
  204. package/lib/typescript/components/Stepper/index.d.ts.map +1 -0
  205. package/lib/typescript/components/Stepper/styles.d.ts +46 -0
  206. package/lib/typescript/components/Stepper/styles.d.ts.map +1 -0
  207. package/lib/typescript/components/Stepper/useStepperLabelFit.d.ts +15 -0
  208. package/lib/typescript/components/Stepper/useStepperLabelFit.d.ts.map +1 -0
  209. package/lib/typescript/components/Stepper/useStepperLabelFit.web.d.ts +10 -0
  210. package/lib/typescript/components/Stepper/useStepperLabelFit.web.d.ts.map +1 -0
  211. package/lib/typescript/components/Stepper/useStepperRingColors.d.ts +6 -0
  212. package/lib/typescript/components/Stepper/useStepperRingColors.d.ts.map +1 -0
  213. package/lib/typescript/components/SystemAlert/animation.d.ts +56 -0
  214. package/lib/typescript/components/SystemAlert/animation.d.ts.map +1 -0
  215. package/lib/typescript/components/SystemAlert/index.d.ts +110 -0
  216. package/lib/typescript/components/SystemAlert/index.d.ts.map +1 -0
  217. package/lib/typescript/components/SystemAlert/styles.d.ts +38 -0
  218. package/lib/typescript/components/SystemAlert/styles.d.ts.map +1 -0
  219. package/lib/typescript/components/SystemAlert/useSystemAlertStatusBarStyle.d.ts +14 -0
  220. package/lib/typescript/components/SystemAlert/useSystemAlertStatusBarStyle.d.ts.map +1 -0
  221. package/lib/typescript/components/Tabs/index.d.ts.map +1 -1
  222. package/lib/typescript/components/chart/ChartInspector.d.ts +101 -0
  223. package/lib/typescript/components/chart/ChartInspector.d.ts.map +1 -0
  224. package/lib/typescript/components/chart/format.d.ts +16 -0
  225. package/lib/typescript/components/chart/format.d.ts.map +1 -0
  226. package/lib/typescript/components/chart/index.d.ts +3 -0
  227. package/lib/typescript/components/chart/index.d.ts.map +1 -0
  228. package/lib/typescript/components/chart/motion.d.ts +27 -0
  229. package/lib/typescript/components/chart/motion.d.ts.map +1 -0
  230. package/lib/typescript/components/chart/palette.d.ts +44 -0
  231. package/lib/typescript/components/chart/palette.d.ts.map +1 -0
  232. package/lib/typescript/components/chart/size.d.ts +25 -0
  233. package/lib/typescript/components/chart/size.d.ts.map +1 -0
  234. package/lib/typescript/components/chart/ticks.d.ts +3 -0
  235. package/lib/typescript/components/chart/ticks.d.ts.map +1 -0
  236. package/lib/typescript/components/chart/types.d.ts +163 -0
  237. package/lib/typescript/components/chart/types.d.ts.map +1 -0
  238. package/lib/typescript/components/chart/useChartHostWidth.d.ts +9 -0
  239. package/lib/typescript/components/chart/useChartHostWidth.d.ts.map +1 -0
  240. package/lib/typescript/components/index.d.ts +5 -0
  241. package/lib/typescript/components/index.d.ts.map +1 -1
  242. package/lib/typescript/figma/SystemAlert.Button.figma.d.ts +11 -0
  243. package/lib/typescript/figma/SystemAlert.Button.figma.d.ts.map +1 -0
  244. package/lib/typescript/figma/SystemAlert.Close.figma.d.ts +11 -0
  245. package/lib/typescript/figma/SystemAlert.Close.figma.d.ts.map +1 -0
  246. package/lib/typescript/figma/SystemAlert.Description.figma.d.ts +8 -0
  247. package/lib/typescript/figma/SystemAlert.Description.figma.d.ts.map +1 -0
  248. package/lib/typescript/figma/SystemAlert.IconButton.figma.d.ts +11 -0
  249. package/lib/typescript/figma/SystemAlert.IconButton.figma.d.ts.map +1 -0
  250. package/lib/typescript/figma/SystemAlert.figma.d.ts +8 -0
  251. package/lib/typescript/figma/SystemAlert.figma.d.ts.map +1 -0
  252. package/package.json +5 -5
  253. package/src/components/BarChart/geometry.ts +1469 -0
  254. package/src/components/BarChart/index.tsx +1424 -0
  255. package/src/components/BarChart/styles.ts +31 -0
  256. package/src/components/Button/index.tsx +1 -1
  257. package/src/components/Chip/styles.ts +3 -1
  258. package/src/components/LineChart/geometry.ts +957 -0
  259. package/src/components/LineChart/index.tsx +1109 -0
  260. package/src/components/LineChart/styles.ts +26 -0
  261. package/src/components/PieChart/geometry.ts +295 -0
  262. package/src/components/PieChart/index.tsx +715 -0
  263. package/src/components/PieChart/styles.ts +101 -0
  264. package/src/components/ProgressCircle/ProgressCircleRing.tsx +10 -39
  265. package/src/components/ProgressCircle/ProgressRing.tsx +60 -0
  266. package/src/components/ScrollShadow/useScrollShadow.ts +12 -11
  267. package/src/components/Stepper/index.tsx +452 -0
  268. package/src/components/Stepper/styles.ts +234 -0
  269. package/src/components/Stepper/useStepperLabelFit.ts +21 -0
  270. package/src/components/Stepper/useStepperLabelFit.web.ts +53 -0
  271. package/src/components/Stepper/useStepperRingColors.ts +29 -0
  272. package/src/components/SystemAlert/animation.ts +252 -0
  273. package/src/components/SystemAlert/index.tsx +684 -0
  274. package/src/components/SystemAlert/styles.ts +212 -0
  275. package/src/components/SystemAlert/useSystemAlertStatusBarStyle.ts +57 -0
  276. package/src/components/Tabs/index.tsx +4 -0
  277. package/src/components/Tabs/styles.ts +1 -1
  278. package/src/components/chart/ChartInspector.tsx +726 -0
  279. package/src/components/chart/format.ts +95 -0
  280. package/src/components/chart/index.ts +24 -0
  281. package/src/components/chart/motion.ts +98 -0
  282. package/src/components/chart/palette.tsx +247 -0
  283. package/src/components/chart/size.ts +21 -0
  284. package/src/components/chart/ticks.ts +53 -0
  285. package/src/components/chart/types.ts +183 -0
  286. package/src/components/chart/useChartHostWidth.ts +26 -0
  287. package/src/components/index.ts +5 -0
@@ -0,0 +1,95 @@
1
+ import { formatNumber } from '@cdx-ui/formatters';
2
+ import type {
3
+ ChartLocaleText,
4
+ ChartSummaryCategory,
5
+ ChartSummaryValue,
6
+ ChartTrend,
7
+ ChartValueFormatter,
8
+ } from './types';
9
+
10
+ interface HasValueFormatter {
11
+ readonly valueFormatter?: ChartValueFormatter;
12
+ }
13
+
14
+ function namedValue(value: ChartSummaryValue): string {
15
+ return value.label.length > 0 ? `${value.label} ${value.formattedValue}` : value.formattedValue;
16
+ }
17
+
18
+ function categoryText(category: ChartSummaryCategory): string {
19
+ return `${category.label} ${category.values.map(namedValue).join(', ')}`;
20
+ }
21
+
22
+ export const defaultChartLocaleText: ChartLocaleText = {
23
+ noData: 'No data',
24
+ noValue: 'No value',
25
+ defaultSeriesLabel: 'Value',
26
+ waterfallIncrease: 'Increase',
27
+ waterfallDecrease: 'Decrease',
28
+ trend: ({ direction, formattedDelta, comparisonLabel }: ChartTrend) => {
29
+ const from = comparisonLabel.length > 0 ? ` from ${comparisonLabel}` : '';
30
+ return direction === 'none' ? `no change${from}` : `${direction} ${formattedDelta}${from}`;
31
+ },
32
+ barChartSummary: (categories) =>
33
+ categories.length === 0
34
+ ? 'Bar chart. No data.'
35
+ : `Bar chart. ${categories.map(categoryText).join('; ')}.`,
36
+ lineChartSummary: (latest) =>
37
+ latest === null ? 'Line chart. No data.' : `Line chart. ${categoryText(latest)}.`,
38
+ pieChartSummary: (slices) =>
39
+ slices.length === 0
40
+ ? 'Pie chart. No data.'
41
+ : `Pie chart. ${slices.map(namedValue).join(', ')}.`,
42
+ };
43
+
44
+ /** Consumer strings over the English defaults. `undefined` entries keep the default. */
45
+ export function resolveChartLocaleText(localeText?: Partial<ChartLocaleText>): ChartLocaleText {
46
+ if (localeText === undefined) {
47
+ return defaultChartLocaleText;
48
+ }
49
+ const overrides = Object.entries(localeText as Record<string, unknown>).filter(
50
+ ([, value]) => value !== undefined,
51
+ );
52
+ return { ...defaultChartLocaleText, ...Object.fromEntries(overrides) } as ChartLocaleText;
53
+ }
54
+
55
+ /** Up to two fraction digits, without trailing zeros: `3`, `2.5`, `1,234.56`. */
56
+ export function formatChartNumber(value: number | null, locale?: string): string {
57
+ if (value === null || !Number.isFinite(value)) {
58
+ return '';
59
+ }
60
+ const hundredths = Math.round(Math.abs(value) * 100);
61
+ const decimalPlaces = hundredths % 100 === 0 ? 0 : hundredths % 10 === 0 ? 1 : 2;
62
+ return formatNumber(value, { locale, decimalPlaces });
63
+ }
64
+
65
+ const percentFormatters = new Map<string, Intl.NumberFormat>();
66
+
67
+ /** A 0–1 share as a whole percent for `locale`: `0.46` → `46%`. */
68
+ export function formatChartPercent(share: number, locale?: string): string {
69
+ if (!Number.isFinite(share)) {
70
+ return '';
71
+ }
72
+ // Without a locale, match the `@cdx-ui/formatters` default that numbers use, not the device locale.
73
+ if (locale === undefined) {
74
+ return `${formatNumber(Math.round(share * 100), { decimalPlaces: 0 })}%`;
75
+ }
76
+ let formatter = percentFormatters.get(locale);
77
+ if (formatter === undefined) {
78
+ formatter = new Intl.NumberFormat(locale, { style: 'percent', maximumFractionDigits: 0 });
79
+ percentFormatters.set(locale, formatter);
80
+ }
81
+ return formatter.format(share);
82
+ }
83
+
84
+ export function defaultChartValueFormatter(locale?: string): ChartValueFormatter {
85
+ return (value) => formatChartNumber(value, locale);
86
+ }
87
+
88
+ /** Series formatter, then axis formatter, then the `locale` default. */
89
+ export function resolveValueFormatter(
90
+ series: HasValueFormatter | null | undefined,
91
+ axis: HasValueFormatter | null | undefined,
92
+ locale?: string,
93
+ ): ChartValueFormatter {
94
+ return series?.valueFormatter ?? axis?.valueFormatter ?? defaultChartValueFormatter(locale);
95
+ }
@@ -0,0 +1,24 @@
1
+ export type {
2
+ ChartAxis,
3
+ ChartAxisPosition,
4
+ ChartGrid,
5
+ ChartLocaleText,
6
+ ChartReferenceLine,
7
+ ChartScaleType,
8
+ ChartSelectedItem,
9
+ ChartSeriesBase,
10
+ ChartSeriesCommon,
11
+ ChartSize,
12
+ ChartSizeProps,
13
+ ChartSummaryCategory,
14
+ ChartSummaryValue,
15
+ ChartTooltipContent,
16
+ ChartTooltipItem,
17
+ ChartTooltipProps,
18
+ ChartTrend,
19
+ ChartTrendDirection,
20
+ ChartValueFormatter,
21
+ ChartValueFormatterContext,
22
+ ChartValueLocation,
23
+ } from './types';
24
+ export type { ChartColor, ChartPalette } from './palette';
@@ -0,0 +1,98 @@
1
+ import { useEffect } from 'react';
2
+ import {
3
+ Easing,
4
+ useReducedMotion,
5
+ useSharedValue,
6
+ withTiming,
7
+ type SharedValue,
8
+ } from 'react-native-reanimated';
9
+ import { useCombinedAnimationDisabledState, type AnimationRootDisableAll } from '../../animation';
10
+
11
+ export const CHART_MOTION_DURATION = 600;
12
+ const CHART_MOTION_EASING = Easing.out(Easing.cubic);
13
+
14
+ export interface ChartMorph {
15
+ readonly from: SharedValue<number[]>;
16
+ readonly to: SharedValue<number[]>;
17
+ readonly progress: SharedValue<number>;
18
+ }
19
+
20
+ /** Off for `'disable-all'`, an ancestor or global `disable-all`, and Reduce Motion. */
21
+ export function useChartMotionEnabled(animation: AnimationRootDisableAll | undefined): boolean {
22
+ const disabled = useCombinedAnimationDisabledState(animation);
23
+ const reducedMotion = useReducedMotion();
24
+ return !disabled && !reducedMotion;
25
+ }
26
+
27
+ /**
28
+ * Non-finite entries mark gaps: they snap to the target instead of tweening.
29
+ * Vectors of different lengths cannot be paired, so the target wins outright.
30
+ */
31
+ export function lerpVector(from: readonly number[], to: readonly number[], t: number): number[] {
32
+ 'worklet';
33
+ const out: number[] = [];
34
+ const paired = from.length === to.length;
35
+ for (let index = 0; index < to.length; index += 1) {
36
+ const end = to[index];
37
+ const start = paired ? from[index] : end;
38
+ out.push(Number.isFinite(start) && Number.isFinite(end) ? start + (end - start) * t : end);
39
+ }
40
+ return out;
41
+ }
42
+
43
+ function parseSignature(signature: string): number[] {
44
+ return signature.length === 0 ? [] : signature.split(',').map(Number);
45
+ }
46
+
47
+ /**
48
+ * Tweens a numeric geometry vector on the UI thread. Mounts at `initial` and runs to
49
+ * `target`; later targets start from wherever the previous tween currently is. When the
50
+ * vector changes length (points or slices added/removed) the entry replays from `initial`.
51
+ */
52
+ export function useChartMorph(
53
+ target: readonly number[],
54
+ initial: readonly number[],
55
+ enabled: boolean,
56
+ ): ChartMorph {
57
+ const from = useSharedValue<number[]>(enabled ? [...initial] : [...target]);
58
+ const to = useSharedValue<number[]>([...target]);
59
+ const progress = useSharedValue(enabled ? 0 : 1);
60
+ const signature = target.join(',');
61
+ const initialSignature = initial.join(',');
62
+
63
+ useEffect(() => {
64
+ const next = parseSignature(signature);
65
+ if (!enabled) {
66
+ from.set(next);
67
+ to.set(next);
68
+ progress.set(1);
69
+ return;
70
+ }
71
+ const current = lerpVector(from.get(), to.get(), progress.get());
72
+ from.set(current.length === next.length ? current : parseSignature(initialSignature));
73
+ to.set(next);
74
+ progress.set(0);
75
+ progress.set(withTiming(1, { duration: CHART_MOTION_DURATION, easing: CHART_MOTION_EASING }));
76
+ }, [signature, initialSignature, enabled, from, to, progress]);
77
+
78
+ return { from, to, progress };
79
+ }
80
+
81
+ /**
82
+ * 0 → 1 on mount and whenever `replayKey` changes. Labels sit on animated geometry, so they
83
+ * stay hidden until the morph is mostly done, then fade in at the final position.
84
+ */
85
+ export function useChartEntrance(enabled: boolean, replayKey = ''): SharedValue<number> {
86
+ const progress = useSharedValue(enabled ? 0 : 1);
87
+
88
+ useEffect(() => {
89
+ if (!enabled) {
90
+ progress.set(1);
91
+ return;
92
+ }
93
+ progress.set(0);
94
+ progress.set(withTiming(1, { duration: CHART_MOTION_DURATION, easing: CHART_MOTION_EASING }));
95
+ }, [enabled, replayKey, progress]);
96
+
97
+ return progress;
98
+ }
@@ -0,0 +1,247 @@
1
+ import { useId } from 'react';
2
+ import { Defs, LinearGradient, Stop } from 'react-native-svg';
3
+ import { useCSSVariable, useResolveClassNames } from 'uniwind';
4
+
5
+ /** Light-theme chart tokens, used when Uniwind has no CSS context (Jest). */
6
+ const CHART_FALLBACKS = {
7
+ simple: '#5b91de',
8
+ simpleSecondary: '#162e49',
9
+ simpleTertiary: '#3b6399',
10
+ categorical: ['#155dfc', '#f54900', '#009689', '#e60076', '#9810fa', '#525252'] as const,
11
+ danger: '#c10007',
12
+ warning: '#ffb900',
13
+ success: '#00a63e',
14
+ info: '#0069a8',
15
+ } as const;
16
+
17
+ function toColor(value: string | number | undefined, fallback: string): string {
18
+ if (typeof value === 'string' && value.length > 0) {
19
+ return value;
20
+ }
21
+ return fallback;
22
+ }
23
+
24
+ export function useChartSimpleColor(): string {
25
+ const value = useCSSVariable('--color-chart-simple-primary');
26
+ return toColor(value, CHART_FALLBACKS.simple);
27
+ }
28
+
29
+ /**
30
+ * A Forge color token by name: `simple-*` and `categorical-*` resolve
31
+ * `--color-chart-<name>`, severity names resolve `--color-surface-<name>-strong`.
32
+ * Overrides take a name, not a CSS color, so FI themes and dark mode recolor every chart.
33
+ */
34
+ export type ChartColor =
35
+ | 'danger'
36
+ | 'warning'
37
+ | 'success'
38
+ | 'info'
39
+ | 'simple-primary'
40
+ | 'simple-secondary'
41
+ | 'simple-tertiary'
42
+ | 'categorical-1'
43
+ | 'categorical-2'
44
+ | 'categorical-3'
45
+ | 'categorical-4'
46
+ | 'categorical-5'
47
+ | 'categorical-6';
48
+
49
+ export type ChartColorPaints = Readonly<Record<ChartColor, string>>;
50
+
51
+ const warnedChartColors = new Set<string>();
52
+
53
+ export function resolveChartColor(
54
+ color: ChartColor | undefined,
55
+ paints: ChartColorPaints,
56
+ ): string | undefined {
57
+ if (color === undefined) return undefined;
58
+ const paint = paints[color] as string | undefined;
59
+ if (paint === undefined && __DEV__ && !warnedChartColors.has(color)) {
60
+ warnedChartColors.add(color);
61
+ console.warn(
62
+ `[Chart] Unknown color "${String(color)}". Pass a ChartColor token name, not a CSS ` +
63
+ 'color; the default series color is used instead.',
64
+ );
65
+ }
66
+ return paint;
67
+ }
68
+
69
+ export function useChartColorPaints(): ChartColorPaints {
70
+ const simple = useChartSimpleColor();
71
+ const secondary = toColor(
72
+ useCSSVariable('--color-chart-simple-secondary'),
73
+ CHART_FALLBACKS.simpleSecondary,
74
+ );
75
+ const tertiary = toColor(
76
+ useCSSVariable('--color-chart-simple-tertiary'),
77
+ CHART_FALLBACKS.simpleTertiary,
78
+ );
79
+ const danger = toColor(useCSSVariable('--color-surface-danger-strong'), CHART_FALLBACKS.danger);
80
+ const warning = toColor(
81
+ useCSSVariable('--color-surface-warning-strong'),
82
+ CHART_FALLBACKS.warning,
83
+ );
84
+ const success = toColor(
85
+ useCSSVariable('--color-surface-success-strong'),
86
+ CHART_FALLBACKS.success,
87
+ );
88
+ const info = toColor(useCSSVariable('--color-surface-info-strong'), CHART_FALLBACKS.info);
89
+ const palette = useChartPalette();
90
+ return {
91
+ danger,
92
+ warning,
93
+ success,
94
+ info,
95
+ 'simple-primary': simple,
96
+ 'simple-secondary': secondary,
97
+ 'simple-tertiary': tertiary,
98
+ 'categorical-1': palette[0] ?? CHART_FALLBACKS.categorical[0],
99
+ 'categorical-2': palette[1] ?? CHART_FALLBACKS.categorical[1],
100
+ 'categorical-3': palette[2] ?? CHART_FALLBACKS.categorical[2],
101
+ 'categorical-4': palette[3] ?? CHART_FALLBACKS.categorical[3],
102
+ 'categorical-5': palette[4] ?? CHART_FALLBACKS.categorical[4],
103
+ 'categorical-6': palette[5] ?? CHART_FALLBACKS.categorical[5],
104
+ };
105
+ }
106
+
107
+ /**
108
+ * SVG text cannot take `className`, so typography tokens are resolved here.
109
+ * `useResolveClassNames` converts rem to px with the consumer's rem base; web
110
+ * may return rem strings, which fall back to the light-theme pixel size.
111
+ */
112
+ function toPx(value: string | number | undefined, fallbackPx: number): number {
113
+ if (typeof value === 'number') {
114
+ return Number.isFinite(value) ? value : fallbackPx;
115
+ }
116
+ if (typeof value !== 'string') return fallbackPx;
117
+ const trimmed = value.trim();
118
+ if (!/^-?\d*\.?\d+(px)?$/.test(trimmed)) return fallbackPx;
119
+ return parseFloat(trimmed);
120
+ }
121
+
122
+ export interface ChartChrome {
123
+ readonly grid: string;
124
+ readonly label: string;
125
+ readonly surface: string;
126
+ readonly fontFamily: string;
127
+ /** `text-xs` — axis ticks and category labels. */
128
+ readonly labelSize: number;
129
+ /** `text-2xs` — values, reference and marker captions. */
130
+ readonly captionSize: number;
131
+ }
132
+
133
+ export function useChartChrome(): ChartChrome {
134
+ const grid = useCSSVariable('--color-stroke-secondary');
135
+ const label = useCSSVariable('--color-content-primary');
136
+ const surface = useCSSVariable('--color-surface-primary');
137
+ const fontFamily = useCSSVariable('--font-body');
138
+ const labelText = useResolveClassNames('text-xs');
139
+ const captionText = useResolveClassNames('text-2xs');
140
+ return {
141
+ grid: toColor(grid, '#e9e9e9'),
142
+ label: toColor(label, '#1b1c1d'),
143
+ surface: toColor(surface, '#ffffff'),
144
+ fontFamily: toColor(fontFamily, 'Inter'),
145
+ labelSize: toPx(labelText.fontSize, 12),
146
+ captionSize: toPx(captionText.fontSize, 10),
147
+ };
148
+ }
149
+
150
+ /**
151
+ * Resolved `categorical-1`…`6` paints, in slot order. Pie slices and charts past
152
+ * three series cycle them.
153
+ */
154
+ export function useChartPalette(): readonly string[] {
155
+ const slot1 = useCSSVariable('--color-chart-categorical-1');
156
+ const slot2 = useCSSVariable('--color-chart-categorical-2');
157
+ const slot3 = useCSSVariable('--color-chart-categorical-3');
158
+ const slot4 = useCSSVariable('--color-chart-categorical-4');
159
+ const slot5 = useCSSVariable('--color-chart-categorical-5');
160
+ const slot6 = useCSSVariable('--color-chart-categorical-6');
161
+
162
+ return [
163
+ toColor(slot1, CHART_FALLBACKS.categorical[0]),
164
+ toColor(slot2, CHART_FALLBACKS.categorical[1]),
165
+ toColor(slot3, CHART_FALLBACKS.categorical[2]),
166
+ toColor(slot4, CHART_FALLBACKS.categorical[3]),
167
+ toColor(slot5, CHART_FALLBACKS.categorical[4]),
168
+ toColor(slot6, CHART_FALLBACKS.categorical[5]),
169
+ ];
170
+ }
171
+
172
+ /**
173
+ * `auto` keeps up to three series in the FI brand family and moves the whole chart to
174
+ * `categorical-1`…`6` past that, so one chart never mixes the two families.
175
+ * `categorical` always uses them.
176
+ */
177
+ export type ChartPalette = 'auto' | 'categorical';
178
+
179
+ export type ChartSeriesKind = 'bar' | 'line';
180
+
181
+ /**
182
+ * Bars alternate light, dark, mid so adjacent bars don't read as a ramp. Lines step
183
+ * primary → tertiary → secondary so a two-line chart pairs neighboring brand steps.
184
+ */
185
+ const SIMPLE_SERIES: Record<ChartSeriesKind, readonly ChartColor[]> = {
186
+ bar: ['simple-primary', 'simple-secondary', 'simple-tertiary'],
187
+ line: ['simple-primary', 'simple-tertiary', 'simple-secondary'],
188
+ };
189
+
190
+ const CATEGORICAL_SERIES: readonly ChartColor[] = [
191
+ 'categorical-1',
192
+ 'categorical-2',
193
+ 'categorical-3',
194
+ 'categorical-4',
195
+ 'categorical-5',
196
+ 'categorical-6',
197
+ ];
198
+
199
+ /** Default color for a series. A series `color` still wins. */
200
+ export function chartSeriesColor(
201
+ seriesIndex: number,
202
+ seriesCount: number,
203
+ palette: ChartPalette,
204
+ kind: ChartSeriesKind,
205
+ ): ChartColor {
206
+ const simple = SIMPLE_SERIES[kind];
207
+ const ramp = palette === 'auto' && seriesCount <= simple.length ? simple : CATEGORICAL_SERIES;
208
+ return ramp[seriesIndex % ramp.length] ?? 'simple-primary';
209
+ }
210
+
211
+ export function useChartGradientId(prefix: string): string {
212
+ return `${prefix}-${useId().replace(/[^a-zA-Z0-9_-]/g, '')}`;
213
+ }
214
+
215
+ export function chartFillUrl(idPrefix: string, index: number): string {
216
+ return `url(#${idPrefix}-${String(index)})`;
217
+ }
218
+
219
+ export function ChartLinearFills({
220
+ idPrefix,
221
+ colors,
222
+ x2,
223
+ y2,
224
+ }: {
225
+ readonly idPrefix: string;
226
+ readonly colors: readonly string[];
227
+ readonly x2: string;
228
+ readonly y2: string;
229
+ }) {
230
+ return (
231
+ <Defs>
232
+ {colors.map((color, index) => (
233
+ <LinearGradient
234
+ key={`${idPrefix}-${String(index)}`}
235
+ id={`${idPrefix}-${String(index)}`}
236
+ x1="0%"
237
+ y1="0%"
238
+ x2={x2}
239
+ y2={y2}
240
+ >
241
+ <Stop offset="0%" stopColor={color} />
242
+ <Stop offset="100%" stopColor={color} />
243
+ </LinearGradient>
244
+ ))}
245
+ </Defs>
246
+ );
247
+ }
@@ -0,0 +1,21 @@
1
+ import type { ChartSize } from './types';
2
+
3
+ /** Plot boxes. Heights match the spacing scale (`size-40`…`size-64`). */
4
+ export const CHART_DIMENSIONS = {
5
+ sm: { width: 256, height: 160 },
6
+ md: { width: 308, height: 192 },
7
+ lg: { width: 360, height: 224 },
8
+ xl: { width: 410, height: 256 },
9
+ } as const satisfies Record<ChartSize, { readonly width: number; readonly height: number }>;
10
+
11
+ export function resolveChartBox(
12
+ size: ChartSize | undefined,
13
+ width?: number,
14
+ height?: number,
15
+ ): { readonly width: number; readonly height: number } {
16
+ const preset = CHART_DIMENSIONS[size ?? 'lg'];
17
+ return {
18
+ width: width ?? preset.width,
19
+ height: height ?? preset.height,
20
+ };
21
+ }
@@ -0,0 +1,53 @@
1
+ /** Rounds away float drift at the step's precision, so steps below 0.01 stay distinct. */
2
+ function roundToStep(value: number, step: number): number {
3
+ const decimals = Math.min(20, Math.max(2, -Math.floor(Math.log10(step)) + 1));
4
+ const rounded = Number(value.toFixed(decimals));
5
+ return Object.is(rounded, -0) ? 0 : rounded;
6
+ }
7
+
8
+ function niceNumber(span: number, round: boolean): number {
9
+ if (span <= 0 || !Number.isFinite(span)) {
10
+ return 1;
11
+ }
12
+ const exponent = Math.floor(Math.log10(span));
13
+ const fraction = span / 10 ** exponent;
14
+ let niceFraction: number;
15
+ if (round) {
16
+ if (fraction < 1.5) {
17
+ niceFraction = 1;
18
+ } else if (fraction < 3) {
19
+ niceFraction = 2;
20
+ } else if (fraction < 7) {
21
+ niceFraction = 5;
22
+ } else {
23
+ niceFraction = 10;
24
+ }
25
+ } else if (fraction <= 1) {
26
+ niceFraction = 1;
27
+ } else if (fraction <= 2) {
28
+ niceFraction = 2;
29
+ } else if (fraction <= 5) {
30
+ niceFraction = 5;
31
+ } else {
32
+ niceFraction = 10;
33
+ }
34
+ return niceFraction * 10 ** exponent;
35
+ }
36
+
37
+ /** Evenly spaced, readable ticks that cover `min`–`max` in about `count` steps. */
38
+ export function niceTicks(min: number, max: number, count: number): number[] {
39
+ if (!Number.isFinite(min) || !Number.isFinite(max)) {
40
+ return [];
41
+ }
42
+ const tickCount = Math.max(2, count);
43
+ const span = niceNumber(max - min, false);
44
+ const step = niceNumber(span / (tickCount - 1), true);
45
+ const niceMin = Math.floor(min / step) * step;
46
+ const niceMax = Math.ceil(max / step) * step;
47
+ const ticks: number[] = [];
48
+ const last = niceMax + step / 2;
49
+ for (let value = niceMin; value <= last; value += step) {
50
+ ticks.push(roundToStep(value, step));
51
+ }
52
+ return ticks;
53
+ }