-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
LG-4574: Add base chart components (#2510)
* Build TimeSeriesLineChart * Core README * Update READMEs * Use seeded data * Match test utils format * Add ARIA * Add darkMode colors * Lint * Add LG provider to storybook * Convert TimeSeries* to just LineChart * Lint * Add tests * Lint * Revert past CHANGELOG diff * Changeset * Remove unused deps * Add lib dep * Try awaiting throw test * Working state * Fix makeData types * Lint * Complete hook tests * Fix test * Lint * Update comment * Allow external styling * Fix README nesting * Fix build * Delete line-chart * Fix storybook * Storybook update * Update README * Lint * Add deps * Fix faker dep * Upgrade lib * LG-4618: Add Grid component (#2516) * Add Grid component * Update README * Add changeset * Fix changelog * Add Grid to live example * Fix storybook * CR changes * Lint * Lint * CR changes * Remove logging * Fix README * Fix tests * Fix linting error
- Loading branch information
Showing
46 changed files
with
1,169 additions
and
744 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,9 @@ | ||
--- | ||
'@lg-charts/core': minor | ||
--- | ||
|
||
Adds core chart components package | ||
|
||
- Adds `Chart` component for overarching chart configuration. | ||
- Adds `Line` component for adding individual series data to a chart. | ||
- Adds `Grid` component for configuring grid line on a chart. |
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,85 @@ | ||
# Core Chart Components | ||
|
||
Library of composable charting components that provides a way to create interactive charts rendered on canvas. | ||
|
||
![npm (scoped)](https://img.shields.io/npm/v/@lg-charts/core.svg) | ||
|
||
## Installation | ||
|
||
### Yarn | ||
|
||
```shell | ||
yarn add @lg-charts/core | ||
``` | ||
|
||
### NPM | ||
|
||
```shell | ||
npm install @lg-charts/core | ||
``` | ||
|
||
## Basic Example | ||
|
||
```js | ||
import { Chart, Line, Grid } from '@lg-charts/core'; | ||
|
||
<Chart> | ||
<Grid vertical={false}> | ||
<Line | ||
name="Series 1" | ||
data={[ | ||
[new Date(2020, 01, 01), 0], | ||
[new Date(2020, 01, 02), 1], | ||
[new Date(2020, 01, 03), 2], | ||
[new Date(2020, 01, 04), 3], | ||
[new Date(2020, 01, 05), 4], | ||
]} | ||
/> | ||
<Line | ||
name="Series 2" | ||
data={[ | ||
[new Date(2020, 01, 01), 4], | ||
[new Date(2020, 01, 02), 3], | ||
[new Date(2020, 01, 03), 2], | ||
[new Date(2020, 01, 04), 1], | ||
[new Date(2020, 01, 05), 0], | ||
]} | ||
/> | ||
</Chart>; | ||
``` | ||
|
||
## Parent Components | ||
|
||
### `Chart` | ||
|
||
Chart container component. | ||
|
||
#### Props | ||
|
||
| Name | Description | Type | Default | | ||
| -------------- | ------------------------------------------------------- | ---------- | ------- | | ||
| `onChartReady` | Callback to be called when chart is finished rendering. | () => void | | | ||
|
||
## Child Components | ||
|
||
### `Line` | ||
|
||
Component that takes in data points and renders a single line on the chart. | ||
|
||
#### Props | ||
|
||
| Name | Description | Type | Default | | ||
| ------ | ---------------------------------------------------------------------- | ----------------------------------------------------------- | ------- | | ||
| `name` | Name used to identify the series. | string | | | ||
| `data` | Data array of tuples that represent x and y coordinates in the series. | Array<[string \| number \| Date, string \| number \| Date]> | | | ||
|
||
### `Grid` | ||
|
||
Component that displays grid lines on the chart. | ||
|
||
#### Props | ||
|
||
| Name | Description | Type | Default | | ||
| ------------ | --------------------------- | ------- | ------- | | ||
| `horizontal` | Show horizontal grid lines. | boolean | true | | ||
| `vertical` | Show vertical grid lines. | boolean | true | |
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
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,50 @@ | ||
import React from 'react'; | ||
import { render, screen } from '@testing-library/react'; | ||
|
||
import '@testing-library/jest-dom/extend-expect'; | ||
|
||
import { ChartProvider } from '../ChartContext'; | ||
|
||
import { Chart } from './Chart'; | ||
|
||
jest.mock('../ChartContext', () => ({ | ||
ChartProvider: jest.fn(({ children }) => <div>{children}</div>), | ||
})); | ||
|
||
jest.mock('./hooks', () => ({ | ||
useChart: jest.fn(() => ({ | ||
chartOptions: {}, | ||
updateChartOptions: jest.fn(), | ||
addChartSeries: jest.fn(), | ||
removeChartSeries: jest.fn(), | ||
})), | ||
})); | ||
|
||
jest.mock('@leafygreen-ui/leafygreen-provider', () => ({ | ||
useDarkMode: jest.fn(() => ({ theme: 'light' })), | ||
})); | ||
|
||
/** | ||
* Tests Echarts wrapper component is rendered with the correct props. Visual changes | ||
* occur on the canvas element, so we can't test those with Jest. Will instead rely on | ||
* Chromatic tests for rendering logic. | ||
*/ | ||
describe('lg-charts/core/Chart', () => { | ||
it('renders the echart container', () => { | ||
render(<Chart />); | ||
expect(screen.getByTestId('echart')).toBeInTheDocument(); | ||
}); | ||
|
||
it('passes the correct props to ChartProvider', () => { | ||
render(<Chart />); | ||
expect(ChartProvider).toHaveBeenCalledWith( | ||
expect.objectContaining({ | ||
chartOptions: {}, | ||
updateChartOptions: expect.any(Function), | ||
addChartSeries: expect.any(Function), | ||
removeChartSeries: expect.any(Function), | ||
}), | ||
expect.anything(), | ||
); | ||
}); | ||
}); |
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,22 @@ | ||
import { css } from '@leafygreen-ui/emotion'; | ||
import { Theme } from '@leafygreen-ui/lib'; | ||
import { | ||
borderRadius, | ||
color, | ||
InteractionState, | ||
Variant, | ||
} from '@leafygreen-ui/tokens'; | ||
|
||
export const chartStyles = css` | ||
grid-row: 2; | ||
`; | ||
|
||
export const getWrapperStyles = (theme: Theme) => css` | ||
height: 280px; | ||
width: 100%; | ||
border: 1px solid | ||
${color[theme].border[Variant.Secondary][InteractionState.Default]}; | ||
border-radius: ${borderRadius[200]}px; | ||
display: grid; | ||
grid-template-rows: auto 1fr; | ||
`; |
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,60 @@ | ||
/** | ||
* React wrapper for Apache Echarts. | ||
* https://echarts.apache.org/en/option.html#title | ||
* | ||
* Wraps the Echarts library and provides a React-friendly API. It adds default options | ||
* and styling according to our design system's specs. | ||
*/ | ||
import React from 'react'; | ||
|
||
import { cx } from '@leafygreen-ui/emotion'; | ||
import { useDarkMode } from '@leafygreen-ui/leafygreen-provider'; | ||
import LeafyGreenProvider from '@leafygreen-ui/leafygreen-provider/src/LeafyGreenContext'; | ||
|
||
import { ChartProvider } from '../ChartContext'; | ||
|
||
import { chartStyles, getWrapperStyles } from './Chart.styles'; | ||
import { ChartProps } from './Chart.types'; | ||
import { useChart } from './hooks'; | ||
|
||
export function Chart({ | ||
children, | ||
darkMode: darkModeProp, | ||
onChartReady, | ||
className, | ||
...rest | ||
}: ChartProps) { | ||
const { theme } = useDarkMode(darkModeProp); | ||
const { | ||
chartOptions, | ||
updateChartOptions, | ||
addChartSeries, | ||
removeChartSeries, | ||
chartRef, | ||
} = useChart({ | ||
theme, | ||
onChartReady, | ||
}); | ||
|
||
return ( | ||
<LeafyGreenProvider darkMode={darkModeProp}> | ||
<ChartProvider | ||
chartOptions={chartOptions} | ||
updateChartOptions={updateChartOptions} | ||
addChartSeries={addChartSeries} | ||
removeChartSeries={removeChartSeries} | ||
> | ||
<div className={cx(getWrapperStyles(theme), className)} {...rest}> | ||
{children} | ||
<div | ||
ref={chartRef} | ||
className={`echart ${chartStyles}`} | ||
data-testid="echart" | ||
/> | ||
</div> | ||
</ChartProvider> | ||
</LeafyGreenProvider> | ||
); | ||
} | ||
|
||
Chart.displayName = 'Chart'; |
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,45 @@ | ||
import type { XAXisComponentOption, YAXisComponentOption } from 'echarts'; | ||
import type { LineSeriesOption } from 'echarts/charts'; | ||
import type { | ||
DatasetComponentOption, | ||
GridComponentOption, | ||
LegendComponentOption, | ||
TitleComponentOption, | ||
ToolboxComponentOption, | ||
TooltipComponentOption, | ||
} from 'echarts/components'; | ||
import type { ComposeOption } from 'echarts/core'; | ||
|
||
import { DarkModeProps, type HTMLElementProps } from '@leafygreen-ui/lib'; | ||
|
||
type RequiredSeriesProps = 'type' | 'name' | 'data'; | ||
export type SeriesOption = Pick<LineSeriesOption, RequiredSeriesProps> & | ||
Partial<Omit<LineSeriesOption, RequiredSeriesProps>>; | ||
|
||
/** | ||
* TODO: This might need to be improved. `ComposeOption` appears to make most base option | ||
* keys "Arrayable". This is making it difficult to properly test partial options on | ||
* methods like updateUtils > updateOptions(), since something like `options.grid` could be | ||
* an array even if an object. | ||
*/ | ||
export type ChartOptions = ComposeOption< | ||
| TooltipComponentOption | ||
| GridComponentOption | ||
| DatasetComponentOption | ||
| TitleComponentOption | ||
| LegendComponentOption | ||
| ToolboxComponentOption | ||
| XAXisComponentOption | ||
| YAXisComponentOption | ||
> & { series?: Array<SeriesOption> }; | ||
|
||
export interface ChartProps extends HTMLElementProps<'div'>, DarkModeProps { | ||
children?: React.ReactNode; | ||
onChartReady?: () => void; | ||
} | ||
|
||
export const ChartActionType = { | ||
addChartSeries: 'addChartSeries', | ||
removeChartSeries: 'removeChartSeries', | ||
updateOptions: 'updateOptions', | ||
} as const; |
38 changes: 38 additions & 0 deletions
38
charts/core/src/Chart/chartSeriesColors/chartSeriesColors.ts
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,38 @@ | ||
import { Theme } from '@leafygreen-ui/lib'; | ||
|
||
export const chartSeriesColors = { | ||
[Theme.Dark]: [ | ||
'#0498EC', | ||
'#00ED64', | ||
'#FFC010', | ||
'#FF6960', | ||
'#B45AF2', | ||
'#C3E7FE', | ||
'#71F6BA', | ||
'#FFEC9E', | ||
'#FFCDC7', | ||
'#F1D4FD', | ||
'#E1F7FF', | ||
'#C0FAE6', | ||
'#FEF7DB', | ||
'#FFEAE5', | ||
'#F9EBFF', | ||
], | ||
[Theme.Light]: [ | ||
'#016BF8', | ||
'#00A35C', | ||
'#FFC010', | ||
'#DB3030', | ||
'#5E0C9E', | ||
'#1254B7', | ||
'#00684A', | ||
'#944F01', | ||
'#970606', | ||
'#2D0B59', | ||
'#0498EC', | ||
'#00ED64', | ||
'#FFEC9E', | ||
'#FF6960', | ||
'#B45AF2', | ||
], | ||
}; |
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 @@ | ||
export { chartSeriesColors } from './chartSeriesColors'; |
Oops, something went wrong.