@misoto22/design 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +87 -0
- package/CLAUDE.md +1 -0
- package/README.md +50 -5
- package/bin/misoto22-design.mjs +59 -13
- package/dist/agent/Accordion.md +24 -1
- package/dist/agent/Alert.md +23 -1
- package/dist/agent/AppShell.md +30 -2
- package/dist/agent/ArchitectureFigure.md +25 -2
- package/dist/agent/AreaChart.md +27 -2
- package/dist/agent/Article.md +26 -3
- package/dist/agent/AspectRatio.md +57 -0
- package/dist/agent/Avatar.md +25 -5
- package/dist/agent/Badge.md +22 -1
- package/dist/agent/BarChart.md +29 -2
- package/dist/agent/BarList.md +27 -1
- package/dist/agent/BigNumber.md +26 -2
- package/dist/agent/BoxPlot.md +24 -1
- package/dist/agent/Breadcrumb.md +24 -2
- package/dist/agent/BulletChart.md +23 -1
- package/dist/agent/Button.md +25 -1
- package/dist/agent/Calendar.md +37 -3
- package/dist/agent/Card.md +24 -2
- package/dist/agent/Checkbox.md +23 -2
- package/dist/agent/Code.md +50 -0
- package/dist/agent/CodeBlock.md +74 -0
- package/dist/agent/Collapsible.md +22 -1
- package/dist/agent/Combobox.md +29 -3
- package/dist/agent/Command.md +25 -2
- package/dist/agent/ComposedChart.md +26 -2
- package/dist/agent/ContextMenu.md +37 -4
- package/dist/agent/DataflowFigure.md +22 -1
- package/dist/agent/DatePicker.md +34 -6
- package/dist/agent/DescriptionList.md +68 -0
- package/dist/agent/Diagram.md +27 -3
- package/dist/agent/DiagramCanvas.md +24 -1
- package/dist/agent/DiagramExportMenu.md +29 -3
- package/dist/agent/DiagramInspector.md +23 -1
- package/dist/agent/DiagramLegend.md +22 -1
- package/dist/agent/DiagramMinimap.md +24 -4
- package/dist/agent/DiagramToolbar.md +23 -1
- package/dist/agent/Dialog.md +26 -3
- package/dist/agent/DropdownMenu.md +45 -6
- package/dist/agent/EmptyState.md +26 -1
- package/dist/agent/ErrorState.md +27 -2
- package/dist/agent/Facet.md +25 -1
- package/dist/agent/Field.md +45 -4
- package/dist/agent/FigureBand.md +24 -1
- package/dist/agent/FloatingIconButton.md +23 -1
- package/dist/agent/FunnelChart.md +23 -1
- package/dist/agent/Heading.md +64 -0
- package/dist/agent/Heatmap.md +25 -1
- package/dist/agent/Histogram.md +26 -2
- package/dist/agent/Input.md +22 -1
- package/dist/agent/Kbd.md +19 -1
- package/dist/agent/LifecycleFigure.md +22 -1
- package/dist/agent/LineChart.md +26 -2
- package/dist/agent/LinkArrow.md +20 -1
- package/dist/agent/Markdown.md +68 -0
- package/dist/agent/NativeSelect.md +23 -2
- package/dist/agent/NavItem.md +21 -1
- package/dist/agent/Pagination.md +28 -2
- package/dist/agent/PieChart.md +26 -2
- package/dist/agent/Popover.md +23 -1
- package/dist/agent/Progress.md +27 -3
- package/dist/agent/RadarChart.md +26 -2
- package/dist/agent/RadialChart.md +26 -3
- package/dist/agent/RadioGroup.md +23 -2
- package/dist/agent/SankeyChart.md +25 -2
- package/dist/agent/ScatterChart.md +27 -2
- package/dist/agent/ScrollArea.md +24 -3
- package/dist/agent/SearchableMenu.md +23 -1
- package/dist/agent/Select.md +29 -3
- package/dist/agent/Separator.md +28 -4
- package/dist/agent/SequenceFigure.md +23 -1
- package/dist/agent/Sheet.md +25 -2
- package/dist/agent/Skeleton.md +24 -2
- package/dist/agent/Slider.md +27 -4
- package/dist/agent/Sparkline.md +23 -1
- package/dist/agent/Spinner.md +24 -2
- package/dist/agent/StatusDot.md +20 -1
- package/dist/agent/StatusPill.md +28 -2
- package/dist/agent/Steps.md +24 -1
- package/dist/agent/Switch.md +21 -1
- package/dist/agent/Table.md +26 -3
- package/dist/agent/Tabs.md +24 -2
- package/dist/agent/Tag.md +40 -9
- package/dist/agent/Text.md +65 -0
- package/dist/agent/Textarea.md +20 -1
- package/dist/agent/Timestamp.md +64 -0
- package/dist/agent/Toast.md +26 -2
- package/dist/agent/ToggleGroup.md +24 -2
- package/dist/agent/Toolbar.md +71 -0
- package/dist/agent/Tooltip.md +23 -1
- package/dist/agent/TreemapChart.md +24 -1
- package/dist/agent/WaterfallChart.md +24 -1
- package/dist/agent/WorkflowFigure.md +24 -2
- package/dist/agent/catalog.json +5602 -745
- package/dist/agent/index.md +13 -4
- package/dist/article.css +16 -4
- package/dist/charts/AreaChart/AreaChart.d.ts +9 -2
- package/dist/charts/AreaChart/AreaChart.js +12 -13
- package/dist/charts/AreaChart/AreaChart.js.map +1 -1
- package/dist/charts/BarChart/BarChart.d.ts +14 -3
- package/dist/charts/BarChart/BarChart.js +20 -12
- package/dist/charts/BarChart/BarChart.js.map +1 -1
- package/dist/charts/BarList/BarList.d.ts +9 -1
- package/dist/charts/BarList/BarList.js +9 -1
- package/dist/charts/BarList/BarList.js.map +1 -1
- package/dist/charts/BigNumber/BigNumber.d.ts +19 -3
- package/dist/charts/BigNumber/BigNumber.js +25 -5
- package/dist/charts/BigNumber/BigNumber.js.map +1 -1
- package/dist/charts/BoxPlot/BoxPlot.js +4 -2
- package/dist/charts/BoxPlot/BoxPlot.js.map +1 -1
- package/dist/charts/BulletChart/BulletChart.js +28 -7
- package/dist/charts/BulletChart/BulletChart.js.map +1 -1
- package/dist/charts/ComposedChart/ComposedChart.d.ts +9 -2
- package/dist/charts/ComposedChart/ComposedChart.js +10 -10
- package/dist/charts/ComposedChart/ComposedChart.js.map +1 -1
- package/dist/charts/FunnelChart/FunnelChart.d.ts +7 -2
- package/dist/charts/FunnelChart/FunnelChart.js +6 -16
- package/dist/charts/FunnelChart/FunnelChart.js.map +1 -1
- package/dist/charts/Heatmap/Heatmap.d.ts +17 -3
- package/dist/charts/Heatmap/Heatmap.js +20 -11
- package/dist/charts/Heatmap/Heatmap.js.map +1 -1
- package/dist/charts/Histogram/Histogram.d.ts +24 -1
- package/dist/charts/Histogram/Histogram.js +43 -11
- package/dist/charts/Histogram/Histogram.js.map +1 -1
- package/dist/charts/LineChart/LineChart.d.ts +9 -2
- package/dist/charts/LineChart/LineChart.js +11 -12
- package/dist/charts/LineChart/LineChart.js.map +1 -1
- package/dist/charts/PieChart/PieChart.d.ts +15 -3
- package/dist/charts/PieChart/PieChart.js +14 -6
- package/dist/charts/PieChart/PieChart.js.map +1 -1
- package/dist/charts/RadarChart/RadarChart.d.ts +15 -3
- package/dist/charts/RadarChart/RadarChart.js +11 -9
- package/dist/charts/RadarChart/RadarChart.js.map +1 -1
- package/dist/charts/RadialChart/RadialChart.d.ts +22 -4
- package/dist/charts/RadialChart/RadialChart.js +28 -6
- package/dist/charts/RadialChart/RadialChart.js.map +1 -1
- package/dist/charts/SankeyChart/SankeyChart.d.ts +16 -4
- package/dist/charts/SankeyChart/SankeyChart.js +14 -6
- package/dist/charts/SankeyChart/SankeyChart.js.map +1 -1
- package/dist/charts/ScatterChart/ScatterChart.d.ts +24 -3
- package/dist/charts/ScatterChart/ScatterChart.js +21 -15
- package/dist/charts/ScatterChart/ScatterChart.js.map +1 -1
- package/dist/charts/Sparkline/Sparkline.js +5 -3
- package/dist/charts/Sparkline/Sparkline.js.map +1 -1
- package/dist/charts/TreemapChart/TreemapChart.d.ts +7 -2
- package/dist/charts/TreemapChart/TreemapChart.js +20 -11
- package/dist/charts/TreemapChart/TreemapChart.js.map +1 -1
- package/dist/charts/WaterfallChart/WaterfallChart.js +4 -2
- package/dist/charts/WaterfallChart/WaterfallChart.js.map +1 -1
- package/dist/charts/lib/export.d.ts +1 -0
- package/dist/charts/lib/figure.d.ts +21 -1
- package/dist/charts/lib/figure.js +5 -2
- package/dist/charts/lib/figure.js.map +1 -1
- package/dist/charts/lib/scale.d.ts +23 -0
- package/dist/charts/lib/scale.js +13 -0
- package/dist/charts/lib/scale.js.map +1 -0
- package/dist/charts/lib/selection.d.ts +20 -0
- package/dist/charts/lib/selection.js +18 -0
- package/dist/charts/lib/selection.js.map +1 -0
- package/dist/charts/lib/toolbar.d.ts +1 -0
- package/dist/components/Accordion/Accordion.js +8 -1
- package/dist/components/Accordion/Accordion.js.map +1 -1
- package/dist/components/AppShell/AppShell.d.ts +6 -0
- package/dist/components/AppShell/AppShell.js +34 -4
- package/dist/components/AppShell/AppShell.js.map +1 -1
- package/dist/components/Article/Article.d.ts +11 -4
- package/dist/components/Article/Article.js +13 -0
- package/dist/components/Article/Article.js.map +1 -1
- package/dist/components/AspectRatio/AspectRatio.d.ts +46 -0
- package/dist/components/AspectRatio/AspectRatio.js +33 -0
- package/dist/components/AspectRatio/AspectRatio.js.map +1 -0
- package/dist/components/Avatar/Avatar.d.ts +12 -3
- package/dist/components/Avatar/Avatar.js +6 -1
- package/dist/components/Avatar/Avatar.js.map +1 -1
- package/dist/components/Breadcrumb/Breadcrumb.d.ts +6 -0
- package/dist/components/Breadcrumb/Breadcrumb.js +15 -0
- package/dist/components/Breadcrumb/Breadcrumb.js.map +1 -1
- package/dist/components/Button/Button.js +14 -0
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Calendar/Calendar.d.ts +29 -3
- package/dist/components/Calendar/Calendar.js +60 -12
- package/dist/components/Calendar/Calendar.js.map +1 -1
- package/dist/components/Card/Card.d.ts +6 -0
- package/dist/components/Card/Card.js +1 -1
- package/dist/components/Card/Card.js.map +1 -1
- package/dist/components/Checkbox/Checkbox.d.ts +5 -2
- package/dist/components/Checkbox/Checkbox.js +12 -2
- package/dist/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/components/Code/Code.d.ts +30 -0
- package/dist/components/Code/Code.js +21 -0
- package/dist/components/Code/Code.js.map +1 -0
- package/dist/components/CodeBlock/CodeBlock.d.ts +141 -0
- package/dist/components/CodeBlock/CodeBlock.js +123 -0
- package/dist/components/CodeBlock/CodeBlock.js.map +1 -0
- package/dist/components/Collapsible/Collapsible.js +10 -2
- package/dist/components/Collapsible/Collapsible.js.map +1 -1
- package/dist/components/Combobox/Combobox.d.ts +15 -1
- package/dist/components/Combobox/Combobox.js +25 -5
- package/dist/components/Combobox/Combobox.js.map +1 -1
- package/dist/components/Command/Command.d.ts +4 -2
- package/dist/components/Command/Command.js +13 -1
- package/dist/components/Command/Command.js.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.d.ts +30 -5
- package/dist/components/ContextMenu/ContextMenu.js +32 -2
- package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
- package/dist/components/DatePicker/DatePicker.d.ts +36 -4
- package/dist/components/DatePicker/DatePicker.js +55 -12
- package/dist/components/DatePicker/DatePicker.js.map +1 -1
- package/dist/components/DescriptionList/DescriptionList.d.ts +73 -0
- package/dist/components/DescriptionList/DescriptionList.js +35 -0
- package/dist/components/DescriptionList/DescriptionList.js.map +1 -0
- package/dist/components/Diagram/Diagram.d.ts +8 -3
- package/dist/components/Diagram/Diagram.js +82 -10
- package/dist/components/Diagram/Diagram.js.map +1 -1
- package/dist/components/Dialog/Dialog.d.ts +18 -3
- package/dist/components/Dialog/Dialog.js +20 -2
- package/dist/components/Dialog/Dialog.js.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.d.ts +49 -11
- package/dist/components/DropdownMenu/DropdownMenu.js +32 -2
- package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/components/EmptyState/EmptyState.d.ts +25 -1
- package/dist/components/EmptyState/EmptyState.js +3 -1
- package/dist/components/EmptyState/EmptyState.js.map +1 -1
- package/dist/components/ErrorState/ErrorState.d.ts +22 -1
- package/dist/components/ErrorState/ErrorState.js +11 -2
- package/dist/components/ErrorState/ErrorState.js.map +1 -1
- package/dist/components/Field/Field.d.ts +70 -3
- package/dist/components/Field/Field.js +53 -12
- package/dist/components/Field/Field.js.map +1 -1
- package/dist/components/Field/field-control.d.ts +31 -0
- package/dist/components/Field/field-control.js +12 -0
- package/dist/components/Field/field-control.js.map +1 -0
- package/dist/components/FloatingIconButton/FloatingIconButton.js +2 -0
- package/dist/components/FloatingIconButton/FloatingIconButton.js.map +1 -1
- package/dist/components/Heading/Heading.d.ts +62 -0
- package/dist/components/Heading/Heading.js +44 -0
- package/dist/components/Heading/Heading.js.map +1 -0
- package/dist/components/Markdown/Markdown.d.ts +139 -0
- package/dist/components/Markdown/Markdown.js +135 -0
- package/dist/components/Markdown/Markdown.js.map +1 -0
- package/dist/components/Markdown/inline.d.ts +29 -0
- package/dist/components/Markdown/inline.js +74 -0
- package/dist/components/Markdown/inline.js.map +1 -0
- package/dist/components/Markdown/nodes.d.ts +65 -0
- package/dist/components/Markdown/nodes.js +1 -0
- package/dist/components/Markdown/nodes.js.map +1 -0
- package/dist/components/Markdown/parse.d.ts +24 -0
- package/dist/components/Markdown/parse.js +110 -0
- package/dist/components/Markdown/parse.js.map +1 -0
- package/dist/components/Markdown/slug.d.ts +15 -0
- package/dist/components/Markdown/slug.js +7 -0
- package/dist/components/Markdown/slug.js.map +1 -0
- package/dist/components/NativeSelect/NativeSelect.d.ts +6 -0
- package/dist/components/NativeSelect/NativeSelect.js +2 -3
- package/dist/components/NativeSelect/NativeSelect.js.map +1 -1
- package/dist/components/Pagination/Pagination.d.ts +24 -1
- package/dist/components/Pagination/Pagination.js +6 -3
- package/dist/components/Pagination/Pagination.js.map +1 -1
- package/dist/components/Progress/Progress.d.ts +17 -5
- package/dist/components/Progress/Progress.js +18 -6
- package/dist/components/Progress/Progress.js.map +1 -1
- package/dist/components/RadioGroup/RadioGroup.d.ts +6 -0
- package/dist/components/RadioGroup/RadioGroup.js +11 -1
- package/dist/components/RadioGroup/RadioGroup.js.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.d.ts +15 -0
- package/dist/components/ScrollArea/ScrollArea.js +2 -2
- package/dist/components/ScrollArea/ScrollArea.js.map +1 -1
- package/dist/components/SearchableMenu/SearchableMenu.d.ts +11 -2
- package/dist/components/SearchableMenu/SearchableMenu.js +24 -2
- package/dist/components/SearchableMenu/SearchableMenu.js.map +1 -1
- package/dist/components/Select/Select.d.ts +18 -2
- package/dist/components/Select/Select.js +20 -3
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Separator/Separator.d.ts +21 -3
- package/dist/components/Separator/Separator.js +9 -1
- package/dist/components/Separator/Separator.js.map +1 -1
- package/dist/components/Sheet/Sheet.d.ts +3 -0
- package/dist/components/Sheet/Sheet.js +11 -2
- package/dist/components/Sheet/Sheet.js.map +1 -1
- package/dist/components/Skeleton/Skeleton.d.ts +8 -1
- package/dist/components/Skeleton/Skeleton.js +1 -1
- package/dist/components/Skeleton/Skeleton.js.map +1 -1
- package/dist/components/Slider/Slider.d.ts +21 -3
- package/dist/components/Slider/Slider.js +54 -27
- package/dist/components/Slider/Slider.js.map +1 -1
- package/dist/components/Spinner/Spinner.d.ts +8 -0
- package/dist/components/Spinner/Spinner.js +3 -2
- package/dist/components/Spinner/Spinner.js.map +1 -1
- package/dist/components/StatusPill/StatusPill.d.ts +5 -0
- package/dist/components/StatusPill/StatusPill.js +6 -0
- package/dist/components/StatusPill/StatusPill.js.map +1 -1
- package/dist/components/Table/Table.d.ts +6 -0
- package/dist/components/Table/Table.js +3 -1
- package/dist/components/Table/Table.js.map +1 -1
- package/dist/components/Tag/Tag.d.ts +68 -9
- package/dist/components/Tag/Tag.js +50 -10
- package/dist/components/Tag/Tag.js.map +1 -1
- package/dist/components/Text/Text.d.ts +62 -0
- package/dist/components/Text/Text.js +30 -0
- package/dist/components/Text/Text.js.map +1 -0
- package/dist/components/Timestamp/Timestamp.d.ts +59 -0
- package/dist/components/Timestamp/Timestamp.js +56 -0
- package/dist/components/Timestamp/Timestamp.js.map +1 -0
- package/dist/components/Toast/Toast.d.ts +9 -1
- package/dist/components/Toast/Toast.js +27 -4
- package/dist/components/Toast/Toast.js.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroup.d.ts +6 -1
- package/dist/components/ToggleGroup/ToggleGroup.js +11 -1
- package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
- package/dist/components/Toolbar/Toolbar.d.ts +55 -0
- package/dist/components/Toolbar/Toolbar.js +43 -0
- package/dist/components/Toolbar/Toolbar.js.map +1 -0
- package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.d.ts +6 -0
- package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js +48 -8
- package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js.map +1 -1
- package/dist/diagrams/DataflowFigure/DataflowFigure.js +21 -2
- package/dist/diagrams/DataflowFigure/DataflowFigure.js.map +1 -1
- package/dist/diagrams/DiagramCanvas/DiagramCanvas.d.ts +14 -0
- package/dist/diagrams/DiagramCanvas/DiagramCanvas.js +14 -7
- package/dist/diagrams/DiagramCanvas/DiagramCanvas.js.map +1 -1
- package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.d.ts +38 -4
- package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js +14 -16
- package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js.map +1 -1
- package/dist/diagrams/DiagramInspector/DiagramInspector.js +2 -2
- package/dist/diagrams/DiagramInspector/DiagramInspector.js.map +1 -1
- package/dist/diagrams/DiagramMinimap/DiagramMinimap.d.ts +23 -7
- package/dist/diagrams/DiagramMinimap/DiagramMinimap.js +45 -18
- package/dist/diagrams/DiagramMinimap/DiagramMinimap.js.map +1 -1
- package/dist/diagrams/LifecycleFigure/LifecycleFigure.js +44 -12
- package/dist/diagrams/LifecycleFigure/LifecycleFigure.js.map +1 -1
- package/dist/diagrams/SequenceFigure/SequenceFigure.js +35 -5
- package/dist/diagrams/SequenceFigure/SequenceFigure.js.map +1 -1
- package/dist/diagrams/WorkflowFigure/WorkflowFigure.d.ts +3 -1
- package/dist/diagrams/WorkflowFigure/WorkflowFigure.js +76 -28
- package/dist/diagrams/WorkflowFigure/WorkflowFigure.js.map +1 -1
- package/dist/diagrams/index.d.ts +1 -0
- package/dist/diagrams/index.js +10 -0
- package/dist/diagrams/index.js.map +1 -1
- package/dist/diagrams/lib/dev.d.ts +61 -0
- package/dist/diagrams/lib/dev.js +96 -0
- package/dist/diagrams/lib/dev.js.map +1 -0
- package/dist/diagrams/lib/frame.d.ts +48 -7
- package/dist/diagrams/lib/frame.js +17 -2
- package/dist/diagrams/lib/frame.js.map +1 -1
- package/dist/diagrams/lib/wires.js.map +1 -1
- package/dist/diagrams/spec.d.ts +64 -12
- package/dist/index.d.ts +16 -4
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/keyframes.css +57 -3
- package/dist/lib/overlay-container.d.ts +14 -4
- package/dist/lib/overlay-container.js.map +1 -1
- package/dist/lib/warn.d.ts +73 -0
- package/dist/lib/warn.js +38 -0
- package/dist/lib/warn.js.map +1 -0
- package/dist/semantic.css +17 -6
- package/dist/styles.css +1 -1
- package/dist/tokens.css +20 -2
- package/dist/tokens.d.ts +1 -1
- package/dist/tokens.js +39 -36
- package/dist/tokens.json +39 -36
- package/llms.txt +35 -0
- package/package.json +5 -2
- package/skills/misoto22-design/evals/evals.json +84 -0
- package/skills/misoto22-design/rules/a11y.md +55 -3
- package/skills/misoto22-design/rules/forms.md +5 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/charts/BarChart/BarChart.tsx"],"sourcesContent":["'use client'\n\nimport {\n Children,\n createContext,\n isValidElement,\n useCallback,\n useContext,\n useId,\n useMemo,\n useState,\n type ComponentProps,\n type ReactNode,\n} from 'react'\nimport {\n Bar as RechartsBar,\n BarChart as RechartsBarChart,\n CartesianGrid,\n Rectangle,\n XAxis as RechartsXAxis,\n YAxis as RechartsYAxis,\n} from 'recharts'\nimport type { RectRadius } from 'recharts/types/shape/Rectangle'\nimport { motion, useReducedMotion } from 'motion/react'\nimport { ChartContainer, type ChartConfig } from '../lib/chart'\nimport { ChartFigure } from '../lib/figure'\nimport { ChartEmpty, type ChartEmptyProps } from '../lib/empty'\nimport { axisLabel } from '../lib/axis'\nimport { defaultTick } from '../lib/format'\nimport { Annotation, ReferenceBand, ReferenceLine } from '../lib/annotations'\nimport { Values, findSlot, resolveValues, type ValuesProps } from '../lib/values'\nimport {\n ChartSonifyButton,\n Sonify,\n useChartSonifySeries,\n type SonifyProps,\n} from '../lib/sonify-control'\n\n/**\n * The axis props, with `label` narrowed to a string.\n *\n * Recharts' own `label` accepts a render function and a config object, neither\n * of which a call site should be reaching for to name an axis — and both of\n * which would let a consumer opt out of the system's own axis type styling\n * without noticing.\n */\nexport type ChartXAxisProps = Omit<ComponentProps<typeof RechartsXAxis>, 'label'> & {\n /** What this axis measures. Say the unit here or in the series label, once. */\n label?: string\n}\n\nexport type ChartYAxisProps = Omit<ComponentProps<typeof RechartsYAxis>, 'label'> & {\n /** What this axis measures. Say the unit here or in the series label, once. */\n label?: string\n}\n\nimport { ChartBackground, type ChartBackgroundVariant } from '../lib/background'\nimport { ChartLegend, ChartLegendContent } from '../lib/legend'\nimport { ChartTooltip, ChartTooltipContent } from '../lib/tooltip'\nimport { Brush, ChartBrush, type BrushProps, type ChartBrushRange } from '../lib/brush'\nimport { ChartControls, Toolbar, type ToolbarProps } from '../lib/toolbar'\nimport { useChartZoom } from '../lib/zoom'\nimport { LoadingIndicator, LoadingShimmer, LOADING_KEY, useLoadingRows } from '../lib/loading'\nimport {\n BarBufferFill,\n BarDuotoneFill,\n BarGradientFill,\n BarHatchedFill,\n BarStrippedFill,\n GlowFilter,\n REVEAL_EASE,\n SeriesGradient,\n type ChartRevealType,\n} from '../lib/paint'\nimport type { ChartLegendSlotProps, ChartTooltipSlotProps } from '../AreaChart/AreaChart'\n\n/** The corner every bar rounds to unless it says otherwise. */\nconst BAR_RADIUS = 2\n\n/** One bar's grow-in, in seconds. */\nconst GROW_DURATION = 0.5\n\n/** How long each bar waits behind the one before it. */\nconst GROW_STAGGER = 0.05\n\nconst STACK_ID = 'm22-bar-stack'\n\n/**\n * Room around the plot, so the first and last tick labels are not sliced by the\n * container's edge. Recharts' own default is 5px on every side, which is not\n * enough for a label centred on the axis's first point.\n */\nconst CHART_MARGIN = { top: 8, right: 12, bottom: 0, left: 12 }\n\n/** How a bar meets the plot. The primary carrier of identity in monochrome. */\nexport type BarVariant = 'default' | 'hatched' | 'duotone' | 'duotone-reverse' | 'gradient' | 'stripped'\n\n/** How several bars combine: side by side, stacked, or normalised to 100%. */\nexport type BarStackType = 'default' | 'stacked' | 'percent'\n\n/**\n * Which way the bars run.\n *\n * `vertical` stands them up from a category axis along the bottom — the default,\n * and what a time series wants. `horizontal` lays them out from a category axis\n * down the side, which is what long category NAMES want: a label that would be\n * rotated 45° to fit under a column reads straight beside a row.\n */\nexport type BarOrientation = 'vertical' | 'horizontal'\n\ninterface BarChartContextValue {\n config: ChartConfig\n /** The rows on screen, so a mark can label its own extremes. */\n rows: Record<string, unknown>[]\n isStacked: boolean\n isHorizontal: boolean\n isLoading: boolean\n barRadius: number\n animationType: ChartRevealType\n introStartedAt: number\n dataLength: number\n selectedDataKey: string | null\n selectDataKey: (dataKey: string | null) => void\n isPointerInChart: boolean\n}\n\nconst BarChartContext = createContext<BarChartContextValue | null>(null)\n\nfunction useBarChart(): BarChartContextValue {\n const context = useContext(BarChartContext)\n if (!context) throw new Error('A bar chart part must be rendered inside <BarChart>')\n return context\n}\n\ntype ValidateKeys<TData, TConfig> = {\n [K in keyof TConfig]: K extends keyof TData ? ChartConfig[string] : never\n}\n\nexport interface BarChartProps<\n TData extends Record<string, unknown>,\n TConfig extends Record<string, ChartConfig[string]>,\n> {\n config: TConfig & ValidateKeys<TData, TConfig>\n /** The rows the chart draws. One entry per point, bar or category. */\n data: TData[]\n /**\n * What the chart shows, in a sentence a reader could act on. Required, and\n * announced to a screen reader even when it is not printed.\n */\n title: string\n /** Prints the title above the plot instead of hiding it from sight. */\n showTitle?: boolean\n /** A line under the title — the unit, the window, the caveat. */\n description?: ReactNode\n /**\n * The composed parts — axes, grid, tooltip, legend, and the marks\n * themselves.\n */\n children: ReactNode\n /** Merged onto the figure, last, so a call site can size or space it. */\n className?: string\n /** Escape hatch onto the raw Recharts chart element. */\n chartProps?: ComponentProps<typeof RechartsBarChart>\n /** How several marks combine: side by side, stacked, or normalised to 100%. */\n stackType?: BarStackType\n /**\n * Which way the bars run. Reach for `horizontal` when the category names are\n * long enough to need rotating under a column.\n */\n orientation?: BarOrientation\n /** The corner every `<BarChart.Bar>` inherits. */\n barRadius?: number\n /** The grow-in order every `<BarChart.Bar>` inherits. */\n animationType?: ChartRevealType\n /** Gap between bars inside one category. */\n barGap?: number\n /** Gap between categories. */\n barCategoryGap?: number\n /** The series lit on first render. Selection dims every other series. */\n defaultSelectedDataKey?: string | null\n /** Fires when the selection changes, and with null when it is cleared. */\n onSelectionChange?: (selectedDataKey: string | null) => void\n /**\n * Swaps the marks for an animated skeleton, keeping the measured height so\n * the page does not jump when the data lands.\n */\n isLoading?: boolean\n /** How many bars the skeleton draws. */\n loadingBars?: number\n /**\n * The row field on the category axis. Needed by the brush and by the table\n * view.\n */\n xDataKey?: keyof TData & string\n /**\n * Drops the hidden table view. Only correct when the page prints the data\n * itself.\n */\n hideDataTable?: boolean\n /**\n * What the chart shows when it has nothing to draw.\n *\n * Rendered instead of the plot whenever `data` is empty and the chart is not\n * loading — the state a real dashboard reaches within a week, and the one an\n * empty pair of axes is indistinguishable from a failed load. `false` keeps\n * the axes, for a chart whose emptiness is itself the reading.\n */\n empty?: ChartEmptyProps | false\n}\n\n/**\n * Discrete categories compared by length — the shape for \"how much, per thing\".\n *\n * Reach for `<AreaChart>` or `<LineChart>` when the axis is continuous and the\n * reader is following a trend rather than comparing buckets.\n *\n * @example\n * <BarChart title=\"Visitors by month\" config={config} data={data} xDataKey=\"month\">\n * <BarChart.Grid />\n * <BarChart.XAxis dataKey=\"month\" />\n * <BarChart.Tooltip />\n * <BarChart.Bar dataKey=\"desktop\" variant=\"duotone\" />\n * </BarChart>\n */\nexport function BarChart<\n TData extends Record<string, unknown>,\n TConfig extends Record<string, ChartConfig[string]>,\n>({\n config,\n data,\n title,\n showTitle,\n description,\n children,\n className,\n chartProps,\n stackType = 'default',\n orientation = 'vertical',\n barRadius = BAR_RADIUS,\n animationType = 'forward',\n barGap,\n barCategoryGap,\n defaultSelectedDataKey = null,\n onSelectionChange,\n isLoading = false,\n loadingBars,\n xDataKey,\n hideDataTable = false,\n empty,\n}: BarChartProps<TData, TConfig>) {\n const chartId = useId().replace(/:/g, '')\n // Stamped once, on the first render. The grow-in reads elapsed time from\n // here rather than from mount, because Recharts remounts every bar on any\n // re-render — a mount-anchored animation would replay on every hover.\n const [introStartedAt] = useState(() => Date.now())\n const [selectedDataKey, setSelectedDataKey] = useState<string | null>(defaultSelectedDataKey)\n const [isPointerInChart, setIsPointerInChart] = useState(false)\n const { rows: loadingData, onShimmerExit } = useLoadingRows(isLoading, loadingBars ?? 12)\n // One window, two views of it: the brush strip below the plot and the\n // toolbar above it both read and write this. See `useChartZoom` for why they\n // are not two separate windows.\n const zoom = useChartZoom({ data, xDataKey })\n\n // The brush, the toolbar and the sonify control are declared as children but\n // never rendered into the Recharts tree — they live in the figure, outside\n // the SVG.\n const { brushSlot, toolbarSlot, sonifySlot, chartChildren } = useMemo(() => {\n const parts = Children.toArray(children)\n const element = parts.find((child) => isValidElement(child) && child.type === Brush)\n const props = (isValidElement(element) ? element.props : {}) as BrushProps\n return {\n brushSlot: { present: isValidElement(element), ...props },\n toolbarSlot: findSlot<ToolbarProps>(parts, Toolbar),\n sonifySlot: findSlot<SonifyProps>(parts, Sonify),\n chartChildren: parts.filter(\n (child) =>\n !(\n isValidElement(child) &&\n (child.type === Brush || child.type === Toolbar || child.type === Sonify)\n ),\n ),\n }\n }, [children])\n\n const isStacked = stackType === 'stacked' || stackType === 'percent'\n const isHorizontal = orientation === 'horizontal'\n const columns = useMemo(\n () => Object.entries(config).map(([key, series]) => ({ key, label: series.label })),\n [config],\n )\n\n const showBrush = brushSlot.present && !isLoading\n const showToolbar = toolbarSlot !== null && !isLoading\n // `empty === false` keeps the axes, for a chart whose emptiness is the\n // reading — a monitoring panel that should show a flat, silent range rather\n // than a message.\n const isEmpty = !isLoading && empty !== false && data.length === 0\n const displayData = showBrush || showToolbar ? zoom.visibleData : data\n\n // The rows on screen, so a brushed range sounds like what it looks like. The\n // skeleton's rows carry no real series, which is what leaves the control\n // disabled while data is in flight rather than playing yesterday's numbers.\n const sonifySeries = useChartSonifySeries(\n sonifySlot,\n (isLoading ? loadingData : displayData) as Record<string, unknown>[],\n config,\n xDataKey,\n )\n\n const selectDataKey = useCallback(\n (next: string | null) => {\n setSelectedDataKey(next)\n onSelectionChange?.(next)\n },\n [onSelectionChange],\n )\n\n const context = useMemo<BarChartContextValue>(\n () => ({\n config,\n rows: displayData as Record<string, unknown>[],\n isStacked,\n isHorizontal,\n isLoading,\n barRadius,\n animationType,\n introStartedAt,\n dataLength: displayData.length,\n selectedDataKey,\n selectDataKey,\n isPointerInChart,\n }),\n [\n animationType,\n barRadius,\n config,\n displayData,\n introStartedAt,\n isHorizontal,\n isLoading,\n isPointerInChart,\n isStacked,\n selectDataKey,\n selectedDataKey,\n ],\n )\n\n return (\n <BarChartContext.Provider value={context}>\n <ChartFigure\n title={title}\n showTitle={showTitle}\n description={description}\n className={className}\n table={\n hideDataTable\n ? false\n : { rows: data, rowKey: xDataKey, columns }\n }\n >\n {sonifySlot && (\n <ChartSonifyButton {...sonifySlot} title={title} series={sonifySeries} />\n )}\n {isEmpty ? (\n <ChartEmpty {...(empty || {})} />\n ) : (\n <ChartControls\n toolbar={showToolbar ? toolbarSlot : null}\n zoom={zoom}\n title={title}\n rows={data}\n columns={columns}\n rowKey={xDataKey}\n >\n <ChartContainer\n config={config}\n footer={\n showBrush && (\n <ChartBrush\n data={data}\n config={config}\n xDataKey={xDataKey}\n variant=\"bar\"\n barRadius={barRadius}\n height={brushSlot.height}\n formatLabel={brushSlot.formatLabel}\n stacked={isStacked}\n className=\"mt-1\"\n {...zoom.brushProps}\n onChange={(range: ChartBrushRange) => {\n zoom.brushProps.onChange(range)\n brushSlot.onChange?.(range)\n }}\n />\n )\n }\n >\n <RechartsBarChart\n id={chartId}\n accessibilityLayer\n margin={CHART_MARGIN}\n // Recharts' `layout` names the axis the CATEGORIES run along, which\n // is the opposite of what a reader means by a horizontal bar chart.\n // The flip is done once, here.\n layout={isHorizontal ? 'vertical' : 'horizontal'}\n data={isLoading ? loadingData : displayData}\n barGap={barGap}\n barCategoryGap={barCategoryGap}\n stackOffset={stackType === 'percent' ? 'expand' : undefined}\n onMouseEnter={() => setIsPointerInChart(true)}\n onMouseLeave={() => setIsPointerInChart(false)}\n {...chartProps}\n >\n {chartChildren}\n {isLoading && <LoadingBar chartId={chartId} onShimmerExit={onShimmerExit} />}\n </RechartsBarChart>\n </ChartContainer>\n </ChartControls>\n )}\n <LoadingIndicator isLoading={isLoading} />\n </ChartFigure>\n </BarChartContext.Provider>\n )\n}\n\nexport interface BarProps {\n dataKey: string\n variant?: BarVariant\n radius?: number\n animationType?: ChartRevealType\n /** Lets a click on this series select it, dimming the rest. */\n isClickable?: boolean\n /** Dims this series while another bar in the same column is hovered. */\n enableHoverHighlight?: boolean\n /** A halo behind the bars — for the one series that is the point of the figure. */\n glowing?: boolean\n /**\n * Draws the LAST category as an open hatch rather than a solid bar.\n *\n * The idiom for a period still in progress: the bar is the same height as any\n * other but is visibly not the same kind of fact.\n */\n buffer?: boolean\n /** `<BarChart.Values>`. */\n children?: ReactNode\n barProps?: ComponentProps<typeof RechartsBar>\n}\n\n/**\n * One bar series. Scopes its own patterns under a unique id, so any number of\n * series with different variants can share a chart.\n */\nfunction Bar({\n dataKey,\n variant = 'default',\n radius,\n animationType,\n isClickable = false,\n enableHoverHighlight = false,\n glowing = false,\n buffer = false,\n children,\n barProps,\n}: BarProps) {\n const {\n config,\n isStacked,\n isHorizontal,\n isLoading,\n rows,\n barRadius: defaultRadius,\n animationType: defaultAnimation,\n introStartedAt,\n dataLength,\n selectedDataKey,\n selectDataKey,\n isPointerInChart,\n } = useBarChart()\n const id = useId().replace(/:/g, '')\n const reduceMotion = useReducedMotion()\n\n if (isLoading) return null\n\n const resolvedRadius = radius ?? defaultRadius\n const isSelected = selectedDataKey === dataKey\n const reveal: ChartRevealType = reduceMotion ? 'none' : (animationType ?? defaultAnimation)\n\n const shared = {\n id,\n dataKey,\n variant,\n barRadius: resolvedRadius,\n glowing,\n buffer,\n isClickable,\n enableHoverHighlight,\n isPointerInChart,\n isHorizontal,\n introStartedAt,\n selectedDataKey,\n dataLength,\n onSelect: () => {\n if (!isClickable) return\n selectDataKey(isSelected ? null : dataKey)\n },\n }\n\n return (\n <>\n <RechartsBar\n dataKey={dataKey}\n stackId={isStacked ? STACK_ID : undefined}\n fill={`url(#${id}-colors-${dataKey})`}\n radius={resolvedRadius}\n isAnimationActive={false}\n style={isClickable || enableHoverHighlight ? { cursor: 'pointer' } : undefined}\n shape={(props: unknown) => (\n <BarShape {...(props as BarGeometry)} {...shared} animationType={reveal} />\n )}\n // The hovered bar re-renders through `activeBar`; without forcing the\n // animation off here it would replay its grow-in under the pointer.\n activeBar={(props: unknown) => (\n <BarShape {...(props as BarGeometry)} {...shared} animationType=\"none\" />\n )}\n {...barProps}\n >\n {resolveValues(\n findSlot<ValuesProps>(children, Values),\n rows.map((row) => Number(row[dataKey])).filter(Number.isFinite),\n )}\n </RechartsBar>\n <defs>\n <SeriesGradient id={id} dataKey={dataKey} config={config} direction=\"vertical\" />\n {variant === 'hatched' && <BarHatchedFill id={id} dataKey={dataKey} />}\n {variant === 'duotone' && <BarDuotoneFill id={id} dataKey={dataKey} config={config} />}\n {variant === 'duotone-reverse' && (\n <BarDuotoneFill id={id} dataKey={dataKey} config={config} reverse />\n )}\n {variant === 'gradient' && <BarGradientFill id={id} dataKey={dataKey} />}\n {variant === 'stripped' && <BarStrippedFill id={id} dataKey={dataKey} />}\n {buffer && <BarBufferFill id={id} dataKey={dataKey} />}\n {glowing && <GlowFilter id={id} dataKey={dataKey} />}\n </defs>\n </>\n )\n}\n\n/** The geometry Recharts hands a custom bar shape. */\ninterface BarGeometry {\n x?: number\n y?: number\n width?: number\n height?: number\n index?: number\n isActive?: boolean\n [key: string]: unknown\n}\n\ninterface BarShapeProps extends BarGeometry {\n id: string\n dataKey: string\n variant: BarVariant\n barRadius: number\n glowing: boolean\n buffer: boolean\n isClickable: boolean\n enableHoverHighlight: boolean\n isPointerInChart: boolean\n isHorizontal: boolean\n animationType: ChartRevealType\n introStartedAt: number\n selectedDataKey: string | null\n dataLength: number\n onSelect: () => void\n}\n\n/**\n * One drawn bar.\n *\n * Two rectangles, and the second one is the reason this is a custom shape: an\n * invisible full-height rect keeps the whole COLUMN hoverable and clickable, so\n * a 3px bar at the bottom of the scale is as easy to hit as a full-height one.\n * The painted bar sits inside it and is the only part that animates.\n */\nfunction BarShape(props: BarShapeProps) {\n const {\n x = 0,\n y = 0,\n width = 0,\n height = 0,\n id,\n dataKey,\n variant,\n barRadius,\n glowing,\n buffer,\n isClickable,\n enableHoverHighlight,\n isPointerInChart,\n isHorizontal,\n animationType,\n introStartedAt,\n selectedDataKey,\n isActive,\n dataLength,\n onSelect,\n } = props\n\n const index = typeof props.index === 'number' ? props.index : -1\n const isBufferBar = buffer && dataLength > 0 && index === dataLength - 1\n const isStripped = variant === 'stripped'\n const grow = growAnimation(animationType, index, dataLength, isHorizontal, introStartedAt)\n\n const fill = isBufferBar ? `url(#${id}-buffer-${dataKey})` : variantFill(variant, id, dataKey)\n const opacity = barOpacity({\n isClickable,\n selectedDataKey,\n dataKey,\n enableHoverHighlight,\n isPointerInChart,\n isActive,\n })\n\n // Stripped rounds only the cap; every other variant rounds all four corners.\n const radius: RectRadius = isStripped ? [barRadius, barRadius, 0, 0] : barRadius\n\n const painted = (\n <>\n <Rectangle\n x={x}\n y={y}\n width={width}\n // Three pixels off the foot, which is the 2px surface gap between a bar\n // and its neighbour above in a stack, plus the hairline.\n height={Math.max(0, height - 3)}\n opacity={opacity}\n radius={radius}\n fill={fill}\n filter={glowing ? `url(#${id}-glow-${dataKey})` : undefined}\n stroke={isBufferBar ? `url(#${id}-colors-${dataKey})` : undefined}\n strokeWidth={isBufferBar ? 1 : undefined}\n />\n {isStripped && (\n <Rectangle\n x={x}\n y={y - 4}\n width={width}\n height={2}\n radius={1}\n fill={`url(#${id}-colors-${dataKey})`}\n />\n )}\n </>\n )\n\n return (\n <g\n style={isClickable || enableHoverHighlight ? { cursor: 'pointer' } : undefined}\n onClick={onSelect}\n >\n <Rectangle {...props} fill=\"transparent\" />\n {grow ? (\n <motion.g\n initial={grow.initial}\n animate={grow.animate}\n transition={grow.transition}\n style={grow.style}\n >\n {painted}\n </motion.g>\n ) : (\n painted\n )}\n </g>\n )\n}\n\n/**\n * The grow-in for a single bar, or `null` when it should render static.\n *\n * The animation is anchored to when the CHART started rather than to when this\n * bar mounted, because Recharts remounts every bar on every re-render — a hover\n * anywhere in the plot would otherwise replay the whole intro. Reading elapsed\n * time makes it a true one-shot: a bar past its window renders flat, and a bar\n * caught mid-grow resumes from where it should already be.\n */\nfunction growAnimation(\n animationType: ChartRevealType,\n index: number,\n dataLength: number,\n isHorizontal: boolean,\n introStartedAt: number,\n) {\n if (animationType === 'none' || index < 0 || dataLength <= 0) return null\n\n const lastIndex = dataLength - 1\n const centre = lastIndex / 2\n\n let step: number\n switch (animationType) {\n case 'reverse':\n step = lastIndex - index\n break\n case 'center-out':\n step = Math.abs(index - centre)\n break\n case 'edges-in':\n step = centre - Math.abs(index - centre)\n break\n default:\n step = index\n }\n\n const startMs = step * GROW_STAGGER * 1000\n const endMs = startMs + GROW_DURATION * 1000\n const elapsed = Date.now() - introStartedAt\n\n if (elapsed >= endMs) return null\n\n const from = elapsed <= startMs ? 0 : (elapsed - startMs) / (GROW_DURATION * 1000)\n const transition = {\n duration: (endMs - Math.max(elapsed, startMs)) / 1000,\n ease: REVEAL_EASE,\n delay: Math.max(0, startMs - elapsed) / 1000,\n }\n\n return isHorizontal\n ? { initial: { scaleX: from }, animate: { scaleX: 1 }, transition, style: { originX: 0 } }\n : { initial: { scaleY: from }, animate: { scaleY: 1 }, transition, style: { originY: 1 } }\n}\n\n/** The paint reference for a variant. */\nfunction variantFill(variant: BarVariant, id: string, dataKey: string): string {\n if (variant === 'default') return `url(#${id}-colors-${dataKey})`\n return `url(#${id}-${variant}-${dataKey})`\n}\n\n/** How lit a bar is, given the click selection and the hover highlight. */\nfunction barOpacity({\n isClickable,\n selectedDataKey,\n dataKey,\n enableHoverHighlight,\n isPointerInChart,\n isActive,\n}: {\n isClickable: boolean\n selectedDataKey: string | null\n dataKey: string\n enableHoverHighlight: boolean\n isPointerInChart: boolean\n isActive?: boolean\n}) {\n const inSelection = selectedDataKey === null || selectedDataKey === dataKey\n const selectionOpacity = isClickable && selectedDataKey !== null ? (inSelection ? 1 : 0.15) : 1\n\n if (enableHoverHighlight && isPointerInChart) {\n return isActive ? selectionOpacity : selectionOpacity * 0.3\n }\n return selectionOpacity\n}\n\n/**\n * The category axis when the bars stand up, the value axis when they lie down.\n * The type is resolved from the orientation so a consumer never has to know\n * which way round Recharts wants it.\n */\nfunction XAxis({\n tickLine = false,\n axisLine = false,\n tickMargin = 8,\n minTickGap = 8,\n type,\n label,\n ...rest\n}: ChartXAxisProps) {\n const { isLoading, isHorizontal } = useBarChart()\n if (isLoading) return null\n return (\n <RechartsXAxis\n tickLine={tickLine}\n axisLine={axisLine}\n tickMargin={tickMargin}\n minTickGap={minTickGap}\n type={type ?? (isHorizontal ? 'number' : 'category')}\n {...rest}\n >\n {axisLabel(label, 'x')}\n </RechartsXAxis>\n )\n}\n\n/** The other axis, resolved the same way. */\nfunction YAxis({\n tickLine = false,\n axisLine = false,\n tickMargin = 8,\n minTickGap = 8,\n width = 'auto',\n type,\n label,\n tickFormatter,\n ...rest\n}: ChartYAxisProps) {\n const { isLoading, isHorizontal } = useBarChart()\n if (isLoading) return null\n return (\n <RechartsYAxis\n tickLine={tickLine}\n axisLine={axisLine}\n tickMargin={tickMargin}\n minTickGap={minTickGap}\n width={width}\n type={type ?? (isHorizontal ? 'category' : 'number')}\n tickFormatter={tickFormatter ?? defaultTick}\n {...rest}\n >\n {axisLabel(label, 'y')}\n </RechartsYAxis>\n )\n}\n\n/** Rules across the value axis — whichever axis that is for this orientation. */\nfunction Grid({\n strokeDasharray = '3 3',\n vertical,\n horizontal,\n ...rest\n}: ComponentProps<typeof CartesianGrid>) {\n const { isHorizontal } = useBarChart()\n return (\n <CartesianGrid\n strokeDasharray={strokeDasharray}\n vertical={vertical ?? isHorizontal}\n horizontal={horizontal ?? !isHorizontal}\n {...rest}\n />\n )\n}\n\n/**\n * The hover panel.\n *\n * No crosshair by default, unlike the line and area charts: a bar already marks\n * its own category, and a cursor over it draws a second edge on a shape that\n * has four already.\n */\nfunction Tooltip({ variant, roundness, defaultIndex, cursor = false }: ChartTooltipSlotProps) {\n const { isLoading, selectedDataKey } = useBarChart()\n if (isLoading) return null\n\n return (\n <ChartTooltip\n cursor={cursor}\n defaultIndex={defaultIndex}\n content={\n <ChartTooltipContent selected={selectedDataKey} roundness={roundness} variant={variant} />\n }\n />\n )\n}\n\n/** The key. Required above one series. */\nfunction Legend({\n variant,\n align = 'right',\n verticalAlign = 'top',\n isClickable = false,\n}: ChartLegendSlotProps) {\n const { selectedDataKey, selectDataKey } = useBarChart()\n\n return (\n <ChartLegend\n verticalAlign={verticalAlign}\n align={align}\n content={\n <ChartLegendContent\n selected={selectedDataKey}\n onSelectChange={selectDataKey}\n isClickable={isClickable}\n variant={variant}\n />\n }\n />\n )\n}\n\n/** The decorative plate behind the plot. */\nfunction Background({ variant }: { variant: ChartBackgroundVariant }) {\n const { isLoading } = useBarChart()\n if (isLoading) return null\n return <ChartBackground variant={variant} />\n}\n\n/** The skeleton drawn in place of the real bars while data is in flight. */\nfunction LoadingBar({ chartId, onShimmerExit }: { chartId: string; onShimmerExit: () => void }) {\n return (\n <>\n <RechartsBar\n dataKey={LOADING_KEY}\n fill=\"currentColor\"\n fillOpacity={0.15}\n radius={BAR_RADIUS}\n isAnimationActive={false}\n legendType=\"none\"\n className=\"text-(--ink)\"\n style={{ mask: `url(#${chartId}-loading-mask)` }}\n />\n <defs>\n <LoadingShimmer id={chartId} onShimmerExit={onShimmerExit} />\n </defs>\n </>\n )\n}\n\nBarChart.Bar = Bar\nBarChart.XAxis = XAxis\nBarChart.YAxis = YAxis\nBarChart.Grid = Grid\nBarChart.Tooltip = Tooltip\nBarChart.Legend = Legend\nBarChart.Background = Background\nBarChart.ReferenceLine = ReferenceLine\nBarChart.ReferenceBand = ReferenceBand\nBarChart.Annotation = Annotation\nBarChart.Values = Values\nBarChart.Brush = Brush\nBarChart.Toolbar = Toolbar\nBarChart.Sonify = Sonify\n\nexport default BarChart\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/charts/BarChart/BarChart.tsx"],"sourcesContent":["'use client'\n\nimport {\n Children,\n createContext,\n isValidElement,\n useContext,\n useId,\n useMemo,\n useState,\n type ComponentProps,\n type ReactNode,\n} from 'react'\nimport {\n Bar as RechartsBar,\n BarChart as RechartsBarChart,\n CartesianGrid,\n Rectangle,\n XAxis as RechartsXAxis,\n YAxis as RechartsYAxis,\n} from 'recharts'\nimport type { RectRadius } from 'recharts/types/shape/Rectangle'\nimport { motion, useReducedMotion } from 'motion/react'\nimport { ChartContainer, type ChartConfig } from '../lib/chart'\nimport { ChartFigure } from '../lib/figure'\nimport { useChartSelection } from '../lib/selection'\nimport { type ChartEmptyProps } from '../lib/empty'\nimport { axisLabel } from '../lib/axis'\nimport { defaultTick } from '../lib/format'\nimport { Annotation, ReferenceBand, ReferenceLine } from '../lib/annotations'\nimport { Values, findSlot, resolveValues, type ValuesProps } from '../lib/values'\nimport {\n ChartSonifyButton,\n Sonify,\n useChartSonifySeries,\n type SonifyProps,\n} from '../lib/sonify-control'\n\n/**\n * The axis props, with `label` narrowed to a string.\n *\n * Recharts' own `label` accepts a render function and a config object, neither\n * of which a call site should be reaching for to name an axis — and both of\n * which would let a consumer opt out of the system's own axis type styling\n * without noticing.\n */\nexport type ChartXAxisProps = Omit<ComponentProps<typeof RechartsXAxis>, 'label'> & {\n /** What this axis measures. Say the unit here or in the series label, once. */\n label?: string\n}\n\nexport type ChartYAxisProps = Omit<ComponentProps<typeof RechartsYAxis>, 'label'> & {\n /** What this axis measures. Say the unit here or in the series label, once. */\n label?: string\n}\n\nimport { ChartBackground, type ChartBackgroundVariant } from '../lib/background'\nimport { ChartLegend, ChartLegendContent } from '../lib/legend'\nimport { ChartTooltip, ChartTooltipContent } from '../lib/tooltip'\nimport { Brush, ChartBrush, type BrushProps, type ChartBrushRange } from '../lib/brush'\nimport { ChartControls, Toolbar, type ToolbarProps } from '../lib/toolbar'\nimport { useChartZoom } from '../lib/zoom'\nimport { LoadingIndicator, LoadingShimmer, LOADING_KEY, useLoadingRows } from '../lib/loading'\nimport {\n BarBufferFill,\n BarDuotoneFill,\n BarGradientFill,\n BarHatchedFill,\n BarStrippedFill,\n GlowFilter,\n REVEAL_EASE,\n SeriesGradient,\n type ChartRevealType,\n} from '../lib/paint'\nimport type { ChartLegendSlotProps, ChartTooltipSlotProps } from '../AreaChart/AreaChart'\n\n/** The corner every bar rounds to unless it says otherwise. */\nconst BAR_RADIUS = 2\n\n/** One bar's grow-in, in seconds. */\nconst GROW_DURATION = 0.5\n\n/** How long each bar waits behind the one before it. */\nconst GROW_STAGGER = 0.05\n\nconst STACK_ID = 'm22-bar-stack'\n\n/**\n * Room around the plot, so the first and last tick labels are not sliced by the\n * container's edge. Recharts' own default is 5px on every side, which is not\n * enough for a label centred on the axis's first point.\n */\nconst CHART_MARGIN = { top: 8, right: 12, bottom: 0, left: 12 }\n\n/**\n * The gap between a bar's foot and its neighbour below in a stack, plus the\n * hairline.\n */\nconst FOOT_GAP = 3\n\n/**\n * The shortest a bar with a value on it may be drawn.\n *\n * Below `FOOT_GAP` the trim used to take the whole bar: a count of two on a\n * scale topping out at a thousand rendered at zero height and was\n * pixel-identical to a category with no rows at all. The full-column hit rect\n * still caught the pointer, so the reader could hover a bar that was not there.\n * One pixel is not much of a bar, and it is the difference between \"small\" and\n * \"absent\" — which is the whole reading.\n */\nconst MIN_BAR_LENGTH = 1\n\n/** How a bar meets the plot. The primary carrier of identity in monochrome. */\nexport type BarVariant = 'default' | 'hatched' | 'duotone' | 'duotone-reverse' | 'gradient' | 'stripped'\n\n/** How several bars combine: side by side, stacked, or normalised to 100%. */\nexport type BarStackType = 'default' | 'stacked' | 'percent'\n\n/**\n * Which way the bars run.\n *\n * `vertical` stands them up from a category axis along the bottom — the default,\n * and what a time series wants. `horizontal` lays them out from a category axis\n * down the side, which is what long category NAMES want: a label that would be\n * rotated 45° to fit under a column reads straight beside a row.\n */\nexport type BarOrientation = 'vertical' | 'horizontal'\n\ninterface BarChartContextValue {\n config: ChartConfig\n /** The rows on screen, so a mark can label its own extremes. */\n rows: Record<string, unknown>[]\n isStacked: boolean\n isHorizontal: boolean\n isLoading: boolean\n barRadius: number\n animationType: ChartRevealType\n introStartedAt: number\n dataLength: number\n /**\n * Where the last row of `data` sits in the window on screen, or -1 when it is\n * outside it. What `buffer` hatches.\n */\n bufferIndex: number\n selectedDataKey: string | null\n selectDataKey: (dataKey: string | null) => void\n isPointerInChart: boolean\n}\n\nconst BarChartContext = createContext<BarChartContextValue | null>(null)\n\nfunction useBarChart(): BarChartContextValue {\n const context = useContext(BarChartContext)\n if (!context) throw new Error('A bar chart part must be rendered inside <BarChart>')\n return context\n}\n\ntype ValidateKeys<TData, TConfig> = {\n [K in keyof TConfig]: K extends keyof TData ? ChartConfig[string] : never\n}\n\nexport interface BarChartProps<\n TData extends Record<string, unknown>,\n TConfig extends Record<string, ChartConfig[string]>,\n> {\n config: TConfig & ValidateKeys<TData, TConfig>\n /** The rows the chart draws. One entry per point, bar or category. */\n data: TData[]\n /**\n * What the chart shows, in a sentence a reader could act on. Required, and\n * announced to a screen reader even when it is not printed.\n */\n title: string\n /** Prints the title above the plot instead of hiding it from sight. */\n showTitle?: boolean\n /** A line under the title — the unit, the window, the caveat. */\n description?: ReactNode\n /**\n * The composed parts — axes, grid, tooltip, legend, and the marks\n * themselves.\n */\n children: ReactNode\n /** Merged onto the figure, last, so a call site can size or space it. */\n className?: string\n /** Escape hatch onto the raw Recharts chart element. */\n chartProps?: ComponentProps<typeof RechartsBarChart>\n /** How several marks combine: side by side, stacked, or normalised to 100%. */\n stackType?: BarStackType\n /**\n * Which way the bars run. Reach for `horizontal` when the category names are\n * long enough to need rotating under a column.\n */\n orientation?: BarOrientation\n /** The corner every `<BarChart.Bar>` inherits. */\n barRadius?: number\n /** The grow-in order every `<BarChart.Bar>` inherits. */\n animationType?: ChartRevealType\n /** Gap between bars inside one category. */\n barGap?: number\n /** Gap between categories. */\n barCategoryGap?: number\n /** The series lit on first render, when the chart keeps its own selection. */\n defaultSelectedDataKey?: string | null\n /**\n * The selected series, driven from outside.\n *\n * Give this and the chart follows it; leave it undefined and the chart keeps\n * its own, starting from `defaultSelectedDataKey`.\n */\n selectedDataKey?: string | null\n /** Fires when the selection changes, and with null when it is cleared. */\n onSelectionChange?: (selectedDataKey: string | null) => void\n /**\n * Swaps the marks for an animated skeleton, keeping the measured height so\n * the page does not jump when the data lands.\n */\n isLoading?: boolean\n /** How many bars the skeleton draws. */\n loadingBars?: number\n /**\n * The row field on the category axis. Needed by the brush and by the table\n * view.\n */\n xDataKey?: keyof TData & string\n /**\n * Drops the hidden table view. Only correct when the page prints the data\n * itself.\n */\n hideDataTable?: boolean\n /**\n * What the chart shows when it has nothing to draw.\n *\n * Rendered instead of the plot whenever `data` is empty and the chart is not\n * loading — the state a real dashboard reaches within a week, and the one an\n * empty pair of axes is indistinguishable from a failed load. `false` keeps\n * the axes, for a chart whose emptiness is itself the reading.\n */\n empty?: ChartEmptyProps | false\n}\n\n/**\n * Discrete categories compared by length — the shape for \"how much, per thing\".\n *\n * Reach for `<AreaChart>` or `<LineChart>` when the axis is continuous and the\n * reader is following a trend rather than comparing buckets.\n *\n * @example\n * <BarChart title=\"Visitors by month\" config={config} data={data} xDataKey=\"month\">\n * <BarChart.Grid />\n * <BarChart.XAxis dataKey=\"month\" />\n * <BarChart.Tooltip />\n * <BarChart.Bar dataKey=\"desktop\" variant=\"duotone\" />\n * </BarChart>\n */\nexport function BarChart<\n TData extends Record<string, unknown>,\n TConfig extends Record<string, ChartConfig[string]>,\n>({\n config,\n data,\n title,\n showTitle,\n description,\n children,\n className,\n chartProps,\n stackType = 'default',\n orientation = 'vertical',\n barRadius = BAR_RADIUS,\n animationType = 'forward',\n barGap,\n barCategoryGap,\n defaultSelectedDataKey = null,\n selectedDataKey: controlledDataKey,\n onSelectionChange,\n isLoading = false,\n loadingBars,\n xDataKey,\n hideDataTable = false,\n empty,\n}: BarChartProps<TData, TConfig>) {\n const chartId = useId().replace(/:/g, '')\n // Stamped once, on the first render. The grow-in reads elapsed time from\n // here rather than from mount, because Recharts remounts every bar on any\n // re-render — a mount-anchored animation would replay on every hover.\n const [introStartedAt] = useState(() => Date.now())\n const [isPointerInChart, setIsPointerInChart] = useState(false)\n const { rows: loadingData, onShimmerExit } = useLoadingRows(isLoading, loadingBars ?? 12)\n // One window, two views of it: the brush strip below the plot and the\n // toolbar above it both read and write this. See `useChartZoom` for why they\n // are not two separate windows.\n const zoom = useChartZoom({ data, xDataKey })\n\n // The brush, the toolbar and the sonify control are declared as children but\n // never rendered into the Recharts tree — they live in the figure, outside\n // the SVG.\n const { brushSlot, toolbarSlot, sonifySlot, chartChildren } = useMemo(() => {\n const parts = Children.toArray(children)\n const element = parts.find((child) => isValidElement(child) && child.type === Brush)\n const props = (isValidElement(element) ? element.props : {}) as BrushProps\n return {\n brushSlot: { present: isValidElement(element), ...props },\n toolbarSlot: findSlot<ToolbarProps>(parts, Toolbar),\n sonifySlot: findSlot<SonifyProps>(parts, Sonify),\n chartChildren: parts.filter(\n (child) =>\n !(\n isValidElement(child) &&\n (child.type === Brush || child.type === Toolbar || child.type === Sonify)\n ),\n ),\n }\n }, [children])\n\n const isStacked = stackType === 'stacked' || stackType === 'percent'\n const isHorizontal = orientation === 'horizontal'\n const columns = useMemo(\n () => Object.entries(config).map(([key, series]) => ({ key, label: series.label })),\n [config],\n )\n\n const showBrush = brushSlot.present && !isLoading\n const showToolbar = toolbarSlot !== null && !isLoading\n // `empty === false` keeps the axes, for a chart whose emptiness is the\n // reading — a monitoring panel that should show a flat, silent range rather\n // than a message.\n const isEmpty = !isLoading && empty !== false && data.length === 0\n const displayData = showBrush || showToolbar ? zoom.visibleData : data\n\n // Which bar on screen is the open period, if any is. Derived from the last\n // ROW rather than from the last bar drawn: brushed or zoomed back into the\n // middle of the range, the last bar in the window is a month that closed long\n // ago, and hatching it says it is still being counted.\n const bufferIndex =\n data.length > 0 && displayData[displayData.length - 1] === data[data.length - 1]\n ? displayData.length - 1\n : -1\n\n // The rows on screen, so a brushed range sounds like what it looks like. The\n // skeleton's rows carry no real series, which is what leaves the control\n // disabled while data is in flight rather than playing yesterday's numbers.\n const sonifySeries = useChartSonifySeries(\n sonifySlot,\n (isLoading ? loadingData : displayData) as Record<string, unknown>[],\n config,\n xDataKey,\n )\n\n const [selectedDataKey, selectDataKey] = useChartSelection(\n controlledDataKey,\n defaultSelectedDataKey,\n onSelectionChange,\n )\n\n const context = useMemo<BarChartContextValue>(\n () => ({\n config,\n rows: displayData as Record<string, unknown>[],\n isStacked,\n isHorizontal,\n isLoading,\n barRadius,\n animationType,\n introStartedAt,\n dataLength: displayData.length,\n bufferIndex,\n selectedDataKey,\n selectDataKey,\n isPointerInChart,\n }),\n [\n animationType,\n barRadius,\n bufferIndex,\n config,\n displayData,\n introStartedAt,\n isHorizontal,\n isLoading,\n isPointerInChart,\n isStacked,\n selectDataKey,\n selectedDataKey,\n ],\n )\n\n return (\n <BarChartContext.Provider value={context}>\n <ChartFigure\n title={title}\n showTitle={showTitle}\n description={description}\n className={className}\n table={\n hideDataTable\n ? false\n : { rows: data, rowKey: xDataKey, columns }\n }\n isEmpty={isEmpty}\n empty={empty}\n >\n {sonifySlot && (\n <ChartSonifyButton {...sonifySlot} title={title} series={sonifySeries} />\n )}\n <ChartControls\n toolbar={showToolbar ? toolbarSlot : null}\n zoom={zoom}\n title={title}\n rows={data}\n columns={columns}\n rowKey={xDataKey}\n >\n <ChartContainer\n config={config}\n footer={\n showBrush && (\n <ChartBrush\n data={data}\n config={config}\n xDataKey={xDataKey}\n variant=\"bar\"\n barRadius={barRadius}\n height={brushSlot.height}\n formatLabel={brushSlot.formatLabel}\n stacked={isStacked}\n className=\"mt-1\"\n {...zoom.brushProps}\n onChange={(range: ChartBrushRange) => {\n zoom.brushProps.onChange(range)\n brushSlot.onChange?.(range)\n }}\n />\n )\n }\n >\n <RechartsBarChart\n id={chartId}\n accessibilityLayer\n margin={CHART_MARGIN}\n // Recharts' `layout` names the axis the CATEGORIES run along, which\n // is the opposite of what a reader means by a horizontal bar chart.\n // The flip is done once, here.\n layout={isHorizontal ? 'vertical' : 'horizontal'}\n data={isLoading ? loadingData : displayData}\n barGap={barGap}\n barCategoryGap={barCategoryGap}\n stackOffset={stackType === 'percent' ? 'expand' : undefined}\n onMouseEnter={() => setIsPointerInChart(true)}\n onMouseLeave={() => setIsPointerInChart(false)}\n {...chartProps}\n >\n {chartChildren}\n {isLoading && <LoadingBar chartId={chartId} onShimmerExit={onShimmerExit} />}\n </RechartsBarChart>\n </ChartContainer>\n </ChartControls>\n <LoadingIndicator isLoading={isLoading} />\n </ChartFigure>\n </BarChartContext.Provider>\n )\n}\n\nexport interface BarProps {\n dataKey: string\n variant?: BarVariant\n radius?: number\n animationType?: ChartRevealType\n /** Lets a click on this series select it, dimming the rest. */\n isClickable?: boolean\n /** Dims this series while another bar in the same column is hovered. */\n enableHoverHighlight?: boolean\n /** A halo behind the bars — for the one series that is the point of the figure. */\n glowing?: boolean\n /**\n * Draws the last row of `data` as an open hatch rather than a solid bar.\n *\n * The idiom for a period still in progress: the bar is the same height as any\n * other but is visibly not the same kind of fact.\n *\n * Tied to the last ROW, not to the last bar on screen. Brush or zoom into the\n * middle of the range and no bar is hatched, because none of the periods in\n * the window is still being counted.\n */\n buffer?: boolean\n /** `<BarChart.Values>`. */\n children?: ReactNode\n barProps?: ComponentProps<typeof RechartsBar>\n}\n\n/**\n * One bar series. Scopes its own patterns under a unique id, so any number of\n * series with different variants can share a chart.\n */\nfunction Bar({\n dataKey,\n variant = 'default',\n radius,\n animationType,\n isClickable = false,\n enableHoverHighlight = false,\n glowing = false,\n buffer = false,\n children,\n barProps,\n}: BarProps) {\n const {\n config,\n isStacked,\n isHorizontal,\n isLoading,\n rows,\n barRadius: defaultRadius,\n animationType: defaultAnimation,\n introStartedAt,\n dataLength,\n bufferIndex,\n selectedDataKey,\n selectDataKey,\n isPointerInChart,\n } = useBarChart()\n const id = useId().replace(/:/g, '')\n const reduceMotion = useReducedMotion()\n\n if (isLoading) return null\n\n const resolvedRadius = radius ?? defaultRadius\n const isSelected = selectedDataKey === dataKey\n const reveal: ChartRevealType = reduceMotion ? 'none' : (animationType ?? defaultAnimation)\n\n const shared = {\n id,\n dataKey,\n variant,\n barRadius: resolvedRadius,\n glowing,\n buffer,\n isClickable,\n enableHoverHighlight,\n isPointerInChart,\n isHorizontal,\n introStartedAt,\n selectedDataKey,\n dataLength,\n bufferIndex,\n onSelect: () => {\n if (!isClickable) return\n selectDataKey(isSelected ? null : dataKey)\n },\n }\n\n return (\n <>\n <RechartsBar\n dataKey={dataKey}\n stackId={isStacked ? STACK_ID : undefined}\n fill={`url(#${id}-colors-${dataKey})`}\n radius={resolvedRadius}\n isAnimationActive={false}\n style={isClickable || enableHoverHighlight ? { cursor: 'pointer' } : undefined}\n shape={(props: unknown) => (\n <BarShape {...(props as BarGeometry)} {...shared} animationType={reveal} />\n )}\n // The hovered bar re-renders through `activeBar`; without forcing the\n // animation off here it would replay its grow-in under the pointer.\n activeBar={(props: unknown) => (\n <BarShape {...(props as BarGeometry)} {...shared} animationType=\"none\" />\n )}\n {...barProps}\n >\n {resolveValues(\n findSlot<ValuesProps>(children, Values),\n rows.map((row) => Number(row[dataKey])).filter(Number.isFinite),\n )}\n </RechartsBar>\n <defs>\n <SeriesGradient id={id} dataKey={dataKey} config={config} direction=\"vertical\" />\n {variant === 'hatched' && <BarHatchedFill id={id} dataKey={dataKey} />}\n {variant === 'duotone' && <BarDuotoneFill id={id} dataKey={dataKey} config={config} />}\n {variant === 'duotone-reverse' && (\n <BarDuotoneFill id={id} dataKey={dataKey} config={config} reverse />\n )}\n {variant === 'gradient' && <BarGradientFill id={id} dataKey={dataKey} />}\n {variant === 'stripped' && <BarStrippedFill id={id} dataKey={dataKey} />}\n {buffer && <BarBufferFill id={id} dataKey={dataKey} />}\n {glowing && <GlowFilter id={id} dataKey={dataKey} />}\n </defs>\n </>\n )\n}\n\n/** The geometry Recharts hands a custom bar shape. */\ninterface BarGeometry {\n x?: number\n y?: number\n width?: number\n height?: number\n index?: number\n isActive?: boolean\n [key: string]: unknown\n}\n\ninterface BarShapeProps extends BarGeometry {\n id: string\n dataKey: string\n variant: BarVariant\n barRadius: number\n glowing: boolean\n buffer: boolean\n isClickable: boolean\n enableHoverHighlight: boolean\n isPointerInChart: boolean\n isHorizontal: boolean\n animationType: ChartRevealType\n introStartedAt: number\n selectedDataKey: string | null\n dataLength: number\n bufferIndex: number\n onSelect: () => void\n}\n\n/**\n * One drawn bar.\n *\n * Two rectangles, and the second one is the reason this is a custom shape: an\n * invisible full-height rect keeps the whole COLUMN hoverable and clickable, so\n * a 3px bar at the bottom of the scale is as easy to hit as a full-height one.\n * The painted bar sits inside it and is the only part that animates.\n */\nfunction BarShape(props: BarShapeProps) {\n const {\n x = 0,\n y = 0,\n width = 0,\n height = 0,\n id,\n dataKey,\n variant,\n barRadius,\n glowing,\n buffer,\n isClickable,\n enableHoverHighlight,\n isPointerInChart,\n isHorizontal,\n animationType,\n introStartedAt,\n selectedDataKey,\n isActive,\n dataLength,\n bufferIndex,\n onSelect,\n } = props\n\n const index = typeof props.index === 'number' ? props.index : -1\n const isBufferBar = buffer && index >= 0 && index === bufferIndex\n const isStripped = variant === 'stripped'\n const grow = growAnimation(animationType, index, dataLength, isHorizontal, introStartedAt)\n\n const fill = isBufferBar ? `url(#${id}-buffer-${dataKey})` : variantFill(variant, id, dataKey)\n const opacity = barOpacity({\n isClickable,\n selectedDataKey,\n dataKey,\n enableHoverHighlight,\n isPointerInChart,\n isActive,\n })\n\n // Stripped rounds only the cap; every other variant rounds all four corners.\n const radius: RectRadius = isStripped ? [barRadius, barRadius, 0, 0] : barRadius\n\n const painted = (\n <>\n <Rectangle\n x={x}\n y={y}\n width={width}\n // Three pixels off the foot, which is the 2px surface gap between a bar\n // and its neighbour above in a stack, plus the hairline — but never all\n // the way to nothing while there is still a bar to draw.\n height={height <= 0 ? 0 : Math.max(MIN_BAR_LENGTH, height - FOOT_GAP)}\n opacity={opacity}\n radius={radius}\n fill={fill}\n filter={glowing ? `url(#${id}-glow-${dataKey})` : undefined}\n stroke={isBufferBar ? `url(#${id}-colors-${dataKey})` : undefined}\n strokeWidth={isBufferBar ? 1 : undefined}\n />\n {isStripped && (\n <Rectangle\n x={x}\n y={y - 4}\n width={width}\n height={2}\n radius={1}\n fill={`url(#${id}-colors-${dataKey})`}\n />\n )}\n </>\n )\n\n return (\n <g\n style={isClickable || enableHoverHighlight ? { cursor: 'pointer' } : undefined}\n onClick={onSelect}\n >\n <Rectangle {...props} fill=\"transparent\" />\n {grow ? (\n <motion.g\n initial={grow.initial}\n animate={grow.animate}\n transition={grow.transition}\n style={grow.style}\n >\n {painted}\n </motion.g>\n ) : (\n painted\n )}\n </g>\n )\n}\n\n/**\n * The grow-in for a single bar, or `null` when it should render static.\n *\n * The animation is anchored to when the CHART started rather than to when this\n * bar mounted, because Recharts remounts every bar on every re-render — a hover\n * anywhere in the plot would otherwise replay the whole intro. Reading elapsed\n * time makes it a true one-shot: a bar past its window renders flat, and a bar\n * caught mid-grow resumes from where it should already be.\n */\nfunction growAnimation(\n animationType: ChartRevealType,\n index: number,\n dataLength: number,\n isHorizontal: boolean,\n introStartedAt: number,\n) {\n if (animationType === 'none' || index < 0 || dataLength <= 0) return null\n\n const lastIndex = dataLength - 1\n const centre = lastIndex / 2\n\n let step: number\n switch (animationType) {\n case 'reverse':\n step = lastIndex - index\n break\n case 'center-out':\n step = Math.abs(index - centre)\n break\n case 'edges-in':\n step = centre - Math.abs(index - centre)\n break\n default:\n step = index\n }\n\n const startMs = step * GROW_STAGGER * 1000\n const endMs = startMs + GROW_DURATION * 1000\n const elapsed = Date.now() - introStartedAt\n\n if (elapsed >= endMs) return null\n\n const from = elapsed <= startMs ? 0 : (elapsed - startMs) / (GROW_DURATION * 1000)\n const transition = {\n duration: (endMs - Math.max(elapsed, startMs)) / 1000,\n ease: REVEAL_EASE,\n delay: Math.max(0, startMs - elapsed) / 1000,\n }\n\n return isHorizontal\n ? { initial: { scaleX: from }, animate: { scaleX: 1 }, transition, style: { originX: 0 } }\n : { initial: { scaleY: from }, animate: { scaleY: 1 }, transition, style: { originY: 1 } }\n}\n\n/** The paint reference for a variant. */\nfunction variantFill(variant: BarVariant, id: string, dataKey: string): string {\n if (variant === 'default') return `url(#${id}-colors-${dataKey})`\n return `url(#${id}-${variant}-${dataKey})`\n}\n\n/** How lit a bar is, given the click selection and the hover highlight. */\nfunction barOpacity({\n isClickable,\n selectedDataKey,\n dataKey,\n enableHoverHighlight,\n isPointerInChart,\n isActive,\n}: {\n isClickable: boolean\n selectedDataKey: string | null\n dataKey: string\n enableHoverHighlight: boolean\n isPointerInChart: boolean\n isActive?: boolean\n}) {\n const inSelection = selectedDataKey === null || selectedDataKey === dataKey\n const selectionOpacity = isClickable && selectedDataKey !== null ? (inSelection ? 1 : 0.15) : 1\n\n if (enableHoverHighlight && isPointerInChart) {\n return isActive ? selectionOpacity : selectionOpacity * 0.3\n }\n return selectionOpacity\n}\n\n/**\n * The category axis when the bars stand up, the value axis when they lie down.\n * The type is resolved from the orientation so a consumer never has to know\n * which way round Recharts wants it.\n */\nfunction XAxis({\n tickLine = false,\n axisLine = false,\n tickMargin = 8,\n minTickGap = 8,\n type,\n label,\n ...rest\n}: ChartXAxisProps) {\n const { isLoading, isHorizontal } = useBarChart()\n if (isLoading) return null\n return (\n <RechartsXAxis\n tickLine={tickLine}\n axisLine={axisLine}\n tickMargin={tickMargin}\n minTickGap={minTickGap}\n type={type ?? (isHorizontal ? 'number' : 'category')}\n {...rest}\n >\n {axisLabel(label, 'x')}\n </RechartsXAxis>\n )\n}\n\n/** The other axis, resolved the same way. */\nfunction YAxis({\n tickLine = false,\n axisLine = false,\n tickMargin = 8,\n minTickGap = 8,\n width = 'auto',\n type,\n label,\n tickFormatter,\n ...rest\n}: ChartYAxisProps) {\n const { isLoading, isHorizontal } = useBarChart()\n if (isLoading) return null\n return (\n <RechartsYAxis\n tickLine={tickLine}\n axisLine={axisLine}\n tickMargin={tickMargin}\n minTickGap={minTickGap}\n width={width}\n type={type ?? (isHorizontal ? 'category' : 'number')}\n tickFormatter={tickFormatter ?? defaultTick}\n {...rest}\n >\n {axisLabel(label, 'y')}\n </RechartsYAxis>\n )\n}\n\n/** Rules across the value axis — whichever axis that is for this orientation. */\nfunction Grid({\n strokeDasharray = '3 3',\n vertical,\n horizontal,\n ...rest\n}: ComponentProps<typeof CartesianGrid>) {\n const { isHorizontal } = useBarChart()\n return (\n <CartesianGrid\n strokeDasharray={strokeDasharray}\n vertical={vertical ?? isHorizontal}\n horizontal={horizontal ?? !isHorizontal}\n {...rest}\n />\n )\n}\n\n/**\n * The hover panel.\n *\n * No crosshair by default, unlike the line and area charts: a bar already marks\n * its own category, and a cursor over it draws a second edge on a shape that\n * has four already.\n */\nfunction Tooltip({ variant, roundness, defaultIndex, cursor = false }: ChartTooltipSlotProps) {\n const { isLoading, selectedDataKey } = useBarChart()\n if (isLoading) return null\n\n return (\n <ChartTooltip\n cursor={cursor}\n defaultIndex={defaultIndex}\n content={\n <ChartTooltipContent selected={selectedDataKey} roundness={roundness} variant={variant} />\n }\n />\n )\n}\n\n/** The key. Required above one series. */\nfunction Legend({\n variant,\n align = 'right',\n verticalAlign = 'top',\n isClickable = false,\n}: ChartLegendSlotProps) {\n const { selectedDataKey, selectDataKey } = useBarChart()\n\n return (\n <ChartLegend\n verticalAlign={verticalAlign}\n align={align}\n content={\n <ChartLegendContent\n selected={selectedDataKey}\n onSelectChange={selectDataKey}\n isClickable={isClickable}\n variant={variant}\n />\n }\n />\n )\n}\n\n/** The decorative plate behind the plot. */\nfunction Background({ variant }: { variant: ChartBackgroundVariant }) {\n const { isLoading } = useBarChart()\n if (isLoading) return null\n return <ChartBackground variant={variant} />\n}\n\n/** The skeleton drawn in place of the real bars while data is in flight. */\nfunction LoadingBar({ chartId, onShimmerExit }: { chartId: string; onShimmerExit: () => void }) {\n return (\n <>\n <RechartsBar\n dataKey={LOADING_KEY}\n fill=\"currentColor\"\n fillOpacity={0.15}\n radius={BAR_RADIUS}\n isAnimationActive={false}\n legendType=\"none\"\n className=\"text-(--ink)\"\n style={{ mask: `url(#${chartId}-loading-mask)` }}\n />\n <defs>\n <LoadingShimmer id={chartId} onShimmerExit={onShimmerExit} />\n </defs>\n </>\n )\n}\n\nBarChart.Bar = Bar\nBarChart.XAxis = XAxis\nBarChart.YAxis = YAxis\nBarChart.Grid = Grid\nBarChart.Tooltip = Tooltip\nBarChart.Legend = Legend\nBarChart.Background = Background\nBarChart.ReferenceLine = ReferenceLine\nBarChart.ReferenceBand = ReferenceBand\nBarChart.Annotation = Annotation\nBarChart.Values = Values\nBarChart.Brush = Brush\nBarChart.Toolbar = Toolbar\nBarChart.Sonify = Sonify\n\nexport default BarChart\n"],"mappings":"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","names":[]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
+
import { ChartEmptyProps } from '../lib/empty.js';
|
|
3
4
|
|
|
4
5
|
interface BarListItem {
|
|
5
6
|
/** What the row is. Doubles as its key, so it must be unique. */
|
|
@@ -31,6 +32,13 @@ interface BarListProps {
|
|
|
31
32
|
/** Sorts descending before rendering. */
|
|
32
33
|
sort?: boolean;
|
|
33
34
|
className?: string;
|
|
35
|
+
/**
|
|
36
|
+
* What the list shows when it has nothing to rank.
|
|
37
|
+
*
|
|
38
|
+
* A caption over an empty `<tbody>` is a list that failed to load as far as
|
|
39
|
+
* the reader can tell, and the reader's next move is to reload the page.
|
|
40
|
+
*/
|
|
41
|
+
empty?: ChartEmptyProps;
|
|
34
42
|
}
|
|
35
43
|
/**
|
|
36
44
|
* A ranked list, with the bar behind the name rather than beside it.
|
|
@@ -52,6 +60,6 @@ interface BarListProps {
|
|
|
52
60
|
* @example
|
|
53
61
|
* <BarList label="Top referrers" items={referrers} limit={5} />
|
|
54
62
|
*/
|
|
55
|
-
declare function BarList({ label, showLabel, items, limit, formatValue, max, sort, className, }: BarListProps): react.JSX.Element;
|
|
63
|
+
declare function BarList({ label, showLabel, items, limit, formatValue, max, sort, className, empty, }: BarListProps): react.JSX.Element;
|
|
56
64
|
|
|
57
65
|
export { BarList, type BarListItem, type BarListProps, BarList as default };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "../../lib/cn.js";
|
|
3
|
+
import { ChartEmpty } from "../lib/empty.js";
|
|
3
4
|
import { defaultTick } from "../lib/format.js";
|
|
4
5
|
function BarList({
|
|
5
6
|
label,
|
|
@@ -9,7 +10,8 @@ function BarList({
|
|
|
9
10
|
formatValue = defaultTick,
|
|
10
11
|
max,
|
|
11
12
|
sort = true,
|
|
12
|
-
className
|
|
13
|
+
className,
|
|
14
|
+
empty
|
|
13
15
|
}) {
|
|
14
16
|
const ordered = sort ? [...items].sort((a, b) => b.value - a.value) : items;
|
|
15
17
|
const shown = limit !== void 0 && ordered.length > limit ? [
|
|
@@ -20,6 +22,12 @@ function BarList({
|
|
|
20
22
|
}
|
|
21
23
|
] : ordered;
|
|
22
24
|
const ceiling = max ?? Math.max(1, ...shown.map((item) => item.value));
|
|
25
|
+
if (shown.length === 0) {
|
|
26
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex w-full flex-col gap-2", className), children: [
|
|
27
|
+
/* @__PURE__ */ jsx("p", { className: cn("text-start", showLabel ? "mb-2 eyebrow text-(--ink-3-aa)" : "sr-only"), children: label }),
|
|
28
|
+
/* @__PURE__ */ jsx(ChartEmpty, { ...empty || {} })
|
|
29
|
+
] });
|
|
30
|
+
}
|
|
23
31
|
return /* @__PURE__ */ jsx("div", { className: cn("flex w-full flex-col gap-2", className), children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-sm", children: [
|
|
24
32
|
/* @__PURE__ */ jsx(
|
|
25
33
|
"caption",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/charts/BarList/BarList.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport { defaultTick } from '../lib/format'\n\nexport interface BarListItem {\n /** What the row is. Doubles as its key, so it must be unique. */\n name: string\n value: number\n /** Turns the row's name into a link. */\n href?: string\n /** Drawn before the name — a favicon, a status dot, a flag. */\n icon?: ReactNode\n}\n\nexport interface BarListProps {\n /** What the list ranks. Required: it names the table for a screen reader. */\n label: string\n /** Prints the label above the list instead of hiding it from sight. */\n showLabel?: boolean\n items: BarListItem[]\n /** Keeps the top N and folds the rest into one \"Other\" row. */\n limit?: number\n /** Formats each value. Defaults to the same compact form the axes use. */\n formatValue?: (value: number) => string\n /**\n * The scale's ceiling. Derived from the largest row when omitted.\n *\n * Pin it to compare two lists side by side — on independent scales the\n * leading row of each fills its track, and two very different numbers look\n * identical.\n */\n max?: number\n /** Sorts descending before rendering. */\n sort?: boolean\n className?: string\n}\n\n/**\n * A ranked list, with the bar behind the name rather than beside it.\n *\n * The answer to \"top referrers\", \"slowest endpoints\", \"biggest accounts\" — and\n * a better one than a horizontal bar chart, which spends a third of its width\n * on a category axis repeating labels the rows could simply contain. Reading a\n * name off a y-axis and matching it to a bar is two steps; reading it off the\n * bar is none.\n *\n * It is a `<table>`, because that is what it is: two columns, a header, and one\n * row per thing. The bar is a background on the name cell, so it never becomes\n * a second element a screen reader has to walk past.\n *\n * Reach for `<BarChart orientation=\"horizontal\">` instead when the categories\n * are few and fixed and the axis is doing real work — a scale a reader needs to\n * read values off, rather than a ranking they need to skim.\n *\n * @example\n * <BarList label=\"Top referrers\" items={referrers} limit={5} />\n */\nexport function BarList({\n label,\n showLabel = false,\n items,\n limit,\n formatValue = defaultTick,\n max,\n sort = true,\n className,\n}: BarListProps) {\n const ordered = sort ? [...items].sort((a, b) => b.value - a.value) : items\n\n // The tail is summed rather than dropped: a \"top five\" that silently discards\n // the other forty misstates the whole, and the reader has no way to tell.\n const shown =\n limit !== undefined && ordered.length > limit\n ? [\n ...ordered.slice(0, limit),\n {\n name: 'Other',\n value: ordered.slice(limit).reduce((sum, item) => sum + item.value, 0),\n },\n ]\n : ordered\n\n const ceiling = max ?? Math.max(1, ...shown.map((item) => item.value))\n\n return (\n <div className={cn('flex w-full flex-col gap-2', className)}>\n <table className=\"w-full border-collapse text-sm\">\n <caption\n className={cn(\n 'text-start',\n showLabel ? 'mb-2 eyebrow text-(--ink-3-aa)' : 'sr-only',\n )}\n >\n {label}\n </caption>\n <thead className=\"sr-only\">\n <tr>\n <th scope=\"col\">Name</th>\n <th scope=\"col\">Value</th>\n </tr>\n </thead>\n <tbody>\n {shown.map((item) => {\n const share = Math.max(0, Math.min(1, item.value / ceiling))\n\n return (\n <tr key={item.name} className=\"align-middle\">\n <th scope=\"row\" className=\"w-full py-1 pe-3 text-start font-normal\">\n {/* The bar is a background on the cell, not a sibling: an\n empty <div> beside the name would be one more thing in the\n accessibility tree saying nothing. */}\n <span\n className=\"flex h-8 items-center gap-2 rounded-(--radius-sm) px-2 text-(--ink)\"\n style={{\n background: `linear-gradient(to right, color-mix(in srgb, var(--series-1) calc(var(--chart-fill) * 100%), transparent) ${share * 100}%, transparent ${share * 100}%)`,\n }}\n >\n {item.icon && (\n <span aria-hidden className=\"flex shrink-0 items-center text-(--ink-3-aa)\">\n {item.icon}\n </span>\n )}\n {item.href ? (\n <a\n href={item.href}\n className=\"truncate underline-offset-2 hover:underline focus-visible:underline\"\n >\n {item.name}\n </a>\n ) : (\n <span className=\"truncate\">{item.name}</span>\n )}\n </span>\n </th>\n <td className=\"py-1 text-end font-mono text-xs whitespace-nowrap tabular-nums text-(--ink-2)\">\n {formatValue(item.value)}\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n )\n}\n\nexport default BarList\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/charts/BarList/BarList.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport { ChartEmpty, type ChartEmptyProps } from '../lib/empty'\nimport { defaultTick } from '../lib/format'\n\nexport interface BarListItem {\n /** What the row is. Doubles as its key, so it must be unique. */\n name: string\n value: number\n /** Turns the row's name into a link. */\n href?: string\n /** Drawn before the name — a favicon, a status dot, a flag. */\n icon?: ReactNode\n}\n\nexport interface BarListProps {\n /** What the list ranks. Required: it names the table for a screen reader. */\n label: string\n /** Prints the label above the list instead of hiding it from sight. */\n showLabel?: boolean\n items: BarListItem[]\n /** Keeps the top N and folds the rest into one \"Other\" row. */\n limit?: number\n /** Formats each value. Defaults to the same compact form the axes use. */\n formatValue?: (value: number) => string\n /**\n * The scale's ceiling. Derived from the largest row when omitted.\n *\n * Pin it to compare two lists side by side — on independent scales the\n * leading row of each fills its track, and two very different numbers look\n * identical.\n */\n max?: number\n /** Sorts descending before rendering. */\n sort?: boolean\n className?: string\n /**\n * What the list shows when it has nothing to rank.\n *\n * A caption over an empty `<tbody>` is a list that failed to load as far as\n * the reader can tell, and the reader's next move is to reload the page.\n */\n empty?: ChartEmptyProps\n}\n\n/**\n * A ranked list, with the bar behind the name rather than beside it.\n *\n * The answer to \"top referrers\", \"slowest endpoints\", \"biggest accounts\" — and\n * a better one than a horizontal bar chart, which spends a third of its width\n * on a category axis repeating labels the rows could simply contain. Reading a\n * name off a y-axis and matching it to a bar is two steps; reading it off the\n * bar is none.\n *\n * It is a `<table>`, because that is what it is: two columns, a header, and one\n * row per thing. The bar is a background on the name cell, so it never becomes\n * a second element a screen reader has to walk past.\n *\n * Reach for `<BarChart orientation=\"horizontal\">` instead when the categories\n * are few and fixed and the axis is doing real work — a scale a reader needs to\n * read values off, rather than a ranking they need to skim.\n *\n * @example\n * <BarList label=\"Top referrers\" items={referrers} limit={5} />\n */\nexport function BarList({\n label,\n showLabel = false,\n items,\n limit,\n formatValue = defaultTick,\n max,\n sort = true,\n className,\n empty,\n}: BarListProps) {\n const ordered = sort ? [...items].sort((a, b) => b.value - a.value) : items\n\n // The tail is summed rather than dropped: a \"top five\" that silently discards\n // the other forty misstates the whole, and the reader has no way to tell.\n const shown =\n limit !== undefined && ordered.length > limit\n ? [\n ...ordered.slice(0, limit),\n {\n name: 'Other',\n value: ordered.slice(limit).reduce((sum, item) => sum + item.value, 0),\n },\n ]\n : ordered\n\n const ceiling = max ?? Math.max(1, ...shown.map((item) => item.value))\n\n if (shown.length === 0) {\n return (\n <div className={cn('flex w-full flex-col gap-2', className)}>\n <p className={cn('text-start', showLabel ? 'mb-2 eyebrow text-(--ink-3-aa)' : 'sr-only')}>\n {label}\n </p>\n <ChartEmpty {...(empty || {})} />\n </div>\n )\n }\n\n return (\n <div className={cn('flex w-full flex-col gap-2', className)}>\n <table className=\"w-full border-collapse text-sm\">\n <caption\n className={cn(\n 'text-start',\n showLabel ? 'mb-2 eyebrow text-(--ink-3-aa)' : 'sr-only',\n )}\n >\n {label}\n </caption>\n <thead className=\"sr-only\">\n <tr>\n <th scope=\"col\">Name</th>\n <th scope=\"col\">Value</th>\n </tr>\n </thead>\n <tbody>\n {shown.map((item) => {\n const share = Math.max(0, Math.min(1, item.value / ceiling))\n\n return (\n <tr key={item.name} className=\"align-middle\">\n <th scope=\"row\" className=\"w-full py-1 pe-3 text-start font-normal\">\n {/* The bar is a background on the cell, not a sibling: an\n empty <div> beside the name would be one more thing in the\n accessibility tree saying nothing. */}\n <span\n className=\"flex h-8 items-center gap-2 rounded-(--radius-sm) px-2 text-(--ink)\"\n style={{\n background: `linear-gradient(to right, color-mix(in srgb, var(--series-1) calc(var(--chart-fill) * 100%), transparent) ${share * 100}%, transparent ${share * 100}%)`,\n }}\n >\n {item.icon && (\n <span aria-hidden className=\"flex shrink-0 items-center text-(--ink-3-aa)\">\n {item.icon}\n </span>\n )}\n {item.href ? (\n <a\n href={item.href}\n className=\"truncate underline-offset-2 hover:underline focus-visible:underline\"\n >\n {item.name}\n </a>\n ) : (\n <span className=\"truncate\">{item.name}</span>\n )}\n </span>\n </th>\n <td className=\"py-1 text-end font-mono text-xs whitespace-nowrap tabular-nums text-(--ink-2)\">\n {formatValue(item.value)}\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n )\n}\n\nexport default BarList\n"],"mappings":"AA+FM,SACE,KADF;AA9FN,SAAS,UAAU;AACnB,SAAS,kBAAwC;AACjD,SAAS,mBAAmB;AA8DrB,SAAS,QAAQ;AAAA,EACtB;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AACF,GAAiB;AACf,QAAM,UAAU,OAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,IAAI;AAItE,QAAM,QACJ,UAAU,UAAa,QAAQ,SAAS,QACpC;AAAA,IACE,GAAG,QAAQ,MAAM,GAAG,KAAK;AAAA,IACzB;AAAA,MACE,MAAM;AAAA,MACN,OAAO,QAAQ,MAAM,KAAK,EAAE,OAAO,CAAC,KAAK,SAAS,MAAM,KAAK,OAAO,CAAC;AAAA,IACvE;AAAA,EACF,IACA;AAEN,QAAM,UAAU,OAAO,KAAK,IAAI,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC;AAErE,MAAI,MAAM,WAAW,GAAG;AACtB,WACE,qBAAC,SAAI,WAAW,GAAG,8BAA8B,SAAS,GACxD;AAAA,0BAAC,OAAE,WAAW,GAAG,cAAc,YAAY,mCAAmC,SAAS,GACpF,iBACH;AAAA,MACA,oBAAC,cAAY,GAAI,SAAS,CAAC,GAAI;AAAA,OACjC;AAAA,EAEJ;AAEA,SACE,oBAAC,SAAI,WAAW,GAAG,8BAA8B,SAAS,GACxD,+BAAC,WAAM,WAAU,kCACf;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA,YAAY,mCAAmC;AAAA,QACjD;AAAA,QAEC;AAAA;AAAA,IACH;AAAA,IACA,oBAAC,WAAM,WAAU,WACf,+BAAC,QACC;AAAA,0BAAC,QAAG,OAAM,OAAM,kBAAI;AAAA,MACpB,oBAAC,QAAG,OAAM,OAAM,mBAAK;AAAA,OACvB,GACF;AAAA,IACA,oBAAC,WACE,gBAAM,IAAI,CAAC,SAAS;AACnB,YAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,QAAQ,OAAO,CAAC;AAE3D,aACE,qBAAC,QAAmB,WAAU,gBAC5B;AAAA,4BAAC,QAAG,OAAM,OAAM,WAAU,2CAIxB;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO;AAAA,cACL,YAAY,6GAA6G,QAAQ,GAAG,kBAAkB,QAAQ,GAAG;AAAA,YACnK;AAAA,YAEC;AAAA,mBAAK,QACJ,oBAAC,UAAK,eAAW,MAAC,WAAU,gDACzB,eAAK,MACR;AAAA,cAED,KAAK,OACJ;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAM,KAAK;AAAA,kBACX,WAAU;AAAA,kBAET,eAAK;AAAA;AAAA,cACR,IAEA,oBAAC,UAAK,WAAU,YAAY,eAAK,MAAK;AAAA;AAAA;AAAA,QAE1C,GACF;AAAA,QACA,oBAAC,QAAG,WAAU,iFACX,sBAAY,KAAK,KAAK,GACzB;AAAA,WA9BO,KAAK,IA+Bd;AAAA,IAEJ,CAAC,GACH;AAAA,KACF,GACF;AAEJ;AAEA,IAAO,kBAAQ;","names":[]}
|
|
@@ -4,7 +4,15 @@ import { ReactNode } from 'react';
|
|
|
4
4
|
/** Which way a change is good. */
|
|
5
5
|
type DeltaIntent = 'up-is-good' | 'down-is-good' | 'neutral';
|
|
6
6
|
interface BigNumberDelta {
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* The change, already computed, as a RATIO. Positive is up, whatever that
|
|
9
|
+
* means here.
|
|
10
|
+
*
|
|
11
|
+
* `0.124` is the twelve-point-four percent the default `format` prints.
|
|
12
|
+
* Passing `12.4` for the same change prints `+1240%`, and nothing can catch
|
|
13
|
+
* that for you — a ratio and a percentage are both plain numbers, and either
|
|
14
|
+
* is a legitimate value under a `format` of your own.
|
|
15
|
+
*/
|
|
8
16
|
value: number;
|
|
9
17
|
/** What it is a change from — "vs last week". */
|
|
10
18
|
label?: ReactNode;
|
|
@@ -22,8 +30,16 @@ interface BigNumberDelta {
|
|
|
22
30
|
interface BigNumberProps {
|
|
23
31
|
/** What the number counts. */
|
|
24
32
|
label: ReactNode;
|
|
25
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* The number, already formatted — this component does not guess a unit.
|
|
35
|
+
*
|
|
36
|
+
* `null` and `undefined` are the empty state rather than a blank space: a
|
|
37
|
+
* headline with nothing under it reads as a figure that failed to load, and
|
|
38
|
+
* the reader's next move is to reload a page that will look the same.
|
|
39
|
+
*/
|
|
26
40
|
value: ReactNode;
|
|
41
|
+
/** What stands in for the number when there is none. */
|
|
42
|
+
emptyValue?: ReactNode;
|
|
27
43
|
delta?: BigNumberDelta;
|
|
28
44
|
/** A sparkline, a note, a caveat. Sits under the number. */
|
|
29
45
|
children?: ReactNode;
|
|
@@ -51,6 +67,6 @@ interface BigNumberProps {
|
|
|
51
67
|
* delta={{ value: 0.124, label: 'vs last month', intent: 'up-is-good' }}
|
|
52
68
|
* />
|
|
53
69
|
*/
|
|
54
|
-
declare function BigNumber({ label, value, delta, children, className }: BigNumberProps): react.JSX.Element;
|
|
70
|
+
declare function BigNumber({ label, value, emptyValue, delta, children, className, }: BigNumberProps): react.JSX.Element;
|
|
55
71
|
|
|
56
72
|
export { BigNumber, type BigNumberDelta, type BigNumberProps, type DeltaIntent, BigNumber as default };
|
|
@@ -1,16 +1,36 @@
|
|
|
1
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "../../lib/cn.js";
|
|
3
3
|
const signed = (value) => `${value > 0 ? "+" : ""}${(value * 100).toFixed(1).replace(/\.0$/, "")}%`;
|
|
4
|
-
function BigNumber({
|
|
4
|
+
function BigNumber({
|
|
5
|
+
label,
|
|
6
|
+
value,
|
|
7
|
+
emptyValue = "\u2014",
|
|
8
|
+
delta,
|
|
9
|
+
children,
|
|
10
|
+
className
|
|
11
|
+
}) {
|
|
5
12
|
const intent = delta?.intent ?? "neutral";
|
|
6
13
|
const format = delta?.format ?? signed;
|
|
7
14
|
const rising = (delta?.value ?? 0) > 0;
|
|
8
15
|
const flat = (delta?.value ?? 0) === 0;
|
|
9
|
-
const
|
|
10
|
-
const
|
|
16
|
+
const isEmpty = value === null || value === void 0;
|
|
17
|
+
const good = flat || intent === "neutral" ? null : intent === "up-is-good" ? rising : !rising;
|
|
18
|
+
const tone = good === null ? "text-(--ink-2)" : good ? "text-(--ok)" : "text-(--danger)";
|
|
11
19
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1", className), children: [
|
|
12
20
|
/* @__PURE__ */ jsx("span", { className: "eyebrow text-(--ink-3-aa)", children: label }),
|
|
13
|
-
/* @__PURE__ */ jsx(
|
|
21
|
+
/* @__PURE__ */ jsx(
|
|
22
|
+
"span",
|
|
23
|
+
{
|
|
24
|
+
className: cn(
|
|
25
|
+
"font-heading text-[length:var(--fs-lead)] leading-none tabular-nums",
|
|
26
|
+
isEmpty ? "text-(--ink-3-aa)" : "text-(--ink)"
|
|
27
|
+
),
|
|
28
|
+
children: isEmpty ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
29
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: emptyValue }),
|
|
30
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "No data" })
|
|
31
|
+
] }) : value
|
|
32
|
+
}
|
|
33
|
+
),
|
|
14
34
|
delta && /* @__PURE__ */ jsxs("span", { className: cn("flex items-baseline gap-1.5 mono-meta", tone), children: [
|
|
15
35
|
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: flat ? "\u2192" : rising ? "\u2191" : "\u2193" }),
|
|
16
36
|
/* @__PURE__ */ jsx("span", { children: format(delta.value) }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/charts/BigNumber/BigNumber.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\n/** Which way a change is good. */\nexport type DeltaIntent = 'up-is-good' | 'down-is-good' | 'neutral'\n\nexport interface BigNumberDelta {\n
|
|
1
|
+
{"version":3,"sources":["../../../src/charts/BigNumber/BigNumber.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\n/** Which way a change is good. */\nexport type DeltaIntent = 'up-is-good' | 'down-is-good' | 'neutral'\n\nexport interface BigNumberDelta {\n /**\n * The change, already computed, as a RATIO. Positive is up, whatever that\n * means here.\n *\n * `0.124` is the twelve-point-four percent the default `format` prints.\n * Passing `12.4` for the same change prints `+1240%`, and nothing can catch\n * that for you — a ratio and a percentage are both plain numbers, and either\n * is a legitimate value under a `format` of your own.\n */\n value: number\n /** What it is a change from — \"vs last week\". */\n label?: ReactNode\n /**\n * Which direction counts as good.\n *\n * Required rather than assumed, because the assumption is wrong half the\n * time: revenue up is good, error rate up is not, and a component that\n * guesses will confidently colour a bad number green.\n */\n intent?: DeltaIntent\n /** Formats the change. Defaults to a signed percentage. */\n format?: (value: number) => string\n}\n\nexport interface BigNumberProps {\n /** What the number counts. */\n label: ReactNode\n /**\n * The number, already formatted — this component does not guess a unit.\n *\n * `null` and `undefined` are the empty state rather than a blank space: a\n * headline with nothing under it reads as a figure that failed to load, and\n * the reader's next move is to reload a page that will look the same.\n */\n value: ReactNode\n /** What stands in for the number when there is none. */\n emptyValue?: ReactNode\n delta?: BigNumberDelta\n /** A sparkline, a note, a caveat. Sits under the number. */\n children?: ReactNode\n className?: string\n}\n\nconst signed = (value: number): string =>\n `${value > 0 ? '+' : ''}${(value * 100).toFixed(1).replace(/\\.0$/, '')}%`\n\n/**\n * One number, at the size of a headline.\n *\n * The form most dashboards need most often and most chart libraries do not\n * ship, on the grounds that it is not a chart. It is the right answer whenever\n * there is exactly one figure to report: a plot of a single value is a plot\n * whose shape carries nothing, and the reader has to decode an axis to recover\n * a number that could simply have been printed.\n *\n * The delta is where this earns its place over a `<p>`. Direction is stated by\n * the CALL SITE (`intent`), never inferred: \"errors down 12%\" is good news and\n * \"revenue down 12%\" is not, and no component can tell which it is holding.\n * Where the direction is known, the arrow and the word carry it — the status\n * colour is the third signal, never the only one.\n *\n * @example\n * <BigNumber\n * label=\"Monthly revenue\"\n * value=\"$48,210\"\n * delta={{ value: 0.124, label: 'vs last month', intent: 'up-is-good' }}\n * />\n */\nexport function BigNumber({\n label,\n value,\n emptyValue = '—',\n delta,\n children,\n className,\n}: BigNumberProps) {\n const intent = delta?.intent ?? 'neutral'\n const format = delta?.format ?? signed\n const rising = (delta?.value ?? 0) > 0\n const flat = (delta?.value ?? 0) === 0\n const isEmpty = value === null || value === undefined\n\n // A change of exactly zero is not good news and not bad news, and the tone\n // and the arrow have always said so. The verdict is dropped with them: an\n // intent decides which DIRECTION is better, and there is no direction here,\n // so `{ value: 0, intent: 'up-is-good' }` used to be announced as \"no\n // change, worse\" — a judgement nothing on screen was making.\n const good = flat || intent === 'neutral' ? null : intent === 'up-is-good' ? rising : !rising\n const tone = good === null ? 'text-(--ink-2)' : good ? 'text-(--ok)' : 'text-(--danger)'\n\n return (\n <div className={cn('flex flex-col gap-1', className)}>\n <span className=\"eyebrow text-(--ink-3-aa)\">{label}</span>\n\n {/* The serif, at the record-title step. A number this size is the page's\n headline, and the system sets headlines in the editorial face. */}\n <span\n className={cn(\n 'font-heading text-[length:var(--fs-lead)] leading-none tabular-nums',\n isEmpty ? 'text-(--ink-3-aa)' : 'text-(--ink)',\n )}\n >\n {isEmpty ? (\n <>\n {/* The dash is the sighted reading and the sentence is the spoken\n one. Announcing \"em dash\" instead would be a third thing. */}\n <span aria-hidden>{emptyValue}</span>\n <span className=\"sr-only\">No data</span>\n </>\n ) : (\n value\n )}\n </span>\n\n {delta && (\n <span className={cn('flex items-baseline gap-1.5 mono-meta', tone)}>\n {/* The arrow is the second carrier and the word is the third, so the\n reading survives greyscale, forced colours and colour blindness —\n which the status tint alone does not. */}\n <span aria-hidden>{flat ? '→' : rising ? '↑' : '↓'}</span>\n <span>{format(delta.value)}</span>\n <span className=\"sr-only\">\n {flat ? 'no change' : rising ? 'up' : 'down'}\n {good === null ? '' : good ? ', better' : ', worse'}\n </span>\n {delta.label && <span className=\"text-(--ink-3-aa)\">{delta.label}</span>}\n </span>\n )}\n\n {children && <div className=\"mt-2\">{children}</div>}\n </div>\n )\n}\n\nexport default BigNumber\n"],"mappings":"AAmGM,SAWI,UAXJ,KAWI,YAXJ;AAlGN,SAAS,UAAU;AAiDnB,MAAM,SAAS,CAAC,UACd,GAAG,QAAQ,IAAI,MAAM,EAAE,IAAI,QAAQ,KAAK,QAAQ,CAAC,EAAE,QAAQ,QAAQ,EAAE,CAAC;AAwBjE,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AACF,GAAmB;AACjB,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,UAAU,OAAO,SAAS,KAAK;AACrC,QAAM,QAAQ,OAAO,SAAS,OAAO;AACrC,QAAM,UAAU,UAAU,QAAQ,UAAU;AAO5C,QAAM,OAAO,QAAQ,WAAW,YAAY,OAAO,WAAW,eAAe,SAAS,CAAC;AACvF,QAAM,OAAO,SAAS,OAAO,mBAAmB,OAAO,gBAAgB;AAEvE,SACE,qBAAC,SAAI,WAAW,GAAG,uBAAuB,SAAS,GACjD;AAAA,wBAAC,UAAK,WAAU,6BAA6B,iBAAM;AAAA,IAInD;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA,UAAU,sBAAsB;AAAA,QAClC;AAAA,QAEC,oBACC,iCAGE;AAAA,8BAAC,UAAK,eAAW,MAAE,sBAAW;AAAA,UAC9B,oBAAC,UAAK,WAAU,WAAU,qBAAO;AAAA,WACnC,IAEA;AAAA;AAAA,IAEJ;AAAA,IAEC,SACC,qBAAC,UAAK,WAAW,GAAG,yCAAyC,IAAI,GAI/D;AAAA,0BAAC,UAAK,eAAW,MAAE,iBAAO,WAAM,SAAS,WAAM,UAAI;AAAA,MACnD,oBAAC,UAAM,iBAAO,MAAM,KAAK,GAAE;AAAA,MAC3B,qBAAC,UAAK,WAAU,WACb;AAAA,eAAO,cAAc,SAAS,OAAO;AAAA,QACrC,SAAS,OAAO,KAAK,OAAO,aAAa;AAAA,SAC5C;AAAA,MACC,MAAM,SAAS,oBAAC,UAAK,WAAU,qBAAqB,gBAAM,OAAM;AAAA,OACnE;AAAA,IAGD,YAAY,oBAAC,SAAI,WAAU,QAAQ,UAAS;AAAA,KAC/C;AAEJ;AAEA,IAAO,oBAAQ;","names":[]}
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "recharts";
|
|
17
17
|
import { ChartContainer } from "../lib/chart.js";
|
|
18
18
|
import { ChartFigure } from "../lib/figure.js";
|
|
19
|
-
import {
|
|
19
|
+
import {} from "../lib/empty.js";
|
|
20
20
|
import { ChartBackground } from "../lib/background.js";
|
|
21
21
|
import { ChartTooltip } from "../lib/tooltip.js";
|
|
22
22
|
import { SeriesGradient } from "../lib/paint.js";
|
|
@@ -131,7 +131,9 @@ function BoxPlot({
|
|
|
131
131
|
{ key: "outlierCount", label: "Outliers" }
|
|
132
132
|
]
|
|
133
133
|
},
|
|
134
|
-
|
|
134
|
+
isEmpty,
|
|
135
|
+
empty,
|
|
136
|
+
children: /* @__PURE__ */ jsx(ChartContainer, { config, children: /* @__PURE__ */ jsx(
|
|
135
137
|
RechartsBarChart,
|
|
136
138
|
{
|
|
137
139
|
id: chartId,
|