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

feat(charts): Support for theme #114

Merged
merged 2 commits into from
Sep 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion .dumi/theme/SiteThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ConfigProvider, token } from '@oceanbase/design';
import { ChartProvider } from '@oceanbase/charts';
import type { ThemeProviderProps } from 'antd-style';
import { ThemeProvider } from 'antd-style';
import type { FC } from 'react';
Expand Down Expand Up @@ -40,7 +41,7 @@ const SiteThemeProvider: FC<ThemeProviderProps> = ({ children, theme, ...rest })
direction={direction}
locale={lang === 'cn' ? zhCN : undefined}
>
{children}
<ChartProvider theme={theme.isDark ? 'dark' : 'light'}>{children}</ChartProvider>
</ConfigProvider>
</ThemeProvider>
);
Expand Down
7 changes: 6 additions & 1 deletion .dumi/theme/layouts/GlobalLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from '@ant-design/cssinjs';
import { App, theme as obTheme } from '@oceanbase/design';
import type { DirectionType } from '@oceanbase/design/es/config-provider';
import { createSearchParams, useOutlet, useSearchParams } from 'dumi';
import { usePrefersColor, createSearchParams, useOutlet, useSearchParams } from 'dumi';
import React, { useCallback, useEffect, useMemo } from 'react';
import useLayoutState from '../../hooks/useLayoutState';
import SiteThemeProvider from '../SiteThemeProvider';
Expand Down Expand Up @@ -42,6 +42,7 @@ const GlobalLayout: React.FC = () => {
const outlet = useOutlet();
const { pathname } = useLocation();
const [searchParams, setSearchParams] = useSearchParams();
const [, , setPrefersColor] = usePrefersColor();
const [{ theme = [], direction, isMobile }, setSiteState] = useLayoutState<SiteState>({
isMobile: false,
direction: 'ltr',
Expand Down Expand Up @@ -69,6 +70,8 @@ const GlobalLayout: React.FC = () => {
...nextSearchParams,
theme: value.filter(t => t !== 'light'),
});
// Set theme of dumi site
setPrefersColor(value?.filter(t => t === 'dark' || t === 'light')?.[0]);
}
});

Expand All @@ -88,6 +91,8 @@ const GlobalLayout: React.FC = () => {
const _direction = searchParams.get('direction') as DirectionType;

setSiteState({ theme: _theme, direction: _direction === 'rtl' ? 'rtl' : 'ltr' });
// Set theme of dumi site
setPrefersColor(_theme?.filter(t => t === 'dark' || t === 'light')?.[0]);
// Handle isMobile
updateMobileMode();

Expand Down
33 changes: 25 additions & 8 deletions docs/charts/charts-theme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,33 @@ group: 可视化图表

OceanBase Charts 的设计体系遵循 AntV 设计规范,并在此基础上扩展出了很多具备 OceanBase 产品风格的设计规范模式,包括但不限于全局样式(色板、圆角、边框)和特定图表的视觉定制,以传递 OceanBase 科技、活力、专注和关怀的品牌特点。

## 使用主题 Token
## 使用主题配置

```ts
import { theme } from '@oceanbase/charts';
```tsx | pure
import { ChartProvider, useTheme } from '@oceanbase/charts';

// 主题色
console.log(theme.defaultColor);

// 折线图线宽
console.log(theme.styleSheet.lineBorder);
export default () {
// 获取主题配置
const themeConfig = useTheme();
// 主题色
console.log(themeConfig.defaultColor);
// 折线图线宽
console.log(themeConfig.styleSheet.lineBorder);
// 设置主题
return (
<>
<ChartProvider theme="light">
{...}
</ChartProvider>
<ChartProvider theme="dark">
{...}
</ChartProvider>
<ChartProvider theme={{ defaultColor: '#ff0000', subColor: '#00ff00' }}>
{...}
</ChartProvider>
</>
);
};
```

- 主题的全量 Token 可参考 https://github.com/oceanbase/charts/blob/master/src/theme/index.ts#L29 。
18 changes: 12 additions & 6 deletions packages/charts/src/Area/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@ import { sortByMoment } from '@oceanbase/util';
import useResizeObserver from 'use-resize-observer';
import type { Tooltip } from '../hooks/useTooltipScrollable';
import useTooltipScrollable from '../hooks/useTooltipScrollable';
import { theme } from '../theme';
import { useTheme } from '../theme';
import type { Theme } from '../theme';

export interface AreaConfig extends AntAreaConfig {
tooltip?: false | Tooltip;
theme?: Theme;
}

const Area: React.FC<AreaConfig> = forwardRef(
({ data, line, xField, xAxis, yAxis, tooltip, legend, interactions, ...restConfig }, ref) => {
(
{ data, line, xField, xAxis, yAxis, tooltip, legend, interactions, theme, ...restConfig },
ref
) => {
const themeConfig = useTheme(theme);
const { ref: containerRef, height: containerHeight } = useResizeObserver<HTMLDivElement>({
// 包含 padding 和 border
box: 'border-box',
Expand All @@ -30,7 +36,7 @@ const Area: React.FC<AreaConfig> = forwardRef(
line: {
...line,
style: {
lineWidth: theme.styleSheet.lineBorder,
lineWidth: themeConfig.styleSheet.lineBorder,
...line?.style,
},
},
Expand All @@ -50,8 +56,8 @@ const Area: React.FC<AreaConfig> = forwardRef(
line: {
...xAxis?.grid?.line,
style: {
lineWidth: theme.styleSheet.axisGridBorder,
stroke: theme.styleSheet.axisGridBorderColor,
lineWidth: themeConfig.styleSheet.axisGridBorder,
stroke: themeConfig.styleSheet.axisGridBorderColor,
lineDash: [4, 4],
...xAxis?.grid?.line?.style,
},
Expand Down Expand Up @@ -81,7 +87,7 @@ const Area: React.FC<AreaConfig> = forwardRef(
type: 'brush-x',
},
],
theme: 'ob',
theme: themeConfig.theme,
...restConfig,
};
return (
Expand Down
1 change: 0 additions & 1 deletion packages/charts/src/Bar/demo/basic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export default () => {
position: 'top-left',
},
};
console.log(Bar);
return (
<Row gutter={200}>
<Col span={12}>
Expand Down
25 changes: 15 additions & 10 deletions packages/charts/src/Bar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import React, { forwardRef } from 'react';
import type { BarConfig as AntBarConfig } from '@ant-design/charts';
import { Bar as AntBar } from '@ant-design/charts';
import { theme } from '../theme';
import { uniq } from 'lodash';
import { toPercent } from '../util/number';
import { useTheme } from '../theme';
import type { Theme } from '../theme';

export interface BarConfig extends AntBarConfig {
// 是否为进度条形图,数值范围为 0 ~ 1
Expand All @@ -11,6 +13,7 @@ export interface BarConfig extends AntBarConfig {
warningPercent?: number;
// 危险水位线,仅 isProgress 为 true 时生效
dangerPercent?: number;
theme?: Theme;
}

const Bar: React.FC<BarConfig> = forwardRef(
Expand All @@ -32,14 +35,16 @@ const Bar: React.FC<BarConfig> = forwardRef(
xAxis,
yAxis,
legend,
theme,
...restConfig
},
ref
) => {
const themeConfig = useTheme(theme);
const stackValues =
(isStack &&
seriesField &&
data?.filter(item => item[seriesField]).map(item => item[seriesField])) ||
uniq(data?.filter(item => item[seriesField]).map(item => item[seriesField]))) ||
[];
// 堆叠柱状图中最后一段对应的值
const lastStackValue = stackValues?.[stackValues?.length - 1];
Expand All @@ -51,8 +56,8 @@ const Bar: React.FC<BarConfig> = forwardRef(
isPercent,
isRange,
seriesField,
maxBarWidth: theme.barWidth,
minBarWidth: theme.barWidth,
maxBarWidth: themeConfig.barWidth,
minBarWidth: themeConfig.barWidth,
meta: isProgress
? {
...meta,
Expand All @@ -78,9 +83,9 @@ const Bar: React.FC<BarConfig> = forwardRef(
let color;
if (isProgress) {
if (dangerPercent && datum[xField] >= dangerPercent) {
color = theme.semanticRed;
color = themeConfig.semanticRed;
} else if (warningPercent && datum[xField] >= warningPercent) {
color = theme.semanticYellow;
color = themeConfig.semanticYellow;
}
}

Expand Down Expand Up @@ -112,7 +117,7 @@ const Bar: React.FC<BarConfig> = forwardRef(
? {
...barBackground,
style: {
fill: theme.barBackgroundColor,
fill: themeConfig.barBackgroundColor,
...barBackground?.style,
},
}
Expand All @@ -125,8 +130,8 @@ const Bar: React.FC<BarConfig> = forwardRef(
line: {
...yAxis?.grid?.line,
style: {
lineWidth: theme.styleSheet.axisGridBorder,
stroke: theme.styleSheet.axisGridBorderColor,
lineWidth: themeConfig.styleSheet.axisGridBorder,
stroke: themeConfig.styleSheet.axisGridBorderColor,
lineDash: [4, 4],
...yAxis?.grid?.line?.style,
},
Expand All @@ -142,7 +147,7 @@ const Bar: React.FC<BarConfig> = forwardRef(
...legend?.marker,
},
},
theme: 'ob',
theme: themeConfig.theme,
...restConfig,
};
return <AntBar {...newConfig} ref={ref} />;
Expand Down
64 changes: 64 additions & 0 deletions packages/charts/src/ChartProvider/__tests__/theme.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from 'react';
import { render } from '@testing-library/react';
import { ChartProvider, useTheme } from '@oceanbase/charts';

describe('ChartProvider theme', () => {
it('default theme', () => {
const Child = () => {
const themeConfig = useTheme();
expect(themeConfig.theme).toBe('light');
expect(themeConfig.defaultColor).toBe('#4C96FF');
return <div />;
};
render(
<ChartProvider>
<Child />
</ChartProvider>
);
});

it('light theme', () => {
const Child = () => {
const themeConfig = useTheme();
expect(themeConfig.theme).toBe('light');
expect(themeConfig.defaultColor).toBe('#4C96FF');
return <div />;
};
render(
<ChartProvider theme="light">
<Child />
</ChartProvider>
);
});

it('dark theme', () => {
const Child = () => {
const themeConfig = useTheme();
expect(themeConfig.theme).toBe('dark');
expect(themeConfig.defaultColor).toBe('#4D97FF');
return <div />;
};
render(
<ChartProvider theme="dark">
<Child />
</ChartProvider>
);
});

it('custom theme config', () => {
const Child = () => {
const themeConfig = useTheme();
expect(themeConfig.theme).toBe('custom-theme');
expect(themeConfig.defaultColor).toBe('#ff0000');
expect(themeConfig.subColor).toBe('#00ff00');
return <div />;
};
render(
<ChartProvider
theme={{ theme: 'custom-theme', defaultColor: '#ff0000', subColor: '#00ff00' }}
>
<Child />
</ChartProvider>
);
});
});
11 changes: 11 additions & 0 deletions packages/charts/src/ChartProvider/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';

export type Theme = 'light' | 'dark' | string | object;

export interface ChartConsumerProps {
theme?: Theme;
}

export const ChartContext = React.createContext<ChartConsumerProps>({
theme: 'light',
});
28 changes: 28 additions & 0 deletions packages/charts/src/ChartProvider/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import { ChartContext } from './context';
import type { ChartConsumerProps } from './context';

export * from './context';

export interface ChartProviderProps extends ChartConsumerProps {
children?: React.ReactNode;
}

const ChartProvider: React.FC<ChartProviderProps> & {
ChartContext: typeof ChartContext;
} = ({ children, theme = 'light', ...restProps }) => {
return (
<ChartContext.Provider
value={{
theme,
...restProps,
}}
>
{children}
</ChartContext.Provider>
);
};

ChartProvider.ChartContext = ChartContext;

export default ChartProvider;
Loading