Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/charts package #1648

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2a42d22
feat: setup with echarts for react component and tests
natanfernandes Jun 13, 2024
3bd8c56
fix: add default value to loading and lint
natanfernandes Jun 13, 2024
f0ed931
Merge branch 'main' of https://github.com/vtex/shoreline into feature…
natanfernandes Jun 13, 2024
30150af
fix: biomejs on vscode
natanfernandes Jun 13, 2024
414b773
fix: color and add props export
natanfernandes Jun 13, 2024
4546750
fix: canUseDom and array check
natanfernandes Jun 17, 2024
8b38b74
feat: add chartConfig props to validate variant and type
natanfernandes Jun 18, 2024
4218d1b
fix: wrong colors on the chart labels and lines
natanfernandes Jun 21, 2024
e417a65
Merge branch 'main' of https://github.com/vtex/shoreline into feature…
natanfernandes Oct 1, 2024
4ef950c
feat: use cloneDeep from lodash, bar default styles
natanfernandes Oct 1, 2024
a45b6bb
feat: add sunrise colors, story with controls and fix somes styles in…
natanfernandes Oct 23, 2024
87a20b7
Merge branch 'main' of https://github.com/vtex/shoreline into feature…
natanfernandes Oct 23, 2024
b00e7f0
fix: pnpm lock for chart lib
natanfernandes Oct 23, 2024
c3db54f
fix: types and spacing grid
natanfernandes Oct 23, 2024
6d6e0a9
fix: legends spacing
natanfernandes Oct 23, 2024
72344e0
feat: add tooltip on charts
natanfernandes Nov 27, 2024
1e6e2ba
fix: lock pnpm
natanfernandes Nov 27, 2024
95a80a6
chore: add chart docs
natanfernandes Nov 27, 2024
581abae
feat: export css chart bundle and import on docs
natanfernandes Nov 28, 2024
4abd5f8
chore: start to add doc to chart variants
natanfernandes Nov 28, 2024
1589a97
docs: improve doc props
natanfernandes Dec 10, 2024
e905a0f
Merge branch 'main' of https://github.com/vtex/shoreline into feature…
natanfernandes Dec 19, 2024
87ce98c
fix: pnpm lock
natanfernandes Dec 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/charts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Shoreline Charts

`shoreline-components` and `echarts` are peer dependencies of `shoreline-charts`

```sh
pnpm add @vtex/shoreline echarts @vtex/shoreline-charts
```
56 changes: 56 additions & 0 deletions packages/charts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"name": "@vtex/shoreline-charts",
"description": "Shoreline datavis library",
"version": "0.0.0",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
},
"files": [
"dist"
],
"exports": {
".": {
"require": "./dist/index.js",
"import": "./dist/index.mjs",
"types": "./dist/index.d.ts"
},
"./css": "./dist/index.css"
},
"engines": {
"node": ">=16"
},
"scripts": {
"prebuild": "rm -rf dist",
"dev": "tsup --watch",
"build": "tsup"
},
"repository": {
"directory": "packages/charts",
"type": "git",
"url": "git+https://github.com/vtex/shoreline.git"
},
"bugs": {
"url": "https://github.com/vtex/shoreline/issues"
},
"peerDependencies": {
"@vtex/shoreline": "1.x",
"echarts": "5.x",
"react": "18.x",
"react-dom": "18.x"
},
"devDependencies": {
"@types/lodash": "^4.17.4",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"@types/lodash": "^4.17.4",

"@vtex/shoreline": "workspace:*",
"echarts": "5.5.0"
},
"dependencies": {
"@vtex/shoreline-utils": "workspace:*",
"echarts-for-react": "^3.0.2",
"lodash": "^4.17.21",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're not using it, right?

Suggested change
"lodash": "^4.17.21",

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, i'll remove it

"vitest-canvas-mock": "^0.3.3"
}
}
111 changes: 111 additions & 0 deletions packages/charts/src/components/chart/chart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import {
useRef,
useEffect,
useMemo,
forwardRef,
useImperativeHandle,
type ComponentPropsWithRef,
useCallback,
} from 'react'
import type { EChartsOption, SetOptionOpts } from 'echarts'
import ReactECharts, { type EChartsInstance } from 'echarts-for-react'
import type * as echarts from 'echarts'

import { defaultTheme } from '../../theme/themes'
import type { ChartConfig } from '../../types/chart'
import { getChartOptions } from '../../utils/chart'
import { canUseDOM } from '@vtex/shoreline-utils'
import { DEFAULT_LOADING_SPINNER } from '../../theme/chartStyles'

/**
* Render a Shoreline Chart with echarts
* @see https://echarts.apache.org/en/index.html
*/
export const Chart = forwardRef<echarts.EChartsType | undefined, ChartProps>(
function Charts(props, ref) {
const {
option,
settings,
loading = false,
loadingConfig = DEFAULT_LOADING_SPINNER,
chartConfig,
style,
...otherProps
} = props

const chartRef = useRef<ReactECharts>(null)

useImperativeHandle(ref, () => {
if (chartRef.current) {
return chartRef.current.getEchartsInstance()
}
return undefined
})

const chartOptions: EChartsOption = useMemo(() => {
const { type, variant } = chartConfig
return getChartOptions(option, type, variant) || option
}, [option, chartConfig])

const handleResize = useCallback(() => {
if (chartRef.current) {
chartRef.current.getEchartsInstance().resize()
}
}, [chartRef])

useEffect(() => {
if (!canUseDOM) return

window.addEventListener('resize', handleResize)
return () => {
window.removeEventListener('resize', handleResize)
}
}, [handleResize, canUseDOM])

return (
<div data-sl-chart>
<ReactECharts
ref={chartRef}
theme={defaultTheme}
option={chartOptions}
style={{ minWidth: 290, ...style }}
opts={{
renderer: 'svg',
}}
showLoading={loading}
loadingOption={loadingConfig}
onChartReady={(instance) => instance.resize()}
{...otherProps}
/>
</div>
)
}
)

export interface ChartsOptions {
/**
* Echarts options for the chart
*/
option: EChartsOption
/**
* Echarts settings
*/
settings?: SetOptionOpts
/**
* Wether is loading
* @default false
*/
loading?: boolean
/**
* Options for customize the chart loading
* @default false
*/
loadingConfig?: EChartsInstance['showLoading']
/**
* Configs containing type of chart and its variants, each variant is a pre-defined chart style for each type
* @default default
*/
chartConfig: ChartConfig
}

export type ChartProps = ChartsOptions & ComponentPropsWithRef<'div'>
1 change: 1 addition & 0 deletions packages/charts/src/components/chart/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './chart'
2 changes: 2 additions & 0 deletions packages/charts/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './tooltip'
export * from './chart'
1 change: 1 addition & 0 deletions packages/charts/src/components/tooltip/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './tooltip'
45 changes: 45 additions & 0 deletions packages/charts/src/components/tooltip/tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { TooltipComponentFormatterCallbackParams } from 'echarts'
import { renderToStaticMarkup } from 'react-dom/server'
import '../../theme/components/tooltip.css'

export default function ChartTooltip({ params }: ChartTooltipProps) {
return (
<div data-sl-chart-tooltip>
{Array.isArray(params) ? (
params.map((param) => (
<ChartTooltipBase key={param.dataIndex} params={param} />
))
) : (
<ChartTooltipBase params={params} />
)}
</div>
)
}

export function ChartTooltipBase({ params }: { params: any }) {
return (
<>
<h4 data-sl-chart-tooltip-title>{params.name}</h4>
<div data-sl-chart-tooltip-data-container>
<div data-sl-chart-tooltip-data-serie-container>
<span
data-sl-chart-tooltip-data-serie-label-box
style={{
backgroundColor: params.color,
}}
/>
<span data-sl-chart-tooltip-data-serie-name>{params.seriesName}</span>
</div>
<span data-sl-chart-tooltip-data-serie-value>{params.value}</span>
</div>
</>
)
}

export const getTooltipStaticString = (
params: TooltipComponentFormatterCallbackParams
) => renderToStaticMarkup(<ChartTooltip params={params} />)

export interface ChartTooltipProps {
params: TooltipComponentFormatterCallbackParams
}
1 change: 1 addition & 0 deletions packages/charts/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components'
122 changes: 122 additions & 0 deletions packages/charts/src/stories/bar-charts.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// biome-ignore lint/correctness/noUnusedImports: <explanation>
import React from 'react'
import { Chart } from '../index'
import { compactNumber } from '../utils/format'
import type { StoryObj } from '@storybook/react'

const Bar = {
title: 'Charts/bar',
component: Chart,
}
export default Bar

type Story = StoryObj<typeof Chart>

export const Basic: Story = {
args: {
option: {
xAxis: {
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
series: [{ data: [1, 2, 3, 4, 5, 6, 7] }],
},
chartConfig: { type: 'bar' },
style: { height: 550 },
},
}

export const Loading: Story = {
render: (args) => {
const { option, chartConfig, loading } = args

return (
<Chart
option={option}
chartConfig={chartConfig}
style={{ height: 550 }}
loading={loading}
/>
)
},
args: {
option: {
xAxis: {
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
series: [{ data: [1, 2, 3, 4, 5, 6, 7] }],
},
chartConfig: { type: 'bar' },
style: { height: 550 },
loading: true,
},
}
export const MultiSeries: Story = {
args: {
option: {
xAxis: {
data: ['Mon', 'Tue', 'Wed'],
},
series: [
{ data: [3, 2, 3, 4], name: 'Series 1' },
{ data: [1, 4, 2, 3], name: 'Series 2' },
{ data: [2, 1, 4, 1], name: 'Series 3' },
],
},
chartConfig: { type: 'bar' },
style: { height: 550 },
},
}
export const WithHugeNumbers: Story = {
args: {
option: {
xAxis: {
data: ['Mon', 'Tue', 'Wed'],
},
yAxis: {
axisLabel: {
formatter: (value: number) => compactNumber(value),
},
},
series: [
{
data: [12344441, 62346346, 97346346],
name: 'Series 1',
},
],
},
chartConfig: { type: 'bar' },
style: { height: 550 },
},
}

export const Horizontal: Story = {
args: {
option: {
xAxis: {
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun', 'Test'],
},
series: [
{ data: [1, 2, 3, 4, 5, 6, 7, 8] },
{ data: [1, 4, 2, 1, 4, 3, 5, 9] },
],
},
chartConfig: { type: 'bar', variant: 'horizontal' },
style: { height: 550 },
},
}

export const MultiType: Story = {
args: {
option: {
xAxis: {
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
series: [
{ data: [1, 2, 3, 4, 5, 6, 7] },
{ data: [1, 4, 2, 1, 4, 3, 5], type: 'line' },
],
},
chartConfig: { type: 'bar', variant: 'default' },
style: { height: 550 },
},
}
8 changes: 8 additions & 0 deletions packages/charts/src/tests/__fixtures__/chartData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const BAR_CHART_DATA = {
xAxis: {
weekdays: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
series: {
dayNumbers: [1, 2, 3, 4, 5, 6, 7],
},
}
Loading
Loading