-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2185 from zetkin/issue-2166/zui-progress-bar
Issue 2166/zui bar diagram
- Loading branch information
Showing
2 changed files
with
122 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import ZUIBarDiagram from './index'; | ||
|
||
const meta: Meta<typeof ZUIBarDiagram> = { | ||
component: ZUIBarDiagram, | ||
}; | ||
export default meta; | ||
|
||
type Story = StoryObj<typeof ZUIBarDiagram>; | ||
|
||
export const Primary: Story = { | ||
args: { | ||
size: 'medium', | ||
values: [25], | ||
}, | ||
}; | ||
|
||
export const ThreeSegments: Story = { | ||
args: { | ||
size: 'medium', | ||
values: [25, 25], | ||
}, | ||
}; | ||
|
||
export const FourSegments: Story = { | ||
args: { | ||
size: 'medium', | ||
values: [33, 33, 10], | ||
}, | ||
}; | ||
|
||
export const ExtraSmall: Story = { | ||
args: { | ||
size: 'extraSmall', | ||
values: [33, 33, 10], | ||
}, | ||
}; | ||
|
||
export const Small: Story = { | ||
args: { | ||
size: 'small', | ||
values: [33, 33, 10], | ||
}, | ||
}; | ||
|
||
export const Large: Story = { | ||
args: { | ||
size: 'large', | ||
values: [33, 33, 10], | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { Box } from '@mui/material'; | ||
|
||
type Sizes = 'extraSmall' | 'small' | 'medium' | 'large'; | ||
|
||
const sizes: Record<Sizes, number> = { | ||
extraSmall: 5, | ||
large: 30, | ||
medium: 20, | ||
small: 10, | ||
}; | ||
|
||
const colors = ['#7800dc', '#9d46e6', '#c189ef', '#e4ccf8']; | ||
|
||
interface ZUIBarDiagramProps { | ||
/** | ||
* Width of segments as an array of numbers whose total is < 100. | ||
* The final segment width is the remainder. | ||
*/ | ||
values: [number] | [number, number] | [number, number, number]; | ||
size: Sizes; | ||
} | ||
|
||
/** | ||
* Renders a horizontal stacked bar. Define the percentage width of | ||
* different segments, up to 100. The final segment width is the | ||
* remainder of 100 minus the previous segment widths. | ||
*/ | ||
const ZUIBarDiagram = ({ values, size }: ZUIBarDiagramProps) => { | ||
const progressSum = values.reduce((sum, val) => { | ||
return sum + val; | ||
}); | ||
|
||
if (progressSum > 100) { | ||
throw new Error('Progress > 100'); | ||
} | ||
if (values.some((value) => value < 0)) { | ||
throw new Error('Values can not be negative'); | ||
} | ||
|
||
const height = sizes[size]; | ||
|
||
return ( | ||
<Box | ||
borderRadius={height / 2} | ||
display="flex" | ||
gap={size === 'large' ? 0.75 : 0.5} | ||
overflow="hidden" | ||
width="100%" | ||
> | ||
{values.map((segmentWidth, index) => { | ||
if (!segmentWidth) { | ||
return null; | ||
} | ||
return ( | ||
<Box | ||
key={index} | ||
bgcolor={colors[index]} | ||
height={height} | ||
width={`${segmentWidth}%`} | ||
/> | ||
); | ||
})} | ||
{progressSum < 100 && ( | ||
<Box bgcolor={colors.at(-1)} flexGrow={1} height={height} /> | ||
)} | ||
</Box> | ||
); | ||
}; | ||
|
||
export default ZUIBarDiagram; |