@epilot/spark-ui 1.0.0-alpha.3 → 1.0.0-alpha.5

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 (229) hide show
  1. package/dist/accent-colors-Ch2J0EEY.js +13 -0
  2. package/dist/accent-colors-Ch2J0EEY.js.map +1 -0
  3. package/dist/accent-colors-CjHCf8fH.cjs +18 -0
  4. package/dist/accent-colors-CjHCf8fH.cjs.map +1 -0
  5. package/dist/components/accordion.cjs +1 -1
  6. package/dist/components/accordion.d.ts +1 -1
  7. package/dist/components/accordion.js +1 -1
  8. package/dist/components/attachment.d.cts +1 -1
  9. package/dist/components/attachment.d.ts +1 -1
  10. package/dist/components/badge.cjs +12 -7
  11. package/dist/components/badge.cjs.map +1 -1
  12. package/dist/components/badge.d.cts +5 -1
  13. package/dist/components/badge.d.ts +5 -1
  14. package/dist/components/badge.js +12 -7
  15. package/dist/components/badge.js.map +1 -1
  16. package/dist/components/bar-chart.cjs +60 -56
  17. package/dist/components/bar-chart.cjs.map +1 -1
  18. package/dist/components/bar-chart.d.cts +7 -2
  19. package/dist/components/bar-chart.d.ts +7 -2
  20. package/dist/components/bar-chart.js +60 -56
  21. package/dist/components/bar-chart.js.map +1 -1
  22. package/dist/components/battery-progress-row.cjs +10 -16
  23. package/dist/components/battery-progress-row.cjs.map +1 -1
  24. package/dist/components/battery-progress-row.d.cts +1 -1
  25. package/dist/components/battery-progress-row.d.ts +2 -2
  26. package/dist/components/battery-progress-row.js +10 -16
  27. package/dist/components/battery-progress-row.js.map +1 -1
  28. package/dist/components/bubble.d.cts +1 -1
  29. package/dist/components/bubble.d.ts +1 -1
  30. package/dist/components/button.cjs +5 -2
  31. package/dist/components/button.cjs.map +1 -1
  32. package/dist/components/button.d.cts +16 -7
  33. package/dist/components/button.d.ts +16 -7
  34. package/dist/components/button.js +5 -2
  35. package/dist/components/button.js.map +1 -1
  36. package/dist/components/callout.d.cts +1 -1
  37. package/dist/components/callout.d.ts +1 -1
  38. package/dist/components/card.d.cts +1 -1
  39. package/dist/components/card.d.ts +1 -1
  40. package/dist/components/chart.cjs +1 -1
  41. package/dist/components/chart.cjs.map +1 -1
  42. package/dist/components/chart.js +1 -1
  43. package/dist/components/chart.js.map +1 -1
  44. package/dist/components/checkbox.cjs +30 -23
  45. package/dist/components/checkbox.cjs.map +1 -1
  46. package/dist/components/checkbox.d.cts +5 -1
  47. package/dist/components/checkbox.d.ts +5 -1
  48. package/dist/components/checkbox.js +30 -23
  49. package/dist/components/checkbox.js.map +1 -1
  50. package/dist/components/circular-gauge.d.ts +1 -1
  51. package/dist/components/day-of-week-picker.cjs +2 -2
  52. package/dist/components/day-of-week-picker.cjs.map +1 -1
  53. package/dist/components/day-of-week-picker.js +2 -2
  54. package/dist/components/day-of-week-picker.js.map +1 -1
  55. package/dist/components/device-card.d.ts +1 -1
  56. package/dist/components/donut-chart.cjs +3 -3
  57. package/dist/components/donut-chart.cjs.map +1 -1
  58. package/dist/components/donut-chart.js +3 -3
  59. package/dist/components/donut-chart.js.map +1 -1
  60. package/dist/components/energy-bar-chart.cjs +2 -1
  61. package/dist/components/energy-bar-chart.cjs.map +1 -1
  62. package/dist/components/energy-bar-chart.d.ts +1 -1
  63. package/dist/components/energy-bar-chart.js +2 -1
  64. package/dist/components/energy-bar-chart.js.map +1 -1
  65. package/dist/components/energy-breakdown.cjs +1 -1
  66. package/dist/components/energy-breakdown.cjs.map +1 -1
  67. package/dist/components/energy-breakdown.js +1 -1
  68. package/dist/components/energy-breakdown.js.map +1 -1
  69. package/dist/components/energy-history-chart.cjs +14 -6
  70. package/dist/components/energy-history-chart.cjs.map +1 -1
  71. package/dist/components/energy-history-chart.d.cts +11 -3
  72. package/dist/components/energy-history-chart.d.ts +11 -3
  73. package/dist/components/energy-history-chart.js +14 -6
  74. package/dist/components/energy-history-chart.js.map +1 -1
  75. package/dist/components/feed-in-hero.d.ts +1 -1
  76. package/dist/components/field.cjs +1 -1
  77. package/dist/components/field.d.cts +1 -1
  78. package/dist/components/field.d.ts +1 -1
  79. package/dist/components/field.js +1 -1
  80. package/dist/components/info-block.d.cts +1 -1
  81. package/dist/components/info-block.d.ts +1 -1
  82. package/dist/components/input-group.cjs +1 -1
  83. package/dist/components/input-group.js +1 -1
  84. package/dist/components/input-otp.cjs +1 -1
  85. package/dist/components/input-otp.js +1 -1
  86. package/dist/components/input.cjs +1 -1
  87. package/dist/components/input.d.cts +1 -1
  88. package/dist/components/input.d.ts +1 -1
  89. package/dist/components/input.js +1 -1
  90. package/dist/components/line-chart.cjs +61 -19
  91. package/dist/components/line-chart.cjs.map +1 -1
  92. package/dist/components/line-chart.d.cts +7 -0
  93. package/dist/components/line-chart.d.ts +7 -0
  94. package/dist/components/line-chart.js +61 -19
  95. package/dist/components/line-chart.js.map +1 -1
  96. package/dist/components/metering-row.d.ts +1 -1
  97. package/dist/components/money-saved-block.cjs +1 -1
  98. package/dist/components/money-saved-block.cjs.map +1 -1
  99. package/dist/components/money-saved-block.js +1 -1
  100. package/dist/components/money-saved-block.js.map +1 -1
  101. package/dist/components/number-flow.d.ts +1 -1
  102. package/dist/components/power-history-chart.cjs +23 -44
  103. package/dist/components/power-history-chart.cjs.map +1 -1
  104. package/dist/components/power-history-chart.d.cts +10 -1
  105. package/dist/components/power-history-chart.d.ts +10 -1
  106. package/dist/components/power-history-chart.js +24 -45
  107. package/dist/components/power-history-chart.js.map +1 -1
  108. package/dist/components/power-history.cjs +1 -1
  109. package/dist/components/power-history.cjs.map +1 -1
  110. package/dist/components/power-history.js +1 -1
  111. package/dist/components/power-history.js.map +1 -1
  112. package/dist/components/power-network.cjs +36 -11
  113. package/dist/components/power-network.cjs.map +1 -1
  114. package/dist/components/power-network.js +36 -11
  115. package/dist/components/power-network.js.map +1 -1
  116. package/dist/components/progress.cjs +1 -1
  117. package/dist/components/progress.cjs.map +1 -1
  118. package/dist/components/progress.js +1 -1
  119. package/dist/components/progress.js.map +1 -1
  120. package/dist/components/radio-card-group.cjs +26 -1
  121. package/dist/components/radio-card-group.cjs.map +1 -1
  122. package/dist/components/radio-card-group.js +26 -1
  123. package/dist/components/radio-card-group.js.map +1 -1
  124. package/dist/components/radio.cjs +11 -4
  125. package/dist/components/radio.cjs.map +1 -1
  126. package/dist/components/radio.d.cts +15 -3
  127. package/dist/components/radio.d.ts +15 -3
  128. package/dist/components/radio.js +11 -4
  129. package/dist/components/radio.js.map +1 -1
  130. package/dist/components/sankey-chart.cjs +12 -45
  131. package/dist/components/sankey-chart.cjs.map +1 -1
  132. package/dist/components/sankey-chart.d.cts +8 -0
  133. package/dist/components/sankey-chart.d.ts +9 -1
  134. package/dist/components/sankey-chart.js +12 -45
  135. package/dist/components/sankey-chart.js.map +1 -1
  136. package/dist/components/schedule-list.cjs +3 -3
  137. package/dist/components/schedule-list.cjs.map +1 -1
  138. package/dist/components/schedule-list.js +3 -3
  139. package/dist/components/schedule-list.js.map +1 -1
  140. package/dist/components/segmented-control.cjs +44 -0
  141. package/dist/components/segmented-control.cjs.map +1 -0
  142. package/dist/components/segmented-control.d.cts +33 -0
  143. package/dist/components/segmented-control.d.ts +33 -0
  144. package/dist/components/segmented-control.js +40 -0
  145. package/dist/components/segmented-control.js.map +1 -0
  146. package/dist/components/select.cjs +1 -1
  147. package/dist/components/select.d.cts +1 -1
  148. package/dist/components/select.d.ts +1 -1
  149. package/dist/components/select.js +1 -1
  150. package/dist/components/separator.cjs +1 -1
  151. package/dist/components/separator.cjs.map +1 -1
  152. package/dist/components/separator.js +1 -1
  153. package/dist/components/separator.js.map +1 -1
  154. package/dist/components/series-legend.cjs +1 -1
  155. package/dist/components/series-legend.cjs.map +1 -1
  156. package/dist/components/series-legend.js +1 -1
  157. package/dist/components/series-legend.js.map +1 -1
  158. package/dist/components/slider.cjs +6 -19
  159. package/dist/components/slider.cjs.map +1 -1
  160. package/dist/components/slider.d.cts +0 -13
  161. package/dist/components/slider.d.ts +0 -13
  162. package/dist/components/slider.js +6 -19
  163. package/dist/components/slider.js.map +1 -1
  164. package/dist/components/solar-forecast-chart.cjs +4 -3
  165. package/dist/components/solar-forecast-chart.cjs.map +1 -1
  166. package/dist/components/solar-forecast-chart.d.cts +4 -1
  167. package/dist/components/solar-forecast-chart.d.ts +4 -1
  168. package/dist/components/solar-forecast-chart.js +4 -3
  169. package/dist/components/solar-forecast-chart.js.map +1 -1
  170. package/dist/components/stepper.cjs +2 -2
  171. package/dist/components/stepper.cjs.map +1 -1
  172. package/dist/components/stepper.js +2 -2
  173. package/dist/components/stepper.js.map +1 -1
  174. package/dist/components/switch.cjs +8 -3
  175. package/dist/components/switch.cjs.map +1 -1
  176. package/dist/components/switch.d.cts +9 -4
  177. package/dist/components/switch.d.ts +9 -4
  178. package/dist/components/switch.js +8 -3
  179. package/dist/components/switch.js.map +1 -1
  180. package/dist/components/tabs.cjs +4 -4
  181. package/dist/components/tabs.cjs.map +1 -1
  182. package/dist/components/tabs.js +4 -4
  183. package/dist/components/tabs.js.map +1 -1
  184. package/dist/components/theme.cjs +1 -1
  185. package/dist/components/theme.d.cts +1 -1
  186. package/dist/components/theme.d.ts +1 -1
  187. package/dist/components/theme.js +1 -1
  188. package/dist/components/time-picker.cjs +1 -1
  189. package/dist/components/time-picker.cjs.map +1 -1
  190. package/dist/components/time-picker.js +1 -1
  191. package/dist/components/time-picker.js.map +1 -1
  192. package/dist/components/tooltip.cjs +1 -1
  193. package/dist/components/tooltip.cjs.map +1 -1
  194. package/dist/components/tooltip.js +1 -1
  195. package/dist/components/tooltip.js.map +1 -1
  196. package/dist/hooks/use-reduced-motion.cjs +22 -0
  197. package/dist/hooks/use-reduced-motion.cjs.map +1 -0
  198. package/dist/hooks/use-reduced-motion.d.cts +7 -0
  199. package/dist/hooks/use-reduced-motion.d.ts +7 -0
  200. package/dist/hooks/use-reduced-motion.js +20 -0
  201. package/dist/hooks/use-reduced-motion.js.map +1 -0
  202. package/dist/{input-box-variants-Dr1K7uYE.js → input-box-variants-DcajYXvo.js} +1 -1
  203. package/dist/{input-box-variants-Dr1K7uYE.js.map → input-box-variants-DcajYXvo.js.map} +1 -1
  204. package/dist/{input-box-variants-BMDdwvqg.cjs → input-box-variants-ZCtgs-1S.cjs} +1 -1
  205. package/dist/{input-box-variants-BMDdwvqg.cjs.map → input-box-variants-ZCtgs-1S.cjs.map} +1 -1
  206. package/dist/{number-flow-DSbucQ_K.d.ts → number-flow-D9zsxH0-.d.ts} +1 -1
  207. package/dist/styles/index.css +39 -0
  208. package/dist/styles/spark-default.css +123 -40
  209. package/dist/styles/theme.css +78 -0
  210. package/dist/{theme-B3WtiByA.js → theme-8PDO9E0S.js} +2 -2
  211. package/dist/theme-8PDO9E0S.js.map +1 -0
  212. package/dist/{theme-C9_OSe0S.cjs → theme-ClRJhexF.cjs} +2 -2
  213. package/dist/theme-ClRJhexF.cjs.map +1 -0
  214. package/dist/{theme-types-DoROIXpi.d.ts → theme-types-BDdoRxXa.d.ts} +2 -3
  215. package/dist/{theme-types-r20EJfEC.d.cts → theme-types-BwSJKdsB.d.cts} +2 -3
  216. package/dist/{tones-DyCkL71h.d.ts → tones-PXJGlSpe.d.ts} +1 -1
  217. package/dist/utils/build-sankey-nodes.cjs +16 -3
  218. package/dist/utils/build-sankey-nodes.cjs.map +1 -1
  219. package/dist/utils/build-sankey-nodes.js +16 -3
  220. package/dist/utils/build-sankey-nodes.js.map +1 -1
  221. package/dist/utils/chart-scale.cjs +43 -0
  222. package/dist/utils/chart-scale.cjs.map +1 -0
  223. package/dist/utils/chart-scale.d.cts +22 -0
  224. package/dist/utils/chart-scale.d.ts +22 -0
  225. package/dist/utils/chart-scale.js +41 -0
  226. package/dist/utils/chart-scale.js.map +1 -0
  227. package/package.json +1 -1
  228. package/dist/theme-B3WtiByA.js.map +0 -1
  229. package/dist/theme-C9_OSe0S.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"bar-chart.cjs","names":["localeNumberFormat","integerFormat","oneDecimalFormat","BarStack","useMeasuredSize","clampTooltipPosition","SectionTitle","SeriesLegend","ChartTooltipCard","Group"],"sources":["../../src/components/bar-chart.tsx"],"sourcesContent":["import { localPoint } from '@visx/event'\nimport { Group } from '@visx/group'\nimport { scaleBand, scaleLinear, scaleOrdinal } from '@visx/scale'\nimport { BarStack } from '@visx/shape'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { cn } from '../utils/cn'\nimport {\n integerFormat,\n localeNumberFormat,\n oneDecimalFormat,\n} from '../utils/format'\nimport {\n ChartTooltipCard,\n type ChartTooltipRow,\n clampTooltipPosition,\n useMeasuredSize,\n} from './chart'\nimport { SeriesLegend } from './series-legend'\nimport { SectionTitle } from './typography'\n\nconst defaultTotalFormat = localeNumberFormat()\n\nexport type BarChartCategory = string | number\n\nexport interface BarChartSeries<TDatum> {\n key: string\n label: string\n color: string\n hoverFill?: string\n getValue: (datum: TDatum) => number\n}\n\nexport interface BarChartLineSeries<TDatum> {\n key: string\n label: string\n color: string\n /** `null` gaps break the line (e.g. hours without a reading). */\n getValue: (datum: TDatum) => number | null\n /** Own y-domain for this line (e.g. `[0, 100]` for a percentage). Defaults to the bar scale. */\n domain?: [number, number]\n /** Start hidden; the user can enable the line from the legend. */\n hiddenByDefault?: boolean\n /** Formats this line's value in the hover tooltip. Defaults to `formatValue`. */\n formatValue?: (value: number) => string\n strokeDasharray?: string\n}\n\nexport interface BarChartProps<TDatum> {\n data: TDatum[]\n series: BarChartSeries<TDatum>[]\n /** Line overlays drawn on top of the bars, toggleable from the legend. */\n lines?: BarChartLineSeries<TDatum>[]\n getCategory: (datum: TDatum) => BarChartCategory\n /** Full ordered set of categories on the x-axis. Defaults to `data.map(getCategory)`. */\n categories?: BarChartCategory[]\n /** Subset of categories that should render an x-axis label. Defaults to every category. */\n categoryTicks?: BarChartCategory[]\n formatCategory?: (category: BarChartCategory) => string\n /** Formats the hovered category in the tooltip header. Defaults to `formatCategory`. */\n formatTooltipCategory?: (category: BarChartCategory) => string\n highlightedCategory?: BarChartCategory\n showHighlightLine?: boolean\n /**\n * Horizontal reference line drawn across the plot at a given y-value.\n * Useful for thresholds (e.g. price ceiling).\n */\n referenceLine?: { value: number; label?: string; color?: string }\n title?: string\n yAxisUnit?: string\n height?: number\n /** Override how the total value (sum of focused or all categories) is rendered. */\n renderTotal?: (value: number) => React.ReactNode\n /** Format function used when `renderTotal` is not provided. */\n formatTotal?: (value: number) => string\n /** Formats per-series values in the hover tooltip. Defaults to `formatTotal`. */\n formatValue?: (value: number) => string\n className?: string\n}\n\ninterface StackDatum {\n __category: BarChartCategory\n __values: Record<string, number>\n}\n\ninterface BarStackLayerProps<TDatum> {\n stackData: StackDatum[]\n series: BarChartSeries<TDatum>[]\n seriesByKey: Map<string, BarChartSeries<TDatum>>\n xScale: ReturnType<typeof scaleBand<BarChartCategory>>\n yScale: ReturnType<typeof scaleLinear<number>>\n colorScale: ReturnType<typeof scaleOrdinal<string, string>>\n}\n\ninterface CategoryTicksProps {\n ticks: BarChartCategory[]\n xScale: ReturnType<typeof scaleBand<BarChartCategory>>\n height: number\n formatCategory: (category: BarChartCategory) => string\n}\n\nconst PADDING_TOP = 20\nconst PADDING_BOTTOM = 28\nconst HOVER_FADE_MS = 200\nconst FOCUS_TRANSITION_MS = 180\nconst DEFAULT_HEIGHT = 220\nconst BAR_RADIUS = 2\nconst Y_AXIS_GUTTER = 34\n\nfunction buildYAxisTicks(yMax: number) {\n const steps = 4\n const rawStep = yMax / steps\n const normalized = rawStep === 0 ? 1 : rawStep\n const magnitude = Math.pow(10, Math.floor(Math.log10(normalized)))\n const niceSteps = [1, 2, 2.5, 5, 10]\n const step =\n (niceSteps.find((value) => value * magnitude >= normalized) ?? 10) *\n magnitude\n const upper = Math.ceil(yMax / step) * step\n const ticks: number[] = []\n\n for (let value = 0; value <= upper + step * 0.001; value += step) {\n ticks.push(Number(value.toFixed(6)))\n }\n\n return ticks\n}\n\nfunction formatYAxisTick(value: number) {\n return value >= 10\n ? integerFormat.format(value)\n : oneDecimalFormat.format(value)\n}\n\nfunction buildBarPath(\n x: number,\n y: number,\n width: number,\n height: number,\n radius: number,\n roundTop: boolean,\n roundBottom: boolean,\n) {\n const r = Math.max(0, Math.min(radius, width / 2, height / 2))\n\n if (r === 0 || (!roundTop && !roundBottom)) {\n return `M ${x} ${y} H ${x + width} V ${y + height} H ${x} Z`\n }\n\n const tl = roundTop ? r : 0\n const tr = roundTop ? r : 0\n const br = roundBottom ? r : 0\n const bl = roundBottom ? r : 0\n\n return [\n `M ${x + tl} ${y}`,\n `H ${x + width - tr}`,\n tr > 0\n ? `Q ${x + width} ${y} ${x + width} ${y + tr}`\n : `L ${x + width} ${y}`,\n `V ${y + height - br}`,\n br > 0\n ? `Q ${x + width} ${y + height} ${x + width - br} ${y + height}`\n : `L ${x + width} ${y + height}`,\n `H ${x + bl}`,\n bl > 0\n ? `Q ${x} ${y + height} ${x} ${y + height - bl}`\n : `L ${x} ${y + height}`,\n `V ${y + tl}`,\n tl > 0 ? `Q ${x} ${y} ${x + tl} ${y}` : `L ${x} ${y}`,\n 'Z',\n ].join(' ')\n}\n\nfunction BarStackLayer<TDatum>({\n stackData,\n series,\n seriesByKey,\n xScale,\n yScale,\n colorScale,\n}: BarStackLayerProps<TDatum>) {\n return (\n <BarStack<StackDatum, string>\n data={stackData}\n keys={series.map((entry) => entry.key)}\n x={(record) => record.__category}\n value={(record, key) => record.__values[key] ?? 0}\n xScale={xScale}\n yScale={yScale}\n color={colorScale}\n >\n {(barStacks) =>\n barStacks.map((barStack) =>\n barStack.bars.map((bar) => {\n const segmentValue = bar.bar.data.__values[barStack.key] ?? 0\n\n if (segmentValue === 0) {\n return null\n }\n\n const seriesEntry = seriesByKey.get(barStack.key)\n const strokeColor = seriesEntry?.color ?? bar.color\n const fillColor = strokeColor\n const valueKeys = series\n .map((entry) => entry.key)\n .filter((key) => (bar.bar.data.__values[key] ?? 0) > 0)\n const isBottomSegment = valueKeys[0] === barStack.key\n const isTopSegment =\n valueKeys[valueKeys.length - 1] === barStack.key\n\n return (\n <path\n key={`bar-${barStack.index}-${bar.index}`}\n d={buildBarPath(\n bar.x,\n bar.y,\n bar.width,\n Math.max(0, bar.height),\n BAR_RADIUS,\n isTopSegment,\n isBottomSegment,\n )}\n fill={fillColor}\n stroke={strokeColor}\n strokeWidth={1}\n style={{ transition: 'fill 180ms ease' }}\n />\n )\n }),\n )\n }\n </BarStack>\n )\n}\n\ninterface FocusBorderProps<TDatum> {\n category: BarChartCategory\n visible: boolean\n stackData: StackDatum[]\n series: BarChartSeries<TDatum>[]\n xScale: ReturnType<typeof scaleBand<BarChartCategory>>\n yScale: ReturnType<typeof scaleLinear<number>>\n}\n\nfunction FocusBorder<TDatum>({\n category,\n visible,\n stackData,\n series,\n xScale,\n yScale,\n}: FocusBorderProps<TDatum>) {\n const x = xScale(category)\n const datum = stackData.find((entry) => entry.__category === category)\n\n if (x === undefined || !datum) {\n return null\n }\n\n const hasAnyValue = series.some(\n (entry) => (datum.__values[entry.key] ?? 0) > 0,\n )\n\n if (!hasAnyValue) {\n return null\n }\n\n const topY = PADDING_TOP\n const baselineY = yScale(0)\n const borderPaddingX = 4\n const borderPaddingY = 3\n const borderXRaw = x - borderPaddingX\n const borderY = topY - borderPaddingY\n const borderWidthRaw = xScale.bandwidth() + borderPaddingX * 2\n const [rangeStart, rangeEnd] = xScale.range()\n const minX = Math.min(rangeStart, rangeEnd)\n const maxX = Math.max(rangeStart, rangeEnd)\n const borderX = Math.max(minX, borderXRaw)\n const borderRight = Math.min(maxX, borderXRaw + borderWidthRaw)\n const borderWidth = Math.max(0, borderRight - borderX)\n const borderHeight = Math.max(1, baselineY - topY + borderPaddingY * 2)\n\n if (borderWidth <= 0) {\n return null\n }\n\n return (\n <rect\n x={borderX}\n y={borderY}\n width={borderWidth}\n height={borderHeight}\n rx={6}\n fill=\"var(--spark-a2)\"\n stroke=\"var(--spark-a9)\"\n strokeWidth={2}\n pointerEvents=\"none\"\n style={{\n opacity: visible ? 1 : 0,\n transition: `x ${FOCUS_TRANSITION_MS}ms ease, y ${FOCUS_TRANSITION_MS}ms ease, width ${FOCUS_TRANSITION_MS}ms ease, height ${FOCUS_TRANSITION_MS}ms ease, opacity ${FOCUS_TRANSITION_MS}ms ease`,\n }}\n />\n )\n}\n\ninterface InteractionLayerProps {\n xDomain: BarChartCategory[]\n activeCategories: Set<BarChartCategory>\n xScale: ReturnType<typeof scaleBand<BarChartCategory>>\n height: number\n onHoverChange: (category: BarChartCategory | null) => void\n}\n\nfunction InteractionLayer({\n xDomain,\n activeCategories,\n xScale,\n height,\n onHoverChange,\n}: InteractionLayerProps) {\n const bandwidth = xScale.bandwidth()\n const [rangeStart, rangeEnd] = xScale.range()\n const minX = Math.min(rangeStart, rangeEnd)\n const maxX = Math.max(rangeStart, rangeEnd)\n\n // A single overlay that maps the pointer to the nearest category with data,\n // so there are no dead zones between/around bars to break the hover.\n const handleMove = (\n event: React.MouseEvent<SVGRectElement> | React.TouchEvent<SVGRectElement>,\n ) => {\n const point = localPoint(event)\n if (!point) return\n\n let nearest: BarChartCategory | null = null\n let best = Infinity\n for (const category of xDomain) {\n if (!activeCategories.has(category)) continue\n const x = xScale(category)\n if (x === undefined) continue\n const distance = Math.abs(x + bandwidth / 2 - point.x)\n if (distance < best) {\n best = distance\n nearest = category\n }\n }\n\n if (nearest !== null) onHoverChange(nearest)\n }\n\n return (\n <rect\n x={minX}\n y={PADDING_TOP}\n width={Math.max(0, maxX - minX)}\n height={height - PADDING_TOP - PADDING_BOTTOM}\n fill=\"transparent\"\n onMouseMove={handleMove}\n onMouseLeave={() => onHoverChange(null)}\n onTouchMove={handleMove}\n onTouchEnd={() => onHoverChange(null)}\n />\n )\n}\n\nfunction CategoryTicks({\n ticks,\n xScale,\n height,\n formatCategory,\n}: CategoryTicksProps) {\n return (\n <>\n {ticks.map((category) => {\n const x = xScale(category)\n\n if (x === undefined) {\n return null\n }\n\n return (\n <text\n key={`tick-${String(category)}`}\n x={x + xScale.bandwidth() / 2}\n y={height - PADDING_BOTTOM + 16}\n textAnchor=\"middle\"\n fill=\"var(--gray-a11)\"\n fontSize={10}\n >\n {formatCategory(category)}\n </text>\n )\n })}\n </>\n )\n}\n\nfunction defaultFormatTotal(value: number) {\n return defaultTotalFormat.format(value)\n}\n\nexport function BarChart<TDatum>({\n data,\n series,\n lines,\n getCategory,\n categories,\n categoryTicks,\n formatCategory = (category) => String(category),\n formatTooltipCategory = formatCategory,\n highlightedCategory,\n showHighlightLine = false,\n referenceLine,\n title,\n yAxisUnit,\n height = DEFAULT_HEIGHT,\n renderTotal,\n formatTotal = defaultFormatTotal,\n formatValue,\n className,\n}: BarChartProps<TDatum>): React.ReactElement {\n const containerRef = useRef<HTMLDivElement>(null)\n const [width, setWidth] = useState(0)\n const [hoveredCategory, setHoveredCategory] =\n useState<BarChartCategory | null>(null)\n const [trailingHoverLabel, setTrailingHoverLabel] = useState<string | null>(\n null,\n )\n const [hiddenSeries, setHiddenSeries] = useState<ReadonlySet<string>>(\n () =>\n new Set(\n (lines ?? [])\n .filter((line) => line.hiddenByDefault)\n .map((line) => line.key),\n ),\n )\n\n const toggleSeries = useCallback((id: string) => {\n setHiddenSeries((prev) => {\n const next = new Set(prev)\n if (next.has(id)) {\n next.delete(id)\n } else {\n next.add(id)\n }\n return next\n })\n }, [])\n\n useEffect(() => {\n const element = containerRef.current\n\n if (!element) {\n return\n }\n\n const resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0]\n\n if (!entry) {\n return\n }\n\n setWidth(entry.contentRect.width)\n })\n\n resizeObserver.observe(element)\n\n return () => {\n resizeObserver.disconnect()\n }\n }, [])\n\n const seriesByKey = useMemo(() => {\n const map = new Map<string, BarChartSeries<TDatum>>()\n\n for (const entry of series) {\n map.set(entry.key, entry)\n }\n\n return map\n }, [series])\n\n const stackData = useMemo<StackDatum[]>(\n () =>\n data.map((datum) => {\n const values: Record<string, number> = {}\n\n for (const entry of series) {\n values[entry.key] = hiddenSeries.has(entry.key)\n ? 0\n : entry.getValue(datum)\n }\n\n return { __category: getCategory(datum), __values: values }\n }),\n [data, getCategory, series, hiddenSeries],\n )\n\n const yMax = useMemo(\n () =>\n Math.max(\n 1,\n referenceLine?.value ?? 0,\n ...stackData.map((record) =>\n series.reduce(\n (sum, entry) => sum + (record.__values[entry.key] ?? 0),\n 0,\n ),\n ),\n ),\n [referenceLine, series, stackData],\n )\n\n const xDomain = useMemo(\n () => categories ?? stackData.map((record) => record.__category),\n [categories, stackData],\n )\n\n const xScale = useMemo(\n () =>\n scaleBand<BarChartCategory>({\n domain: xDomain,\n range: [Y_AXIS_GUTTER, Math.max(Y_AXIS_GUTTER, width)],\n padding: 0.32,\n }),\n [xDomain, width],\n )\n\n const yScale = useMemo(\n () =>\n scaleLinear<number>({\n domain: [0, yMax],\n range: [height - PADDING_BOTTOM, PADDING_TOP],\n }),\n [height, yMax],\n )\n\n const colorScale = useMemo(\n () =>\n scaleOrdinal<string, string>({\n domain: series.map((entry) => entry.key),\n range: series.map((entry) => entry.color),\n }),\n [series],\n )\n\n const linePaths = useMemo(() => {\n if (!lines || width === 0) {\n return []\n }\n\n return lines\n .filter((line) => !hiddenSeries.has(line.key))\n .map((line) => {\n const lineScale = line.domain\n ? scaleLinear<number>({\n domain: line.domain,\n range: [height - PADDING_BOTTOM, PADDING_TOP],\n })\n : yScale\n const segments: string[] = []\n let previous: { x: number; y: number } | null = null\n\n for (const datum of data) {\n const x = xScale(getCategory(datum))\n const value = line.getValue(datum)\n\n if (x === undefined || value === null || !Number.isFinite(value)) {\n previous = null\n continue\n }\n\n const point = {\n x: x + xScale.bandwidth() / 2,\n y: lineScale(value),\n }\n segments.push(\n previous === null\n ? `M ${point.x} ${point.y}`\n : `L ${point.x} ${point.y}`,\n )\n previous = point\n }\n\n return {\n key: line.key,\n d: segments.join(' '),\n color: line.color,\n strokeDasharray: line.strokeDasharray ?? '5 4',\n }\n })\n .filter((path) => path.d !== '')\n }, [lines, hiddenSeries, data, getCategory, xScale, yScale, height, width])\n\n const stackCategorySet = useMemo(\n () => new Set(stackData.map((record) => record.__category)),\n [stackData],\n )\n\n const lastFocusCategoryRef = useRef<BarChartCategory | null>(null)\n if (hoveredCategory !== null) {\n lastFocusCategoryRef.current = hoveredCategory\n }\n const focusCategory = lastFocusCategoryRef.current\n\n const focused = useMemo(\n () =>\n hoveredCategory === null\n ? null\n : (stackData.find((record) => record.__category === hoveredCategory) ??\n null),\n [hoveredCategory, stackData],\n )\n\n const totalValue = useMemo(() => {\n if (focused) {\n return series.reduce(\n (sum, entry) => sum + (focused.__values[entry.key] ?? 0),\n 0,\n )\n }\n\n return stackData.reduce(\n (sum, record) =>\n sum +\n series.reduce((s, entry) => s + (record.__values[entry.key] ?? 0), 0),\n 0,\n )\n }, [focused, series, stackData])\n\n const hoverLabel = focused ? formatTooltipCategory(focused.__category) : null\n\n useEffect(() => {\n if (hoverLabel) {\n setTrailingHoverLabel(hoverLabel)\n return\n }\n\n const timeoutId = window.setTimeout(() => {\n setTrailingHoverLabel(null)\n }, HOVER_FADE_MS)\n\n return () => {\n window.clearTimeout(timeoutId)\n }\n }, [hoverLabel])\n\n const ticks = categoryTicks ?? xDomain\n const yTicks = useMemo(() => buildYAxisTicks(yMax), [yMax])\n const highlightX = useMemo(() => {\n if (!showHighlightLine || highlightedCategory === undefined) {\n return null\n }\n\n const x = xScale(highlightedCategory)\n\n if (x === undefined) {\n return null\n }\n\n return x + xScale.bandwidth() / 2\n }, [highlightedCategory, showHighlightLine, xScale])\n\n const focusedDatum = useMemo(\n () =>\n hoveredCategory === null\n ? null\n : (data.find((datum) => getCategory(datum) === hoveredCategory) ??\n null),\n [hoveredCategory, data, getCategory],\n )\n\n const fmtTooltipValue = formatValue ?? formatTotal\n const tooltipRows: ChartTooltipRow[] = focused\n ? [\n ...series\n .filter((entry) => (focused.__values[entry.key] ?? 0) > 0)\n .map((entry) => ({\n key: entry.key,\n label: entry.label,\n color: entry.color,\n value: fmtTooltipValue(focused.__values[entry.key] ?? 0),\n })),\n ...(lines ?? [])\n .filter((line) => !hiddenSeries.has(line.key))\n .flatMap((line) => {\n const value =\n focusedDatum === null ? null : line.getValue(focusedDatum)\n\n if (value === null || !Number.isFinite(value)) {\n return []\n }\n\n return [\n {\n key: line.key,\n label: line.label,\n color: line.color,\n value: (line.formatValue ?? fmtTooltipValue)(value),\n },\n ]\n }),\n ]\n : []\n const tooltipActive = tooltipRows.length > 0\n const anchorX =\n focusCategory !== null\n ? (xScale(focusCategory) ?? 0) + xScale.bandwidth() / 2\n : 0\n const anchorY = yScale(totalValue)\n const [tooltipRef, tooltipSize] = useMeasuredSize<HTMLDivElement>()\n const tooltipPos = clampTooltipPosition({\n anchorX,\n anchorY,\n width,\n height,\n tipWidth: tooltipSize.width,\n tipHeight: tooltipSize.height,\n })\n\n return (\n <div className={cn('flex w-full flex-col', className)}>\n <div className=\"flex items-baseline justify-between\">\n {title && <SectionTitle>{title}</SectionTitle>}\n <span className=\"tabular-nums\">\n {renderTotal ? (\n renderTotal(totalValue)\n ) : (\n <span className=\"text-base font-bold text-gray tabular-nums\">\n {formatTotal(totalValue)}\n </span>\n )}\n </span>\n </div>\n\n <div className=\"flex min-h-5 items-baseline justify-between gap-4\">\n <SeriesLegend\n items={[\n ...series.map((entry) => ({\n id: entry.key,\n label: entry.label,\n color: entry.color,\n })),\n ...(lines ?? []).map((line) => ({\n id: line.key,\n label: line.label,\n color: line.color,\n marker: 'dashed-line' as const,\n })),\n ]}\n hiddenIds={hiddenSeries}\n onToggle={toggleSeries}\n className=\"gap-y-1\"\n />\n <span\n className={cn(\n 'text-xs text-gray-light transition-opacity duration-200',\n hoverLabel ? 'opacity-100' : 'opacity-0',\n )}\n >\n {trailingHoverLabel ?? ' '}\n </span>\n </div>\n\n <div\n ref={containerRef}\n className=\"relative mt-2 w-full\"\n style={{ height }}\n >\n <div\n ref={tooltipRef}\n className=\"pointer-events-none absolute z-10\"\n style={{\n left: tooltipPos.left,\n top: tooltipPos.top,\n opacity: tooltipActive ? 1 : 0,\n transition:\n 'left 140ms ease-out, top 140ms ease-out, opacity 140ms ease-out',\n }}\n >\n {focusCategory !== null && (\n <ChartTooltipCard\n label={formatTooltipCategory(focusCategory)}\n rows={tooltipRows}\n />\n )}\n </div>\n {width > 0 && (\n <svg width={width} height={height}>\n <line\n x1={Y_AXIS_GUTTER}\n x2={Y_AXIS_GUTTER}\n y1={PADDING_TOP}\n y2={yScale(0)}\n stroke=\"var(--gray-a6)\"\n strokeWidth={1}\n />\n\n {yTicks.map((tick, index) => {\n const y = yScale(tick)\n const hideTickLabel =\n yAxisUnit !== undefined && index === yTicks.length - 1\n\n return (\n <g key={`y-tick-${tick}`}>\n {!hideTickLabel && (\n <line\n x1={Y_AXIS_GUTTER - 4}\n x2={Y_AXIS_GUTTER}\n y1={y}\n y2={y}\n stroke=\"var(--gray-a8)\"\n strokeWidth={1}\n />\n )}\n {!hideTickLabel && (\n <text\n x={Y_AXIS_GUTTER - 7}\n y={y + 3}\n textAnchor=\"end\"\n fill=\"var(--gray-a11)\"\n fontSize={10}\n >\n {formatYAxisTick(tick)}\n </text>\n )}\n </g>\n )\n })}\n\n {yAxisUnit && (\n <text\n x={0}\n y={PADDING_TOP - 6}\n textAnchor=\"start\"\n fill=\"var(--gray-a11)\"\n fontSize={10}\n fontWeight={600}\n >\n {yAxisUnit}\n </text>\n )}\n\n {highlightX !== null && (\n <line\n x1={highlightX}\n x2={highlightX}\n y1={PADDING_TOP}\n y2={yScale(0)}\n stroke=\"var(--spark-a9)\"\n strokeWidth={1.5}\n strokeDasharray=\"5 4\"\n pointerEvents=\"none\"\n />\n )}\n\n <line\n x1={Y_AXIS_GUTTER}\n x2={width}\n y1={yScale(0)}\n y2={yScale(0)}\n stroke=\"var(--gray-a5)\"\n strokeWidth={1}\n />\n\n <Group>\n {focusCategory !== null && (\n <FocusBorder\n category={focusCategory}\n visible={hoveredCategory !== null}\n stackData={stackData}\n series={series}\n xScale={xScale}\n yScale={yScale}\n />\n )}\n <BarStackLayer\n stackData={stackData}\n series={series}\n seriesByKey={seriesByKey}\n xScale={xScale}\n yScale={yScale}\n colorScale={colorScale}\n />\n\n {referenceLine && (\n <line\n x1={Y_AXIS_GUTTER}\n x2={width}\n y1={yScale(referenceLine.value)}\n y2={yScale(referenceLine.value)}\n stroke={referenceLine.color ?? 'var(--gray-a11)'}\n strokeWidth={1.5}\n pointerEvents=\"none\"\n />\n )}\n\n {linePaths.map((path) => (\n <path\n key={`line-${path.key}`}\n d={path.d}\n fill=\"none\"\n stroke={path.color}\n strokeWidth={1.5}\n strokeDasharray={path.strokeDasharray}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n pointerEvents=\"none\"\n />\n ))}\n </Group>\n\n <InteractionLayer\n xDomain={xDomain}\n activeCategories={stackCategorySet}\n xScale={xScale}\n height={height}\n onHoverChange={setHoveredCategory}\n />\n\n <CategoryTicks\n ticks={ticks}\n xScale={xScale}\n height={height}\n formatCategory={formatCategory}\n />\n </svg>\n )}\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"bar-chart.cjs","names":["localeNumberFormat","BarStack","useReducedMotion","buildYAxisScale","useMeasuredSize","clampTooltipPosition","SectionTitle","SeriesLegend","ChartTooltipCard","formatYAxisTick","Group"],"sources":["../../src/components/bar-chart.tsx"],"sourcesContent":["import { localPoint } from '@visx/event'\nimport { Group } from '@visx/group'\nimport { scaleBand, scaleLinear, scaleOrdinal } from '@visx/scale'\nimport { BarStack } from '@visx/shape'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { useReducedMotion } from '../hooks/use-reduced-motion'\nimport { buildYAxisScale, formatYAxisTick } from '../utils/chart-scale'\nimport { cn } from '../utils/cn'\nimport { localeNumberFormat } from '../utils/format'\nimport {\n ChartTooltipCard,\n type ChartTooltipRow,\n clampTooltipPosition,\n useMeasuredSize,\n} from './chart'\nimport { SeriesLegend } from './series-legend'\nimport { SectionTitle } from './typography'\n\nconst defaultTotalFormat = localeNumberFormat()\n\nexport type BarChartCategory = string | number\n\nexport interface BarChartSeries<TDatum> {\n key: string\n label: string\n color: string\n hoverFill?: string\n getValue: (datum: TDatum) => number\n}\n\nexport interface BarChartLineSeries<TDatum> {\n key: string\n label: string\n color: string\n /** `null` gaps break the line (e.g. hours without a reading). */\n getValue: (datum: TDatum) => number | null\n /** Own y-domain for this line (e.g. `[0, 100]` for a percentage). Defaults to the bar scale. */\n domain?: [number, number]\n /** Start hidden; the user can enable the line from the legend. */\n hiddenByDefault?: boolean\n /** Formats this line's value in the hover tooltip. Defaults to `formatValue`. */\n formatValue?: (value: number) => string\n strokeDasharray?: string\n}\n\nexport interface BarChartProps<TDatum> {\n data: TDatum[]\n series: BarChartSeries<TDatum>[]\n /** Line overlays drawn on top of the bars, toggleable from the legend. */\n lines?: BarChartLineSeries<TDatum>[]\n getCategory: (datum: TDatum) => BarChartCategory\n /** Full ordered set of categories on the x-axis. Defaults to `data.map(getCategory)`. */\n categories?: BarChartCategory[]\n /** Subset of categories that should render an x-axis label. Defaults to every category. */\n categoryTicks?: BarChartCategory[]\n formatCategory?: (category: BarChartCategory) => string\n /** Formats the hovered category in the tooltip header. Defaults to `formatCategory`. */\n formatTooltipCategory?: (category: BarChartCategory) => string\n highlightedCategory?: BarChartCategory\n showHighlightLine?: boolean\n /**\n * Horizontal reference line drawn across the plot at a given y-value.\n * Useful for thresholds (e.g. price ceiling).\n */\n referenceLine?: { value: number; label?: string; color?: string }\n title?: string\n yAxisUnit?: string\n height?: number\n /**\n * Override how the total value (sum of focused or all categories) is\n * rendered. `animated` is false while a bar is focused (hover), so an\n * animated total can snap between hovered buckets instead of re-firing a\n * tween on every bar the pointer crosses.\n */\n renderTotal?: (value: number, animated: boolean) => React.ReactNode\n /** Format function used when `renderTotal` is not provided. */\n formatTotal?: (value: number) => string\n /** Formats per-series values in the hover tooltip. Defaults to `formatTotal`. */\n formatValue?: (value: number) => string\n className?: string\n}\n\ninterface StackDatum {\n __category: BarChartCategory\n __values: Record<string, number>\n}\n\ninterface BarStackLayerProps<TDatum> {\n stackData: StackDatum[]\n series: BarChartSeries<TDatum>[]\n seriesByKey: Map<string, BarChartSeries<TDatum>>\n xScale: ReturnType<typeof scaleBand<BarChartCategory>>\n yScale: ReturnType<typeof scaleLinear<number>>\n colorScale: ReturnType<typeof scaleOrdinal<string, string>>\n}\n\ninterface CategoryTicksProps {\n ticks: BarChartCategory[]\n xScale: ReturnType<typeof scaleBand<BarChartCategory>>\n height: number\n formatCategory: (category: BarChartCategory) => string\n}\n\nconst PADDING_TOP = 20\nconst PADDING_BOTTOM = 28\nconst HOVER_FADE_MS = 200\nconst FOCUS_TRANSITION_MS = 180\nconst DEFAULT_HEIGHT = 220\nconst BAR_RADIUS = 2\nconst Y_AXIS_GUTTER = 34\n\nfunction buildBarPath(\n x: number,\n y: number,\n width: number,\n height: number,\n radius: number,\n roundTop: boolean,\n roundBottom: boolean,\n) {\n const r = Math.max(0, Math.min(radius, width / 2, height / 2))\n\n if (r === 0 || (!roundTop && !roundBottom)) {\n return `M ${x} ${y} H ${x + width} V ${y + height} H ${x} Z`\n }\n\n const tl = roundTop ? r : 0\n const tr = roundTop ? r : 0\n const br = roundBottom ? r : 0\n const bl = roundBottom ? r : 0\n\n return [\n `M ${x + tl} ${y}`,\n `H ${x + width - tr}`,\n tr > 0\n ? `Q ${x + width} ${y} ${x + width} ${y + tr}`\n : `L ${x + width} ${y}`,\n `V ${y + height - br}`,\n br > 0\n ? `Q ${x + width} ${y + height} ${x + width - br} ${y + height}`\n : `L ${x + width} ${y + height}`,\n `H ${x + bl}`,\n bl > 0\n ? `Q ${x} ${y + height} ${x} ${y + height - bl}`\n : `L ${x} ${y + height}`,\n `V ${y + tl}`,\n tl > 0 ? `Q ${x} ${y} ${x + tl} ${y}` : `L ${x} ${y}`,\n 'Z',\n ].join(' ')\n}\n\nfunction BarStackLayer<TDatum>({\n stackData,\n series,\n seriesByKey,\n xScale,\n yScale,\n colorScale,\n}: BarStackLayerProps<TDatum>) {\n return (\n <BarStack<StackDatum, string>\n data={stackData}\n keys={series.map((entry) => entry.key)}\n x={(record) => record.__category}\n value={(record, key) => record.__values[key] ?? 0}\n xScale={xScale}\n yScale={yScale}\n color={colorScale}\n offset=\"diverging\"\n >\n {(barStacks) =>\n barStacks.map((barStack) =>\n barStack.bars.map((bar) => {\n const values = bar.bar.data.__values\n const segmentValue = values[barStack.key] ?? 0\n\n if (segmentValue === 0) {\n return null\n }\n\n const seriesEntry = seriesByKey.get(barStack.key)\n const strokeColor = seriesEntry?.color ?? bar.color\n const fillColor = strokeColor\n\n // Positive segments stack up from the baseline, negatives down.\n // Round only the outermost corner of each side of the axis.\n const positiveKeys = series\n .map((entry) => entry.key)\n .filter((key) => (values[key] ?? 0) > 0)\n const negativeKeys = series\n .map((entry) => entry.key)\n .filter((key) => (values[key] ?? 0) < 0)\n const roundTop =\n segmentValue > 0 &&\n positiveKeys[positiveKeys.length - 1] === barStack.key\n const roundBottom =\n segmentValue > 0\n ? positiveKeys[0] === barStack.key\n : negativeKeys[negativeKeys.length - 1] === barStack.key\n\n // visx returns a signed height for below-baseline bars; normalize\n // to a top-left origin with a positive height for the path.\n const top = bar.height < 0 ? bar.y + bar.height : bar.y\n const barHeight = Math.abs(bar.height)\n\n return (\n <path\n key={`bar-${barStack.index}-${bar.index}`}\n d={buildBarPath(\n bar.x,\n top,\n bar.width,\n Math.max(0, barHeight),\n BAR_RADIUS,\n roundTop,\n roundBottom,\n )}\n fill={fillColor}\n stroke={strokeColor}\n strokeWidth={1}\n style={{ transition: 'fill 180ms ease' }}\n />\n )\n }),\n )\n }\n </BarStack>\n )\n}\n\ninterface FocusBorderProps<TDatum> {\n category: BarChartCategory\n visible: boolean\n stackData: StackDatum[]\n series: BarChartSeries<TDatum>[]\n xScale: ReturnType<typeof scaleBand<BarChartCategory>>\n yScale: ReturnType<typeof scaleLinear<number>>\n}\n\nfunction FocusBorder<TDatum>({\n category,\n visible,\n stackData,\n series,\n xScale,\n yScale,\n}: FocusBorderProps<TDatum>) {\n const reducedMotion = useReducedMotion()\n const x = xScale(category)\n const datum = stackData.find((entry) => entry.__category === category)\n\n if (x === undefined || !datum) {\n return null\n }\n\n const hasAnyValue = series.some(\n (entry) => (datum.__values[entry.key] ?? 0) !== 0,\n )\n\n if (!hasAnyValue) {\n return null\n }\n\n const topY = PADDING_TOP\n // Extend past the baseline to cover any below-axis (feed-in) segment.\n const negativeSum = series.reduce(\n (sum, entry) => sum + Math.min(0, datum.__values[entry.key] ?? 0),\n 0,\n )\n const bottomY = yScale(negativeSum)\n const borderPaddingX = 4\n const borderPaddingY = 3\n const borderXRaw = x - borderPaddingX\n const borderY = topY - borderPaddingY\n const borderWidthRaw = xScale.bandwidth() + borderPaddingX * 2\n const [rangeStart, rangeEnd] = xScale.range()\n const minX = Math.min(rangeStart, rangeEnd)\n const maxX = Math.max(rangeStart, rangeEnd)\n const borderX = Math.max(minX, borderXRaw)\n const borderRight = Math.min(maxX, borderXRaw + borderWidthRaw)\n const borderWidth = Math.max(0, borderRight - borderX)\n const borderHeight = Math.max(1, bottomY - topY + borderPaddingY * 2)\n\n if (borderWidth <= 0) {\n return null\n }\n\n return (\n <rect\n x={borderX}\n y={borderY}\n width={borderWidth}\n height={borderHeight}\n rx={6}\n fill=\"var(--spark-a2)\"\n stroke=\"var(--spark-a9)\"\n strokeWidth={2}\n pointerEvents=\"none\"\n style={{\n opacity: visible ? 1 : 0,\n transition: reducedMotion\n ? `opacity ${FOCUS_TRANSITION_MS}ms ease`\n : `x ${FOCUS_TRANSITION_MS}ms ease, y ${FOCUS_TRANSITION_MS}ms ease, width ${FOCUS_TRANSITION_MS}ms ease, height ${FOCUS_TRANSITION_MS}ms ease, opacity ${FOCUS_TRANSITION_MS}ms ease`,\n }}\n />\n )\n}\n\ninterface InteractionLayerProps {\n xDomain: BarChartCategory[]\n activeCategories: Set<BarChartCategory>\n xScale: ReturnType<typeof scaleBand<BarChartCategory>>\n height: number\n onHoverChange: (category: BarChartCategory | null) => void\n}\n\nfunction InteractionLayer({\n xDomain,\n activeCategories,\n xScale,\n height,\n onHoverChange,\n}: InteractionLayerProps) {\n const bandwidth = xScale.bandwidth()\n const [rangeStart, rangeEnd] = xScale.range()\n const minX = Math.min(rangeStart, rangeEnd)\n const maxX = Math.max(rangeStart, rangeEnd)\n\n // A single overlay that maps the pointer to the nearest category with data,\n // so there are no dead zones between/around bars to break the hover.\n const handleMove = (\n event: React.MouseEvent<SVGRectElement> | React.TouchEvent<SVGRectElement>,\n ) => {\n const point = localPoint(event)\n if (!point) return\n\n let nearest: BarChartCategory | null = null\n let best = Infinity\n for (const category of xDomain) {\n if (!activeCategories.has(category)) continue\n const x = xScale(category)\n if (x === undefined) continue\n const distance = Math.abs(x + bandwidth / 2 - point.x)\n if (distance < best) {\n best = distance\n nearest = category\n }\n }\n\n if (nearest !== null) onHoverChange(nearest)\n }\n\n return (\n <rect\n x={minX}\n y={PADDING_TOP}\n width={Math.max(0, maxX - minX)}\n height={height - PADDING_TOP - PADDING_BOTTOM}\n fill=\"transparent\"\n onMouseMove={handleMove}\n onMouseLeave={() => onHoverChange(null)}\n onTouchMove={handleMove}\n onTouchEnd={() => onHoverChange(null)}\n />\n )\n}\n\nfunction CategoryTicks({\n ticks,\n xScale,\n height,\n formatCategory,\n}: CategoryTicksProps) {\n return (\n <>\n {ticks.map((category) => {\n const x = xScale(category)\n\n if (x === undefined) {\n return null\n }\n\n return (\n <text\n key={`tick-${String(category)}`}\n x={x + xScale.bandwidth() / 2}\n y={height - PADDING_BOTTOM + 16}\n textAnchor=\"middle\"\n fill=\"var(--neutral-a11)\"\n fontSize={10}\n >\n {formatCategory(category)}\n </text>\n )\n })}\n </>\n )\n}\n\nfunction defaultFormatTotal(value: number) {\n return defaultTotalFormat.format(value)\n}\n\nexport function BarChart<TDatum>({\n data,\n series,\n lines,\n getCategory,\n categories,\n categoryTicks,\n formatCategory = (category) => String(category),\n formatTooltipCategory = formatCategory,\n highlightedCategory,\n showHighlightLine = false,\n referenceLine,\n title,\n yAxisUnit,\n height = DEFAULT_HEIGHT,\n renderTotal,\n formatTotal = defaultFormatTotal,\n formatValue,\n className,\n}: BarChartProps<TDatum>): React.ReactElement {\n const containerRef = useRef<HTMLDivElement>(null)\n const reducedMotion = useReducedMotion()\n const [width, setWidth] = useState(0)\n const [hoveredCategory, setHoveredCategory] =\n useState<BarChartCategory | null>(null)\n const [trailingHoverLabel, setTrailingHoverLabel] = useState<string | null>(\n null,\n )\n const [hiddenSeries, setHiddenSeries] = useState<ReadonlySet<string>>(\n () =>\n new Set(\n (lines ?? [])\n .filter((line) => line.hiddenByDefault)\n .map((line) => line.key),\n ),\n )\n\n const toggleSeries = useCallback((id: string) => {\n setHiddenSeries((prev) => {\n const next = new Set(prev)\n if (next.has(id)) {\n next.delete(id)\n } else {\n next.add(id)\n }\n return next\n })\n }, [])\n\n useEffect(() => {\n const element = containerRef.current\n\n if (!element) {\n return\n }\n\n const resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0]\n\n if (!entry) {\n return\n }\n\n setWidth(entry.contentRect.width)\n })\n\n resizeObserver.observe(element)\n\n return () => {\n resizeObserver.disconnect()\n }\n }, [])\n\n const seriesByKey = useMemo(() => {\n const map = new Map<string, BarChartSeries<TDatum>>()\n\n for (const entry of series) {\n map.set(entry.key, entry)\n }\n\n return map\n }, [series])\n\n const stackData = useMemo<StackDatum[]>(\n () =>\n data.map((datum) => {\n const values: Record<string, number> = {}\n\n for (const entry of series) {\n values[entry.key] = hiddenSeries.has(entry.key)\n ? 0\n : entry.getValue(datum)\n }\n\n return { __category: getCategory(datum), __values: values }\n }),\n [data, getCategory, series, hiddenSeries],\n )\n\n const yMax = useMemo(\n () =>\n Math.max(\n 1,\n referenceLine?.value ?? 0,\n ...stackData.map((record) =>\n series.reduce(\n (sum, entry) => sum + Math.max(0, record.__values[entry.key] ?? 0),\n 0,\n ),\n ),\n ),\n [referenceLine, series, stackData],\n )\n\n // Most negative stack sum across buckets (0 when nothing dips below the axis).\n const yMin = useMemo(\n () =>\n Math.min(\n 0,\n ...stackData.map((record) =>\n series.reduce(\n (sum, entry) => sum + Math.min(0, record.__values[entry.key] ?? 0),\n 0,\n ),\n ),\n ),\n [series, stackData],\n )\n\n const xDomain = useMemo(\n () => categories ?? stackData.map((record) => record.__category),\n [categories, stackData],\n )\n\n const xScale = useMemo(\n () =>\n scaleBand<BarChartCategory>({\n domain: xDomain,\n range: [Y_AXIS_GUTTER, Math.max(Y_AXIS_GUTTER, width)],\n padding: 0.32,\n }),\n [xDomain, width],\n )\n\n const yScale = useMemo(\n () =>\n scaleLinear<number>({\n domain: [yMin, yMax],\n range: [height - PADDING_BOTTOM, PADDING_TOP],\n }),\n [height, yMax, yMin],\n )\n\n const colorScale = useMemo(\n () =>\n scaleOrdinal<string, string>({\n domain: series.map((entry) => entry.key),\n range: series.map((entry) => entry.color),\n }),\n [series],\n )\n\n const linePaths = useMemo(() => {\n if (!lines || width === 0) {\n return []\n }\n\n return lines\n .filter((line) => !hiddenSeries.has(line.key))\n .map((line) => {\n const lineScale = line.domain\n ? scaleLinear<number>({\n domain: line.domain,\n range: [height - PADDING_BOTTOM, PADDING_TOP],\n })\n : yScale\n const segments: string[] = []\n let previous: { x: number; y: number } | null = null\n\n for (const datum of data) {\n const x = xScale(getCategory(datum))\n const value = line.getValue(datum)\n\n if (x === undefined || value === null || !Number.isFinite(value)) {\n previous = null\n continue\n }\n\n const point = {\n x: x + xScale.bandwidth() / 2,\n y: lineScale(value),\n }\n segments.push(\n previous === null\n ? `M ${point.x} ${point.y}`\n : `L ${point.x} ${point.y}`,\n )\n previous = point\n }\n\n return {\n key: line.key,\n d: segments.join(' '),\n color: line.color,\n strokeDasharray: line.strokeDasharray ?? '5 4',\n }\n })\n .filter((path) => path.d !== '')\n }, [lines, hiddenSeries, data, getCategory, xScale, yScale, height, width])\n\n const stackCategorySet = useMemo(\n () => new Set(stackData.map((record) => record.__category)),\n [stackData],\n )\n\n const lastFocusCategoryRef = useRef<BarChartCategory | null>(null)\n if (hoveredCategory !== null) {\n lastFocusCategoryRef.current = hoveredCategory\n }\n const focusCategory = lastFocusCategoryRef.current\n\n const focused = useMemo(\n () =>\n hoveredCategory === null\n ? null\n : (stackData.find((record) => record.__category === hoveredCategory) ??\n null),\n [hoveredCategory, stackData],\n )\n\n // Below-baseline segments (feed-in) are context, not part of the headline\n // sum, so the total counts only the positive stack (energy consumed).\n const totalValue = useMemo(() => {\n if (focused) {\n return series.reduce(\n (sum, entry) => sum + Math.max(0, focused.__values[entry.key] ?? 0),\n 0,\n )\n }\n\n return stackData.reduce(\n (sum, record) =>\n sum +\n series.reduce(\n (s, entry) => s + Math.max(0, record.__values[entry.key] ?? 0),\n 0,\n ),\n 0,\n )\n }, [focused, series, stackData])\n\n const hoverLabel = focused ? formatTooltipCategory(focused.__category) : null\n\n useEffect(() => {\n if (hoverLabel) {\n setTrailingHoverLabel(hoverLabel)\n return\n }\n\n const timeoutId = window.setTimeout(() => {\n setTrailingHoverLabel(null)\n }, HOVER_FADE_MS)\n\n return () => {\n window.clearTimeout(timeoutId)\n }\n }, [hoverLabel])\n\n const ticks = categoryTicks ?? xDomain\n const yTicks = useMemo(() => buildYAxisScale(yMin, yMax).ticks, [yMin, yMax])\n const highlightX = useMemo(() => {\n if (!showHighlightLine || highlightedCategory === undefined) {\n return null\n }\n\n const x = xScale(highlightedCategory)\n\n if (x === undefined) {\n return null\n }\n\n return x + xScale.bandwidth() / 2\n }, [highlightedCategory, showHighlightLine, xScale])\n\n const focusedDatum = useMemo(\n () =>\n hoveredCategory === null\n ? null\n : (data.find((datum) => getCategory(datum) === hoveredCategory) ??\n null),\n [hoveredCategory, data, getCategory],\n )\n\n // The bars don't depend on hover state, so memoize the layer: hovering\n // across bars must not re-render (and re-stack) every bar path each move.\n const barStackLayer = useMemo(\n () => (\n <BarStackLayer\n stackData={stackData}\n series={series}\n seriesByKey={seriesByKey}\n xScale={xScale}\n yScale={yScale}\n colorScale={colorScale}\n />\n ),\n [stackData, series, seriesByKey, xScale, yScale, colorScale],\n )\n\n const fmtTooltipValue = formatValue ?? formatTotal\n const tooltipRows: ChartTooltipRow[] = focused\n ? [\n ...series\n .filter((entry) => (focused.__values[entry.key] ?? 0) !== 0)\n .map((entry) => ({\n key: entry.key,\n label: entry.label,\n color: entry.color,\n value: fmtTooltipValue(Math.abs(focused.__values[entry.key] ?? 0)),\n })),\n ...(lines ?? [])\n .filter((line) => !hiddenSeries.has(line.key))\n .flatMap((line) => {\n const value =\n focusedDatum === null ? null : line.getValue(focusedDatum)\n\n if (value === null || !Number.isFinite(value)) {\n return []\n }\n\n return [\n {\n key: line.key,\n label: line.label,\n color: line.color,\n value: (line.formatValue ?? fmtTooltipValue)(value),\n },\n ]\n }),\n ]\n : []\n const tooltipActive = tooltipRows.length > 0\n const anchorX =\n focusCategory !== null\n ? (xScale(focusCategory) ?? 0) + xScale.bandwidth() / 2\n : 0\n const anchorY = yScale(totalValue)\n const [tooltipRef, tooltipSize] = useMeasuredSize<HTMLDivElement>()\n const tooltipPos = clampTooltipPosition({\n anchorX,\n anchorY,\n width,\n height,\n tipWidth: tooltipSize.width,\n tipHeight: tooltipSize.height,\n })\n\n return (\n <div className={cn('flex w-full flex-col', className)}>\n <div className=\"flex items-baseline justify-between\">\n {title && <SectionTitle>{title}</SectionTitle>}\n <span className=\"tabular-nums\">\n {renderTotal ? (\n renderTotal(totalValue, focused === null)\n ) : (\n <span className=\"text-base font-bold text-gray tabular-nums\">\n {formatTotal(totalValue)}\n </span>\n )}\n </span>\n </div>\n\n <div className=\"flex min-h-5 items-baseline justify-between gap-4\">\n <SeriesLegend\n items={[\n ...series.map((entry) => ({\n id: entry.key,\n label: entry.label,\n color: entry.color,\n })),\n ...(lines ?? []).map((line) => ({\n id: line.key,\n label: line.label,\n color: line.color,\n marker: 'dashed-line' as const,\n })),\n ]}\n hiddenIds={hiddenSeries}\n onToggle={toggleSeries}\n className=\"gap-y-1\"\n />\n <span\n className={cn(\n 'text-xs text-gray-light transition-opacity duration-200',\n hoverLabel ? 'opacity-100' : 'opacity-0',\n )}\n >\n {trailingHoverLabel ?? ' '}\n </span>\n </div>\n\n <div\n ref={containerRef}\n className=\"relative mt-2 w-full\"\n style={{ height }}\n >\n <div\n ref={tooltipRef}\n className=\"pointer-events-none absolute z-10\"\n style={{\n left: tooltipPos.left,\n top: tooltipPos.top,\n opacity: tooltipActive ? 1 : 0,\n transition: reducedMotion\n ? 'opacity 140ms ease-out'\n : 'left 140ms ease-out, top 140ms ease-out, opacity 140ms ease-out',\n }}\n >\n {focusCategory !== null && (\n <ChartTooltipCard\n label={formatTooltipCategory(focusCategory)}\n rows={tooltipRows}\n />\n )}\n </div>\n {width > 0 && (\n <svg width={width} height={height}>\n <line\n x1={Y_AXIS_GUTTER}\n x2={Y_AXIS_GUTTER}\n y1={PADDING_TOP}\n y2={height - PADDING_BOTTOM}\n stroke=\"var(--neutral-a6)\"\n strokeWidth={1}\n />\n\n {yTicks.map((tick, index) => {\n const y = yScale(tick)\n const hideTickLabel =\n yAxisUnit !== undefined && index === yTicks.length - 1\n\n return (\n <g key={`y-tick-${tick}`}>\n {!hideTickLabel && (\n <line\n x1={Y_AXIS_GUTTER - 4}\n x2={Y_AXIS_GUTTER}\n y1={y}\n y2={y}\n stroke=\"var(--neutral-a8)\"\n strokeWidth={1}\n />\n )}\n {!hideTickLabel && (\n <text\n x={Y_AXIS_GUTTER - 7}\n y={y + 3}\n textAnchor=\"end\"\n fill=\"var(--neutral-a11)\"\n fontSize={10}\n >\n {formatYAxisTick(tick)}\n </text>\n )}\n </g>\n )\n })}\n\n {yAxisUnit && (\n <text\n x={0}\n y={PADDING_TOP - 6}\n textAnchor=\"start\"\n fill=\"var(--neutral-a11)\"\n fontSize={10}\n fontWeight={600}\n >\n {yAxisUnit}\n </text>\n )}\n\n {highlightX !== null && (\n <line\n x1={highlightX}\n x2={highlightX}\n y1={PADDING_TOP}\n y2={height - PADDING_BOTTOM}\n stroke=\"var(--spark-a9)\"\n strokeWidth={1.5}\n strokeDasharray=\"5 4\"\n pointerEvents=\"none\"\n />\n )}\n\n <line\n x1={Y_AXIS_GUTTER}\n x2={width}\n y1={yScale(0)}\n y2={yScale(0)}\n stroke=\"var(--neutral-a5)\"\n strokeWidth={1}\n />\n\n <Group>\n {focusCategory !== null && (\n <FocusBorder\n category={focusCategory}\n visible={hoveredCategory !== null}\n stackData={stackData}\n series={series}\n xScale={xScale}\n yScale={yScale}\n />\n )}\n {barStackLayer}\n\n {referenceLine && (\n <line\n x1={Y_AXIS_GUTTER}\n x2={width}\n y1={yScale(referenceLine.value)}\n y2={yScale(referenceLine.value)}\n stroke={referenceLine.color ?? 'var(--neutral-a11)'}\n strokeWidth={1.5}\n pointerEvents=\"none\"\n />\n )}\n\n {linePaths.map((path) => (\n <path\n key={`line-${path.key}`}\n d={path.d}\n fill=\"none\"\n stroke={path.color}\n strokeWidth={1.5}\n strokeDasharray={path.strokeDasharray}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n pointerEvents=\"none\"\n />\n ))}\n </Group>\n\n <InteractionLayer\n xDomain={xDomain}\n activeCategories={stackCategorySet}\n xScale={xScale}\n height={height}\n onHoverChange={setHoveredCategory}\n />\n\n <CategoryTicks\n ticks={ticks}\n xScale={xScale}\n height={height}\n formatCategory={formatCategory}\n />\n </svg>\n )}\n </div>\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAkBA,MAAM,qBAAqBA,qBAAAA,oBAAoB;AAqF/C,MAAM,cAAc;AACpB,MAAM,iBAAiB;AACvB,MAAM,gBAAgB;AACtB,MAAM,sBAAsB;AAC5B,MAAM,iBAAiB;AACvB,MAAM,aAAa;AACnB,MAAM,gBAAgB;AAEtB,SAAS,aACP,GACA,GACA,OACA,QACA,QACA,UACA,aACA;CACA,MAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,QAAQ,GAAG,SAAS,EAAE,CAAC;AAE9D,KAAI,MAAM,KAAM,CAAC,YAAY,CAAC,YAC5B,QAAO,KAAK,EAAE,GAAG,EAAE,KAAK,IAAI,MAAM,KAAK,IAAI,OAAO,KAAK,EAAE;CAG3D,MAAM,KAAK,WAAW,IAAI;CAC1B,MAAM,KAAK,WAAW,IAAI;CAC1B,MAAM,KAAK,cAAc,IAAI;CAC7B,MAAM,KAAK,cAAc,IAAI;AAE7B,QAAO;EACL,KAAK,IAAI,GAAG,GAAG;EACf,KAAK,IAAI,QAAQ;EACjB,KAAK,IACD,KAAK,IAAI,MAAM,GAAG,EAAE,GAAG,IAAI,MAAM,GAAG,IAAI,OACxC,KAAK,IAAI,MAAM,GAAG;EACtB,KAAK,IAAI,SAAS;EAClB,KAAK,IACD,KAAK,IAAI,MAAM,GAAG,IAAI,OAAO,GAAG,IAAI,QAAQ,GAAG,GAAG,IAAI,WACtD,KAAK,IAAI,MAAM,GAAG,IAAI;EAC1B,KAAK,IAAI;EACT,KAAK,IACD,KAAK,EAAE,GAAG,IAAI,OAAO,GAAG,EAAE,GAAG,IAAI,SAAS,OAC1C,KAAK,EAAE,GAAG,IAAI;EAClB,KAAK,IAAI;EACT,KAAK,IAAI,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,GAAG,GAAG,MAAM,KAAK,EAAE,GAAG;EAClD;EACD,CAAC,KAAK,IAAI;;AAGb,SAAS,cAAsB,EAC7B,WACA,QACA,aACA,QACA,QACA,cAC6B;AAC7B,QACE,iBAAA,GAAA,kBAAA,KAACC,YAAAA,UAAD;EACE,MAAM;EACN,MAAM,OAAO,KAAK,UAAU,MAAM,IAAI;EACtC,IAAI,WAAW,OAAO;EACtB,QAAQ,QAAQ,QAAQ,OAAO,SAAS,QAAQ;EACxC;EACA;EACR,OAAO;EACP,QAAO;aAEL,cACA,UAAU,KAAK,aACb,SAAS,KAAK,KAAK,QAAQ;GACzB,MAAM,SAAS,IAAI,IAAI,KAAK;GAC5B,MAAM,eAAe,OAAO,SAAS,QAAQ;AAE7C,OAAI,iBAAiB,EACnB,QAAO;GAIT,MAAM,cADc,YAAY,IAAI,SAAS,IACd,EAAE,SAAS,IAAI;GAC9C,MAAM,YAAY;GAIlB,MAAM,eAAe,OAClB,KAAK,UAAU,MAAM,IAAI,CACzB,QAAQ,SAAS,OAAO,QAAQ,KAAK,EAAE;GAC1C,MAAM,eAAe,OAClB,KAAK,UAAU,MAAM,IAAI,CACzB,QAAQ,SAAS,OAAO,QAAQ,KAAK,EAAE;GAC1C,MAAM,WACJ,eAAe,KACf,aAAa,aAAa,SAAS,OAAO,SAAS;GACrD,MAAM,cACJ,eAAe,IACX,aAAa,OAAO,SAAS,MAC7B,aAAa,aAAa,SAAS,OAAO,SAAS;GAIzD,MAAM,MAAM,IAAI,SAAS,IAAI,IAAI,IAAI,IAAI,SAAS,IAAI;GACtD,MAAM,YAAY,KAAK,IAAI,IAAI,OAAO;AAEtC,UACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;IAEE,GAAG,aACD,IAAI,GACJ,KACA,IAAI,OACJ,KAAK,IAAI,GAAG,UAAU,EACtB,YACA,UACA,YACD;IACD,MAAM;IACN,QAAQ;IACR,aAAa;IACb,OAAO,EAAE,YAAY,mBAAmB;IACxC,EAdK,OAAO,SAAS,MAAM,GAAG,IAAI,QAclC;IAEJ,CACH;EAEM,CAAA;;AAaf,SAAS,YAAoB,EAC3B,UACA,SACA,WACA,QACA,QACA,UAC2B;CAC3B,MAAM,gBAAgBC,iCAAAA,kBAAkB;CACxC,MAAM,IAAI,OAAO,SAAS;CAC1B,MAAM,QAAQ,UAAU,MAAM,UAAU,MAAM,eAAe,SAAS;AAEtE,KAAI,MAAM,KAAA,KAAa,CAAC,MACtB,QAAO;AAOT,KAAI,CAJgB,OAAO,MACxB,WAAW,MAAM,SAAS,MAAM,QAAQ,OAAO,EAGlC,CACd,QAAO;CAGT,MAAM,OAAO;CAMb,MAAM,UAAU,OAJI,OAAO,QACxB,KAAK,UAAU,MAAM,KAAK,IAAI,GAAG,MAAM,SAAS,MAAM,QAAQ,EAAE,EACjE,EAEgC,CAAC;CACnC,MAAM,iBAAiB;CACvB,MAAM,iBAAiB;CACvB,MAAM,aAAa,IAAI;CACvB,MAAM,UAAU,OAAO;CACvB,MAAM,iBAAiB,OAAO,WAAW,GAAG,iBAAiB;CAC7D,MAAM,CAAC,YAAY,YAAY,OAAO,OAAO;CAC7C,MAAM,OAAO,KAAK,IAAI,YAAY,SAAS;CAC3C,MAAM,OAAO,KAAK,IAAI,YAAY,SAAS;CAC3C,MAAM,UAAU,KAAK,IAAI,MAAM,WAAW;CAC1C,MAAM,cAAc,KAAK,IAAI,MAAM,aAAa,eAAe;CAC/D,MAAM,cAAc,KAAK,IAAI,GAAG,cAAc,QAAQ;CACtD,MAAM,eAAe,KAAK,IAAI,GAAG,UAAU,OAAO,iBAAiB,EAAE;AAErE,KAAI,eAAe,EACjB,QAAO;AAGT,QACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;EACE,GAAG;EACH,GAAG;EACH,OAAO;EACP,QAAQ;EACR,IAAI;EACJ,MAAK;EACL,QAAO;EACP,aAAa;EACb,eAAc;EACd,OAAO;GACL,SAAS,UAAU,IAAI;GACvB,YAAY,gBACR,WAAW,oBAAoB,WAC/B,KAAK,oBAAoB,aAAa,oBAAoB,iBAAiB,oBAAoB,kBAAkB,oBAAoB,mBAAmB,oBAAoB;GACjL;EACD,CAAA;;AAYN,SAAS,iBAAiB,EACxB,SACA,kBACA,QACA,QACA,iBACwB;CACxB,MAAM,YAAY,OAAO,WAAW;CACpC,MAAM,CAAC,YAAY,YAAY,OAAO,OAAO;CAC7C,MAAM,OAAO,KAAK,IAAI,YAAY,SAAS;CAC3C,MAAM,OAAO,KAAK,IAAI,YAAY,SAAS;CAI3C,MAAM,cACJ,UACG;EACH,MAAM,SAAA,GAAA,YAAA,YAAmB,MAAM;AAC/B,MAAI,CAAC,MAAO;EAEZ,IAAI,UAAmC;EACvC,IAAI,OAAO;AACX,OAAK,MAAM,YAAY,SAAS;AAC9B,OAAI,CAAC,iBAAiB,IAAI,SAAS,CAAE;GACrC,MAAM,IAAI,OAAO,SAAS;AAC1B,OAAI,MAAM,KAAA,EAAW;GACrB,MAAM,WAAW,KAAK,IAAI,IAAI,YAAY,IAAI,MAAM,EAAE;AACtD,OAAI,WAAW,MAAM;AACnB,WAAO;AACP,cAAU;;;AAId,MAAI,YAAY,KAAM,eAAc,QAAQ;;AAG9C,QACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;EACE,GAAG;EACH,GAAG;EACH,OAAO,KAAK,IAAI,GAAG,OAAO,KAAK;EAC/B,QAAQ,SAAS,cAAc;EAC/B,MAAK;EACL,aAAa;EACb,oBAAoB,cAAc,KAAK;EACvC,aAAa;EACb,kBAAkB,cAAc,KAAK;EACrC,CAAA;;AAIN,SAAS,cAAc,EACrB,OACA,QACA,QACA,kBACqB;AACrB,QACE,iBAAA,GAAA,kBAAA,KAAA,kBAAA,UAAA,EAAA,UACG,MAAM,KAAK,aAAa;EACvB,MAAM,IAAI,OAAO,SAAS;AAE1B,MAAI,MAAM,KAAA,EACR,QAAO;AAGT,SACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;GAEE,GAAG,IAAI,OAAO,WAAW,GAAG;GAC5B,GAAG,SAAS,iBAAiB;GAC7B,YAAW;GACX,MAAK;GACL,UAAU;aAET,eAAe,SAAS;GACpB,EARA,QAAQ,OAAO,SAAS,GAQxB;GAET,EACD,CAAA;;AAIP,SAAS,mBAAmB,OAAe;AACzC,QAAO,mBAAmB,OAAO,MAAM;;AAGzC,SAAgB,SAAiB,EAC/B,MACA,QACA,OACA,aACA,YACA,eACA,kBAAkB,aAAa,OAAO,SAAS,EAC/C,wBAAwB,gBACxB,qBACA,oBAAoB,OACpB,eACA,OACA,WACA,SAAS,gBACT,aACA,cAAc,oBACd,aACA,aAC4C;CAC5C,MAAM,gBAAA,GAAA,MAAA,QAAsC,KAAK;CACjD,MAAM,gBAAgBA,iCAAAA,kBAAkB;CACxC,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,UAAqB,EAAE;CACrC,MAAM,CAAC,iBAAiB,uBAAA,GAAA,MAAA,UACY,KAAK;CACzC,MAAM,CAAC,oBAAoB,0BAAA,GAAA,MAAA,UACzB,KACD;CACD,MAAM,CAAC,cAAc,oBAAA,GAAA,MAAA,gBAEjB,IAAI,KACD,SAAS,EAAE,EACT,QAAQ,SAAS,KAAK,gBAAgB,CACtC,KAAK,SAAS,KAAK,IAAI,CAC3B,CACJ;CAED,MAAM,gBAAA,GAAA,MAAA,cAA4B,OAAe;AAC/C,mBAAiB,SAAS;GACxB,MAAM,OAAO,IAAI,IAAI,KAAK;AAC1B,OAAI,KAAK,IAAI,GAAG,CACd,MAAK,OAAO,GAAG;OAEf,MAAK,IAAI,GAAG;AAEd,UAAO;IACP;IACD,EAAE,CAAC;AAEN,EAAA,GAAA,MAAA,iBAAgB;EACd,MAAM,UAAU,aAAa;AAE7B,MAAI,CAAC,QACH;EAGF,MAAM,iBAAiB,IAAI,gBAAgB,YAAY;GACrD,MAAM,QAAQ,QAAQ;AAEtB,OAAI,CAAC,MACH;AAGF,YAAS,MAAM,YAAY,MAAM;IACjC;AAEF,iBAAe,QAAQ,QAAQ;AAE/B,eAAa;AACX,kBAAe,YAAY;;IAE5B,EAAE,CAAC;CAEN,MAAM,eAAA,GAAA,MAAA,eAA4B;EAChC,MAAM,sBAAM,IAAI,KAAqC;AAErD,OAAK,MAAM,SAAS,OAClB,KAAI,IAAI,MAAM,KAAK,MAAM;AAG3B,SAAO;IACN,CAAC,OAAO,CAAC;CAEZ,MAAM,aAAA,GAAA,MAAA,eAEF,KAAK,KAAK,UAAU;EAClB,MAAM,SAAiC,EAAE;AAEzC,OAAK,MAAM,SAAS,OAClB,QAAO,MAAM,OAAO,aAAa,IAAI,MAAM,IAAI,GAC3C,IACA,MAAM,SAAS,MAAM;AAG3B,SAAO;GAAE,YAAY,YAAY,MAAM;GAAE,UAAU;GAAQ;GAC3D,EACJ;EAAC;EAAM;EAAa;EAAQ;EAAa,CAC1C;CAED,MAAM,QAAA,GAAA,MAAA,eAEF,KAAK,IACH,GACA,eAAe,SAAS,GACxB,GAAG,UAAU,KAAK,WAChB,OAAO,QACJ,KAAK,UAAU,MAAM,KAAK,IAAI,GAAG,OAAO,SAAS,MAAM,QAAQ,EAAE,EAClE,EACD,CACF,CACF,EACH;EAAC;EAAe;EAAQ;EAAU,CACnC;CAGD,MAAM,QAAA,GAAA,MAAA,eAEF,KAAK,IACH,GACA,GAAG,UAAU,KAAK,WAChB,OAAO,QACJ,KAAK,UAAU,MAAM,KAAK,IAAI,GAAG,OAAO,SAAS,MAAM,QAAQ,EAAE,EAClE,EACD,CACF,CACF,EACH,CAAC,QAAQ,UAAU,CACpB;CAED,MAAM,WAAA,GAAA,MAAA,eACE,cAAc,UAAU,KAAK,WAAW,OAAO,WAAW,EAChE,CAAC,YAAY,UAAU,CACxB;CAED,MAAM,UAAA,GAAA,MAAA,gBAAA,GAAA,YAAA,WAE0B;EAC1B,QAAQ;EACR,OAAO,CAAC,eAAe,KAAK,IAAI,eAAe,MAAM,CAAC;EACtD,SAAS;EACV,CAAC,EACJ,CAAC,SAAS,MAAM,CACjB;CAED,MAAM,UAAA,GAAA,MAAA,gBAAA,GAAA,YAAA,aAEkB;EAClB,QAAQ,CAAC,MAAM,KAAK;EACpB,OAAO,CAAC,SAAS,gBAAgB,YAAY;EAC9C,CAAC,EACJ;EAAC;EAAQ;EAAM;EAAK,CACrB;CAED,MAAM,cAAA,GAAA,MAAA,gBAAA,GAAA,YAAA,cAE2B;EAC3B,QAAQ,OAAO,KAAK,UAAU,MAAM,IAAI;EACxC,OAAO,OAAO,KAAK,UAAU,MAAM,MAAM;EAC1C,CAAC,EACJ,CAAC,OAAO,CACT;CAED,MAAM,aAAA,GAAA,MAAA,eAA0B;AAC9B,MAAI,CAAC,SAAS,UAAU,EACtB,QAAO,EAAE;AAGX,SAAO,MACJ,QAAQ,SAAS,CAAC,aAAa,IAAI,KAAK,IAAI,CAAC,CAC7C,KAAK,SAAS;GACb,MAAM,YAAY,KAAK,UAAA,GAAA,YAAA,aACC;IAClB,QAAQ,KAAK;IACb,OAAO,CAAC,SAAS,gBAAgB,YAAY;IAC9C,CAAC,GACF;GACJ,MAAM,WAAqB,EAAE;GAC7B,IAAI,WAA4C;AAEhD,QAAK,MAAM,SAAS,MAAM;IACxB,MAAM,IAAI,OAAO,YAAY,MAAM,CAAC;IACpC,MAAM,QAAQ,KAAK,SAAS,MAAM;AAElC,QAAI,MAAM,KAAA,KAAa,UAAU,QAAQ,CAAC,OAAO,SAAS,MAAM,EAAE;AAChE,gBAAW;AACX;;IAGF,MAAM,QAAQ;KACZ,GAAG,IAAI,OAAO,WAAW,GAAG;KAC5B,GAAG,UAAU,MAAM;KACpB;AACD,aAAS,KACP,aAAa,OACT,KAAK,MAAM,EAAE,GAAG,MAAM,MACtB,KAAK,MAAM,EAAE,GAAG,MAAM,IAC3B;AACD,eAAW;;AAGb,UAAO;IACL,KAAK,KAAK;IACV,GAAG,SAAS,KAAK,IAAI;IACrB,OAAO,KAAK;IACZ,iBAAiB,KAAK,mBAAmB;IAC1C;IACD,CACD,QAAQ,SAAS,KAAK,MAAM,GAAG;IACjC;EAAC;EAAO;EAAc;EAAM;EAAa;EAAQ;EAAQ;EAAQ;EAAM,CAAC;CAE3E,MAAM,oBAAA,GAAA,MAAA,eACE,IAAI,IAAI,UAAU,KAAK,WAAW,OAAO,WAAW,CAAC,EAC3D,CAAC,UAAU,CACZ;CAED,MAAM,wBAAA,GAAA,MAAA,QAAuD,KAAK;AAClE,KAAI,oBAAoB,KACtB,sBAAqB,UAAU;CAEjC,MAAM,gBAAgB,qBAAqB;CAE3C,MAAM,WAAA,GAAA,MAAA,eAEF,oBAAoB,OAChB,OACC,UAAU,MAAM,WAAW,OAAO,eAAe,gBAAgB,IAClE,MACN,CAAC,iBAAiB,UAAU,CAC7B;CAID,MAAM,cAAA,GAAA,MAAA,eAA2B;AAC/B,MAAI,QACF,QAAO,OAAO,QACX,KAAK,UAAU,MAAM,KAAK,IAAI,GAAG,QAAQ,SAAS,MAAM,QAAQ,EAAE,EACnE,EACD;AAGH,SAAO,UAAU,QACd,KAAK,WACJ,MACA,OAAO,QACJ,GAAG,UAAU,IAAI,KAAK,IAAI,GAAG,OAAO,SAAS,MAAM,QAAQ,EAAE,EAC9D,EACD,EACH,EACD;IACA;EAAC;EAAS;EAAQ;EAAU,CAAC;CAEhC,MAAM,aAAa,UAAU,sBAAsB,QAAQ,WAAW,GAAG;AAEzE,EAAA,GAAA,MAAA,iBAAgB;AACd,MAAI,YAAY;AACd,yBAAsB,WAAW;AACjC;;EAGF,MAAM,YAAY,OAAO,iBAAiB;AACxC,yBAAsB,KAAK;KAC1B,cAAc;AAEjB,eAAa;AACX,UAAO,aAAa,UAAU;;IAE/B,CAAC,WAAW,CAAC;CAEhB,MAAM,QAAQ,iBAAiB;CAC/B,MAAM,UAAA,GAAA,MAAA,eAAuBC,0BAAAA,gBAAgB,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;CAC7E,MAAM,cAAA,GAAA,MAAA,eAA2B;AAC/B,MAAI,CAAC,qBAAqB,wBAAwB,KAAA,EAChD,QAAO;EAGT,MAAM,IAAI,OAAO,oBAAoB;AAErC,MAAI,MAAM,KAAA,EACR,QAAO;AAGT,SAAO,IAAI,OAAO,WAAW,GAAG;IAC/B;EAAC;EAAqB;EAAmB;EAAO,CAAC;CAEpD,MAAM,gBAAA,GAAA,MAAA,eAEF,oBAAoB,OAChB,OACC,KAAK,MAAM,UAAU,YAAY,MAAM,KAAK,gBAAgB,IAC7D,MACN;EAAC;EAAiB;EAAM;EAAY,CACrC;CAID,MAAM,iBAAA,GAAA,MAAA,eAEF,iBAAA,GAAA,kBAAA,KAAC,eAAD;EACa;EACH;EACK;EACL;EACA;EACI;EACZ,CAAA,EAEJ;EAAC;EAAW;EAAQ;EAAa;EAAQ;EAAQ;EAAW,CAC7D;CAED,MAAM,kBAAkB,eAAe;CACvC,MAAM,cAAiC,UACnC,CACE,GAAG,OACA,QAAQ,WAAW,QAAQ,SAAS,MAAM,QAAQ,OAAO,EAAE,CAC3D,KAAK,WAAW;EACf,KAAK,MAAM;EACX,OAAO,MAAM;EACb,OAAO,MAAM;EACb,OAAO,gBAAgB,KAAK,IAAI,QAAQ,SAAS,MAAM,QAAQ,EAAE,CAAC;EACnE,EAAE,EACL,IAAI,SAAS,EAAE,EACZ,QAAQ,SAAS,CAAC,aAAa,IAAI,KAAK,IAAI,CAAC,CAC7C,SAAS,SAAS;EACjB,MAAM,QACJ,iBAAiB,OAAO,OAAO,KAAK,SAAS,aAAa;AAE5D,MAAI,UAAU,QAAQ,CAAC,OAAO,SAAS,MAAM,CAC3C,QAAO,EAAE;AAGX,SAAO,CACL;GACE,KAAK,KAAK;GACV,OAAO,KAAK;GACZ,OAAO,KAAK;GACZ,QAAQ,KAAK,eAAe,iBAAiB,MAAM;GACpD,CACF;GACD,CACL,GACD,EAAE;CACN,MAAM,gBAAgB,YAAY,SAAS;CAC3C,MAAM,UACJ,kBAAkB,QACb,OAAO,cAAc,IAAI,KAAK,OAAO,WAAW,GAAG,IACpD;CACN,MAAM,UAAU,OAAO,WAAW;CAClC,MAAM,CAAC,YAAY,eAAeC,yBAAAA,iBAAiC;CACnE,MAAM,aAAaC,yBAAAA,qBAAqB;EACtC;EACA;EACA;EACA;EACA,UAAU,YAAY;EACtB,WAAW,YAAY;EACxB,CAAC;AAEF,QACE,iBAAA,GAAA,kBAAA,MAAC,OAAD;EAAK,YAAA,GAAA,OAAA,IAAc,wBAAwB,UAAU;YAArD;GACE,iBAAA,GAAA,kBAAA,MAAC,OAAD;IAAK,WAAU;cAAf,CACG,SAAS,iBAAA,GAAA,kBAAA,KAACC,8BAAAA,cAAD,EAAA,UAAe,OAAqB,CAAA,EAC9C,iBAAA,GAAA,kBAAA,KAAC,QAAD;KAAM,WAAU;eACb,cACC,YAAY,YAAY,YAAY,KAAK,GAEzC,iBAAA,GAAA,kBAAA,KAAC,QAAD;MAAM,WAAU;gBACb,YAAY,WAAW;MACnB,CAAA;KAEJ,CAAA,CACH;;GAEN,iBAAA,GAAA,kBAAA,MAAC,OAAD;IAAK,WAAU;cAAf,CACE,iBAAA,GAAA,kBAAA,KAACC,iCAAAA,cAAD;KACE,OAAO,CACL,GAAG,OAAO,KAAK,WAAW;MACxB,IAAI,MAAM;MACV,OAAO,MAAM;MACb,OAAO,MAAM;MACd,EAAE,EACH,IAAI,SAAS,EAAE,EAAE,KAAK,UAAU;MAC9B,IAAI,KAAK;MACT,OAAO,KAAK;MACZ,OAAO,KAAK;MACZ,QAAQ;MACT,EAAE,CACJ;KACD,WAAW;KACX,UAAU;KACV,WAAU;KACV,CAAA,EACF,iBAAA,GAAA,kBAAA,KAAC,QAAD;KACE,YAAA,GAAA,OAAA,IACE,2DACA,aAAa,gBAAgB,YAC9B;eAEA,sBAAsB;KAClB,CAAA,CACH;;GAEN,iBAAA,GAAA,kBAAA,MAAC,OAAD;IACE,KAAK;IACL,WAAU;IACV,OAAO,EAAE,QAAQ;cAHnB,CAKE,iBAAA,GAAA,kBAAA,KAAC,OAAD;KACE,KAAK;KACL,WAAU;KACV,OAAO;MACL,MAAM,WAAW;MACjB,KAAK,WAAW;MAChB,SAAS,gBAAgB,IAAI;MAC7B,YAAY,gBACR,2BACA;MACL;eAEA,kBAAkB,QACjB,iBAAA,GAAA,kBAAA,KAACC,yBAAAA,kBAAD;MACE,OAAO,sBAAsB,cAAc;MAC3C,MAAM;MACN,CAAA;KAEA,CAAA,EACL,QAAQ,KACP,iBAAA,GAAA,kBAAA,MAAC,OAAD;KAAY;KAAe;eAA3B;MACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;OACE,IAAI;OACJ,IAAI;OACJ,IAAI;OACJ,IAAI,SAAS;OACb,QAAO;OACP,aAAa;OACb,CAAA;MAED,OAAO,KAAK,MAAM,UAAU;OAC3B,MAAM,IAAI,OAAO,KAAK;OACtB,MAAM,gBACJ,cAAc,KAAA,KAAa,UAAU,OAAO,SAAS;AAEvD,cACE,iBAAA,GAAA,kBAAA,MAAC,KAAD,EAAA,UAAA,CACG,CAAC,iBACA,iBAAA,GAAA,kBAAA,KAAC,QAAD;QACE,IAAI,gBAAgB;QACpB,IAAI;QACJ,IAAI;QACJ,IAAI;QACJ,QAAO;QACP,aAAa;QACb,CAAA,EAEH,CAAC,iBACA,iBAAA,GAAA,kBAAA,KAAC,QAAD;QACE,GAAG,gBAAgB;QACnB,GAAG,IAAI;QACP,YAAW;QACX,MAAK;QACL,UAAU;kBAETC,0BAAAA,gBAAgB,KAAK;QACjB,CAAA,CAEP,EAAA,EAtBI,UAAU,OAsBd;QAEN;MAED,aACC,iBAAA,GAAA,kBAAA,KAAC,QAAD;OACE,GAAG;OACH,GAAG,cAAc;OACjB,YAAW;OACX,MAAK;OACL,UAAU;OACV,YAAY;iBAEX;OACI,CAAA;MAGR,eAAe,QACd,iBAAA,GAAA,kBAAA,KAAC,QAAD;OACE,IAAI;OACJ,IAAI;OACJ,IAAI;OACJ,IAAI,SAAS;OACb,QAAO;OACP,aAAa;OACb,iBAAgB;OAChB,eAAc;OACd,CAAA;MAGJ,iBAAA,GAAA,kBAAA,KAAC,QAAD;OACE,IAAI;OACJ,IAAI;OACJ,IAAI,OAAO,EAAE;OACb,IAAI,OAAO,EAAE;OACb,QAAO;OACP,aAAa;OACb,CAAA;MAEF,iBAAA,GAAA,kBAAA,MAACC,YAAAA,OAAD,EAAA,UAAA;OACG,kBAAkB,QACjB,iBAAA,GAAA,kBAAA,KAAC,aAAD;QACE,UAAU;QACV,SAAS,oBAAoB;QAClB;QACH;QACA;QACA;QACR,CAAA;OAEH;OAEA,iBACC,iBAAA,GAAA,kBAAA,KAAC,QAAD;QACE,IAAI;QACJ,IAAI;QACJ,IAAI,OAAO,cAAc,MAAM;QAC/B,IAAI,OAAO,cAAc,MAAM;QAC/B,QAAQ,cAAc,SAAS;QAC/B,aAAa;QACb,eAAc;QACd,CAAA;OAGH,UAAU,KAAK,SACd,iBAAA,GAAA,kBAAA,KAAC,QAAD;QAEE,GAAG,KAAK;QACR,MAAK;QACL,QAAQ,KAAK;QACb,aAAa;QACb,iBAAiB,KAAK;QACtB,eAAc;QACd,gBAAe;QACf,eAAc;QACd,EATK,QAAQ,KAAK,MASlB,CACF;OACI,EAAA,CAAA;MAER,iBAAA,GAAA,kBAAA,KAAC,kBAAD;OACW;OACT,kBAAkB;OACV;OACA;OACR,eAAe;OACf,CAAA;MAEF,iBAAA,GAAA,kBAAA,KAAC,eAAD;OACS;OACC;OACA;OACQ;OAChB,CAAA;MACE;OAEJ;;GACF"}
@@ -50,8 +50,13 @@ interface BarChartProps<TDatum> {
50
50
  title?: string;
51
51
  yAxisUnit?: string;
52
52
  height?: number;
53
- /** Override how the total value (sum of focused or all categories) is rendered. */
54
- renderTotal?: (value: number) => React.ReactNode;
53
+ /**
54
+ * Override how the total value (sum of focused or all categories) is
55
+ * rendered. `animated` is false while a bar is focused (hover), so an
56
+ * animated total can snap between hovered buckets instead of re-firing a
57
+ * tween on every bar the pointer crosses.
58
+ */
59
+ renderTotal?: (value: number, animated: boolean) => React.ReactNode;
55
60
  /** Format function used when `renderTotal` is not provided. */
56
61
  formatTotal?: (value: number) => string;
57
62
  /** Formats per-series values in the hover tooltip. Defaults to `formatTotal`. */
@@ -50,8 +50,13 @@ interface BarChartProps<TDatum> {
50
50
  title?: string;
51
51
  yAxisUnit?: string;
52
52
  height?: number;
53
- /** Override how the total value (sum of focused or all categories) is rendered. */
54
- renderTotal?: (value: number) => React.ReactNode;
53
+ /**
54
+ * Override how the total value (sum of focused or all categories) is
55
+ * rendered. `animated` is false while a bar is focused (hover), so an
56
+ * animated total can snap between hovered buckets instead of re-firing a
57
+ * tween on every bar the pointer crosses.
58
+ */
59
+ renderTotal?: (value: number, animated: boolean) => React.ReactNode;
55
60
  /** Format function used when `renderTotal` is not provided. */
56
61
  formatTotal?: (value: number) => string;
57
62
  /** Formats per-series values in the hover tooltip. Defaults to `formatTotal`. */
@@ -1,6 +1,8 @@
1
1
  "use client";
2
+ import { useReducedMotion } from "../hooks/use-reduced-motion.js";
2
3
  import { cn } from "../utils/cn.js";
3
- import { integerFormat, localeNumberFormat, oneDecimalFormat } from "../utils/format.js";
4
+ import { localeNumberFormat } from "../utils/format.js";
5
+ import { buildYAxisScale, formatYAxisTick } from "../utils/chart-scale.js";
4
6
  import { ChartTooltipCard, clampTooltipPosition, useMeasuredSize } from "./chart.js";
5
7
  import { SeriesLegend } from "./series-legend.js";
6
8
  import { SectionTitle } from "./typography.js";
@@ -19,25 +21,6 @@ const FOCUS_TRANSITION_MS = 180;
19
21
  const DEFAULT_HEIGHT = 220;
20
22
  const BAR_RADIUS = 2;
21
23
  const Y_AXIS_GUTTER = 34;
22
- function buildYAxisTicks(yMax) {
23
- const rawStep = yMax / 4;
24
- const normalized = rawStep === 0 ? 1 : rawStep;
25
- const magnitude = Math.pow(10, Math.floor(Math.log10(normalized)));
26
- const step = ([
27
- 1,
28
- 2,
29
- 2.5,
30
- 5,
31
- 10
32
- ].find((value) => value * magnitude >= normalized) ?? 10) * magnitude;
33
- const upper = Math.ceil(yMax / step) * step;
34
- const ticks = [];
35
- for (let value = 0; value <= upper + step * .001; value += step) ticks.push(Number(value.toFixed(6)));
36
- return ticks;
37
- }
38
- function formatYAxisTick(value) {
39
- return value >= 10 ? integerFormat.format(value) : oneDecimalFormat.format(value);
40
- }
41
24
  function buildBarPath(x, y, width, height, radius, roundTop, roundBottom) {
42
25
  const r = Math.max(0, Math.min(radius, width / 2, height / 2));
43
26
  if (r === 0 || !roundTop && !roundBottom) return `M ${x} ${y} H ${x + width} V ${y + height} H ${x} Z`;
@@ -67,15 +50,21 @@ function BarStackLayer({ stackData, series, seriesByKey, xScale, yScale, colorSc
67
50
  xScale,
68
51
  yScale,
69
52
  color: colorScale,
53
+ offset: "diverging",
70
54
  children: (barStacks) => barStacks.map((barStack) => barStack.bars.map((bar) => {
71
- if ((bar.bar.data.__values[barStack.key] ?? 0) === 0) return null;
55
+ const values = bar.bar.data.__values;
56
+ const segmentValue = values[barStack.key] ?? 0;
57
+ if (segmentValue === 0) return null;
72
58
  const strokeColor = seriesByKey.get(barStack.key)?.color ?? bar.color;
73
59
  const fillColor = strokeColor;
74
- const valueKeys = series.map((entry) => entry.key).filter((key) => (bar.bar.data.__values[key] ?? 0) > 0);
75
- const isBottomSegment = valueKeys[0] === barStack.key;
76
- const isTopSegment = valueKeys[valueKeys.length - 1] === barStack.key;
60
+ const positiveKeys = series.map((entry) => entry.key).filter((key) => (values[key] ?? 0) > 0);
61
+ const negativeKeys = series.map((entry) => entry.key).filter((key) => (values[key] ?? 0) < 0);
62
+ const roundTop = segmentValue > 0 && positiveKeys[positiveKeys.length - 1] === barStack.key;
63
+ const roundBottom = segmentValue > 0 ? positiveKeys[0] === barStack.key : negativeKeys[negativeKeys.length - 1] === barStack.key;
64
+ const top = bar.height < 0 ? bar.y + bar.height : bar.y;
65
+ const barHeight = Math.abs(bar.height);
77
66
  return /* @__PURE__ */ jsx("path", {
78
- d: buildBarPath(bar.x, bar.y, bar.width, Math.max(0, bar.height), BAR_RADIUS, isTopSegment, isBottomSegment),
67
+ d: buildBarPath(bar.x, top, bar.width, Math.max(0, barHeight), BAR_RADIUS, roundTop, roundBottom),
79
68
  fill: fillColor,
80
69
  stroke: strokeColor,
81
70
  strokeWidth: 1,
@@ -85,12 +74,13 @@ function BarStackLayer({ stackData, series, seriesByKey, xScale, yScale, colorSc
85
74
  });
86
75
  }
87
76
  function FocusBorder({ category, visible, stackData, series, xScale, yScale }) {
77
+ const reducedMotion = useReducedMotion();
88
78
  const x = xScale(category);
89
79
  const datum = stackData.find((entry) => entry.__category === category);
90
80
  if (x === void 0 || !datum) return null;
91
- if (!series.some((entry) => (datum.__values[entry.key] ?? 0) > 0)) return null;
81
+ if (!series.some((entry) => (datum.__values[entry.key] ?? 0) !== 0)) return null;
92
82
  const topY = PADDING_TOP;
93
- const baselineY = yScale(0);
83
+ const bottomY = yScale(series.reduce((sum, entry) => sum + Math.min(0, datum.__values[entry.key] ?? 0), 0));
94
84
  const borderPaddingX = 4;
95
85
  const borderPaddingY = 3;
96
86
  const borderXRaw = x - borderPaddingX;
@@ -102,7 +92,7 @@ function FocusBorder({ category, visible, stackData, series, xScale, yScale }) {
102
92
  const borderX = Math.max(minX, borderXRaw);
103
93
  const borderRight = Math.min(maxX, borderXRaw + borderWidthRaw);
104
94
  const borderWidth = Math.max(0, borderRight - borderX);
105
- const borderHeight = Math.max(1, baselineY - topY + borderPaddingY * 2);
95
+ const borderHeight = Math.max(1, bottomY - topY + borderPaddingY * 2);
106
96
  if (borderWidth <= 0) return null;
107
97
  return /* @__PURE__ */ jsx("rect", {
108
98
  x: borderX,
@@ -116,7 +106,7 @@ function FocusBorder({ category, visible, stackData, series, xScale, yScale }) {
116
106
  pointerEvents: "none",
117
107
  style: {
118
108
  opacity: visible ? 1 : 0,
119
- transition: `x ${FOCUS_TRANSITION_MS}ms ease, y ${FOCUS_TRANSITION_MS}ms ease, width ${FOCUS_TRANSITION_MS}ms ease, height ${FOCUS_TRANSITION_MS}ms ease, opacity ${FOCUS_TRANSITION_MS}ms ease`
109
+ transition: reducedMotion ? `opacity ${FOCUS_TRANSITION_MS}ms ease` : `x ${FOCUS_TRANSITION_MS}ms ease, y ${FOCUS_TRANSITION_MS}ms ease, width ${FOCUS_TRANSITION_MS}ms ease, height ${FOCUS_TRANSITION_MS}ms ease, opacity ${FOCUS_TRANSITION_MS}ms ease`
120
110
  }
121
111
  });
122
112
  }
@@ -162,7 +152,7 @@ function CategoryTicks({ ticks, xScale, height, formatCategory }) {
162
152
  x: x + xScale.bandwidth() / 2,
163
153
  y: height - PADDING_BOTTOM + 16,
164
154
  textAnchor: "middle",
165
- fill: "var(--gray-a11)",
155
+ fill: "var(--neutral-a11)",
166
156
  fontSize: 10,
167
157
  children: formatCategory(category)
168
158
  }, `tick-${String(category)}`);
@@ -173,6 +163,7 @@ function defaultFormatTotal(value) {
173
163
  }
174
164
  function BarChart({ data, series, lines, getCategory, categories, categoryTicks, formatCategory = (category) => String(category), formatTooltipCategory = formatCategory, highlightedCategory, showHighlightLine = false, referenceLine, title, yAxisUnit, height = DEFAULT_HEIGHT, renderTotal, formatTotal = defaultFormatTotal, formatValue, className }) {
175
165
  const containerRef = useRef(null);
166
+ const reducedMotion = useReducedMotion();
176
167
  const [width, setWidth] = useState(0);
177
168
  const [hoveredCategory, setHoveredCategory] = useState(null);
178
169
  const [trailingHoverLabel, setTrailingHoverLabel] = useState(null);
@@ -216,11 +207,12 @@ function BarChart({ data, series, lines, getCategory, categories, categoryTicks,
216
207
  series,
217
208
  hiddenSeries
218
209
  ]);
219
- const yMax = useMemo(() => Math.max(1, referenceLine?.value ?? 0, ...stackData.map((record) => series.reduce((sum, entry) => sum + (record.__values[entry.key] ?? 0), 0))), [
210
+ const yMax = useMemo(() => Math.max(1, referenceLine?.value ?? 0, ...stackData.map((record) => series.reduce((sum, entry) => sum + Math.max(0, record.__values[entry.key] ?? 0), 0))), [
220
211
  referenceLine,
221
212
  series,
222
213
  stackData
223
214
  ]);
215
+ const yMin = useMemo(() => Math.min(0, ...stackData.map((record) => series.reduce((sum, entry) => sum + Math.min(0, record.__values[entry.key] ?? 0), 0))), [series, stackData]);
224
216
  const xDomain = useMemo(() => categories ?? stackData.map((record) => record.__category), [categories, stackData]);
225
217
  const xScale = useMemo(() => scaleBand({
226
218
  domain: xDomain,
@@ -228,9 +220,13 @@ function BarChart({ data, series, lines, getCategory, categories, categoryTicks,
228
220
  padding: .32
229
221
  }), [xDomain, width]);
230
222
  const yScale = useMemo(() => scaleLinear({
231
- domain: [0, yMax],
223
+ domain: [yMin, yMax],
232
224
  range: [height - PADDING_BOTTOM, PADDING_TOP]
233
- }), [height, yMax]);
225
+ }), [
226
+ height,
227
+ yMax,
228
+ yMin
229
+ ]);
234
230
  const colorScale = useMemo(() => scaleOrdinal({
235
231
  domain: series.map((entry) => entry.key),
236
232
  range: series.map((entry) => entry.color)
@@ -281,8 +277,8 @@ function BarChart({ data, series, lines, getCategory, categories, categoryTicks,
281
277
  const focusCategory = lastFocusCategoryRef.current;
282
278
  const focused = useMemo(() => hoveredCategory === null ? null : stackData.find((record) => record.__category === hoveredCategory) ?? null, [hoveredCategory, stackData]);
283
279
  const totalValue = useMemo(() => {
284
- if (focused) return series.reduce((sum, entry) => sum + (focused.__values[entry.key] ?? 0), 0);
285
- return stackData.reduce((sum, record) => sum + series.reduce((s, entry) => s + (record.__values[entry.key] ?? 0), 0), 0);
280
+ if (focused) return series.reduce((sum, entry) => sum + Math.max(0, focused.__values[entry.key] ?? 0), 0);
281
+ return stackData.reduce((sum, record) => sum + series.reduce((s, entry) => s + Math.max(0, record.__values[entry.key] ?? 0), 0), 0);
286
282
  }, [
287
283
  focused,
288
284
  series,
@@ -302,7 +298,7 @@ function BarChart({ data, series, lines, getCategory, categories, categoryTicks,
302
298
  };
303
299
  }, [hoverLabel]);
304
300
  const ticks = categoryTicks ?? xDomain;
305
- const yTicks = useMemo(() => buildYAxisTicks(yMax), [yMax]);
301
+ const yTicks = useMemo(() => buildYAxisScale(yMin, yMax).ticks, [yMin, yMax]);
306
302
  const highlightX = useMemo(() => {
307
303
  if (!showHighlightLine || highlightedCategory === void 0) return null;
308
304
  const x = xScale(highlightedCategory);
@@ -318,12 +314,27 @@ function BarChart({ data, series, lines, getCategory, categories, categoryTicks,
318
314
  data,
319
315
  getCategory
320
316
  ]);
317
+ const barStackLayer = useMemo(() => /* @__PURE__ */ jsx(BarStackLayer, {
318
+ stackData,
319
+ series,
320
+ seriesByKey,
321
+ xScale,
322
+ yScale,
323
+ colorScale
324
+ }), [
325
+ stackData,
326
+ series,
327
+ seriesByKey,
328
+ xScale,
329
+ yScale,
330
+ colorScale
331
+ ]);
321
332
  const fmtTooltipValue = formatValue ?? formatTotal;
322
- const tooltipRows = focused ? [...series.filter((entry) => (focused.__values[entry.key] ?? 0) > 0).map((entry) => ({
333
+ const tooltipRows = focused ? [...series.filter((entry) => (focused.__values[entry.key] ?? 0) !== 0).map((entry) => ({
323
334
  key: entry.key,
324
335
  label: entry.label,
325
336
  color: entry.color,
326
- value: fmtTooltipValue(focused.__values[entry.key] ?? 0)
337
+ value: fmtTooltipValue(Math.abs(focused.__values[entry.key] ?? 0))
327
338
  })), ...(lines ?? []).filter((line) => !hiddenSeries.has(line.key)).flatMap((line) => {
328
339
  const value = focusedDatum === null ? null : line.getValue(focusedDatum);
329
340
  if (value === null || !Number.isFinite(value)) return [];
@@ -353,7 +364,7 @@ function BarChart({ data, series, lines, getCategory, categories, categoryTicks,
353
364
  className: "flex items-baseline justify-between",
354
365
  children: [title && /* @__PURE__ */ jsx(SectionTitle, { children: title }), /* @__PURE__ */ jsx("span", {
355
366
  className: "tabular-nums",
356
- children: renderTotal ? renderTotal(totalValue) : /* @__PURE__ */ jsx("span", {
367
+ children: renderTotal ? renderTotal(totalValue, focused === null) : /* @__PURE__ */ jsx("span", {
357
368
  className: "text-base font-bold text-gray tabular-nums",
358
369
  children: formatTotal(totalValue)
359
370
  })
@@ -391,7 +402,7 @@ function BarChart({ data, series, lines, getCategory, categories, categoryTicks,
391
402
  left: tooltipPos.left,
392
403
  top: tooltipPos.top,
393
404
  opacity: tooltipActive ? 1 : 0,
394
- transition: "left 140ms ease-out, top 140ms ease-out, opacity 140ms ease-out"
405
+ transition: reducedMotion ? "opacity 140ms ease-out" : "left 140ms ease-out, top 140ms ease-out, opacity 140ms ease-out"
395
406
  },
396
407
  children: focusCategory !== null && /* @__PURE__ */ jsx(ChartTooltipCard, {
397
408
  label: formatTooltipCategory(focusCategory),
@@ -405,8 +416,8 @@ function BarChart({ data, series, lines, getCategory, categories, categoryTicks,
405
416
  x1: Y_AXIS_GUTTER,
406
417
  x2: Y_AXIS_GUTTER,
407
418
  y1: PADDING_TOP,
408
- y2: yScale(0),
409
- stroke: "var(--gray-a6)",
419
+ y2: height - PADDING_BOTTOM,
420
+ stroke: "var(--neutral-a6)",
410
421
  strokeWidth: 1
411
422
  }),
412
423
  yTicks.map((tick, index) => {
@@ -417,13 +428,13 @@ function BarChart({ data, series, lines, getCategory, categories, categoryTicks,
417
428
  x2: Y_AXIS_GUTTER,
418
429
  y1: y,
419
430
  y2: y,
420
- stroke: "var(--gray-a8)",
431
+ stroke: "var(--neutral-a8)",
421
432
  strokeWidth: 1
422
433
  }), !hideTickLabel && /* @__PURE__ */ jsx("text", {
423
434
  x: Y_AXIS_GUTTER - 7,
424
435
  y: y + 3,
425
436
  textAnchor: "end",
426
- fill: "var(--gray-a11)",
437
+ fill: "var(--neutral-a11)",
427
438
  fontSize: 10,
428
439
  children: formatYAxisTick(tick)
429
440
  })] }, `y-tick-${tick}`);
@@ -432,7 +443,7 @@ function BarChart({ data, series, lines, getCategory, categories, categoryTicks,
432
443
  x: 0,
433
444
  y: PADDING_TOP - 6,
434
445
  textAnchor: "start",
435
- fill: "var(--gray-a11)",
446
+ fill: "var(--neutral-a11)",
436
447
  fontSize: 10,
437
448
  fontWeight: 600,
438
449
  children: yAxisUnit
@@ -441,7 +452,7 @@ function BarChart({ data, series, lines, getCategory, categories, categoryTicks,
441
452
  x1: highlightX,
442
453
  x2: highlightX,
443
454
  y1: PADDING_TOP,
444
- y2: yScale(0),
455
+ y2: height - PADDING_BOTTOM,
445
456
  stroke: "var(--spark-a9)",
446
457
  strokeWidth: 1.5,
447
458
  strokeDasharray: "5 4",
@@ -452,7 +463,7 @@ function BarChart({ data, series, lines, getCategory, categories, categoryTicks,
452
463
  x2: width,
453
464
  y1: yScale(0),
454
465
  y2: yScale(0),
455
- stroke: "var(--gray-a5)",
466
+ stroke: "var(--neutral-a5)",
456
467
  strokeWidth: 1
457
468
  }),
458
469
  /* @__PURE__ */ jsxs(Group, { children: [
@@ -464,20 +475,13 @@ function BarChart({ data, series, lines, getCategory, categories, categoryTicks,
464
475
  xScale,
465
476
  yScale
466
477
  }),
467
- /* @__PURE__ */ jsx(BarStackLayer, {
468
- stackData,
469
- series,
470
- seriesByKey,
471
- xScale,
472
- yScale,
473
- colorScale
474
- }),
478
+ barStackLayer,
475
479
  referenceLine && /* @__PURE__ */ jsx("line", {
476
480
  x1: Y_AXIS_GUTTER,
477
481
  x2: width,
478
482
  y1: yScale(referenceLine.value),
479
483
  y2: yScale(referenceLine.value),
480
- stroke: referenceLine.color ?? "var(--gray-a11)",
484
+ stroke: referenceLine.color ?? "var(--neutral-a11)",
481
485
  strokeWidth: 1.5,
482
486
  pointerEvents: "none"
483
487
  }),