From 722afb0c5949b482c1dedd88e721a0ff09158825 Mon Sep 17 00:00:00 2001 From: wangdicoder Date: Fri, 27 Mar 2026 10:39:07 +1100 Subject: [PATCH 1/5] chore: add changeset for chart tokens and charts package --- .changeset/add-chart-tokens-and-charts-package.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/add-chart-tokens-and-charts-package.md diff --git a/.changeset/add-chart-tokens-and-charts-package.md b/.changeset/add-chart-tokens-and-charts-package.md new file mode 100644 index 00000000..dcb92219 --- /dev/null +++ b/.changeset/add-chart-tokens-and-charts-package.md @@ -0,0 +1,5 @@ +--- +"@tiny-design/tokens": minor +--- + +Add chart color tokens (chart-1 through chart-5) for light and dark themes From 7025f2c376880cefbe6c4ca1dbdeb34cf66f9d48 Mon Sep 17 00:00:00 2001 From: wangdicoder Date: Fri, 27 Mar 2026 10:49:12 +1100 Subject: [PATCH 2/5] feat(tokens): add chart color tokens Add chart-1 through chart-5 color tokens for both light and dark themes to support the new charts package. --- packages/tokens/css/base.css | 15 +++++++++++++++ packages/tokens/scss/_tokens.scss | 7 +++++++ packages/tokens/scss/themes/_dark.scss | 7 +++++++ packages/tokens/scss/themes/_light.scss | 7 +++++++ 4 files changed, 36 insertions(+) diff --git a/packages/tokens/css/base.css b/packages/tokens/css/base.css index d30c728f..3c7579f9 100644 --- a/packages/tokens/css/base.css +++ b/packages/tokens/css/base.css @@ -289,6 +289,11 @@ --ty-height-md: 32px; --ty-height-lg: 42px; --ty-spacer: 1rem; + --ty-chart-1: #6e41bf; + --ty-chart-2: #1890ff; + --ty-chart-3: #52c41a; + --ty-chart-4: #ff9800; + --ty-chart-5: #f44336; } html[data-tiny-theme=dark] { @@ -582,6 +587,11 @@ html[data-tiny-theme=dark] { --ty-height-md: 32px; --ty-height-lg: 42px; --ty-spacer: 1rem; + --ty-chart-1: #9065d0; + --ty-chart-2: #177ddc; + --ty-chart-3: #49aa19; + --ty-chart-4: #d89614; + --ty-chart-5: #d32029; } @media (prefers-color-scheme: dark) { @@ -876,6 +886,11 @@ html[data-tiny-theme=dark] { --ty-height-md: 32px; --ty-height-lg: 42px; --ty-spacer: 1rem; + --ty-chart-1: #9065d0; + --ty-chart-2: #177ddc; + --ty-chart-3: #49aa19; + --ty-chart-4: #d89614; + --ty-chart-5: #d32029; } } /* stylelint-disable scss/comment-no-empty */ diff --git a/packages/tokens/scss/_tokens.scss b/packages/tokens/scss/_tokens.scss index 1a88bb29..e5f7967c 100644 --- a/packages/tokens/scss/_tokens.scss +++ b/packages/tokens/scss/_tokens.scss @@ -82,3 +82,10 @@ $token-height-sm: var(--ty-height-sm); $token-height-md: var(--ty-height-md); $token-height-lg: var(--ty-height-lg); $token-spacer: var(--ty-spacer); + +// ---- Chart ---- +$token-chart-1: var(--ty-chart-1); +$token-chart-2: var(--ty-chart-2); +$token-chart-3: var(--ty-chart-3); +$token-chart-4: var(--ty-chart-4); +$token-chart-5: var(--ty-chart-5); diff --git a/packages/tokens/scss/themes/_dark.scss b/packages/tokens/scss/themes/_dark.scss index c2e65ce3..6134cc2e 100644 --- a/packages/tokens/scss/themes/_dark.scss +++ b/packages/tokens/scss/themes/_dark.scss @@ -407,4 +407,11 @@ $dark-theme: ( height-md: 32px, height-lg: 42px, spacer: 1rem, + + // ---- Chart ---- + chart-1: #9065d0, + chart-2: #177ddc, + chart-3: #49aa19, + chart-4: #d89614, + chart-5: #d32029, ); diff --git a/packages/tokens/scss/themes/_light.scss b/packages/tokens/scss/themes/_light.scss index 8664cc69..29d47dcd 100644 --- a/packages/tokens/scss/themes/_light.scss +++ b/packages/tokens/scss/themes/_light.scss @@ -407,4 +407,11 @@ $light-theme: ( height-md: 32px, height-lg: 42px, spacer: 1rem, + + // ---- Chart ---- + chart-1: #6e41bf, + chart-2: #1890ff, + chart-3: #52c41a, + chart-4: #ff9800, + chart-5: #f44336, ); From 79604076f193f18262840edae55bea399c8a7001 Mon Sep 17 00:00:00 2001 From: wangdicoder Date: Fri, 27 Mar 2026 10:49:21 +1100 Subject: [PATCH 3/5] feat(charts): add @tiny-design/charts package Theme-aware chart components built on Recharts, including ChartContainer, ChartTooltip, ChartLegend, and ChartStyle with light/dark theme support. --- packages/charts/package.json | 58 ++++++++ packages/charts/src/chart-container.tsx | 58 ++++++++ packages/charts/src/chart-context.tsx | 28 ++++ packages/charts/src/chart-legend.tsx | 89 +++++++++++++ packages/charts/src/chart-style.tsx | 48 +++++++ packages/charts/src/chart-tooltip.tsx | 140 +++++++++++++++++++ packages/charts/src/demo/AreaChart.tsx | 71 ++++++++++ packages/charts/src/demo/BarChart.tsx | 52 ++++++++ packages/charts/src/demo/LineChart.tsx | 61 +++++++++ packages/charts/src/demo/PieChart.tsx | 65 +++++++++ packages/charts/src/demo/RadarChart.tsx | 62 +++++++++ packages/charts/src/demo/Tooltip.tsx | 56 ++++++++ packages/charts/src/index.md | 170 ++++++++++++++++++++++++ packages/charts/src/index.ts | 13 ++ packages/charts/src/index.zh_CN.md | 170 ++++++++++++++++++++++++ packages/charts/src/style/index.scss | 151 +++++++++++++++++++++ packages/charts/src/types.ts | 11 ++ packages/charts/tsconfig.json | 14 ++ 18 files changed, 1317 insertions(+) create mode 100644 packages/charts/package.json create mode 100644 packages/charts/src/chart-container.tsx create mode 100644 packages/charts/src/chart-context.tsx create mode 100644 packages/charts/src/chart-legend.tsx create mode 100644 packages/charts/src/chart-style.tsx create mode 100644 packages/charts/src/chart-tooltip.tsx create mode 100644 packages/charts/src/demo/AreaChart.tsx create mode 100644 packages/charts/src/demo/BarChart.tsx create mode 100644 packages/charts/src/demo/LineChart.tsx create mode 100644 packages/charts/src/demo/PieChart.tsx create mode 100644 packages/charts/src/demo/RadarChart.tsx create mode 100644 packages/charts/src/demo/Tooltip.tsx create mode 100644 packages/charts/src/index.md create mode 100644 packages/charts/src/index.ts create mode 100644 packages/charts/src/index.zh_CN.md create mode 100644 packages/charts/src/style/index.scss create mode 100644 packages/charts/src/types.ts create mode 100644 packages/charts/tsconfig.json diff --git a/packages/charts/package.json b/packages/charts/package.json new file mode 100644 index 00000000..8332f92b --- /dev/null +++ b/packages/charts/package.json @@ -0,0 +1,58 @@ +{ + "name": "@tiny-design/charts", + "version": "1.6.1", + "description": "Theme-aware chart components for Tiny Design, built on Recharts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/wangdicoder/tiny-design.git", + "directory": "packages/charts" + }, + "publishConfig": { + "access": "public" + }, + "main": "lib/index.js", + "module": "es/index.js", + "typings": "lib/index.d.ts", + "exports": { + ".": { + "types": "./lib/index.d.ts", + "import": "./es/index.js", + "require": "./lib/index.js" + }, + "./lib/*": "./lib/*", + "./es/*": "./es/*" + }, + "sideEffects": [ + "**/*.css", + "**/*.scss" + ], + "files": [ + "lib", + "es" + ], + "scripts": { + "build": "npm run clean && tsdown", + "clean": "rimraf lib es" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-dom": ">=18.0.0", + "recharts": ">=2.0.0" + }, + "dependencies": { + "@tiny-design/tokens": "workspace:*", + "classnames": "^2.3.1", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@types/react": "^18.2.0", + "@types/react-dom": "^18.2.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "recharts": "^2.15.0", + "rimraf": "^3.0.2", + "tsdown": "^0.21.1", + "typescript": "^5.4.0" + } +} diff --git a/packages/charts/src/chart-container.tsx b/packages/charts/src/chart-container.tsx new file mode 100644 index 00000000..05dd038e --- /dev/null +++ b/packages/charts/src/chart-container.tsx @@ -0,0 +1,58 @@ +import React, { useId, useMemo } from 'react'; +import classNames from 'classnames'; +import { ResponsiveContainer } from 'recharts'; +import { ChartContextProvider } from './chart-context'; +import { ChartStyle } from './chart-style'; +import { ChartConfig } from './types'; + +const PREFIX = 'ty-chart'; + +export interface ChartContainerProps extends React.HTMLAttributes { + config: ChartConfig; + children: React.ReactElement; +} + +/** + * ChartContainer wraps Recharts charts with: + * 1. A ResponsiveContainer for auto-sizing + * 2. CSS custom properties (--color-KEY) injected via inline styles + * 3. ChartConfig provided via React context for tooltip/legend + */ +const ChartContainer = React.forwardRef( + ({ config, children, className, style, id, ...props }, ref) => { + const uniqueId = useId(); + const chartId = id || `chart-${uniqueId}`; + + // Build --color-KEY CSS custom properties from config + const colorVars = useMemo(() => { + const vars: Record = {}; + for (const [key, value] of Object.entries(config)) { + if (value.color) { + vars[`--color-${key}`] = value.color; + } + } + return vars; + }, [config]); + + return ( + + +
+ + {children} + +
+
+ ); + } +); + +ChartContainer.displayName = 'ChartContainer'; + +export default ChartContainer; diff --git a/packages/charts/src/chart-context.tsx b/packages/charts/src/chart-context.tsx new file mode 100644 index 00000000..b0d493f7 --- /dev/null +++ b/packages/charts/src/chart-context.tsx @@ -0,0 +1,28 @@ +import React, { createContext, useContext } from 'react'; +import { ChartConfig } from './types'; + +interface ChartContextValue { + config: ChartConfig; +} + +const ChartContext = createContext(null); + +export function useChart(): ChartContextValue { + const context = useContext(ChartContext); + if (!context) { + throw new Error('useChart must be used within a '); + } + return context; +} + +export function ChartContextProvider({ + config, + children, +}: { + config: ChartConfig; + children: React.ReactNode; +}) { + return ( + {children} + ); +} diff --git a/packages/charts/src/chart-legend.tsx b/packages/charts/src/chart-legend.tsx new file mode 100644 index 00000000..9cfb0046 --- /dev/null +++ b/packages/charts/src/chart-legend.tsx @@ -0,0 +1,89 @@ +import React from 'react'; +import classNames from 'classnames'; +import { Legend as RechartsLegend } from 'recharts'; +import { useChart } from './chart-context'; + +const PREFIX = 'ty-chart-legend'; + +export const ChartLegend = RechartsLegend; + +export interface ChartLegendContentProps + extends React.HTMLAttributes { + payload?: Array<{ + value?: string; + dataKey?: string; + color?: string; + type?: string; + }>; + nameKey?: string; + hideIcon?: boolean; + verticalAlign?: 'top' | 'bottom'; +} + +export const ChartLegendContent = React.forwardRef< + HTMLDivElement, + ChartLegendContentProps +>( + ( + { + payload, + nameKey, + hideIcon = false, + verticalAlign = 'bottom', + className, + ...props + }, + ref + ) => { + const { config } = useChart(); + + if (!payload?.length) { + return null; + } + + return ( +
+ {payload.map((entry) => { + const key = nameKey + ? (entry.dataKey || entry.value) + : entry.dataKey || entry.value; + const itemConfig = key ? config[key] : undefined; + const displayName = itemConfig?.label || entry.value || key; + const color = + entry.color || (itemConfig?.color ? `var(--color-${key})` : undefined); + + const IconComponent = itemConfig?.icon; + + return ( +
+ {!hideIcon && ( + IconComponent ? ( + + ) : ( + + ) + )} + {displayName} +
+ ); + })} +
+ ); + } +); + +ChartLegendContent.displayName = 'ChartLegendContent'; diff --git a/packages/charts/src/chart-style.tsx b/packages/charts/src/chart-style.tsx new file mode 100644 index 00000000..a9fcdaeb --- /dev/null +++ b/packages/charts/src/chart-style.tsx @@ -0,0 +1,48 @@ +import React, { useMemo } from 'react'; +import { ChartConfig } from './types'; + +const THEMES = { light: '', dark: 'html[data-tiny-theme=dark]' } as const; + +/** + * Generates an inline